From 2636a2fe037220e236fe1eee72edbdfd366de177 Mon Sep 17 00:00:00 2001 From: lagergren Date: Mon, 10 Jun 2013 13:21:29 +0200 Subject: [PATCH] 8015892: canBeUndefined too conservative for some use before declaration cases Reviewed-by: attila, hannesw --- src/jdk/nashorn/internal/codegen/Attr.java | 34 +++++++++++ src/jdk/nashorn/internal/ir/Symbol.java | 2 +- test/script/basic/JDK-8015892.js | 38 +++++++++++++ test/script/basic/fib_wtf.js | 38 +++++++++++++ test/script/basic/fib_wtf.js.EXPECTED | 65 ++++++++++++++++++++++ 5 files changed, 176 insertions(+), 1 deletion(-) create mode 100644 test/script/basic/JDK-8015892.js create mode 100644 test/script/basic/fib_wtf.js create mode 100644 test/script/basic/fib_wtf.js.EXPECTED diff --git a/src/jdk/nashorn/internal/codegen/Attr.java b/src/jdk/nashorn/internal/codegen/Attr.java index d0b5a00a..f330fb80 100644 --- a/src/jdk/nashorn/internal/codegen/Attr.java +++ b/src/jdk/nashorn/internal/codegen/Attr.java @@ -202,18 +202,52 @@ final class Attr extends NodeOperatorVisitor { 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(new LexicalContext()) { + private final Set uses = new HashSet<>(); + private final Set 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); diff --git a/src/jdk/nashorn/internal/ir/Symbol.java b/src/jdk/nashorn/internal/ir/Symbol.java index d26fe561..2f7ec129 100644 --- a/src/jdk/nashorn/internal/ir/Symbol.java +++ b/src/jdk/nashorn/internal/ir/Symbol.java @@ -462,7 +462,7 @@ public final class Symbol implements Comparable { */ public void setCanBeUndefined() { assert type.isObject() : type; - if(!canBeUndefined()) { + if (!isParam() && !canBeUndefined()) {//parameters are never undefined assert !isShared(); flags |= CAN_BE_UNDEFINED; } diff --git a/test/script/basic/JDK-8015892.js b/test/script/basic/JDK-8015892.js new file mode 100644 index 00000000..a6ab4c8b --- /dev/null +++ b/test/script/basic/JDK-8015892.js @@ -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"; + } +} diff --git a/test/script/basic/fib_wtf.js b/test/script/basic/fib_wtf.js new file mode 100644 index 00000000..a48ebc5c --- /dev/null +++ b/test/script/basic/fib_wtf.js @@ -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)); +} diff --git a/test/script/basic/fib_wtf.js.EXPECTED b/test/script/basic/fib_wtf.js.EXPECTED new file mode 100644 index 00000000..c33277ca --- /dev/null +++ b/test/script/basic/fib_wtf.js.EXPECTED @@ -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 -- GitLab