Basic JIT support for Records
[hiphop-php.git] / hphp / runtime / vm / class-inl.h
blob808e6dbb0ff83aa04e7a1dadfd51ac75e445cd7f
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_CLASS_INL_H_
18 #error "class-inl.h should only be included by class.h"
19 #endif
21 #include "hphp/runtime/base/runtime-error.h"
22 #include "hphp/runtime/base/strings.h"
24 namespace HPHP {
25 ///////////////////////////////////////////////////////////////////////////////
27 inline bool Class::isZombie() const {
28 return !m_cachedClass.bound();
32 inline bool Class::validate() const {
33 #ifndef NDEBUG
34 assertx(m_magic == kMagic);
35 #endif
36 assertx(name()->checkSane());
37 return true;
40 ///////////////////////////////////////////////////////////////////////////////
41 // Class::PropInitVec.
43 inline Class::PropInitVec::PropInitVec() : m_data(nullptr),
44 m_size(0),
45 m_capacity(0) {
48 inline Class::PropInitVec::iterator Class::PropInitVec::begin() {
49 return m_data;
52 inline Class::PropInitVec::iterator Class::PropInitVec::end() {
53 return m_data + m_size;
56 inline size_t Class::PropInitVec::size() const {
57 return m_size;
60 inline TypedValueAux& Class::PropInitVec::operator[](size_t i) {
61 assertx(i < m_size);
62 return m_data[i];
65 inline const TypedValueAux& Class::PropInitVec::operator[](size_t i) const {
66 assertx(i < m_size);
67 return m_data[i];
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 {
97 return m_classVec;
100 inline Class::veclen_t Class::classVecLen() const {
101 return m_classVecLen;
104 ///////////////////////////////////////////////////////////////////////////////
105 // Ancestry.
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);
112 return false;
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
123 // interfaces).
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 ///////////////////////////////////////////////////////////////////////////////
136 // Basic info.
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) {
168 m_RTAttrs |= a;
171 inline bool Class::isPersistent() const {
172 return attrs() & AttrPersistent;
175 inline bool Class::isDynamicallyConstructible() const {
176 return attrs() & AttrDynamicallyConstructible;
179 ///////////////////////////////////////////////////////////////////////////////
180 // Magic methods.
182 inline const Func* Class::getCtor() const {
183 return m_ctor;
186 inline const Func* Class::getToString() const {
187 return m_toString;
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 ///////////////////////////////////////////////////////////////////////////////
203 // Builtin classes.
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 ///////////////////////////////////////////////////////////////////////////////
218 // Methods.
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;
307 m_serialized = true;
308 return true;
311 inline bool Class::wasSerialized() const {
312 return m_serialized;
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 {
335 return m_pinitVec;
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 ///////////////////////////////////////////////////////////////////////////////
351 // Property storage.
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 ///////////////////////////////////////////////////////////////////////////////
381 // Constants.
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 {
416 return m_interfaces;
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 {
436 allocExtraData();
437 m_extra.raw()->m_traitAliases.push_back(rule.asNamePair());
440 inline const Class::RequirementMap& Class::allRequirements() const {
441 return m_requirements;
444 ///////////////////////////////////////////////////////////////////////////////
445 // Instance bits.
447 inline bool Class::checkInstanceBit(unsigned int bit) const {
448 assertx(bit > 0);
449 return m_instanceBits[bit];
452 ///////////////////////////////////////////////////////////////////////////////
453 // Throwable initialization.
455 inline bool Class::needsInitThrowable() const {
456 return m_needsInitThrowable;
459 ///////////////////////////////////////////////////////////////////////////////
460 // JIT data.
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 ///////////////////////////////////////////////////////////////////////////////
481 // Native data.
483 inline const Native::NativeDataInfo* Class::getNativeDataInfo() const {
484 return m_extra->m_nativeDataInfo;
487 ///////////////////////////////////////////////////////////////////////////////
488 // Closure subclasses.
490 inline bool Class::isScopedClosure() const {
491 return m_scoped;
494 inline const Class::ScopedClonesMap& Class::scopedClones() const {
495 return m_extra->m_scopedClones;
498 /////////////////////////////////////////////////////////////////////////////
499 // Memoization
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 ///////////////////////////////////////////////////////////////////////////////
521 // Other methods.
523 inline MaybeDataType Class::enumBaseTy() const {
524 return m_enumBaseTy;
527 inline EnumValues* Class::getEnumValues() const {
528 return m_extra->m_enumValues.load(std::memory_order_relaxed);
531 ///////////////////////////////////////////////////////////////////////////////
532 // ExtraData.
534 inline void Class::allocExtraData() const {
535 if (!m_extra) {
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");
586 return cls->name();
588 ///////////////////////////////////////////////////////////////////////////////