/* * Helper for the freeLocalsHelpers which does the actual work of decrementing * a value's refcount or releasing it. * * This helper is reached via call from the various freeLocalHelpers. It * expects `tv' to be the address of a TypedValue with refcounted type `type' * (though it may be static, and we will do nothing in that case). * * The `live' registers must be preserved across any native calls (and * generally left untouched). */ static TCA emitDecRefHelper(CodeBlock& cb, DataBlock& data, CGMeta& fixups, PhysReg tv, PhysReg type, RegSet live) { return vwrap(cb, data, fixups, [&] (Vout& v) { // We use the first argument register for the TV data because we might pass // it to the native release call. It's not live when we enter the helper. auto const data = rarg(0); v << load{tv[TVOFF(m_data)], data}; auto destroy = [&](Vout& v) { PhysRegSaver prs{v, live}; auto const dword_size = sizeof(int64_t); // saving return value on the stack, but keeping it 16-byte aligned v << mflr{rfuncln()}; v << lea {rsp()[-2 * dword_size], rsp()}; v << store{rfuncln(), rsp()[0]}; // The refcount is exactly 1; release the value. // Avoid 'this' pointer overwriting by reserving it as an argument. v << callm{lookupDestructor(v, type), arg_regs(1)}; // Between where r1 is now and the saved RIP of the call into the // freeLocalsHelpers stub, we have all the live regs we pushed, plus the // stack size reserved for the LR saved right above and the LR offset in // the frame. v << syncpoint{makeIndirectFixup(prs.dwordsPushed())}; // fallthru // restore the return value from the stack v << load{rsp()[0], rfuncln()}; v << lea {rsp()[2 * dword_size], rsp()}; v << mtlr{rfuncln()}; }; auto const sf = emitCmpRefCount(v, OneReference, data); if (one_bit_refcount) { ifThen(v, CC_E, sf, destroy); } else { ifThen(v, CC_NL, sf, [&] (Vout& v) { // The refcount is positive, so the value is refcounted. We need to // either decref or release. ifThen(v, CC_NE, sf, [&] (Vout& v) { // The refcount is greater than 1; decref it. emitDecRefCount(v, data); v << ret{live}; }); destroy(v); }); } // Either we did a decref, or the value was static. v << ret{live}; }); }
/* * Helper for the freeLocalsHelpers which does the actual work of decrementing * a value's refcount or releasing it. * * This helper is reached via call from the various freeLocalHelpers. It * expects `tv' to be the address of a TypedValue with refcounted type `type' * (though it may be static, and we will do nothing in that case). * * The `live' registers must be preserved across any native calls (and * generally left untouched). */ static TCA emitDecRefHelper(CodeBlock& cb, DataBlock& data, CGMeta& fixups, PhysReg tv, PhysReg type, RegSet live) { return vwrap(cb, data, fixups, [&] (Vout& v) { // Set up frame linkage to avoid an indirect fixup. v << pushp{rlr(), rfp()}; v << copy{rsp(), rfp()}; // We use the first argument register for the TV data because we might pass // it to the native release call. It's not live when we enter the helper. auto const data = rarg(0); v << load{tv[TVOFF(m_data)], data}; auto const sf = v.makeReg(); v << cmplim{1, data[FAST_REFCOUNT_OFFSET], sf}; ifThen(v, CC_NL, sf, [&] (Vout& v) { // The refcount is positive, so the value is refcounted. We need to // either decref or release. ifThen(v, CC_NE, sf, [&] (Vout& v) { // The refcount is greater than 1; decref it. v << declm{data[FAST_REFCOUNT_OFFSET], v.makeReg()}; // Pop FP/LR and return v << popp{rfp(), rlr()}; v << ret{live}; }); // Note that the stack is aligned since we called to this helper from an // stack-unaligned stub. PhysRegSaver prs{v, live}; // The refcount is exactly 1; release the value. // Avoid 'this' pointer overwriting by reserving it as an argument. v << callm{lookupDestructor(v, type), arg_regs(1)}; // Between where %rsp is now and the saved RIP of the call into the // freeLocalsHelpers stub, we have all the live regs we pushed, plus the // saved RIP of the call from the stub to this helper. v << syncpoint{makeIndirectFixup(prs.dwordsPushed())}; // fallthru }); // Either we did a decref, or the value was static. // Pop FP/LR and return v << popp{rfp(), rlr()}; v << ret{live}; }); }