Bug 1032869 - Part 5: Add JSOP_DEBUGAFTERYIELD to fix up resumed generator BaselineFrames. (r=jandem)
authorShu-yu Guo <shu@rfrn.org>
Thu, 13 Nov 2014 14:39:41 -0800
changeset 215653 d65f01b9e6c6a57fb9a49fe246a8d378fa1e4369
parent 215652 06d07689a043ede470605c5f75692f6bc100e153
child 215654 2e8496d85ba2410228a73b685e39970aff9cbbbe
push id51810
push usershu@rfrn.org
push dateThu, 13 Nov 2014 22:39:12 +0000
treeherdermozilla-inbound@d65f01b9e6c6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjandem
bugs1032869
milestone36.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1032869 - Part 5: Add JSOP_DEBUGAFTERYIELD to fix up resumed generator BaselineFrames. (r=jandem)
js/src/frontend/BytecodeEmitter.cpp
js/src/jit/BaselineCompiler.cpp
js/src/jit/BaselineCompiler.h
js/src/jit/VMFunctions.cpp
js/src/jit/VMFunctions.h
js/src/vm/Interpreter.cpp
js/src/vm/Opcodes.h
js/src/vm/Xdr.h
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -3012,17 +3012,20 @@ EmitYieldOp(ExclusiveContext *cx, Byteco
     uint32_t yieldIndex = bce->yieldOffsetList.length();
     if (yieldIndex >= JS_BIT(24)) {
         bce->reportError(nullptr, JSMSG_TOO_MANY_YIELDS);
         return false;
     }
 
     SET_UINT24(bce->code(off), yieldIndex);
 
-    return bce->yieldOffsetList.append(bce->offset());
+    if (!bce->yieldOffsetList.append(bce->offset()))
+        return false;
+
+    return Emit1(cx, bce, JSOP_DEBUGAFTERYIELD) >= 0;
 }
 
 bool
 frontend::EmitFunctionScript(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *body)
 {
     if (!bce->updateLocalsToFrameSlots())
         return false;
 
--- a/js/src/jit/BaselineCompiler.cpp
+++ b/js/src/jit/BaselineCompiler.cpp
@@ -3400,16 +3400,32 @@ BaselineCompiler::emit_JSOP_YIELD()
         if (!callVM(NormalSuspendInfo))
             return false;
     }
 
     masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), JSReturnOperand);
     return emitReturn();
 }
 
