summaryrefslogtreecommitdiffstats
path: root/js/src/jit-test/tests/debug/Debugger-onEnterFrame-resumption-05.js
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/jit-test/tests/debug/Debugger-onEnterFrame-resumption-05.js')
-rw-r--r--js/src/jit-test/tests/debug/Debugger-onEnterFrame-resumption-05.js98
1 files changed, 98 insertions, 0 deletions
diff --git a/js/src/jit-test/tests/debug/Debugger-onEnterFrame-resumption-05.js b/js/src/jit-test/tests/debug/Debugger-onEnterFrame-resumption-05.js
new file mode 100644
index 0000000000..8885aa0d80
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Debugger-onEnterFrame-resumption-05.js
@@ -0,0 +1,98 @@
+// 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);