Bug 693895 - Remove call to js_ReconstructStackDepth in StackIter (r=dmandelin)
authorLuke Wagner <luke@mozilla.com>
Wed, 12 Oct 2011 10:30:15 -0700
changeset 78664 ccd092244e4c41c9612ed957c0a30e64e85ee38b
parent 78663 66f1de1d9cbaab1183aae2e28d6eeb493f171dd9
child 78665 6fa6594375486a76da7b7e4a25d163b00e6bbf05
push id21321
push usermak77@bonardo.net
push dateThu, 13 Oct 2011 13:50:30 +0000
treeherdermozilla-central@d6d3a1f90e2e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdmandelin
bugs693895
milestone10.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 693895 - Remove call to js_ReconstructStackDepth in StackIter (r=dmandelin)
js/src/jit-test/tests/basic/testStackIter.js
js/src/vm/Stack.cpp
--- a/js/src/jit-test/tests/basic/testStackIter.js
+++ b/js/src/jit-test/tests/basic/testStackIter.js
@@ -40,17 +40,16 @@ assertStackIs(["global-code"]);
 (function f() { assertStackIs([f, "global-code"]) })();
 eval("assertStackIs(['eval-code', 'global-code'])");
 (function f() { eval("assertStackIs(['eval-code', f, 'global-code'])"); })();
 (function f() { eval("(function g() { assertStackIs([g, 'eval-code', f, 'global-code']); })()"); })();
 (function f() { assertStackIs([f, 'bound(f)', 'global-code']); }).bind()()
 this['eval']("assertStackIs(['eval-code', eval, 'global-code'])");
 eval.bind(null, "assertStackIs(['eval-code', eval, 'bound(eval)', 'global-code'])")();
 (function f() { assertStackIs([f, Function.prototype.call, 'global-code']) }).call(null);
-(function f() { assertStackIs([f, Function.prototype.apply, 'global-code']) }).apply(null, {});
 (function f() { (function g(x,y,z) { assertStackIs([g,f,'global-code']); })() })(1);
 
 /***********/
 
 var gen = (function g() { assertStackIs([g, gen.next, fun, 'global-code']); yield; })();
 var fun = function f() { gen.next() };
 fun();
 
