Move findFPI wrapper to func-inl.h
[hiphop-php.git] / hphp / runtime / vm / func-inl.h
blob59ea64e0aac76f7adab14d6e1bd88c936f8b39d0
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 namespace HPHP {
22 ///////////////////////////////////////////////////////////////////////////////
23 // EH and FPI tables.
25 template<class SerDe>
26 void FPIEnt::serde(SerDe& sd) {
27 sd(m_fpushOff)
28 (m_fcallOff)
29 (m_fpOff)
30 // These fields are recomputed by sortFPITab:
31 // (m_parentIndex)
32 // (m_fpiDepth)
36 ///////////////////////////////////////////////////////////////////////////////
37 // ParamInfo.
39 inline Func::ParamInfo::ParamInfo()
40 : defaultValue(make_tv<KindOfUninit>())
43 template<class SerDe>
44 inline void Func::ParamInfo::serde(SerDe& sd) {
45 sd(builtinType)
46 (funcletOff)
47 (defaultValue)
48 (phpCode)
49 (typeConstraint)
50 (variadic)
51 (userAttributes)
52 (userType)
56 inline bool Func::ParamInfo::hasDefaultValue() const {
57 return funcletOff != InvalidAbsoluteOffset;
60 inline bool Func::ParamInfo::hasScalarDefaultValue() const {
61 return hasDefaultValue() && defaultValue.m_type != KindOfUninit;
64 inline bool Func::ParamInfo::isVariadic() const {
65 return variadic;
68 ///////////////////////////////////////////////////////////////////////////////
69 // Func.
71 inline const void* Func::mallocEnd() const {
72 return reinterpret_cast<const char*>(this)
73 + Func::prologueTableOff()
74 + numPrologues() * sizeof(m_prologueTable[0]);
77 inline void Func::validate() const {
78 #ifdef DEBUG
79 assert(m_magic == kMagic);
80 #endif
81 assert(m_name != nullptr);
84 ///////////////////////////////////////////////////////////////////////////////
85 // FuncId manipulation.
87 inline FuncId Func::getFuncId() const {
88 assert(m_funcId != InvalidFuncId);
89 assert(fromFuncId(m_funcId) == this);
90 return m_funcId;
93 ///////////////////////////////////////////////////////////////////////////////
94 // Basic info.
96 inline bool Func::top() const {
97 return shared()->m_top;
100 inline Unit* Func::unit() const {
101 return m_unit;
104 inline Class* Func::cls() const {
105 return m_cls;
108 inline PreClass* Func::preClass() const {
109 return shared()->m_preClass;
112 inline Class* Func::baseCls() const {
113 return m_baseCls;
116 inline Class* Func::implCls() const {
117 return isClosureBody() ? baseCls() : cls();
120 inline const StringData* Func::name() const {
121 assert(m_name != nullptr);
122 return m_name;
125 inline StrNR Func::nameStr() const {
126 assert(m_name != nullptr);
127 return StrNR(m_name);
130 inline const StringData* Func::fullName() const {
131 if (m_fullName == nullptr) return m_name;
132 return m_fullName;
135 inline StrNR Func::fullNameStr() const {
136 assert(m_fullName != nullptr);
137 return StrNR(m_fullName);
140 inline const StringData* Func::displayName() const {
141 auto const target = dynCallTarget();
142 return LIKELY(!target) ? name() : target->name();
145 inline const StringData* Func::fullDisplayName() const {
146 auto const target = dynCallTarget();
147 return LIKELY(!target) ? fullName() : target->fullName();
150 inline const NamedEntity* Func::getNamedEntity() const {
151 assert(!shared()->m_preClass);
152 return *reinterpret_cast<const LowPtr<const NamedEntity>*>(&m_namedEntity);
155 inline void Func::setNamedEntity(const NamedEntity* e) {
156 *reinterpret_cast<LowPtr<const NamedEntity>*>(&m_namedEntity) = e;
159 ///////////////////////////////////////////////////////////////////////////////
160 // File info.
162 inline const StringData* Func::originalFilename() const {
163 return shared()->m_originalFilename;
166 inline const StringData* Func::filename() const {
167 // Builtins don't have filenames
168 if (isBuiltin()) {
169 return staticEmptyString();
172 // Use the original filename if it exists, otherwise grab the filename from
173 // the unit
174 const StringData* name = originalFilename();
175 if (!name) {
176 assert(m_unit);
177 name = m_unit->filepath();
178 assert(name);
180 return name;
183 inline int Func::line1() const {
184 return shared()->m_line1;
187 inline int Func::line2() const {
188 auto const sd = shared();
189 auto const delta = sd->m_line2Delta;
190 if (UNLIKELY(delta == kSmallDeltaLimit)) {
191 assert(extShared());
192 return static_cast<const ExtendedSharedData*>(sd)->m_line2;
194 return line1() + delta;
197 inline const StringData* Func::docComment() const {
198 return shared()->m_docComment;
201 ///////////////////////////////////////////////////////////////////////////////
202 // Bytecode.
204 inline PC Func::getEntry() const {
205 return m_unit->entry() + shared()->m_base;
208 inline Offset Func::base() const {
209 return shared()->m_base;
212 inline Offset Func::past() const {
213 auto const sd = shared();
214 auto const delta = sd->m_pastDelta;
215 if (UNLIKELY(delta == kSmallDeltaLimit)) {
216 assert(extShared());
217 return static_cast<const ExtendedSharedData*>(sd)->m_past;
219 return base() + delta;
222 inline bool Func::contains(PC pc) const {
223 return contains(Offset(pc - unit()->entry()));
226 inline bool Func::contains(Offset offset) const {
227 return offset >= base() && offset < past();
230 ///////////////////////////////////////////////////////////////////////////////
231 // Return type.
233 inline MaybeDataType Func::hniReturnType() const {
234 auto const ex = extShared();
235 return ex ? ex->m_hniReturnType : folly::none;
238 inline RepoAuthType Func::repoReturnType() const {
239 return shared()->m_repoReturnType;
242 inline RepoAuthType Func::repoAwaitedReturnType() const {
243 return shared()->m_repoAwaitedReturnType;
246 inline bool Func::isReturnByValue() const {
247 return shared()->m_returnByValue;
250 inline bool Func::isReturnRef() const {
251 return m_attrs & AttrReference;
254 inline const TypeConstraint& Func::returnTypeConstraint() const {
255 return shared()->m_retTypeConstraint;
258 inline const StringData* Func::returnUserType() const {
259 return shared()->m_retUserType;
262 ///////////////////////////////////////////////////////////////////////////////
263 // Parameters.
265 inline const Func::ParamInfoVec& Func::params() const {
266 return shared()->m_params;
269 inline uint32_t Func::numParams() const {
270 assert(bool(m_attrs & AttrVariadicParam) != bool(m_paramCounts & 1));
271 assert((m_paramCounts >> 1) == params().size());
272 return (m_paramCounts) >> 1;
275 inline uint32_t Func::numNonVariadicParams() const {
276 assert(bool(m_attrs & AttrVariadicParam) != bool(m_paramCounts & 1));
277 assert((m_paramCounts >> 1) == params().size());
278 return (m_paramCounts - 1) >> 1;
281 inline bool Func::hasVariadicCaptureParam() const {
282 #ifdef DEBUG
283 assert(bool(m_attrs & AttrVariadicParam) ==
284 (numParams() && params()[numParams() - 1].variadic));
285 #endif
286 return m_attrs & AttrVariadicParam;
289 inline bool Func::discardExtraArgs() const {
290 return !(m_attrs & (AttrMayUseVV | AttrVariadicParam));
293 ///////////////////////////////////////////////////////////////////////////////
294 // Locals, iterators, and stack.
296 inline int Func::numLocals() const {
297 return shared()->m_numLocals;
300 inline int Func::numIterators() const {
301 return shared()->m_numIterators;
304 inline Id Func::numNamedLocals() const {
305 return shared()->m_localNames.size();
308 inline const StringData* Func::localVarName(Id id) const {
309 assert(id >= 0);
310 return id < numNamedLocals() ? shared()->m_localNames[id] : nullptr;
313 inline LowStringPtr const* Func::localNames() const {
314 return shared()->m_localNames.accessList();
317 inline int Func::maxStackCells() const {
318 return m_maxStackCells;
321 inline int Func::numSlotsInFrame() const {
322 return shared()->m_numLocals +
323 shared()->m_numIterators * (sizeof(Iter) / sizeof(Cell));
326 inline bool Func::hasForeignThis() const {
327 return attrs() & AttrHasForeignThis;
330 ///////////////////////////////////////////////////////////////////////////////
331 // Static locals.
333 inline const Func::SVInfoVec& Func::staticVars() const {
334 return shared()->m_staticVars;
337 inline bool Func::hasStaticLocals() const {
338 return !shared()->m_staticVars.empty();
341 inline int Func::numStaticLocals() const {
342 return shared()->m_staticVars.size();
345 ///////////////////////////////////////////////////////////////////////////////
346 // Definition context.
348 inline bool Func::isPseudoMain() const {
349 return m_name->empty();
352 inline bool Func::isMethod() const {
353 return !isPseudoMain() && (bool)baseCls();
356 inline bool Func::isFromTrait() const {
357 return m_attrs & AttrTrait;
360 inline bool Func::isPublic() const {
361 return m_attrs & AttrPublic;
364 inline bool Func::isStatic() const {
365 return m_attrs & AttrStatic;
368 inline bool Func::isStaticInPrologue() const {
369 return (m_attrs & (AttrStatic | AttrRequiresThis)) == AttrStatic;
372 inline bool Func::requiresThisInBody() const {
373 return (m_attrs & AttrRequiresThis) && !isClosureBody();
376 inline bool Func::hasThisVaries() const {
377 return mayHaveThis() && !requiresThisInBody();
380 inline bool Func::isAbstract() const {
381 return m_attrs & AttrAbstract;
384 inline bool Func::mayHaveThis() const {
385 return cls() && !isStatic();
388 inline bool Func::isPreFunc() const {
389 return m_isPreFunc;
392 inline bool Func::isMemoizeWrapper() const {
393 return shared()->m_isMemoizeWrapper;
396 inline const StringData* Func::memoizeImplName() const {
397 assertx(isMemoizeWrapper());
398 return genMemoizeImplName(name());
401 ///////////////////////////////////////////////////////////////////////////////
402 // Builtins.
404 inline bool Func::isBuiltin() const {
405 return m_attrs & AttrBuiltin;
408 inline bool Func::isCPPBuiltin() const {
409 auto const ex = extShared();
410 return UNLIKELY(!!ex) && ex->m_builtinFuncPtr;
413 inline bool Func::readsCallerFrame() const {
414 return m_attrs & AttrReadsCallerFrame;
417 inline bool Func::writesCallerFrame() const {
418 return m_attrs & AttrWritesCallerFrame;
421 inline bool Func::accessesCallerFrame() const {
422 return m_attrs & (AttrReadsCallerFrame | AttrWritesCallerFrame);
425 inline BuiltinFunction Func::builtinFuncPtr() const {
426 if (auto const ex = extShared()) {
427 if (UNLIKELY(ex->m_dynCallTarget != nullptr)) {
428 return ex->m_dynCallTarget->builtinFuncPtr();
430 return ex->m_builtinFuncPtr;
432 return nullptr;
435 inline BuiltinFunction Func::nativeFuncPtr() const {
436 if (auto const ex = extShared()) {
437 if (UNLIKELY(ex->m_dynCallTarget != nullptr)) {
438 return ex->m_dynCallTarget->nativeFuncPtr();
440 return ex->m_nativeFuncPtr;
442 return nullptr;
445 inline Func* Func::dynCallWrapper() const {
446 if (auto const ex = extShared()) {
447 return ex->m_dynCallWrapper;
449 return nullptr;
452 inline Func* Func::dynCallTarget() const {
453 if (auto const ex = extShared()) {
454 return ex->m_dynCallTarget;
456 return nullptr;
459 ///////////////////////////////////////////////////////////////////////////////
460 // Closures.
462 inline bool Func::isClosureBody() const {
463 return shared()->m_isClosureBody;
466 ///////////////////////////////////////////////////////////////////////////////
467 // Resumables.
469 inline bool Func::isAsync() const {
470 return shared()->m_isAsync;
473 inline bool Func::isGenerator() const {
474 return shared()->m_isGenerator;
477 inline bool Func::isPairGenerator() const {
478 return shared()->m_isPairGenerator;
481 inline bool Func::isAsyncFunction() const {
482 return isAsync() && !isGenerator();
485 inline bool Func::isNonAsyncGenerator() const {
486 return !isAsync() && isGenerator();
489 inline bool Func::isAsyncGenerator() const {
490 return isAsync() && isGenerator();
493 inline bool Func::isResumable() const {
494 return isAsync() || isGenerator();
497 ///////////////////////////////////////////////////////////////////////////////
498 // Methods.
500 inline Slot Func::methodSlot() const {
501 assert(isMethod());
502 return m_methodSlot;
505 inline bool Func::hasPrivateAncestor() const {
506 return m_hasPrivateAncestor;
509 ///////////////////////////////////////////////////////////////////////////////
510 // Magic methods.
512 inline bool Func::isGenerated() const {
513 return shared()->m_isGenerated;
516 inline bool Func::isDestructor() const {
517 return !strcmp(m_name->data(), "__destruct");
520 inline bool Func::isMagic() const {
521 return isMagicCallMethod() || isMagicCallStaticMethod();
524 inline bool Func::isMagicCallMethod() const {
525 return m_name->isame(s___call);
528 inline bool Func::isMagicCallStaticMethod() const {
529 return m_name->isame(s___callStatic);
532 inline bool Func::isSpecial(const StringData* name) {
533 return strncmp("86", name->data(), 2) == 0;
536 ///////////////////////////////////////////////////////////////////////////////
537 // Other attributes.
539 inline Attr Func::attrs() const {
540 return m_attrs;
543 inline const UserAttributeMap& Func::userAttributes() const {
544 return shared()->m_userAttributes;
547 inline bool Func::isUnique() const {
548 return m_attrs & AttrUnique;
551 inline bool Func::isPersistent() const {
552 return m_attrs & AttrPersistent;
555 inline bool Func::isNoInjection() const {
556 return m_attrs & AttrNoInjection;
559 inline bool Func::isSkipFrame() const {
560 return m_attrs & AttrSkipFrame;
563 inline bool Func::isFoldable() const {
564 return m_attrs & AttrIsFoldable;
567 inline bool Func::isParamCoerceMode() const {
568 return attrs() & (AttrParamCoerceModeFalse | AttrParamCoerceModeNull);
571 ///////////////////////////////////////////////////////////////////////////////
572 // Unit table entries.
574 inline const Func::EHEntVec& Func::ehtab() const {
575 return shared()->m_ehtab;
578 inline const Func::FPIEntVec& Func::fpitab() const {
579 return shared()->m_fpitab;
582 inline const FPIEnt* Func::findFPI(Offset o) const {
583 assertx(o >= base() && o < past());
584 return findFPI(fpitab().begin(), fpitab().end(), o);
587 ///////////////////////////////////////////////////////////////////////////////
588 // JIT data.
590 inline rds::Handle Func::funcHandle() const {
591 return m_cachedFunc.handle();
594 inline unsigned char* Func::getFuncBody() const {
595 return m_funcBody;
598 inline void Func::setFuncBody(unsigned char* fb) {
599 m_funcBody = fb;
602 inline uint8_t* Func::getPrologue(int index) const {
603 return m_prologueTable[index];
606 inline void Func::setPrologue(int index, unsigned char* tca) {
607 m_prologueTable[index] = tca;
610 ///////////////////////////////////////////////////////////////////////////////
611 // Other methods.
613 inline int8_t& Func::maybeIntercepted() const {
614 return m_maybeIntercepted;
617 ///////////////////////////////////////////////////////////////////////////////
618 // Public setters.
620 inline void Func::setAttrs(Attr attrs) {
621 m_attrs = attrs;
622 assertx(IMPLIES(accessesCallerFrame(), isBuiltin() && !isMethod()));
625 inline void Func::setBaseCls(Class* baseCls) {
626 m_baseCls = baseCls;
629 inline void Func::setFuncHandle(rds::Link<LowPtr<Func>> l) {
630 // TODO(#2950356): This assertion fails for create_function with an existing
631 // declared function named __lambda_func.
632 //assert(!m_cachedFunc.valid());
633 m_cachedFunc = l;
636 inline void Func::setHasPrivateAncestor(bool b) {
637 m_hasPrivateAncestor = b;
640 inline void Func::setMethodSlot(Slot s) {
641 assert(isMethod());
642 m_methodSlot = s;
645 inline void Func::setDynCallWrapper(Func* f) {
646 assert(accessesCallerFrame());
647 assert(f->accessesCallerFrame());
648 assert(!f->dynCallWrapper());
649 assert(extShared());
650 assert(!dynCallWrapper() || dynCallWrapper() == f);
651 assert(!dynCallTarget());
652 assert(!f->dynCallTarget() || f->dynCallTarget() == this);
653 extShared()->m_dynCallWrapper = f;
656 inline void Func::setDynCallTarget(Func* f) {
657 assert(accessesCallerFrame());
658 assert(f->accessesCallerFrame());
659 assert(!f->dynCallTarget());
660 assert(extShared());
661 assert(!dynCallTarget() || dynCallTarget() == f);
662 assert(!dynCallWrapper());
663 assert(!f->dynCallWrapper() || f->dynCallWrapper() == this);
664 extShared()->m_dynCallTarget = f;
667 //////////////////////////////////////////////////////////////////////
669 inline const Func::ExtendedSharedData* Func::extShared() const {
670 return const_cast<Func*>(this)->extShared();
673 inline Func::ExtendedSharedData* Func::extShared() {
674 auto const s = shared();
675 return UNLIKELY(s->m_hasExtendedSharedData)
676 ? static_cast<ExtendedSharedData*>(s)
677 : nullptr;
680 ///////////////////////////////////////////////////////////////////////////////