| function loop(f, expected) { |
| // This is the loop that breaks us. |
| // At record time, f's parent is a Call object with no fp. |
| // At second execute time, it is a Call object with fp, |
| // and all the Call object's dslots are still JSVAL_VOID. |
| for (var i = 0; i < 9; i++) |
| assertEq(f(), expected); |
| } |
| |
| function C(bad) { |
| var x = bad; |
| function f() { |
| return x; // We trick TR::callProp() into emitting code that gets |
| // JSVAL_VOID (from the Call object's dslots) |
| // rather than the actual value (true or false). |
| } |
| if (bad) |
| void (f + "a!"); |
| return f; |
| } |
| |
| var obj = { |
| }; |
| |
| // Warm up and trace with C's Call object entrained but its stack frame gone. |
| loop(C.call(obj, false), false); |
| |
| // Sneaky access to f via a prototype method called implicitly by operator +. |
| Function.prototype.toString = function () { loop(this, true); return "hah"; }; |
| |
| // Fail hard if we don't handle the implicit call out of C to F.p.toString. |
| C.call(obj, true); |