|
1 // Exercise the call to ScriptDebugPrologue in js_InternalInterpret. |
|
2 |
|
3 // This may change, but as of this writing, inline caches (ICs) are |
|
4 // disabled in debug mode, and those are the only users of the out-of-line entry |
|
5 // points for JIT code (arityCheckEntry, argsCheckEntry, fastEntry); debug |
|
6 // mode uses only invokeEntry. This means most of the bytecode tails in |
|
7 // js_InternalInterpret that might call ScriptPrologue or ScriptEpilogue are |
|
8 // unreachable in debug mode: they're only called from the out-of-line entry |
|
9 // points. |
|
10 // |
|
11 // The exception is REJOIN_THIS_PROTOTYPE, which can be reached reliably if you |
|
12 // add a JS_GC call to stubs::GetPropNoCache. JIT code calls that stub to |
|
13 // retrieve the 'prototype' property of a function called as a constructor, if |
|
14 // TI can't establish the exact identity of that prototype's value at compile |
|
15 // time. Thus the preoccupation with constructors here. |
|
16 |
|
17 load(libdir + "asserts.js"); |
|
18 |
|
19 var debuggee = newGlobal(); |
|
20 var dbg = Debugger(debuggee); |
|
21 var hits, savedFrame; |
|
22 |
|
23 // Allow the constructor to return normally. |
|
24 dbg.onEnterFrame = function (frame) { |
|
25 hits++; |
|
26 if (frame.constructing) { |
|
27 savedFrame = frame; |
|
28 assertEq(savedFrame.live, true); |
|
29 return undefined; |
|
30 } |
|
31 return undefined; |
|
32 }; |
|
33 hits = 0; |
|
34 debuggee.hits = 0; |
|
35 savedFrame = undefined; |
|
36 assertEq(typeof debuggee.eval("function f(){ hits++; } f.prototype = {}; new f;"), "object"); |
|
37 assertEq(hits, 2); |
|
38 assertEq(savedFrame.live, false); |
|
39 assertEq(debuggee.hits, 1); |
|
40 |
|
41 // Force an early return from the constructor. |
|
42 dbg.onEnterFrame = function (frame) { |
|
43 hits++; |
|
44 if (frame.constructing) { |
|
45 savedFrame = frame; |
|
46 assertEq(savedFrame.live, true); |
|
47 return { return: "pass" }; |
|
48 } |
|
49 return undefined; |
|
50 }; |
|
51 hits = 0; |
|
52 debuggee.hits = 0; |
|
53 savedFrame = undefined; |
|
54 assertEq(typeof debuggee.eval("function f(){ hits++; } f.prototype = {}; new f;"), "object"); |
|
55 assertEq(hits, 2); |
|
56 assertEq(savedFrame.live, false); |
|
57 assertEq(debuggee.hits, 0); |
|
58 |
|
59 // Force the constructor to throw an exception. |
|
60 dbg.onEnterFrame = function (frame) { |
|
61 hits++; |
|
62 if (frame.constructing) { |
|
63 savedFrame = frame; |
|
64 assertEq(savedFrame.live, true); |
|
65 return { throw: "pass" }; |
|
66 } |
|
67 return undefined; |
|
68 }; |
|
69 hits = 0; |
|
70 debuggee.hits = 0; |
|
71 savedFrame = undefined; |
|
72 assertThrowsValue(function () { |
|
73 debuggee.eval("function f(){ hits++ } f.prototype = {}; new f;"); |
|
74 }, "pass"); |
|
75 assertEq(hits, 2); |
|
76 assertEq(savedFrame.live, false); |
|
77 assertEq(debuggee.hits, 0); |
|
78 |
|
79 // Ensure that forcing an early return only returns from one JS call. |
|
80 debuggee.eval("function g() { var result = new f; g_hits++; return result; }"); |
|
81 dbg.onEnterFrame = function (frame) { |
|
82 hits++; |
|
83 if (frame.constructing) { |
|
84 savedFrame = frame; |
|
85 assertEq(savedFrame.live, true); |
|
86 return { return: "pass" }; |
|
87 } |
|
88 return undefined; |
|
89 }; |
|
90 hits = 0; |
|
91 debuggee.hits = 0; |
|
92 debuggee.g_hits = 0; |
|
93 savedFrame = undefined; |
|
94 assertEq(typeof debuggee.eval("g();"), "object"); |
|
95 assertEq(hits, 3); |
|
96 assertEq(savedFrame.live, false); |
|
97 assertEq(debuggee.hits, 0); |
|
98 assertEq(debuggee.g_hits, 1); |