2 +----------------------------------------------------------------------+
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"
21 #include "hphp/runtime/vm/unit-util.h"
24 ///////////////////////////////////////////////////////////////////////////////
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
);
42 if (SerDe::deserializing
) {
43 m_end
= end
.value_or(kInvalidOffset
);
47 ///////////////////////////////////////////////////////////////////////////////
50 inline Func::ParamInfo::ParamInfo()
51 : defaultValue(make_tv
<KindOfUninit
>())
55 inline void Func::ParamInfo::serde(SerDe
& sd
) {
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 ///////////////////////////////////////////////////////////////////////////////
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 {
102 assertx(m_magic
== kMagic
);
104 assertx(m_name
!= nullptr);
108 ///////////////////////////////////////////////////////////////////////////////
109 // FuncId manipulation.
111 inline FuncId
Func::getFuncId() const {
112 assertx(m_funcId
!= InvalidFuncId
);
113 assertx(fromFuncId(m_funcId
) == this);
117 ///////////////////////////////////////////////////////////////////////////////
120 inline bool Func::top() const {
121 return shared()->m_top
;
124 inline Unit
* Func::unit() const {
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);
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());
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
);
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());
202 inline const StringData
* Func::methCallerMethName() const {
203 assertx(isMethCaller() && isBuiltin() &&
204 (m_methCallerMethName
& kMethCallerBit
));
205 return reinterpret_cast<StringData
*>(m_methCallerMethName
- kMethCallerBit
);
208 ///////////////////////////////////////////////////////////////////////////////
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
218 return staticEmptyString();
221 // Use the original filename if it exists, otherwise grab the filename from
223 const StringData
* name
= originalFilename();
226 name
= m_unit
->filepath();
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 ///////////////////////////////////////////////////////////////////////////////
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
) {
289 sd
->m_cti_size
= size
;
290 sd
->m_cti_base
.store(base
, std::memory_order_release
);
293 ///////////////////////////////////////////////////////////////////////////////
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 ///////////////////////////////////////////////////////////////////////////////
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
;
356 inline bool Func::hasVariadicCaptureParam() const {
358 assertx(bool(m_attrs
& AttrVariadicParam
) ==
359 (numParams() && params()[numParams() - 1].isVariadic()));
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 {
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 {
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 {
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 ///////////////////////////////////////////////////////////////////////////////
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
;
492 inline NativeFunction
Func::nativeFuncPtr() const {
493 if (auto const ex
= extShared()) return ex
->m_nativeFuncPtr
;
497 ///////////////////////////////////////////////////////////////////////////////
500 inline bool Func::isClosureBody() const {
501 return shared()->m_isClosureBody
;
504 ///////////////////////////////////////////////////////////////////////////////
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 ///////////////////////////////////////////////////////////////////////////////
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 ///////////////////////////////////////////////////////////////////////////////
553 inline Slot
Func::methodSlot() const {
558 inline bool Func::hasPrivateAncestor() const {
559 return m_hasPrivateAncestor
;
562 ///////////////////////////////////////////////////////////////////////////////
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 ///////////////////////////////////////////////////////////////////////////////
576 inline Attr
Func::attrs() const {
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
) {
657 ///////////////////////////////////////////////////////////////////////////////
660 inline rds::Handle
Func::funcHandle() const {
661 return m_cachedFunc
.handle();
664 inline unsigned char* Func::getFuncBody() const {
668 inline void Func::setFuncBody(unsigned char* 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 ///////////////////////////////////////////////////////////////////////////////
683 inline int8_t& Func::maybeIntercepted() const {
684 return m_maybeIntercepted
;
687 ///////////////////////////////////////////////////////////////////////////////
690 inline void Func::setAttrs(Attr 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());
706 inline void Func::setHasPrivateAncestor(bool b
) {
707 m_hasPrivateAncestor
= b
;
710 inline void Func::setMethodSlot(Slot s
) {
715 inline bool Func::serialize() const {
716 if (m_serialized
) return false;
717 const_cast<Func
*>(this)->m_serialized
= 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
)
734 ///////////////////////////////////////////////////////////////////////////////