Bug 687683: Separate ScriptDebugPrologue add ScriptDebugEpilogue from and ScriptPrologue and ScriptEpilogue. r=jorendorff
authorJim Blandy <jimb@mozilla.com>
Tue, 06 Dec 2011 11:40:27 -0800
changeset 82080 9aca452cf4519114e31f6917a37050366e5a3d57
parent 82079 6a2bb05dd97ea248d19b1e657d656cdd5fbd3104
child 82081 2e7abb74ed3e960add927b34721470b1918533e5
push id21582
push userbmo@edmorley.co.uk
push dateWed, 07 Dec 2011 09:30:09 +0000
treeherdermozilla-central@489f2d51b011 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjorendorff
bugs687683
milestone11.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 687683: Separate ScriptDebugPrologue add ScriptDebugEpilogue from and ScriptPrologue and ScriptEpilogue. r=jorendorff At the moment, ScriptDebugPrologue is called (conditionally) from within ScriptPrologue. For onEnterFrame handlers to be able to return a resumption value, we need ScriptDebugPrologue to return a JSTrapStatus value, but it is (non-debug) ScriptPrologue's callers that would need to handle those values. It seems strange to have ScriptPrologue return a JSTrapStatus. So this patch brings ScriptDebugPrologue out of ScriptPrologue (and ScriptPrologueOrGeneratorResume), and has ScriptPrologue's callers call ScriptDebugPrologue explicitly. For symmetry, we do the same with ScriptEpilogue, ScriptEpilogueOrGeneratorYield, and ScriptDebugEpilogue. Actually adding and processing the JSTrapStatus values comes in a later patch. This is just meant to be a behavior-preserving rearrangement.
js/src/jsinterp.cpp
js/src/jsinterpinlines.h
js/src/methodjit/InvokeHelpers.cpp
js/src/methodjit/StubCalls.cpp
--- a/js/src/jsinterp.cpp
+++ b/js/src/jsinterp.cpp
@@ -1785,16 +1785,18 @@ js::Interpret(JSContext *cx, StackFrame 
 #endif
 
     /* Don't call the script prologue if executing between Method and Trace JIT. */
     if (interpMode == JSINTERP_NORMAL) {
         StackFrame *fp = regs.fp();
         JS_ASSERT_IF(!fp->isGeneratorFrame(), regs.pc == script->code);
         if (!ScriptPrologueOrGeneratorResume(cx, fp, UseNewTypeAtEntry(cx, fp)))
             goto error;
+        if (cx->compartment->debugMode())
+            ScriptDebugPrologue(cx, fp);
     }
 
     /* The REJOIN mode acts like the normal mode, except the prologue is skipped. */
     if (interpMode == JSINTERP_REJOIN)
         interpMode = JSINTERP_NORMAL;
 
     JS_ASSERT_IF(interpMode == JSINTERP_SKIP_TRAP, JSOp(*regs.pc) == JSOP_TRAP);
 
@@ -2026,16 +2028,20 @@ BEGIN_CASE(JSOP_STOP)
      */
     CHECK_BRANCH();
 
     interpReturnOK = true;
     if (entryFrame != regs.fp())
   inline_return:
     {
         JS_ASSERT(!IsActiveWithOrBlock(cx, regs.fp()->scopeChain(), 0));
+
+        if (cx->compartment->debugMode())
+            interpReturnOK = ScriptDebugEpilogue(cx, regs.fp(), interpReturnOK);
+ 
         interpReturnOK = ScriptEpilogue(cx, regs.fp(), interpReturnOK);
 
         /* The JIT inlines ScriptEpilogue. */
 #ifdef JS_METHODJIT
   jit_return:
 #endif
 
         /* The results of lowered call/apply frames need to be shifted. */
@@ -3502,16 +3508,19 @@ BEGIN_CASE(JSOP_FUNAPPLY)
             goto jit_return;
         }
     }
 #endif
 
     if (!ScriptPrologue(cx, regs.fp(), newType))
         goto error;
 
+    if (cx->compartment->debugMode())
+        ScriptDebugPrologue(cx, regs.fp());
+
     CHECK_INTERRUPT_HANDLER();
 
     /* Load first op and dispatch it (safe since JSOP_STOP). */
     op = (JSOp) *regs.pc;
     DO_OP();
 }
 
 BEGIN_CASE(JSOP_SETCALL)
@@ -5519,16 +5528,18 @@ END_CASE(JSOP_ARRAYPUSH)
      */
     interpReturnOK &= (JSBool)UnwindScope(cx, 0, interpReturnOK || cx->isExceptionPending());
     JS_ASSERT(regs.sp == regs.fp()->base());
 
     if (entryFrame != regs.fp())
         goto inline_return;
 
   exit:
