| "use strict"; |
| |
| function truth() { |
| return true; |
| } |
| noInline(truth); |
| |
| function assert(cond) { |
| if (!cond) |
| throw new Error("broke assertion"); |
| } |
| noInline(assert); |
| |
| function shouldThrowTDZ(func) { |
| var hasThrown = false; |
| try { |
| func(); |
| } catch(e) { |
| if (e.name.indexOf("ReferenceError") !== -1) |
| hasThrown = true; |
| } |
| assert(hasThrown); |
| } |
| noInline(shouldThrowTDZ); |
| |
| // Test cases |
| |
| const NUM_LOOPS = 1000; |
| const SHORT_LOOPS = 100; |
| |
| ;(function() { |
| function foo() { |
| x; |
| const x = 20; |
| } |
| function bar() { |
| const x = x; |
| } |
| function baz() { |
| const {x: prop, y: prop2} = {x: prop}; |
| } |
| function jaz() { |
| const {x: prop, y: prop2} = {x: 20, y: prop}; |
| } |
| for (var i = 0; i < NUM_LOOPS; i++) { |
| shouldThrowTDZ(foo); |
| shouldThrowTDZ(bar); |
| shouldThrowTDZ(baz); |
| shouldThrowTDZ(jaz); |
| } |
| })(); |
| |
| |
| ;(function() { |
| function foo() { |
| x; |
| const x = 20; |
| function captureX() { return x; } |
| } |
| function bar() { |
| captureX(); |
| const x = 20; |
| function captureX() { return x; } |
| } |
| |
| for (var i = 0; i < NUM_LOOPS; i++) { |
| shouldThrowTDZ(foo); |
| shouldThrowTDZ(bar); |
| } |
| })(); |
| |
| |
| ;(function() { |
| function foo() { |
| if (truth()) { |
| const x = 20; |
| assert(x === 20); |
| } |
| x; |
| const x = 20; |
| } |
| |
| for (var i = 0; i < NUM_LOOPS; i++) { |
| shouldThrowTDZ(foo); |
| } |
| })(); |
| |
| |
| |
| ;(function() { |
| function foo() { |
| if (truth()) { |
| const y = 20; |
| const captureY = function() { return y; } |
| assert(y === 20); |
| x; |
| } |
| const x = 20; |
| const y = 40; |
| } |
| |
| for (var i = 0; i < NUM_LOOPS; i++) { |
| shouldThrowTDZ(foo); |
| } |
| })(); |
| |
| |
| ;(function() { |
| function foo() { |
| if (truth()) { |
| const y = 20; |
| const x = 40; |
| const captureAll = function() { return x + y; } |
| assert(y === 20); |
| assert(x === 40); |
| assert(captureAll() === 60); |
| } |
| tdz; |
| const tdz = 20; |
| } |
| |
| for (var i = 0; i < NUM_LOOPS; i++) { |
| shouldThrowTDZ(foo); |
| } |
| })(); |
| |
| |
| ;(function() { |
| function foo() { |
| if (truth()) { |
| const y = 20; |
| const x = 40; |
| const captureAll = function() { return x + y + tdz; } |
| assert(y === 20); |
| assert(x === 40); |
| } |
| tdz; |
| const tdz = 20; |
| } |
| |
| for (var i = 0; i < NUM_LOOPS; i++) { |
| shouldThrowTDZ(foo); |
| } |
| })(); |
| |
| |
| ;(function() { |
| function foo() { |
| x = 10; |
| const x = 20; |
| } |
| |
| for (var i = 0; i < NUM_LOOPS; i++) { |
| shouldThrowTDZ(foo); |
| } |
| })(); |
| |
| |
| ;(function() { |
| function foo() { |
| x = 10; |
| const x = 20; |
| function cap() { return x; } |
| } |
| function bar() { |
| captureX(); |
| const x = 20; |
| function captureX() { return x; } |
| } |
| |
| for (var i = 0; i < NUM_LOOPS; i++) { |
| shouldThrowTDZ(foo); |
| shouldThrowTDZ(bar); |
| } |
| })(); |
| |
| |
| ;(function() { |
| function foo() { |
| if (!truth()) { |
| y; |
| assert(false); |
| } |
| const y = undefined; |
| assert(y === undefined); |
| if (truth()) { |
| x; |
| } |
| const x = undefined; |
| } |
| |
| for (var i = 0; i < NUM_LOOPS; i++) { |
| shouldThrowTDZ(foo); |
| } |
| })(); |
| |
| |
| ;(function() { |
| function foo() { |
| eval("x;"); |
| const x = 20; |
| } |
| function bar() { |
| function captureX() { return x; } |
| eval("captureX();"); |
| const x = 20; |
| } |
| function baz() { |
| function captureX() { return x; } |
| function other() { return captureX; } |
| other()(); |
| const x = 20; |
| } |
| |
| for (var i = 0; i < SHORT_LOOPS; i++) { |
| shouldThrowTDZ(foo); |
| shouldThrowTDZ(bar); |
| shouldThrowTDZ(baz); |
| } |
| })(); |
| |
| |
| ;(function() { |
| function foo() { |
| const y = 40; |
| eval("y; x;"); |
| const x = 20; |
| } |
| |
| for (var i = 0; i < 1; i++) { |
| shouldThrowTDZ(foo); |
| } |
| })(); |
| |
| |
| ;(function() { |
| function foo() { |
| const x = 20; |
| const y = 40; |
| assert(eval("x;") === 20); |
| if (truth()) { |
| assert(eval("eval('y');") === 40); |
| eval("eval('x');"); |
| const x = 40; |
| } |
| } |
| |
| for (var i = 0; i < SHORT_LOOPS; i++) { |
| shouldThrowTDZ(foo); |
| } |
| })(); |
| |
| |
| // FunctionResolveNode |
| ;(function() { |
| function foo() { |
| function captureX() { return x; } |
| x(); |
| const x = function() { return 20; }; |
| } |
| |
| function bar() { |
| x(); |
| let x = function() { return 20; }; |
| } |
| |
| for (var i = 0; i < NUM_LOOPS; i++) { |
| shouldThrowTDZ(foo); |
| shouldThrowTDZ(bar); |
| } |
| })(); |
| |
| |
| // TypeofResolveNode |
| ;(function() { |
| function foo() { |
| function captureX() { return x; } |
| typeof x; |
| const x = function() { return 20; }; |
| } |
| |
| function bar() { |
| typeof x; |
| const x = function() { return 20; }; |
| } |
| |
| for (var i = 0; i < NUM_LOOPS; i++) { |
| shouldThrowTDZ(foo); |
| shouldThrowTDZ(bar); |
| } |
| })(); |
| |
| |
| // ReadModifyResolveNode |
| ;(function() { |
| function foo() { |
| function captureX() { return x; } |
| x++; |
| const x = 20; |
| } |
| |
| function bar() { |
| x--; |
| const x = 30; |
| } |
| |
| function baz() { |
| x *= 40; |
| const x = 30; |
| } |
| |
| function kaz() { |
| function captureX() { return x; } |
| x /= 20; |
| const x = 20; |
| } |
| |
| function haz() { |
| function captureX() { return x; } |
| --x; |
| const x = 20; |
| } |
| |
| function jaz() { |
| --x; |
| const x = 30; |
| } |
| |
| for (var i = 0; i < NUM_LOOPS; i++) { |
| shouldThrowTDZ(foo); |
| shouldThrowTDZ(bar); |
| shouldThrowTDZ(baz); |
| shouldThrowTDZ(kaz); |
| shouldThrowTDZ(haz); |
| shouldThrowTDZ(jaz); |
| } |
| })(); |
| |
| |
| ;(function() { |
| function foo(x) { |
| const y = 50; |
| let result = null; |
| switch(x) { |
| case 10: |
| const y = 40; |
| assert(y === 40); |
| case 20: |
| y += 1; |
| assert(y === 41); |
| result = y; |
| break; |
| default: |
| result = x; |
| break; |
| } |
| assert(y === 50); |
| return result; |
| } |
| function bar(x) { |
| const y = 50; |
| let result = null; |
| switch(x) { |
| case 10: |
| const y = 40; |
| assert(y === 40); |
| case 20: |
| const capY = function() { return y; } |
| y += 1; |
| assert(y === 41); |
| result = y; |
| break; |
| default: |
| result = x; |
| break; |
| } |
| assert(y === 50); |
| return result; |
| } |
| function baz(x) { |
| const y = 50; |
| let result = null; |
| switch(x) { |
| case 10: |
| const y = 40; |
| assert(y === 40); |
| case 20: |
| let inc = function() { y += 1; } |
| inc(); |
| assert(y === 41); |
| result = y; |
| break; |
| default: |
| result = x; |
| break; |
| } |
| assert(y === 50); |
| return result; |
| } |
| |
| for (var i = 0; i < NUM_LOOPS; i++) { |
| shouldThrowTDZ(function() { foo(20); }); |
| shouldThrowTDZ(function() { bar(20); }); |
| shouldThrowTDZ(function() { baz(20); }); |
| } |
| })(); |
| |
| |
| ;(function() { |
| function foo() { |
| [x] = [1]; |
| const x = null; |
| } |
| |
| function boo() { |
| [x] = [1]; |
| const x = 20; |
| function capX() { return x; } |
| } |
| |
| function bar() { |
| ({a, p: y} = {a: 100, p: 40}); |
| const y = 40; |
| } |
| |
| function zar() { |
| ({a, p: y} = {a: 100, p: 40}); |
| const y = 10; |
| function capY() { return y; } |
| } |
| |
| function baz() { |
| ({a, p: {y}} = {a: 100, p: {p: {y: 40}}}); |
| const y = 100; |
| } |
| |
| function jaz() { |
| ({y} = {}); |
| const y = null; |
| } |
| |
| for (var i = 0; i < NUM_LOOPS; i++) { |
| shouldThrowTDZ(foo); |
| shouldThrowTDZ(boo); |
| shouldThrowTDZ(bar); |
| shouldThrowTDZ(zar); |
| shouldThrowTDZ(baz); |
| shouldThrowTDZ(jaz); |
| } |
| })(); |