d6fb6de709
Switch statements introduce their own scope for cases, but this scope is not necessarily executed in order, as the following function shows: switch (x) { case 1: let y = 1; case 2: y = 2; case 3: print(y); } If x = 2 or x = 3, the code should throw a ReferenceError. However, FullCodeGen's hole check elimination used the simple algorithm of assuming that if the initializer was in the same scope, then it was reached before the use, and therefore the hole check could be eliminated. This patch adds an extra bit to scopes, to track if they may nonlinearly. The parser marks the scope that switch introduces as nonlinear. FullCodeGen does not eliminate the hole check from a scope which is nonlinear. This patch refactors FullCodeGen to put the hole check elimination in one place, rather than in each backend. BUG=v8:3926 LOG=Y R=adamk Review URL: https://codereview.chromium.org/1312613003 Cr-Commit-Position: refs/heads/master@{#30453}
88 lines
2.0 KiB
JavaScript
88 lines
2.0 KiB
JavaScript
// Copyright 2015 the V8 project authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
// Flags: --harmony-sloppy --harmony-sloppy-let
|
|
|
|
// See: http://code.google.com/p/v8/issues/detail?id=3926
|
|
|
|
// Switch statements should disable hole check elimination
|
|
|
|
// Ensure that both reads and writes encounter the hole check
|
|
// FullCodeGen had an issue on reads; TurboFan had an issue on writes
|
|
function f(x) {
|
|
var z;
|
|
switch (x) {
|
|
case 1:
|
|
let y = 1;
|
|
case 2:
|
|
y = 2;
|
|
case 3:
|
|
z = y;
|
|
}
|
|
return z;
|
|
}
|
|
assertEquals(2, f(1));
|
|
assertThrows(function() {f(2)}, ReferenceError);
|
|
assertThrows(function() {f(3)}, ReferenceError);
|
|
|
|
// Ensure that hole checks are done even in subordinate scopes
|
|
assertThrows(function() {
|
|
switch (1) {
|
|
case 0:
|
|
let x = 2;
|
|
case 1:
|
|
{ // this block, plus the let below, adds another linear lexical scope
|
|
let y = 3;
|
|
x;
|
|
}
|
|
}
|
|
}, ReferenceError);
|
|
|
|
// Ensure that inner functions and eval don't skip hole checks
|
|
|
|
function g(x) {
|
|
switch (x) {
|
|
case 1:
|
|
let z;
|
|
case 2:
|
|
return function() { z = 1; }
|
|
case 3:
|
|
return function() { return z; }
|
|
case 4:
|
|
return eval("z = 1");
|
|
case 5:
|
|
return eval("z");
|
|
}
|
|
}
|
|
|
|
assertEquals(undefined, g(1)());
|
|
assertThrows(g(2), ReferenceError);
|
|
assertThrows(g(3), ReferenceError);
|
|
assertThrows(function () {g(4)}, ReferenceError);
|
|
assertThrows(function () {g(5)}, ReferenceError);
|
|
|
|
// Ensure the same in strict mode, with different eval and function semantics
|
|
|
|
function h(x) {
|
|
'use strict'
|
|
switch (x) {
|
|
case 1:
|
|
let z;
|
|
case 2:
|
|
return function() { z = 1; }
|
|
case 3:
|
|
return function() { return z; }
|
|
case 4:
|
|
return eval("z = 1");
|
|
case 5:
|
|
return eval("z");
|
|
}
|
|
}
|
|
|
|
assertEquals(undefined, h(1)());
|
|
assertThrows(h(2), ReferenceError);
|
|
assertThrows(h(3), ReferenceError);
|
|
assertThrows(function () {h(4)}, ReferenceError);
|
|
assertThrows(function () {h(5)}, ReferenceError);
|