[turbofan] Fix broken dynamic TDZ check for let and const.
authormstarzinger <mstarzinger@chromium.org>
Wed, 26 Aug 2015 09:52:59 +0000 (02:52 -0700)
committerCommit bot <commit-bot@chromium.org>
Wed, 26 Aug 2015 09:53:11 +0000 (09:53 +0000)
This fixes broken dynamic hole-checks for the temporal dead zone of
non-initializing assignments to {let} and {const} declared variables.
Also note that this exemplifies a case where the dynamic check for such
assignments to {let} declared variables can no longer be elided as the
comment suggested.

R=rossberg@chromium.org
TEST=mjsunit/regress/regress-4388
BUG=v8:4388
LOG=n

Review URL: https://codereview.chromium.org/1318693002

Cr-Commit-Position: refs/heads/master@{#30375}

src/compiler/ast-graph-builder.cc
test/mjsunit/regress/regress-4388.js [new file with mode: 0644]

index c31bdb1..255e231 100644 (file)
@@ -3511,13 +3511,10 @@ Node* AstGraphBuilder::BuildVariableAssignment(
         return value;
       } else if (mode == LET && op != Token::INIT_LET) {
         // Perform an initialization check for let declared variables.
-        // Also note that the dynamic hole-check is only done to ensure that
-        // this does not break in the presence of do-expressions within the
-        // temporal dead zone of a let declared variable.
         Node* current = environment()->Lookup(variable);
         if (current->op() == the_hole->op()) {
           value = BuildThrowReferenceError(variable, bailout_id);
-        } else if (value->opcode() == IrOpcode::kPhi) {
+        } else if (current->opcode() == IrOpcode::kPhi) {
           value = BuildHoleCheckThenThrow(current, variable, value, bailout_id);
         }
       } else if (mode == CONST && op == Token::INIT_CONST) {
@@ -3533,7 +3530,7 @@ Node* AstGraphBuilder::BuildVariableAssignment(
         Node* current = environment()->Lookup(variable);
         if (current->op() == the_hole->op()) {
           return BuildThrowReferenceError(variable, bailout_id);
-        } else if (value->opcode() == IrOpcode::kPhi) {
+        } else if (current->opcode() == IrOpcode::kPhi) {
           BuildHoleCheckThenThrow(current, variable, value, bailout_id);
         }
         return BuildThrowConstAssignError(bailout_id);
diff --git a/test/mjsunit/regress/regress-4388.js b/test/mjsunit/regress/regress-4388.js
new file mode 100644 (file)
index 0000000..908bccc
--- /dev/null
@@ -0,0 +1,35 @@
+// 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: --allow-natives-syntax --turbo-filter=test*
+
+// Tests that TurboFan emits a dynamic hole-check for the temporal dead zone at
+// a non-initializing assignments to a {let} variable.
+function test_hole_check_for_let(a) {
+  'use strict';
+  { switch (a) {
+      case 0: let x;
+      case 1: x = 9;
+    }
+  }
+}
+assertDoesNotThrow("test_hole_check_for_let(0)");
+assertThrows("test_hole_check_for_let(1)", ReferenceError);
+%OptimizeFunctionOnNextCall(test_hole_check_for_let)
+assertThrows("test_hole_check_for_let(1)", ReferenceError);
+
+// Tests that TurboFan emits a dynamic hole-check for the temporal dead zone at
+// a non-initializing assignments to a {const} variable.
+function test_hole_check_for_const(a) {
+  'use strict';
+  { switch (a) {
+      case 0: const x = 3;
+      case 1: x = 2;
+    }
+  }
+}
+assertThrows("test_hole_check_for_const(0)", TypeError);
+assertThrows("test_hole_check_for_const(1)", ReferenceError);
+%OptimizeFunctionOnNextCall(test_hole_check_for_const)
+assertThrows("test_hole_check_for_const(1)", ReferenceError);