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_CLASS_INL_H_
18 #error "class-inl.h should only be included by class.h"
21 #include "hphp/runtime/base/runtime-error.h"
22 #include "hphp/runtime/base/strings.h"
25 ///////////////////////////////////////////////////////////////////////////////
27 inline bool Class::isZombie() const {
28 return !m_cachedClass
.bound();
32 inline bool Class::validate() const {
34 assertx(m_magic
== kMagic
);
36 assertx(name()->checkSane());
40 ///////////////////////////////////////////////////////////////////////////////
41 // Class::PropInitVec.
43 inline Class::PropInitVec::PropInitVec() : m_data(nullptr),
48 inline Class::PropInitVec::iterator
Class::PropInitVec::begin() {
52 inline Class::PropInitVec::iterator
Class::PropInitVec::end() {
53 return m_data
+ m_size
;
56 inline size_t Class::PropInitVec::size() const {
60 inline TypedValueAux
& Class::PropInitVec::operator[](size_t i
) {
65 inline const TypedValueAux
& Class::PropInitVec::operator[](size_t i
) const {
70 inline bool Class::PropInitVec::reqAllocated() const {
71 return m_capacity
< 0;
74 ///////////////////////////////////////////////////////////////////////////////
75 // Pre- and post-allocations.
77 inline LowPtr
<Func
>* Class::funcVec() const {
78 return reinterpret_cast<LowPtr
<Func
>*>(
79 reinterpret_cast<uintptr_t>(this) -
80 m_funcVecLen
* sizeof(LowPtr
<Func
>)
84 inline void* Class::mallocPtr() const {
85 return reinterpret_cast<void*>(
86 reinterpret_cast<uintptr_t>(funcVec()) & ~(alignof(Class
) - 1)
90 inline const void* Class::mallocEnd() const {
91 return reinterpret_cast<const char*>(this)
92 + Class::classVecOff()
93 + classVecLen() * sizeof(*classVec());
96 inline const LowPtr
<Class
>* Class::classVec() const {
100 inline Class::veclen_t
Class::classVecLen() const {
101 return m_classVecLen
;
104 ///////////////////////////////////////////////////////////////////////////////
107 inline bool Class::classofNonIFace(const Class
* cls
) const {
108 assertx(!(cls
->attrs() & AttrInterface
));
109 if (m_classVecLen
>= cls
->m_classVecLen
) {
110 return (m_classVec
[cls
->m_classVecLen
-1] == cls
);
115 inline bool Class::classof(const Class
* cls
) const {
116 // If `cls' is an interface, we can simply check to see if cls is in
117 // this->m_interfaces. Otherwise, if `this' is not an interface, the
118 // classVec check will determine whether it's an instance of cls (including
119 // the case where this and cls are the same trait). Otherwise, `this' is an
120 // interface, and `cls' is not, so we need to return false. But the classVec
121 // check can never return true in that case (cls's classVec contains only
122 // non-interfaces, while this->classVec is either empty, or contains
124 if (UNLIKELY(cls
->attrs() & AttrInterface
)) {
125 return this == cls
||
126 m_interfaces
.lookupDefault(cls
->m_preClass
->name(), nullptr) == cls
;
128 return classofNonIFace(cls
);
131 inline bool Class::ifaceofDirect(const StringData
* name
) const {
132 return m_interfaces
.contains(name
);
135 ///////////////////////////////////////////////////////////////////////////////
138 inline const StringData
* Class::name() const {
139 return m_preClass
->name();
142 inline const PreClass
* Class::preClass() const {
143 return m_preClass
.get();
146 inline Class
* Class::parent() const {
147 return m_parent
.get();
150 inline StrNR
Class::nameStr() const {
151 return m_preClass
->nameStr();
154 inline StrNR
Class::parentStr() const {
155 return m_preClass
->parentStr();
158 inline Attr
Class::attrs() const {
159 assertx(Attr(m_attrCopy
) == m_preClass
->attrs());
160 return Attr(m_attrCopy
);
163 inline bool Class::rtAttribute(RuntimeAttribute a
) const {
164 return m_RTAttrs
& a
;
167 inline void Class::initRTAttributes(uint8_t a
) {
171 inline bool Class::isPersistent() const {
172 return attrs() & AttrPersistent
;
175 inline bool Class::isDynamicallyConstructible() const {
176 return attrs() & AttrDynamicallyConstructible
;
179 ///////////////////////////////////////////////////////////////////////////////
182 inline const Func
* Class::getCtor() const {
186 inline const Func
* Class::getToString() const {
190 inline const Func
* Class::get86pinit() const {
191 return m_pinitVec
.back();
194 inline const Func
* Class::get86sinit() const {
195 return m_sinitVec
.back();
198 inline const Func
* Class::get86linit() const {
199 return m_linitVec
.back();
202 ///////////////////////////////////////////////////////////////////////////////
205 inline bool Class::isBuiltin() const {
206 return attrs() & AttrBuiltin
;
209 inline BuiltinCtorFunction
Class::instanceCtor() const {
210 return m_extra
->m_instanceCtor
;
213 inline BuiltinDtorFunction
Class::instanceDtor() const {
214 return m_extra
->m_instanceDtor
;
217 ///////////////////////////////////////////////////////////////////////////////
220 inline size_t Class::numMethods() const {
221 return m_methods
.size();
224 inline Func
* Class::getMethod(Slot idx
) const {
225 auto funcVec
= (LowPtr
<Func
>*)this;
226 return funcVec
[-((int32_t)idx
+ 1)];
229 inline void Class::setMethod(Slot idx
, Func
* func
) {
230 auto funcVec
= (LowPtr
<Func
>*)this;
231 funcVec
[-((int32_t)idx
+ 1)] = func
;
234 inline Func
* Class::lookupMethod(const StringData
* methName
) const {
235 Slot
* idx
= m_methods
.find(methName
);
236 if (!idx
) return nullptr;
237 return getMethod(*idx
);
240 ///////////////////////////////////////////////////////////////////////////////
241 // Property metadata.
243 inline size_t Class::numDeclProperties() const {
244 return m_declProperties
.size();
247 inline size_t Class::numStaticProperties() const {
248 return m_staticProperties
.size();
251 inline uint32_t Class::declPropNumAccessible() const {
252 return m_declPropNumAccessible
;
255 inline folly::Range
<const Class::Prop
*> Class::declProperties() const {
256 return m_declProperties
.range();
259 inline folly::Range
<const Class::SProp
*> Class::staticProperties() const {
260 return m_staticProperties
.range();
263 inline Slot
Class::lookupDeclProp(const StringData
* propName
) const {
264 return m_declProperties
.findIndex(propName
);
267 inline Slot
Class::lookupSProp(const StringData
* sPropName
) const {
268 return m_staticProperties
.findIndex(sPropName
);
271 extern const StaticString s_86reified_prop
;
273 inline Slot
Class::lookupReifiedInitProp() const {
274 return m_declProperties
.findIndex(s_86reified_prop
.get());
277 inline RepoAuthType
Class::declPropRepoAuthType(Slot index
) const {
278 return m_declProperties
[index
].repoAuthType
;
281 inline RepoAuthType
Class::staticPropRepoAuthType(Slot index
) const {
282 return m_staticProperties
[index
].repoAuthType
;
285 inline const TypeConstraint
& Class::declPropTypeConstraint(Slot index
) const {
286 return m_declProperties
[index
].typeConstraint
;
289 inline const TypeConstraint
& Class::staticPropTypeConstraint(Slot index
) const {
290 return m_staticProperties
[index
].typeConstraint
;
293 inline bool Class::hasDeepInitProps() const {
294 return m_hasDeepInitProps
;
297 inline bool Class::forbidsDynamicProps() const {
298 return attrs() & AttrForbidDynamicProps
;
301 inline bool Class::hasImmutableProps() const {
302 return attrs() & AttrHasImmutable
;
305 inline bool Class::serialize() const {
306 if (m_serialized
) return false;
311 inline bool Class::wasSerialized() const {
315 ///////////////////////////////////////////////////////////////////////////////
316 // Property initialization.
318 inline bool Class::needInitialization() const {
319 return m_needInitialization
;
322 inline bool Class::maybeRedefinesPropTypes() const {
323 return m_maybeRedefsPropTy
;
326 inline bool Class::needsPropInitialValueCheck() const {
327 return m_needsPropInitialCheck
;
330 inline const Class::PropInitVec
& Class::declPropInit() const {
331 return m_declPropInit
;
334 inline const VMFixedVector
<const Func
*>& Class::pinitVec() const {
338 inline rds::Handle
Class::checkedPropTypeRedefinesHandle() const {
339 assertx(m_maybeRedefsPropTy
);
340 m_extra
->m_checkedPropTypeRedefs
.bind(rds::Mode::Normal
);
341 return m_extra
->m_checkedPropTypeRedefs
.handle();
344 inline rds::Handle
Class::checkedPropInitialValuesHandle() const {
345 assertx(m_needsPropInitialCheck
);
346 m_extra
->m_checkedPropInitialValues
.bind(rds::Mode::Normal
);
347 return m_extra
->m_checkedPropInitialValues
.handle();
350 ///////////////////////////////////////////////////////////////////////////////
353 inline void Class::initPropHandle() const {
354 m_propDataCache
.bind(rds::Mode::Normal
);
357 inline rds::Handle
Class::propHandle() const {
358 return m_propDataCache
.handle();
361 inline rds::Handle
Class::sPropInitHandle() const {
362 return m_sPropCacheInit
.handle();
365 inline rds::Handle
Class::sPropHandle(Slot index
) const {
366 return sPropLink(index
).handle();
369 inline rds::Link
<StaticPropData
, rds::Mode::NonNormal
>
370 Class::sPropLink(Slot index
) const {
371 assertx(m_sPropCacheInit
.bound());
372 assertx(numStaticProperties() > index
);
373 return m_sPropCache
[index
];
376 inline rds::Link
<bool, rds::Mode::NonLocal
> Class::sPropInitLink() const {
377 return m_sPropCacheInit
;
380 ///////////////////////////////////////////////////////////////////////////////
383 inline size_t Class::numConstants() const {
384 return m_constants
.size();
387 inline const Class::Const
* Class::constants() const {
388 return m_constants
.accessList();
391 inline bool Class::hasConstant(const StringData
* clsCnsName
) const {
392 // m_constants.contains(clsCnsName) returns abstract constants
393 auto clsCnsInd
= m_constants
.findIndex(clsCnsName
);
394 return (clsCnsInd
!= kInvalidSlot
) &&
395 !m_constants
[clsCnsInd
].isAbstract() &&
396 !m_constants
[clsCnsInd
].isType();
399 inline bool Class::hasTypeConstant(const StringData
* typeConstName
,
400 bool includeAbs
) const {
401 auto typeConstInd
= m_constants
.findIndex(typeConstName
);
402 return (typeConstInd
!= kInvalidSlot
) &&
403 (!m_constants
[typeConstInd
].isAbstract() || includeAbs
) &&
404 m_constants
[typeConstInd
].isType();
407 ///////////////////////////////////////////////////////////////////////////////
408 // Interfaces and traits.
410 inline folly::Range
<const ClassPtr
*> Class::declInterfaces() const {
411 return folly::range(m_declInterfaces
.begin(),
412 m_declInterfaces
.end());
415 inline const Class::InterfaceMap
& Class::allInterfaces() const {
419 inline Slot
Class::traitsBeginIdx() const {
420 return m_extra
->m_traitsBeginIdx
;
423 inline Slot
Class::traitsEndIdx() const {
424 return m_extra
->m_traitsEndIdx
;
427 inline const VMCompactVector
<ClassPtr
>& Class::usedTraitClasses() const {
428 return m_extra
->m_usedTraits
;
431 inline const Class::TraitAliasVec
& Class::traitAliases() const {
432 return m_extra
->m_traitAliases
;
435 inline void Class::addTraitAlias(const PreClass::TraitAliasRule
& rule
) const {
437 m_extra
.raw()->m_traitAliases
.push_back(rule
.asNamePair());
440 inline const Class::RequirementMap
& Class::allRequirements() const {
441 return m_requirements
;
444 ///////////////////////////////////////////////////////////////////////////////
447 inline bool Class::checkInstanceBit(unsigned int bit
) const {
449 return m_instanceBits
[bit
];
452 ///////////////////////////////////////////////////////////////////////////////
453 // Throwable initialization.
455 inline bool Class::needsInitThrowable() const {
456 return m_needsInitThrowable
;
459 ///////////////////////////////////////////////////////////////////////////////
462 inline rds::Handle
Class::classHandle() const {
463 return m_cachedClass
.handle();
466 inline void Class::setClassHandle(rds::Link
<LowPtr
<Class
>,
467 rds::Mode::NonLocal
> link
) const {
468 assertx(!m_cachedClass
.bound());
469 m_cachedClass
= link
;
472 inline Class
* Class::getCached() const {
473 return m_cachedClass
.isInit() ? *m_cachedClass
: nullptr;
476 inline void Class::setCached() {
477 m_cachedClass
.initWith(this);
480 ///////////////////////////////////////////////////////////////////////////////
483 inline const Native::NativeDataInfo
* Class::getNativeDataInfo() const {
484 return m_extra
->m_nativeDataInfo
;
487 ///////////////////////////////////////////////////////////////////////////////
488 // Closure subclasses.
490 inline bool Class::isScopedClosure() const {
494 inline const Class::ScopedClonesMap
& Class::scopedClones() const {
495 return m_extra
->m_scopedClones
;
498 /////////////////////////////////////////////////////////////////////////////
501 inline size_t Class::numMemoSlots() const {
502 return m_extra
->m_nextMemoSlot
;
505 inline bool Class::hasMemoSlots() const {
506 return numMemoSlots() > 0;
509 inline std::pair
<Slot
, bool> Class::memoSlotForFunc(FuncId func
) const {
510 assertx(hasMemoSlots());
511 auto const it
= m_extra
->m_memoMappings
.find(func
);
512 if (it
!= m_extra
->m_memoMappings
.end()) return it
->second
;
513 // Each mapping is only stored in the class which defines it, so recurse up to
514 // the parent. We should only be calling this with functions which have a memo
515 // slot, so assert if we reach the end without finding a slot.
516 if (m_parent
) return m_parent
->memoSlotForFunc(func
);
517 always_assert(false);
520 ///////////////////////////////////////////////////////////////////////////////
523 inline MaybeDataType
Class::enumBaseTy() const {
527 inline EnumValues
* Class::getEnumValues() const {
528 return m_extra
->m_enumValues
.load(std::memory_order_relaxed
);
531 ///////////////////////////////////////////////////////////////////////////////
534 inline void Class::allocExtraData() const {
536 m_extra
= new ExtraData();
540 ///////////////////////////////////////////////////////////////////////////////
541 // Non-member functions.
543 inline Attr
classKindAsAttr(ClassKind kind
) {
544 return static_cast<Attr
>(kind
);
547 inline bool isTrait(const Class
* cls
) {
548 return cls
->attrs() & AttrTrait
;
551 inline bool isEnum(const Class
* cls
) {
552 return cls
->attrs() & AttrEnum
;
555 inline bool isInterface(const Class
* cls
) {
556 return cls
->attrs() & AttrInterface
;
559 inline bool isNormalClass(const Class
* cls
) {
560 return !(cls
->attrs() & (AttrTrait
| AttrInterface
| AttrEnum
));
563 inline bool isAbstract(const Class
* cls
) {
564 return cls
->attrs() & AttrAbstract
;
567 inline bool classHasPersistentRDS(const Class
* cls
) {
568 return cls
!= nullptr &&
569 rds::isPersistentHandle(cls
->classHandle());
572 inline bool classMayHaveMagicPropMethods(const Class
* cls
) {
573 auto constexpr no_overrides
=
574 AttrNoOverrideMagicGet
|
575 AttrNoOverrideMagicSet
|
576 AttrNoOverrideMagicIsset
|
577 AttrNoOverrideMagicUnset
;
579 return (cls
->attrs() & no_overrides
) != no_overrides
;
582 inline const StringData
* classToStringHelper(const Class
* cls
) {
583 if (RuntimeOption::EvalRaiseClassConversionWarning
) {
584 raise_warning("Class to string conversion");
588 ///////////////////////////////////////////////////////////////////////////////