Eliminate Continuation in local 0: JIT

The the code is being translated, we statically know offset of
Continuaton from its ActRec. Use this knowledge to emit data fetches
relative to ActRec rather than relative to Continuation loaded from
local 0.
Esse commit está contido em:
Mirek Klimos
2013-07-17 21:42:17 -07:00
commit de Sara Golemon
commit f11bab46b7
6 arquivos alterados com 173 adições e 77 exclusões
Arquivo normal → Arquivo executável
+36 -12
Ver Arquivo
@@ -1537,11 +1537,6 @@ ContEnter S0:FramePtr S1:TCA S2:ConstInt S3:FramePtr
object. S1 is the address to jump to. S2 is the bytecode offset in the
caller to return to when the generator body yields. S3 is the current frame.
ContRaiseCheck S0:Obj -> L
Checks whethre the continuation object S0 has raised an exception,
and if so branches to the label L.
ContPreNext S0:Obj -> L
Performs operations needed for the Continuation::next() method. This
@@ -1558,16 +1553,45 @@ ContSetRunning S0:Obj S1:ConstBool
Sets the continuation object S0 to running if S1 is true, or
sets it as stopped otherwise.
ContIncKey S0:Obj
ContArIncKey S0:FramePtr
Special-case key update for continuation S0, which increments the
key of a continuation if that continuation's key is an Int. This will
cause undefined behavior if the continuation's key is not an Int.
Special-case key update for continuation, ActRec of which is S0,
which increments the key of a continuation if that continuation's key
is an Int. This will cause undefined behavior if the continuation's key
is not an Int.
ContUpdateIdx S0:Obj S1:Int
ContArUpdateIdx S0:FramePtr S1:Int
Updates the internal index of continuation with S1 if necessary, i.e. if
S1 is larger than the index. S0 is the pointer to the embedded ActRec.
D:T LdContArRaw<T> S0:FramePtr S1:ConstInt
Loads raw data from the Continuation object ActRec of which is S0.
S1 is a constant from the RawMemSlot::Kind enum, which
describes the offset from the continuation base, and the size.
StContArRaw S0:FramePtr S1:ConstInt S2:??
Stores raw data into the Continuation object ActRec of which is S0.
S1 is a constant from the RawMemSlow::Kind enum, which
describes the offset from the continutaion base, and the size.
S2 is the value.
D:Cell LdContArValue S0:FramePtr
Loads 'value' from the Continuation object ActRec of which is S0.
StContArValue S0:FramePtr S1:Cell
Stores 'value' into the Continuation object ActRec of which is S0.
S1 is the new value.
D:Cell LdContArKey S0:FramePtr
Loads 'key' from the Continuation object ActRec of which is S0.
StContArKey S0:FramePtr S1:Cell
Stores 'key' into the Continuation object ActRec of which is S0.
S1 is the new value.
Updates the internal index of continuation S0 from S1 if necessary,
i.e. if S1 is larger than the index.
17. Debugging and instrumentation
Arquivo normal → Arquivo executável
Ver Arquivo
Arquivo normal → Arquivo executável
+86 -21
Ver Arquivo
@@ -5369,13 +5369,6 @@ void CodeGenerator::cgContSetRunning(IRInstruction* inst) {
}
}
void CodeGenerator::cgContDone(IRInstruction* inst) {
auto contReg = m_regs[inst->src(0)].reg();
const Offset stateOffset = c_Continuation::stateOffset();
m_as.storeb(0x2, contReg[stateOffset]);
}
void CodeGenerator::cgContValid(IRInstruction* inst) {
auto contReg = m_regs[inst->src(0)].reg();
auto destReg = m_regs[inst->dst()].reg();
@@ -5385,31 +5378,103 @@ void CodeGenerator::cgContValid(IRInstruction* inst) {
m_as.xorb(0x1, rbyte(destReg));
}
void CodeGenerator::cgContIncKey(IRInstruction* inst) {
auto contReg = m_regs[inst->src(0)].reg();
m_as.incq(contReg[CONTOFF(m_key) + TVOFF(m_data)]);
void CodeGenerator::cgContArIncKey(IRInstruction* inst) {
auto contArReg = m_regs[inst->src(0)].reg();
m_as.incq(contArReg[CONTOFF(m_key) + TVOFF(m_data) -
(int64_t)c_Continuation::getArOffset(curFunc())]);
}
void CodeGenerator::cgContUpdateIdx(IRInstruction* inst) {
auto contReg = m_regs[inst->src(0)].reg();
void CodeGenerator::cgContArUpdateIdx(IRInstruction* inst) {
auto contArReg = m_regs[inst->src(0)].reg();
int64_t off = CONTOFF(m_index) -
(int64_t)c_Continuation::getArOffset(curFunc());
auto newIdx = inst->src(1);
// this is hacky and awful oh god
if (newIdx->isConst()) {
auto const val = newIdx->getValRawInt();
m_as.emitImmReg(
val, m_rScratch);
m_as.cmpq (m_rScratch, contReg[CONTOFF(m_index)]);
m_as.cload_reg64_disp_reg64(
CC_G, contReg, CONTOFF(m_index), m_rScratch);
m_as.emitImmReg(val, m_rScratch);
m_as.cmpq (m_rScratch, contArReg[off]);
m_as.cload_reg64_disp_reg64(CC_G, contArReg, off, m_rScratch);
} else {
auto newIdxReg = m_regs[newIdx].reg();
m_as.loadq (contReg[CONTOFF(m_index)], m_rScratch);
m_as.loadq (contArReg[off], m_rScratch);
m_as.cmpq (m_rScratch, newIdxReg);
m_as.cmov_reg64_reg64(
CC_G, newIdxReg, m_rScratch);
m_as.cmov_reg64_reg64(CC_G, newIdxReg, m_rScratch);
}
m_as.storeq (m_rScratch, contReg[CONTOFF(m_index)]);
m_as.storeq (m_rScratch, contArReg[off]);
}
void CodeGenerator::cgLdContArRaw(IRInstruction* inst) {
auto destReg = m_regs[inst->dst()].reg();
auto contArReg = m_regs[inst->src(0)].reg();
int64_t kind = inst->src(1)->getValInt();
RawMemSlot& slot = RawMemSlot::Get(RawMemSlot::Kind(kind));
int64_t off = slot.offset() - (int64_t)c_Continuation::getArOffset(curFunc());
switch (slot.size()) {
case sz::byte: m_as.loadzbl(contArReg[off], r32(destReg)); break;
case sz::dword: m_as.loadl(contArReg[off], r32(destReg)); break;
case sz::qword: m_as.loadq(contArReg[off], destReg); break;
default: not_implemented();
}
}
void CodeGenerator::cgStContArRaw(IRInstruction* inst) {
auto contArReg = m_regs[inst->src(0)].reg();
int64_t kind = inst->src(1)->getValInt();
SSATmp* value = inst->src(2);
RawMemSlot& slot = RawMemSlot::Get(RawMemSlot::Kind(kind));
assert(value->type().equals(slot.type()));
int64_t off = slot.offset() - (int64_t)c_Continuation::getArOffset(curFunc());
if (value->isConst()) {
switch (slot.size()) {
case sz::byte: m_as.storeb(value->getValRawInt(), contArReg[off]); break;
case sz::dword: m_as.storel(value->getValRawInt(), contArReg[off]); break;
case sz::qword: m_as.storeq(value->getValRawInt(), contArReg[off]); break;
default: not_implemented();
}
} else {
auto valueReg = m_regs[value].reg();
switch (slot.size()) {
case sz::byte: m_as.storeb(rbyte(valueReg), contArReg[off]); break;
case sz::dword: m_as.storel(r32(valueReg), contArReg[off]); break;
case sz::qword: m_as.storeq(r64(valueReg), contArReg[off]); break;
default: not_implemented();
}
}
}
void CodeGenerator::cgLdContArValue(IRInstruction* inst) {
auto contArReg = m_regs[inst->src(0)].reg();
const int64_t valueOff = CONTOFF(m_value);
int64_t off = valueOff - (int64_t)c_Continuation::getArOffset(curFunc());
cgLoad(contArReg, off, inst);
}
void CodeGenerator::cgStContArValue(IRInstruction* inst) {
auto contArReg = m_regs[inst->src(0)].reg();
SSATmp* value = inst->src(1);
const int64_t valueOff = CONTOFF(m_value);
int64_t off = valueOff - (int64_t)c_Continuation::getArOffset(curFunc());
cgStore(contArReg, off, value, true);
}
void CodeGenerator::cgLdContArKey(IRInstruction* inst) {
auto contArReg = m_regs[inst->src(0)].reg();
const int64_t keyOff = CONTOFF(m_key);
int64_t off = keyOff - (int64_t)c_Continuation::getArOffset(curFunc());
cgLoad(contArReg, off, inst);
}
void CodeGenerator::cgStContArKey(IRInstruction* inst) {
auto contArReg = m_regs[inst->src(0)].reg();
SSATmp* value = inst->src(1);
const int64_t keyOff = CONTOFF(m_key);
int64_t off = keyOff - (int64_t)c_Continuation::getArOffset(curFunc());
cgStore(contArReg, off, value, true);
}
void CodeGenerator::cgIterInit(IRInstruction* inst) {
Arquivo normal → Arquivo executável
+34 -37
Ver Arquivo
@@ -1228,76 +1228,72 @@ void HhbcTranslator::emitContReturnControl() {
}
void HhbcTranslator::emitUnpackCont() {
gen(AssertLoc, Type::Obj, LocalId(0), m_tb->fp());
auto const cont = ldLoc(0);
push(gen(LdContArRaw, Type::Int, m_tb->fp(), cns(RawMemSlot::ContLabel)));
}
push(gen(LdRaw, Type::Int, cont, cns(RawMemSlot::ContLabel)));
void HhbcTranslator::emitContSuspendImpl(int64_t labelId) {
gen(ExitWhenSurprised, getExitSlowTrace());
// set m_value = popC();
auto const oldValue = gen(LdContArValue, Type::Cell, m_tb->fp());
gen(StContArValue, m_tb->fp(), popC());
gen(DecRef, oldValue);
// set m_label = labelId;
gen(StContArRaw, m_tb->fp(), cns(RawMemSlot::ContLabel), cns(labelId));
}
void HhbcTranslator::emitContSuspend(int64_t labelId) {
gen(ExitWhenSurprised, getExitSlowTrace());
gen(AssertLoc, Type::Obj, LocalId(0), m_tb->fp());
auto const cont = ldLoc(0);
auto const newVal = popC();
auto const oldValue = gen(LdProp, Type::Cell, cont, cns(CONTOFF(m_value)));
gen(StProp, cont, cns(CONTOFF(m_value)), newVal);
gen(DecRef, oldValue);
emitContSuspendImpl(labelId);
// take a fast path if this generator has no yield k => v;
if (curFunc()->isPairGenerator()) {
// this needs optimization
auto const idx = gen(LdRaw, Type::Int, cont, cns(RawMemSlot::ContIndex));
auto const idx = gen(LdContArRaw, Type::Int,
m_tb->fp(), cns(RawMemSlot::ContIndex));
auto const newIdx = gen(OpAdd, idx, cns(1));
gen(StRaw, cont, cns(RawMemSlot::ContIndex), newIdx);
auto const oldKey = gen(LdProp, Type::Cell, cont, cns(CONTOFF(m_key)));
gen(StProp, cont, cns(CONTOFF(m_key)), newIdx);
gen(StContArRaw, m_tb->fp(), cns(RawMemSlot::ContIndex), newIdx);
auto const oldKey = gen(LdContArKey, Type::Cell, m_tb->fp());
gen(StContArKey, m_tb->fp(), newIdx);
gen(DecRef, oldKey);
} else {
// we're guaranteed that the key is an int
gen(ContIncKey, cont);
gen(ContArIncKey, m_tb->fp());
}
gen(StRaw, cont, cns(RawMemSlot::ContLabel), cns(labelId));
// transfer control
emitContReturnControl();
}
void HhbcTranslator::emitContSuspendK(int64_t labelId) {
gen(ExitWhenSurprised, getExitSlowTrace());
emitContSuspendImpl(labelId);
gen(AssertLoc, Type::Obj, LocalId(0), m_tb->fp());
auto const cont = ldLoc(0);
auto const newVal = popC();
auto const oldValue = gen(LdProp, Type::Cell, cont, cns(CONTOFF(m_value)));
gen(StProp, cont, cns(CONTOFF(m_value)), newVal);
gen(DecRef, oldValue);
auto const newKey = popC();
auto const oldKey = gen(LdProp, Type::Cell, cont, cns(CONTOFF(m_key)));
gen(StProp, cont, cns(CONTOFF(m_key)), newKey);
auto const oldKey = gen(LdContArKey, Type::Cell, m_tb->fp());
gen(StContArKey, m_tb->fp(), newKey);
gen(DecRef, oldKey);
auto const keyType = newKey->type();
if (keyType.subtypeOf(Type::Int)) {
gen(ContUpdateIdx, cont, newKey);
gen(ContArUpdateIdx, m_tb->fp(), newKey);
}
gen(StRaw, cont, cns(RawMemSlot::ContLabel), cns(labelId));
// transfer control
emitContReturnControl();
}
void HhbcTranslator::emitContRetC() {
gen(AssertLoc, Type::Obj, LocalId(0), m_tb->fp());
auto const cont = ldLoc(0);
gen(ExitWhenSurprised, getExitSlowTrace());
gen(ContDone, cont);
auto const newVal = popC();
auto const oldVal = gen(LdProp, Type::Cell, cont, cns(CONTOFF(m_value)));
gen(StProp, cont, cns(CONTOFF(m_value)), newVal);
gen(DecRef, oldVal);
// set state to done
gen(StContArRaw, m_tb->fp(), cns(RawMemSlot::ContState),
cns(c_Continuation::Done));
// set m_value = popC();
auto const oldValue = gen(LdContArValue, Type::Cell, m_tb->fp());
gen(StContArValue, m_tb->fp(), popC());
gen(DecRef, oldValue);
// transfer control
emitContReturnControl();
@@ -1349,6 +1345,7 @@ void HhbcTranslator::emitContCurrent() {
void HhbcTranslator::emitContStopped() {
assert(curClass());
SSATmp* cont = gen(LdThis, m_tb->fp());
gen(ContSetRunning, cont, cns(false));
}
Arquivo normal → Arquivo executável
+1
Ver Arquivo
@@ -399,6 +399,7 @@ struct HhbcTranslator {
void emitContEnter(int32_t returnBcOffset);
void emitUnpackCont();
void emitContReturnControl();
void emitContSuspendImpl(int64_t labelId);
void emitContSuspend(int64_t labelId);
void emitContSuspendK(int64_t labelId);
void emitContRetC();
Arquivo normal → Arquivo executável
+16 -7
Ver Arquivo
@@ -480,13 +480,16 @@ O(ContEnter, ND, S(FramePtr) \
S(TCA) C(Int) S(FramePtr), E|Mem) \
O(ContPreNext, ND, S(Obj), E|Mem) \
O(ContStartedCheck, ND, S(Obj), E) \
O(ContSetRunning, ND, S(Obj) \
C(Bool), E|Mem) \
O(ContDone, ND, S(Obj), E|Mem) \
O(ContSetRunning, ND, S(Obj) C(Bool), E|Mem) \
O(ContValid, D(Bool), S(Obj), E) \
O(ContIncKey, ND, S(Obj), E|Mem) \
O(ContUpdateIdx, ND, S(Obj) \
S(Int), E|Mem) \
O(ContArIncKey, ND, S(FramePtr), E|Mem) \
O(ContArUpdateIdx, ND, S(FramePtr) S(Int), E|Mem) \
O(LdContArRaw, DParam, S(FramePtr) C(Int), NF) \
O(StContArRaw, ND, S(FramePtr) C(Int) S(Gen), E|Mem) \
O(LdContArValue, DParam, S(FramePtr), NF) \
O(StContArValue, ND, S(FramePtr) S(Gen), E|Mem|CRc|Refs) \
O(LdContArKey, DParam, S(FramePtr), NF) \
O(StContArKey, ND, S(FramePtr) S(Gen), E|Mem|CRc|Refs) \
O(IterInit, D(Bool), S(Arr,Obj) \
S(FramePtr) \
C(Int) \
@@ -842,7 +845,7 @@ class RawMemSlot {
public:
enum Kind {
ContLabel, ContIndex, ContARPtr,
ContLabel, ContIndex, ContARPtr, ContState,
StrLen, FuncNumParams, ContEntry, MisCtx, MaxKind
};
@@ -851,6 +854,7 @@ class RawMemSlot {
case ContLabel: return GetContLabel();
case ContIndex: return GetContIndex();
case ContARPtr: return GetContARPtr();
case ContState: return GetContState();
case StrLen: return GetStrLen();
case FuncNumParams: return GetFuncNumParams();
case ContEntry: return GetContEntry();
@@ -880,6 +884,11 @@ class RawMemSlot {
static RawMemSlot m(CONTOFF(m_arPtr), Transl::sz::qword, Type::StkPtr);
return m;
}
static RawMemSlot& GetContState() {
static RawMemSlot m(c_Continuation::stateOffset(),
Transl::sz::byte, Type::Int);
return m;
}
static RawMemSlot& GetStrLen() {
static RawMemSlot m(StringData::sizeOffset(), Transl::sz::dword, Type::Int);
return m;