1
// Two Environments nested in the same runtime scope share the correct tail of their parent chains.
3
// The compiler must be allowed to elide empty scopes and so forth, so this
4
// test does not check the number of unshared Environments. Instead, each test
5
// case identifies the expected innermost shared scope by the name of a
8
var g = newGlobal('new-compartment');
9
g.eval("function h() { debugger; }");
10
var dbg = Debugger(g);
11
var hits, name, shared, unshared;
12
dbg.onDebuggerStatement = function (hframe) {
13
var frame = hframe.older;
15
// Find name in frame.environment.
16
var env, child = null;
17
for (env = frame.environment; env !== null; env = env.parent) {
18
if (env.names().indexOf(name) != -1)
22
assertEq(env !== null, true, "expected '" + name + "' to be in scope");
23
assertEq(env, frame.environment.find(name),
24
"env.find should find the same frame as the written out search");
32
assertEq(env, shared, "the environment containing '" + name + "' should be shared");
33
assertEq(child === null || unshared === null || unshared !== child, true,
34
"environments nested within the one containing '" + name + "' should not be shared");
39
function test(sharedName, expectedHits, code) {
42
shared = unshared = undefined;
44
assertEq(hits, expectedHits);
49
// (The stray "a = b" assignments in these tests are to inhibit the flat closure
50
// optimization, which Environments expose. There's nothing really wrong with
51
// the optimization or with the debugger exposing it, but that's not what we
52
// want to test here.)
54
test("q", 2, "var q = function (a) { h(); }; q(1); q(2);");
55
test("a", 2, "q = function (a) { (function (b) { h(); a = b; })(2); h(); }; q(1);");
56
test("a", 2, "q = function (a) { h(); return function (b) { h(); a = b; }; }; q(1)(2);");
57
test("n", 3, "q = function (n) { for (var i = 0; i < n; i++) { let (j = i) { h(); } } }; q(3);");
59
// Don't crash in E4X filter scopes.
60
test("x", 2, "q = function () { var x = <><y/><z/></>.(function (e) { h(); }(this)); }; q();");
62
// A function with long dynamic and static chains.
65
var code = "function f" + N + "(a" + N + ") {\neval('a0 + a1'); h();\n}\n";
66
for (var i = N; --i >= 0;) {
67
var call = "f" + (i + 1) + "(a" + i + " - 1);\n";
68
code = ("function f" + i + "(a" + i + ") {\n" +
71
"if (a" + i + " === 0) " + call +
76
test("a0", 2, "f0(0);");
77
test("a17", 2, "f0(17);");
78
test("a" + (N-2), 2, "f0(" + (N-2) + ");");
79
test("a" + (N-1), 2, "f0(" + (N-1) + ");");
81
// A function with a short dynamic chain and a long static chain.
84
function DeepStaticShallowDynamic(i, n) {
85
var code = "function f" + i + "(a" + i + ") {\n";
87
code += "eval('a1 + a2'); h();\n";
89
code += "return " + DeepStaticShallowDynamic(i+1, n) + ";\n";
93
g.eval(DeepStaticShallowDynamic(1, N));
95
function range(start, stop) {
96
for (var i = start; i < stop; i++)
100
function DSSDsplit(s) {
101
return ("var mid = f1" + ["(" + i + ")" for (i in range(0, s))].join("") + ";\n" +
102
"mid" + ["(" + i + ")" for (i in range(s, N))].join("") + ";\n" +
103
"mid" + ["(" + i + ")" for (i in range(s, N))].join("") + ";\n");
106
test("a1", 2, DSSDsplit(1));
107
test("a17", 2, DSSDsplit(17));
108
test("a" + (N-2), 2, DSSDsplit(N-2));
109
test("a" + (N-1), 2, DSSDsplit(N-1));