From 4e011cfb8c0805708981bbccb01d5e5b42878610 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hannes=20Walln=C3=B6fer?= Date: Mon, 8 Jul 2013 19:34:55 +0200 Subject: [PATCH 01/15] 8019963: empty char range in regex Reviewed-by: jlaskey, sundar --- .../runtime/regexp/joni/CodeRangeBuffer.java | 2 +- .../internal/runtime/regexp/joni/Parser.java | 57 ++-------------- nashorn/test/script/basic/JDK-8019963.js | 66 +++++++++++++++++++ .../test/script/basic/JDK-8019963.js.EXPECTED | 29 ++++++++ 4 files changed, 102 insertions(+), 52 deletions(-) create mode 100644 nashorn/test/script/basic/JDK-8019963.js create mode 100644 nashorn/test/script/basic/JDK-8019963.js.EXPECTED diff --git a/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/CodeRangeBuffer.java b/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/CodeRangeBuffer.java index 87e0f8e1fc3..d6c2a61e23a 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/CodeRangeBuffer.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/CodeRangeBuffer.java @@ -183,7 +183,7 @@ public final class CodeRangeBuffer { // add_code_range, be aware of it returning null! public static CodeRangeBuffer addCodeRange(CodeRangeBuffer pbuf, ScanEnvironment env, int from, int to) { - if (from >to) { + if (from > to) { if (env.syntax.allowEmptyRangeInCC()) { return pbuf; } else { diff --git a/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/Parser.java b/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/Parser.java index 03c99a3c03c..45c8838e5d4 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/Parser.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/Parser.java @@ -125,32 +125,8 @@ class Parser extends Lexer { break; case RAW_BYTE: - if (token.base != 0) { /* tok->base != 0 : octal or hexadec. */ - byte[] buf = new byte[4]; - int psave = p; - int base = token.base; - buf[0] = (byte)token.getC(); - int i; - for (i=1; i<4; i++) { - fetchTokenInCC(); - if (token.type != TokenType.RAW_BYTE || token.base != base) { - fetched = true; - break; - } - buf[i] = (byte)token.getC(); - } - - if (i == 1) { - arg.v = buf[0] & 0xff; - arg.inType = CCVALTYPE.SB; // goto raw_single - } else { - arg.v = EncodingHelper.mbcToCode(buf, 0, buf.length); - arg.inType = CCVALTYPE.CODE_POINT; - } - } else { - arg.v = token.getC(); - arg.inType = CCVALTYPE.SB; // raw_single: - } + arg.v = token.getC(); + arg.inType = CCVALTYPE.SB; // raw_single: arg.vIsRaw = true; parseCharClassValEntry2(cc, arg); // goto val_entry2 break; @@ -615,31 +591,10 @@ class Parser extends Lexer { StringNode node = new StringNode((char)token.getC()); node.setRaw(); - int len = 1; - while (true) { - if (len >= 1) { - if (len == 1) { - fetchToken(); - node.clearRaw(); - // !goto string_end;! - return parseExpRepeat(node, group); - } - } - - fetchToken(); - if (token.type != TokenType.RAW_BYTE) { - /* Don't use this, it is wrong for little endian encodings. */ - // USE_PAD_TO_SHORT_BYTE_CHAR ... - - newValueException(ERR_TOO_SHORT_MULTI_BYTE_STRING); - } - - // important: we don't use 0xff mask here neither in the compiler - // (in the template string) so we won't have to mask target - // strings when comparing against them in the matcher - node.cat((char)token.getC()); - len++; - } // while + fetchToken(); + node.clearRaw(); + // !goto string_end;! + return parseExpRepeat(node, group); } private Node parseExpRepeat(Node target, boolean group) { diff --git a/nashorn/test/script/basic/JDK-8019963.js b/nashorn/test/script/basic/JDK-8019963.js new file mode 100644 index 00000000000..5767a414a49 --- /dev/null +++ b/nashorn/test/script/basic/JDK-8019963.js @@ -0,0 +1,66 @@ +/* + * 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-8019963: empty char range in regex + * + * @test + * @run + */ + +var re1 = /[\x00-\x08\x0B\x0C\x0E-\x9F\uD800-\uDFFF\uFFFE\uFFFF]/; + +print(re1.test("\x00")); +print(re1.test("\x04")); +print(re1.test("\x08")); +print(re1.test("\x0a")); +print(re1.test("\x0B")); +print(re1.test("\x0C")); +print(re1.test("\x0E")); +print(re1.test("\x10")); +print(re1.test("\x1A")); +print(re1.test("\x2F")); +print(re1.test("\x8E")); +print(re1.test("\x8F")); +print(re1.test("\x9F")); +print(re1.test("\xA0")); +print(re1.test("\xAF")); +print(re1.test("\uD800")); +print(re1.test("\xDA00")); +print(re1.test("\xDCFF")); +print(re1.test("\xDFFF")); +print(re1.test("\xFFFE")); +print(re1.test("\xFFFF")); + +var re2 = /[\x1F\x7F-\x84\x86]/; + +print(re2.test("\x1F")); +print(re2.test("\x2F")); +print(re2.test("\x3F")); +print(re2.test("\x7F")); +print(re2.test("\x80")); +print(re2.test("\x84")); +print(re2.test("\x85")); +print(re2.test("\x86")); + +var re3 = /^([\x00-\x7F]|[\xC2-\xDF][\x80-\xBF]|\xE0[\xA0-\xBF][\x80-\xBF]|[\xE1-\xEC\xEE\xEF][\x80-\xBF]{2}|\xED[\x80-\x9F][\x80-\xBF]|\xF0[\x90-\xBF][\x80-\xBF]{2}|[\xF1-\xF3][\x80-\xBF]{3}|\xF4[\x80-\x8F][\x80-\xBF]{2})*$/; diff --git a/nashorn/test/script/basic/JDK-8019963.js.EXPECTED b/nashorn/test/script/basic/JDK-8019963.js.EXPECTED new file mode 100644 index 00000000000..ffde31fe38d --- /dev/null +++ b/nashorn/test/script/basic/JDK-8019963.js.EXPECTED @@ -0,0 +1,29 @@ +true +true +true +false +true +true +true +true +true +true +true +true +true +false +false +true +true +true +true +true +true +true +false +false +true +true +true +false +true From 3e0c71b6c11e9b87e6e510915e8ecbe0b1e90bbf Mon Sep 17 00:00:00 2001 From: Attila Szegedi Date: Tue, 9 Jul 2013 13:57:24 +0200 Subject: [PATCH 02/15] 8009758: reactivate the 8006529 test Reviewed-by: jlaskey, sundar --- .../jdk/nashorn/internal/codegen/Attr.java | 18 ++- .../internal/codegen/CompilerConstants.java | 4 +- .../codegen/ObjectClassGenerator.java | 4 +- .../nashorn/internal/codegen/types/Type.java | 66 ++++----- .../internal/runtime/AccessorProperty.java | 7 +- .../internal/runtime/FunctionScope.java | 4 +- .../JDK-8006529.js | 131 +++++++++++------- 7 files changed, 134 insertions(+), 100 deletions(-) rename nashorn/test/script/{currently-failing => trusted}/JDK-8006529.js (68%) diff --git a/nashorn/src/jdk/nashorn/internal/codegen/Attr.java b/nashorn/src/jdk/nashorn/internal/codegen/Attr.java index 6dbfa6d4c9b..e076825dfe0 100644 --- a/nashorn/src/jdk/nashorn/internal/codegen/Attr.java +++ b/nashorn/src/jdk/nashorn/internal/codegen/Attr.java @@ -94,7 +94,6 @@ import jdk.nashorn.internal.runtime.DebugLogger; import jdk.nashorn.internal.runtime.JSType; import jdk.nashorn.internal.runtime.Property; import jdk.nashorn.internal.runtime.PropertyMap; -import jdk.nashorn.internal.runtime.ScriptObject; /** * This is the attribution pass of the code generator. Attr takes Lowered IR, @@ -166,19 +165,19 @@ final class Attr extends NodeOperatorVisitor { } private void initFunctionWideVariables(final FunctionNode functionNode, final Block body) { - initCompileConstant(CALLEE, body, IS_PARAM | IS_INTERNAL, FunctionNode.FUNCTION_TYPE); + initCompileConstant(CALLEE, body, IS_PARAM | IS_INTERNAL); initCompileConstant(THIS, body, IS_PARAM | IS_THIS, Type.OBJECT); if (functionNode.isVarArg()) { - initCompileConstant(VARARGS, body, IS_PARAM | IS_INTERNAL, Type.OBJECT_ARRAY); + initCompileConstant(VARARGS, body, IS_PARAM | IS_INTERNAL); if (functionNode.needsArguments()) { - initCompileConstant(ARGUMENTS, body, IS_VAR | IS_INTERNAL | IS_ALWAYS_DEFINED, Type.typeFor(ScriptObject.class)); + initCompileConstant(ARGUMENTS, body, IS_VAR | IS_INTERNAL | IS_ALWAYS_DEFINED); addLocalDef(ARGUMENTS.symbolName()); } } initParameters(functionNode, body); - initCompileConstant(SCOPE, body, IS_VAR | IS_INTERNAL | IS_ALWAYS_DEFINED, Type.typeFor(ScriptObject.class)); + initCompileConstant(SCOPE, body, IS_VAR | IS_INTERNAL | IS_ALWAYS_DEFINED); initCompileConstant(RETURN, body, IS_VAR | IS_INTERNAL | IS_ALWAYS_DEFINED, Type.OBJECT); } @@ -1424,9 +1423,16 @@ final class Attr extends NodeOperatorVisitor { return end(ensureSymbol(type, ternaryNode)); } + private void initCompileConstant(final CompilerConstants cc, final Block block, final int flags) { + final Class type = cc.type(); + // Must not call this method for constants with no explicit types; use the one with (..., Type) signature instead. + assert type != null; + initCompileConstant(cc, block, flags, Type.typeFor(type)); + } + private void initCompileConstant(final CompilerConstants cc, final Block block, final int flags, final Type type) { final Symbol symbol = defineSymbol(block, cc.symbolName(), flags); - newType(symbol, type); + symbol.setTypeOverride(type); symbol.setNeedsSlot(true); } diff --git a/nashorn/src/jdk/nashorn/internal/codegen/CompilerConstants.java b/nashorn/src/jdk/nashorn/internal/codegen/CompilerConstants.java index 3deff98c00a..c8ccc1cedc1 100644 --- a/nashorn/src/jdk/nashorn/internal/codegen/CompilerConstants.java +++ b/nashorn/src/jdk/nashorn/internal/codegen/CompilerConstants.java @@ -100,10 +100,10 @@ public enum CompilerConstants { CALLEE(":callee", ScriptFunction.class), /** the varargs variable when necessary */ - VARARGS(":varargs"), + VARARGS(":varargs", Object[].class), /** the arguments vector when necessary and the slot */ - ARGUMENTS("arguments", Object.class, 2), + ARGUMENTS("arguments", ScriptObject.class, 2), /** prefix for iterators for for (x in ...) */ ITERATOR_PREFIX(":i", Iterator.class), diff --git a/nashorn/src/jdk/nashorn/internal/codegen/ObjectClassGenerator.java b/nashorn/src/jdk/nashorn/internal/codegen/ObjectClassGenerator.java index 7d61db1f691..fa3d19e5d05 100644 --- a/nashorn/src/jdk/nashorn/internal/codegen/ObjectClassGenerator.java +++ b/nashorn/src/jdk/nashorn/internal/codegen/ObjectClassGenerator.java @@ -435,13 +435,13 @@ public final class ObjectClassGenerator { * @return Open method emitter. */ private static MethodEmitter newInitScopeWithArgumentsMethod(final ClassEmitter classEmitter) { - final MethodEmitter init = classEmitter.init(PropertyMap.class, ScriptObject.class, Object.class); + final MethodEmitter init = classEmitter.init(PropertyMap.class, ScriptObject.class, ScriptObject.class); init.begin(); init.load(Type.OBJECT, JAVA_THIS.slot()); init.load(Type.OBJECT, INIT_MAP.slot()); init.load(Type.OBJECT, INIT_SCOPE.slot()); init.load(Type.OBJECT, INIT_ARGUMENTS.slot()); - init.invoke(constructorNoLookup(FunctionScope.class, PropertyMap.class, ScriptObject.class, Object.class)); + init.invoke(constructorNoLookup(FunctionScope.class, PropertyMap.class, ScriptObject.class, ScriptObject.class)); return init; } diff --git a/nashorn/src/jdk/nashorn/internal/codegen/types/Type.java b/nashorn/src/jdk/nashorn/internal/codegen/types/Type.java index ab32a779703..c1e8bfbb432 100644 --- a/nashorn/src/jdk/nashorn/internal/codegen/types/Type.java +++ b/nashorn/src/jdk/nashorn/internal/codegen/types/Type.java @@ -47,9 +47,8 @@ import static jdk.internal.org.objectweb.asm.Opcodes.T_INT; import static jdk.internal.org.objectweb.asm.Opcodes.T_LONG; import java.lang.invoke.MethodHandle; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; import jdk.internal.org.objectweb.asm.MethodVisitor; import jdk.nashorn.internal.codegen.CompilerConstants.Call; @@ -548,19 +547,19 @@ public abstract class Type implements Comparable, BytecodeOps { * @return the Type representing this class */ public static Type typeFor(final Class clazz) { - Type type = cache.get(clazz); - - if (type == null) { - assert !clazz.isPrimitive() || clazz == void.class; - if (clazz.isArray()) { - type = new ArrayType(clazz); - } else { - type = new ObjectType(clazz); - } - cache.put(clazz, type); + final Type type = cache.get(clazz); + if(type != null) { + return type; } - - return type; + assert !clazz.isPrimitive() || clazz == void.class; + final Type newType; + if (clazz.isArray()) { + newType = new ArrayType(clazz); + } else { + newType = new ObjectType(clazz); + } + final Type existingType = cache.putIfAbsent(clazz, newType); + return existingType == null ? newType : existingType; } @Override @@ -663,35 +662,38 @@ public abstract class Type implements Comparable, BytecodeOps { } } + /** Mappings between java classes and their Type singletons */ + private static final ConcurrentMap, Type> cache = new ConcurrentHashMap<>(); + /** * This is the boolean singleton, used for all boolean types */ - public static final Type BOOLEAN = new BooleanType(); + public static final Type BOOLEAN = putInCache(new BooleanType()); /** * This is an integer type, i.e INT, INT32. */ - public static final Type INT = new IntType(); + public static final Type INT = putInCache(new IntType()); /** * This is the number singleton, used for all number types */ - public static final Type NUMBER = new NumberType(); + public static final Type NUMBER = putInCache(new NumberType()); /** * This is the long singleton, used for all long types */ - public static final Type LONG = new LongType(); + public static final Type LONG = putInCache(new LongType()); /** * A string singleton */ - public static final Type STRING = new ObjectType(String.class); + public static final Type STRING = putInCache(new ObjectType(String.class)); /** * This is the object singleton, used for all object types */ - public static final Type OBJECT = new ObjectType(); + public static final Type OBJECT = putInCache(new ObjectType()); /** * This is the singleton for integer arrays @@ -775,13 +777,13 @@ public abstract class Type implements Comparable, BytecodeOps { }; /** Singleton for method handle arrays used for properties etc. */ - public static final ArrayType METHODHANDLE_ARRAY = new ArrayType(MethodHandle[].class); + public static final ArrayType METHODHANDLE_ARRAY = putInCache(new ArrayType(MethodHandle[].class)); /** This is the singleton for string arrays */ - public static final ArrayType STRING_ARRAY = new ArrayType(String[].class); + public static final ArrayType STRING_ARRAY = putInCache(new ArrayType(String[].class)); /** This is the singleton for object arrays */ - public static final ArrayType OBJECT_ARRAY = new ArrayType(Object[].class); + public static final ArrayType OBJECT_ARRAY = putInCache(new ArrayType(Object[].class)); /** This type, always an object type, just a toString override */ public static final Type THIS = new ObjectType() { @@ -855,18 +857,8 @@ public abstract class Type implements Comparable, BytecodeOps { } }; - /** Mappings between java classes and their Type singletons */ - private static final Map, Type> cache = Collections.synchronizedMap(new HashMap, Type>()); - - //TODO may need to be cleared, as all types are retained throughout code generation - static { - cache.put(BOOLEAN.getTypeClass(), BOOLEAN); - cache.put(INT.getTypeClass(), INT); - cache.put(LONG.getTypeClass(), LONG); - cache.put(NUMBER.getTypeClass(), NUMBER); - cache.put(STRING.getTypeClass(), STRING); - cache.put(OBJECT.getTypeClass(), OBJECT); - cache.put(OBJECT_ARRAY.getTypeClass(), OBJECT_ARRAY); + private static T putInCache(T type) { + cache.put(type.getTypeClass(), type); + return type; } - } diff --git a/nashorn/src/jdk/nashorn/internal/runtime/AccessorProperty.java b/nashorn/src/jdk/nashorn/internal/runtime/AccessorProperty.java index f7ece9df533..f1f0ebe33c0 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/AccessorProperty.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/AccessorProperty.java @@ -248,11 +248,10 @@ public class AccessorProperty extends Property { primitiveSetter = null; if (isParameter() && hasArguments()) { - final MethodHandle arguments = MH.getter(lookup, structure, "arguments", Object.class); - final MethodHandle argumentsSO = MH.asType(arguments, arguments.type().changeReturnType(ScriptObject.class)); + final MethodHandle arguments = MH.getter(lookup, structure, "arguments", ScriptObject.class); - objectGetter = MH.asType(MH.insertArguments(MH.filterArguments(ScriptObject.GET_ARGUMENT.methodHandle(), 0, argumentsSO), 1, slot), Lookup.GET_OBJECT_TYPE); - objectSetter = MH.asType(MH.insertArguments(MH.filterArguments(ScriptObject.SET_ARGUMENT.methodHandle(), 0, argumentsSO), 1, slot), Lookup.SET_OBJECT_TYPE); + objectGetter = MH.asType(MH.insertArguments(MH.filterArguments(ScriptObject.GET_ARGUMENT.methodHandle(), 0, arguments), 1, slot), Lookup.GET_OBJECT_TYPE); + objectSetter = MH.asType(MH.insertArguments(MH.filterArguments(ScriptObject.SET_ARGUMENT.methodHandle(), 0, arguments), 1, slot), Lookup.SET_OBJECT_TYPE); } else { final GettersSetters gs = GETTERS_SETTERS.get(structure); objectGetter = gs.getters[slot]; diff --git a/nashorn/src/jdk/nashorn/internal/runtime/FunctionScope.java b/nashorn/src/jdk/nashorn/internal/runtime/FunctionScope.java index 59a9d5ede03..b3872c45cd7 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/FunctionScope.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/FunctionScope.java @@ -41,7 +41,7 @@ package jdk.nashorn.internal.runtime; public class FunctionScope extends ScriptObject implements Scope { /** Area to store scope arguments. (public for access from scripts.) */ - public final Object arguments; + public final ScriptObject arguments; /** Flag to indicate that a split method issued a return statement */ private int splitState = -1; @@ -53,7 +53,7 @@ public class FunctionScope extends ScriptObject implements Scope { * @param callerScope caller scope * @param arguments arguments */ - public FunctionScope(final PropertyMap map, final ScriptObject callerScope, final Object arguments) { + public FunctionScope(final PropertyMap map, final ScriptObject callerScope, final ScriptObject arguments) { super(callerScope, map); this.arguments = arguments; setIsScope(); diff --git a/nashorn/test/script/currently-failing/JDK-8006529.js b/nashorn/test/script/trusted/JDK-8006529.js similarity index 68% rename from nashorn/test/script/currently-failing/JDK-8006529.js rename to nashorn/test/script/trusted/JDK-8006529.js index ca21f0b9c48..378cd6cf7a6 100644 --- a/nashorn/test/script/currently-failing/JDK-8006529.js +++ b/nashorn/test/script/trusted/JDK-8006529.js @@ -39,30 +39,35 @@ * and FunctionNode because of package-access check and so reflective calls. */ -var Parser = Java.type("jdk.nashorn.internal.parser.Parser") -var Compiler = Java.type("jdk.nashorn.internal.codegen.Compiler") -var Context = Java.type("jdk.nashorn.internal.runtime.Context") -var ScriptEnvironment = Java.type("jdk.nashorn.internal.runtime.ScriptEnvironment") -var Source = Java.type("jdk.nashorn.internal.runtime.Source") -var FunctionNode = Java.type("jdk.nashorn.internal.ir.FunctionNode") -var ThrowErrorManager = Java.type("jdk.nashorn.internal.runtime.Context$ThrowErrorManager"); +var forName = java.lang.Class["forName(String)"] + +var Parser = forName("jdk.nashorn.internal.parser.Parser").static +var Compiler = forName("jdk.nashorn.internal.codegen.Compiler").static +var Context = forName("jdk.nashorn.internal.runtime.Context").static +var ScriptEnvironment = forName("jdk.nashorn.internal.runtime.ScriptEnvironment").static +var Source = forName("jdk.nashorn.internal.runtime.Source").static +var FunctionNode = forName("jdk.nashorn.internal.ir.FunctionNode").static +var Block = forName("jdk.nashorn.internal.ir.Block").static +var VarNode = forName("jdk.nashorn.internal.ir.VarNode").static +var ExecuteNode = forName("jdk.nashorn.internal.ir.ExecuteNode").static +var UnaryNode = forName("jdk.nashorn.internal.ir.UnaryNode").static +var BinaryNode = forName("jdk.nashorn.internal.ir.BinaryNode").static +var ThrowErrorManager = forName("jdk.nashorn.internal.runtime.Context$ThrowErrorManager").static +var Debug = forName("jdk.nashorn.internal.runtime.Debug").static -// Compiler class methods and fields var parseMethod = Parser.class.getMethod("parse"); -var compileMethod = Compiler.class.getMethod("compile"); - -// NOTE: private field. But this is a trusted test! -// Compiler.functionNode -var functionNodeField = Compiler.class.getDeclaredField("functionNode"); -functionNodeField.setAccessible(true); - -// FunctionNode methods - -// FunctionNode.getFunctions method -var getFunctionsMethod = FunctionNode.class.getMethod("getFunctions"); +var compileMethod = Compiler.class.getMethod("compile", FunctionNode.class); +var getBodyMethod = FunctionNode.class.getMethod("getBody"); +var getStatementsMethod = Block.class.getMethod("getStatements"); +var getInitMethod = VarNode.class.getMethod("getInit"); +var getExpressionMethod = ExecuteNode.class.getMethod("getExpression") +var rhsMethod = UnaryNode.class.getMethod("rhs") +var lhsMethod = BinaryNode.class.getMethod("lhs") +var binaryRhsMethod = BinaryNode.class.getMethod("rhs") +var debugIdMethod = Debug.class.getMethod("id", java.lang.Object.class) // These are method names of methods in FunctionNode class -var allAssertionList = ['isVarArg', 'needsParentScope', 'needsCallee', 'needsScope', 'needsSelfSymbol', 'isSplit', 'hasEval', 'hasWith', 'hasDeepWithOrEval', 'allVarsInScope', 'isStrictMode'] +var allAssertionList = ['isVarArg', 'needsParentScope', 'needsCallee', 'hasScopeBlock', 'needsSelfSymbol', 'isSplit', 'hasEval', 'allVarsInScope', 'isStrict'] // corresponding Method objects of FunctionNode class var functionNodeMethods = {}; @@ -74,30 +79,54 @@ var functionNodeMethods = {}; } })(); -// returns "script" functionNode from Compiler instance -function getScriptNode(compiler) { - // compiler.functionNode - return functionNodeField.get(compiler); +// returns functionNode.getBody().getStatements().get(0) +function getFirstFunction(functionNode) { + var f = findFunction(getBodyMethod.invoke(functionNode)) + if (f == null) { + throw new Error(); + } + return f; } -// returns functionNode.getFunctions().get(0) -function getFirstFunction(functionNode) { - // functionNode.getFunctions().get(0) - return getFunctionsMethod.invoke(functionNode).get(0); +function findFunction(node) { + if(node instanceof Block) { + var stmts = getStatementsMethod.invoke(node) + for(var i = 0; i < stmts.size(); ++i) { + var retval = findFunction(stmts.get(i)) + if(retval != null) { + return retval; + } + } + } else if(node instanceof VarNode) { + return findFunction(getInitMethod.invoke(node)) + } else if(node instanceof UnaryNode) { + return findFunction(rhsMethod.invoke(node)) + } else if(node instanceof BinaryNode) { + return findFunction(lhsMethod.invoke(node)) || findFunction(binaryRhsMethod.invoke(node)) + } else if(node instanceof ExecuteNode) { + return findFunction(getExpressionMethod.invoke(node)) + } else if(node instanceof FunctionNode) { + return node + } } +var getContextMethod = Context.class.getMethod("getContext") +var getEnvMethod = Context.class.getMethod("getEnv") + // compile(script) -- compiles a script specified as a string with its // source code, returns a jdk.nashorn.internal.ir.FunctionNode object // representing it. function compile(source) { var source = new Source("", source); - var parser = new Parser(Context.getContext().getEnv(), source, new ThrowErrorManager()); + + var env = getEnvMethod.invoke(getContextMethod.invoke(null)) + + var parser = new Parser(env, source, new ThrowErrorManager()); var func = parseMethod.invoke(parser); - var compiler = new Compiler(Context.getContext().getEnv(), func); - compileMethod.invoke(compiler); + var compiler = new Compiler(env); - return getScriptNode(compiler); + return compileMethod.invoke(compiler, func); }; var allAssertions = (function() { @@ -122,8 +151,9 @@ function test(f) { } for(var assertion in allAssertions) { var expectedValue = !!assertions[assertion] - if(functionNodeMethods[assertion].invoke(f) !== expectedValue) { - throw "Expected " + assertion + " === " + expectedValue + " for " + f; + var actualValue = functionNodeMethods[assertion].invoke(f) + if(actualValue !== expectedValue) { + throw "Expected " + assertion + " === " + expectedValue + ", got " + actualValue + " for " + f + ":" + debugIdMethod.invoke(null, f); } } } @@ -152,7 +182,7 @@ testFirstFn("function f() { arguments }", 'needsCallee', 'isVarArg') // A function referencing "arguments" will have to be vararg. If it is // strict, it will not have to have a callee, though. -testFirstFn("function f() {'use strict'; arguments }", 'isVarArg', 'isStrictMode') +testFirstFn("function f() {'use strict'; arguments }", 'isVarArg', 'isStrict') // A function defining "arguments" as a parameter will not be vararg. testFirstFn("function f(arguments) { arguments }") @@ -173,11 +203,11 @@ testFirstFn("(function f() { f() })", 'needsCallee', 'needsSelfSymbol') // A child function accessing parent's variable triggers the need for scope // in parent -testFirstFn("(function f() { var x; function g() { x } })", 'needsScope') +testFirstFn("(function f() { var x; function g() { x } })", 'hasScopeBlock') // A child function accessing parent's parameter triggers the need for scope // in parent -testFirstFn("(function f(x) { function g() { x } })", 'needsScope') +testFirstFn("(function f(x) { function g() { x } })", 'hasScopeBlock') // A child function accessing a global variable triggers the need for parent // scope in parent @@ -187,22 +217,29 @@ testFirstFn("(function f() { function g() { x } })", 'needsParentScope', 'needsC // affect the parent function in any way testFirstFn("(function f() { var x; function g() { var x; x } })") -// Using "with" unleashes a lot of needs: parent scope, callee, own scope, -// and all variables in scope. Actually, we could make "with" less wasteful, -// and only put those variables in scope that it actually references, similar -// to what nested functions do with variables in their parents. -testFirstFn("(function f() { var o; with(o) {} })", 'needsParentScope', 'needsCallee', 'needsScope', 'hasWith', 'hasDeepWithOrEval', 'allVarsInScope') +// Using "with" on its own doesn't do much. +testFirstFn("(function f() { var o; with(o) {} })") -// Using "eval" is as bad as using "with" with the added requirement of -// being vararg, 'cause we don't know if eval will be using "arguments". -testFirstFn("(function f() { eval() })", 'needsParentScope', 'needsCallee', 'needsScope', 'hasEval', 'isVarArg', 'hasDeepWithOrEval', 'allVarsInScope') +// "with" referencing a local variable triggers scoping. +testFirstFn("(function f() { var x; var y; with(x) { y } })", 'hasScopeBlock') + +// "with" referencing a non-local variable triggers parent scope. +testFirstFn("(function f() { var x; with(x) { y } })", 'needsCallee', 'needsParentScope') // Nested function using "with" is pretty much the same as the parent // function needing with. -testFirstFn("(function f() { function g() { var o; with(o) {} } })", 'needsParentScope', 'needsCallee', 'needsScope', 'hasDeepWithOrEval', 'allVarsInScope') +testFirstFn("(function f() { function g() { var o; with(o) {} } })") + +// Nested function using "with" referencing a local variable. +testFirstFn("(function f() { var x; function g() { var o; with(o) { x } } })", 'hasScopeBlock') + +// Using "eval" triggers pretty much everything. The function even needs to be +// vararg, 'cause we don't know if eval will be using "arguments". +testFirstFn("(function f() { eval() })", 'needsParentScope', 'needsCallee', 'hasScopeBlock', 'hasEval', 'isVarArg', 'allVarsInScope') + // Nested function using "eval" is almost the same as parent function using // eval, but at least the parent doesn't have to be vararg. -testFirstFn("(function f() { function g() { eval() } })", 'needsParentScope', 'needsCallee', 'needsScope', 'hasDeepWithOrEval', 'allVarsInScope') +testFirstFn("(function f() { function g() { eval() } })", 'needsParentScope', 'needsCallee', 'hasScopeBlock', 'allVarsInScope') // Function with 250 named parameters is ordinary testFirstFn("function f(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27, p28, p29, p30, p31, p32, p33, p34, p35, p36, p37, p38, p39, p40, p41, p42, p43, p44, p45, p46, p47, p48, p49, p50, p51, p52, p53, p54, p55, p56, p57, p58, p59, p60, p61, p62, p63, p64, p65, p66, p67, p68, p69, p70, p71, p72, p73, p74, p75, p76, p77, p78, p79, p80, p81, p82, p83, p84, p85, p86, p87, p88, p89, p90, p91, p92, p93, p94, p95, p96, p97, p98, p99, p100, p101, p102, p103, p104, p105, p106, p107, p108, p109, p110, p111, p112, p113, p114, p115, p116, p117, p118, p119, p120, p121, p122, p123, p124, p125, p126, p127, p128, p129, p130, p131, p132, p133, p134, p135, p136, p137, p138, p139, p140, p141, p142, p143, p144, p145, p146, p147, p148, p149, p150, p151, p152, p153, p154, p155, p156, p157, p158, p159, p160, p161, p162, p163, p164, p165, p166, p167, p168, p169, p170, p171, p172, p173, p174, p175, p176, p177, p178, p179, p180, p181, p182, p183, p184, p185, p186, p187, p188, p189, p190, p191, p192, p193, p194, p195, p196, p197, p198, p199, p200, p201, p202, p203, p204, p205, p206, p207, p208, p209, p210, p211, p212, p213, p214, p215, p216, p217, p218, p219, p220, p221, p222, p223, p224, p225, p226, p227, p228, p229, p230, p231, p232, p233, p234, p235, p236, p237, p238, p239, p240, p241, p242, p243, p244, p245, p246, p247, p248, p249, p250) { p250 = p249 }") From 8854b24a3034df1b4751789d403ae7a8205abf23 Mon Sep 17 00:00:00 2001 From: Athijegannathan Sundararajan Date: Tue, 9 Jul 2013 17:37:46 +0530 Subject: [PATCH 03/15] 8014785: Ability to extend global instance by binding properties of another object Reviewed-by: attila, hannesw, jlaskey, lagergren --- .../internal/objects/NativeObject.java | 116 ++++++++++++++++++ .../internal/runtime/AccessorProperty.java | 4 +- .../jdk/nashorn/internal/runtime/Context.java | 8 +- .../nashorn/internal/runtime/PropertyMap.java | 2 +- .../internal/runtime/ScriptObject.java | 32 ++++- .../internal/runtime/linker/InvokeByName.java | 2 +- nashorn/test/script/basic/JDK-8014785.js | 62 ++++++++++ .../test/script/basic/JDK-8014785.js.EXPECTED | 8 ++ 8 files changed, 224 insertions(+), 10 deletions(-) create mode 100644 nashorn/test/script/basic/JDK-8014785.js create mode 100644 nashorn/test/script/basic/JDK-8014785.js.EXPECTED diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeObject.java b/nashorn/src/jdk/nashorn/internal/objects/NativeObject.java index 6e4791bd20c..c8bff8b0203 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeObject.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeObject.java @@ -27,18 +27,24 @@ package jdk.nashorn.internal.objects; import static jdk.nashorn.internal.runtime.ECMAErrors.typeError; import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED; + +import java.lang.invoke.MethodHandle; +import java.util.ArrayList; import jdk.nashorn.api.scripting.ScriptObjectMirror; import jdk.nashorn.internal.objects.annotations.Attribute; import jdk.nashorn.internal.objects.annotations.Constructor; import jdk.nashorn.internal.objects.annotations.Function; import jdk.nashorn.internal.objects.annotations.ScriptClass; import jdk.nashorn.internal.objects.annotations.Where; +import jdk.nashorn.internal.runtime.AccessorProperty; import jdk.nashorn.internal.runtime.ECMAException; import jdk.nashorn.internal.runtime.JSType; +import jdk.nashorn.internal.runtime.Property; import jdk.nashorn.internal.runtime.PropertyMap; import jdk.nashorn.internal.runtime.ScriptFunction; import jdk.nashorn.internal.runtime.ScriptObject; import jdk.nashorn.internal.runtime.ScriptRuntime; +import jdk.nashorn.internal.runtime.linker.Bootstrap; import jdk.nashorn.internal.runtime.linker.InvokeByName; /** @@ -471,4 +477,114 @@ public final class NativeObject { return false; } + + /** + * Nashorn extension: Object.bindProperties + * + * Binds the source object's properties to the target object. Binding + * properties allows two-way read/write for the properties of the source object. + * + * Example: + *
+     * var obj = { x: 34, y: 100 };
+     * var foo = {}
+     *
+     * // bind properties of "obj" to "foo" object
+     * Object.bindProperties(foo, obj);
+     *
+     * // now, we can access/write on 'foo' properties
+     * print(foo.x); // prints obj.x which is 34
+     *
+     * // update obj.x via foo.x
+     * foo.x = "hello";
+     * print(obj.x); // prints "hello" now
+     *
+     * obj.x = 42;   // foo.x also becomes 42
+     * print(foo.x); // prints 42
+     * 
+ *

+ * The source object bound can be a ScriptObject or a ScriptOjectMirror. + * null or undefined source object results in TypeError being thrown. + *

+ * Example: + *
+     * var obj = loadWithNewGlobal({
+     *    name: "test",
+     *    script: "obj = { x: 33, y: 'hello' }"
+     * });
+     *
+     * // bind 'obj's properties to global scope 'this'
+     * Object.bindProperties(this, obj);
+     * print(x);         // prints 33
+     * print(y);         // prints "hello"
+     * x = Math.PI;      // changes obj.x to Math.PI
+     * print(obj.x);     // prints Math.PI
+     * 
+ * + * Limitations of property binding: + *
    + *
  • Only enumerable, immediate (not proto inherited) properties of the source object are bound. + *
  • If the target object already contains a property called "foo", the source's "foo" is skipped (not bound). + *
  • Properties added to the source object after binding to the target are not bound. + *
  • Property configuration changes on the source object (or on the target) is not propagated. + *
  • Delete of property on the target (or the source) is not propagated - + * only the property value is set to 'undefined' if the property happens to be a data property. + *
+ *

+ * It is recommended that the bound properties be treated as non-configurable + * properties to avoid surprises. + *

+ * + * @param self self reference + * @param target the target object to which the source object's properties are bound + * @param source the source object whose properties are bound to the target + * @return the target object after property binding + */ + @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) + public static Object bindProperties(final Object self, final Object target, final Object source) { + // target object has to be a ScriptObject + Global.checkObject(target); + // check null or undefined source object + Global.checkObjectCoercible(source); + + final ScriptObject targetObj = (ScriptObject)target; + + if (source instanceof ScriptObject) { + final ScriptObject sourceObj = (ScriptObject)source; + final Property[] properties = sourceObj.getMap().getProperties(); + + // filter non-enumerable properties + final ArrayList propList = new ArrayList<>(); + for (Property prop : properties) { + if (prop.isEnumerable()) { + propList.add(prop); + } + } + + if (! propList.isEmpty()) { + targetObj.addBoundProperties(sourceObj, propList.toArray(new Property[propList.size()])); + } + } else if (source instanceof ScriptObjectMirror) { + // get enumerable, immediate properties of mirror + final ScriptObjectMirror mirror = (ScriptObjectMirror)source; + final String[] keys = mirror.getOwnKeys(false); + if (keys.length == 0) { + // nothing to bind + return target; + } + + // make accessor properties using dynamic invoker getters and setters + final AccessorProperty[] props = new AccessorProperty[keys.length]; + for (int idx = 0; idx < keys.length; idx++) { + final String name = keys[idx]; + final MethodHandle getter = Bootstrap.createDynamicInvoker("dyn:getMethod|getProp|getElem:" + name, Object.class, ScriptObjectMirror.class); + final MethodHandle setter = Bootstrap.createDynamicInvoker("dyn:setProp|setElem:" + name, Object.class, ScriptObjectMirror.class, Object.class); + props[idx] = (AccessorProperty.create(name, 0, getter, setter)); + } + + targetObj.addBoundProperties(source, props); + } + + return target; + } } diff --git a/nashorn/src/jdk/nashorn/internal/runtime/AccessorProperty.java b/nashorn/src/jdk/nashorn/internal/runtime/AccessorProperty.java index f1f0ebe33c0..c9d2a04229f 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/AccessorProperty.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/AccessorProperty.java @@ -147,9 +147,9 @@ public class AccessorProperty extends Property { * and are thus rebound with that as receiver * * @param property accessor property to rebind - * @param delegate delegate script object to rebind receiver to + * @param delegate delegate object to rebind receiver to */ - public AccessorProperty(final AccessorProperty property, final ScriptObject delegate) { + public AccessorProperty(final AccessorProperty property, final Object delegate) { super(property); this.primitiveGetter = bindTo(property.primitiveGetter, delegate); diff --git a/nashorn/src/jdk/nashorn/internal/runtime/Context.java b/nashorn/src/jdk/nashorn/internal/runtime/Context.java index 8f00d52127e..7d639cd31c3 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/Context.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/Context.java @@ -199,6 +199,7 @@ public final class Context { private static final ClassLoader myLoader = Context.class.getClassLoader(); private static final StructureLoader sharedLoader; + private static final AccessControlContext NO_PERMISSIONS_CONTEXT; static { sharedLoader = AccessController.doPrivileged(new PrivilegedAction() { @@ -207,6 +208,7 @@ public final class Context { return new StructureLoader(myLoader, null); } }); + NO_PERMISSIONS_CONTEXT = new AccessControlContext(new ProtectionDomain[] { new ProtectionDomain(null, new Permissions()) }); } /** @@ -564,7 +566,7 @@ public final class Context { sm.checkPackageAccess(fullName.substring(0, index)); return null; } - }, createNoPermissionsContext()); + }, NO_PERMISSIONS_CONTEXT); } } @@ -707,10 +709,6 @@ public final class Context { return (context != null) ? context : Context.getContextTrusted(); } - private static AccessControlContext createNoPermissionsContext() { - return new AccessControlContext(new ProtectionDomain[] { new ProtectionDomain(null, new Permissions()) }); - } - private Object evaluateSource(final Source source, final ScriptObject scope, final ScriptObject thiz) { ScriptFunction script = null; diff --git a/nashorn/src/jdk/nashorn/internal/runtime/PropertyMap.java b/nashorn/src/jdk/nashorn/internal/runtime/PropertyMap.java index 05e8dc78235..511ff666cd5 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/PropertyMap.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/PropertyMap.java @@ -260,7 +260,7 @@ public final class PropertyMap implements Iterable, PropertyListener { * * @return New {@link PropertyMap} with {@link Property} added. */ - PropertyMap addPropertyBind(final AccessorProperty property, final ScriptObject bindTo) { + PropertyMap addPropertyBind(final AccessorProperty property, final Object bindTo) { return addProperty(new AccessorProperty(property, bindTo)); } diff --git a/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java b/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java index c56c32c7257..f770bd65a6f 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java @@ -203,9 +203,19 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr * @param source The source object to copy from. */ public void addBoundProperties(final ScriptObject source) { + addBoundProperties(source, source.getMap().getProperties()); + } + + /** + * Copy all properties from the array with their receiver bound to the source. + * + * @param source The source object to copy from. + * @param properties The array of properties to copy. + */ + public void addBoundProperties(final ScriptObject source, final Property[] properties) { PropertyMap newMap = this.getMap(); - for (final Property property : source.getMap().getProperties()) { + for (final Property property : properties) { final String key = property.getKey(); if (newMap.findProperty(key) == null) { @@ -221,6 +231,26 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr this.setMap(newMap); } + /** + * Copy all properties from the array with their receiver bound to the source. + * + * @param source The source object to copy from. + * @param properties The collection of accessor properties to copy. + */ + public void addBoundProperties(final Object source, final AccessorProperty[] properties) { + PropertyMap newMap = this.getMap(); + + for (final AccessorProperty property : properties) { + final String key = property.getKey(); + + if (newMap.findProperty(key) == null) { + newMap = newMap.addPropertyBind(property, source); + } + } + + this.setMap(newMap); + } + /** * Bind the method handle to the specified receiver, while preserving its original type (it will just ignore the * first argument in lieu of the bound argument). diff --git a/nashorn/src/jdk/nashorn/internal/runtime/linker/InvokeByName.java b/nashorn/src/jdk/nashorn/internal/runtime/linker/InvokeByName.java index 4bfb6851c08..efec5b44738 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/linker/InvokeByName.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/InvokeByName.java @@ -83,7 +83,7 @@ public class InvokeByName { */ public InvokeByName(final String name, final Class targetClass, final Class rtype, final Class... ptypes) { this.name = name; - getter = Bootstrap.createDynamicInvoker("dyn:getMethod|getProp|getItem:" + name, Object.class, targetClass); + getter = Bootstrap.createDynamicInvoker("dyn:getMethod|getProp|getElem:" + name, Object.class, targetClass); final Class[] finalPtypes; final int plength = ptypes.length; diff --git a/nashorn/test/script/basic/JDK-8014785.js b/nashorn/test/script/basic/JDK-8014785.js new file mode 100644 index 00000000000..27b05bd1f32 --- /dev/null +++ b/nashorn/test/script/basic/JDK-8014785.js @@ -0,0 +1,62 @@ +/* + * 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-8014785: Ability to extend global instance by binding properties of another object + * + * @test + * @run + */ + +var obj = { x: 34, y: 100 }; +var foo = {} + +// bind properties of "obj" to "foo" obj +Object.bindProperties(foo, obj); + +// now we can access/write on foo properties +print("foo.x = " + foo.x); // prints obj.x which is 34 + +// update obj.x via foo.x +foo.x = "hello"; +print("obj.x = " + obj.x); // prints "hello" now + +obj.x = 42; // foo.x also becomes 42 +print("obj.x = " + obj.x); // prints 42 +print("foo.x = " + foo.x); // prints 42 + +// now bind a mirror object to an object +var obj = loadWithNewGlobal({ + name: "test", + script: "obj = { x: 33, y: 'hello' }" +}); + +Object.bindProperties(this, obj); +print("x = " + x); // prints 33 +print("y = " + y); // prints "hello" + +x = Math.PI; // changes obj.x to Math.PI +print("obj.x = " +obj.x); // prints Math.PI + +obj.y = 32; +print("y = " + y); // should print 32 diff --git a/nashorn/test/script/basic/JDK-8014785.js.EXPECTED b/nashorn/test/script/basic/JDK-8014785.js.EXPECTED new file mode 100644 index 00000000000..cb2b154cffe --- /dev/null +++ b/nashorn/test/script/basic/JDK-8014785.js.EXPECTED @@ -0,0 +1,8 @@ +foo.x = 34 +obj.x = hello +obj.x = 42 +foo.x = 42 +x = 33 +y = hello +obj.x = 3.141592653589793 +y = 32 From cfbe70e2231e591d8888d654f2148cac5168e147 Mon Sep 17 00:00:00 2001 From: Marcus Lagergren Date: Tue, 9 Jul 2013 15:56:59 +0200 Subject: [PATCH 04/15] 8020124: In the case of an eval switch, we might need explicit conversions of the tag store, as it was not known in the surrounding environment Reviewed-by: sundar, jlaskey --- .../internal/codegen/CodeGenerator.java | 2 ++ nashorn/test/script/basic/JDK-8020124.js | 32 +++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 nashorn/test/script/basic/JDK-8020124.js diff --git a/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java b/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java index 79936473fb9..250c44c1541 100644 --- a/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java +++ b/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java @@ -1869,6 +1869,8 @@ final class CodeGenerator extends NodeOperatorVisitor Date: Wed, 10 Jul 2013 13:25:07 +0530 Subject: [PATCH 05/15] 8020224: LinkageError: attempted duplicate class definition when --loader-per-compiler=false Reviewed-by: hannesw --- .../nashorn/internal/codegen/Compiler.java | 5 +- .../internal/runtime/CodeInstaller.java | 6 +++ .../jdk/nashorn/internal/runtime/Context.java | 12 +++++ .../runtime/TrustedScriptEngineTest.java | 51 +++++++++++++++++++ 4 files changed, 73 insertions(+), 1 deletion(-) diff --git a/nashorn/src/jdk/nashorn/internal/codegen/Compiler.java b/nashorn/src/jdk/nashorn/internal/codegen/Compiler.java index 72fcf178bea..e40986d4e4a 100644 --- a/nashorn/src/jdk/nashorn/internal/codegen/Compiler.java +++ b/nashorn/src/jdk/nashorn/internal/codegen/Compiler.java @@ -528,7 +528,7 @@ public final class Compiler { return this.env; } - private static String safeSourceName(final Source source) { + private String safeSourceName(final Source source) { String baseName = new File(source.getName()).getName(); final int index = baseName.lastIndexOf(".js"); @@ -537,6 +537,9 @@ public final class Compiler { } baseName = baseName.replace('.', '_').replace('-', '_'); + if (! env._loader_per_compile) { + baseName = baseName + installer.getUniqueScriptId(); + } final String mangled = NameCodec.encode(baseName); return mangled != null ? mangled : baseName; diff --git a/nashorn/src/jdk/nashorn/internal/runtime/CodeInstaller.java b/nashorn/src/jdk/nashorn/internal/runtime/CodeInstaller.java index 80fac179cb0..be9976e7d84 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/CodeInstaller.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/CodeInstaller.java @@ -62,4 +62,10 @@ public interface CodeInstaller { * @param code bytecode to verify */ public void verify(final byte[] code); + + /** + * Get next unique script id + * @return unique script id + */ + public long getUniqueScriptId(); } diff --git a/nashorn/src/jdk/nashorn/internal/runtime/Context.java b/nashorn/src/jdk/nashorn/internal/runtime/Context.java index 7d639cd31c3..dae27cd9e42 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/Context.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/Context.java @@ -96,6 +96,11 @@ public final class Context { public void verify(final byte[] code) { context.verify(code); } + + @Override + public long getUniqueScriptId() { + return context.getUniqueScriptId(); + } } /** Is Context global debug mode enabled ? */ @@ -197,6 +202,9 @@ public final class Context { /** Current error manager. */ private final ErrorManager errors; + /** Unique id for script. Used only when --loader-per-compile=false */ + private long uniqueScriptId; + private static final ClassLoader myLoader = Context.class.getClassLoader(); private static final StructureLoader sharedLoader; private static final AccessControlContext NO_PERMISSIONS_CONTEXT; @@ -816,4 +824,8 @@ public final class Context { private ScriptObject newGlobalTrusted() { return new Global(this); } + + private synchronized long getUniqueScriptId() { + return uniqueScriptId++; + } } diff --git a/nashorn/test/src/jdk/nashorn/internal/runtime/TrustedScriptEngineTest.java b/nashorn/test/src/jdk/nashorn/internal/runtime/TrustedScriptEngineTest.java index 0f740a483c6..f7f7c6ae298 100644 --- a/nashorn/test/src/jdk/nashorn/internal/runtime/TrustedScriptEngineTest.java +++ b/nashorn/test/src/jdk/nashorn/internal/runtime/TrustedScriptEngineTest.java @@ -145,4 +145,55 @@ public class TrustedScriptEngineTest { fail("Cannot find nashorn factory!"); } + + @Test + /** + * Test repeated evals with --loader-per-compile=false + * We used to get "class redefinition error". + */ + public void noLoaderPerCompilerTest() { + final ScriptEngineManager sm = new ScriptEngineManager(); + for (ScriptEngineFactory fac : sm.getEngineFactories()) { + if (fac instanceof NashornScriptEngineFactory) { + final NashornScriptEngineFactory nfac = (NashornScriptEngineFactory)fac; + final String[] options = new String[] { "--loader-per-compile=false" }; + final ScriptEngine e = nfac.getScriptEngine(options); + try { + e.eval("2 + 3"); + e.eval("4 + 4"); + } catch (final ScriptException se) { + se.printStackTrace(); + fail(se.getMessage()); + } + return; + } + } + fail("Cannot find nashorn factory!"); + } + + @Test + /** + * Test that we can use same script name in repeated evals with --loader-per-compile=false + * We used to get "class redefinition error" as name was derived from script name. + */ + public void noLoaderPerCompilerWithSameNameTest() { + final ScriptEngineManager sm = new ScriptEngineManager(); + for (ScriptEngineFactory fac : sm.getEngineFactories()) { + if (fac instanceof NashornScriptEngineFactory) { + final NashornScriptEngineFactory nfac = (NashornScriptEngineFactory)fac; + final String[] options = new String[] { "--loader-per-compile=false" }; + final ScriptEngine e = nfac.getScriptEngine(options); + e.put(ScriptEngine.FILENAME, "test.js"); + try { + e.eval("2 + 3"); + e.eval("4 + 4"); + } catch (final ScriptException se) { + se.printStackTrace(); + fail(se.getMessage()); + } + return; + } + } + fail("Cannot find nashorn factory!"); + } } From 652b0209056637422dc9b76f479a558487e6cfc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hannes=20Walln=C3=B6fer?= Date: Wed, 10 Jul 2013 10:54:19 +0200 Subject: [PATCH 06/15] 8016681: regex capture behaves differently than on V8 Reviewed-by: lagergren, sundar --- .../runtime/regexp/RegExpScanner.java | 58 ++++++++++--------- nashorn/test/script/basic/JDK-8016681.js | 42 ++++++++++++++ .../test/script/basic/JDK-8016681.js.EXPECTED | 15 +++++ 3 files changed, 87 insertions(+), 28 deletions(-) create mode 100644 nashorn/test/script/basic/JDK-8016681.js create mode 100644 nashorn/test/script/basic/JDK-8016681.js.EXPECTED diff --git a/nashorn/src/jdk/nashorn/internal/runtime/regexp/RegExpScanner.java b/nashorn/src/jdk/nashorn/internal/runtime/regexp/RegExpScanner.java index 52829fac099..68df99f3af3 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/regexp/RegExpScanner.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/regexp/RegExpScanner.java @@ -57,7 +57,10 @@ final class RegExpScanner extends Scanner { private final LinkedList forwardReferences = new LinkedList<>(); /** Current level of zero-width negative lookahead assertions. */ - private int negativeLookaheadLevel; + private int negLookaheadLevel; + + /** Sequential id of current top-level zero-width negative lookahead assertion. */ + private int negLookaheadGroup; /** Are we currently inside a character class? */ private boolean inCharClass = false; @@ -68,17 +71,18 @@ final class RegExpScanner extends Scanner { private static final String NON_IDENT_ESCAPES = "$^*+(){}[]|\\.?-"; private static class Capture { - /** - * Zero-width negative lookaheads enclosing the capture. - */ - private final int negativeLookaheadLevel; + /** Zero-width negative lookaheads enclosing the capture. */ + private final int negLookaheadLevel; + /** Sequential id of top-level negative lookaheads containing the capture. */ + private final int negLookaheadGroup; - Capture(final int negativeLookaheadLevel) { - this.negativeLookaheadLevel = negativeLookaheadLevel; + Capture(final int negLookaheadGroup, final int negLookaheadLevel) { + this.negLookaheadGroup = negLookaheadGroup; + this.negLookaheadLevel = negLookaheadLevel; } - public int getNegativeLookaheadLevel() { - return negativeLookaheadLevel; + boolean isContained(final int group, final int level) { + return group == this.negLookaheadGroup && level >= this.negLookaheadLevel; } } @@ -152,7 +156,7 @@ final class RegExpScanner extends Scanner { BitVector vec = null; for (int i = 0; i < caps.size(); i++) { final Capture cap = caps.get(i); - if (cap.getNegativeLookaheadLevel() > 0) { + if (cap.negLookaheadLevel > 0) { if (vec == null) { vec = new BitVector(caps.size() + 1); } @@ -311,11 +315,14 @@ final class RegExpScanner extends Scanner { commit(3); if (isNegativeLookahead) { - negativeLookaheadLevel++; + if (negLookaheadLevel == 0) { + negLookaheadGroup++; + } + negLookaheadLevel++; } disjunction(); if (isNegativeLookahead) { - negativeLookaheadLevel--; + negLookaheadLevel--; } if (ch0 == ')') { @@ -432,20 +439,17 @@ final class RegExpScanner extends Scanner { } if (ch0 == '(') { - boolean capturingParens = true; commit(1); if (ch0 == '?' && ch1 == ':') { - capturingParens = false; commit(2); + } else { + caps.add(new Capture(negLookaheadGroup, negLookaheadLevel)); } disjunction(); if (ch0 == ')') { commit(1); - if (capturingParens) { - caps.add(new Capture(negativeLookaheadLevel)); - } return true; } } @@ -675,24 +679,22 @@ final class RegExpScanner extends Scanner { sb.setLength(sb.length() - 1); octalOrLiteral(Integer.toString(decimalValue), sb); - } else if (decimalValue <= caps.size() && caps.get(decimalValue - 1).getNegativeLookaheadLevel() > 0) { - // Captures that live inside a negative lookahead are dead after the - // lookahead and will be undefined if referenced from outside. - if (caps.get(decimalValue - 1).getNegativeLookaheadLevel() > negativeLookaheadLevel) { + } else if (decimalValue <= caps.size()) { + // Captures inside a negative lookahead are undefined when referenced from the outside. + if (!caps.get(decimalValue - 1).isContained(negLookaheadGroup, negLookaheadLevel)) { + // Reference to capture in negative lookahead, omit from output buffer. sb.setLength(sb.length() - 1); } else { + // Append backreference to output buffer. sb.append(decimalValue); } - } else if (decimalValue > caps.size()) { - // Forward reference to a capture group. Forward references are always undefined so we can omit - // it from the output buffer. However, if the target capture does not exist, we need to rewrite - // the reference as hex escape or literal string, so register the reference for later processing. + } else { + // Forward references to a capture group are always undefined so we can omit it from the output buffer. + // However, if the target capture does not exist, we need to rewrite the reference as hex escape + // or literal string, so register the reference for later processing. sb.setLength(sb.length() - 1); forwardReferences.add(decimalValue); forwardReferences.add(sb.length()); - } else { - // Append as backreference - sb.append(decimalValue); } } diff --git a/nashorn/test/script/basic/JDK-8016681.js b/nashorn/test/script/basic/JDK-8016681.js new file mode 100644 index 00000000000..9596b0ddbd3 --- /dev/null +++ b/nashorn/test/script/basic/JDK-8016681.js @@ -0,0 +1,42 @@ +/* + * 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-8016681: regex capture behaves differently than on V8 + * + * @test + * @run + */ + +// regexp similar to the one used in marked.js +/^((?:[^\n]+\n?(?!( *[-*_]){3,} *(?:\n+|$)| *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)|([^\n]+)\n *(=|-){3,} *\n*))+)\n*/ + .exec("a\n\nb") + .forEach(function(e) { print(e); }); + +// simplified regexp +/(x(?!(a))(?!(b))y)/ + .exec("xy") + .forEach(function(e) { print(e); }); + +// should not match as cross-negative-lookeahead backreference \2 should be undefined +print(/(x(?!(a))(?!(b)\2))/.exec("xbc")); diff --git a/nashorn/test/script/basic/JDK-8016681.js.EXPECTED b/nashorn/test/script/basic/JDK-8016681.js.EXPECTED new file mode 100644 index 00000000000..06b855074ea --- /dev/null +++ b/nashorn/test/script/basic/JDK-8016681.js.EXPECTED @@ -0,0 +1,15 @@ +a + + +a + +undefined +undefined +undefined +undefined +undefined +xy +xy +undefined +undefined +null From 48c4649f17a8ce482c8b5a442d695b4d3fa3df94 Mon Sep 17 00:00:00 2001 From: Athijegannathan Sundararajan Date: Wed, 10 Jul 2013 19:08:04 +0530 Subject: [PATCH 07/15] 8020276: interface checks in Invocable.getInterface implementation Reviewed-by: jlaskey, hannesw, attila --- .../api/scripting/NashornScriptEngine.java | 19 +++++++ .../jdk/nashorn/internal/runtime/Context.java | 15 ++++-- .../runtime/linker/JavaAdapterFactory.java | 11 +++++ .../api/scripting/ScriptEngineTest.java | 49 +++++++++++++++++++ 4 files changed, 90 insertions(+), 4 deletions(-) diff --git a/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java b/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java index d38e63c88b8..64574229d0a 100644 --- a/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java +++ b/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java @@ -33,6 +33,7 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; import java.lang.reflect.Method; +import java.lang.reflect.Modifier; import java.net.URL; import java.nio.charset.Charset; import java.security.AccessController; @@ -184,6 +185,23 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C } private T getInterfaceInner(final Object self, final Class clazz) { + if (clazz == null || !clazz.isInterface()) { + throw new IllegalArgumentException("interface Class expected"); + } + + // perform security access check as early as possible + final SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + if (! Modifier.isPublic(clazz.getModifiers())) { + throw new SecurityException("attempt to implement non-public interfce: " + clazz); + } + final String fullName = clazz.getName(); + final int index = fullName.lastIndexOf('.'); + if (index != -1) { + sm.checkPackageAccess(fullName.substring(0, index)); + } + } + final ScriptObject realSelf; final ScriptObject ctxtGlobal = getNashornGlobalFrom(context); if(self == null) { @@ -193,6 +211,7 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C } else { realSelf = (ScriptObject)self; } + try { final ScriptObject oldGlobal = getNashornGlobal(); try { diff --git a/nashorn/src/jdk/nashorn/internal/runtime/Context.java b/nashorn/src/jdk/nashorn/internal/runtime/Context.java index dae27cd9e42..fb362b1725e 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/Context.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/Context.java @@ -36,6 +36,7 @@ import java.io.IOException; import java.io.PrintWriter; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; +import java.util.concurrent.atomic.AtomicLong; import java.net.MalformedURLException; import java.net.URL; import java.security.AccessControlContext; @@ -203,7 +204,7 @@ public final class Context { private final ErrorManager errors; /** Unique id for script. Used only when --loader-per-compile=false */ - private long uniqueScriptId; + private final AtomicLong uniqueScriptId; private static final ClassLoader myLoader = Context.class.getClassLoader(); private static final StructureLoader sharedLoader; @@ -263,7 +264,13 @@ public final class Context { this.env = new ScriptEnvironment(options, out, err); this._strict = env._strict; this.appLoader = appLoader; - this.scriptLoader = env._loader_per_compile? null : createNewLoader(); + if (env._loader_per_compile) { + this.scriptLoader = null; + this.uniqueScriptId = null; + } else { + this.scriptLoader = createNewLoader(); + this.uniqueScriptId = new AtomicLong(); + } this.errors = errors; // if user passed -classpath option, make a class loader with that and set it as @@ -825,7 +832,7 @@ public final class Context { return new Global(this); } - private synchronized long getUniqueScriptId() { - return uniqueScriptId++; + private long getUniqueScriptId() { + return uniqueScriptId.getAndIncrement(); } } diff --git a/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterFactory.java b/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterFactory.java index f207d37cf66..77dcc695a0a 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterFactory.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterFactory.java @@ -99,6 +99,17 @@ public final class JavaAdapterFactory { */ public static StaticClass getAdapterClassFor(final Class[] types, ScriptObject classOverrides) { assert types != null && types.length > 0; + final SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + for (Class type : types) { + // check for restricted package access + final String fullName = type.getName(); + final int index = fullName.lastIndexOf('.'); + if (index != -1) { + sm.checkPackageAccess(fullName.substring(0, index)); + } + } + } return getAdapterInfo(types).getAdapterClassFor(classOverrides); } diff --git a/nashorn/test/src/jdk/nashorn/api/scripting/ScriptEngineTest.java b/nashorn/test/src/jdk/nashorn/api/scripting/ScriptEngineTest.java index a6c015a1e54..73572502605 100644 --- a/nashorn/test/src/jdk/nashorn/api/scripting/ScriptEngineTest.java +++ b/nashorn/test/src/jdk/nashorn/api/scripting/ScriptEngineTest.java @@ -36,6 +36,7 @@ import java.io.StringWriter; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; +import java.util.Objects; import java.util.concurrent.Callable; import javax.script.Bindings; import javax.script.Compilable; @@ -344,6 +345,23 @@ public class ScriptEngineTest { foo2.bar2(); } + @Test + /** + * Try passing non-interface Class object for interface implementation. + */ + public void getNonInterfaceGetInterfaceTest() { + final ScriptEngineManager manager = new ScriptEngineManager(); + final ScriptEngine engine = manager.getEngineByName("nashorn"); + try { + log(Objects.toString(((Invocable)engine).getInterface(Object.class))); + fail("Should have thrown IllegalArgumentException"); + } catch (final Exception exp) { + if (! (exp instanceof IllegalArgumentException)) { + fail("IllegalArgumentException expected, got " + exp); + } + } + } + @Test public void accessGlobalTest() { final ScriptEngineManager m = new ScriptEngineManager(); @@ -927,4 +945,35 @@ public class ScriptEngineTest { Assert.assertEquals(itf.test1(42, "a", "b"), "i == 42, strings instanceof java.lang.String[] == true, strings == [a, b]"); Assert.assertEquals(itf.test2(44, "c", "d", "e"), "arguments[0] == 44, arguments[1] instanceof java.lang.String[] == true, arguments[1] == [c, d, e]"); } + + @Test + /** + * Check that script can't implement sensitive package interfaces. + */ + public void checkSensitiveInterfaceImplTest() throws ScriptException { + final ScriptEngineManager m = new ScriptEngineManager(); + final ScriptEngine e = m.getEngineByName("nashorn"); + final Object[] holder = new Object[1]; + e.put("holder", holder); + // put an empty script object into array + e.eval("holder[0] = {}"); + // holder[0] is an object of some subclass of ScriptObject + Class ScriptObjectClass = holder[0].getClass().getSuperclass(); + Class PropertyAccessClass = ScriptObjectClass.getInterfaces()[0]; + // implementation methods for PropertyAccess class + e.eval("function set() {}; function get() {}; function getInt(){} " + + "function getDouble(){}; function getLong() {}; " + + "this.delete = function () {}; function has() {}; " + + "function hasOwnProperty() {}"); + + // get implementation of a restricted package interface + try { + log(Objects.toString(((Invocable)e).getInterface(PropertyAccessClass))); + fail("should have thrown SecurityException"); + } catch (final Exception exp) { + if (! (exp instanceof SecurityException)) { + fail("SecurityException expected, got " + exp); + } + } + } } From f0144d9d93a3b2907573437f448ecf45d8bb2858 Mon Sep 17 00:00:00 2001 From: Athijegannathan Sundararajan Date: Thu, 11 Jul 2013 16:34:55 +0530 Subject: [PATCH 08/15] 8020325: static property does not work on accessible, public classes Reviewed-by: attila, hannesw, lagergren --- nashorn/make/build.xml | 6 ++- .../api/scripting/NashornScriptEngine.java | 6 +-- .../internal/codegen/CodeGenerator.java | 2 +- .../nashorn/internal/codegen/Compiler.java | 4 +- .../jdk/nashorn/internal/lookup/Lookup.java | 2 - .../nashorn/internal/objects/NativeDebug.java | 3 ++ .../internal/objects/NativeNumber.java | 1 - .../internal/objects/ScriptFunctionImpl.java | 4 +- .../jdk/nashorn/internal/runtime/Context.java | 34 ++++++++--------- .../runtime/linker/JavaAdapterFactory.java | 9 ++--- .../runtime/linker/ReflectionCheckLinker.java | 23 +++++++++++ nashorn/test/script/basic/JDK-8020325.js | 38 +++++++++++++++++++ .../test/script/basic/JDK-8020325.js.EXPECTED | 4 ++ nashorn/test/script/trusted/JDK-8006529.js | 28 +++++++------- .../api/scripting/ScriptEngineTest.java | 2 +- 15 files changed, 111 insertions(+), 55 deletions(-) create mode 100644 nashorn/test/script/basic/JDK-8020325.js create mode 100644 nashorn/test/script/basic/JDK-8020325.js.EXPECTED diff --git a/nashorn/make/build.xml b/nashorn/make/build.xml index da2ded1ea1d..2bda503fd88 100644 --- a/nashorn/make/build.xml +++ b/nashorn/make/build.xml @@ -219,8 +219,10 @@ target="${javac.target}" debug="${javac.debug}" encoding="${javac.encoding}" - includeantruntime="false"> - + includeantruntime="false" fork="true"> + + + diff --git a/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java b/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java index 64574229d0a..682975a85d5 100644 --- a/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java +++ b/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java @@ -195,11 +195,7 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C if (! Modifier.isPublic(clazz.getModifiers())) { throw new SecurityException("attempt to implement non-public interfce: " + clazz); } - final String fullName = clazz.getName(); - final int index = fullName.lastIndexOf('.'); - if (index != -1) { - sm.checkPackageAccess(fullName.substring(0, index)); - } + Context.checkPackageAccess(clazz.getName()); } final ScriptObject realSelf; diff --git a/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java b/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java index 250c44c1541..b9d35682458 100644 --- a/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java +++ b/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java @@ -1313,7 +1313,7 @@ final class CodeGenerator extends NodeOperatorVisitor literalNode) { assert literalNode.getSymbol() != null : literalNode + " has no symbol"; load(literalNode).store(literalNode.getSymbol()); return false; diff --git a/nashorn/src/jdk/nashorn/internal/codegen/Compiler.java b/nashorn/src/jdk/nashorn/internal/codegen/Compiler.java index e40986d4e4a..a31358f6503 100644 --- a/nashorn/src/jdk/nashorn/internal/codegen/Compiler.java +++ b/nashorn/src/jdk/nashorn/internal/codegen/Compiler.java @@ -528,8 +528,8 @@ public final class Compiler { return this.env; } - private String safeSourceName(final Source source) { - String baseName = new File(source.getName()).getName(); + private String safeSourceName(final Source src) { + String baseName = new File(src.getName()).getName(); final int index = baseName.lastIndexOf(".js"); if (index != -1) { diff --git a/nashorn/src/jdk/nashorn/internal/lookup/Lookup.java b/nashorn/src/jdk/nashorn/internal/lookup/Lookup.java index e874cfd7bbe..0dd2741e00c 100644 --- a/nashorn/src/jdk/nashorn/internal/lookup/Lookup.java +++ b/nashorn/src/jdk/nashorn/internal/lookup/Lookup.java @@ -32,8 +32,6 @@ import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; import jdk.nashorn.internal.runtime.JSType; -import jdk.nashorn.internal.runtime.Property; -import jdk.nashorn.internal.runtime.PropertyMap; import jdk.nashorn.internal.runtime.ScriptRuntime; /** diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeDebug.java b/nashorn/src/jdk/nashorn/internal/objects/NativeDebug.java index 30a4228958e..82757cbae51 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeDebug.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeDebug.java @@ -179,6 +179,9 @@ public final class NativeDebug extends ScriptObject { /** * Returns the property listener count for a script object + * + * @param self self reference + * @param obj script object whose listener count is returned * @return listener count */ @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeNumber.java b/nashorn/src/jdk/nashorn/internal/objects/NativeNumber.java index c69478967f4..d9d568b7e38 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeNumber.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeNumber.java @@ -48,7 +48,6 @@ import jdk.nashorn.internal.runtime.JSType; import jdk.nashorn.internal.runtime.PropertyMap; import jdk.nashorn.internal.runtime.ScriptObject; import jdk.nashorn.internal.runtime.ScriptRuntime; -import jdk.nashorn.internal.lookup.MethodHandleFactory; import jdk.nashorn.internal.runtime.linker.PrimitiveLookup; /** diff --git a/nashorn/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java b/nashorn/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java index 643d9acddf3..88421a70bd1 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java +++ b/nashorn/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java @@ -212,10 +212,10 @@ public class ScriptFunctionImpl extends ScriptFunction { // Instance of this class is used as global anonymous function which // serves as Function.prototype object. private static class AnonymousFunction extends ScriptFunctionImpl { - private static final PropertyMap map$ = PropertyMap.newMap().setIsShared(); + private static final PropertyMap anonmap$ = PropertyMap.newMap().setIsShared(); static PropertyMap getInitialMap() { - return map$; + return anonmap$; } AnonymousFunction(final Global global) { diff --git a/nashorn/src/jdk/nashorn/internal/runtime/Context.java b/nashorn/src/jdk/nashorn/internal/runtime/Context.java index fb362b1725e..9d603c66b72 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/Context.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/Context.java @@ -39,13 +39,10 @@ import java.lang.invoke.MethodHandles; import java.util.concurrent.atomic.AtomicLong; import java.net.MalformedURLException; import java.net.URL; -import java.security.AccessControlContext; import java.security.AccessController; import java.security.CodeSigner; import java.security.CodeSource; -import java.security.Permissions; import java.security.PrivilegedAction; -import java.security.ProtectionDomain; import java.util.Map; import jdk.internal.org.objectweb.asm.ClassReader; import jdk.internal.org.objectweb.asm.util.CheckClassAdapter; @@ -208,7 +205,6 @@ public final class Context { private static final ClassLoader myLoader = Context.class.getClassLoader(); private static final StructureLoader sharedLoader; - private static final AccessControlContext NO_PERMISSIONS_CONTEXT; static { sharedLoader = AccessController.doPrivileged(new PrivilegedAction() { @@ -217,7 +213,6 @@ public final class Context { return new StructureLoader(myLoader, null); } }); - NO_PERMISSIONS_CONTEXT = new AccessControlContext(new ProtectionDomain[] { new ProtectionDomain(null, new Permissions()) }); } /** @@ -559,6 +554,21 @@ public final class Context { return Class.forName(fullName, true, sharedLoader); } + /** + * Checks that the given package can be accessed from current call stack. + * + * @param fullName fully qualified package name + */ + public static void checkPackageAccess(final String fullName) { + final int index = fullName.lastIndexOf('.'); + if (index != -1) { + final SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkPackageAccess(fullName.substring(0, index)); + } + } + } + /** * Lookup a Java class. This is used for JSR-223 stuff linking in from * {@code jdk.nashorn.internal.objects.NativeJava} and {@code jdk.nashorn.internal.runtime.NativeJavaPackage} @@ -571,19 +581,7 @@ public final class Context { */ public Class findClass(final String fullName) throws ClassNotFoundException { // check package access as soon as possible! - final int index = fullName.lastIndexOf('.'); - if (index != -1) { - final SecurityManager sm = System.getSecurityManager(); - if (sm != null) { - AccessController.doPrivileged(new PrivilegedAction() { - @Override - public Void run() { - sm.checkPackageAccess(fullName.substring(0, index)); - return null; - } - }, NO_PERMISSIONS_CONTEXT); - } - } + checkPackageAccess(fullName); // try the script -classpath loader, if that is set if (classPathLoader != null) { diff --git a/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterFactory.java b/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterFactory.java index 77dcc695a0a..472b8dcd727 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterFactory.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterFactory.java @@ -43,6 +43,7 @@ import java.util.Map; import jdk.internal.dynalink.beans.StaticClass; import jdk.internal.dynalink.support.LinkRequestImpl; import jdk.nashorn.internal.objects.NativeJava; +import jdk.nashorn.internal.runtime.Context; import jdk.nashorn.internal.runtime.ECMAException; import jdk.nashorn.internal.runtime.ScriptFunction; import jdk.nashorn.internal.runtime.ScriptObject; @@ -101,13 +102,9 @@ public final class JavaAdapterFactory { assert types != null && types.length > 0; final SecurityManager sm = System.getSecurityManager(); if (sm != null) { - for (Class type : types) { + for (Class type : types) { // check for restricted package access - final String fullName = type.getName(); - final int index = fullName.lastIndexOf('.'); - if (index != -1) { - sm.checkPackageAccess(fullName.substring(0, index)); - } + Context.checkPackageAccess(type.getName()); } } return getAdapterInfo(types).getAdapterClassFor(classOverrides); diff --git a/nashorn/src/jdk/nashorn/internal/runtime/linker/ReflectionCheckLinker.java b/nashorn/src/jdk/nashorn/internal/runtime/linker/ReflectionCheckLinker.java index eb8837a8d70..53c652cab15 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/linker/ReflectionCheckLinker.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/ReflectionCheckLinker.java @@ -25,10 +25,14 @@ package jdk.nashorn.internal.runtime.linker; +import java.lang.reflect.Modifier; +import jdk.internal.dynalink.CallSiteDescriptor; import jdk.internal.dynalink.linker.GuardedInvocation; import jdk.internal.dynalink.linker.LinkRequest; import jdk.internal.dynalink.linker.LinkerServices; import jdk.internal.dynalink.linker.TypeBasedGuardingDynamicLinker; +import jdk.internal.dynalink.support.CallSiteDescriptorFactory; +import jdk.nashorn.internal.runtime.Context; /** * Check java reflection permission for java reflective and java.lang.invoke access from scripts @@ -52,6 +56,25 @@ final class ReflectionCheckLinker implements TypeBasedGuardingDynamicLinker{ throws Exception { final SecurityManager sm = System.getSecurityManager(); if (sm != null) { + final LinkRequest requestWithoutContext = origRequest.withoutRuntimeContext(); // Nashorn has no runtime context + final Object self = requestWithoutContext.getReceiver(); + // allow 'static' access on Class objects representing public classes of non-restricted packages + if ((self instanceof Class) && Modifier.isPublic(((Class)self).getModifiers())) { + final CallSiteDescriptor desc = requestWithoutContext.getCallSiteDescriptor(); + final String operator = CallSiteDescriptorFactory.tokenizeOperators(desc).get(0); + // check for 'get' on 'static' property + switch (operator) { + case "getProp": + case "getMethod": { + if ("static".equals(desc.getNameToken(CallSiteDescriptor.NAME_OPERAND))) { + Context.checkPackageAccess(((Class)self).getName()); + // let bean linker do the actual linking part + return null; + } + } + break; + } // fall through for all other stuff + } sm.checkPermission(new RuntimePermission("nashorn.JavaReflection")); } // let the next linker deal with actual linking diff --git a/nashorn/test/script/basic/JDK-8020325.js b/nashorn/test/script/basic/JDK-8020325.js new file mode 100644 index 00000000000..5c8e64f530d --- /dev/null +++ b/nashorn/test/script/basic/JDK-8020325.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-8020325: static property does not work on accessible, public classes + * + * @test + * @run + */ + +function printStatic(obj) { + print(obj.getClass().static); +} + +printStatic(new java.util.ArrayList()); +printStatic(new java.util.HashMap()); +printStatic(new java.lang.Object()); +printStatic(new (Java.type("java.lang.Object[]"))(0)); diff --git a/nashorn/test/script/basic/JDK-8020325.js.EXPECTED b/nashorn/test/script/basic/JDK-8020325.js.EXPECTED new file mode 100644 index 00000000000..96542b75cf3 --- /dev/null +++ b/nashorn/test/script/basic/JDK-8020325.js.EXPECTED @@ -0,0 +1,4 @@ +[JavaClass java.util.ArrayList] +[JavaClass java.util.HashMap] +[JavaClass java.lang.Object] +[JavaClass [Ljava.lang.Object;] diff --git a/nashorn/test/script/trusted/JDK-8006529.js b/nashorn/test/script/trusted/JDK-8006529.js index 378cd6cf7a6..6837fcd8d83 100644 --- a/nashorn/test/script/trusted/JDK-8006529.js +++ b/nashorn/test/script/trusted/JDK-8006529.js @@ -39,21 +39,19 @@ * and FunctionNode because of package-access check and so reflective calls. */ -var forName = java.lang.Class["forName(String)"] - -var Parser = forName("jdk.nashorn.internal.parser.Parser").static -var Compiler = forName("jdk.nashorn.internal.codegen.Compiler").static -var Context = forName("jdk.nashorn.internal.runtime.Context").static -var ScriptEnvironment = forName("jdk.nashorn.internal.runtime.ScriptEnvironment").static -var Source = forName("jdk.nashorn.internal.runtime.Source").static -var FunctionNode = forName("jdk.nashorn.internal.ir.FunctionNode").static -var Block = forName("jdk.nashorn.internal.ir.Block").static -var VarNode = forName("jdk.nashorn.internal.ir.VarNode").static -var ExecuteNode = forName("jdk.nashorn.internal.ir.ExecuteNode").static -var UnaryNode = forName("jdk.nashorn.internal.ir.UnaryNode").static -var BinaryNode = forName("jdk.nashorn.internal.ir.BinaryNode").static -var ThrowErrorManager = forName("jdk.nashorn.internal.runtime.Context$ThrowErrorManager").static -var Debug = forName("jdk.nashorn.internal.runtime.Debug").static +var Parser = Java.type("jdk.nashorn.internal.parser.Parser") +var Compiler = Java.type("jdk.nashorn.internal.codegen.Compiler") +var Context = Java.type("jdk.nashorn.internal.runtime.Context") +var ScriptEnvironment = Java.type("jdk.nashorn.internal.runtime.ScriptEnvironment") +var Source = Java.type("jdk.nashorn.internal.runtime.Source") +var FunctionNode = Java.type("jdk.nashorn.internal.ir.FunctionNode") +var Block = Java.type("jdk.nashorn.internal.ir.Block") +var VarNode = Java.type("jdk.nashorn.internal.ir.VarNode") +var ExecuteNode = Java.type("jdk.nashorn.internal.ir.ExecuteNode") +var UnaryNode = Java.type("jdk.nashorn.internal.ir.UnaryNode") +var BinaryNode = Java.type("jdk.nashorn.internal.ir.BinaryNode") +var ThrowErrorManager = Java.type("jdk.nashorn.internal.runtime.Context$ThrowErrorManager") +var Debug = Java.type("jdk.nashorn.internal.runtime.Debug") var parseMethod = Parser.class.getMethod("parse"); var compileMethod = Compiler.class.getMethod("compile", FunctionNode.class); diff --git a/nashorn/test/src/jdk/nashorn/api/scripting/ScriptEngineTest.java b/nashorn/test/src/jdk/nashorn/api/scripting/ScriptEngineTest.java index 73572502605..1ba08657a6f 100644 --- a/nashorn/test/src/jdk/nashorn/api/scripting/ScriptEngineTest.java +++ b/nashorn/test/src/jdk/nashorn/api/scripting/ScriptEngineTest.java @@ -968,7 +968,7 @@ public class ScriptEngineTest { // get implementation of a restricted package interface try { - log(Objects.toString(((Invocable)e).getInterface(PropertyAccessClass))); + log(Objects.toString(((Invocable)e).getInterface((Class)PropertyAccessClass))); fail("should have thrown SecurityException"); } catch (final Exception exp) { if (! (exp instanceof SecurityException)) { From 80f5124f23fb0e7288b03382aede08ff87f4d3ac Mon Sep 17 00:00:00 2001 From: Athijegannathan Sundararajan Date: Thu, 11 Jul 2013 18:23:13 +0530 Subject: [PATCH 09/15] 8020380: __noSuchProperty__ defined in mozilla_compat.js script should be non-enumerable Reviewed-by: jlaskey, hannesw, attila --- .../runtime/resources/mozilla_compat.js | 7 +++- nashorn/test/script/basic/JDK-8020380.js | 36 +++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 nashorn/test/script/basic/JDK-8020380.js diff --git a/nashorn/src/jdk/nashorn/internal/runtime/resources/mozilla_compat.js b/nashorn/src/jdk/nashorn/internal/runtime/resources/mozilla_compat.js index 206a193f7fa..8a9fcc7de0c 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/resources/mozilla_compat.js +++ b/nashorn/src/jdk/nashorn/internal/runtime/resources/mozilla_compat.js @@ -48,7 +48,7 @@ Object.defineProperty(this, "importPackage", { var _packages = []; var global = this; var oldNoSuchProperty = global.__noSuchProperty__; - global.__noSuchProperty__ = function(name) { + var __noSuchProperty__ = function(name) { 'use strict'; for (var i in _packages) { try { @@ -69,6 +69,11 @@ Object.defineProperty(this, "importPackage", { } } + Object.defineProperty(global, "__noSuchProperty__", { + writable: true, configurable: true, enumerable: false, + value: __noSuchProperty__ + }); + var prefix = "[JavaPackage "; return function() { for (var i in arguments) { diff --git a/nashorn/test/script/basic/JDK-8020380.js b/nashorn/test/script/basic/JDK-8020380.js new file mode 100644 index 00000000000..90357fa7606 --- /dev/null +++ b/nashorn/test/script/basic/JDK-8020380.js @@ -0,0 +1,36 @@ +/* + * 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-8020380: __noSuchProperty__ defined in mozilla_compat.js script should be non-enumerable + * + * @test + * @run + */ + +load("nashorn:mozilla_compat.js"); + +var desc = Object.getOwnPropertyDescriptor(this, "__noSuchProperty__"); +if (typeof desc.enumerable != 'boolean' || desc.enumerable != false) { + fail("__noSuchProperty__ is enumerable"); +} From 4eb5c9e3a42cdda2c0bf7d79920844f8b8c9d1ee Mon Sep 17 00:00:00 2001 From: Attila Szegedi Date: Thu, 11 Jul 2013 18:33:33 +0200 Subject: [PATCH 10/15] 8013925: Remove symbol fields from nodes that don't need them Reviewed-by: jlaskey, lagergren --- .../jdk/nashorn/internal/codegen/Attr.java | 113 ++++----- .../internal/codegen/BranchOptimizer.java | 14 +- .../internal/codegen/CodeGenerator.java | 236 +++++++++--------- .../internal/codegen/CompilationPhase.java | 26 +- .../internal/codegen/FinalizeTypes.java | 81 +++--- .../internal/codegen/FoldConstants.java | 8 +- .../internal/codegen/FunctionSignature.java | 8 +- .../jdk/nashorn/internal/codegen/Lower.java | 69 ++--- .../internal/codegen/RangeAnalyzer.java | 11 +- .../internal/codegen/SpillObjectCreator.java | 17 +- .../nashorn/internal/codegen/Splitter.java | 6 +- .../nashorn/internal/codegen/WeighNodes.java | 7 +- .../jdk/nashorn/internal/ir/AccessNode.java | 8 +- .../jdk/nashorn/internal/ir/Assignment.java | 4 +- .../src/jdk/nashorn/internal/ir/BaseNode.java | 11 +- .../jdk/nashorn/internal/ir/BinaryNode.java | 26 +- .../src/jdk/nashorn/internal/ir/Block.java | 36 ++- .../nashorn/internal/ir/BlockStatement.java | 115 +++++++++ .../nashorn/internal/ir/BreakableNode.java | 47 +--- .../internal/ir/BreakableStatement.java | 91 +++++++ .../src/jdk/nashorn/internal/ir/CallNode.java | 57 +++-- .../src/jdk/nashorn/internal/ir/CaseNode.java | 12 +- .../jdk/nashorn/internal/ir/CatchNode.java | 12 +- .../jdk/nashorn/internal/ir/Expression.java | 99 ++++++++ ...cuteNode.java => ExpressionStatement.java} | 20 +- .../src/jdk/nashorn/internal/ir/ForNode.java | 28 +-- .../jdk/nashorn/internal/ir/FunctionNode.java | 17 +- .../jdk/nashorn/internal/ir/IdentNode.java | 3 +- .../src/jdk/nashorn/internal/ir/IfNode.java | 12 +- .../jdk/nashorn/internal/ir/IndexNode.java | 16 +- .../jdk/nashorn/internal/ir/LabelNode.java | 2 +- .../nashorn/internal/ir/LexicalContext.java | 9 +- .../internal/ir/LexicalContextExpression.java | 59 +++++ .../internal/ir/LexicalContextNode.java | 53 +--- .../internal/ir/LexicalContextStatement.java | 55 ++++ .../jdk/nashorn/internal/ir/LiteralNode.java | 28 +-- .../src/jdk/nashorn/internal/ir/LoopNode.java | 13 +- nashorn/src/jdk/nashorn/internal/ir/Node.java | 55 ---- .../jdk/nashorn/internal/ir/ObjectNode.java | 2 +- .../jdk/nashorn/internal/ir/PropertyNode.java | 16 +- .../jdk/nashorn/internal/ir/ReturnNode.java | 13 +- .../jdk/nashorn/internal/ir/RuntimeNode.java | 25 +- .../jdk/nashorn/internal/ir/SplitNode.java | 7 +- .../jdk/nashorn/internal/ir/SwitchNode.java | 15 +- .../nashorn/internal/ir/TemporarySymbols.java | 2 +- .../jdk/nashorn/internal/ir/TernaryNode.java | 120 ++++----- .../jdk/nashorn/internal/ir/ThrowNode.java | 12 +- .../jdk/nashorn/internal/ir/UnaryNode.java | 23 +- .../src/jdk/nashorn/internal/ir/VarNode.java | 22 +- .../jdk/nashorn/internal/ir/WhileNode.java | 12 +- .../src/jdk/nashorn/internal/ir/WithNode.java | 12 +- .../nashorn/internal/ir/debug/ASTWriter.java | 22 +- .../nashorn/internal/ir/debug/JSONWriter.java | 29 ++- .../internal/ir/debug/PrintVisitor.java | 16 +- .../ir/visitor/NodeOperatorVisitor.java | 2 - .../internal/ir/visitor/NodeVisitor.java | 39 ++- .../nashorn/internal/parser/JSONParser.java | 13 +- .../jdk/nashorn/internal/parser/Parser.java | 170 +++++++------ .../linker/NashornCallSiteDescriptor.java | 3 +- nashorn/test/script/trusted/JDK-8006529.js | 30 +-- 60 files changed, 1236 insertions(+), 853 deletions(-) create mode 100644 nashorn/src/jdk/nashorn/internal/ir/BlockStatement.java create mode 100644 nashorn/src/jdk/nashorn/internal/ir/BreakableStatement.java create mode 100644 nashorn/src/jdk/nashorn/internal/ir/Expression.java rename nashorn/src/jdk/nashorn/internal/ir/{ExecuteNode.java => ExpressionStatement.java} (78%) create mode 100644 nashorn/src/jdk/nashorn/internal/ir/LexicalContextExpression.java create mode 100644 nashorn/src/jdk/nashorn/internal/ir/LexicalContextStatement.java diff --git a/nashorn/src/jdk/nashorn/internal/codegen/Attr.java b/nashorn/src/jdk/nashorn/internal/codegen/Attr.java index e076825dfe0..f56a881def6 100644 --- a/nashorn/src/jdk/nashorn/internal/codegen/Attr.java +++ b/nashorn/src/jdk/nashorn/internal/codegen/Attr.java @@ -61,6 +61,7 @@ import jdk.nashorn.internal.ir.Block; import jdk.nashorn.internal.ir.CallNode; import jdk.nashorn.internal.ir.CaseNode; import jdk.nashorn.internal.ir.CatchNode; +import jdk.nashorn.internal.ir.Expression; import jdk.nashorn.internal.ir.ForNode; import jdk.nashorn.internal.ir.FunctionNode; import jdk.nashorn.internal.ir.FunctionNode.CompilationState; @@ -72,7 +73,6 @@ import jdk.nashorn.internal.ir.LiteralNode; import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode; import jdk.nashorn.internal.ir.Node; import jdk.nashorn.internal.ir.ObjectNode; -import jdk.nashorn.internal.ir.PropertyNode; import jdk.nashorn.internal.ir.ReturnNode; import jdk.nashorn.internal.ir.RuntimeNode; import jdk.nashorn.internal.ir.RuntimeNode.Request; @@ -512,7 +512,6 @@ final class Attr extends NodeOperatorVisitor { assert nameSymbol != null; selfInit = selfInit.setName((IdentNode)name.setSymbol(lc, nameSymbol)); - selfInit = (VarNode)selfInit.setSymbol(lc, nameSymbol); newStatements.add(selfInit); newStatements.addAll(body.getStatements()); @@ -739,15 +738,9 @@ final class Attr extends NodeOperatorVisitor { return end(ensureSymbol(Type.OBJECT, objectNode)); } - @Override - public Node leavePropertyNode(final PropertyNode propertyNode) { - // assign a pseudo symbol to property name, see NASHORN-710 - return propertyNode.setSymbol(lc, new Symbol(propertyNode.getKeyName(), 0, Type.OBJECT)); - } - @Override public Node leaveReturnNode(final ReturnNode returnNode) { - final Node expr = returnNode.getExpression(); + final Expression expr = returnNode.getExpression(); final Type returnType; if (expr != null) { @@ -784,7 +777,7 @@ final class Attr extends NodeOperatorVisitor { final LiteralNode lit = (LiteralNode)test; if (lit.isNumeric() && !(lit.getValue() instanceof Integer)) { if (JSType.isRepresentableAsInt(lit.getNumber())) { - newCaseNode = caseNode.setTest(LiteralNode.newInstance(lit, lit.getInt32()).accept(this)); + newCaseNode = caseNode.setTest((Expression)LiteralNode.newInstance(lit, lit.getInt32()).accept(this)); } } } else { @@ -847,19 +840,18 @@ final class Attr extends NodeOperatorVisitor { @Override public Node leaveVarNode(final VarNode varNode) { - VarNode newVarNode = varNode; + final Expression init = varNode.getInit(); + final IdentNode ident = varNode.getName(); + final String name = ident.getName(); - final Node init = newVarNode.getInit(); - final IdentNode ident = newVarNode.getName(); - final String name = ident.getName(); - - final Symbol symbol = findSymbol(lc.getCurrentBlock(), ident.getName()); + final Symbol symbol = findSymbol(lc.getCurrentBlock(), name); + assert ident.getSymbol() == symbol; if (init == null) { // var x; with no init will be treated like a use of x by // leaveIdentNode unless we remove the name from the localdef list. removeLocalDef(name); - return end(newVarNode.setSymbol(lc, symbol)); + return end(varNode); } addLocalDef(name); @@ -868,8 +860,7 @@ final class Attr extends NodeOperatorVisitor { final IdentNode newIdent = (IdentNode)ident.setSymbol(lc, symbol); - newVarNode = newVarNode.setName(newIdent); - newVarNode = (VarNode)newVarNode.setSymbol(lc, symbol); + final VarNode newVarNode = varNode.setName(newIdent); final boolean isScript = lc.getDefiningFunction(symbol).isProgram(); //see NASHORN-56 if ((init.getType().isNumeric() || init.getType().isBoolean()) && !isScript) { @@ -879,7 +870,7 @@ final class Attr extends NodeOperatorVisitor { newType(symbol, Type.OBJECT); } - assert newVarNode.hasType() : newVarNode + " has no type"; + assert newVarNode.getName().hasType() : newVarNode + " has no type"; return end(newVarNode); } @@ -907,11 +898,11 @@ final class Attr extends NodeOperatorVisitor { public Node leaveDELETE(final UnaryNode unaryNode) { final FunctionNode currentFunctionNode = lc.getCurrentFunction(); final boolean strictMode = currentFunctionNode.isStrict(); - final Node rhs = unaryNode.rhs(); - final Node strictFlagNode = LiteralNode.newInstance(unaryNode, strictMode).accept(this); + final Expression rhs = unaryNode.rhs(); + final Expression strictFlagNode = (Expression)LiteralNode.newInstance(unaryNode, strictMode).accept(this); Request request = Request.DELETE; - final List args = new ArrayList<>(); + final List args = new ArrayList<>(); if (rhs instanceof IdentNode) { // If this is a declared variable or a function parameter, delete always fails (except for globals). @@ -922,7 +913,7 @@ final class Attr extends NodeOperatorVisitor { if (failDelete && rhs.getSymbol().isThis()) { return LiteralNode.newInstance(unaryNode, true).accept(this); } - final Node literalNode = LiteralNode.newInstance(unaryNode, name).accept(this); + final Expression literalNode = (Expression)LiteralNode.newInstance(unaryNode, name).accept(this); if (!failDelete) { args.add(compilerConstant(SCOPE)); @@ -934,16 +925,17 @@ final class Attr extends NodeOperatorVisitor { request = Request.FAIL_DELETE; } } else if (rhs instanceof AccessNode) { - final Node base = ((AccessNode)rhs).getBase(); - final IdentNode property = ((AccessNode)rhs).getProperty(); + final Expression base = ((AccessNode)rhs).getBase(); + final IdentNode property = ((AccessNode)rhs).getProperty(); args.add(base); - args.add(LiteralNode.newInstance(unaryNode, property.getName()).accept(this)); + args.add((Expression)LiteralNode.newInstance(unaryNode, property.getName()).accept(this)); args.add(strictFlagNode); } else if (rhs instanceof IndexNode) { - final Node base = ((IndexNode)rhs).getBase(); - final Node index = ((IndexNode)rhs).getIndex(); + final IndexNode indexNode = (IndexNode)rhs; + final Expression base = indexNode.getBase(); + final Expression index = indexNode.getIndex(); args.add(base); args.add(index); @@ -998,15 +990,15 @@ final class Attr extends NodeOperatorVisitor { @Override public Node leaveTYPEOF(final UnaryNode unaryNode) { - final Node rhs = unaryNode.rhs(); + final Expression rhs = unaryNode.rhs(); - List args = new ArrayList<>(); + List args = new ArrayList<>(); if (rhs instanceof IdentNode && !rhs.getSymbol().isParam() && !rhs.getSymbol().isVar()) { args.add(compilerConstant(SCOPE)); - args.add(LiteralNode.newInstance(rhs, ((IdentNode)rhs).getName()).accept(this)); //null + args.add((Expression)LiteralNode.newInstance(rhs, ((IdentNode)rhs).getName()).accept(this)); //null } else { args.add(rhs); - args.add(LiteralNode.newInstance(unaryNode).accept(this)); //null, do not reuse token of identifier rhs, it can be e.g. 'this' + args.add((Expression)LiteralNode.newInstance(unaryNode).accept(this)); //null, do not reuse token of identifier rhs, it can be e.g. 'this' } RuntimeNode runtimeNode = new RuntimeNode(unaryNode, Request.TYPEOF, args); @@ -1040,8 +1032,8 @@ final class Attr extends NodeOperatorVisitor { */ @Override public Node leaveADD(final BinaryNode binaryNode) { - final Node lhs = binaryNode.lhs(); - final Node rhs = binaryNode.rhs(); + final Expression lhs = binaryNode.lhs(); + final Expression rhs = binaryNode.rhs(); ensureTypeNotUnknown(lhs); ensureTypeNotUnknown(rhs); @@ -1096,8 +1088,8 @@ final class Attr extends NodeOperatorVisitor { private Node leaveAssignmentNode(final BinaryNode binaryNode) { BinaryNode newBinaryNode = binaryNode; - final Node lhs = binaryNode.lhs(); - final Node rhs = binaryNode.rhs(); + final Expression lhs = binaryNode.lhs(); + final Expression rhs = binaryNode.rhs(); final Type type; if (rhs.getType().isNumeric()) { @@ -1133,8 +1125,8 @@ final class Attr extends NodeOperatorVisitor { @Override public Node leaveASSIGN_ADD(final BinaryNode binaryNode) { - final Node lhs = binaryNode.lhs(); - final Node rhs = binaryNode.rhs(); + final Expression lhs = binaryNode.lhs(); + final Expression rhs = binaryNode.rhs(); final Type widest = Type.widest(lhs.getType(), rhs.getType()); //Type.NUMBER if we can't prove that the add doesn't overflow. todo @@ -1413,13 +1405,13 @@ final class Attr extends NodeOperatorVisitor { @Override public Node leaveTernaryNode(final TernaryNode ternaryNode) { - final Node lhs = ternaryNode.rhs(); - final Node rhs = ternaryNode.third(); + final Expression trueExpr = ternaryNode.getTrueExpression(); + final Expression falseExpr = ternaryNode.getFalseExpression(); - ensureTypeNotUnknown(lhs); - ensureTypeNotUnknown(rhs); + ensureTypeNotUnknown(trueExpr); + ensureTypeNotUnknown(falseExpr); - final Type type = Type.widest(lhs.getType(), rhs.getType()); + final Type type = Type.widest(trueExpr.getType(), falseExpr.getType()); return end(ensureSymbol(type, ternaryNode)); } @@ -1537,7 +1529,7 @@ final class Attr extends NodeOperatorVisitor { } } - private static void ensureTypeNotUnknown(final Node node) { + private static void ensureTypeNotUnknown(final Expression node) { final Symbol symbol = node.getSymbol(); @@ -1594,13 +1586,13 @@ final class Attr extends NodeOperatorVisitor { * * @param assignmentDest the destination node of the assignment, e.g. lhs for binary nodes */ - private Node ensureAssignmentSlots(final Node assignmentDest) { + private Expression ensureAssignmentSlots(final Expression assignmentDest) { final LexicalContext attrLexicalContext = lc; - return assignmentDest.accept(new NodeVisitor(new LexicalContext()) { + return (Expression)assignmentDest.accept(new NodeVisitor(new LexicalContext()) { @Override public Node leaveIndexNode(final IndexNode indexNode) { assert indexNode.getSymbol().isTemp(); - final Node index = indexNode.getIndex(); + final Expression index = indexNode.getIndex(); //only temps can be set as needing slots. the others will self resolve //it is illegal to take a scope var and force it to be a slot, that breaks Symbol indexSymbol = index.getSymbol(); @@ -1642,7 +1634,7 @@ final class Attr extends NodeOperatorVisitor { changed.clear(); final FunctionNode newFunctionNode = (FunctionNode)currentFunctionNode.accept(new NodeVisitor(new LexicalContext()) { - private Node widen(final Node node, final Type to) { + private Expression widen(final Expression node, final Type to) { if (node instanceof LiteralNode) { return node; } @@ -1654,7 +1646,7 @@ final class Attr extends NodeOperatorVisitor { symbol = temporarySymbols.getTypedTemporarySymbol(to); } newType(symbol, to); - final Node newNode = node.setSymbol(lc, symbol); + final Expression newNode = node.setSymbol(lc, symbol); changed.add(newNode); return newNode; } @@ -1709,7 +1701,7 @@ final class Attr extends NodeOperatorVisitor { private Node leaveSelfModifyingAssignmentNode(final BinaryNode binaryNode, final Type destType) { //e.g. for -=, Number, no wider, destType (binaryNode.getWidestOperationType()) is the coerce type - final Node lhs = binaryNode.lhs(); + final Expression lhs = binaryNode.lhs(); newType(lhs.getSymbol(), destType); //may not narrow if dest is already wider than destType // ensureSymbol(destType, binaryNode); //for OP= nodes, the node can carry a narrower types than its lhs rhs. This is perfectly fine @@ -1717,9 +1709,9 @@ final class Attr extends NodeOperatorVisitor { return end(ensureSymbol(destType, ensureAssignmentSlots(binaryNode))); } - private Node ensureSymbol(final Type type, final Node node) { + private Expression ensureSymbol(final Type type, final Expression expr) { LOG.info("New TEMPORARY added to ", lc.getCurrentFunction().getName(), " type=", type); - return temporarySymbols.ensureSymbol(lc, type, node); + return temporarySymbols.ensureSymbol(lc, type, expr); } private Symbol newInternal(final String name, final Type type) { @@ -1841,11 +1833,11 @@ final class Attr extends NodeOperatorVisitor { return true; } - private Node end(final Node node) { + private T end(final T node) { return end(node, true); } - private Node end(final Node node, final boolean printNode) { + private T end(final T node, final boolean printNode) { if(node instanceof Statement) { // If we're done with a statement, all temporaries can be reused. temporarySymbols.reuse(); @@ -1860,10 +1852,13 @@ final class Attr extends NodeOperatorVisitor { append(" in '"). append(lc.getCurrentFunction().getName()); - if (node.getSymbol() == null) { - sb.append(" "); - } else { - sb.append(" '); + if(node instanceof Expression) { + final Symbol symbol = ((Expression)node).getSymbol(); + if (symbol == null) { + sb.append(" "); + } else { + sb.append(" '); + } } LOG.unindent(); diff --git a/nashorn/src/jdk/nashorn/internal/codegen/BranchOptimizer.java b/nashorn/src/jdk/nashorn/internal/codegen/BranchOptimizer.java index ee922115d15..02ea95f17e6 100644 --- a/nashorn/src/jdk/nashorn/internal/codegen/BranchOptimizer.java +++ b/nashorn/src/jdk/nashorn/internal/codegen/BranchOptimizer.java @@ -34,7 +34,7 @@ import static jdk.nashorn.internal.codegen.Condition.NE; import jdk.nashorn.internal.codegen.types.Type; import jdk.nashorn.internal.ir.BinaryNode; -import jdk.nashorn.internal.ir.Node; +import jdk.nashorn.internal.ir.Expression; import jdk.nashorn.internal.ir.TernaryNode; import jdk.nashorn.internal.ir.UnaryNode; @@ -52,16 +52,16 @@ final class BranchOptimizer { this.method = method; } - void execute(final Node node, final Label label, final boolean state) { + void execute(final Expression node, final Label label, final boolean state) { branchOptimizer(node, label, state); } - private void load(final Node node) { + private void load(final Expression node) { codegen.load(node); } private void branchOptimizer(final UnaryNode unaryNode, final Label label, final boolean state) { - final Node rhs = unaryNode.rhs(); + final Expression rhs = unaryNode.rhs(); switch (unaryNode.tokenType()) { case NOT: @@ -88,8 +88,8 @@ final class BranchOptimizer { } private void branchOptimizer(final BinaryNode binaryNode, final Label label, final boolean state) { - final Node lhs = binaryNode.lhs(); - final Node rhs = binaryNode.rhs(); + final Expression lhs = binaryNode.lhs(); + final Expression rhs = binaryNode.rhs(); switch (binaryNode.tokenType()) { case AND: @@ -173,7 +173,7 @@ final class BranchOptimizer { } } - private void branchOptimizer(final Node node, final Label label, final boolean state) { + private void branchOptimizer(final Expression node, final Label label, final boolean state) { if (!(node instanceof TernaryNode)) { if (node instanceof BinaryNode) { diff --git a/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java b/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java index b9d35682458..b6c6f3a13e9 100644 --- a/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java +++ b/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java @@ -69,6 +69,7 @@ import jdk.nashorn.internal.ir.AccessNode; import jdk.nashorn.internal.ir.BaseNode; import jdk.nashorn.internal.ir.BinaryNode; import jdk.nashorn.internal.ir.Block; +import jdk.nashorn.internal.ir.BlockStatement; import jdk.nashorn.internal.ir.BreakNode; import jdk.nashorn.internal.ir.BreakableNode; import jdk.nashorn.internal.ir.CallNode; @@ -76,7 +77,8 @@ import jdk.nashorn.internal.ir.CaseNode; import jdk.nashorn.internal.ir.CatchNode; import jdk.nashorn.internal.ir.ContinueNode; import jdk.nashorn.internal.ir.EmptyNode; -import jdk.nashorn.internal.ir.ExecuteNode; +import jdk.nashorn.internal.ir.Expression; +import jdk.nashorn.internal.ir.ExpressionStatement; import jdk.nashorn.internal.ir.ForNode; import jdk.nashorn.internal.ir.FunctionNode; import jdk.nashorn.internal.ir.FunctionNode.CompilationState; @@ -350,11 +352,11 @@ final class CodeGenerator extends NodeOperatorVisitor args) { + private int loadArgs(final List args) { return loadArgs(args, null, false, args.size()); } - private int loadArgs(final List args, final String signature, final boolean isVarArg, final int argCount) { + private int loadArgs(final List args, final String signature, final boolean isVarArg, final int argCount) { // arg have already been converted to objects here. if (isVarArg || argCount > LinkerCallSite.ARGLIMIT) { loadArgsArray(args); @@ -553,7 +555,7 @@ final class CodeGenerator extends NodeOperatorVisitor= argCount) { @@ -574,13 +576,13 @@ final class CodeGenerator extends NodeOperatorVisitor args = callNode.getArgs(); - final Node function = callNode.getFunction(); - final Block currentBlock = lc.getCurrentBlock(); + final List args = callNode.getArgs(); + final Expression function = callNode.getFunction(); + final Block currentBlock = lc.getCurrentBlock(); final CodeGeneratorLexicalContext codegenLexicalContext = lc; - final Type callNodeType = callNode.getType(); + final Type callNodeType = callNode.getType(); function.accept(new NodeVisitor(new LexicalContext()) { @@ -771,11 +773,19 @@ final class CodeGenerator extends NodeOperatorVisitor(init) { + new Store(init) { @Override protected void storeNonDiscard() { return; @@ -1047,7 +1051,7 @@ final class CodeGenerator extends NodeOperatorVisitor type = arrayType.getTypeClass(); @@ -1166,11 +1173,11 @@ final class CodeGenerator extends NodeOperatorVisitor args) { + private MethodEmitter loadArgsArray(final List args) { final Object[] array = new Object[args.size()]; loadConstant(array); @@ -1323,16 +1330,16 @@ final class CodeGenerator extends NodeOperatorVisitor elements = objectNode.getElements(); - final List keys = new ArrayList<>(); - final List symbols = new ArrayList<>(); - final List values = new ArrayList<>(); + final List keys = new ArrayList<>(); + final List symbols = new ArrayList<>(); + final List values = new ArrayList<>(); boolean hasGettersSetters = false; for (PropertyNode propertyNode: elements) { - final Node value = propertyNode.getValue(); + final Expression value = propertyNode.getValue(); final String key = propertyNode.getKeyName(); - final Symbol symbol = value == null ? null : propertyNode.getSymbol(); + final Symbol symbol = value == null ? null : propertyNode.getKey().getSymbol(); if (value == null) { hasGettersSetters = true; @@ -1346,9 +1353,9 @@ final class CodeGenerator extends NodeOperatorVisitor OBJECT_SPILL_THRESHOLD) { new SpillObjectCreator(this, keys, symbols, values).makeObject(method); } else { - new FieldObjectCreator(this, keys, symbols, values) { + new FieldObjectCreator(this, keys, symbols, values) { @Override - protected void loadValue(final Node node) { + protected void loadValue(final Expression node) { load(node); } @@ -1419,7 +1426,7 @@ final class CodeGenerator extends NodeOperatorVisitor && ((LiteralNode) node).isNull(); } - private boolean nullCheck(final RuntimeNode runtimeNode, final List args, final String signature) { + private boolean nullCheck(final RuntimeNode runtimeNode, final List args, final String signature) { final Request request = runtimeNode.getRequest(); if (!Request.isEQ(request) && !Request.isNE(request)) { @@ -1444,11 +1451,11 @@ final class CodeGenerator extends NodeOperatorVisitor args) { + private boolean specializationCheck(final RuntimeNode.Request request, final Expression node, final List args) { if (!request.canSpecialize()) { return false; } @@ -1555,10 +1562,11 @@ final class CodeGenerator extends NodeOperatorVisitor args = runtimeNode.getArgs(); if (runtimeNode.isPrimitive() && !runtimeNode.isFinal() && isReducible(runtimeNode.getRequest())) { - final Node lhs = runtimeNode.getArgs().get(0); - assert runtimeNode.getArgs().size() > 1 : runtimeNode + " must have two args"; - final Node rhs = runtimeNode.getArgs().get(1); + final Expression lhs = args.get(0); + assert args.size() > 1 : runtimeNode + " must have two args"; + final Expression rhs = args.get(1); final Type type = runtimeNode.getType(); final Symbol symbol = runtimeNode.getSymbol(); @@ -1595,9 +1603,6 @@ final class CodeGenerator extends NodeOperatorVisitor args = runtimeNode.getArgs(); - if (nullCheck(runtimeNode, args, new FunctionSignature(false, false, runtimeNode.getType(), args).toString())) { return false; } @@ -1606,7 +1611,7 @@ final class CodeGenerator extends NodeOperatorVisitor cases = switchNode.getCases(); @@ -1875,7 +1878,7 @@ final class CodeGenerator extends NodeOperatorVisitor(exception) { @Override @@ -2038,7 +2041,7 @@ final class CodeGenerator extends NodeOperatorVisitor args = callNode.getArgs(); + final List args = callNode.getArgs(); // Load function reference. load(callNode.getFunction()).convert(Type.OBJECT); // must detect type error @@ -2302,7 +2303,7 @@ final class CodeGenerator extends NodeOperatorVisitor */ - private abstract class SelfModifyingStore extends Store { - protected SelfModifyingStore(final T assignNode, final Node target) { + private abstract class SelfModifyingStore extends Store { + protected SelfModifyingStore(final T assignNode, final Expression target) { super(assignNode, target); } @@ -2939,13 +2939,13 @@ final class CodeGenerator extends NodeOperatorVisitor { + private abstract class Store { /** An assignment node, e.g. x += y */ protected final T assignNode; /** The target node to store to, e.g. x */ - private final Node target; + private final Expression target; /** How deep on the stack do the arguments go if this generates an indy call */ private int depth; @@ -2959,7 +2959,7 @@ final class CodeGenerator extends NodeOperatorVisitor { * strings etc as well. */ @Override - public Node leaveADD(final BinaryNode binaryNode) { - final Node lhs = binaryNode.lhs(); - final Node rhs = binaryNode.rhs(); + public Expression leaveADD(final BinaryNode binaryNode) { + final Expression lhs = binaryNode.lhs(); + final Expression rhs = binaryNode.rhs(); final Type type = binaryNode.getType(); @@ -240,7 +241,7 @@ final class FinalizeTypes extends NodeOperatorVisitor { return leaveASSIGN(binaryNode); } - private boolean symbolIsInteger(Node node) { + private boolean symbolIsInteger(final Expression node) { final Symbol symbol = node.getSymbol(); assert symbol != null && symbol.getSymbolType().isInteger() : "int coercion expected: " + Debug.id(symbol) + " " + symbol + " " + lc.getCurrentFunction().getSource(); return true; @@ -372,7 +373,7 @@ final class FinalizeTypes extends NodeOperatorVisitor { @Override public Node leaveCatchNode(final CatchNode catchNode) { - final Node exceptionCondition = catchNode.getExceptionCondition(); + final Expression exceptionCondition = catchNode.getExceptionCondition(); if (exceptionCondition != null) { return catchNode.setExceptionCondition(convert(exceptionCondition, Type.BOOLEAN)); } @@ -380,16 +381,16 @@ final class FinalizeTypes extends NodeOperatorVisitor { } @Override - public Node leaveExecuteNode(final ExecuteNode executeNode) { + public Node leaveExpressionStatement(final ExpressionStatement expressionStatement) { temporarySymbols.reuse(); - return executeNode.setExpression(discard(executeNode.getExpression())); + return expressionStatement.setExpression(discard(expressionStatement.getExpression())); } @Override public Node leaveForNode(final ForNode forNode) { - final Node init = forNode.getInit(); - final Node test = forNode.getTest(); - final Node modify = forNode.getModify(); + final Expression init = forNode.getInit(); + final Expression test = forNode.getTest(); + final Expression modify = forNode.getModify(); if (forNode.isForIn()) { return forNode.setModify(lc, convert(forNode.getModify(), Type.OBJECT)); // NASHORN-400 @@ -439,13 +440,13 @@ final class FinalizeTypes extends NodeOperatorVisitor { public boolean enterLiteralNode(final LiteralNode literalNode) { if (literalNode instanceof ArrayLiteralNode) { final ArrayLiteralNode arrayLiteralNode = (ArrayLiteralNode)literalNode; - final Node[] array = arrayLiteralNode.getValue(); + final Expression[] array = arrayLiteralNode.getValue(); final Type elementType = arrayLiteralNode.getElementType(); for (int i = 0; i < array.length; i++) { final Node element = array[i]; if (element != null) { - array[i] = convert(element.accept(this), elementType); + array[i] = convert((Expression)element.accept(this), elementType); } } } @@ -455,7 +456,7 @@ final class FinalizeTypes extends NodeOperatorVisitor { @Override public Node leaveReturnNode(final ReturnNode returnNode) { - final Node expr = returnNode.getExpression(); + final Expression expr = returnNode.getExpression(); if (expr != null) { return returnNode.setExpression(convert(expr, lc.getCurrentFunction().getReturnType())); } @@ -464,8 +465,8 @@ final class FinalizeTypes extends NodeOperatorVisitor { @Override public Node leaveRuntimeNode(final RuntimeNode runtimeNode) { - final List args = runtimeNode.getArgs(); - for (final Node arg : args) { + final List args = runtimeNode.getArgs(); + for (final Expression arg : args) { assert !arg.getType().isUnknown(); } return runtimeNode; @@ -479,12 +480,12 @@ final class FinalizeTypes extends NodeOperatorVisitor { return switchNode; } - final Node expression = switchNode.getExpression(); + final Expression expression = switchNode.getExpression(); final List cases = switchNode.getCases(); final List newCases = new ArrayList<>(); for (final CaseNode caseNode : cases) { - final Node test = caseNode.getTest(); + final Expression test = caseNode.getTest(); newCases.add(test != null ? caseNode.setTest(convert(test, Type.OBJECT)) : caseNode); } @@ -495,7 +496,7 @@ final class FinalizeTypes extends NodeOperatorVisitor { @Override public Node leaveTernaryNode(final TernaryNode ternaryNode) { - return ternaryNode.setLHS(convert(ternaryNode.lhs(), Type.BOOLEAN)); + return ternaryNode.setTest(convert(ternaryNode.getTest(), Type.BOOLEAN)); } @Override @@ -505,16 +506,16 @@ final class FinalizeTypes extends NodeOperatorVisitor { @Override public Node leaveVarNode(final VarNode varNode) { - final Node init = varNode.getInit(); + final Expression init = varNode.getInit(); if (init != null) { final SpecializedNode specialized = specialize(varNode); final VarNode specVarNode = (VarNode)specialized.node; Type destType = specialized.type; if (destType == null) { - destType = specVarNode.getType(); + destType = specVarNode.getName().getType(); } - assert specVarNode.hasType() : specVarNode + " doesn't have a type"; - final Node convertedInit = convert(init, destType); + assert specVarNode.getName().hasType() : specVarNode + " doesn't have a type"; + final Expression convertedInit = convert(init, destType); temporarySymbols.reuse(); return specVarNode.setInit(convertedInit); } @@ -524,7 +525,7 @@ final class FinalizeTypes extends NodeOperatorVisitor { @Override public Node leaveWhileNode(final WhileNode whileNode) { - final Node test = whileNode.getTest(); + final Expression test = whileNode.getTest(); if (test != null) { return whileNode.setTest(lc, convert(test, Type.BOOLEAN)); } @@ -599,8 +600,8 @@ final class FinalizeTypes extends NodeOperatorVisitor { */ @SuppressWarnings("fallthrough") private Node leaveCmp(final BinaryNode binaryNode, final RuntimeNode.Request request) { - final Node lhs = binaryNode.lhs(); - final Node rhs = binaryNode.rhs(); + final Expression lhs = binaryNode.lhs(); + final Expression rhs = binaryNode.rhs(); Type widest = Type.widest(lhs.getType(), rhs.getType()); @@ -696,10 +697,10 @@ final class FinalizeTypes extends NodeOperatorVisitor { } } - SpecializedNode specialize(final Assignment assignment) { + SpecializedNode specialize(final Assignment assignment) { final Node node = ((Node)assignment); final T lhs = assignment.getAssignmentDest(); - final Node rhs = assignment.getAssignmentSource(); + final Expression rhs = assignment.getAssignmentSource(); if (!canHaveCallSiteType(lhs)) { return new SpecializedNode(node, null); @@ -718,8 +719,16 @@ final class FinalizeTypes extends NodeOperatorVisitor { } final Node newNode = assignment.setAssignmentDest(setTypeOverride(lhs, to)); - final Node typePropagatedNode = propagateType(newNode, to); - + final Node typePropagatedNode; + if(newNode instanceof Expression) { + typePropagatedNode = propagateType((Expression)newNode, to); + } else if(newNode instanceof VarNode) { + // VarNode, being a statement, doesn't have its own symbol; it uses the symbol of its name instead. + final VarNode varNode = (VarNode)newNode; + typePropagatedNode = varNode.setName((IdentNode)propagateType(varNode.getName(), to)); + } else { + throw new AssertionError(); + } return new SpecializedNode(typePropagatedNode, to); } @@ -759,7 +768,7 @@ final class FinalizeTypes extends NodeOperatorVisitor { * @param to new type */ @SuppressWarnings("unchecked") - T setTypeOverride(final T node, final Type to) { + T setTypeOverride(final T node, final Type to) { final Type from = node.getType(); if (!node.getType().equals(to)) { LOG.info("Changing call override type for '", node, "' from ", node.getType(), " to ", to); @@ -788,7 +797,7 @@ final class FinalizeTypes extends NodeOperatorVisitor { * @param to destination type * @return conversion node */ - private Node convert(final Node node, final Type to) { + private Expression convert(final Expression node, final Type to) { assert !to.isUnknown() : "unknown type for " + node + " class=" + node.getClass(); assert node != null : "node is null"; assert node.getSymbol() != null : "node " + node + " " + node.getClass() + " has no symbol! " + lc.getCurrentFunction(); @@ -804,7 +813,7 @@ final class FinalizeTypes extends NodeOperatorVisitor { return node; } - Node resultNode = node; + Expression resultNode = node; if (node instanceof LiteralNode && !(node instanceof ArrayLiteralNode) && !to.isObject()) { final LiteralNode newNode = new LiteralNodeConstantEvaluator((LiteralNode)node, to).eval(); @@ -828,9 +837,9 @@ final class FinalizeTypes extends NodeOperatorVisitor { return temporarySymbols.ensureSymbol(lc, to, resultNode); } - private static Node discard(final Node node) { + private static Expression discard(final Expression node) { if (node.getSymbol() != null) { - final Node discard = new UnaryNode(Token.recast(node.getToken(), TokenType.DISCARD), node); + final UnaryNode discard = new UnaryNode(Token.recast(node.getToken(), TokenType.DISCARD), node); //discard never has a symbol in the discard node - then it would be a nop assert !node.isTerminal(); return discard; @@ -853,7 +862,7 @@ final class FinalizeTypes extends NodeOperatorVisitor { * @param node * @param to */ - private Node propagateType(final Node node, final Type to) { + private Expression propagateType(final Expression node, final Type to) { Symbol symbol = node.getSymbol(); if (symbol.isTemp() && symbol.getSymbolType() != to) { symbol = symbol.setTypeOverrideShared(to, temporarySymbols); diff --git a/nashorn/src/jdk/nashorn/internal/codegen/FoldConstants.java b/nashorn/src/jdk/nashorn/internal/codegen/FoldConstants.java index 2331cf7570d..49dfbb324b7 100644 --- a/nashorn/src/jdk/nashorn/internal/codegen/FoldConstants.java +++ b/nashorn/src/jdk/nashorn/internal/codegen/FoldConstants.java @@ -28,8 +28,8 @@ package jdk.nashorn.internal.codegen; import jdk.nashorn.internal.codegen.types.Type; import jdk.nashorn.internal.ir.BinaryNode; import jdk.nashorn.internal.ir.Block; +import jdk.nashorn.internal.ir.BlockStatement; import jdk.nashorn.internal.ir.EmptyNode; -import jdk.nashorn.internal.ir.ExecuteNode; import jdk.nashorn.internal.ir.FunctionNode; import jdk.nashorn.internal.ir.FunctionNode.CompilationState; import jdk.nashorn.internal.ir.IfNode; @@ -91,7 +91,7 @@ final class FoldConstants extends NodeVisitor { if (test instanceof LiteralNode) { final Block shortCut = ((LiteralNode)test).isTrue() ? ifNode.getPass() : ifNode.getFail(); if (shortCut != null) { - return new ExecuteNode(shortCut.getLineNumber(), shortCut.getToken(), shortCut.getFinish(), shortCut); + return new BlockStatement(ifNode.getLineNumber(), shortCut); } return new EmptyNode(ifNode); } @@ -100,9 +100,9 @@ final class FoldConstants extends NodeVisitor { @Override public Node leaveTernaryNode(final TernaryNode ternaryNode) { - final Node test = ternaryNode.lhs(); + final Node test = ternaryNode.getTest(); if (test instanceof LiteralNode) { - return ((LiteralNode)test).isTrue() ? ternaryNode.rhs() : ternaryNode.third(); + return ((LiteralNode)test).isTrue() ? ternaryNode.getTrueExpression() : ternaryNode.getFalseExpression(); } return ternaryNode; } diff --git a/nashorn/src/jdk/nashorn/internal/codegen/FunctionSignature.java b/nashorn/src/jdk/nashorn/internal/codegen/FunctionSignature.java index 057d2d4e454..1c1b5f7469f 100644 --- a/nashorn/src/jdk/nashorn/internal/codegen/FunctionSignature.java +++ b/nashorn/src/jdk/nashorn/internal/codegen/FunctionSignature.java @@ -31,8 +31,8 @@ import java.lang.invoke.MethodType; import java.util.ArrayList; import java.util.List; import jdk.nashorn.internal.codegen.types.Type; +import jdk.nashorn.internal.ir.Expression; import jdk.nashorn.internal.ir.FunctionNode; -import jdk.nashorn.internal.ir.Node; import jdk.nashorn.internal.runtime.ScriptFunction; import jdk.nashorn.internal.runtime.linker.LinkerCallSite; @@ -63,7 +63,7 @@ public final class FunctionSignature { * @param retType what is the return type * @param args argument list of AST Nodes */ - public FunctionSignature(final boolean hasSelf, final boolean hasCallee, final Type retType, final List args) { + public FunctionSignature(final boolean hasSelf, final boolean hasCallee, final Type retType, final List args) { this(hasSelf, hasCallee, retType, FunctionSignature.typeArray(args)); } @@ -167,7 +167,7 @@ public final class FunctionSignature { * * @return the array of types */ - private static Type[] typeArray(final List args) { + private static Type[] typeArray(final List args) { if (args == null) { return null; } @@ -175,7 +175,7 @@ public final class FunctionSignature { final Type[] typeArray = new Type[args.size()]; int pos = 0; - for (final Node arg : args) { + for (final Expression arg : args) { typeArray[pos++] = arg.getType(); } diff --git a/nashorn/src/jdk/nashorn/internal/codegen/Lower.java b/nashorn/src/jdk/nashorn/internal/codegen/Lower.java index 880fea67640..cc109695d38 100644 --- a/nashorn/src/jdk/nashorn/internal/codegen/Lower.java +++ b/nashorn/src/jdk/nashorn/internal/codegen/Lower.java @@ -37,12 +37,14 @@ import jdk.nashorn.internal.ir.BaseNode; import jdk.nashorn.internal.ir.BinaryNode; import jdk.nashorn.internal.ir.Block; import jdk.nashorn.internal.ir.BlockLexicalContext; +import jdk.nashorn.internal.ir.BlockStatement; import jdk.nashorn.internal.ir.BreakNode; import jdk.nashorn.internal.ir.CallNode; import jdk.nashorn.internal.ir.CatchNode; import jdk.nashorn.internal.ir.ContinueNode; import jdk.nashorn.internal.ir.EmptyNode; -import jdk.nashorn.internal.ir.ExecuteNode; +import jdk.nashorn.internal.ir.Expression; +import jdk.nashorn.internal.ir.ExpressionStatement; import jdk.nashorn.internal.ir.ForNode; import jdk.nashorn.internal.ir.FunctionNode; import jdk.nashorn.internal.ir.FunctionNode.CompilationState; @@ -138,7 +140,7 @@ final class Lower extends NodeOperatorVisitor { public boolean enterBlock(final Block block) { final FunctionNode function = lc.getCurrentFunction(); if (lc.isFunctionBody() && function.isProgram() && !function.hasDeclaredFunctions()) { - new ExecuteNode(block.getLineNumber(), block.getToken(), block.getFinish(), LiteralNode.newInstance(block, ScriptRuntime.UNDEFINED)).accept(this); + new ExpressionStatement(function.getLineNumber(), block.getToken(), block.getFinish(), LiteralNode.newInstance(block, ScriptRuntime.UNDEFINED)).accept(this); } return true; } @@ -154,7 +156,7 @@ final class Lower extends NodeOperatorVisitor { final boolean isProgram = currentFunction.isProgram(); final Statement last = lc.getLastStatement(); final ReturnNode returnNode = new ReturnNode( - last == null ? block.getLineNumber() : last.getLineNumber(), //TODO? + last == null ? currentFunction.getLineNumber() : last.getLineNumber(), //TODO? currentFunction.getToken(), currentFunction.getFinish(), isProgram ? @@ -195,29 +197,32 @@ final class Lower extends NodeOperatorVisitor { } @Override - public Node leaveExecuteNode(final ExecuteNode executeNode) { - final Node expr = executeNode.getExpression(); - ExecuteNode node = executeNode; + public Node leaveExpressionStatement(final ExpressionStatement expressionStatement) { + final Expression expr = expressionStatement.getExpression(); + ExpressionStatement node = expressionStatement; final FunctionNode currentFunction = lc.getCurrentFunction(); if (currentFunction.isProgram()) { - if (!(expr instanceof Block) || expr instanceof FunctionNode) { // it's not a block, but can be a function - if (!isInternalExpression(expr) && !isEvalResultAssignment(expr)) { - node = executeNode.setExpression( - new BinaryNode( - Token.recast( - executeNode.getToken(), - TokenType.ASSIGN), - compilerConstant(RETURN), - expr)); - } + if (!isInternalExpression(expr) && !isEvalResultAssignment(expr)) { + node = expressionStatement.setExpression( + new BinaryNode( + Token.recast( + expressionStatement.getToken(), + TokenType.ASSIGN), + compilerConstant(RETURN), + expr)); } } return addStatement(node); } + @Override + public Node leaveBlockStatement(BlockStatement blockStatement) { + return addStatement(blockStatement); + } + @Override public Node leaveForNode(final ForNode forNode) { ForNode newForNode = forNode; @@ -302,11 +307,11 @@ final class Lower extends NodeOperatorVisitor { final IdentNode exception = new IdentNode(token, finish, lc.getCurrentFunction().uniqueName("catch_all")); - final Block catchBody = new Block(lineNumber, token, finish, new ThrowNode(lineNumber, token, finish, new IdentNode(exception), ThrowNode.IS_SYNTHETIC_RETHROW)). + final Block catchBody = new Block(token, finish, new ThrowNode(lineNumber, token, finish, new IdentNode(exception), ThrowNode.IS_SYNTHETIC_RETHROW)). setIsTerminal(lc, true); //ends with throw, so terminal final CatchNode catchAllNode = new CatchNode(lineNumber, token, finish, new IdentNode(exception), null, catchBody, CatchNode.IS_SYNTHETIC_RETHROW); - final Block catchAllBlock = new Block(lineNumber, token, finish, catchAllNode); + final Block catchAllBlock = new Block(token, finish, catchAllNode); //catchallblock -> catchallnode (catchnode) -> exception -> throw @@ -355,14 +360,14 @@ final class Lower extends NodeOperatorVisitor { if (!isTerminal(newStatements)) { newStatements.add(throwNode); } - return new Block(throwNode.getLineNumber(), throwNode.getToken(), throwNode.getFinish(), newStatements); + return BlockStatement.createReplacement(throwNode, newStatements); } return throwNode; } @Override public Node leaveBreakNode(final BreakNode breakNode) { - return copy(breakNode, Lower.this.lc.getBreakable(breakNode.getLabel())); + return copy(breakNode, (Node)Lower.this.lc.getBreakable(breakNode.getLabel())); } @Override @@ -372,15 +377,15 @@ final class Lower extends NodeOperatorVisitor { @Override public Node leaveReturnNode(final ReturnNode returnNode) { - final Node expr = returnNode.getExpression(); + final Expression expr = returnNode.getExpression(); final List newStatements = new ArrayList<>(); - final Node resultNode; + final Expression resultNode; if (expr != null) { //we need to evaluate the result of the return in case it is complex while //still in the try block, store it in a result value and return it afterwards resultNode = new IdentNode(Lower.this.compilerConstant(RETURN)); - newStatements.add(new ExecuteNode(returnNode.getLineNumber(), returnNode.getToken(), returnNode.getFinish(), new BinaryNode(Token.recast(returnNode.getToken(), TokenType.ASSIGN), resultNode, expr))); + newStatements.add(new ExpressionStatement(returnNode.getLineNumber(), returnNode.getToken(), returnNode.getFinish(), new BinaryNode(Token.recast(returnNode.getToken(), TokenType.ASSIGN), resultNode, expr))); } else { resultNode = null; } @@ -390,7 +395,7 @@ final class Lower extends NodeOperatorVisitor { newStatements.add(expr == null ? returnNode : returnNode.setExpression(resultNode)); } - return new ExecuteNode(returnNode.getLineNumber(), returnNode.getToken(), returnNode.getFinish(), new Block(returnNode.getLineNumber(), returnNode.getToken(), lc.getCurrentBlock().getFinish(), newStatements)); + return BlockStatement.createReplacement(returnNode, lc.getCurrentBlock().getFinish(), newStatements); } private Node copy(final Statement endpoint, final Node targetNode) { @@ -399,7 +404,7 @@ final class Lower extends NodeOperatorVisitor { if (!isTerminal(newStatements)) { newStatements.add(endpoint); } - return new ExecuteNode(endpoint.getLineNumber(), endpoint.getToken(), endpoint.getFinish(), new Block(endpoint.getLineNumber(), endpoint.getToken(), finish, newStatements)); + return BlockStatement.createReplacement(endpoint, finish, newStatements); } return endpoint; } @@ -461,7 +466,7 @@ final class Lower extends NodeOperatorVisitor { if (tryNode.getCatchBlocks().isEmpty()) { newTryNode = tryNode.setFinallyBody(null); } else { - Block outerBody = new Block(tryNode.getLineNumber(), tryNode.getToken(), tryNode.getFinish(), new ArrayList(Arrays.asList(tryNode.setFinallyBody(null)))); + Block outerBody = new Block(tryNode.getToken(), tryNode.getFinish(), new ArrayList(Arrays.asList(tryNode.setFinallyBody(null)))); newTryNode = tryNode.setBody(outerBody).setCatchBlocks(null); } @@ -478,7 +483,7 @@ final class Lower extends NodeOperatorVisitor { public Node leaveVarNode(final VarNode varNode) { addStatement(varNode); if (varNode.getFlag(VarNode.IS_LAST_FUNCTION_DECLARATION) && lc.getCurrentFunction().isProgram()) { - new ExecuteNode(varNode.getLineNumber(), varNode.getToken(), varNode.getFinish(), new IdentNode(varNode.getName())).accept(this); + new ExpressionStatement(varNode.getLineNumber(), varNode.getToken(), varNode.getFinish(), new IdentNode(varNode.getName())).accept(this); } return varNode; } @@ -511,7 +516,7 @@ final class Lower extends NodeOperatorVisitor { * @param function function called by a CallNode * @return transformed node to marker function or identity if not ident/access/indexnode */ - private static Node markerFunction(final Node function) { + private static Expression markerFunction(final Expression function) { if (function instanceof IdentNode) { return ((IdentNode)function).setIsFunction(); } else if (function instanceof BaseNode) { @@ -553,15 +558,15 @@ final class Lower extends NodeOperatorVisitor { private CallNode checkEval(final CallNode callNode) { if (callNode.getFunction() instanceof IdentNode) { - final List args = callNode.getArgs(); - final IdentNode callee = (IdentNode)callNode.getFunction(); + final List args = callNode.getArgs(); + final IdentNode callee = (IdentNode)callNode.getFunction(); // 'eval' call with at least one argument if (args.size() >= 1 && EVAL.symbolName().equals(callee.getName())) { final FunctionNode currentFunction = lc.getCurrentFunction(); return callNode.setEvalArgs( new CallNode.EvalArgs( - ensureUniqueNamesIn(args.get(0)).accept(this), + (Expression)ensureUniqueNamesIn(args.get(0)).accept(this), compilerConstant(THIS), evalLocation(callee), currentFunction.isStrict())); @@ -630,7 +635,7 @@ final class Lower extends NodeOperatorVisitor { * @param expression expression to check for internal symbol * @return true if internal, false otherwise */ - private static boolean isInternalExpression(final Node expression) { + private static boolean isInternalExpression(final Expression expression) { final Symbol symbol = expression.getSymbol(); return symbol != null && symbol.isInternal(); } diff --git a/nashorn/src/jdk/nashorn/internal/codegen/RangeAnalyzer.java b/nashorn/src/jdk/nashorn/internal/codegen/RangeAnalyzer.java index ab61d374818..4056ec0c2bd 100644 --- a/nashorn/src/jdk/nashorn/internal/codegen/RangeAnalyzer.java +++ b/nashorn/src/jdk/nashorn/internal/codegen/RangeAnalyzer.java @@ -28,11 +28,11 @@ package jdk.nashorn.internal.codegen; import java.util.HashMap; import java.util.HashSet; import java.util.Map; - import jdk.nashorn.internal.codegen.types.Range; import jdk.nashorn.internal.codegen.types.Type; import jdk.nashorn.internal.ir.Assignment; import jdk.nashorn.internal.ir.BinaryNode; +import jdk.nashorn.internal.ir.Expression; import jdk.nashorn.internal.ir.ForNode; import jdk.nashorn.internal.ir.IdentNode; import jdk.nashorn.internal.ir.LexicalContext; @@ -87,7 +87,7 @@ final class RangeAnalyzer extends NodeOperatorVisitor { } //destination visited - private Symbol setRange(final Node dest, final Range range) { + private Symbol setRange(final Expression dest, final Range range) { if (range.isUnknown()) { return null; } @@ -352,7 +352,6 @@ final class RangeAnalyzer extends NodeOperatorVisitor { range = range.isUnknown() ? Range.createGenericRange() : range; setRange(node.getName(), range); - setRange(node, range); } return node; @@ -438,12 +437,12 @@ final class RangeAnalyzer extends NodeOperatorVisitor { * @return */ private static Symbol findLoopCounter(final LoopNode node) { - final Node test = node.getTest(); + final Expression test = node.getTest(); if (test != null && test.isComparison()) { final BinaryNode binaryNode = (BinaryNode)test; - final Node lhs = binaryNode.lhs(); - final Node rhs = binaryNode.rhs(); + final Expression lhs = binaryNode.lhs(); + final Expression rhs = binaryNode.rhs(); //detect ident cmp int_literal if (lhs instanceof IdentNode && rhs instanceof LiteralNode && ((LiteralNode)rhs).getType().isInteger()) { diff --git a/nashorn/src/jdk/nashorn/internal/codegen/SpillObjectCreator.java b/nashorn/src/jdk/nashorn/internal/codegen/SpillObjectCreator.java index 33e1d432ac3..08dfedf1a9f 100644 --- a/nashorn/src/jdk/nashorn/internal/codegen/SpillObjectCreator.java +++ b/nashorn/src/jdk/nashorn/internal/codegen/SpillObjectCreator.java @@ -25,26 +25,25 @@ package jdk.nashorn.internal.codegen; +import static jdk.nashorn.internal.codegen.CompilerConstants.constructorNoLookup; +import static jdk.nashorn.internal.codegen.types.Type.OBJECT; + +import java.util.List; import jdk.nashorn.internal.codegen.types.Type; +import jdk.nashorn.internal.ir.Expression; import jdk.nashorn.internal.ir.LiteralNode; -import jdk.nashorn.internal.ir.Node; import jdk.nashorn.internal.ir.Symbol; import jdk.nashorn.internal.runtime.Property; import jdk.nashorn.internal.runtime.PropertyMap; import jdk.nashorn.internal.runtime.ScriptObject; import jdk.nashorn.internal.scripts.JO; -import java.util.List; - -import static jdk.nashorn.internal.codegen.CompilerConstants.constructorNoLookup; -import static jdk.nashorn.internal.codegen.types.Type.OBJECT; - /** * An object creator that uses spill properties. */ public class SpillObjectCreator extends ObjectCreator { - private final List values; + private final List values; /** * Constructor @@ -54,7 +53,7 @@ public class SpillObjectCreator extends ObjectCreator { * @param symbols symbols for fields in object * @param values list of values corresponding to keys */ - protected SpillObjectCreator(final CodeGenerator codegen, final List keys, final List symbols, final List values) { + protected SpillObjectCreator(final CodeGenerator codegen, final List keys, final List symbols, final List values) { super(codegen, keys, symbols, false, false); this.values = values; makeMap(); @@ -107,7 +106,7 @@ public class SpillObjectCreator extends ObjectCreator { for (int i = 0; i < length; i++) { final String key = keys.get(i); final Property property = propertyMap.findProperty(key); - final Node value = values.get(i); + final Expression value = values.get(i); if (property == null && value != null) { method.dup(); diff --git a/nashorn/src/jdk/nashorn/internal/codegen/Splitter.java b/nashorn/src/jdk/nashorn/internal/codegen/Splitter.java index e724ce261c3..a35c6dfdcf1 100644 --- a/nashorn/src/jdk/nashorn/internal/codegen/Splitter.java +++ b/nashorn/src/jdk/nashorn/internal/codegen/Splitter.java @@ -31,7 +31,6 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; - import jdk.nashorn.internal.ir.Block; import jdk.nashorn.internal.ir.FunctionNode; import jdk.nashorn.internal.ir.FunctionNode.CompilationState; @@ -221,14 +220,13 @@ final class Splitter extends NodeVisitor { * @return New split node. */ private SplitNode createBlockSplitNode(final Block parent, final FunctionNode function, final List statements, final long weight) { - final int lineNumber = parent.getLineNumber(); final long token = parent.getToken(); final int finish = parent.getFinish(); final String name = function.uniqueName(SPLIT_PREFIX.symbolName()); - final Block newBlock = new Block(lineNumber, token, finish, statements); + final Block newBlock = new Block(token, finish, statements); - return new SplitNode(lineNumber, name, newBlock, compiler.findUnit(weight + WeighNodes.FUNCTION_WEIGHT)); + return new SplitNode(name, newBlock, compiler.findUnit(weight + WeighNodes.FUNCTION_WEIGHT)); } @Override diff --git a/nashorn/src/jdk/nashorn/internal/codegen/WeighNodes.java b/nashorn/src/jdk/nashorn/internal/codegen/WeighNodes.java index 1adef12bb3c..57b3bafa797 100644 --- a/nashorn/src/jdk/nashorn/internal/codegen/WeighNodes.java +++ b/nashorn/src/jdk/nashorn/internal/codegen/WeighNodes.java @@ -27,7 +27,6 @@ package jdk.nashorn.internal.codegen; import java.util.List; import java.util.Map; - import jdk.nashorn.internal.codegen.types.Type; import jdk.nashorn.internal.ir.AccessNode; import jdk.nashorn.internal.ir.BinaryNode; @@ -36,7 +35,7 @@ import jdk.nashorn.internal.ir.BreakNode; import jdk.nashorn.internal.ir.CallNode; import jdk.nashorn.internal.ir.CatchNode; import jdk.nashorn.internal.ir.ContinueNode; -import jdk.nashorn.internal.ir.ExecuteNode; +import jdk.nashorn.internal.ir.ExpressionStatement; import jdk.nashorn.internal.ir.ForNode; import jdk.nashorn.internal.ir.FunctionNode; import jdk.nashorn.internal.ir.IdentNode; @@ -158,8 +157,8 @@ final class WeighNodes extends NodeOperatorVisitor { } @Override - public Node leaveExecuteNode(final ExecuteNode executeNode) { - return executeNode; + public Node leaveExpressionStatement(final ExpressionStatement expressionStatement) { + return expressionStatement; } @Override diff --git a/nashorn/src/jdk/nashorn/internal/ir/AccessNode.java b/nashorn/src/jdk/nashorn/internal/ir/AccessNode.java index eecc5713541..55b0aa3feb3 100644 --- a/nashorn/src/jdk/nashorn/internal/ir/AccessNode.java +++ b/nashorn/src/jdk/nashorn/internal/ir/AccessNode.java @@ -45,12 +45,12 @@ public final class AccessNode extends BaseNode { * @param base base node * @param property property */ - public AccessNode(final long token, final int finish, final Node base, final IdentNode property) { + public AccessNode(final long token, final int finish, final Expression base, final IdentNode property) { super(token, finish, base, false, false); this.property = property.setIsPropertyName(); } - private AccessNode(final AccessNode accessNode, final Node base, final IdentNode property, final boolean isFunction, final boolean hasCallSiteType) { + private AccessNode(final AccessNode accessNode, final Expression base, final IdentNode property, final boolean isFunction, final boolean hasCallSiteType) { super(accessNode, base, isFunction, hasCallSiteType); this.property = property; } @@ -63,7 +63,7 @@ public final class AccessNode extends BaseNode { public Node accept(final NodeVisitor visitor) { if (visitor.enterAccessNode(this)) { return visitor.leaveAccessNode( - setBase(base.accept(visitor)). + setBase((Expression)base.accept(visitor)). setProperty((IdentNode)property.accept(visitor))); } return this; @@ -103,7 +103,7 @@ public final class AccessNode extends BaseNode { return property; } - private AccessNode setBase(final Node base) { + private AccessNode setBase(final Expression base) { if (this.base == base) { return this; } diff --git a/nashorn/src/jdk/nashorn/internal/ir/Assignment.java b/nashorn/src/jdk/nashorn/internal/ir/Assignment.java index 0c531bc2906..093b0d80a7d 100644 --- a/nashorn/src/jdk/nashorn/internal/ir/Assignment.java +++ b/nashorn/src/jdk/nashorn/internal/ir/Assignment.java @@ -31,7 +31,7 @@ package jdk.nashorn.internal.ir; * * @param the destination type */ -public interface Assignment { +public interface Assignment { /** * Get assignment destination @@ -45,7 +45,7 @@ public interface Assignment { * * @return get the assignment source node */ - public Node getAssignmentSource(); + public Expression getAssignmentSource(); /** * Set assignment destination node. diff --git a/nashorn/src/jdk/nashorn/internal/ir/BaseNode.java b/nashorn/src/jdk/nashorn/internal/ir/BaseNode.java index a1b7c0eed7d..f945ef35711 100644 --- a/nashorn/src/jdk/nashorn/internal/ir/BaseNode.java +++ b/nashorn/src/jdk/nashorn/internal/ir/BaseNode.java @@ -26,6 +26,7 @@ package jdk.nashorn.internal.ir; import static jdk.nashorn.internal.codegen.ObjectClassGenerator.DEBUG_FIELDS; + import jdk.nashorn.internal.codegen.ObjectClassGenerator; import jdk.nashorn.internal.codegen.types.Type; import jdk.nashorn.internal.ir.annotations.Immutable; @@ -37,10 +38,10 @@ import jdk.nashorn.internal.ir.annotations.Immutable; * @see IndexNode */ @Immutable -public abstract class BaseNode extends Node implements FunctionCall, TypeOverride { +public abstract class BaseNode extends Expression implements FunctionCall, TypeOverride { /** Base Node. */ - protected final Node base; + protected final Expression base; private final boolean isFunction; @@ -55,7 +56,7 @@ public abstract class BaseNode extends Node implements FunctionCall, TypeOverrid * @param isFunction is this a function * @param hasCallSiteType does this access have a callsite type */ - public BaseNode(final long token, final int finish, final Node base, final boolean isFunction, final boolean hasCallSiteType) { + public BaseNode(final long token, final int finish, final Expression base, final boolean isFunction, final boolean hasCallSiteType) { super(token, base.getStart(), finish); this.base = base; this.isFunction = isFunction; @@ -69,7 +70,7 @@ public abstract class BaseNode extends Node implements FunctionCall, TypeOverrid * @param isFunction is this a function * @param hasCallSiteType does this access have a callsite type */ - protected BaseNode(final BaseNode baseNode, final Node base, final boolean isFunction, final boolean hasCallSiteType) { + protected BaseNode(final BaseNode baseNode, final Expression base, final boolean isFunction, final boolean hasCallSiteType) { super(baseNode); this.base = base; this.isFunction = isFunction; @@ -80,7 +81,7 @@ public abstract class BaseNode extends Node implements FunctionCall, TypeOverrid * Get the base node for this access * @return the base node */ - public Node getBase() { + public Expression getBase() { return base; } diff --git a/nashorn/src/jdk/nashorn/internal/ir/BinaryNode.java b/nashorn/src/jdk/nashorn/internal/ir/BinaryNode.java index 4afa1945eae..1576fb9316e 100644 --- a/nashorn/src/jdk/nashorn/internal/ir/BinaryNode.java +++ b/nashorn/src/jdk/nashorn/internal/ir/BinaryNode.java @@ -34,11 +34,11 @@ import jdk.nashorn.internal.parser.TokenType; * BinaryNode nodes represent two operand operations. */ @Immutable -public final class BinaryNode extends Node implements Assignment { +public final class BinaryNode extends Expression implements Assignment { /** Left hand side argument. */ - private final Node lhs; + private final Expression lhs; - private final Node rhs; + private final Expression rhs; /** * Constructor @@ -47,13 +47,13 @@ public final class BinaryNode extends Node implements Assignment { * @param lhs left hand side * @param rhs right hand side */ - public BinaryNode(final long token, final Node lhs, final Node rhs) { + public BinaryNode(final long token, final Expression lhs, final Expression rhs) { super(token, lhs.getStart(), rhs.getFinish()); this.lhs = lhs; this.rhs = rhs; } - private BinaryNode(final BinaryNode binaryNode, final Node lhs, final Node rhs) { + private BinaryNode(final BinaryNode binaryNode, final Expression lhs, final Expression rhs) { super(binaryNode); this.lhs = lhs; this.rhs = rhs; @@ -141,17 +141,17 @@ public final class BinaryNode extends Node implements Assignment { } @Override - public Node getAssignmentDest() { + public Expression getAssignmentDest() { return isAssignment() ? lhs() : null; } @Override - public Node setAssignmentDest(Node n) { + public BinaryNode setAssignmentDest(Expression n) { return setLHS(n); } @Override - public Node getAssignmentSource() { + public Expression getAssignmentSource() { return rhs(); } @@ -162,7 +162,7 @@ public final class BinaryNode extends Node implements Assignment { @Override public Node accept(final NodeVisitor visitor) { if (visitor.enterBinaryNode(this)) { - return visitor.leaveBinaryNode(setLHS(lhs.accept(visitor)).setRHS(rhs.accept(visitor))); + return visitor.leaveBinaryNode(setLHS((Expression)lhs.accept(visitor)).setRHS((Expression)rhs.accept(visitor))); } return this; @@ -218,7 +218,7 @@ public final class BinaryNode extends Node implements Assignment { * Get the left hand side expression for this node * @return the left hand side expression */ - public Node lhs() { + public Expression lhs() { return lhs; } @@ -226,7 +226,7 @@ public final class BinaryNode extends Node implements Assignment { * Get the right hand side expression for this node * @return the left hand side expression */ - public Node rhs() { + public Expression rhs() { return rhs; } @@ -235,7 +235,7 @@ public final class BinaryNode extends Node implements Assignment { * @param lhs new left hand side expression * @return a node equivalent to this one except for the requested change. */ - public BinaryNode setLHS(final Node lhs) { + public BinaryNode setLHS(final Expression lhs) { if (this.lhs == lhs) { return this; } @@ -247,7 +247,7 @@ public final class BinaryNode extends Node implements Assignment { * @param rhs new left hand side expression * @return a node equivalent to this one except for the requested change. */ - public BinaryNode setRHS(final Node rhs) { + public BinaryNode setRHS(final Expression rhs) { if (this.rhs == rhs) { return this; } diff --git a/nashorn/src/jdk/nashorn/internal/ir/Block.java b/nashorn/src/jdk/nashorn/internal/ir/Block.java index 71692144167..c411401e710 100644 --- a/nashorn/src/jdk/nashorn/internal/ir/Block.java +++ b/nashorn/src/jdk/nashorn/internal/ir/Block.java @@ -38,11 +38,10 @@ import jdk.nashorn.internal.ir.annotations.Immutable; import jdk.nashorn.internal.ir.visitor.NodeVisitor; /** - * IR representation for a list of statements and functions. All provides the - * basis for script body. + * IR representation for a list of statements. */ @Immutable -public class Block extends BreakableNode implements Flags { +public class Block extends Node implements BreakableNode, Flags { /** List of statements */ protected final List statements; @@ -52,6 +51,9 @@ public class Block extends BreakableNode implements Flags { /** Entry label. */ protected final Label entryLabel; + /** Break label. */ + private final Label breakLabel; + /** Does the block/function need a new scope? */ protected final int flags; @@ -76,17 +78,17 @@ public class Block extends BreakableNode implements Flags { /** * Constructor * - * @param lineNumber line number * @param token token * @param finish finish * @param statements statements */ - public Block(final int lineNumber, final long token, final int finish, final Statement... statements) { - super(lineNumber, token, finish, new Label("block_break")); + public Block(final long token, final int finish, final Statement... statements) { + super(token, finish); this.statements = Arrays.asList(statements); this.symbols = new LinkedHashMap<>(); this.entryLabel = new Label("block_entry"); + this.breakLabel = new Label("block_break"); this.flags = 0; } @@ -98,8 +100,8 @@ public class Block extends BreakableNode implements Flags { * @param finish finish * @param statements statements */ - public Block(final int lineNumber, final long token, final int finish, final List statements) { - this(lineNumber, token, finish, statements.toArray(new Statement[statements.size()])); + public Block(final long token, final int finish, final List statements) { + this(token, finish, statements.toArray(new Statement[statements.size()])); } private Block(final Block block, final int finish, final List statements, final int flags, final Map symbols) { @@ -108,6 +110,7 @@ public class Block extends BreakableNode implements Flags { this.flags = flags; this.symbols = new LinkedHashMap<>(symbols); //todo - symbols have no dependencies on any IR node and can as far as we understand it be shallow copied now this.entryLabel = new Label(block.entryLabel); + this.breakLabel = new Label(block.breakLabel); this.finish = finish; } @@ -223,6 +226,11 @@ public class Block extends BreakableNode implements Flags { return entryLabel; } + @Override + public Label getBreakLabel() { + return breakLabel; + } + /** * Get the list of statements in this block * @@ -322,7 +330,17 @@ public class Block extends BreakableNode implements Flags { } @Override - protected boolean isBreakableWithoutLabel() { + public boolean isBreakableWithoutLabel() { return false; } + + @Override + public List