Don't raise warning when converting fun() pointer to bool
[hiphop-php.git] / hphp / runtime / vm / func-inl.h
blob787c6f9ba71b29b0c26b87621abb93aef7820f18
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-present Facebook, Inc. (http://www.facebook.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
17 #ifndef incl_HPHP_VM_FUNC_INL_H_
18 #error "func-inl.h should only be included by func.h"
19 #endif
21 #include "hphp/runtime/vm/unit-util.h"
23 namespace HPHP {
24 ///////////////////////////////////////////////////////////////////////////////
25 // EH table.
27 template<class SerDe>
28 void EHEnt::serde(SerDe& sd) {
29 folly::Optional<Offset> end;
30 if (!SerDe::deserializing) {
31 end = (m_end == kInvalidOffset) ? folly::none : folly::make_optional(m_end);
34 sd(m_base)
35 (m_past)
36 (m_iterId)
37 (m_handler)
38 (end)
39 (m_parentIndex)
42 if (SerDe::deserializing) {
43 m_end = end.value_or(kInvalidOffset);
47 ///////////////////////////////////////////////////////////////////////////////
48 // ParamInfo.
50 inline Func::ParamInfo::ParamInfo()
51 : defaultValue(make_tv<KindOfUninit>())
54 template<class SerDe>
55 inline void Func::ParamInfo::serde(SerDe& sd) {
56 sd(builtinType)
57 (funcletOff)
58 (defaultValue)
59 (phpCode)
60 (typeConstraint)
61 (flags)
62 (userAttributes)
63 (userType)
67 inline bool Func::ParamInfo::hasDefaultValue() const {
68 return funcletOff != kInvalidOffset;
71 inline bool Func::ParamInfo::hasScalarDefaultValue() const {
72 return hasDefaultValue() && defaultValue.m_type != KindOfUninit;
75 inline bool Func::ParamInfo::isInOut() const {
76 return flags & (1 << static_cast<int32_t>(Flags::InOut));
79 inline bool Func::ParamInfo::isVariadic() const {
80 return flags & (1 << static_cast<int32_t>(Flags::Variadic));
83 inline bool Func::ParamInfo::isNativeArg() const {
84 return flags & (1 << static_cast<int32_t>(Flags::NativeArg));
87 inline void Func::ParamInfo::setFlag(Func::ParamInfo::Flags flag) {
88 flags |= 1 << static_cast<int32_t>(flag);
91 ///////////////////////////////////////////////////////////////////////////////
92 // Func.
94 inline const void* Func::mallocEnd() const {
95 return reinterpret_cast<const char*>(this)
96 + Func::prologueTableOff()
97 + numPrologues() * sizeof(m_prologueTable[0]);
100 inline bool Func::validate() const {
101 #ifndef NDEBUG
102 assertx(m_magic == kMagic);
103 #endif
104 assertx(m_name != nullptr);
105 return true;
108 ///////////////////////////////////////////////////////////////////////////////
109 // FuncId manipulation.
111 inline FuncId Func::getFuncId() const {
112 assertx(m_funcId != InvalidFuncId);
113 assertx(fromFuncId(m_funcId) == this);
114 return m_funcId;
117 ///////////////////////////////////////////////////////////////////////////////
118 // Basic info.
120 inline bool Func::top() const {
121 return shared()->m_top;
124 inline Unit* Func::unit() const {
125 return m_unit;
128 inline Class* Func::cls() const {
129 return !isMethCaller() ? m_u.cls() : nullptr;
132 inline PreClass* Func::preClass() const {
133 return shared()->m_preClass;
136 inline Class* Func::baseCls() const {
137 return !(m_baseCls & kMethCallerBit) ?
138 reinterpret_cast<Class*>(m_baseCls) : nullptr;
141 inline Class* Func::implCls() const {
142 return isClosureBody() ? baseCls() : cls();
145 inline const StringData* Func::name() const {
146 assertx(m_name != nullptr);
147 return m_name;
150 inline StrNR Func::nameStr() const {
151 assertx(m_name != nullptr);
152 return StrNR(m_name);
155 inline const StringData* Func::fullName() const {
156 if (m_fullName == nullptr) return m_name;
157 if (UNLIKELY((intptr_t)m_fullName.get() == kNeedsFullName)) {
158 m_fullName = makeStaticString(
159 std::string(cls()->name()->data()) + "::" + m_name->data());
161 return m_fullName;
164 inline StrNR Func::fullNameStr() const {
165 assertx(m_fullName != nullptr);
166 return StrNR(fullName());
169 inline const StringData* funcToStringHelper(const Func* func) {
170 if (RuntimeOption::EvalRaiseFuncConversionWarning) {
171 raise_warning(Strings::FUNC_TO_STRING);
173 return func->name();
176 inline int64_t funcToInt64Helper(const Func* func) {
177 if (RuntimeOption::EvalRaiseFuncConversionWarning) {
178 raise_warning("Func to int conversion");
180 return func->name()->toInt64();
183 inline NamedEntity* Func::getNamedEntity() {
184 assertx(!shared()->m_preClass);
185 return *reinterpret_cast<LowPtr<NamedEntity>*>(&m_namedEntity);
188 inline const NamedEntity* Func::getNamedEntity() const {
189 assertx(!shared()->m_preClass);
190 return *reinterpret_cast<const LowPtr<const NamedEntity>*>(&m_namedEntity);
193 inline void Func::setNamedEntity(const NamedEntity* e) {
194 *reinterpret_cast<LowPtr<const NamedEntity>*>(&m_namedEntity) = e;
197 inline const StringData* Func::methCallerClsName() const {
198 assertx(isMethCaller() && isBuiltin());
199 return m_u.name();
202 inline const StringData* Func::methCallerMethName() const {
203 assertx(isMethCaller() && isBuiltin() &&
204 (m_methCallerMethName & kMethCallerBit));
205 return reinterpret_cast<StringData*>(m_methCallerMethName - kMethCallerBit);
208 ///////////////////////////////////////////////////////////////////////////////
209 // File info.
211 inline const StringData* Func::originalFilename() const {
212 return shared()->m_originalFilename;
215 inline const StringData* Func::filename() const {
216 // Builtins don't have filenames
217 if (isBuiltin()) {
218 return staticEmptyString();
221 // Use the original filename if it exists, otherwise grab the filename from
222 // the unit
223 const StringData* name = originalFilename();
224 if (!name) {
225 assertx(m_unit);
226 name = m_unit->filepath();
227 assertx(name);
229 return name;
232 inline int Func::line1() const {
233 return shared()->m_line1;
236 inline int Func::line2() const {
237 auto const sd = shared();
238 auto const delta = sd->m_line2Delta;
239 if (UNLIKELY(delta == kSmallDeltaLimit)) {
240 assertx(extShared());
241 return static_cast<const ExtendedSharedData*>(sd)->m_line2;
243 return line1() + delta;
246 inline const StringData* Func::docComment() const {
247 return shared()->m_docComment;
250 ///////////////////////////////////////////////////////////////////////////////
251 // Bytecode.
253 inline PC Func::getEntry() const {
254 return m_unit->entry() + shared()->m_base;
257 inline Offset Func::base() const {
258 return shared()->m_base;
261 inline Offset Func::past() const {
262 auto const sd = shared();
263 auto const delta = sd->m_pastDelta;
264 if (UNLIKELY(delta == kSmallDeltaLimit)) {
265 assertx(extShared());
266 return static_cast<const ExtendedSharedData*>(sd)->m_past;
268 return base() + delta;
271 inline bool Func::contains(PC pc) const {
272 return contains(Offset(pc - unit()->entry()));
275 inline bool Func::contains(Offset offset) const {
276 return offset >= base() && offset < past();
279 inline Offset Func::ctiEntry() const {
280 return shared()->m_cti_base.load(std::memory_order_acquire);
283 inline void Func::setCtiFunclet(int i, Offset cti_funclet) {
284 shared()->m_params[i].ctiFunclet = cti_funclet;
287 inline void Func::setCtiEntry(Offset base, uint32_t size) {
288 auto sd = shared();
289 sd->m_cti_size = size;
290 sd->m_cti_base.store(base, std::memory_order_release);
293 ///////////////////////////////////////////////////////////////////////////////
294 // Return type.
296 inline MaybeDataType Func::hniReturnType() const {
297 auto const ex = extShared();
298 return ex ? ex->m_hniReturnType : folly::none;
301 inline RepoAuthType Func::repoReturnType() const {
302 return shared()->m_repoReturnType;
305 inline RepoAuthType Func::repoAwaitedReturnType() const {
306 return shared()->m_repoAwaitedReturnType;
309 inline bool Func::isReturnByValue() const {
310 return shared()->m_returnByValue;
313 inline const TypeConstraint& Func::returnTypeConstraint() const {
314 return shared()->m_retTypeConstraint;
317 inline const StringData* Func::returnUserType() const {
318 return shared()->m_retUserType;
321 inline bool Func::hasReturnWithMultiUBs() const {
322 return shared()->m_hasReturnWithMultiUBs;
325 inline const Func::UpperBoundVec& Func::returnUBs() const {
326 assertx(hasReturnWithMultiUBs());
327 return extShared()->m_returnUBs;
330 ///////////////////////////////////////////////////////////////////////////////
331 // Parameters.
333 inline const Func::ParamInfoVec& Func::params() const {
334 return shared()->m_params;
337 inline uint32_t Func::numParams() const {
338 assertx(bool(m_attrs & AttrVariadicParam) != bool(m_paramCounts & 1));
339 assertx((m_paramCounts >> 1) == params().size());
340 return (m_paramCounts) >> 1;
343 inline uint32_t Func::numNonVariadicParams() const {
344 assertx(bool(m_attrs & AttrVariadicParam) != bool(m_paramCounts & 1));
345 assertx((m_paramCounts >> 1) == params().size());
346 return (m_paramCounts - 1) >> 1;
349 inline uint32_t Func::numRequiredParams() const {
350 for (auto i = numNonVariadicParams(); i > 0; --i) {
351 if (!params()[i - 1].hasDefaultValue()) return i;
353 return 0;
356 inline bool Func::hasVariadicCaptureParam() const {
357 #ifndef NDEBUG
358 assertx(bool(m_attrs & AttrVariadicParam) ==
359 (numParams() && params()[numParams() - 1].isVariadic()));
360 #endif
361 return m_attrs & AttrVariadicParam;
364 inline bool Func::hasParamsWithMultiUBs() const {
365 return shared()->m_hasParamsWithMultiUBs;
368 inline const Func::ParamUBMap& Func::paramUBs() const {
369 assertx(hasParamsWithMultiUBs());
370 return extShared()->m_paramUBs;
373 ///////////////////////////////////////////////////////////////////////////////
374 // Locals, iterators, and stack.
376 inline int Func::numLocals() const {
377 return shared()->m_numLocals;
380 inline int Func::numIterators() const {
381 return shared()->m_numIterators;
384 inline Id Func::numNamedLocals() const {
385 return shared()->m_localNames.size();
388 inline const StringData* Func::localVarName(Id id) const {
389 assertx(id >= 0);
390 return id < numNamedLocals() ? shared()->m_localNames[id] : nullptr;
393 inline LowStringPtr const* Func::localNames() const {
394 return shared()->m_localNames.accessList();
397 inline int Func::maxStackCells() const {
398 return m_maxStackCells;
401 inline int Func::numSlotsInFrame() const {
402 return
403 shared()->m_numLocals +
404 shared()->m_numIterators * (sizeof(Iter) / sizeof(TypedValue));
407 inline bool Func::hasForeignThis() const {
408 return m_hasForeignThis;
411 inline void Func::setHasForeignThis(bool hasForeignThis) {
412 m_hasForeignThis = hasForeignThis;
415 inline void Func::setGenerated(bool isGenerated) {
416 shared()->m_isGenerated = isGenerated;
419 ///////////////////////////////////////////////////////////////////////////////
420 // Definition context.
422 inline bool Func::isPseudoMain() const {
423 return m_name->empty();
426 inline bool Func::isMethod() const {
427 return !isPseudoMain() && (bool)baseCls();
430 inline bool Func::isFromTrait() const {
431 return m_attrs & AttrTrait;
434 inline bool Func::isPublic() const {
435 return m_attrs & AttrPublic;
438 inline bool Func::isStatic() const {
439 return m_attrs & AttrStatic;
442 inline bool Func::isStaticInPrologue() const {
443 return isStatic() && !isClosureBody();
446 inline bool Func::hasThisInBody() const {
447 return cls() && !isStatic();
450 inline bool Func::isAbstract() const {
451 return m_attrs & AttrAbstract;
454 inline bool Func::isPreFunc() const {
455 return m_isPreFunc;
458 inline bool Func::isMemoizeWrapper() const {
459 return shared()->m_isMemoizeWrapper;
462 inline bool Func::isMemoizeWrapperLSB() const {
463 return shared()->m_isMemoizeWrapperLSB;
466 inline bool Func::isMemoizeImpl() const {
467 return isMemoizeImplName(name());
470 inline const StringData* Func::memoizeImplName() const {
471 assertx(isMemoizeWrapper());
472 return genMemoizeImplName(name());
475 ///////////////////////////////////////////////////////////////////////////////
476 // Builtins.
478 inline bool Func::isBuiltin() const {
479 return m_attrs & AttrBuiltin;
482 inline bool Func::isCPPBuiltin() const {
483 auto const ex = extShared();
484 return UNLIKELY(!!ex) && ex->m_arFuncPtr;
487 inline ArFunction Func::arFuncPtr() const {
488 if (auto const ex = extShared()) return ex->m_arFuncPtr;
489 return nullptr;
492 inline NativeFunction Func::nativeFuncPtr() const {
493 if (auto const ex = extShared()) return ex->m_nativeFuncPtr;
494 return nullptr;
497 ///////////////////////////////////////////////////////////////////////////////
498 // Closures.
500 inline bool Func::isClosureBody() const {
501 return shared()->m_isClosureBody;
504 ///////////////////////////////////////////////////////////////////////////////
505 // Resumables.
507 inline bool Func::isAsync() const {
508 return shared()->m_isAsync;
511 inline bool Func::isGenerator() const {
512 return shared()->m_isGenerator;
515 inline bool Func::isPairGenerator() const {
516 return shared()->m_isPairGenerator;
519 inline bool Func::isAsyncFunction() const {
520 return isAsync() && !isGenerator();
523 inline bool Func::isNonAsyncGenerator() const {
524 return !isAsync() && isGenerator();
527 inline bool Func::isAsyncGenerator() const {
528 return isAsync() && isGenerator();
531 inline bool Func::isResumable() const {
532 return isAsync() || isGenerator();
535 ///////////////////////////////////////////////////////////////////////////////
536 // Reactivity.
538 inline RxLevel Func::rxLevel() const {
539 return rxLevelFromAttr(m_attrs);
542 inline bool Func::isRxDisabled() const {
543 return shared()->m_isRxDisabled;
546 inline bool Func::isRxConditional() const {
547 return rxConditionalFromAttr(m_attrs);
550 ///////////////////////////////////////////////////////////////////////////////
551 // Methods.
553 inline Slot Func::methodSlot() const {
554 assertx(isMethod());
555 return m_methodSlot;
558 inline bool Func::hasPrivateAncestor() const {
559 return m_hasPrivateAncestor;
562 ///////////////////////////////////////////////////////////////////////////////
563 // Magic methods.
565 inline bool Func::isGenerated() const {
566 return shared()->m_isGenerated;
569 inline bool Func::isSpecial(const StringData* name) {
570 return strncmp("86", name->data(), 2) == 0;
573 ///////////////////////////////////////////////////////////////////////////////
574 // Other attributes.
576 inline Attr Func::attrs() const {
577 return m_attrs;
580 inline const UserAttributeMap& Func::userAttributes() const {
581 return shared()->m_userAttributes;
584 inline bool Func::isUnique() const {
585 return m_attrs & AttrUnique;
588 inline bool Func::isPersistent() const {
589 return m_attrs & AttrPersistent;
592 inline bool Func::isInterceptable() const {
593 return m_attrs & AttrInterceptable;
596 inline bool Func::isNoInjection() const {
597 return m_attrs & AttrNoInjection;
600 inline bool Func::isSkipFrame() const {
601 return isCPPBuiltin() || (isBuiltin() && !isMethod() && !isPseudoMain());
604 inline bool Func::isProvenanceSkipFrame() const {
605 return m_attrs & AttrProvenanceSkipFrame;
608 inline bool Func::isFoldable() const {
609 return m_attrs & AttrIsFoldable;
612 inline bool Func::supportsAsyncEagerReturn() const {
613 return m_attrs & AttrSupportsAsyncEagerReturn;
616 inline bool Func::isDynamicallyCallable() const {
617 return m_attrs & AttrDynamicallyCallable;
620 inline bool Func::isMethCaller() const {
621 return m_attrs & AttrIsMethCaller;
624 inline bool Func::isPhpLeafFn() const {
625 return shared()->m_isPhpLeafFn;
628 inline bool Func::hasReifiedGenerics() const {
629 return shared()->m_hasReifiedGenerics;
632 ///////////////////////////////////////////////////////////////////////////////
633 // Unit table entries.
635 inline const Func::EHEntVec& Func::ehtab() const {
636 return shared()->m_ehtab;
639 inline const EHEnt* Func::findEH(Offset o) const {
640 assertx(o >= base() && o < past());
641 return findEH(shared()->m_ehtab, o);
644 template<class Container>
645 const typename Container::value_type*
646 Func::findEH(const Container& ehtab, Offset o) {
647 const typename Container::value_type* eh = nullptr;
649 for (uint32_t i = 0, sz = ehtab.size(); i < sz; ++i) {
650 if (ehtab[i].m_base <= o && o < ehtab[i].m_past) {
651 eh = &ehtab[i];
654 return eh;
657 ///////////////////////////////////////////////////////////////////////////////
658 // JIT data.
660 inline rds::Handle Func::funcHandle() const {
661 return m_cachedFunc.handle();
664 inline unsigned char* Func::getFuncBody() const {
665 return m_funcBody;
668 inline void Func::setFuncBody(unsigned char* fb) {
669 m_funcBody = fb;
672 inline uint8_t* Func::getPrologue(int index) const {
673 return m_prologueTable[index];
676 inline void Func::setPrologue(int index, unsigned char* tca) {
677 m_prologueTable[index] = tca;
680 ///////////////////////////////////////////////////////////////////////////////
681 // Other methods.
683 inline int8_t& Func::maybeIntercepted() const {
684 return m_maybeIntercepted;
687 ///////////////////////////////////////////////////////////////////////////////
688 // Public setters.
690 inline void Func::setAttrs(Attr attrs) {
691 m_attrs = attrs;
694 inline void Func::setBaseCls(Class* baseCls) {
695 m_baseCls = to_low(baseCls);
698 inline void Func::setFuncHandle(rds::Link<LowPtr<Func>,
699 rds::Mode::NonLocal> l) {
700 // TODO(#2950356): This assertion fails for create_function with an existing
701 // declared function named __lambda_func.
702 //assertx(!m_cachedFunc.valid());
703 m_cachedFunc = l;
706 inline void Func::setHasPrivateAncestor(bool b) {
707 m_hasPrivateAncestor = b;
710 inline void Func::setMethodSlot(Slot s) {
711 assertx(isMethod());
712 m_methodSlot = s;
715 inline bool Func::serialize() const {
716 if (m_serialized) return false;
717 const_cast<Func*>(this)->m_serialized = true;
718 return true;
721 //////////////////////////////////////////////////////////////////////
723 inline const Func::ExtendedSharedData* Func::extShared() const {
724 return const_cast<Func*>(this)->extShared();
727 inline Func::ExtendedSharedData* Func::extShared() {
728 auto const s = shared();
729 return UNLIKELY(s->m_hasExtendedSharedData)
730 ? static_cast<ExtendedSharedData*>(s)
731 : nullptr;
734 ///////////////////////////////////////////////////////////////////////////////