/* 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; }
/* Classes with NativeData structs allocate extra memory prior * to the ObjectData. * * [padding][NativeData][SweepNode][ObjectData](prop0)...(propN) * /\ * ObjectData* points here * * padding is added by alignTypedValue() to ensure that ObjectData* * falls on a memory alignment boundary * NativeData is info.sz bytes for the custom class Native Data * SweepNode is a link in the NativeData sweep list for this ND block */ ObjectData* nativeDataInstanceCtor(Class* cls) { Attr attrs = cls->attrs(); if (UNLIKELY(attrs & (AttrAbstract | AttrInterface | AttrTrait | AttrEnum))) { ObjectData::raiseAbstractClassError(cls); } auto ndi = cls->getNativeDataInfo(); size_t nativeDataSize = alignTypedValue(ndi->sz + sizeof(SweepNode)); size_t nProps = cls->numDeclProperties(); size_t size = ObjectData::sizeForNProps(nProps) + nativeDataSize; void *ptr = MM().objMallocLogged(size); auto obj = new (static_cast<char*>(ptr) + nativeDataSize) ObjectData(cls); obj->setAttribute(static_cast<ObjectData::Attribute>(ndi->odattrs)); if (ndi->init) { ndi->init(obj); } if (ndi->sweep) { prependSweepNode(getSweepNode(obj)); } if (UNLIKELY(cls->callsCustomInstanceInit())) { obj->callCustomInstanceInit(); } return obj; }
ObjectData* new_ZendObjectData_Instance(Class* cls) { TSRMLS_FETCH(); size_t nProps = cls->numDeclProperties(); size_t builtinObjSize = sizeof(c_ZendObjectData) - sizeof(ObjectData); size_t size = ObjectData::sizeForNProps(nProps) + builtinObjSize; auto obj = new (MM().objMallocLogged(size)) c_ZendObjectData(cls); zend_class_entry* ce = zend_hphp_class_to_class_entry(cls); auto create_func = ce->create_object; Class * current_class = cls; while (!create_func) { Class* parent = current_class->parent(); if (!parent) { break; } zend_class_entry* parent_ce = zend_hphp_class_to_class_entry(parent); create_func = parent_ce->create_object; current_class = parent; } zend_object_value ov; if (create_func) { ov = create_func(ce TSRMLS_CC); } else { zend_object *object; ov = zend_objects_new(&object, ce TSRMLS_CC); } obj->setHandle(ov.handle); if (UNLIKELY(cls->callsCustomInstanceInit())) { /* This must happen after the constructor finishes, because it can leak references to obj AND it can throw exceptions. If we have this in the ObjectData constructor, and it throws, obj will be partially destroyed (ie ~ObjectData will be called, resetting the vtable pointer) leaving dangling references to the object (eg in backtraces). */ obj->callCustomInstanceInit(); } return obj; }