v8/test/mjsunit/regress/regress-3926.js
littledan d6fb6de709 Ensure hole checks take place in switch statement scopes
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}
2015-08-28 18:49:57 +00:00

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);