diff --git a/hphp/runtime/ext/asio/continuation_wait_handle.cpp b/hphp/runtime/ext/asio/continuation_wait_handle.cpp index 64cb13e9f..bdb795d5b 100644 --- a/hphp/runtime/ext/asio/continuation_wait_handle.cpp +++ b/hphp/runtime/ext/asio/continuation_wait_handle.cpp @@ -98,7 +98,7 @@ void c_ContinuationWaitHandle::Create(c_Continuation* continuation) { if (UNLIKELY(continuation->m_index != -1)) { Object e(SystemLib::AllocInvalidOperationExceptionObject( - continuation->m_running + continuation->running() ? "Encountered an attempt to start currently running continuation" : "Encountered an attempt to start tainted continuation")); throw e; @@ -159,7 +159,7 @@ void c_ContinuationWaitHandle::run() { } // continuation finished, retrieve result from its m_value - if (m_continuation->m_done) { + if (m_continuation->done()) { markAsSucceeded(m_continuation->m_value.asTypedValue()); return; } diff --git a/hphp/runtime/ext/ext_continuation.cpp b/hphp/runtime/ext/ext_continuation.cpp index 3d319e135..479539eea 100644 --- a/hphp/runtime/ext/ext_continuation.cpp +++ b/hphp/runtime/ext/ext_continuation.cpp @@ -49,8 +49,9 @@ c_Continuation::c_Continuation(Class* cb) : m_index(-1LL), m_value(Variant::NullInit()), m_received(Variant::NullInit()), - m_done(false), m_running(false), - m_vmFunc(nullptr), m_label(0ll) { + m_origFunc(nullptr), + m_label(0) { + o_subclassData.u16 = 0; } c_Continuation::~c_Continuation() { @@ -66,7 +67,7 @@ c_Continuation::~c_Continuation() { if (ar->hasVarEnv()) { ar->getVarEnv()->detach(ar); } else { - frame_free_locals_inl(ar, m_vmFunc->numLocals()); + frame_free_locals_inl(ar, ar->m_func->numLocals()); } } @@ -74,6 +75,7 @@ void c_Continuation::t___construct() {} void c_Continuation::t_update(int64_t label, CVarRef value) { m_label = label; + assert(m_label == label); // check m_label for truncation m_value.assignVal(value); } @@ -128,7 +130,7 @@ void c_Continuation::t_rewind() { bool c_Continuation::t_valid() { const_assert(false); - return !m_done; + return !done(); } void c_Continuation::t_send(CVarRef v) { @@ -140,7 +142,11 @@ void c_Continuation::t_raise(CVarRef v) { } String c_Continuation::t_getorigfuncname() { - return String(const_cast(m_origFuncName)); + static auto const closureName = StringData::GetStaticString("{closure}"); + auto const origName = m_origFunc->isClosureBody() ? closureName + : m_origFunc->name(); + assert(origName->isStatic()); + return String(const_cast(origName)); } String c_Continuation::t_getcalledclass() { diff --git a/hphp/runtime/ext/ext_continuation.h b/hphp/runtime/ext/ext_continuation.h index 6cc57ffa9..0d5270fbb 100644 --- a/hphp/runtime/ext/ext_continuation.h +++ b/hphp/runtime/ext/ext_continuation.h @@ -38,22 +38,18 @@ class c_Continuation : public ExtObjectData { virtual void sweep(); void operator delete(void* p) { c_Continuation* this_ = (c_Continuation*)p; - DELETEOBJSZ(sizeForLocalsAndIters(this_->m_vmFunc->numLocals(), - this_->m_vmFunc->numIterators()))(this_); + DELETEOBJSZ((char*)(this_->m_arPtr + 1) - (char*)p)(this_); } explicit c_Continuation(Class* cls = c_Continuation::s_cls); ~c_Continuation(); public: - void init(const Func* vmFunc, - const StringData* origFuncName, + void init(const Func* origFunc, ObjectData* thisPtr, ArrayData* args) noexcept { - m_vmFunc = const_cast(vmFunc); - assert(m_vmFunc); - m_origFuncName = origFuncName; - assert(m_origFuncName->isStatic()); + m_origFunc = const_cast(origFunc); + assert(m_origFunc); if (thisPtr != nullptr) { m_obj = thisPtr; @@ -64,6 +60,17 @@ public: m_args = args; } + bool done() const { return o_subclassData.u8[0]; } + bool running() const { return o_subclassData.u8[1]; } + void setDone(bool done) { o_subclassData.u8[0] = done; } + void setRunning(bool running) { o_subclassData.u8[1] = running; } + static constexpr uint doneOffset() { + return offsetof(c_Continuation, o_subclassData); + } + static constexpr uint runningOffset() { + return offsetof(c_Continuation, o_subclassData) + 1; + } + void t___construct(); void t_update(int64_t label, CVarRef value); Object t_getwaithandle(); @@ -101,15 +108,15 @@ public: void call_raise(ObjectData* e); inline void preNext() { - if (m_done) { + if (done()) { throw_exception(Object(SystemLib::AllocExceptionObject( "Continuation is already finished"))); } - if (m_running) { + if (running()) { throw_exception(Object(SystemLib::AllocExceptionObject( "Continuation is already running"))); } - m_running = true; + setRunning(true); ++m_index; } @@ -126,13 +133,10 @@ public: int64_t m_index; Variant m_value; Variant m_received; - const StringData* m_origFuncName; - bool m_done; - bool m_running; + Func *m_origFunc; + int32_t m_label; int m_localsOffset; - Func *m_vmFunc; - int64_t m_label; ActRec* m_arPtr; p_ContinuationWaitHandle m_waitHandle; diff --git a/hphp/runtime/vm/bytecode.cpp b/hphp/runtime/vm/bytecode.cpp index 24de47be0..ae194d4ad 100644 --- a/hphp/runtime/vm/bytecode.cpp +++ b/hphp/runtime/vm/bytecode.cpp @@ -7036,12 +7036,7 @@ VMExecutionContext::createContinuationHelper(const Func* origFunc, ); cont->incRefCount(); cont->setNoDestruct(); - - static auto const closureName = StringData::GetStaticString("{closure}"); - auto const origName = origFunc->isClosureBody() ? closureName - : origFunc->name(); - - cont->init(genFunc, origName, thisPtr, args); + cont->init(origFunc, thisPtr, args); // The ActRec corresponding to the generator body lives as long as the object // does. We set it up once, here, and then just change FP to point to it when @@ -7290,7 +7285,7 @@ inline void OPTBLD_INLINE VMExecutionContext::iopContReceive(PC& pc) { inline void OPTBLD_INLINE VMExecutionContext::iopContRetC(PC& pc) { NEXT(); c_Continuation* cont = frame_continuation(m_fp); - cont->m_done = true; + cont->setDone(true); tvSetIgnoreRef(m_stack.topC(), cont->m_value.asTypedValue()); m_stack.popC(); @@ -7333,7 +7328,7 @@ inline void OPTBLD_INLINE VMExecutionContext::iopContValid(PC& pc) { NEXT(); TypedValue* tv = m_stack.allocTV(); tvWriteUninit(tv); - tvAsVariant(tv) = !this_continuation(m_fp)->m_done; + tvAsVariant(tv) = !this_continuation(m_fp)->done(); } inline void OPTBLD_INLINE VMExecutionContext::iopContCurrent(PC& pc) { @@ -7348,14 +7343,14 @@ inline void OPTBLD_INLINE VMExecutionContext::iopContCurrent(PC& pc) { inline void OPTBLD_INLINE VMExecutionContext::iopContStopped(PC& pc) { NEXT(); - this_continuation(m_fp)->m_running = false; + this_continuation(m_fp)->setRunning(false); } inline void OPTBLD_INLINE VMExecutionContext::iopContHandle(PC& pc) { NEXT(); c_Continuation* cont = this_continuation(m_fp); - cont->m_running = false; - cont->m_done = true; + cont->setRunning(false); + cont->setDone(true); cont->m_value.setNull(); Variant exn = tvAsVariant(m_stack.topTV()); diff --git a/hphp/runtime/vm/jit/codegen.cpp b/hphp/runtime/vm/jit/codegen.cpp index 4152b3b76..8cf5443e2 100644 --- a/hphp/runtime/vm/jit/codegen.cpp +++ b/hphp/runtime/vm/jit/codegen.cpp @@ -5135,17 +5135,17 @@ void CodeGenerator::cgLinkContVarEnv(IRInstruction* inst) { void CodeGenerator::cgContPreNext(IRInstruction* inst) { auto contReg = m_regs[inst->src(0)].reg(); - const Offset doneOffset = CONTOFF(m_done); - static_assert((doneOffset + 1) == CONTOFF(m_running), - "m_done should immediately precede m_running"); - // Check m_done and m_running at the same time - m_as.test_imm32_disp_reg32(0x0101, doneOffset, contReg); + const Offset doneOffset = c_Continuation::doneOffset(); + static_assert((doneOffset + 1) == c_Continuation::runningOffset(), + "done should immediately precede running"); + // Check done and running at the same time + m_as.test_imm16_disp_reg16(0x0101, doneOffset, contReg); emitFwdJcc(CC_NZ, inst->taken()); // ++m_index m_as.add_imm64_disp_reg64(0x1, CONTOFF(m_index), contReg); - // m_running = true - m_as.store_imm8_disp_reg(0x1, CONTOFF(m_running), contReg); + // running = true + m_as.store_imm8_disp_reg(0x1, c_Continuation::runningOffset(), contReg); } void CodeGenerator::cgContStartedCheck(IRInstruction* inst) { diff --git a/hphp/runtime/vm/jit/ir.h b/hphp/runtime/vm/jit/ir.h index 4284096cc..e5fcab39c 100644 --- a/hphp/runtime/vm/jit/ir.h +++ b/hphp/runtime/vm/jit/ir.h @@ -788,15 +788,17 @@ class RawMemSlot { : m_offset(offset), m_size(size), m_type(type), m_allowExtra(allowExtra) { } static RawMemSlot& GetContLabel() { - static RawMemSlot m(CONTOFF(m_label), Transl::sz::qword, Type::Int); + static RawMemSlot m(CONTOFF(m_label), Transl::sz::dword, Type::Int); return m; } static RawMemSlot& GetContDone() { - static RawMemSlot m(CONTOFF(m_done), Transl::sz::byte, Type::Bool); + static RawMemSlot m(c_Continuation::doneOffset(), Transl::sz::byte, + Type::Bool); return m; } static RawMemSlot& GetContRunning() { - static RawMemSlot m(CONTOFF(m_running), Transl::sz::byte, Type::Bool); + static RawMemSlot m(c_Continuation::runningOffset(), Transl::sz::byte, + Type::Bool); return m; } static RawMemSlot& GetContARPtr() { diff --git a/hphp/util/asm-x64.h b/hphp/util/asm-x64.h index 784f74f49..0ad538c46 100644 --- a/hphp/util/asm-x64.h +++ b/hphp/util/asm-x64.h @@ -1794,6 +1794,12 @@ struct X64Assembler { sz::byte); } + void emitIM16(X64Instr op, RegNumber br, RegNumber ir, int s, + int disp, ssize_t imm) ALWAYS_INLINE { + emitCMX(op, 0, br, ir, s, disp, reg::noreg, false, imm, true, + sz::word); + } + void emitIM32(X64Instr op, RegNumber br, RegNumber ir, int s, int disp, ssize_t imm) ALWAYS_INLINE { emitCMX(op, 0, br, ir, s, disp, reg::noreg, false, imm, true, @@ -2039,6 +2045,12 @@ public: inline void name ## _imm32_reg32(int64_t imm, RegNumber rdest) { \ emitIR32(instr_ ## name, rdest, safe_cast(imm)); \ } \ + /* op imm, disp(rdest) */ \ + inline void name ## _imm16_disp_reg16(int64_t imm, int disp, \ + RegNumber rdest) { \ + emitIM16(instr_ ## name, rdest, reg::noreg, \ + sz::byte, disp, safe_cast(imm)); \ + } \ /* opl imm, disp(rdest) */ \ inline void name ## _imm32_disp_reg32(int64_t imm, int disp, \ RegNumber rdest) { \