+    if (cx->compartment->debugMode())
+        interpReturnOK = ScriptDebugEpilogue(cx, regs.fp(), interpReturnOK);
     interpReturnOK = ScriptEpilogueOrGeneratorYield(cx, regs.fp(), interpReturnOK);
     regs.fp()->setFinishedInInterpreter();
 
     /*
      * At this point we are inevitably leaving an interpreted function or a
      * top-level script, and returning to one of:
      * (a) an "out of line" call made through Invoke;
      * (b) a js_Execute activation;
--- a/js/src/jsinterpinlines.h
+++ b/js/src/jsinterpinlines.h
@@ -200,28 +200,24 @@ ScriptPrologue(JSContext *cx, StackFrame
     if (fp->isConstructing()) {
         JSObject *obj = js_CreateThisForFunction(cx, &fp->callee(), newType);
         if (!obj)
             return false;
         fp->functionThis().setObject(*obj);
     }
 
     Probes::enterJSFun(cx, fp->maybeFun(), fp->script());
-    if (cx->compartment->debugMode())
-        ScriptDebugPrologue(cx, fp);
 
     return true;
 }
 
 inline bool
 ScriptEpilogue(JSContext *cx, StackFrame *fp, bool ok)
 {
     Probes::exitJSFun(cx, fp->maybeFun(), fp->script());
-    if (cx->compartment->debugMode())
-        ok = ScriptDebugEpilogue(cx, fp, ok);
 
     /*
      * If inline-constructing, replace primitive rval with the new object
      * passed in via |this|, and instrument this constructor invocation.
      */
     if (fp->isConstructing() && ok) {
         if (fp->returnValue().isPrimitive())
             fp->setReturnValue(ObjectValue(fp->constructorThis()));
@@ -230,28 +226,24 @@ ScriptEpilogue(JSContext *cx, StackFrame
     return ok;
 }
 
 inline bool
 ScriptPrologueOrGeneratorResume(JSContext *cx, StackFrame *fp, bool newType)
 {
     if (!fp->isGeneratorFrame())
         return ScriptPrologue(cx, fp, newType);
-    if (cx->compartment->debugMode())
-        ScriptDebugPrologue(cx, fp);
     return true;
 }
 
 inline bool
 ScriptEpilogueOrGeneratorYield(JSContext *cx, StackFrame *fp, bool ok)
 {
     if (!fp->isYielding())
         return ScriptEpilogue(cx, fp, ok);
-    if (cx->compartment->debugMode())
-        return ScriptDebugEpilogue(cx, fp, ok);
     return ok;
 }
 
 inline void
 InterpreterFrames::enableInterruptsIfRunning(JSScript *script)
 {
     if (script == regs->fp()->script())
         enabler.enableInterrupts();
--- a/js/src/methodjit/InvokeHelpers.cpp
+++ b/js/src/methodjit/InvokeHelpers.cpp
@@ -571,16 +571,20 @@ js_InternalThrow(VMFrame &f)
 
         // The JIT guarantees that ScriptEpilogue() has always been run
         // upon exiting to its caller. This is important for consistency,
         // where execution modes make similar guarantees about prologues
         // and epilogues. RunTracer(), Interpret(), and Invoke() all
         // rely on this property.
         JS_ASSERT(!f.fp()->finishedInInterpreter());
         UnwindScope(cx, 0, cx->isExceptionPending());
+
+        if (cx->compartment->debugMode())
+            js::ScriptDebugEpilogue(cx, f.fp(), false);
+
         ScriptEpilogue(f.cx, f.fp(), false);
 
         // Don't remove the last frame, this is the responsibility of
         // JaegerShot()'s caller. We only guarantee that ScriptEpilogue()
         // has been run.
         if (f.entryfp == f.fp())
             break;
 
@@ -910,16 +914,20 @@ js_InternalInterpret(void *returnData, v
         /* FALLTHROUGH */
 
       case REJOIN_FUNCTION_PROLOGUE:
         fp->scopeChain();
 
         /* Construct the 'this' object for the frame if necessary. */
         if (!ScriptPrologueOrGeneratorResume(cx, fp, types::UseNewTypeAtEntry(cx, fp)))
             return js_InternalThrow(f);
+
+        if (cx->compartment->debugMode())
+            js::ScriptDebugPrologue(cx, fp);
+
         break;
 
       case REJOIN_CALL_PROLOGUE:
       case REJOIN_CALL_PROLOGUE_LOWERED_CALL:
       case REJOIN_CALL_PROLOGUE_LOWERED_APPLY:
         if (returnReg) {
             uint32 argc = 0;
             if (rejoin == REJOIN_CALL_PROLOGUE)
--- a/js/src/methodjit/StubCalls.cpp
+++ b/js/src/methodjit/StubCalls.cpp
@@ -2347,21 +2347,25 @@ stubs::FunctionFrameEpilogue(VMFrame &f)
 {
     f.fp()->functionEpilogue();
 }
 
 void JS_FASTCALL
 stubs::AnyFrameEpilogue(VMFrame &f)
 {
     /*
-     * On the normal execution path, emitReturn inlines ScriptEpilogue.
-     * This function implements forced early returns, so it must have the
-     * same effect.
+     * On the normal execution path, emitReturn calls ScriptDebugEpilogue
+     * and inlines ScriptEpilogue. This function implements forced early
+     * returns, so it must have the same effect.
      */
-    if (!ScriptEpilogue(f.cx, f.fp(), true))
+    bool ok = true;
+    if (f.cx->compartment->debugMode())
+        ok = js::ScriptDebugEpilogue(f.cx, f.fp(), ok);
+    ok = ScriptEpilogue(f.cx, f.fp(), ok);
+    if (!ok)
         THROW();
     if (f.fp()->isNonEvalFunctionFrame())
         f.fp()->functionEpilogue();
 }
 
 template <bool Clamped>
 int32 JS_FASTCALL
 stubs::ConvertToTypedInt(JSContext *cx, Value *vp)