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