8015892: canBeUndefined too conservative for some use before declaration cases
Reviewed-by: attila, hannesw
--- a/nashorn/src/jdk/nashorn/internal/codegen/Attr.java Fri Jun 07 17:44:25 2013 +0200
+++ b/nashorn/src/jdk/nashorn/internal/codegen/Attr.java Mon Jun 10 13:21:29 2013 +0200
@@ -202,18 +202,52 @@
private void acceptDeclarations(final FunctionNode functionNode, final Block body) {
// This visitor will assign symbol to all declared variables, except function declarations (which are taken care
// in a separate step above) and "var" declarations in for loop initializers.
+ //
+ // It also handles the case that a variable can be undefined, e.g
+ // if (cond) {
+ // x = x.y;
+ // }
+ // var x = 17;
+ //
+ // by making sure that no identifier has been found earlier in the body than the
+ // declaration - if such is the case the identifier is flagged as caBeUndefined to
+ // be safe if it turns into a local var. Otherwise corrupt bytecode results
+
body.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
+ private final Set<String> uses = new HashSet<>();
+ private final Set<String> canBeUndefined = new HashSet<>();
+
@Override
public boolean enterFunctionNode(final FunctionNode nestedFn) {
return false;
}
@Override
+ public Node leaveIdentNode(final IdentNode identNode) {
+ uses.add(identNode.getName());
+ return identNode;
+ }
+
+ @Override
+ public boolean enterVarNode(final VarNode varNode) {
+ final String name = varNode.getName().getName();
+ //if this is used the var node symbol needs to be tagged as can be undefined
+ if (uses.contains(name)) {
+ canBeUndefined.add(name);
+ }
+ return true;
+ }
+
+ @Override
public Node leaveVarNode(final VarNode varNode) {
// any declared symbols that aren't visited need to be typed as well, hence the list
if (varNode.isStatement()) {
final IdentNode ident = varNode.getName();
final Symbol symbol = defineSymbol(body, ident.getName(), IS_VAR);
+ if (canBeUndefined.contains(ident.getName())) {
+ symbol.setType(Type.OBJECT);
+ symbol.setCanBeUndefined();
+ }
functionNode.addDeclaredSymbol(symbol);
if (varNode.isFunctionDeclaration()) {
newType(symbol, FunctionNode.FUNCTION_TYPE);
--- a/nashorn/src/jdk/nashorn/internal/ir/Symbol.java Fri Jun 07 17:44:25 2013 +0200
+++ b/nashorn/src/jdk/nashorn/internal/ir/Symbol.java Mon Jun 10 13:21:29 2013 +0200
@@ -462,7 +462,7 @@
*/
public void setCanBeUndefined() {
assert type.isObject() : type;
- if(!canBeUndefined()) {
+ if (!isParam() && !canBeUndefined()) {//parameters are never undefined
assert !isShared();
flags |= CAN_BE_UNDEFINED;
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8015892.js Mon Jun 10 13:21:29 2013 +0200
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2010, 2013, 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-8015892.js : use before definition with valid declaration that turns into
+ * local var must be "canBeUndefined"
+ *
+ * @test
+ * @run
+ */
+
+function doIt() {
+ if (something) {
+ x = x.obj;
+ } else {
+ var x = "x";
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/fib_wtf.js Mon Jun 10 13:21:29 2013 +0200
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2010, 2013, 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.
+ */
+
+/**
+ * fib_wtf - obfuscated fibonacci
+ *
+ * @test
+ * @run
+ */
+
+function fib(_) {
+ for(_=[+[],++[[]][+[]],+[],_],_[++[++[++[[]][+[]]][+[]]][+[]]]=(((_[++[++[++[[]][+[]]][+[]]][+[]]]-(++[[]][+[]]))&(((--[[]][+[]])>>>(++[[]][+[]]))))===(_[++[++[++[[]][+[]]][+[]]][+[]]]-(++[[]][+[]])))?(_[++[++[[]][+[]]][+[]]]=++[[]][+[]],_[++[++[++[[]][+[]]][+[]]][+[]]]-(++[[]][+[]])):+[];_[++[++[++[[]][+[]]][+[]]][+[]]]--;_[+[]]=(_[++[[]][+[]]]=_[++[++[[]][+[]]][+[]]]=_[+[]]+_[++[[]][+[]]])-_[+[]]);
+ return _[++[++[[]][+[]]][+[]]];
+}
+
+for (var x = -1; x <= 63; x++) {
+ print(fib(x));
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/fib_wtf.js.EXPECTED Mon Jun 10 13:21:29 2013 +0200
@@ -0,0 +1,65 @@
+0
+0
+1
+1
+2
+3
+5
+8
+13
+21
+34
+55
+89
+144
+233
+377
+610
+987
+1597
+2584
+4181
+6765
+10946
+17711
+28657
+46368
+75025
+121393
+196418
+317811
+514229
+832040
+1346269
+2178309
+3524578
+5702887
+9227465
+14930352
+24157817
+39088169
+63245986
+102334155
+165580141
+267914296
+433494437
+701408733
+1134903170
+1836311903
+2971215073
+4807526976
+7778742049
+12586269025
+20365011074
+32951280099
+53316291173
+86267571272
+139583862445
+225851433717
+365435296162
+591286729879
+956722026041
+1548008755920
+2504730781961
+4052739537881
+6557470319842