SSATmp* TraceBuilder::preOptimizeDecRefThis(IRInstruction* inst) { /* * If $this is available, convert to an instruction sequence that * doesn't need to test if it's already live. */ if (isThisAvailable()) { auto const thiss = gen(LdThis, m_fpValue); auto const thisInst = thiss->inst(); /* * DecRef optimization for $this in an inlined frame: if a caller * local contains the $this, we know it can't go to zero and can * switch DecRef to DecRefNZ. * * It's ok not to do DecRefThis (which normally nulls out the ActRec * $this), because there is still a reference to it in the caller * frame, so debug_backtrace() can't see a non-live pointer value. */ if (thisInst->op() == IncRef && callerHasValueAvailable(thisInst->src(0))) { gen(DecRefNZ, thiss); inst->convertToNop(); return nullptr; } assert(inst->src(0) == m_fpValue); gen(DecRef, thiss); inst->convertToNop(); return nullptr; } return nullptr; }
SSATmp* TraceBuilder::preOptimizeLdThis(IRInstruction* inst) { if (isThisAvailable()) { auto fpInst = inst->src(0)->inst(); if (fpInst->op() == DefInlineFP) { if (!m_frameSpansCall) { // check that we haven't nuked the SSATmp auto spInst = fpInst->src(0)->inst(); if (spInst->op() == SpillFrame && spInst->src(3)->isA(Type::Obj)) { return spInst->src(3); } } } inst->setTaken(nullptr); } return nullptr; }
SSATmp* TraceBuilder::preOptimizeLdCtx(IRInstruction* inst) { if (isThisAvailable()) return gen(LdThis, m_fpValue); return nullptr; }
SSATmp* TraceBuilder::preOptimizeLdThis(IRInstruction* inst) { if (isThisAvailable()) inst->setTaken(nullptr); return nullptr; }