diff --git a/hphp/doc/ir.specification b/hphp/doc/ir.specification old mode 100644 new mode 100755 index 3c3c2f155..bcdae453a --- a/hphp/doc/ir.specification +++ b/hphp/doc/ir.specification @@ -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 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 diff --git a/hphp/runtime/ext/ext_continuation.h b/hphp/runtime/ext/ext_continuation.h old mode 100644 new mode 100755 diff --git a/hphp/runtime/vm/jit/code-gen.cpp b/hphp/runtime/vm/jit/code-gen.cpp old mode 100644 new mode 100755 index 403afb967..5a1287e10 --- a/hphp/runtime/vm/jit/code-gen.cpp +++ b/hphp/runtime/vm/jit/code-gen.cpp @@ -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) { diff --git a/hphp/runtime/vm/jit/hhbc-translator.cpp b/hphp/runtime/vm/jit/hhbc-translator.cpp old mode 100644 new mode 100755 index b67285ce9..d854ab6a6 --- a/hphp/runtime/vm/jit/hhbc-translator.cpp +++ b/hphp/runtime/vm/jit/hhbc-translator.cpp @@ -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)); } diff --git a/hphp/runtime/vm/jit/hhbc-translator.h b/hphp/runtime/vm/jit/hhbc-translator.h old mode 100644 new mode 100755 index fd4f0a395..cfcd5fae4 --- a/hphp/runtime/vm/jit/hhbc-translator.h +++ b/hphp/runtime/vm/jit/hhbc-translator.h @@ -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(); diff --git a/hphp/runtime/vm/jit/ir.h b/hphp/runtime/vm/jit/ir.h old mode 100644 new mode 100755 index 66c5ec600..2ac47c142 --- a/hphp/runtime/vm/jit/ir.h +++ b/hphp/runtime/vm/jit/ir.h @@ -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;