8134488: var statement in if(false) block incorrectly evacuated into enclosing function
Reviewed-by: hannesw, sundar
--- 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