Source code

Revision control

Copy as Markdown

Other Tools

// Exercise the call to ScriptDebugPrologue in js_InternalInterpret.
// This may change, but as of this writing, inline caches (ICs) are
// disabled in debug mode, and those are the only users of the out-of-line entry
// points for JIT code (arityCheckEntry, argsCheckEntry, fastEntry); debug
// mode uses only invokeEntry. This means most of the bytecode tails in
// js_InternalInterpret that might call ScriptPrologue or ScriptEpilogue are
// unreachable in debug mode: they're only called from the out-of-line entry
// points.
//
// The exception is REJOIN_THIS_PROTOTYPE, which can be reached reliably if you
// add a JS_GC call to stubs::GetPropNoCache. JIT code calls that stub to
// retrieve the 'prototype' property of a function called as a constructor, if
// TI can't establish the exact identity of that prototype's value at compile
// time. Thus the preoccupation with constructors here.
load(libdir + "asserts.js");
var debuggee = newGlobal({newCompartment: true});
var dbg = Debugger(debuggee);
var hits, savedFrame;
// Allow the constructor to return normally.
dbg.onEnterFrame = function (frame) {
hits++;
if (frame.constructing) {
savedFrame = frame;
assertEq(savedFrame.onStack, true);
return undefined;
}
return undefined;
};
hits = 0;
debuggee.hits = 0;
savedFrame = undefined;
assertEq(typeof debuggee.eval("function f(){ hits++; } f.prototype = {}; new f;"), "object");
assertEq(hits, 2);
assertEq(savedFrame.onStack, false);
assertEq(debuggee.hits, 1);
// Force an early return from the constructor.
dbg.onEnterFrame = function (frame) {
hits++;
if (frame.constructing) {
savedFrame = frame;
assertEq(savedFrame.onStack, true);
return { return: "pass" };
}
return undefined;
};
hits = 0;
debuggee.hits = 0;
savedFrame = undefined;
assertEq(typeof debuggee.eval("function f(){ hits++; } f.prototype = {}; new f;"), "object");
assertEq(hits, 2);
assertEq(savedFrame.onStack, false);
assertEq(debuggee.hits, 0);
// Force the constructor to throw an exception.
dbg.onEnterFrame = function (frame) {
hits++;
if (frame.constructing) {
savedFrame = frame;
assertEq(savedFrame.onStack, true);
return { throw: "pass" };
}
return undefined;
};
hits = 0;
debuggee.hits = 0;
savedFrame = undefined;
assertThrowsValue(function () {
debuggee.eval("function f(){ hits++ } f.prototype = {}; new f;");
}, "pass");
assertEq(hits, 2);
assertEq(savedFrame.onStack, false);
assertEq(debuggee.hits, 0);
// Ensure that forcing an early return only returns from one JS call.
debuggee.eval("function g() { var result = new f; g_hits++; return result; }");
dbg.onEnterFrame = function (frame) {
hits++;
if (frame.constructing) {
savedFrame = frame;
assertEq(savedFrame.onStack, true);
return { return: "pass" };
}
return undefined;
};
hits = 0;
debuggee.hits = 0;
debuggee.g_hits = 0;
savedFrame = undefined;
assertEq(typeof debuggee.eval("g();"), "object");
assertEq(hits, 3);
assertEq(savedFrame.onStack, false);
assertEq(debuggee.hits, 0);
assertEq(debuggee.g_hits, 1);