void nativeDataInstanceDtor(ObjectData* obj, const Class* cls) { assert(!cls->preClass()->builtinObjSize()); assert(!cls->preClass()->builtinODOffset()); obj->~ObjectData(); auto const nProps = size_t{cls->numDeclProperties()}; auto prop = reinterpret_cast<TypedValue*>(obj + 1); auto const stop = prop + nProps; for (; prop != stop; ++prop) { tvRefcountedDecRef(prop); } auto ndi = cls->getNativeDataInfo(); if (ndi->destroy) { ndi->destroy(obj); } auto node = getNativeNode(obj, ndi); if (ndi->sweep) { MM().removeNativeObject(node); } size_t size = ObjectData::sizeForNProps(nProps) + ndsize(obj, ndi); if (LIKELY(size <= kMaxSmallSize)) { return MM().freeSmallSize(node, size); } MM().freeBigSize(node, size); }
/* Classes with NativeData structs allocate extra memory prior * to the ObjectData. * * [NativeNode][padding][NativeData][ObjectData](prop0)...(propN) * /\ * ObjectData* points here * * padding is added by alignTypedValue(sizeof(NativeData)) to ensure * that ObjectData* falls on a 16-aligned boundary. NativeData is * sizeof(NativeData) (NativeDataInfo.sz) bytes for the custom struct. * NativeNode is a link in the NativeData sweep list for this ND block */ ObjectData* nativeDataInstanceCtor(Class* cls) { HPHP::Attr attrs = cls->attrs(); if (UNLIKELY(attrs & (AttrAbstract | AttrInterface | AttrTrait | AttrEnum))) { ObjectData::raiseAbstractClassError(cls); } auto ndi = cls->getNativeDataInfo(); size_t nativeDataSize = ndsize(ndi->sz); size_t nProps = cls->numDeclProperties(); size_t size = ObjectData::sizeForNProps(nProps) + nativeDataSize; auto node = reinterpret_cast<NativeNode*>( MM().objMalloc(size) ); node->obj_offset = nativeDataSize; node->hdr.kind = HeaderKind::NativeData; auto obj = new (reinterpret_cast<char*>(node) + nativeDataSize) ObjectData(cls); assert(obj->hasExactlyOneRef()); obj->setAttribute(static_cast<ObjectData::Attribute>(ndi->odattrs)); if (ndi->init) { ndi->init(obj); } if (ndi->sweep) { MM().addNativeObject(node); } if (UNLIKELY(cls->needsInitThrowable())) { obj->callCustomInstanceInit(); } return obj; }
size_t ndsize(const ObjectData* obj, const NativeDataInfo* ndi) { auto cls = obj->getVMClass(); if (cls == Generator::getClass() || cls == AsyncGenerator::getClass()) { return (cls == Generator::getClass()) ? Native::data<Generator>(obj)->resumable()->size() - sizeof(ObjectData) : Native::data<AsyncGenerator>(obj)->resumable()->size() - sizeof(ObjectData); } return ndsize(ndi->sz); }
void sweepNativeData(std::vector<NativeNode*>& natives) { while (!natives.empty()) { assert(natives.back()->sweep_index == natives.size() - 1); auto node = natives.back(); natives.pop_back(); auto obj = Native::obj(node); auto ndi = obj->getVMClass()->getNativeDataInfo(); assert(ndi->sweep); assert(node->obj_offset == ndsize(ndi)); ndi->sweep(obj); assert(invalidateNativeData(obj, ndi)); } }
/* Classes with NativeData structs allocate extra memory prior * to the ObjectData. * * [NativeNode][padding][NativeData][ObjectData](prop0)...(propN) * /\ * ObjectData* points here * * padding is added by alignTypedValue(sizeof(NativeData)) to ensure * that ObjectData* falls on a 16-aligned boundary. NativeData is * sizeof(NativeData) (NativeDataInfo.sz) bytes for the custom struct. * NativeNode is a link in the NativeData sweep list for this ND block */ ObjectData* nativeDataInstanceCtor(Class* cls) { auto ndi = cls->getNativeDataInfo(); size_t nativeDataSize = ndsize(ndi->sz); size_t nProps = cls->numDeclProperties(); size_t size = ObjectData::sizeForNProps(nProps) + nativeDataSize; auto node = reinterpret_cast<NativeNode*>( MM().objMalloc(size) ); node->obj_offset = nativeDataSize; node->hdr.kind = HeaderKind::NativeData; auto obj = new (reinterpret_cast<char*>(node) + nativeDataSize) ObjectData(cls); assert(obj->hasExactlyOneRef()); obj->setAttribute(static_cast<ObjectData::Attribute>(ndi->odattrs)); if (ndi->init) { ndi->init(obj); } if (ndi->sweep) { MM().addNativeObject(node); } return obj; }
DEBUG_ONLY static bool invalidateNativeData(ObjectData* obj, const NativeDataInfo* ndi) { memset(getSweepNode(obj, ndi), kSmartFreeFill, ndsize(ndi)); return true; }
inline NativeNode* getSweepNode(ObjectData *obj, const NativeDataInfo* ndi) { return reinterpret_cast<NativeNode*>( reinterpret_cast<char*>(obj) - ndsize(ndi) ); }