| // Test reading and setting values on "hollow" debug scopes. In testGet and |
| // testSet below, f and g *must* be called from a non-heavyweight lambda to |
| // trigger the creation of the "hollow" debug scopes for the missing scopes. |
| // |
| // The reason is that a direct call to f or g that accesses a in testGet or |
| // testSet's frame is actually recoverable. The Debugger can synthesize a scope |
| // based on the frame. By contorting through a lambda, it becomes unsound to |
| // synthesize a scope based on the lambda function's frame. Since f and g are |
| // accessing a, which is itself free inside the lambda, the Debugger has no way |
| // to tell if the on-stack testGet or testSet frame is the frame that *would |
| // have* allocated a scope for the lambda, *had the lambda been heavyweight*. |
| // |
| // More concretely, if the inner lambda were returned from testGet and testSet, |
| // then called from a different invocation of testGet or testSet, it becomes |
| // obvious that it is incorrect to synthesize a scope based on the frame of |
| // that different invocation. |
| |
| load(libdir + "evalInFrame.js"); |
| |
| function f() { |
| // Eval one frame up. Nothing aliases a. |
| evalInFrame(1, "print(a)"); |
| } |
| |
| function g() { |
| evalInFrame(1, "a = 43"); |
| } |
| |
| function testGet() { |
| { |
| let a = 42; |
| (function () { f(); })(); |
| } |
| } |
| |
| function testSet() { |
| { |
| let a = 42; |
| (function () { g(); })(); |
| } |
| } |
| |
| var log = ""; |
| |
| try { |
| testGet(); |
| } catch (e) { |
| // Throws due to a having been optimized out. |
| log += "g"; |
| } |
| |
| try { |
| testSet(); |
| } catch (e) { |
| // Throws due to a having been optimized out. |
| log += "s"; |
| } |
| |
| assertEq(log, "gs"); |