+typedef bool (*DebugAfterYieldFn)(JSContext *, BaselineFrame *);
+static const VMFunction DebugAfterYieldInfo = FunctionInfo<DebugAfterYieldFn>(jit::DebugAfterYield);
+
+bool
+BaselineCompiler::emit_JSOP_DEBUGAFTERYIELD()
+{
+    if (!compileDebugInstrumentation_)
+        return true;
+
+    frame.assertSyncedStack();
+    masm.loadBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
+    prepareVMCall();
+    pushArg(R0.scratchReg());
+    return callVM(DebugAfterYieldInfo);
+}
+
 typedef bool (*FinalSuspendFn)(JSContext *, HandleObject, BaselineFrame *, jsbytecode *);
 static const VMFunction FinalSuspendInfo = FunctionInfo<FinalSuspendFn>(jit::FinalSuspend);
 
 bool
 BaselineCompiler::emit_JSOP_FINALYIELDRVAL()
 {
     // Store generator in R0, BaselineFrame pointer in R1.
     frame.popRegsAndSync(1);
--- a/js/src/jit/BaselineCompiler.h
+++ b/js/src/jit/BaselineCompiler.h
@@ -171,16 +171,17 @@ namespace jit {
     _(JSOP_TABLESWITCH)        \
     _(JSOP_ITER)               \
     _(JSOP_MOREITER)           \
     _(JSOP_ISNOITER)           \
     _(JSOP_ENDITER)            \
     _(JSOP_GENERATOR)          \
     _(JSOP_INITIALYIELD)       \
     _(JSOP_YIELD)              \
+    _(JSOP_DEBUGAFTERYIELD)    \
     _(JSOP_FINALYIELDRVAL)     \
     _(JSOP_RESUME)             \
     _(JSOP_CALLEE)             \
     _(JSOP_SETRVAL)            \
     _(JSOP_RETRVAL)            \
     _(JSOP_RETURN)
 
 class BaselineCompiler : public BaselineCompilerSpecific
--- a/js/src/jit/VMFunctions.cpp
+++ b/js/src/jit/VMFunctions.cpp
@@ -903,16 +903,26 @@ InterpretResume(JSContext *cx, HandleObj
     if (!Invoke(cx, args))
         return false;
 
     rval.set(args.rval());
     return true;
 }
 
 bool
+DebugAfterYield(JSContext *cx, BaselineFrame *frame)
+{
+    // The BaselineFrame has just been constructed by JSOP_RESUME in the
+    // caller. We need to set its debuggee flag as necessary.
+    if (frame->script()->isDebuggee())
+        frame->setIsDebuggee();
+    return true;
+}
+
+bool
 StrictEvalPrologue(JSContext *cx, BaselineFrame *frame)
 {
     return frame->strictEvalPrologue(cx);
 }
 
 bool
 HeavyweightFunPrologue(JSContext *cx, BaselineFrame *frame)
 {
--- a/js/src/jit/VMFunctions.h
+++ b/js/src/jit/VMFunctions.h
@@ -707,16 +707,17 @@ bool DebugEpilogue(JSContext *cx, Baseli
 bool DebugEpilogueOnBaselineReturn(JSContext *cx, BaselineFrame *frame, jsbytecode *pc);
 
 JSObject *CreateGenerator(JSContext *cx, BaselineFrame *frame);
 bool NormalSuspend(JSContext *cx, HandleObject obj, BaselineFrame *frame, jsbytecode *pc,
                    uint32_t stackDepth);
 bool FinalSuspend(JSContext *cx, HandleObject obj, BaselineFrame *frame, jsbytecode *pc);
 bool InterpretResume(JSContext *cx, HandleObject obj, HandleValue val, HandlePropertyName kind,
                      MutableHandleValue rval);
+bool DebugAfterYield(JSContext *cx, BaselineFrame *frame);
 
 bool StrictEvalPrologue(JSContext *cx, BaselineFrame *frame);
 bool HeavyweightFunPrologue(JSContext *cx, BaselineFrame *frame);
 
 bool NewArgumentsObject(JSContext *cx, BaselineFrame *frame, MutableHandleValue res);
 
 JSObject *InitRestParameter(JSContext *cx, uint32_t length, Value *rest, HandleObject templateObj,
                             HandleObject res);
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -1640,17 +1640,16 @@ CASE(JSOP_UNUSED183)
 CASE(JSOP_UNUSED185)
 CASE(JSOP_UNUSED186)
 CASE(JSOP_UNUSED187)
 CASE(JSOP_UNUSED189)
 CASE(JSOP_UNUSED190)
 CASE(JSOP_UNUSED191)
 CASE(JSOP_UNUSED192)
 CASE(JSOP_UNUSED196)
-CASE(JSOP_UNUSED208)
 CASE(JSOP_UNUSED209)
 CASE(JSOP_UNUSED210)
 CASE(JSOP_UNUSED211)
 CASE(JSOP_UNUSED212)
 CASE(JSOP_UNUSED213)
 CASE(JSOP_UNUSED219)
 CASE(JSOP_UNUSED220)
 CASE(JSOP_UNUSED221)
@@ -3408,16 +3407,24 @@ CASE(JSOP_RESUME)
     bool ok = GeneratorObject::resume(cx, activation, gen, val, resumeKind);
     SET_SCRIPT(REGS.fp()->script());
     if (!ok)
         goto error;
 
     ADVANCE_AND_DISPATCH(0);
 }
 
+CASE(JSOP_DEBUGAFTERYIELD)
+{
+    // No-op in the interpreter, as GeneratorObject::resume takes care of
+    // fixing up InterpreterFrames.
+    MOZ_ASSERT_IF(REGS.fp()->script()->isDebuggee(), REGS.fp()->isDebuggee());
+}
+END_CASE(JSOP_DEBUGAFTERYIELD)
+
 CASE(JSOP_FINALYIELDRVAL)
 {
     RootedObject &gen = rootObject0;
     gen = &REGS.sp[-1].toObject();
     REGS.sp--;
 
     if (!GeneratorObject::finalSuspend(cx, gen)) {
         interpReturnOK = false;
--- a/js/src/vm/Opcodes.h
+++ b/js/src/vm/Opcodes.h
@@ -1614,17 +1614,25 @@ 1234567890123456789012345678901234567890
      * the JITs so the script always runs in the interpreter.
      *
      *   Category: Other
      *   Operands:
      *   Stack: =>
      */ \
     macro(JSOP_FORCEINTERPRETER, 207, "forceinterpreter", NULL,  1,  0,  0,  JOF_BYTE) \
     \
-    macro(JSOP_UNUSED208,     208, "unused208",    NULL,  1,  0,  0,  JOF_BYTE) \
+    /*
+     * Bytecode emitted after 'yield' statements to help the Debugger
+     * fix up the frame in the JITs. No-op in the interpreter.
+     *
+     *   Category: Debugger
+     *   Operands:
+     *   Stack: =>
+     */ \
+    macro(JSOP_DEBUGAFTERYIELD,  208, "debugafteryield",  NULL,  1,  0,  0,  JOF_BYTE) \
     macro(JSOP_UNUSED209,     209, "unused209",    NULL,  1,  0,  0,  JOF_BYTE) \
     macro(JSOP_UNUSED210,     210, "unused210",    NULL,  1,  0,  0,  JOF_BYTE) \
     macro(JSOP_UNUSED211,     211, "unused211",    NULL,  1,  0,  0,  JOF_BYTE) \
     macro(JSOP_UNUSED212,     212, "unused212",    NULL,  1,  0,  0,  JOF_BYTE) \
     macro(JSOP_UNUSED213,     213, "unused213",    NULL,  1,  0,  0,  JOF_BYTE) \
     /*
      * Pushes the global scope onto the stack.
      *
--- a/js/src/vm/Xdr.h
+++ b/js/src/vm/Xdr.h
@@ -29,17 +29,17 @@ namespace js {
  *  https://developer.mozilla.org/en-US/docs/SpiderMonkey/Internals/Bytecode
  *
  * === GREETINGS, FELLOW SUBTRAHEND INCREMENTER! ===
  * For the time being, please increment the subtrahend by 2 each time it
  * changes, because we have two flavors of bytecode: with JSOP_SYMBOL (in
  * Nightly) and without (all others).  FIXME: Bug 1066322 - Enable ES6 symbols
  * in all builds.
  */
-static const uint32_t XDR_BYTECODE_VERSION_SUBTRAHEND = 202;
+static const uint32_t XDR_BYTECODE_VERSION_SUBTRAHEND = 204;
 static_assert(XDR_BYTECODE_VERSION_SUBTRAHEND % 2 == 0, "see the comment above");
 static const uint32_t XDR_BYTECODE_VERSION =
     uint32_t(0xb973c0de - (XDR_BYTECODE_VERSION_SUBTRAHEND
 #ifdef JS_HAS_SYMBOLS
                                                            + 1
 #endif
                                                               ));