Added DecRefNZOrBranch and basic memory tracking to enable additional IncRef-DecRef elimation for Set[S,G,M].
Added a new IRInstruction, DecRefNZOrBranch, that decrefs but
branches out of the trace if the reference count is about to go to
zero. This guarantees that no destructor will run, and thus no memory
side effects on trace. Tracked the last value available in memory in
TraceBuilder and used it to convert DecRef instructions to
DecRefNZ. These 2 changes allow us to eliminate more IncRef-DecRef
pairs, in particular cases due to SetS, SetG & SetM; for example:
85: SetS
(20) t12:Cls = LdStack<Cls> t10:StkPtr, 1
(21) t13:Str = LdStack<Str> t10:StkPtr, 2
(23) t15:PtrToGen = LdClsPropAddr t12:Cls, t13:Str, Cls(0)
(24) DecRef t13:Str
(25) t16:PtrToCell = UnboxPtr t15:PtrToGen
(26) t17:Cell = LdMem<Cell> t16:PtrToCell, 0
(27) t18:Obj = IncRef t11:Obj
(28) StMem [t16:PtrToCell]:Obj, t11:Obj
(36) DecRefNZOrBranch t17:Cell -> L4
L5:
(38) DefLabel
86: PopC
(39) DecRefNZ t18:Obj
In the above example, memory tracking and DecRefNZOrBranch allowed us
to change instruction (39) from a DecRef to a DecRefNZ. Subsequent
dead-code elimination will remove the IncRef instruction (27) and
DecRefNZ instruction (39).
This diff does not handle SetM.
Esse commit está contido em:
@@ -2954,6 +2954,11 @@ void CodeGenerator::cgDecRefNZ(IRInstruction* inst) {
|
||||
cgDecRefWork(inst, false);
|
||||
}
|
||||
|
||||
void CodeGenerator::cgDecRefNZOrBranch(IRInstruction* inst) {
|
||||
assert(inst->getTaken());
|
||||
cgDecRefWork(inst, true);
|
||||
}
|
||||
|
||||
void CodeGenerator::emitSpillActRec(SSATmp* sp,
|
||||
int64_t spOffset,
|
||||
SSATmp* defAR) {
|
||||
|
||||
@@ -2137,10 +2137,17 @@ SSATmp* HhbcTranslator::unboxPtr(SSATmp* ptr) {
|
||||
}
|
||||
|
||||
void HhbcTranslator::emitBindMem(SSATmp* ptr, SSATmp* src) {
|
||||
SSATmp* prevValue = m_tb->genLdMem(ptr, Type::Gen, NULL);
|
||||
SSATmp* prevValue = m_tb->genLdMem(ptr, ptr->getType().deref(), NULL);
|
||||
pushIncRef(src);
|
||||
m_tb->genStMem(ptr, src, true);
|
||||
m_tb->genDecRef(prevValue);
|
||||
if (isRefCounted(src) && src->getType().canRunDtor()) {
|
||||
Block* exitBlock = getExitTrace(getNextSrcKey().offset())->front();
|
||||
Block::iterator markerInst = exitBlock->skipLabel();
|
||||
exitBlock->insert(++markerInst, m_irFactory.gen(DecRef, prevValue));
|
||||
m_tb->gen(DecRefNZOrBranch, exitBlock, prevValue);
|
||||
} else {
|
||||
m_tb->genDecRef(prevValue);
|
||||
}
|
||||
}
|
||||
|
||||
template<class CheckSupportedFun, class EmitLdAddrFun>
|
||||
@@ -2153,11 +2160,7 @@ void HhbcTranslator::emitBind(const StringData* name,
|
||||
}
|
||||
|
||||
void HhbcTranslator::emitSetMem(SSATmp* ptr, SSATmp* src) {
|
||||
ptr = unboxPtr(ptr);
|
||||
SSATmp* prevValue = m_tb->genLdMem(ptr, Type::Cell, nullptr);
|
||||
pushIncRef(src);
|
||||
m_tb->genStMem(ptr, src, true);
|
||||
m_tb->genDecRef(prevValue);
|
||||
emitBindMem(unboxPtr(ptr), src);
|
||||
}
|
||||
|
||||
template<class CheckSupportedFun, class EmitLdAddrFun>
|
||||
|
||||
@@ -564,6 +564,14 @@ private:
|
||||
const Func* getCurFunc() { return m_curFunc; }
|
||||
Class* getCurClass() { return getCurFunc()->cls(); }
|
||||
Unit* getCurUnit() { return getCurFunc()->unit(); }
|
||||
|
||||
SrcKey getCurSrcKey() { return SrcKey(m_curFunc, m_bcOff); }
|
||||
SrcKey getNextSrcKey() {
|
||||
SrcKey srcKey(m_curFunc, m_bcOff);
|
||||
srcKey.advance(m_curFunc->unit());
|
||||
return srcKey;
|
||||
}
|
||||
|
||||
/*
|
||||
* Helpers for resolving bytecode immediate ids.
|
||||
*/
|
||||
|
||||
@@ -316,6 +316,7 @@ O(DecRef, ND, S(Gen), N|E|Mem|CRc|Refs|K) \
|
||||
O(DecRefMem, ND, S(PtrToGen) \
|
||||
C(Int), N|E|Mem|CRc|Refs) \
|
||||
O(DecRefNZ, ND, S(Gen), Mem|CRc) \
|
||||
O(DecRefNZOrBranch, ND, S(Gen), Mem|CRc) \
|
||||
O(DefLabel, DMulti, SUnk, E) \
|
||||
O(Marker, ND, NA, E) \
|
||||
O(DefFP, D(StkPtr), NA, E) \
|
||||
|
||||
@@ -130,6 +130,7 @@ SSATmp* Simplifier::simplify(IRInstruction* inst) {
|
||||
case PrintInt:
|
||||
case PrintBool: return simplifyPrint(inst);
|
||||
case DecRef:
|
||||
case DecRefNZOrBranch:
|
||||
case DecRefNZ: return simplifyDecRef(inst);
|
||||
case IncRef: return simplifyIncRef(inst);
|
||||
case GuardType: return simplifyGuardType(inst);
|
||||
|
||||
@@ -43,6 +43,7 @@ TraceBuilder::TraceBuilder(Offset initialBcOffset,
|
||||
, m_fpValue(nullptr)
|
||||
, m_spOffset(initialSpOffsetFromFp)
|
||||
, m_thisIsAvailable(false)
|
||||
, m_refCountedMemValue(nullptr)
|
||||
, m_localValues(func->numLocals(), nullptr)
|
||||
, m_localTypes(func->numLocals(), Type::None)
|
||||
{
|
||||
@@ -160,6 +161,7 @@ SSATmp* TraceBuilder::genUnboxPtr(SSATmp* ptr) {
|
||||
*/
|
||||
bool TraceBuilder::isValueAvailable(SSATmp* tmp) const {
|
||||
while (true) {
|
||||
if (m_refCountedMemValue == tmp) return true;
|
||||
if (anyLocalHasValue(tmp)) return true;
|
||||
|
||||
IRInstruction* srcInstr = tmp->getInstruction();
|
||||
@@ -1152,6 +1154,12 @@ SSATmp* TraceBuilder::genIterFree(uint32_t iterId) {
|
||||
void TraceBuilder::updateTrackedState(IRInstruction* inst) {
|
||||
Opcode opc = inst->getOpcode();
|
||||
// Update tracked state of local values/types, stack/frame pointer, CSE, etc.
|
||||
|
||||
// kill tracked memory values
|
||||
if (inst->mayModifyRefs()) {
|
||||
m_refCountedMemValue = nullptr;
|
||||
}
|
||||
|
||||
switch (opc) {
|
||||
case Call: {
|
||||
m_spValue = inst->getDst();
|
||||
@@ -1208,8 +1216,25 @@ void TraceBuilder::updateTrackedState(IRInstruction* inst) {
|
||||
break;
|
||||
}
|
||||
|
||||
case StProp:
|
||||
case StPropNT:
|
||||
// fall through to StMem; stored value is the same arg number (2)
|
||||
case StMem:
|
||||
case StMemNT: {
|
||||
m_refCountedMemValue = inst->getSrc(2);
|
||||
break;
|
||||
}
|
||||
|
||||
case LdMem:
|
||||
case LdProp:
|
||||
case LdRef: {
|
||||
m_refCountedMemValue = inst->getDst();
|
||||
break;
|
||||
}
|
||||
|
||||
case StRefNT:
|
||||
case StRef: {
|
||||
m_refCountedMemValue = inst->getSrc(2);
|
||||
SSATmp* newRef = inst->getDst();
|
||||
SSATmp* prevRef = inst->getSrc(0);
|
||||
// update other tracked locals that also contain prevRef
|
||||
@@ -1312,6 +1337,7 @@ void TraceBuilder::saveState(Block* block) {
|
||||
state->thisAvailable = m_thisIsAvailable;
|
||||
state->localValues = m_localValues;
|
||||
state->localTypes = m_localTypes;
|
||||
state->refCountedMemValue = m_refCountedMemValue;
|
||||
m_snapshots[block] = state;
|
||||
}
|
||||
}
|
||||
@@ -1351,6 +1377,11 @@ void TraceBuilder::mergeState(State* state) {
|
||||
state->localTypes[i] = (t1 == Type::None || t2 == Type::None) ? Type::None :
|
||||
Type::unionOf(t1, t2);
|
||||
}
|
||||
// Reference counted memory value is available only if it is available on both
|
||||
// paths
|
||||
if (state->refCountedMemValue != m_refCountedMemValue) {
|
||||
state->refCountedMemValue = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void TraceBuilder::useState(Block* block) {
|
||||
@@ -1361,6 +1392,7 @@ void TraceBuilder::useState(Block* block) {
|
||||
m_fpValue = state->fpValue;
|
||||
m_spOffset = state->spOffset;
|
||||
m_thisIsAvailable = state->thisAvailable;
|
||||
m_refCountedMemValue = state->refCountedMemValue;
|
||||
m_localValues = std::move(state->localValues);
|
||||
m_localTypes = std::move(state->localTypes);
|
||||
delete state;
|
||||
@@ -1380,6 +1412,7 @@ void TraceBuilder::clearTrackedState() {
|
||||
m_spValue = m_fpValue = nullptr;
|
||||
m_spOffset = 0;
|
||||
m_thisIsAvailable = false;
|
||||
m_refCountedMemValue = nullptr;
|
||||
for (auto i = m_snapshots.begin(), end = m_snapshots.end(); i != end; ++i) {
|
||||
delete *i;
|
||||
*i = nullptr;
|
||||
@@ -1572,8 +1605,9 @@ void TraceBuilder::optimizeTrace() {
|
||||
// Could have converted a conditional branch to Jmp; clear next.
|
||||
block->setNext(nullptr);
|
||||
} else {
|
||||
// if the last instruction was a branch, we already saved state for the
|
||||
// target in updateTrackedState(). Now save state for the fall-through path.
|
||||
// if the last instruction was a branch, we already saved state
|
||||
// for the target in updateTrackedState(). Now save state for
|
||||
// the fall-through path.
|
||||
saveState(block->getNext());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -357,6 +357,7 @@ private:
|
||||
bool thisAvailable;
|
||||
std::vector<SSATmp*> localValues;
|
||||
std::vector<Type> localTypes;
|
||||
SSATmp* refCountedMemValue;
|
||||
};
|
||||
void saveState(Block*);
|
||||
void mergeState(State* s1);
|
||||
@@ -414,14 +415,17 @@ private:
|
||||
*/
|
||||
SSATmp* m_spValue; // current physical sp
|
||||
SSATmp* m_fpValue; // current physical fp
|
||||
int32_t m_spOffset; // offset of physical sp from physical fp
|
||||
int32_t m_spOffset; // offset of physical sp from physical fp
|
||||
SSATmp* m_curFunc; // current function context
|
||||
CSEHash m_cseHash;
|
||||
bool m_thisIsAvailable; // true only if current ActRec has non-null this
|
||||
|
||||
// state of values in memory
|
||||
SSATmp* m_refCountedMemValue;
|
||||
|
||||
// vectors that track local values & types
|
||||
std::vector<SSATmp*> m_localValues;
|
||||
std::vector<Type> m_localTypes;
|
||||
std::vector<Type> m_localTypes;
|
||||
};
|
||||
|
||||
template<>
|
||||
|
||||
Referência em uma Nova Issue
Bloquear um usuário