8134488: var statement in if(false) block incorrectly evacuated into enclosing function
authorattila
Fri, 25 Sep 2015 17:53:06 +0200
changeset 32787 c49a2638ad02
parent 32786 dedf2b6ea495
child 32788 c55cf68474be
8134488: var statement in if(false) block incorrectly evacuated into enclosing function Reviewed-by: hannesw, sundar
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/FoldConstants.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Lower.java
nashorn/test/script/basic/JDK-8134488.js
nashorn/test/script/basic/JDK-8134488.js.EXPECTED
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/FoldConstants.java	Fri Sep 25 15:57:57 2015 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/FoldConstants.java	Fri Sep 25 17:53:06 2015 +0200
@@ -116,7 +116,7 @@
                 statements.addAll(executed.getStatements()); // Get statements form executed branch
             }
             if (dropped != null) {
-                extractVarNodes(dropped, statements); // Get var-nodes from non-executed branch
+                extractVarNodesFromDeadCode(dropped, statements); // Get var-nodes from non-executed branch
             }
             if (statements.isEmpty()) {
                 return new EmptyNode(ifNode);
@@ -185,14 +185,27 @@
         protected abstract LiteralNode<?> eval();
     }
 
-    private static void extractVarNodes(final Block block, final List<Statement> statements) {
-        final LexicalContext lc = new LexicalContext();
-        block.accept(lc, new NodeVisitor<LexicalContext>(lc) {
+    /**
+     * When we eliminate dead code, we must preserve var declarations as they are scoped to the whole
+     * function. This method gathers var nodes from code passed to it, removing their initializers.
+     *
+     * @param deadCodeRoot the root node of eliminated dead code
+     * @param statements a list that will be receiving the var nodes from the dead code, with their
+     * initializers removed.
+     */
+    static void extractVarNodesFromDeadCode(final Node deadCodeRoot, final List<Statement> statements) {
+        deadCodeRoot.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
             @Override
             public boolean enterVarNode(final VarNode varNode) {
                 statements.add(varNode.setInit(null));
                 return false;
             }
+
+            @Override
+            public boolean enterFunctionNode(final FunctionNode functionNode) {
+                // Don't descend into nested functions
+                return false;
+            }
         });
     }
 
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Lower.java	Fri Sep 25 15:57:57 2015 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Lower.java	Fri Sep 25 17:53:06 2015 +0200
@@ -121,22 +121,7 @@
                             terminated = true;
                         }
                     } else {
-                        statement.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
-                            @Override
-                            public boolean enterVarNode(final VarNode varNode) {
-                                // We can't entirely eliminate dead statements, as var declarations are scoped
-                                // to the whole function so we need to preserve them although without
-                                // initializers.
-                                newStatements.add(varNode.setInit(null));
-                                return false;
-                            }
-
-                            @Override
-                            public boolean enterFunctionNode(final FunctionNode functionNode) {
-                                // Don't descend into nested functions when searching for VarNodes, though.
-                                return false;
-                            }
-                        });
+                        FoldConstants.extractVarNodesFromDeadCode(statement, newStatements);
                     }
                 }
                 return newStatements;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8134488.js	Fri Sep 25 17:53:06 2015 +0200
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2015 Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * 
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ * 
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ * 
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ * 
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8134488: var statement in if(false) block incorrectly evacuated into enclosing function
+ *
+ * @test
+ * @run
+ */
+
+var x = "string"; 
+print(x); 
+
+(function f1() { 
+    (function f2() { 
+        // If it finds both 'print' and 'x', it'll print 'string'.
+        print(x); 
+    })(); 
+
+    if (false) { 
+        (function f3() { 
+            var x; 
+        })(); 
+    } 
+
+})(); 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8134488.js.EXPECTED	Fri Sep 25 17:53:06 2015 +0200
@@ -0,0 +1,2 @@
+string
+string