Compute ambient coeffects and write to coeffects local
[hiphop-php.git] / hphp / runtime / vm / class-inl.h
blob582fde4240e26f47c4ba4306f947e2f20badd15a
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 template <bool is_const>
44 Class::PropInitVec::iterator_impl<is_const>::iterator_impl(
45 tv_iter_t tv,
46 bit_iter_t bit
47 ) : m_val(tv), m_bit(bit) {}
49 template <bool is_const>
50 bool Class::PropInitVec::iterator_impl<is_const>::operator==(
51 const Class::PropInitVec::iterator_impl<is_const>& o
52 ) const {
53 return m_val == o.m_val;
56 template <bool is_const>
57 bool Class::PropInitVec::iterator_impl<is_const>::operator!=(
58 const Class::PropInitVec::iterator_impl<is_const>& o
59 ) const {
60 return !(*this == o);
63 template <bool is_const>
64 Class::PropInitVec::iterator_impl<is_const>&
65 Class::PropInitVec::iterator_impl<is_const>::operator++() {
66 ++m_bit;
67 ++m_val;
68 return *this;
71 template <bool is_const>
72 Class::PropInitVec::iterator_impl<is_const>
73 Class::PropInitVec::iterator_impl<is_const>::operator++(int) {
74 auto const ret = *this;
75 ++(*this);
76 return ret;
79 template <bool is_const>
80 Class::PropInitVec::Entry<is_const>
81 Class::PropInitVec::iterator_impl<is_const>::operator*() const {
82 return Entry<is_const>{m_val, *m_bit};
85 template <bool is_const>
86 Class::PropInitVec::Entry<is_const>
87 Class::PropInitVec::iterator_impl<is_const>::operator->() const {
88 return *(*this);
91 inline Class::PropInitVec::PropInitVec() : m_data(nullptr),
92 m_size(0),
93 m_capacity(0) {}
95 template <typename T>
96 inline Class::PropInitVec::Entry<false>
97 Class::PropInitVec::operator[](T i) {
98 auto lval = m_data->at(i);
99 auto deepInit = deepInitBits()[i];
100 return Entry<false>{lval, deepInit};
103 template <typename T>
104 inline Class::PropInitVec::Entry<true>
105 Class::PropInitVec::operator[](T i) const {
106 auto lval = m_data->at(i);
107 auto deepInit = deepInitBits()[i];
108 return Entry<true>{lval, deepInit};
111 inline Class::PropInitVec::iterator Class::PropInitVec::begin() {
112 return iterator{m_data->iteratorAt(0),
113 deepInitBits().iteratorAt(0)};
116 inline Class::PropInitVec::iterator Class::PropInitVec::end() {
117 return iterator{m_data->iteratorAt(m_size),
118 deepInitBits().iteratorAt(m_size)};
121 inline Class::PropInitVec::const_iterator Class::PropInitVec::cbegin() const {
122 return const_iterator{
123 const_cast<const ObjectProps*>(m_data)->iteratorAt(0),
124 deepInitBits().iteratorAt(0)};
127 inline Class::PropInitVec::const_iterator Class::PropInitVec::cend() const {
128 return const_iterator{
129 const_cast<const ObjectProps*>(m_data)->iteratorAt(m_size),
130 deepInitBits().iteratorAt(m_size)};
133 inline size_t Class::PropInitVec::size() const {
134 return m_size;
137 inline bool Class::PropInitVec::reqAllocated() const {
138 return m_capacity < 0;
141 inline const ObjectProps* Class::PropInitVec::data() const {
142 return m_data;
145 inline BitsetView<false> Class::PropInitVec::deepInitBits() {
146 auto const cap = m_capacity < 0 ? ~m_capacity : m_capacity;
147 return BitsetView<false>{reinterpret_cast<unsigned char*>(m_data) +
148 ObjectProps::sizeFor(cap)};
151 inline BitsetView<true>
152 Class::PropInitVec::deepInitBits() const {
153 auto const cap = m_capacity < 0 ? ~m_capacity : m_capacity;
154 return BitsetView<true>{reinterpret_cast<const unsigned char*>(m_data) +
155 ObjectProps::sizeFor(cap)};
159 ///////////////////////////////////////////////////////////////////////////////
160 // Pre- and post-allocations.
162 inline LowPtr<Func>* Class::funcVec() const {
163 return reinterpret_cast<LowPtr<Func>*>(
164 reinterpret_cast<uintptr_t>(this) -
165 m_funcVecLen * sizeof(LowPtr<Func>)
169 inline void* Class::mallocPtr() const {
170 return reinterpret_cast<void*>(
171 reinterpret_cast<uintptr_t>(funcVec()) & ~(alignof(Class) - 1)
175 inline const void* Class::mallocEnd() const {
176 return reinterpret_cast<const char*>(this)
177 + Class::classVecOff()
178 + classVecLen() * sizeof(*classVec());
181 inline const LowPtr<Class>* Class::classVec() const {
182 return m_classVec;
185 inline Class::veclen_t Class::classVecLen() const {
186 return m_classVecLen;
189 ///////////////////////////////////////////////////////////////////////////////
190 // Ancestry.
192 inline bool Class::classofNonIFace(const Class* cls) const {
193 assertx(!(cls->attrs() & AttrInterface));
194 if (m_classVecLen >= cls->m_classVecLen) {
195 return (m_classVec[cls->m_classVecLen-1] == cls);
197 return false;
200 inline bool Class::classof(const Class* cls) const {
201 // If `cls' is an interface, we can simply check to see if cls is in
202 // this->m_interfaces. Otherwise, if `this' is not an interface, the
203 // classVec check will determine whether it's an instance of cls (including
204 // the case where this and cls are the same trait). Otherwise, `this' is an
205 // interface, and `cls' is not, so we need to return false. But the classVec
206 // check can never return true in that case (cls's classVec contains only
207 // non-interfaces, while this->classVec is either empty, or contains
208 // interfaces).
209 if (UNLIKELY(cls->attrs() & AttrInterface)) {
210 return this == cls ||
211 m_interfaces.lookupDefault(cls->m_preClass->name(), nullptr) == cls;
213 if (UNLIKELY(cls->attrs() & this->attrs() & AttrEnum)) {
214 if (this == cls) {
215 return true;
216 } else if (cls->m_extra && cls->m_extra->m_includedEnums.size() != 0) {
217 cls->m_extra->m_includedEnums.lookupDefault(this->m_preClass->name(), nullptr) == this;
220 return classofNonIFace(cls);
223 inline bool Class::subtypeOf(const Class* cls) const { return classof(cls); }
225 inline bool Class::ifaceofDirect(const StringData* name) const {
226 return m_interfaces.contains(name);
229 ///////////////////////////////////////////////////////////////////////////////
230 // Basic info.
232 inline const StringData* Class::name() const {
233 return m_preClass->name();
236 inline const PreClass* Class::preClass() const {
237 return m_preClass.get();
240 inline Class* Class::parent() const {
241 return m_parent.get();
244 inline StrNR Class::nameStr() const {
245 return m_preClass->nameStr();
248 inline StrNR Class::parentStr() const {
249 return m_preClass->parentStr();
252 inline Attr Class::attrs() const {
253 assertx(Attr(m_attrCopy) == m_preClass->attrs());
254 return Attr(m_attrCopy);
257 inline bool Class::rtAttribute(RuntimeAttribute a) const {
258 return m_RTAttrs & a;
261 inline void Class::initRTAttributes(uint8_t a) {
262 m_RTAttrs |= a;
265 inline bool Class::isUnique() const {
266 return attrs() & AttrUnique;
269 inline bool Class::isPersistent() const {
270 return attrs() & AttrPersistent;
273 inline bool Class::isDynamicallyConstructible() const {
274 return attrs() & AttrDynamicallyConstructible;
277 inline folly::Optional<int64_t> Class::dynConstructSampleRate() const {
278 auto const rate = preClass()->dynConstructSampleRate();
279 if (rate < 0) return {};
280 return rate;
284 ///////////////////////////////////////////////////////////////////////////////
285 // Magic methods.
287 inline const Func* Class::getCtor() const {
288 return m_ctor;
291 inline const Func* Class::getToString() const {
292 return m_toString;
295 inline const Func* Class::get86pinit() const {
296 return m_pinitVec.back();
299 inline const Func* Class::get86sinit() const {
300 return m_sinitVec.back();
303 inline const Func* Class::get86linit() const {
304 return m_linitVec.back();
307 ///////////////////////////////////////////////////////////////////////////////
308 // Builtin classes.
310 inline bool Class::isBuiltin() const {
311 return attrs() & AttrBuiltin;
314 template <bool Unlocked>
315 inline BuiltinCtorFunction Class::instanceCtor() const {
316 return Unlocked ? m_extra->m_instanceCtorUnlocked : m_extra->m_instanceCtor;
319 inline BuiltinDtorFunction Class::instanceDtor() const {
320 return m_extra->m_instanceDtor;
323 ///////////////////////////////////////////////////////////////////////////////
324 // Object release.
326 inline ObjReleaseFunc Class::releaseFunc() const {
327 return m_releaseFunc;
330 inline uint32_t Class::memoSize() const {
331 return m_memoSize;
334 inline uint8_t Class::sizeIdx() const {
335 return m_sizeIdx;
338 ///////////////////////////////////////////////////////////////////////////////
339 // Methods.
341 inline size_t Class::numMethods() const {
342 return m_methods.size();
345 inline Func* Class::getMethod(Slot idx) const {
346 auto funcVec = (LowPtr<Func>*)this;
347 return funcVec[-((int32_t)idx + 1)];
350 inline void Class::setMethod(Slot idx, Func* func) {
351 auto funcVec = (LowPtr<Func>*)this;
352 funcVec[-((int32_t)idx + 1)] = func;
355 inline Func* Class::lookupMethod(const StringData* methName) const {
356 Slot* idx = m_methods.find(methName);
357 if (!idx) return nullptr;
358 return getMethod(*idx);
361 ///////////////////////////////////////////////////////////////////////////////
362 // Property metadata.
364 inline size_t Class::numDeclProperties() const {
365 return m_declProperties.size();
368 inline size_t Class::numStaticProperties() const {
369 return m_staticProperties.size();
372 inline uint32_t Class::declPropNumAccessible() const {
373 return m_declPropNumAccessible;
376 inline folly::Range<const Class::Prop*> Class::declProperties() const {
377 return m_declProperties.range();
380 inline folly::Range<const Class::SProp*> Class::staticProperties() const {
381 return m_staticProperties.range();
384 inline Slot Class::lookupDeclProp(const StringData* propName) const {
385 return m_declProperties.findIndex(propName);
388 inline Slot Class::lookupSProp(const StringData* sPropName) const {
389 return m_staticProperties.findIndex(sPropName);
392 inline Slot Class::lookupReifiedInitProp() const {
393 return m_declProperties.findIndex(s_86reified_prop.get());
396 inline bool Class::hasReifiedGenerics() const {
397 return m_hasReifiedGenerics;
400 inline bool Class::hasReifiedParent() const {
401 return m_hasReifiedParent;
404 inline RepoAuthType Class::declPropRepoAuthType(Slot index) const {
405 return m_declProperties[index].repoAuthType;
408 inline RepoAuthType Class::staticPropRepoAuthType(Slot index) const {
409 return m_staticProperties[index].repoAuthType;
412 inline const TypeConstraint& Class::declPropTypeConstraint(Slot index) const {
413 return m_declProperties[index].typeConstraint;
416 inline const TypeConstraint& Class::staticPropTypeConstraint(Slot index) const {
417 return m_staticProperties[index].typeConstraint;
420 inline bool Class::hasDeepInitProps() const {
421 return m_hasDeepInitProps;
424 inline bool Class::forbidsDynamicProps() const {
425 return attrs() & AttrForbidDynamicProps;
428 inline bool Class::serialize() const {
429 if (m_serialized) return false;
430 m_serialized = true;
431 return true;
434 inline bool Class::wasSerialized() const {
435 return m_serialized;
438 ///////////////////////////////////////////////////////////////////////////////
439 // Property initialization.
441 inline bool Class::needInitialization() const {
442 return m_needInitialization;
445 inline bool Class::maybeRedefinesPropTypes() const {
446 return m_maybeRedefsPropTy;
449 inline bool Class::needsPropInitialValueCheck() const {
450 return m_needsPropInitialCheck;
453 inline const Class::PropInitVec& Class::declPropInit() const {
454 return m_declPropInit;
457 inline const VMFixedVector<const Func*>& Class::pinitVec() const {
458 return m_pinitVec;
461 inline rds::Handle Class::checkedPropTypeRedefinesHandle() const {
462 assertx(m_maybeRedefsPropTy);
463 m_extra->m_checkedPropTypeRedefs.bind(
464 rds::Mode::Normal,
465 rds::LinkName{"PropTypeRedefs", name()}
467 return m_extra->m_checkedPropTypeRedefs.handle();
470 inline rds::Handle Class::checkedPropInitialValuesHandle() const {
471 assertx(m_needsPropInitialCheck);
472 m_extra->m_checkedPropInitialValues.bind(
473 rds::Mode::Normal,
474 rds::LinkName{"PropInitialValues", name()}
476 return m_extra->m_checkedPropInitialValues.handle();
479 ///////////////////////////////////////////////////////////////////////////////
480 // Property storage.
482 inline void Class::initPropHandle() const {
483 m_propDataCache.bind(
484 rds::Mode::Normal,
485 rds::LinkName{"PropDataCache", name()}
489 inline rds::Handle Class::propHandle() const {
490 return m_propDataCache.handle();
493 inline rds::Handle Class::sPropInitHandle() const {
494 return m_sPropCacheInit.handle();
497 inline rds::Handle Class::sPropHandle(Slot index) const {
498 return sPropLink(index).handle();
501 inline rds::Link<StaticPropData, rds::Mode::NonNormal>
502 Class::sPropLink(Slot index) const {
503 assertx(m_sPropCacheInit.bound());
504 assertx(numStaticProperties() > index);
505 return m_sPropCache[index];
508 inline rds::Link<bool, rds::Mode::NonLocal> Class::sPropInitLink() const {
509 return m_sPropCacheInit;
512 ///////////////////////////////////////////////////////////////////////////////
513 // Constants.
515 inline size_t Class::numConstants() const {
516 return m_constants.size();
519 inline const Class::Const* Class::constants() const {
520 return m_constants.accessList();
523 inline bool Class::hasConstant(const StringData* clsCnsName) const {
524 // m_constants.contains(clsCnsName) returns abstract constants
525 auto clsCnsInd = m_constants.findIndex(clsCnsName);
526 return (clsCnsInd != kInvalidSlot) &&
527 !m_constants[clsCnsInd].isAbstract() &&
528 m_constants[clsCnsInd].kind() == ConstModifiers::Kind::Value;
531 inline bool Class::hasTypeConstant(const StringData* typeConstName,
532 bool includeAbs) const {
533 auto typeConstInd = m_constants.findIndex(typeConstName);
534 return (typeConstInd != kInvalidSlot) &&
535 (!m_constants[typeConstInd].isAbstract() || includeAbs) &&
536 m_constants[typeConstInd].kind() == ConstModifiers::Kind::Type;
539 ///////////////////////////////////////////////////////////////////////////////
540 // Interfaces and traits.
542 inline folly::Range<const ClassPtr*> Class::declInterfaces() const {
543 return folly::range(m_declInterfaces.begin(),
544 m_declInterfaces.end());
547 inline const Class::InterfaceMap& Class::allInterfaces() const {
548 return m_interfaces;
551 inline const bool Class::hasIncludedEnums() const {
552 return m_extra && (m_extra->m_includedEnums.size() != 0);
555 inline const Class::IncludedEnumMap& Class::allIncludedEnums() const {
556 return m_extra->m_includedEnums;
559 inline Slot Class::traitsBeginIdx() const {
560 return m_extra->m_traitsBeginIdx;
563 inline Slot Class::traitsEndIdx() const {
564 return m_extra->m_traitsEndIdx;
567 inline const VMCompactVector<ClassPtr>& Class::usedTraitClasses() const {
568 return m_extra->m_usedTraits;
571 inline const Class::TraitAliasVec& Class::traitAliases() const {
572 return m_extra->m_traitAliases;
575 inline void Class::addTraitAlias(const PreClass::TraitAliasRule& rule) const {
576 allocExtraData();
577 m_extra.raw()->m_traitAliases.push_back(rule.asNamePair());
580 inline const Class::RequirementMap& Class::allRequirements() const {
581 return m_requirements;
584 ///////////////////////////////////////////////////////////////////////////////
585 // Instance bits.
587 inline bool Class::checkInstanceBit(unsigned int bit) const {
588 assertx(bit > 0);
589 return m_instanceBits[bit];
592 ///////////////////////////////////////////////////////////////////////////////
593 // Throwable initialization.
595 inline bool Class::needsInitThrowable() const {
596 return m_needsInitThrowable;
599 ///////////////////////////////////////////////////////////////////////////////
600 // JIT data.
602 inline rds::Handle Class::classHandle() const {
603 return m_cachedClass.handle();
606 inline void Class::setClassHandle(rds::Link<LowPtr<Class>,
607 rds::Mode::NonLocal> link) const {
608 assertx(!m_cachedClass.bound());
609 m_cachedClass = link;
612 inline Class* Class::getCached() const {
613 return m_cachedClass.isInit() ? *m_cachedClass : nullptr;
616 inline void Class::setCached() {
617 m_cachedClass.initWith(this);
620 ///////////////////////////////////////////////////////////////////////////////
621 // Native data.
623 inline const Native::NativeDataInfo* Class::getNativeDataInfo() const {
624 return m_extra->m_nativeDataInfo;
627 ///////////////////////////////////////////////////////////////////////////////
628 // Closure subclasses.
630 inline bool Class::isScopedClosure() const {
631 return m_scoped;
634 inline const Class::ScopedClonesMap& Class::scopedClones() const {
635 return m_extra->m_scopedClones;
638 /////////////////////////////////////////////////////////////////////////////
639 // Memoization
641 inline size_t Class::numMemoSlots() const {
642 return m_extra->m_nextMemoSlot;
645 inline bool Class::hasMemoSlots() const {
646 return numMemoSlots() > 0;
649 inline std::pair<Slot, bool> Class::memoSlotForFunc(FuncId func) const {
650 assertx(hasMemoSlots());
651 auto const it = m_extra->m_memoMappings.find(func);
652 if (it != m_extra->m_memoMappings.end()) return it->second;
653 // Each mapping is only stored in the class which defines it, so recurse up to
654 // the parent. We should only be calling this with functions which have a memo
655 // slot, so assert if we reach the end without finding a slot.
656 if (m_parent) return m_parent->memoSlotForFunc(func);
657 always_assert(false);
660 ///////////////////////////////////////////////////////////////////////////////
661 // Other methods.
663 inline MaybeDataType Class::enumBaseTy() const {
664 return m_enumBaseTy;
667 inline EnumValues* Class::getEnumValues() const {
668 return m_extra->m_enumValues.load(std::memory_order_relaxed);
671 ///////////////////////////////////////////////////////////////////////////////
672 // ExtraData.
674 inline void Class::allocExtraData() const {
675 if (!m_extra) {
676 m_extra = new ExtraData();
680 ///////////////////////////////////////////////////////////////////////////////
681 // Non-member functions.
683 inline Attr classKindAsAttr(ClassKind kind) {
684 return static_cast<Attr>(kind);
687 inline bool isTrait(const Class* cls) {
688 return cls->attrs() & AttrTrait;
691 inline bool isEnum(const Class* cls) {
692 return cls->attrs() & AttrEnum;
695 inline bool isInterface(const Class* cls) {
696 return cls->attrs() & AttrInterface;
699 inline bool isNormalClass(const Class* cls) {
700 return !(cls->attrs() & (AttrTrait | AttrInterface | AttrEnum));
703 inline bool isAbstract(const Class* cls) {
704 return cls->attrs() & AttrAbstract;
707 inline bool classHasPersistentRDS(const Class* cls) {
708 return cls != nullptr &&
709 rds::isPersistentHandle(cls->classHandle());
712 inline const StringData* classToStringHelper(const Class* cls) {
713 if (RuntimeOption::EvalRaiseClassConversionWarning) {
714 raise_warning(Strings::CLASS_TO_STRING);
716 return cls->name();
719 ///////////////////////////////////////////////////////////////////////////////
720 // Lookup.
722 inline Class* Class::lookup(const NamedEntity* ne) {
723 return ne->getCachedClass();
726 inline Class* Class::lookup(const StringData* name) {
727 return lookup(NamedEntity::get(name));
730 inline const Class* Class::lookupUniqueInContext(const NamedEntity* ne,
731 const Class* ctx,
732 const Unit* unit) {
733 Class* cls = ne->clsList();
734 if (UNLIKELY(cls == nullptr)) return nullptr;
735 if (cls->attrs() & AttrUnique) return cls;
736 if (unit && cls->preClass()->unit() == unit) return cls;
737 if (!ctx) return nullptr;
738 return ctx->getClassDependency(cls->name());
741 inline const Class* Class::lookupUniqueInContext(const StringData* name,
742 const Class* ctx,
743 const Unit* unit) {
744 return lookupUniqueInContext(NamedEntity::get(name), ctx, unit);
747 inline Class* Class::load(const StringData* name) {
748 if (name->isSymbol()) {
749 if (auto const result = name->getCachedClass()) return result;
751 auto const orig = name;
753 auto const result = [&]() -> Class* {
754 String normStr;
755 auto ne = NamedEntity::get(name, true, &normStr);
757 // Try to fetch from cache
758 Class* class_ = ne->getCachedClass();
759 if (LIKELY(class_ != nullptr)) return class_;
761 // Normalize the namespace
762 if (normStr) name = normStr.get();
764 // Autoload the class
765 return load(ne, name);
766 }();
768 if (orig->isSymbol() && result && classHasPersistentRDS(result)) {
769 const_cast<StringData*>(orig)->setCachedClass(result);
771 return result;
774 inline Class* Class::get(const StringData* name, bool tryAutoload) {
775 String normStr;
776 auto ne = NamedEntity::get(name, true, &normStr);
777 if (normStr) {
778 name = normStr.get();
780 return get(ne, name, tryAutoload);
783 ///////////////////////////////////////////////////////////////////////////////