author | Jim Blandy <jimb@mozilla.com> |
Thu, 18 Dec 2014 13:56:27 -0800 | |
changeset 225450 | b717156bf98959771966739441165654ae04659c |
parent 225449 | a21c59ad2af3f1848da35501d712f3925b3f125b |
child 225451 | 4ba8480c860809190ebcb29cf17b6cbb4bfe9dca |
push id | 28163 |
push user | philringnalda@gmail.com |
push date | Sat, 24 Jan 2015 16:27:39 +0000 |
treeherder | mozilla-central@1cf171c1a177 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | shu |
bugs | 1026477 |
milestone | 38.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
|
new file mode 100644 --- /dev/null +++ b/js/src/jit-test/tests/debug/Frame-eval-26.js @@ -0,0 +1,16 @@ +// Bug 1026477: Defining functions with D.F.p.eval works, even if there's +// already a non-aliased var binding for the identifier. + +var g = newGlobal(); +var dbg = new Debugger(g); +dbg.onDebuggerStatement = function (frame) { + frame.older.eval('function f() { }'); +}; + +// When the compiler sees the 'debugger' statement, it marks all variables as +// aliased, but we want to test the case where f is in a stack frame slot, so we +// put the 'debugger' statement in a separate function, and use frame.older to +// get back to the anonymous function's frame. +g.eval('function q() { debugger; }'); +assertEq(typeof g.eval('(function () { var f = 42; q(); return f; })();'), + "function");
new file mode 100644 --- /dev/null +++ b/js/src/jit-test/tests/debug/Frame-eval-27.js @@ -0,0 +1,13 @@ +// Bug 1026477: Defining functions with D.F.p.eval works, even if there's +// already a var binding for the identifier. + +var g = newGlobal(); +var dbg = new Debugger(g); +dbg.onDebuggerStatement = function (frame) { + frame.eval('function f() { }'); +}; + +// When the compiler sees the 'debugger' statement, it marks all variables as +// aliased, so f will live in a Call object. +assertEq(typeof g.eval('(function () { var f = 42; debugger; return f;})();'), + "function");
--- a/js/src/vm/Interpreter.cpp +++ b/js/src/vm/Interpreter.cpp @@ -3720,18 +3720,26 @@ js::DefFunOperation(JSContext *cx, Handl unsigned attrs = script->isActiveEval() ? JSPROP_ENUMERATE : JSPROP_ENUMERATE | JSPROP_PERMANENT; /* Steps 5d, 5f. */ if (!shape || pobj != parent) return DefineProperty(cx, parent, name, rval, nullptr, nullptr, attrs); - /* Step 5e. */ - MOZ_ASSERT(parent->isNative()); + /* + * Step 5e. + * + * A DebugScopeObject is okay here, and sometimes necessary. If + * Debugger.Frame.prototype.eval defines a function with the same name as an + * extant variable in the frame, the DebugScopeObject takes care of storing + * the function in the stack frame (for non-aliased variables) or on the + * scope object (for aliased). + */ + MOZ_ASSERT(parent->isNative() || parent->is<DebugScopeObject>()); if (parent->is<GlobalObject>()) { if (shape->configurable()) return DefineProperty(cx, parent, name, rval, nullptr, nullptr, attrs); if (shape->isAccessorDescriptor() || !shape->writable() || !shape->enumerable()) { JSAutoByteString bytes; if (AtomToPrintableString(cx, name, &bytes)) { JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_CANT_REDEFINE_PROP,