@@ -130,51 +129,28 @@ var obj = { valueOf:(function valueOf() 
 
 var proxy = Proxy.createFunction({}, function f() { assertStackIs([f, "global-code"]) });
 proxy();
 new proxy();
 
 /***********/
 
 for (var i = 0; i < 10; ++i) {
+    eval("'no imacros please'");
+
     /* No loss for scripts. */
     (function f() {
-        assertStackIs([f, Function.prototype.apply, 'global-code']);
-    }).apply(null, {});
-    (function f() {
         assertStackIs([f, Function.prototype.call, 'global-code']);
     }).call(null);
 
     /* Loss for natives. */
     (function f() {
         var stack = dumpStack();
         assertEq(stack[0], f);
         if (stack.length === 4) {
             assertEq(stack[1].name, 'f');
             assertEq(stack[2], Function.prototype.call);
         } else {
             assertEq(stack.length, 3);
             assertEq(stack[1], Function.prototype.call);
         }
     }).bind().call(null);
-    (function f() {
-        var stack = dumpStack();
-        assertEq(stack[0], f);
-        if (stack.length === 4) {
-            assertEq(stack[1].name, 'f');
-            assertEq(stack[2], Function.prototype.apply);
-        } else {
-            assertEq(stack.length, 3);
-            assertEq(stack[1], Function.prototype.apply);
-        }
-    }).bind().apply(null, {});
-    (function f() {
-        var stack = dumpStack();
-        assertEq(stack[0], f);
-        if (stack.length === 4) {
-            assertEq(stack[1].name, 'f');
-            assertEq(stack[2], Function.prototype.apply);
-        } else {
-            assertEq(stack.length, 3);
-            assertEq(stack[1], Function.prototype.apply);
-        }
-    }).bind().apply(null, [1,2,3,4,5]);
 }
--- a/js/src/vm/Stack.cpp
+++ b/js/src/vm/Stack.cpp
@@ -1023,68 +1023,51 @@ StackIter::settleOnNewState()
             /*
              * As an optimization, there is no CallArgsList element pushed for
              * natives called directly by a script (compiled or interpreted).
              * We catch these by inspecting the bytecode and stack. This check
              * relies on the property that, at a call opcode,
              *
              *   regs.sp == vp + 2 + argc
              *
-             * The mjit Function.prototype.apply optimization breaks this
-             * invariant (see ic::SplatApplyArgs). Thus, for JSOP_FUNAPPLY we
-             * need to (slowly) reconstruct the depth.
-             *
-             * Additionally, the Function.prototype.{call,apply} optimizations
-             * leave no record when 'this' is a native function. Thus, if the
-             * following expression runs and breaks in the debugger, the call
-             * to 'replace' will not appear on the callstack.
+             * The Function.prototype.call optimization leaves no record when
+             * 'this' is a native function. Thus, if the following expression
+             * runs and breaks in the debugger, the call to 'replace' will not
+             * appear on the callstack.
              *
              *   (String.prototype.replace).call('a',/a/,function(){debugger});
              *
              * Function.prototype.call will however appear, hence the debugger
              * can, by inspecting 'args.thisv', give some useful information.
+             *
+             * For Function.prototype.apply, the situation is even worse: since
+             * a dynamic number of arguments have been pushed onto the stack
+             * (see SplatApplyArgs), there is no efficient way to know how to
+             * find the callee. Thus, calls to apply are lost completely.
              */
             JSOp op = js_GetOpcode(cx_, fp_->script(), pc_);
             if (op == JSOP_CALL || op == JSOP_FUNCALL) {
                 uintN argc = GET_ARGC(pc_);
                 DebugOnly<uintN> spoff = sp_ - fp_->base();
                 JS_ASSERT_IF(cx_->stackIterAssertionEnabled && !fp_->hasImacropc(),
                              spoff == js_ReconstructStackDepth(cx_, fp_->script(), pc_));
                 Value *vp = sp_ - (2 + argc);
 
                 CrashIfInvalidSlot(fp_, vp);
                 if (IsNativeFunction(*vp)) {
                     state_ = IMPLICIT_NATIVE;
                     args_ = CallArgsFromVp(argc, vp);
                     return;
                 }
-            } else if (op == JSOP_FUNAPPLY) {
-                JS_ASSERT(!fp_->hasImacropc());
-                uintN argc = GET_ARGC(pc_);
-                uintN spoff = js_ReconstructStackDepth(cx_, fp_->script(), pc_);
-                Value *sp = fp_->base() + spoff;
-                Value *vp = sp - (2 + argc);
-
-                CrashIfInvalidSlot(fp_, vp);
-                if (IsNativeFunction(*vp)) {
-                    if (sp_ != sp) {
-                        JS_ASSERT(argc == 2);
-                        JS_ASSERT(vp[0].toObject().getFunctionPrivate()->native() == js_fun_apply);
-                        JS_ASSERT(sp_ >= vp + 3);
-                        argc = sp_ - (vp + 2);
-                    }
-                    state_ = IMPLICIT_NATIVE;
-                    args_ = CallArgsFromVp(argc, vp);
-                    return;
-                }
             }
 
             state_ = SCRIPTED;
-            JS_ASSERT(sp_ >= fp_->base() && sp_ <= fp_->slots() + fp_->script()->nslots);
             DebugOnly<JSScript *> script = fp_->script();
+            JS_ASSERT_IF(op != JSOP_FUNAPPLY,
+                         sp_ >= fp_->base() && sp_ <= fp_->slots() + script->nslots);
             JS_ASSERT_IF(!fp_->hasImacropc(),
                          pc_ >= script->code && pc_ < script->code + script->length);
             return;
         }
 
         /*
          * A CallArgsList element is pushed for any call to Invoke, regardless
          * of whether the callee is a scripted function or even a callable