Fix incoherent PC in FixupArity failure case (bug 629650, r=luke).
authorDavid Anderson <danderson@mozilla.com>
Tue, 01 Feb 2011 12:04:07 -0800
changeset 62038 a7a3317dac326fe906fffe2f241968e901b66a84
parent 62037 aa1cf1121a203aac671b85ba308510976a9cf454
child 62039 e510e0303de5870e875815f68835f6f67072d3f0
push idunknown
push userunknown
push dateunknown
reviewersluke
bugs629650
milestone2.0b11pre
Fix incoherent PC in FixupArity failure case (bug 629650, r=luke).
js/src/jsinterp.cpp
js/src/methodjit/InvokeHelpers.cpp
js/src/methodjit/MethodJIT.cpp
js/src/methodjit/MethodJIT.h
--- a/js/src/jsinterp.cpp
+++ b/js/src/jsinterp.cpp
@@ -128,39 +128,18 @@ JSStackFrame::pc(JSContext *cx, JSStackF
 
     if (!next)
         next = cx->computeNextFrame(this);
 
     if (next->flags_ & JSFRAME_HAS_PREVPC)
         return next->prevpc_;
 
 #if defined(JS_METHODJIT) && defined(JS_MONOIC)
-    JSScript *script = this->script();
-    js::mjit::JITScript *jit = script->getJIT(isConstructing());
-    size_t low = 0;
-    size_t high = jit->nCallICs;
-    while (high > low + 1) {
-        /* Could overflow here on a script with 2 billion calls. Oh well. */
-        size_t mid = (high + low) / 2;
-        void *entry = jit->callICs[mid].funGuard.executableAddress();
-
-        /*
-         * Use >= here as the return address of the call is likely to be
-         * the start address of the next (possibly IC'ed) operation.
-         */
-        if (entry >= next->ncode_)
-            high = mid;
-        else
-            low = mid;
-    }
-
-    js::mjit::ic::CallICInfo &callIC = jit->callICs[low];
-
-    JS_ASSERT((uint8*)callIC.funGuard.executableAddress() + callIC.joinPointOffset == next->ncode_);
-    return callIC.pc;
+    js::mjit::JITScript *jit = script()->getJIT(isConstructing());
+    return jit->nativeToPC(next->ncode_);
 #else
     JS_NOT_REACHED("Unknown PC for frame");
     return NULL;
 #endif
 }
 
 JSObject *
 js::GetScopeChain(JSContext *cx)
--- a/js/src/methodjit/InvokeHelpers.cpp
+++ b/js/src/methodjit/InvokeHelpers.cpp
@@ -267,18 +267,24 @@ stubs::FixupArity(VMFrame &f, uint32 nac
     /* Pop the inline frame. */
     f.fp() = oldfp->prev();
     f.regs.sp = (Value*) oldfp;
 
     /* Reserve enough space for a callee frame. */
     JSStackFrame *newfp = cx->stack().getInlineFrameWithinLimit(cx, (Value*) oldfp, nactual,
                                                                 fun, fun->script(), &flags,
                                                                 f.entryfp, &f.stackLimit);
-    if (!newfp)
+    if (!newfp) {
+        /*
+         * The PC is not coherent with the current frame, so fix it up for
+         * exception handling.
+         */
+        f.regs.pc = f.jit()->nativeToPC(ncode);
         THROWV(NULL);
+    }
 
     /* Reset the part of the stack frame set by the caller. */
     newfp->initCallFrameCallerHalf(cx, flags, ncode);
 
     /* Reset the part of the stack frame set by the prologue up to now. */
     newfp->initCallFrameEarlyPrologue(fun, nactual);
 
     /* The caller takes care of assigning fp to regs. */
--- a/js/src/methodjit/MethodJIT.cpp
+++ b/js/src/methodjit/MethodJIT.cpp
@@ -943,8 +943,35 @@ mjit::GetCallTargetCount(JSScript *scrip
 }
 #else
 uintN
 mjit::GetCallTargetCount(JSScript *script, jsbytecode *pc)
 {
     return 1;
 }
 #endif
+
+jsbytecode *
+JITScript::nativeToPC(void *returnAddress) const
+{
+    size_t low = 0;
+    size_t high = nCallICs;
+    while (high > low + 1) {
+        /* Could overflow here on a script with 2 billion calls. Oh well. */
+        size_t mid = (high + low) / 2;
+        void *entry = callICs[mid].funGuard.executableAddress();
+
+        /*
+         * Use >= here as the return address of the call is likely to be
+         * the start address of the next (possibly IC'ed) operation.
+         */
+        if (entry >= returnAddress)
+            high = mid;
+        else
+            low = mid;
+    }
+
+    js::mjit::ic::CallICInfo &ic = callICs[low];
+
+    JS_ASSERT((uint8*)ic.funGuard.executableAddress() + ic.joinPointOffset == returnAddress);
+    return ic.pc;
+}
+
--- a/js/src/methodjit/MethodJIT.h
+++ b/js/src/methodjit/MethodJIT.h
@@ -356,16 +356,18 @@ struct JITScript {
     void nukeScriptDependentICs();
     void sweepCallICs(JSContext *cx, bool purgeAll);
     void purgeMICs();
     void purgePICs();
 
     size_t scriptDataSize();
 
     size_t mainCodeSize() { return code.m_size; } /* doesn't account for fragmentation */
+
+    jsbytecode *nativeToPC(void *returnAddress) const;
 };
 
 /*
  * Execute the given mjit code. This is a low-level call and callers must
  * provide the same guarantees as JaegerShot/CheckStackAndEnterMethodJIT.
  */
 JSBool EnterMethodJIT(JSContext *cx, JSStackFrame *fp, void *code, Value *stackLimit);