diff --git a/hphp/runtime/base/object-data.cpp b/hphp/runtime/base/object-data.cpp index f2cd53277b4216..3069ca87ac27bb 100644 --- a/hphp/runtime/base/object-data.cpp +++ b/hphp/runtime/base/object-data.cpp @@ -225,6 +225,10 @@ void ObjectData::release(ObjectData* obj, const Class* cls) noexcept { AARCH64_WALKABLE_FRAME(); } +void ObjectData::release2(ObjectData* obj) noexcept { + release(obj, obj->m_cls.get()); +} + /////////////////////////////////////////////////////////////////////////////// // class info diff --git a/hphp/runtime/base/object-data.h b/hphp/runtime/base/object-data.h index 5386a9b56db7ce..b2278a38272320 100644 --- a/hphp/runtime/base/object-data.h +++ b/hphp/runtime/base/object-data.h @@ -267,6 +267,12 @@ struct ObjectData : Countable, type_scan::MarkCollectable { */ static void release(ObjectData* obj, const Class* cls) noexcept; + /* + * An optimised version of the above function when the class can be loaded + * from the object. + */ + static void release2(ObjectData* obj) noexcept; + Class* getVMClass() const; StrNR getClassName() const; diff --git a/hphp/runtime/vm/class.cpp b/hphp/runtime/vm/class.cpp index 4f26cd4148ebeb..9f3b755f7f5951 100644 --- a/hphp/runtime/vm/class.cpp +++ b/hphp/runtime/vm/class.cpp @@ -5260,6 +5260,12 @@ std::vector prioritySerializeClasses() { return ret; } +Optional Class::optReleaseFunc() const { + if (m_releaseFunc == ObjectData::release) + return ObjectData::release2; + return std::nullopt; +} + /////////////////////////////////////////////////////////////////////////////// namespace { diff --git a/hphp/runtime/vm/class.h b/hphp/runtime/vm/class.h index b19dbf9e99596a..b1606b826d128f 100644 --- a/hphp/runtime/vm/class.h +++ b/hphp/runtime/vm/class.h @@ -142,6 +142,7 @@ using ClassPtr = AtomicSharedPackedPtr; // Since native instance dtors can be release functions, they have to have // compatible signatures. using ObjReleaseFunc = BuiltinDtorFunction; +using OptObjReleaseFunc = SmallPtr; using ObjectProps = std::conditional::type; @@ -825,6 +826,15 @@ struct Class : AtomicCountable { ObjReleaseFunc releaseFunc() const; + ///////////////////////////////////////////////////////////////////////////// + // Optimized Object release. + // + // Similar to the above, except only the object needs passing to the release + // function. The class is obtained directly from the object itself. If an + // optimized version does not exist, return std::nullopt. + + Optional optReleaseFunc() const; + ///////////////////////////////////////////////////////////////////////////// // Property metadata. [const] // diff --git a/hphp/runtime/vm/jit/irlower-refcount.cpp b/hphp/runtime/vm/jit/irlower-refcount.cpp index a4485dea39e43f..0419de4fc61b6b 100644 --- a/hphp/runtime/vm/jit/irlower-refcount.cpp +++ b/hphp/runtime/vm/jit/irlower-refcount.cpp @@ -240,6 +240,9 @@ CallSpec makeDtorCall(Vout& v, Type ty, Vloc loc, ArgGroup& args) { // a builtin, as only builtins can override release method and builtins // never subclass non-builtins. if (!isInterface(cls) && !cls->isBuiltin()) { + if (auto rf = cls->optReleaseFunc()) { + return CallSpec::direct(rf->get()); + } args.reg(emitLdObjClass(v, loc.reg(0), v.makeReg())); return CallSpec::direct(cls->releaseFunc().get()); }