8015892: canBeUndefined too conservative for some use before declaration cases
authorlagergren
Mon, 10 Jun 2013 13:21:29 +0200
changeset 18319 0e1497116130
parent 18318 5e4244619d79
child 18320 9cb04632b21a
8015892: canBeUndefined too conservative for some use before declaration cases Reviewed-by: attila, hannesw
nashorn/src/jdk/nashorn/internal/codegen/Attr.java
nashorn/src/jdk/nashorn/internal/ir/Symbol.java
nashorn/test/script/basic/JDK-8015892.js
nashorn/test/script/basic/fib_wtf.js
nashorn/test/script/basic/fib_wtf.js.EXPECTED
--- 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