author | Luke Wagner <luke@mozilla.com> |
Wed, 12 Oct 2011 10:30:15 -0700 | |
changeset 78664 | ccd092244e4c41c9612ed957c0a30e64e85ee38b |
parent 78663 | 66f1de1d9cbaab1183aae2e28d6eeb493f171dd9 |
child 78665 | 6fa6594375486a76da7b7e4a25d163b00e6bbf05 |
push id | 21321 |
push user | mak77@bonardo.net |
push date | Thu, 13 Oct 2011 13:50:30 +0000 |
treeherder | mozilla-central@d6d3a1f90e2e [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | dmandelin |
bugs | 693895 |
milestone | 10.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
|
js/src/jit-test/tests/basic/testStackIter.js | file | annotate | diff | comparison | revisions | |
js/src/vm/Stack.cpp | file | annotate | diff | comparison | revisions |
--- 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