Bug 579183 - loosen-up StackSegment invariants - part 1 - decompiler (r=brendan)
authorLuke Wagner <lw@mozilla.com>
Fri, 30 Jul 2010 14:49:29 -0700
changeset 50464 b16d966d3b6f10db7d2b1fb6de572a0468609e7b
parent 50463 68a9a3355a6303f0c704b2df04c9347fd6215dc2
child 50465 c2411a6276fc54fd73c5c90edbfc838947c28934
push idunknown
push userunknown
push dateunknown
reviewersbrendan
bugs579183
milestone2.0b4pre
Bug 579183 - loosen-up StackSegment invariants - part 1 - decompiler (r=brendan)
js/src/jsfun.cpp
js/src/jsopcode.cpp
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -2650,24 +2650,43 @@ js_ValueToCallableObject(JSContext *cx, 
 
 void
 js_ReportIsNotFunction(JSContext *cx, const Value *vp, uintN flags)
 {
     const char *name = NULL, *source = NULL;
     AutoValueRooter tvr(cx);
     uintN error = (flags & JSV2F_CONSTRUCT) ? JSMSG_NOT_CONSTRUCTOR : JSMSG_NOT_FUNCTION;
     LeaveTrace(cx);
+
+    /*
+     * We try to the print the code that produced vp if vp is a value in the
+     * most recent interpreted stack frame. Note that additional values, not
+     * directly produced by the script, may have been pushed onto the frame's
+     * expression stack (e.g. by InvokeFromEngine) thereby incrementing sp past
+     * the depth simulated by ReconstructPCStack. Since we must pass an offset
+     * from the top of the simulated stack to js_ReportValueError3, it is
+     * important to do bounds checking using the simulated, rather than actual,
+     * stack depth.
+     */
+    ptrdiff_t spindex = 0;
+
     FrameRegsIter i(cx);
     while (!i.done() && !i.pc())
         ++i;
 
-    ptrdiff_t spindex =
-        (!i.done() && i.fp()->base() <= vp && vp < i.sp())
-        ? vp - i.sp()
-        : ((flags & JSV2F_SEARCH_STACK) ? JSDVG_SEARCH_STACK : JSDVG_IGNORE_STACK);
+    if (!i.done()) {
+        uintN depth = js_ReconstructStackDepth(cx, i.fp()->script, i.pc());
+        Value *simsp = i.fp()->base() + depth;
+        JS_ASSERT(simsp <= i.sp());
+        if (i.fp()->base() <= vp && vp < simsp)
+            spindex = vp - simsp;
+    }
+
+    if (!spindex)
+        spindex = ((flags & JSV2F_SEARCH_STACK) ? JSDVG_SEARCH_STACK : JSDVG_IGNORE_STACK);
 
     js_ReportValueError3(cx, error, spindex, *vp, NULL, name, source);
 }
 
 /*
  * When a function has between 2 and MAX_ARRAY_LOCALS arguments and variables,
  * their name are stored as the JSLocalNames.array.
  */
--- a/js/src/jsopcode.cpp
+++ b/js/src/jsopcode.cpp
@@ -5124,25 +5124,29 @@ js_DecompileValueGenerator(JSContext *cx
             do {
                 if (sp == stackBase) {
                     pcdepth = -1;
                     goto release_pcstack;
                 }
             } while (*--sp != v);
 
             /*
-             * The value may have come from beyond stackBase + pcdepth,
-             * meaning that it came from a temporary slot that the
-             * interpreter uses for GC roots or when JSOP_APPLY extended
-             * the stack to fit the argument array elements. Only update pc
-             * if beneath stackBase + pcdepth; otherwise blame existing
-             * (current) PC.
+             * The value may have come from beyond stackBase + pcdepth, meaning
+             * that it came from a temporary slot pushed by the interpreter or
+             * arguments pushed for an InvokeFromEngine call. Only update pc if
+             * beneath stackBase + pcdepth. If above, we don't know whether the
+             * value is associated with the current pc or from a fast native
+             * whose arguments have been pushed, so just print the value.
              */
-            if (sp < stackBase + pcdepth)
-                pc = pcstack[sp - stackBase];
+            if (sp >= stackBase + pcdepth) {
+                pcdepth = -1;
+                goto release_pcstack;
+            }
+
+            pc = pcstack[sp - stackBase];
         }
 
       release_pcstack:
         cx->free(pcstack);
         if (pcdepth < 0)
             goto do_fallback;
     }