# HG changeset patch # User kizune # Date 1386065595 -14400 # Node ID c1049f63d4f568a8ba96a5d511c01e8df268ad85 # Parent b9fdc55a6e2869424bbbb4c04f23e1a977b1400d# Parent b55a011cf8aef27e6ada94a6e0b5232a2a1701b5 Merge diff -r b9fdc55a6e28 -r c1049f63d4f5 .hgtags --- a/.hgtags Sun Nov 03 07:33:34 2013 +0000 +++ b/.hgtags Tue Dec 03 14:13:15 2013 +0400 @@ -224,3 +224,7 @@ 6a4fdb3bb4e34af4c5bb8db467bb01e13b1a7e31 jdk8-b112 676cd7bf5e092356f7ee2116c8cf88cdc12377c7 jdk8-b113 79f7b79bf97b71c9b5c9b103dbdef5f269eeb86d jdk8-b114 +f0d3ac2474ee755b1180ec71bcdfa190845b17eb jdk8-b115 +0fb1a427fbf6e04c77cebbbf99b6631c664ed793 jdk8-b116 +1db3d4e4d18913e853d7bebf86816e87fda00a71 jdk8-b117 +8d014b039b44c23fa520ce20c2c27f7aa91441e9 jdk8-b118 diff -r b9fdc55a6e28 -r c1049f63d4f5 make/build.xml --- a/make/build.xml Sun Nov 03 07:33:34 2013 +0000 +++ b/make/build.xml Tue Dec 03 14:13:15 2013 +0400 @@ -372,6 +372,12 @@ + + + + + + @@ -380,6 +386,7 @@ + diff -r b9fdc55a6e28 -r c1049f63d4f5 make/project.properties --- a/make/project.properties Sun Nov 03 07:33:34 2013 +0000 +++ b/make/project.properties Tue Dec 03 14:13:15 2013 +0400 @@ -230,7 +230,7 @@ ${file.reference.jemmyawtinput.jar}${path.separator}\ ${file.reference.testng.jar}${path.separator}\ ${nashorn.internal.tests.jar}${path.separator}\ - ${nashorn.api.tests.jar} + ${nashorn.api.tests.jar} # testjfx VM options for script tests with @fork option testjfx-test-sys-prop.test.fork.jvm.options=${run.test.jvmargs.main} -Xmx${run.test.xmx} -cp ${testjfx.run.test.classpath} diff -r b9fdc55a6e28 -r c1049f63d4f5 src/jdk/nashorn/api/scripting/ScriptObjectMirror.java --- a/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java Sun Nov 03 07:33:34 2013 +0000 +++ b/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java Tue Dec 03 14:13:15 2013 +0400 @@ -41,6 +41,7 @@ import java.util.Set; import java.util.concurrent.Callable; import javax.script.Bindings; +import jdk.nashorn.internal.runtime.ConsString; import jdk.nashorn.internal.runtime.Context; import jdk.nashorn.internal.runtime.GlobalObject; import jdk.nashorn.internal.runtime.JSType; @@ -594,14 +595,35 @@ } /** - * Make a script object mirror on given object if needed. + * Utilitity to convert this script object to the given type. * - * @param obj object to be wrapped - * @param homeGlobal global to which this object belongs - * @return wrapped object + * @param type destination type to convert to + * @return converted object */ - public static Object wrap(final Object obj, final ScriptObject homeGlobal) { - return (obj instanceof ScriptObject && homeGlobal != null) ? new ScriptObjectMirror((ScriptObject)obj, homeGlobal) : obj; + public T to(final Class type) { + return inGlobal(new Callable() { + @Override + public T call() { + return type.cast(ScriptUtils.convert(sobj, type)); + } + }); + } + + /** + * Make a script object mirror on given object if needed. Also converts ConsString instances to Strings. + * + * @param obj object to be wrapped/converted + * @param homeGlobal global to which this object belongs. Not used for ConsStrings. + * @return wrapped/converted object + */ + public static Object wrap(final Object obj, final Object homeGlobal) { + if(obj instanceof ScriptObject) { + return homeGlobal instanceof ScriptObject ? new ScriptObjectMirror((ScriptObject)obj, (ScriptObject)homeGlobal) : obj; + } + if(obj instanceof ConsString) { + return obj.toString(); + } + return obj; } /** @@ -611,7 +633,7 @@ * @param homeGlobal global to which this object belongs * @return unwrapped object */ - public static Object unwrap(final Object obj, final ScriptObject homeGlobal) { + public static Object unwrap(final Object obj, final Object homeGlobal) { if (obj instanceof ScriptObjectMirror) { final ScriptObjectMirror mirror = (ScriptObjectMirror)obj; return (mirror.global == homeGlobal)? mirror.sobj : obj; @@ -627,7 +649,7 @@ * @param homeGlobal global to which this object belongs * @return wrapped array */ - public static Object[] wrapArray(final Object[] args, final ScriptObject homeGlobal) { + public static Object[] wrapArray(final Object[] args, final Object homeGlobal) { if (args == null || args.length == 0) { return args; } @@ -648,7 +670,7 @@ * @param homeGlobal global to which this object belongs * @return unwrapped array */ - public static Object[] unwrapArray(final Object[] args, final ScriptObject homeGlobal) { + public static Object[] unwrapArray(final Object[] args, final Object homeGlobal) { if (args == null || args.length == 0) { return args; } diff -r b9fdc55a6e28 -r c1049f63d4f5 src/jdk/nashorn/api/scripting/ScriptUtils.java --- a/src/jdk/nashorn/api/scripting/ScriptUtils.java Sun Nov 03 07:33:34 2013 +0000 +++ b/src/jdk/nashorn/api/scripting/ScriptUtils.java Tue Dec 03 14:13:15 2013 +0400 @@ -25,11 +25,17 @@ package jdk.nashorn.api.scripting; +import java.lang.invoke.MethodHandle; +import jdk.internal.dynalink.beans.StaticClass; +import jdk.internal.dynalink.linker.LinkerServices; +import jdk.nashorn.internal.runtime.linker.Bootstrap; +import jdk.nashorn.internal.runtime.Context; import jdk.nashorn.internal.runtime.ScriptFunction; +import jdk.nashorn.internal.runtime.ScriptObject; import jdk.nashorn.internal.runtime.ScriptRuntime; /** - * Utilities that are to be called from script code + * Utilities that are to be called from script code. */ public final class ScriptUtils { private ScriptUtils() {} @@ -71,4 +77,96 @@ return func.makeSynchronizedFunction(sync); } + /** + * Make a script object mirror on given object if needed. + * + * @param obj object to be wrapped + * @return wrapped object + */ + public static Object wrap(final Object obj) { + if (obj instanceof ScriptObject) { + return ScriptObjectMirror.wrap(obj, Context.getGlobal()); + } + + return obj; + } + + /** + * Unwrap a script object mirror if needed. + * + * @param obj object to be unwrapped + * @return unwrapped object + */ + public static Object unwrap(final Object obj) { + if (obj instanceof ScriptObjectMirror) { + return ScriptObjectMirror.unwrap(obj, Context.getGlobal()); + } + + return obj; + } + + /** + * Wrap an array of object to script object mirrors if needed. + * + * @param args array to be unwrapped + * @return wrapped array + */ + public static Object[] wrapArray(final Object[] args) { + if (args == null || args.length == 0) { + return args; + } + + return ScriptObjectMirror.wrapArray(args, Context.getGlobal()); + } + + /** + * Unwrap an array of script object mirrors if needed. + * + * @param args array to be unwrapped + * @return unwrapped array + */ + public static Object[] unwrapArray(final Object[] args) { + if (args == null || args.length == 0) { + return args; + } + + return ScriptObjectMirror.unwrapArray(args, Context.getGlobal()); + } + + /** + * Convert the given object to the given type. + * + * @param obj object to be converted + * @param type destination type to convert to + * @return converted object + */ + public static Object convert(final Object obj, final Object type) { + if (obj == null) { + return null; + } + + final Class clazz; + if (type instanceof Class) { + clazz = (Class)type; + } else if (type instanceof StaticClass) { + clazz = ((StaticClass)type).getRepresentedClass(); + } else { + throw new IllegalArgumentException("type expected"); + } + + final LinkerServices linker = Bootstrap.getLinkerServices(); + final MethodHandle converter = linker.getTypeConverter(obj.getClass(), clazz); + if (converter == null) { + // no supported conversion! + throw new UnsupportedOperationException("conversion not supported"); + } + + try { + return converter.invoke(obj); + } catch (final RuntimeException | Error e) { + throw e; + } catch (final Throwable t) { + throw new RuntimeException(t); + } + } } diff -r b9fdc55a6e28 -r c1049f63d4f5 src/jdk/nashorn/internal/codegen/Attr.java --- a/src/jdk/nashorn/internal/codegen/Attr.java Sun Nov 03 07:33:34 2013 +0000 +++ b/src/jdk/nashorn/internal/codegen/Attr.java Tue Dec 03 14:13:15 2013 +0400 @@ -271,6 +271,7 @@ functionNode.addDeclaredSymbol(symbol); if (varNode.isFunctionDeclaration()) { newType(symbol, FunctionNode.FUNCTION_TYPE); + symbol.setIsFunctionDeclaration(); } return varNode.setName((IdentNode)ident.setSymbol(lc, symbol)); } @@ -1264,12 +1265,17 @@ @Override public Node leaveCOMMARIGHT(final BinaryNode binaryNode) { - return end(ensureSymbol(binaryNode.rhs().getType(), binaryNode)); + return leaveComma(binaryNode, binaryNode.rhs()); } @Override public Node leaveCOMMALEFT(final BinaryNode binaryNode) { - return end(ensureSymbol(binaryNode.lhs().getType(), binaryNode)); + return leaveComma(binaryNode, binaryNode.lhs()); + } + + private Node leaveComma(final BinaryNode commaNode, final Expression effectiveExpr) { + ensureTypeNotUnknown(effectiveExpr); + return end(ensureSymbol(effectiveExpr.getType(), commaNode)); } @Override diff -r b9fdc55a6e28 -r c1049f63d4f5 src/jdk/nashorn/internal/codegen/CodeGenerator.java --- a/src/jdk/nashorn/internal/codegen/CodeGenerator.java Sun Nov 03 07:33:34 2013 +0000 +++ b/src/jdk/nashorn/internal/codegen/CodeGenerator.java Tue Dec 03 14:13:15 2013 +0400 @@ -359,8 +359,11 @@ return load(node, node.hasType() ? node.getType() : null, false); } - private static boolean safeLiteral(final Expression rhs) { - return rhs instanceof LiteralNode && !(rhs instanceof ArrayLiteralNode); + // Test whether conversion from source to target involves a call of ES 9.1 ToPrimitive + // with possible side effects from calling an object's toString or valueOf methods. + private boolean noToPrimitiveConversion(final Type source, final Type target) { + // Object to boolean conversion does not cause ToPrimitive call + return source.isJSPrimitive() || !target.isJSPrimitive() || target.isBoolean(); } MethodEmitter loadBinaryOperands(final Expression lhs, final Expression rhs, final Type type) { @@ -374,25 +377,19 @@ // can combine a LOAD with a CONVERT operation (e.g. use a dynamic getter with the conversion target type as its // return value). What we do here is reorder LOAD RIGHT and CONVERT LEFT when possible; it is possible only when // we can prove that executing CONVERT LEFT can't have a side effect that changes the value of LOAD RIGHT. - // Basically, if we know that either LEFT is not an object, or RIGHT is a constant literal, then we can do the + // Basically, if we know that either LEFT already is a primitive value, or does not have to be converted to + // a primitive value, or RIGHT is an expression that loads without side effects, then we can do the // reordering and collapse LOAD/CONVERT into a single operation; otherwise we need to do the more costly // separate operations to preserve specification semantics. - final Type lhsType = lhs.getType(); - if (lhsType.isObject() && !safeLiteral(rhs)) { - // Can't reorder. Load and convert separately. - load(lhs, lhsType, baseAlreadyOnStack); - load(rhs, rhs.getType(), false); - // Avoid empty SWAP, SWAP bytecode sequence if CONVERT LEFT is a no-op - if (!lhsType.isEquivalentTo(type)) { - method.swap(); - method.convert(type); - method.swap(); - } - method.convert(type); - } else { + if (noToPrimitiveConversion(lhs.getType(), type) || rhs.isLocal()) { // Can reorder. Combine load and convert into single operations. load(lhs, type, baseAlreadyOnStack); load(rhs, type, false); + } else { + // Can't reorder. Load and convert separately. + load(lhs, lhs.getType(), baseAlreadyOnStack); + load(rhs, rhs.getType(), false); + method.swap().convert(type).swap().convert(type); } return method; @@ -415,6 +412,8 @@ return method; } + assert !type.isUnknown(); + /* * The load may be of type IdentNode, e.g. "x", AccessNode, e.g. "x.y" * or IndexNode e.g. "x[y]". Both AccessNodes and IndexNodes are @@ -709,6 +708,12 @@ final CallNode.EvalArgs evalArgs = callNode.getEvalArgs(); // load evaluated code load(evalArgs.getCode(), Type.OBJECT); + // load second and subsequent args for side-effect + final List args = callNode.getArgs(); + final int numArgs = args.size(); + for (int i = 1; i < numArgs; i++) { + load(args.get(i)).pop(); + } // special/extra 'eval' arguments load(evalArgs.getThis()); method.load(evalArgs.getLocation()); diff -r b9fdc55a6e28 -r c1049f63d4f5 src/jdk/nashorn/internal/codegen/MapCreator.java --- a/src/jdk/nashorn/internal/codegen/MapCreator.java Sun Nov 03 07:33:34 2013 +0000 +++ b/src/jdk/nashorn/internal/codegen/MapCreator.java Tue Dec 03 14:13:15 2013 +0400 @@ -134,6 +134,10 @@ flags |= Property.CAN_BE_UNDEFINED; } + if (symbol.isFunctionDeclaration()) { + flags |= Property.IS_FUNCTION_DECLARATION; + } + return flags; } diff -r b9fdc55a6e28 -r c1049f63d4f5 src/jdk/nashorn/internal/codegen/types/Type.java --- a/src/jdk/nashorn/internal/codegen/types/Type.java Sun Nov 03 07:33:34 2013 +0000 +++ b/src/jdk/nashorn/internal/codegen/types/Type.java Tue Dec 03 14:13:15 2013 +0400 @@ -292,6 +292,16 @@ } /** + * Determines whether this type represents an primitive type according to the ECMAScript specification, + * which includes Boolean, Number, and String. + * + * @return true if a JavaScript primitive type, false otherwise. + */ + public boolean isJSPrimitive() { + return !isObject() || isString(); + } + + /** * Determines whether a type is the BOOLEAN type * @return true if BOOLEAN, false otherwise */ @@ -443,7 +453,7 @@ } else if (type0.isArray() != type1.isArray()) { //array and non array is always object, widest(Object[], int) NEVER returns Object[], which has most weight. that does not make sense return Type.OBJECT; - } else if (type0.isObject() && type1.isObject() && ((ObjectType)type0).getTypeClass() != ((ObjectType)type1).getTypeClass()) { + } else if (type0.isObject() && type1.isObject() && type0.getTypeClass() != type1.getTypeClass()) { // Object and Object will produce Object // TODO: maybe find most specific common superclass? return Type.OBJECT; diff -r b9fdc55a6e28 -r c1049f63d4f5 src/jdk/nashorn/internal/ir/BinaryNode.java --- a/src/jdk/nashorn/internal/ir/BinaryNode.java Sun Nov 03 07:33:34 2013 +0000 +++ b/src/jdk/nashorn/internal/ir/BinaryNode.java Tue Dec 03 14:13:15 2013 +0400 @@ -90,6 +90,9 @@ return Type.LONG; case ASSIGN_SAR: case ASSIGN_SHL: + case BIT_AND: + case BIT_OR: + case BIT_XOR: case ASSIGN_BIT_AND: case ASSIGN_BIT_OR: case ASSIGN_BIT_XOR: @@ -170,6 +173,42 @@ } @Override + public boolean isLocal() { + switch (tokenType()) { + case SAR: + case SHL: + case SHR: + case BIT_AND: + case BIT_OR: + case BIT_XOR: + case ADD: + case DIV: + case MOD: + case MUL: + case SUB: + return lhs.isLocal() && lhs.getType().isJSPrimitive() + && rhs.isLocal() && rhs.getType().isJSPrimitive(); + case ASSIGN_ADD: + case ASSIGN_BIT_AND: + case ASSIGN_BIT_OR: + case ASSIGN_BIT_XOR: + case ASSIGN_DIV: + case ASSIGN_MOD: + case ASSIGN_MUL: + case ASSIGN_SAR: + case ASSIGN_SHL: + case ASSIGN_SHR: + case ASSIGN_SUB: + return lhs instanceof IdentNode && lhs.isLocal() && lhs.getType().isJSPrimitive() + && rhs.isLocal() && rhs.getType().isJSPrimitive(); + case ASSIGN: + return lhs instanceof IdentNode && lhs.isLocal() && rhs.isLocal(); + default: + return false; + } + } + + @Override public void toString(final StringBuilder sb) { final TokenType type = tokenType(); diff -r b9fdc55a6e28 -r c1049f63d4f5 src/jdk/nashorn/internal/ir/Expression.java --- a/src/jdk/nashorn/internal/ir/Expression.java Sun Nov 03 07:33:34 2013 +0000 +++ b/src/jdk/nashorn/internal/ir/Expression.java Tue Dec 03 14:13:15 2013 +0400 @@ -96,4 +96,16 @@ assert hasType() : this + " has no type"; return symbol.getSymbolType(); } + + /** + * Returns {@code true} if this expression depends exclusively on state that is constant + * or local to the currently running function and thus inaccessible to other functions. + * This implies that a local expression must not call any other functions (neither directly + * nor implicitly through a getter, setter, or object-to-primitive type conversion). + * + * @return true if this expression does not depend on state shared with other functions. + */ + public boolean isLocal() { + return false; + } } diff -r b9fdc55a6e28 -r c1049f63d4f5 src/jdk/nashorn/internal/ir/IdentNode.java --- a/src/jdk/nashorn/internal/ir/IdentNode.java Sun Nov 03 07:33:34 2013 +0000 +++ b/src/jdk/nashorn/internal/ir/IdentNode.java Tue Dec 03 14:13:15 2013 +0400 @@ -138,6 +138,11 @@ return getName(); } + @Override + public boolean isLocal() { + return !getSymbol().isScope(); + } + /** * Check if this IdentNode is a property name * @return true if this is a property name diff -r b9fdc55a6e28 -r c1049f63d4f5 src/jdk/nashorn/internal/ir/LiteralNode.java --- a/src/jdk/nashorn/internal/ir/LiteralNode.java Sun Nov 03 07:33:34 2013 +0000 +++ b/src/jdk/nashorn/internal/ir/LiteralNode.java Tue Dec 03 14:13:15 2013 +0400 @@ -275,6 +275,11 @@ public boolean isTrue() { return JSType.toBoolean(value); } + + @Override + public boolean isLocal() { + return true; + } } @Immutable diff -r b9fdc55a6e28 -r c1049f63d4f5 src/jdk/nashorn/internal/ir/Symbol.java --- a/src/jdk/nashorn/internal/ir/Symbol.java Sun Nov 03 07:33:34 2013 +0000 +++ b/src/jdk/nashorn/internal/ir/Symbol.java Tue Dec 03 14:13:15 2013 +0400 @@ -75,6 +75,8 @@ public static final int IS_SPECIALIZED_PARAM = 1 << 13; /** Is this symbol a shared temporary? */ public static final int IS_SHARED = 1 << 14; + /** Is this a function declaration? */ + public static final int IS_FUNCTION_DECLARATION = 1 << 15; /** Null or name identifying symbol. */ private final String name; @@ -360,6 +362,14 @@ } /** + * Check if this symbol is a function declaration + * @return true if a function declaration + */ + public boolean isFunctionDeclaration() { + return (flags & IS_FUNCTION_DECLARATION) == IS_FUNCTION_DECLARATION; + } + + /** * Creates an unshared copy of a symbol. The symbol must be currently shared. * @param newName the name for the new symbol. * @return a new, unshared symbol. @@ -396,6 +406,16 @@ /** + * Mark this symbol as a function declaration. + */ + public void setIsFunctionDeclaration() { + if (!isFunctionDeclaration()) { + trace("SET IS FUNCTION DECLARATION"); + flags |= IS_FUNCTION_DECLARATION; + } + } + + /** * Check if this symbol is a variable * @return true if variable */ diff -r b9fdc55a6e28 -r c1049f63d4f5 src/jdk/nashorn/internal/ir/TernaryNode.java --- a/src/jdk/nashorn/internal/ir/TernaryNode.java Sun Nov 03 07:33:34 2013 +0000 +++ b/src/jdk/nashorn/internal/ir/TernaryNode.java Tue Dec 03 14:13:15 2013 +0400 @@ -109,6 +109,13 @@ } } + @Override + public boolean isLocal() { + return getTest().isLocal() + && getTrueExpression().isLocal() + && getFalseExpression().isLocal(); + } + /** * Get the test expression for this ternary expression, i.e. "x" in x ? y : z * @return the test expression diff -r b9fdc55a6e28 -r c1049f63d4f5 src/jdk/nashorn/internal/ir/UnaryNode.java --- a/src/jdk/nashorn/internal/ir/UnaryNode.java Sun Nov 03 07:33:34 2013 +0000 +++ b/src/jdk/nashorn/internal/ir/UnaryNode.java Tue Dec 03 14:13:15 2013 +0400 @@ -129,6 +129,26 @@ } @Override + public boolean isLocal() { + switch (tokenType()) { + case NEW: + return false; + case ADD: + case SUB: + case NOT: + case BIT_NOT: + return rhs.isLocal() && rhs.getType().isJSPrimitive(); + case DECPOSTFIX: + case DECPREFIX: + case INCPOSTFIX: + case INCPREFIX: + return rhs instanceof IdentNode && rhs.isLocal() && rhs.getType().isJSPrimitive(); + default: + return rhs.isLocal(); + } + } + + @Override public void toString(final StringBuilder sb) { toString(sb, new Runnable() { @Override diff -r b9fdc55a6e28 -r c1049f63d4f5 src/jdk/nashorn/internal/ir/debug/ObjectSizeCalculator.java --- a/src/jdk/nashorn/internal/ir/debug/ObjectSizeCalculator.java Sun Nov 03 07:33:34 2013 +0000 +++ b/src/jdk/nashorn/internal/ir/debug/ObjectSizeCalculator.java Tue Dec 03 14:13:15 2013 +0400 @@ -25,10 +25,10 @@ package jdk.nashorn.internal.ir.debug; -import java.lang.management.ManagementFactory; -import java.lang.management.MemoryPoolMXBean; import java.lang.reflect.Array; import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.ArrayDeque; import java.util.ArrayList; @@ -51,9 +51,9 @@ * switch, it can not detect * this fact and will report incorrect sizes, as it will presume the default JVM * behavior. - * - * @author Attila Szegedi */ + +@SuppressWarnings("StaticNonFinalUsedInInitialization") public class ObjectSizeCalculator { /** @@ -368,6 +368,29 @@ type.getName()); } + // ALERT: java.lang.management is not available in compact 1. We need + // to use reflection to soft link test memory statistics. + + static Class managementFactory = null; + static Class memoryPoolMXBean = null; + static Class memoryUsage = null; + static Method getMemoryPoolMXBeans = null; + static Method getUsage = null; + static Method getMax = null; + static { + try { + managementFactory = Class.forName("java.lang.management.ManagementFactory"); + memoryPoolMXBean = Class.forName("java.lang.management.MemoryPoolMXBean"); + memoryUsage = Class.forName("java.lang.management.MemoryUsage"); + + getMemoryPoolMXBeans = managementFactory.getMethod("getMemoryPoolMXBeans"); + getUsage = memoryPoolMXBean.getMethod("getUsage"); + getMax = memoryUsage.getMethod("getMax"); + } catch (ClassNotFoundException | NoSuchMethodException | SecurityException ex) { + // Pass thru, asserts when attempting to use. + } + } + /** * Return the current memory usage * @return current memory usage derived from system configuration @@ -409,9 +432,33 @@ strVmVersion.indexOf('.'))); if (vmVersion >= 17) { long maxMemory = 0; - for (MemoryPoolMXBean mp : ManagementFactory.getMemoryPoolMXBeans()) { - maxMemory += mp.getUsage().getMax(); + + /* + See ALERT above. The reflection code below duplicates the following + sequence, and avoids hard coding of java.lang.management. + + for (MemoryPoolMXBean mp : ManagementFactory.getMemoryPoolMXBeans()) { + maxMemory += mp.getUsage().getMax(); + } + */ + + if (getMemoryPoolMXBeans == null) { + throw new AssertionError("java.lang.management not available in compact 1"); } + + try { + final List memoryPoolMXBeans = (List)getMemoryPoolMXBeans.invoke(managementFactory); + for (final Object mp : memoryPoolMXBeans) { + final Object usage = getUsage.invoke(mp); + final Object max = getMax.invoke(usage); + maxMemory += ((Long)max).longValue(); + } + } catch (IllegalAccessException | + IllegalArgumentException | + InvocationTargetException ex) { + throw new AssertionError("java.lang.management not available in compact 1"); + } + if (maxMemory < 30L * 1024 * 1024 * 1024) { // HotSpot 17.0 and above use compressed OOPs below 30GB of RAM total // for all memory pools (yes, including code cache). diff -r b9fdc55a6e28 -r c1049f63d4f5 src/jdk/nashorn/internal/objects/Global.java --- a/src/jdk/nashorn/internal/objects/Global.java Sun Nov 03 07:33:34 2013 +0000 +++ b/src/jdk/nashorn/internal/objects/Global.java Tue Dec 03 14:13:15 2013 +0400 @@ -53,19 +53,19 @@ import jdk.nashorn.internal.runtime.GlobalObject; import jdk.nashorn.internal.runtime.JSType; import jdk.nashorn.internal.runtime.NativeJavaPackage; +import jdk.nashorn.internal.runtime.PropertyDescriptor; import jdk.nashorn.internal.runtime.PropertyMap; +import jdk.nashorn.internal.runtime.Scope; import jdk.nashorn.internal.runtime.ScriptEnvironment; -import jdk.nashorn.internal.runtime.PropertyDescriptor; -import jdk.nashorn.internal.runtime.arrays.ArrayData; -import jdk.nashorn.internal.runtime.regexp.RegExpResult; -import jdk.nashorn.internal.runtime.Scope; import jdk.nashorn.internal.runtime.ScriptFunction; import jdk.nashorn.internal.runtime.ScriptObject; import jdk.nashorn.internal.runtime.ScriptRuntime; import jdk.nashorn.internal.runtime.ScriptingFunctions; import jdk.nashorn.internal.runtime.Source; +import jdk.nashorn.internal.runtime.arrays.ArrayData; import jdk.nashorn.internal.runtime.linker.Bootstrap; import jdk.nashorn.internal.runtime.linker.InvokeByName; +import jdk.nashorn.internal.runtime.regexp.RegExpResult; import jdk.nashorn.internal.scripts.JO; /** diff -r b9fdc55a6e28 -r c1049f63d4f5 src/jdk/nashorn/internal/objects/NativeObject.java --- a/src/jdk/nashorn/internal/objects/NativeObject.java Sun Nov 03 07:33:34 2013 +0000 +++ b/src/jdk/nashorn/internal/objects/NativeObject.java Tue Dec 03 14:13:15 2013 +0400 @@ -60,6 +60,7 @@ import jdk.nashorn.internal.runtime.ScriptRuntime; import jdk.nashorn.internal.runtime.linker.Bootstrap; import jdk.nashorn.internal.runtime.linker.InvokeByName; +import jdk.nashorn.internal.runtime.linker.NashornBeansLinker; /** * ECMA 15.2 Object objects @@ -729,8 +730,7 @@ final MethodType methodType, final Object source) { final GuardedInvocation inv; try { - inv = linker.getGuardedInvocation(createLinkRequest(operation, methodType, source), - Bootstrap.getLinkerServices()); + inv = NashornBeansLinker.getGuardedInvocation(linker, createLinkRequest(operation, methodType, source), Bootstrap.getLinkerServices()); assert passesGuard(source, inv.getGuard()); } catch(RuntimeException|Error e) { throw e; diff -r b9fdc55a6e28 -r c1049f63d4f5 src/jdk/nashorn/internal/runtime/CompiledFunctions.java --- a/src/jdk/nashorn/internal/runtime/CompiledFunctions.java Sun Nov 03 07:33:34 2013 +0000 +++ b/src/jdk/nashorn/internal/runtime/CompiledFunctions.java Tue Dec 03 14:13:15 2013 +0400 @@ -24,6 +24,7 @@ */ package jdk.nashorn.internal.runtime; +import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodType; import java.util.Iterator; import java.util.TreeSet; @@ -35,6 +36,8 @@ @SuppressWarnings("serial") final class CompiledFunctions extends TreeSet { + private CompiledFunction generic; + CompiledFunction best(final MethodType type) { final Iterator iter = iterator(); while (iter.hasNext()) { @@ -43,13 +46,10 @@ return next; } } - return mostGeneric(); + return generic(); } boolean needsCallee() { - for (final CompiledFunction inv : this) { - assert ScriptFunctionData.needsCallee(inv.getInvoker()) == ScriptFunctionData.needsCallee(mostGeneric().getInvoker()); - } return ScriptFunctionData.needsCallee(mostGeneric().getInvoker()); } @@ -57,6 +57,48 @@ return last(); } + CompiledFunction generic() { + CompiledFunction gen = this.generic; + if (gen == null) { + gen = this.generic = makeGeneric(mostGeneric()); + } + return gen; + } + + private static CompiledFunction makeGeneric(final CompiledFunction func) { + final MethodHandle invoker = composeGenericMethod(func.getInvoker()); + final MethodHandle constructor = func.hasConstructor() ? composeGenericMethod(func.getConstructor()) : null; + return new CompiledFunction(invoker.type(), invoker, constructor); + } + + /** + * Takes a method handle, and returns a potentially different method handle that can be used in + * {@code ScriptFunction#invoke(Object, Object...)} or {code ScriptFunction#construct(Object, Object...)}. + * The returned method handle will be sure to return {@code Object}, and will have all its parameters turned into + * {@code Object} as well, except for the following ones: + *
    + *
  • a last parameter of type {@code Object[]} which is used for vararg functions,
  • + *
  • the first argument, which is forced to be {@link ScriptFunction}, in case the function receives itself + * (callee) as an argument.
  • + *
+ * + * @param mh the original method handle + * + * @return the new handle, conforming to the rules above. + */ + private static MethodHandle composeGenericMethod(final MethodHandle mh) { + final MethodType type = mh.type(); + final boolean isVarArg = ScriptFunctionData.isVarArg(mh); + final int paramCount = isVarArg ? type.parameterCount() - 1 : type.parameterCount(); + + MethodType newType = MethodType.genericMethodType(paramCount, isVarArg); + + if (ScriptFunctionData.needsCallee(mh)) { + newType = newType.changeParameterType(0, ScriptFunction.class); + } + return type.equals(newType) ? mh : mh.asType(newType); + } + /** * Is the given type even more specific than this entire list? That means * we have an opportunity for more specific versions of the method diff -r b9fdc55a6e28 -r c1049f63d4f5 src/jdk/nashorn/internal/runtime/ConsString.java --- a/src/jdk/nashorn/internal/runtime/ConsString.java Sun Nov 03 07:33:34 2013 +0000 +++ b/src/jdk/nashorn/internal/runtime/ConsString.java Tue Dec 03 14:13:15 2013 +0400 @@ -57,10 +57,7 @@ @Override public String toString() { - if (!flat) { - flatten(); - } - return (String) left; + return (String) flattened(); } @Override @@ -70,18 +67,19 @@ @Override public char charAt(final int index) { - if (!flat) { - flatten(); - } - return left.charAt(index); + return flattened().charAt(index); } @Override public CharSequence subSequence(final int start, final int end) { + return flattened().subSequence(start, end); + } + + private CharSequence flattened() { if (!flat) { flatten(); } - return left.subSequence(start, end); + return left; } private void flatten() { diff -r b9fdc55a6e28 -r c1049f63d4f5 src/jdk/nashorn/internal/runtime/FinalScriptFunctionData.java --- a/src/jdk/nashorn/internal/runtime/FinalScriptFunctionData.java Sun Nov 03 07:33:34 2013 +0000 +++ b/src/jdk/nashorn/internal/runtime/FinalScriptFunctionData.java Tue Dec 03 14:13:15 2013 +0400 @@ -40,7 +40,7 @@ * * @param name name * @param arity arity - * @param list precompiled code + * @param functions precompiled code * @param isStrict strict * @param isBuiltin builtin * @param isConstructor constructor @@ -73,12 +73,13 @@ } private void addInvoker(final MethodHandle mh) { - boolean needsCallee = needsCallee(mh); if (isConstructor(mh)) { - //only nasgen constructors: (boolean, self, args) are subject to binding a boolean newObj. isConstructor - //is too conservative a check. However, isConstructor(mh) always implies isConstructor param + // only nasgen constructors: (boolean, self, args) are subject to binding a boolean newObj. isConstructor + // is too conservative a check. However, isConstructor(mh) always implies isConstructor param assert isConstructor(); - code.add(new CompiledFunction(mh.type(), MH.insertArguments(mh, 0, false), composeConstructor(MH.insertArguments(mh, 0, true), needsCallee))); //make sure callee state can be determined when we reach constructor + final MethodHandle invoker = MH.insertArguments(mh, 0, false); + final MethodHandle constructor = composeConstructor(MH.insertArguments(mh, 0, true)); + code.add(new CompiledFunction(mh.type(), invoker, constructor)); } else { code.add(new CompiledFunction(mh.type(), mh)); } diff -r b9fdc55a6e28 -r c1049f63d4f5 src/jdk/nashorn/internal/runtime/JSType.java --- a/src/jdk/nashorn/internal/runtime/JSType.java Sun Nov 03 07:33:34 2013 +0000 +++ b/src/jdk/nashorn/internal/runtime/JSType.java Tue Dec 03 14:13:15 2013 +0400 @@ -88,6 +88,9 @@ /** JavaScript compliant conversion function from Object to number */ public static final Call TO_NUMBER = staticCall(myLookup, JSType.class, "toNumber", double.class, Object.class); + /** JavaScript compliant conversion function from Object to String */ + public static final Call TO_STRING = staticCall(myLookup, JSType.class, "toString", String.class, Object.class); + /** JavaScript compliant conversion function from Object to int32 */ public static final Call TO_INT32 = staticCall(myLookup, JSType.class, "toInt32", int.class, Object.class); @@ -883,7 +886,7 @@ */ public static Object toJavaArray(final Object obj, final Class componentType) { if (obj instanceof ScriptObject) { - return convertArray(((ScriptObject)obj).getArray().asObjectArray(), componentType); + return ((ScriptObject)obj).getArray().asArrayOfType(componentType); } else if (obj instanceof JSObject) { final ArrayLikeIterator itr = ArrayLikeIterator.arrayLikeIterator(obj); final int len = (int) itr.getLength(); @@ -908,6 +911,15 @@ * @return converted Java array */ public static Object convertArray(final Object[] src, final Class componentType) { + if(componentType == Object.class) { + for(int i = 0; i < src.length; ++i) { + final Object e = src[i]; + if(e instanceof ConsString) { + src[i] = e.toString(); + } + } + } + final int l = src.length; final Object dst = Array.newInstance(componentType, l); final MethodHandle converter = Bootstrap.getLinkerServices().getTypeConverter(Object.class, componentType); diff -r b9fdc55a6e28 -r c1049f63d4f5 src/jdk/nashorn/internal/runtime/Property.java --- a/src/jdk/nashorn/internal/runtime/Property.java Sun Nov 03 07:33:34 2013 +0000 +++ b/src/jdk/nashorn/internal/runtime/Property.java Tue Dec 03 14:13:15 2013 +0400 @@ -56,33 +56,36 @@ public static final int WRITABLE_ENUMERABLE_CONFIGURABLE = 0b0000_0000_0000; /** ECMA 8.6.1 - Is this property not writable? */ - public static final int NOT_WRITABLE = 0b0000_0000_0001; + public static final int NOT_WRITABLE = 1 << 0; /** ECMA 8.6.1 - Is this property not enumerable? */ - public static final int NOT_ENUMERABLE = 0b0000_0000_0010; + public static final int NOT_ENUMERABLE = 1 << 1; /** ECMA 8.6.1 - Is this property not configurable? */ - public static final int NOT_CONFIGURABLE = 0b0000_0000_0100; + public static final int NOT_CONFIGURABLE = 1 << 2; - private static final int MODIFY_MASK = 0b0000_0000_1111; + private static final int MODIFY_MASK = (NOT_WRITABLE | NOT_ENUMERABLE | NOT_CONFIGURABLE); /** Is this a spill property? See {@link AccessorProperty} */ - public static final int IS_SPILL = 0b0000_0001_0000; + public static final int IS_SPILL = 1 << 3; /** Is this a function parameter? */ - public static final int IS_PARAMETER = 0b0000_0010_0000; + public static final int IS_PARAMETER = 1 << 4; /** Is parameter accessed thru arguments? */ - public static final int HAS_ARGUMENTS = 0b0000_0100_0000; + public static final int HAS_ARGUMENTS = 1 << 5; /** Is this property always represented as an Object? See {@link ObjectClassGenerator} and dual fields flag. */ - public static final int IS_ALWAYS_OBJECT = 0b0000_1000_0000; + public static final int IS_ALWAYS_OBJECT = 1 << 6; /** Can this property be primitive? */ - public static final int CAN_BE_PRIMITIVE = 0b0001_0000_0000; + public static final int CAN_BE_PRIMITIVE = 1 << 7; /** Can this property be undefined? */ - public static final int CAN_BE_UNDEFINED = 0b0010_0000_0000; + public static final int CAN_BE_UNDEFINED = 1 << 8; + + /* Is this a function declaration property ? */ + public static final int IS_FUNCTION_DECLARATION = 1 << 9; /** Property key. */ private final String key; @@ -522,4 +525,12 @@ public boolean canBeUndefined() { return (flags & CAN_BE_UNDEFINED) == CAN_BE_UNDEFINED; } + + /** + * Check whether this property represents a function declaration. + * @return whether this property is a function declaration or not. + */ + public boolean isFunctionDeclaration() { + return (flags & IS_FUNCTION_DECLARATION) == IS_FUNCTION_DECLARATION; + } } diff -r b9fdc55a6e28 -r c1049f63d4f5 src/jdk/nashorn/internal/runtime/ScriptFunctionData.java --- a/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java Sun Nov 03 07:33:34 2013 +0000 +++ b/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java Tue Dec 03 14:13:15 2013 +0400 @@ -213,13 +213,13 @@ */ public final MethodHandle getGenericInvoker() { ensureCodeGenerated(); - return composeGenericMethod(code.mostGeneric().getInvoker()); + return code.generic().getInvoker(); } final MethodHandle getGenericConstructor() { ensureCodeGenerated(); - ensureConstructor(code.mostGeneric()); - return composeGenericMethod(code.mostGeneric().getConstructor()); + ensureConstructor(code.generic()); + return code.generic().getConstructor(); } private CompiledFunction getBest(final MethodType callSiteType) { @@ -267,18 +267,17 @@ } /** - * Compose a constructor given a primordial constructor handle + * Compose a constructor given a primordial constructor handle. * - * @param ctor primordial constructor handle - * @param needsCallee do we need to pass a callee - * + * @param ctor primordial constructor handle * @return the composed constructor */ - protected MethodHandle composeConstructor(final MethodHandle ctor, final boolean needsCallee) { + protected MethodHandle composeConstructor(final MethodHandle ctor) { // If it was (callee, this, args...), permute it to (this, callee, args...). We're doing this because having // "this" in the first argument position is what allows the elegant folded composition of // (newFilter x constructor x allocator) further down below in the code. Also, ensure the composite constructor // always returns Object. + final boolean needsCallee = needsCallee(ctor); MethodHandle composedCtor = needsCallee ? swapCalleeAndThis(ctor) : ctor; composedCtor = changeReturnTypeToObject(composedCtor); @@ -472,33 +471,6 @@ } /** - * Takes a method handle, and returns a potentially different method handle that can be used in - * {@code ScriptFunction#invoke(Object, Object...)} or {code ScriptFunction#construct(Object, Object...)}. - * The returned method handle will be sure to return {@code Object}, and will have all its parameters turned into - * {@code Object} as well, except for the following ones: - *
    - *
  • a last parameter of type {@code Object[]} which is used for vararg functions,
  • - *
  • the first argument, which is forced to be {@link ScriptFunction}, in case the function receives itself - * (callee) as an argument.
  • - *
- * - * @param mh the original method handle - * - * @return the new handle, conforming to the rules above. - */ - protected MethodHandle composeGenericMethod(final MethodHandle mh) { - final MethodType type = mh.type(); - MethodType newType = type.generic(); - if (isVarArg(mh)) { - newType = newType.changeParameterType(type.parameterCount() - 1, Object[].class); - } - if (needsCallee(mh)) { - newType = newType.changeParameterType(0, ScriptFunction.class); - } - return type.equals(newType) ? mh : mh.asType(newType); - } - - /** * Execute this script function. * * @param self Target object. @@ -508,10 +480,9 @@ * @throws Throwable if there is an exception/error with the invocation or thrown from it */ Object invoke(final ScriptFunction fn, final Object self, final Object... arguments) throws Throwable { - final MethodHandle mh = getGenericInvoker(); - - final Object selfObj = convertThisObject(self); - final Object[] args = arguments == null ? ScriptRuntime.EMPTY_ARRAY : arguments; + final MethodHandle mh = getGenericInvoker(); + final Object selfObj = convertThisObject(self); + final Object[] args = arguments == null ? ScriptRuntime.EMPTY_ARRAY : arguments; if (isVarArg(mh)) { if (needsCallee(mh)) { @@ -531,6 +502,12 @@ return mh.invokeExact(fn, selfObj, getArg(args, 0), getArg(args, 1)); case 5: return mh.invokeExact(fn, selfObj, getArg(args, 0), getArg(args, 1), getArg(args, 2)); + case 6: + return mh.invokeExact(fn, selfObj, getArg(args, 0), getArg(args, 1), getArg(args, 2), getArg(args, 3)); + case 7: + return mh.invokeExact(fn, selfObj, getArg(args, 0), getArg(args, 1), getArg(args, 2), getArg(args, 3), getArg(args, 4)); + case 8: + return mh.invokeExact(fn, selfObj, getArg(args, 0), getArg(args, 1), getArg(args, 2), getArg(args, 3), getArg(args, 4), getArg(args, 5)); default: return mh.invokeWithArguments(withArguments(fn, selfObj, paramCount, args)); } @@ -545,15 +522,20 @@ return mh.invokeExact(selfObj, getArg(args, 0), getArg(args, 1)); case 4: return mh.invokeExact(selfObj, getArg(args, 0), getArg(args, 1), getArg(args, 2)); + case 5: + return mh.invokeExact(selfObj, getArg(args, 0), getArg(args, 1), getArg(args, 2), getArg(args, 3)); + case 6: + return mh.invokeExact(selfObj, getArg(args, 0), getArg(args, 1), getArg(args, 2), getArg(args, 3), getArg(args, 4)); + case 7: + return mh.invokeExact(selfObj, getArg(args, 0), getArg(args, 1), getArg(args, 2), getArg(args, 3), getArg(args, 4), getArg(args, 5)); default: return mh.invokeWithArguments(withArguments(null, selfObj, paramCount, args)); } } Object construct(final ScriptFunction fn, final Object... arguments) throws Throwable { - final MethodHandle mh = getGenericConstructor(); - - final Object[] args = arguments == null ? ScriptRuntime.EMPTY_ARRAY : arguments; + final MethodHandle mh = getGenericConstructor(); + final Object[] args = arguments == null ? ScriptRuntime.EMPTY_ARRAY : arguments; if (isVarArg(mh)) { if (needsCallee(mh)) { @@ -573,6 +555,12 @@ return mh.invokeExact(fn, getArg(args, 0), getArg(args, 1)); case 4: return mh.invokeExact(fn, getArg(args, 0), getArg(args, 1), getArg(args, 2)); + case 5: + return mh.invokeExact(fn, getArg(args, 0), getArg(args, 1), getArg(args, 2), getArg(args, 3)); + case 6: + return mh.invokeExact(fn, getArg(args, 0), getArg(args, 1), getArg(args, 2), getArg(args, 3), getArg(args, 4)); + case 7: + return mh.invokeExact(fn, getArg(args, 0), getArg(args, 1), getArg(args, 2), getArg(args, 3), getArg(args, 4), getArg(args, 5)); default: return mh.invokeWithArguments(withArguments(fn, paramCount, args)); } @@ -587,6 +575,12 @@ return mh.invokeExact(getArg(args, 0), getArg(args, 1)); case 3: return mh.invokeExact(getArg(args, 0), getArg(args, 1), getArg(args, 2)); + case 4: + return mh.invokeExact(getArg(args, 0), getArg(args, 1), getArg(args, 2), getArg(args, 3)); + case 5: + return mh.invokeExact(getArg(args, 0), getArg(args, 1), getArg(args, 2), getArg(args, 3), getArg(args, 4)); + case 6: + return mh.invokeExact(getArg(args, 0), getArg(args, 1), getArg(args, 2), getArg(args, 3), getArg(args, 4), getArg(args, 5)); default: return mh.invokeWithArguments(withArguments(null, paramCount, args)); } @@ -664,20 +658,21 @@ * @return the adapted handle */ private static MethodHandle changeReturnTypeToObject(final MethodHandle mh) { - return MH.asType(mh, mh.type().changeReturnType(Object.class)); + final MethodType type = mh.type(); + return (type.returnType() == Object.class) ? mh : MH.asType(mh, type.changeReturnType(Object.class)); } private void ensureConstructor(final CompiledFunction inv) { if (!inv.hasConstructor()) { - inv.setConstructor(composeConstructor(inv.getInvoker(), needsCallee(inv.getInvoker()))); + inv.setConstructor(composeConstructor(inv.getInvoker())); } } /** - * Heuristic to figure out if the method handle has a callee argument. If it's type is either - * {@code (boolean, ScriptFunction, ...)} or {@code (ScriptFunction, ...)}, then we'll assume it has - * a callee argument. We need this as the constructor above is not passed this information, and can't just blindly - * assume it's false (notably, it's being invoked for creation of new scripts, and scripts have scopes, therefore + * Heuristic to figure out if the method handle has a callee argument. If it's type is + * {@code (ScriptFunction, ...)}, then we'll assume it has a callee argument. We need this as + * the constructor above is not passed this information, and can't just blindly assume it's false + * (notably, it's being invoked for creation of new scripts, and scripts have scopes, therefore * they also always receive a callee). * * @param mh the examined method handle @@ -685,18 +680,8 @@ * @return true if the method handle expects a callee, false otherwise */ protected static boolean needsCallee(final MethodHandle mh) { - final MethodType type = mh.type(); - final int length = type.parameterCount(); - - if (length == 0) { - return false; - } - - if (type.parameterType(0) == ScriptFunction.class) { - return true; - } - - return length > 1 && type.parameterType(0) == boolean.class && type.parameterType(1) == ScriptFunction.class; + final MethodType type = mh.type(); + return (type.parameterCount() > 0 && type.parameterType(0) == ScriptFunction.class); } /** diff -r b9fdc55a6e28 -r c1049f63d4f5 src/jdk/nashorn/internal/runtime/ScriptObject.java --- a/src/jdk/nashorn/internal/runtime/ScriptObject.java Sun Nov 03 07:33:34 2013 +0000 +++ b/src/jdk/nashorn/internal/runtime/ScriptObject.java Tue Dec 03 14:13:15 2013 +0400 @@ -226,14 +226,23 @@ for (final Property property : properties) { final String key = property.getKey(); - - if (newMap.findProperty(key) == null) { + final Property oldProp = newMap.findProperty(key); + if (oldProp == null) { if (property instanceof UserAccessorProperty) { final UserAccessorProperty prop = this.newUserAccessors(key, property.getFlags(), property.getGetterFunction(source), property.getSetterFunction(source)); newMap = newMap.addProperty(prop); } else { newMap = newMap.addPropertyBind((AccessorProperty)property, source); } + } else { + // See ECMA section 10.5 Declaration Binding Instantiation + // step 5 processing each function declaration. + if (property.isFunctionDeclaration() && !oldProp.isConfigurable()) { + if (oldProp instanceof UserAccessorProperty || + !(oldProp.isWritable() && oldProp.isEnumerable())) { + throw typeError("cant.redefine.property", key, ScriptRuntime.safeToString(this)); + } + } } } diff -r b9fdc55a6e28 -r c1049f63d4f5 src/jdk/nashorn/internal/runtime/ScriptingFunctions.java --- a/src/jdk/nashorn/internal/runtime/ScriptingFunctions.java Sun Nov 03 07:33:34 2013 +0000 +++ b/src/jdk/nashorn/internal/runtime/ScriptingFunctions.java Tue Dec 03 14:13:15 2013 +0400 @@ -190,7 +190,7 @@ char buffer[] = new char[1024]; try (final InputStreamReader inputStream = new InputStreamReader(process.getErrorStream())) { for (int length; (length = inputStream.read(buffer, 0, buffer.length)) != -1; ) { - outBuffer.append(buffer, 0, length); + errBuffer.append(buffer, 0, length); } } catch (IOException ex) { exception[1] = ex; diff -r b9fdc55a6e28 -r c1049f63d4f5 src/jdk/nashorn/internal/runtime/linker/Bootstrap.java --- a/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java Sun Nov 03 07:33:34 2013 +0000 +++ b/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java Tue Dec 03 14:13:15 2013 +0400 @@ -63,7 +63,7 @@ final DynamicLinkerFactory factory = new DynamicLinkerFactory(); factory.setPrioritizedLinkers(new NashornLinker(), new NashornPrimitiveLinker(), new NashornStaticClassLinker(), new BoundDynamicMethodLinker(), new JavaSuperAdapterLinker(), new JSObjectLinker(), new ReflectionCheckLinker()); - factory.setFallbackLinkers(new BeansLinker(), new NashornBottomLinker()); + factory.setFallbackLinkers(new NashornBeansLinker(), new NashornBottomLinker()); factory.setSyncOnRelink(true); final int relinkThreshold = Options.getIntProperty("nashorn.unstable.relink.threshold", -1); if (relinkThreshold > -1) { diff -r b9fdc55a6e28 -r c1049f63d4f5 src/jdk/nashorn/internal/runtime/linker/BoundDynamicMethodLinker.java --- a/src/jdk/nashorn/internal/runtime/linker/BoundDynamicMethodLinker.java Sun Nov 03 07:33:34 2013 +0000 +++ b/src/jdk/nashorn/internal/runtime/linker/BoundDynamicMethodLinker.java Tue Dec 03 14:13:15 2013 +0400 @@ -72,7 +72,7 @@ type.changeParameterType(0, dynamicMethodClass).changeParameterType(1, boundThis.getClass())); // Delegate to BeansLinker - final GuardedInvocation inv = BeansLinker.getLinkerForClass(dynamicMethodClass).getGuardedInvocation( + final GuardedInvocation inv = NashornBeansLinker.getGuardedInvocation(BeansLinker.getLinkerForClass(dynamicMethodClass), linkRequest.replaceArguments(newDescriptor, args), linkerServices); if(inv == null) { return null; diff -r b9fdc55a6e28 -r c1049f63d4f5 src/jdk/nashorn/internal/runtime/linker/JavaSuperAdapterLinker.java --- a/src/jdk/nashorn/internal/runtime/linker/JavaSuperAdapterLinker.java Sun Nov 03 07:33:34 2013 +0000 +++ b/src/jdk/nashorn/internal/runtime/linker/JavaSuperAdapterLinker.java Tue Dec 03 14:13:15 2013 +0400 @@ -100,8 +100,9 @@ type.changeParameterType(0, adapterClass), 0); // Delegate to BeansLinker - final GuardedInvocation guardedInv = BeansLinker.getLinkerForClass(adapterClass).getGuardedInvocation( - linkRequest.replaceArguments(newDescriptor, args), linkerServices); + final GuardedInvocation guardedInv = NashornBeansLinker.getGuardedInvocation( + BeansLinker.getLinkerForClass(adapterClass), linkRequest.replaceArguments(newDescriptor, args), + linkerServices); final MethodHandle guard = IS_ADAPTER_OF_CLASS.bindTo(adapterClass); if(guardedInv == null) { diff -r b9fdc55a6e28 -r c1049f63d4f5 src/jdk/nashorn/internal/runtime/linker/NashornBeansLinker.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/jdk/nashorn/internal/runtime/linker/NashornBeansLinker.java Tue Dec 03 14:13:15 2013 +0400 @@ -0,0 +1,127 @@ +/* + * 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ + +package jdk.nashorn.internal.runtime.linker; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import jdk.internal.dynalink.beans.BeansLinker; +import jdk.internal.dynalink.linker.ConversionComparator.Comparison; +import jdk.internal.dynalink.linker.GuardedInvocation; +import jdk.internal.dynalink.linker.GuardingDynamicLinker; +import jdk.internal.dynalink.linker.LinkRequest; +import jdk.internal.dynalink.linker.LinkerServices; +import jdk.internal.dynalink.support.Lookup; +import jdk.nashorn.internal.runtime.ConsString; + +/** + * This linker delegates to a {@code BeansLinker} but passes it a special linker services object that has a modified + * {@code asType} method that will ensure that we never pass internal engine objects that should not be externally + * observable (currently only ConsString) to Java APIs, but rather that we flatten it into a String. We can't just add + * this functionality as custom converters via {@code GuaardingTypeConverterFactory}, since they are not consulted when + * the target method handle parameter signature is {@code Object}. + */ +public class NashornBeansLinker implements GuardingDynamicLinker { + private static final MethodHandle EXPORT_ARGUMENT = new Lookup(MethodHandles.lookup()).findOwnStatic("exportArgument", Object.class, Object.class); + + private final BeansLinker beansLinker = new BeansLinker(); + + @Override + public GuardedInvocation getGuardedInvocation(final LinkRequest linkRequest, final LinkerServices linkerServices) throws Exception { + return getGuardedInvocation(beansLinker, linkRequest, linkerServices); + } + + /** + * Delegates to the specified linker but injects its linker services wrapper so that it will apply all special + * conversions that this class does. + * @param delegateLinker the linker to which the actual work is delegated to. + * @param linkRequest the delegated link request + * @param linkerServices the original link services that will be augmented with special conversions + * @return the guarded invocation from the delegate, possibly augmented with special conversions + * @throws Exception if the delegate throws an exception + */ + public static GuardedInvocation getGuardedInvocation(final GuardingDynamicLinker delegateLinker, final LinkRequest linkRequest, final LinkerServices linkerServices) throws Exception { + return delegateLinker.getGuardedInvocation(linkRequest, new NashornBeansLinkerServices(linkerServices)); + } + + @SuppressWarnings("unused") + private static Object exportArgument(final Object arg) { + return arg instanceof ConsString ? arg.toString() : arg; + } + + private static class NashornBeansLinkerServices implements LinkerServices { + private final LinkerServices linkerServices; + + NashornBeansLinkerServices(final LinkerServices linkerServices) { + this.linkerServices = linkerServices; + } + + @Override + public MethodHandle asType(final MethodHandle handle, final MethodType fromType) { + final MethodHandle typed = linkerServices.asType(handle, fromType); + + final MethodType handleType = handle.type(); + final int paramCount = handleType.parameterCount(); + assert fromType.parameterCount() == handleType.parameterCount(); + + MethodHandle[] filters = null; + for(int i = 0; i < paramCount; ++i) { + if(shouldConvert(handleType.parameterType(i), fromType.parameterType(i))) { + if(filters == null) { + filters = new MethodHandle[paramCount]; + } + filters[i] = EXPORT_ARGUMENT; + } + } + + return filters != null ? MethodHandles.filterArguments(typed, 0, filters) : typed; + } + + private static boolean shouldConvert(final Class handleType, final Class fromType) { + return handleType == Object.class && fromType == Object.class; + } + + @Override + public MethodHandle getTypeConverter(final Class sourceType, final Class targetType) { + return linkerServices.getTypeConverter(sourceType, targetType); + } + + @Override + public boolean canConvert(final Class from, final Class to) { + return linkerServices.canConvert(from, to); + } + + @Override + public GuardedInvocation getGuardedInvocation(final LinkRequest linkRequest) throws Exception { + return linkerServices.getGuardedInvocation(linkRequest); + } + + @Override + public Comparison compareConversion(final Class sourceType, final Class targetType1, final Class targetType2) { + return linkerServices.compareConversion(sourceType, targetType1, targetType2); + } + } +} diff -r b9fdc55a6e28 -r c1049f63d4f5 src/jdk/nashorn/internal/runtime/linker/NashornBottomLinker.java --- a/src/jdk/nashorn/internal/runtime/linker/NashornBottomLinker.java Sun Nov 03 07:33:34 2013 +0000 +++ b/src/jdk/nashorn/internal/runtime/linker/NashornBottomLinker.java Tue Dec 03 14:13:15 2013 +0400 @@ -33,14 +33,18 @@ import java.lang.invoke.MethodType; import java.lang.reflect.Method; import java.lang.reflect.Modifier; +import java.util.Map; +import java.util.HashMap; import jdk.internal.dynalink.CallSiteDescriptor; import jdk.internal.dynalink.beans.BeansLinker; import jdk.internal.dynalink.linker.GuardedInvocation; import jdk.internal.dynalink.linker.GuardingDynamicLinker; +import jdk.internal.dynalink.linker.GuardingTypeConverterFactory; import jdk.internal.dynalink.linker.LinkRequest; import jdk.internal.dynalink.linker.LinkerServices; import jdk.internal.dynalink.support.Guards; import jdk.nashorn.internal.runtime.Context; +import jdk.nashorn.internal.runtime.JSType; import jdk.nashorn.internal.runtime.ScriptRuntime; /** @@ -50,7 +54,7 @@ * setters for Java objects that couldn't be linked by any other linker, and throw appropriate ECMAScript errors for * attempts to invoke arbitrary Java objects as functions or constructors. */ -final class NashornBottomLinker implements GuardingDynamicLinker { +final class NashornBottomLinker implements GuardingDynamicLinker, GuardingTypeConverterFactory { @Override public GuardedInvocation getGuardedInvocation(final LinkRequest linkRequest, final LinkerServices linkerServices) @@ -129,6 +133,29 @@ throw new AssertionError("unknown call type " + desc); } + @Override + public GuardedInvocation convertToType(final Class sourceType, final Class targetType) throws Exception { + final GuardedInvocation gi = convertToTypeNoCast(sourceType, targetType); + return gi == null ? null : gi.asType(MH.type(targetType, sourceType)); + } + + /** + * Main part of the implementation of {@link GuardingTypeConverterFactory#convertToType(Class, Class)} that doesn't + * care about adapting the method signature; that's done by the invoking method. Returns conversion from Object to String/number/boolean (JS primitive types). + * @param sourceType the source type + * @param targetType the target type + * @return a guarded invocation that converts from the source type to the target type. + * @throws Exception if something goes wrong + */ + private static GuardedInvocation convertToTypeNoCast(final Class sourceType, final Class targetType) throws Exception { + final MethodHandle mh = CONVERTERS.get(targetType); + if (mh != null) { + return new GuardedInvocation(mh, null); + } + + return null; + } + private static GuardedInvocation getInvocation(final MethodHandle handle, final Object self, final LinkerServices linkerServices, final CallSiteDescriptor desc) { return Bootstrap.asType(new GuardedInvocation(handle, Guards.getClassGuard(self.getClass())), linkerServices, desc); } @@ -161,6 +188,15 @@ throw new AssertionError("unknown call type " + desc); } + private static final Map, MethodHandle> CONVERTERS = new HashMap<>(); + static { + CONVERTERS.put(boolean.class, JSType.TO_BOOLEAN.methodHandle()); + CONVERTERS.put(double.class, JSType.TO_NUMBER.methodHandle()); + CONVERTERS.put(int.class, JSType.TO_INTEGER.methodHandle()); + CONVERTERS.put(long.class, JSType.TO_LONG.methodHandle()); + CONVERTERS.put(String.class, JSType.TO_STRING.methodHandle()); + } + private static String getArgument(final LinkRequest linkRequest) { final CallSiteDescriptor desc = linkRequest.getCallSiteDescriptor(); if (desc.getNameTokenCount() > 2) { diff -r b9fdc55a6e28 -r c1049f63d4f5 src/jdk/nashorn/internal/runtime/linker/NashornLinker.java --- a/src/jdk/nashorn/internal/runtime/linker/NashornLinker.java Sun Nov 03 07:33:34 2013 +0000 +++ b/src/jdk/nashorn/internal/runtime/linker/NashornLinker.java Tue Dec 03 14:13:15 2013 +0400 @@ -32,6 +32,8 @@ import java.lang.reflect.Modifier; import java.util.Deque; import java.util.List; +import java.util.Map; +import javax.script.Bindings; import jdk.internal.dynalink.CallSiteDescriptor; import jdk.internal.dynalink.linker.ConversionComparator; import jdk.internal.dynalink.linker.GuardedInvocation; @@ -40,7 +42,11 @@ import jdk.internal.dynalink.linker.LinkerServices; import jdk.internal.dynalink.linker.TypeBasedGuardingDynamicLinker; import jdk.internal.dynalink.support.Guards; +import jdk.nashorn.api.scripting.JSObject; +import jdk.nashorn.api.scripting.ScriptObjectMirror; +import jdk.nashorn.api.scripting.ScriptUtils; import jdk.nashorn.internal.objects.NativeArray; +import jdk.nashorn.internal.runtime.Context; import jdk.nashorn.internal.runtime.JSType; import jdk.nashorn.internal.runtime.ScriptFunction; import jdk.nashorn.internal.runtime.ScriptObject; @@ -115,9 +121,14 @@ return new GuardedInvocation(mh, canLinkTypeStatic(sourceType) ? null : IS_NASHORN_OR_UNDEFINED_TYPE); } - GuardedInvocation inv = getArrayConverter(sourceType, targetType); - if(inv != null) { - return inv; + final GuardedInvocation arrayConverter = getArrayConverter(sourceType, targetType); + if(arrayConverter != null) { + return arrayConverter; + } + + final GuardedInvocation mirrorConverter = getMirrorConverter(sourceType, targetType); + if(mirrorConverter != null) { + return mirrorConverter; } return getSamTypeConverter(sourceType, targetType); @@ -181,6 +192,18 @@ return MH.asType(converter, converter.type().changeReturnType(type)); } + private static GuardedInvocation getMirrorConverter(Class sourceType, Class targetType) { + // Could've also used (targetType.isAssignableFrom(ScriptObjectMirror.class) && targetType != Object.class) but + // it's probably better to explicitly spell out the supported target types + if (targetType == Map.class || targetType == Bindings.class || targetType == JSObject.class || targetType == ScriptObjectMirror.class) { + if(ScriptObject.class.isAssignableFrom(sourceType)) { + return new GuardedInvocation(CREATE_MIRROR, null); + } + return new GuardedInvocation(CREATE_MIRROR, IS_SCRIPT_OBJECT); + } + return null; + } + private static boolean isAutoConvertibleFromFunction(final Class clazz) { return isAbstractClass(clazz) && !ScriptObject.class.isAssignableFrom(clazz) && JavaAdapterFactory.isAutoConvertibleFromFunction(clazz); @@ -235,17 +258,23 @@ return clazz == List.class || clazz == Deque.class; } + private static final MethodHandle IS_SCRIPT_OBJECT = Guards.isInstance(ScriptObject.class, MH.type(Boolean.TYPE, Object.class)); private static final MethodHandle IS_SCRIPT_FUNCTION = Guards.isInstance(ScriptFunction.class, MH.type(Boolean.TYPE, Object.class)); private static final MethodHandle IS_NATIVE_ARRAY = Guards.isOfClass(NativeArray.class, MH.type(Boolean.TYPE, Object.class)); - private static final MethodHandle IS_NASHORN_OR_UNDEFINED_TYPE = findOwnMH("isNashornTypeOrUndefined", - Boolean.TYPE, Object.class); + private static final MethodHandle IS_NASHORN_OR_UNDEFINED_TYPE = findOwnMH("isNashornTypeOrUndefined", Boolean.TYPE, Object.class); + private static final MethodHandle CREATE_MIRROR = findOwnMH("createMirror", Object.class, Object.class); @SuppressWarnings("unused") private static boolean isNashornTypeOrUndefined(final Object obj) { return obj instanceof ScriptObject || obj instanceof Undefined; } + @SuppressWarnings("unused") + private static Object createMirror(final Object obj) { + return ScriptUtils.wrap(obj); + } + private static MethodHandle findOwnMH(final String name, final Class rtype, final Class... types) { return MH.findStatic(MethodHandles.lookup(), NashornLinker.class, name, MH.type(rtype, types)); } diff -r b9fdc55a6e28 -r c1049f63d4f5 src/jdk/nashorn/internal/runtime/linker/NashornStaticClassLinker.java --- a/src/jdk/nashorn/internal/runtime/linker/NashornStaticClassLinker.java Sun Nov 03 07:33:34 2013 +0000 +++ b/src/jdk/nashorn/internal/runtime/linker/NashornStaticClassLinker.java Tue Dec 03 14:13:15 2013 +0400 @@ -93,7 +93,7 @@ } private static GuardedInvocation delegate(LinkerServices linkerServices, final LinkRequest request) throws Exception { - return staticClassLinker.getGuardedInvocation(request, linkerServices); + return NashornBeansLinker.getGuardedInvocation(staticClassLinker, request, linkerServices); } private static GuardedInvocation checkNullConstructor(final GuardedInvocation ctorInvocation, final Class receiverClass) { diff -r b9fdc55a6e28 -r c1049f63d4f5 test/script/basic/JDK-8015355.js --- a/test/script/basic/JDK-8015355.js Sun Nov 03 07:33:34 2013 +0000 +++ b/test/script/basic/JDK-8015355.js Tue Dec 03 14:13:15 2013 +0400 @@ -28,10 +28,6 @@ * @run */ -function fail(msg) { - print(msg); -} - function check(callback) { try { callback(); diff -r b9fdc55a6e28 -r c1049f63d4f5 test/script/basic/JDK-8027042.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/script/basic/JDK-8027042.js Tue Dec 03 14:13:15 2013 +0400 @@ -0,0 +1,58 @@ +/* + * 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-8027042: Evaluation order for binary operators can be improved + * + * @test + * @run + */ + +// var with getter side effect +Object.defineProperty(this, "a", { get: function() {print("get a"); return 1; }}); + +// var with both getter and conversion side effect +Object.defineProperty(this, "b", { get: function() {print("get b"); return {valueOf: function() { print("conv b"); return 10; }}; }}); + +(function() { + // var with toPrimitive conversion side effect + var c = {valueOf: function() { print("conv c"); return 100; }}; + + print(b + (c + a)); + print(b + (c + b)); + print(b + (a + b)); + print(b + (b + c)); + print(b + (b + c)); + print(b + (c + (a - b))); + print(b + (c + (c - b))); + print(b + (c + (b - c))); + print(b + (b + (a ? 2 : 3))); + print(b + (b + (b ? 2 : 3))); + print(b + (b + (c ? 2 : 3))); + print(b + ((-c) + (-a))); + print(b + ((-c) + (-b))); + print(b + ((-c) + (-c))); + try { print(b + new a); } catch (e) {} + try { print(b + new b); } catch (e) {} + try { print(b + new c); } catch (e) {} +})(); diff -r b9fdc55a6e28 -r c1049f63d4f5 test/script/basic/JDK-8027042.js.EXPECTED --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/script/basic/JDK-8027042.js.EXPECTED Tue Dec 03 14:13:15 2013 +0400 @@ -0,0 +1,88 @@ +get b +get a +conv c +conv b +111 +get b +get b +conv c +conv b +conv b +120 +get b +get a +get b +conv b +conv b +21 +get b +get b +conv b +conv c +conv b +120 +get b +get b +conv b +conv c +conv b +120 +get b +get a +get b +conv b +conv c +conv b +101 +get b +get b +conv c +conv b +conv c +conv b +200 +get b +get b +conv b +conv c +conv c +conv b +20 +get b +get b +get a +conv b +conv b +22 +get b +get b +get b +conv b +conv b +22 +get b +get b +conv b +conv b +22 +get b +conv c +get a +conv b +-91 +get b +conv c +get b +conv b +conv b +-100 +get b +conv c +conv c +conv b +-190 +get b +get a +get b +get b +get b diff -r b9fdc55a6e28 -r c1049f63d4f5 test/script/basic/JDK-8027236.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/script/basic/JDK-8027236.js Tue Dec 03 14:13:15 2013 +0400 @@ -0,0 +1,37 @@ +/* + * 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-8027236: Ensure ScriptObject and ConsString aren't visible to Java + * + * @test + * @run + */ + +// Check that ConsString is flattened +var m = new java.util.HashMap() +var x = "f" +x += "oo" +m.put(x, "bar") +print(m.get("foo")) +// Note: many more tests are run by the JavaExportImportTest TestNG class. diff -r b9fdc55a6e28 -r c1049f63d4f5 test/script/basic/JDK-8027236.js.EXPECTED --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/script/basic/JDK-8027236.js.EXPECTED Tue Dec 03 14:13:15 2013 +0400 @@ -0,0 +1,1 @@ +bar diff -r b9fdc55a6e28 -r c1049f63d4f5 test/script/basic/JDK-8027562.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/script/basic/JDK-8027562.js Tue Dec 03 14:13:15 2013 +0400 @@ -0,0 +1,39 @@ +/* + * 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-8027562: eval should load second and subsequent arguments for side effect + * + * @test + * @run + */ + +try { + eval("", x); + fail("should have thrown ReferenceError for 'x'"); +} catch (e) { + if (! (e instanceof ReferenceError)) { + fail("Expected ReferenceError, got " + e); + } + print(e); +} diff -r b9fdc55a6e28 -r c1049f63d4f5 test/script/basic/JDK-8027562.js.EXPECTED --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/script/basic/JDK-8027562.js.EXPECTED Tue Dec 03 14:13:15 2013 +0400 @@ -0,0 +1,1 @@ +ReferenceError: "x" is not defined diff -r b9fdc55a6e28 -r c1049f63d4f5 test/script/basic/JDK-8027700.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/script/basic/JDK-8027700.js Tue Dec 03 14:13:15 2013 +0400 @@ -0,0 +1,54 @@ +/* + * 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-8027700: function redeclaration checks missing for declaration binding instantiation + * + * @test + * @run + */ + +Object.defineProperty(this,"x", { + value:0, + writable:true, + enumerable:false +}) + +try { + eval("function x() {}"); + fail("should have thrown TypeError"); +} catch (e) { + if (! (e instanceof TypeError)) { + fail("TypeError expected but got " + e); + } +} + +Object.defineProperty(this, "foo", { value:0 }) +try { + eval("function foo() {}"); + fail("should have thrown TypeError"); +} catch (e) { + if (! (e instanceof TypeError)) { + fail("TypeError expected but got " + e); + } +} diff -r b9fdc55a6e28 -r c1049f63d4f5 test/script/basic/JDK-8027753.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/script/basic/JDK-8027753.js Tue Dec 03 14:13:15 2013 +0400 @@ -0,0 +1,50 @@ +/* + * 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-8027753: Support ScriptObject to JSObject, ScriptObjectMirror, Map, Bindings auto-conversion as well as explicit wrap, unwrap + * + * @test + * @run + */ + +var ScriptUtils = Java.type("jdk.nashorn.api.scripting.ScriptUtils"); +var ScriptObjectMirror = Java.type("jdk.nashorn.api.scripting.ScriptObjectMirror"); + +var obj = { foo: 34, bar: 'hello' }; + +var wrapped = ScriptUtils.wrap(obj); +if (! (wrapped instanceof ScriptObjectMirror)) { + fail("ScriptUtils.wrap does not return a ScriptObjectMirror"); +} + +print("wrapped.foo = " + wrapped.foo); +print("wrapped.bar = " + wrapped.bar); + +var unwrapped = ScriptUtils.unwrap(wrapped); +if (! (unwrapped instanceof Object)) { + fail("ScriptUtils.unwrap does not return a ScriptObject"); +} + +// same object unwrapped? +print(unwrapped === obj); diff -r b9fdc55a6e28 -r c1049f63d4f5 test/script/basic/JDK-8027753.js.EXPECTED --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/script/basic/JDK-8027753.js.EXPECTED Tue Dec 03 14:13:15 2013 +0400 @@ -0,0 +1,3 @@ +wrapped.foo = 34 +wrapped.bar = hello +true diff -r b9fdc55a6e28 -r c1049f63d4f5 test/script/basic/JDK-8027828.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/script/basic/JDK-8027828.js Tue Dec 03 14:13:15 2013 +0400 @@ -0,0 +1,35 @@ +/* + * 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-8027828: ClassCastException when converting return value of a Java method to boolean + * + * @test + * @run + */ + +var x = new java.util.HashMap() +x.put('test', new java.io.File('test')) +if (x.get("test")) { + print('Found!') +} diff -r b9fdc55a6e28 -r c1049f63d4f5 test/script/basic/JDK-8027828.js.EXPECTED --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/script/basic/JDK-8027828.js.EXPECTED Tue Dec 03 14:13:15 2013 +0400 @@ -0,0 +1,1 @@ +Found! diff -r b9fdc55a6e28 -r c1049f63d4f5 test/script/basic/JDK-8028020.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/script/basic/JDK-8028020.js Tue Dec 03 14:13:15 2013 +0400 @@ -0,0 +1,40 @@ +/* + * 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-8028020: Function parameter as last expression in comma in return value causes bad type calculation + * + * @test + * @run + */ + +function f(x) { + return 1, x +} + +function g(x, y) { + return x, y +} + +print(f("'1, x' works.")) +print(g(42, "'x, y' works too.")) diff -r b9fdc55a6e28 -r c1049f63d4f5 test/script/basic/JDK-8028020.js.EXPECTED --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/script/basic/JDK-8028020.js.EXPECTED Tue Dec 03 14:13:15 2013 +0400 @@ -0,0 +1,2 @@ +'1, x' works. +'x, y' works too. diff -r b9fdc55a6e28 -r c1049f63d4f5 test/script/basic/convert.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/script/basic/convert.js Tue Dec 03 14:13:15 2013 +0400 @@ -0,0 +1,61 @@ +/* + * 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. + */ + +/** + * Tests for convert method of ScriptUtils. + * + * @test + * @run + */ + +var ScriptUtils = Java.type("jdk.nashorn.api.scripting.ScriptUtils"); +obj = { valueOf: function() { print("hello"); return 43.3; } }; + +// object to double +print(ScriptUtils.convert(obj, java.lang.Number.class)); + +// array to List +var arr = [3, 44, 23, 33]; +var list = ScriptUtils.convert(arr, java.util.List.class); +print(list instanceof java.util.List) +print(list); + +// object to Map +obj = { foo: 333, bar: 'hello'}; +var map = ScriptUtils.convert(obj, java.util.Map.class); +print(map instanceof java.util.Map); +for (m in map) { + print(m + " " + map[m]); +} + +// object to String +obj = { toString: function() { print("in toString"); return "foo" } }; +print(ScriptUtils.convert(obj, java.lang.String.class)); + +// array to Java array +var jarr = ScriptUtils.convert(arr, Java.type("int[]")); +print(jarr instanceof Java.type("int[]")); +for (i in jarr) { + print(jarr[i]); +} + diff -r b9fdc55a6e28 -r c1049f63d4f5 test/script/basic/convert.js.EXPECTED --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/script/basic/convert.js.EXPECTED Tue Dec 03 14:13:15 2013 +0400 @@ -0,0 +1,14 @@ +hello +43.3 +true +[3, 44, 23, 33] +true +foo 333 +bar hello +in toString +foo +true +3 +44 +23 +33 diff -r b9fdc55a6e28 -r c1049f63d4f5 test/script/jfx.js --- a/test/script/jfx.js Sun Nov 03 07:33:34 2013 +0000 +++ b/test/script/jfx.js Tue Dec 03 14:13:15 2013 +0400 @@ -37,13 +37,24 @@ var Scene = Java.type("javafx.scene.Scene"); var Stage = Java.type("javafx.stage.Stage"); var File = Java.type("java.io.File"); -var Timer = Java.type("java.util.Timer"); -var TimerTask = Java.type("java.util.TimerTask"); var OSInfo = Java.type("sun.awt.OSInfo"); var OSType = Java.type("sun.awt.OSInfo.OSType"); var StringBuffer = Java.type("java.lang.StringBuffer"); +var Paint = Java.type("javafx.scene.paint.Paint"); +var Color = Java.type("javafx.scene.paint.Color"); +var Image = Java.type("javafx.scene.image.Image"); +var Canvas = Java.type("javafx.scene.canvas.Canvas"); +var BorderPane = Java.type("javafx.scene.layout.BorderPane"); +var StackPane = Java.type("javafx.scene.layout.StackPane"); +var StrokeLineCap = Java.type("javafx.scene.shape.StrokeLineCap"); +var Platform = Java.type("javafx.application.Platform"); +var Runnable = Java.type("java.lang.Runnable"); +var RunnableExtend = Java.extend(Runnable); +var AnimationTimer = Java.type("javafx.animation.AnimationTimer"); +var AnimationTimerExtend = Java.extend(AnimationTimer); +var Timer = Java.type("java.util.Timer"); +var TimerTask = Java.type("java.util.TimerTask"); -var WAIT = 2000; var TESTNAME = "test"; var fsep = System.getProperty("file.separator"); @@ -53,14 +64,16 @@ run: function run() { var tmpdir = System.getProperty("java.io.tmpdir"); var timenow = (new Date()).getTime(); - makeScreenShot(tmpdir + fsep + "screenshot" + timenow +".png"); - var dupImg = isDuplicateImages(tmpdir + fsep + "screenshot" + timenow +".png", __DIR__ + "jfx" + fsep + TESTNAME + fsep + "golden"); - (new File(mpdir + fsep + "screenshot" + timenow +".png")).delete(); - if (!dupImg) System.err.println("ERROR: screenshot does not match golden image"); + var scrShotTmp = tmpdir + fsep + "screenshot" + timenow +".png"; + var goldenImageDir = __DIR__ + "jfx" + fsep + TESTNAME + fsep + "golden"; + makeScreenShot(scrShotTmp); + var dupImg = isDuplicateImages(scrShotTmp, goldenImageDir); + (new File(scrShotTmp)).delete(); + if (!dupImg) System.err.println("ERROR: screenshot does not match the golden image"); exit(0); } }; - raceTimer.schedule(timerTask, WAIT); + raceTimer.schedule(timerTask, 100); } function makeScreenShot(shootToImg) { @@ -70,10 +83,10 @@ imageJemmy.save(shootToImg); } -function isDuplicateImages(file1, file2) { - var f1 = new File(file1); +function isDuplicateImages(screenShot, goldenDir) { + var f1 = new File(screenShot); var f2; - var sb = new StringBuffer(file2); + var sb = new StringBuffer(goldenDir); if (OSInfo.getOSType() == OSType.WINDOWS) { f2 = new File(sb.append(fsep + "windows.png").toString()); } else if (OSInfo.getOSType() == OSType.LINUX) { @@ -81,8 +94,6 @@ } else if (OSInfo.getOSType() == OSType.MACOSX) { f2 = new File(sb.append(fsep + "macosx.png").toString()); } - print(f1.getAbsolutePath()); - print(f2.getAbsolutePath()); if (f1.exists() && f2.exists()) { var image1 = new AWTImage(PNGDecoder.decode(f1.getAbsolutePath())); var image2 = new AWTImage(PNGDecoder.decode(f2.getAbsolutePath())); diff -r b9fdc55a6e28 -r c1049f63d4f5 test/script/jfx/flyingimage.js --- a/test/script/jfx/flyingimage.js Sun Nov 03 07:33:34 2013 +0000 +++ b/test/script/jfx/flyingimage.js Tue Dec 03 14:13:15 2013 +0400 @@ -31,15 +31,6 @@ TESTNAME = "flyingimage"; -var Image = Java.type("javafx.scene.image.Image"); -var Color = Java.type("javafx.scene.paint.Color"); -var Canvas = Java.type("javafx.scene.canvas.Canvas"); -var BorderPane = Java.type("javafx.scene.layout.BorderPane"); -var StackPane = Java.type("javafx.scene.layout.StackPane"); -var Font = Java.type("javafx.scene.text.Font"); -var FontSmoothingType = Java.type("javafx.scene.text.FontSmoothingType"); -var Text = Java.type("javafx.scene.text.Text"); - var WIDTH = 800; var HEIGHT = 600; var canvas = new Canvas(WIDTH, HEIGHT); @@ -48,10 +39,9 @@ } var imageUrl = fileToURL(__DIR__ + "flyingimage/flyingimage.png"); var img = new Image(imageUrl); -var font = new Font("Arial", 16); -var t = 0; var isFrameRendered = false; function renderFrame() { + var t = frame; var gc = canvas.graphicsContext2D; gc.setFill(Color.web("#cccccc")); gc.fillRect(0, 0, WIDTH, HEIGHT); @@ -61,7 +51,7 @@ var c = 200; var msc= 0.5 * HEIGHT / img.height; var sp0 = 0.003; - for (var h = 0; h < c; h++, t++) { + for (var h = 0; h < c; h++) { gc.setTransform(1, 0, 0, 1, 0, 0); var yh = h / (c - 1); gc.translate((0.5 + Math.sin(t * sp0 + h * 0.1) / 3) * WIDTH, 25 + (HEIGHT * 3 / 4 - 40) * (yh * yh)); @@ -69,15 +59,26 @@ gc.rotate(90 * Math.sin(t * sp0 + h * 0.1 + Math.PI)); gc.scale(sc, sc); gc.drawImage(img, -img.width / 2, -img.height / 2); - } + } gc.setTransform(1, 0, 0, 1, 0, 0); isFrameRendered = true; } var stack = new StackPane(); var pane = new BorderPane(); - pane.setCenter(canvas); stack.getChildren().add(pane); $STAGE.scene = new Scene(stack); -renderFrame(); -checkImageAndExit(); +var frame = 0; +var timer = new AnimationTimerExtend() { + handle: function handle(now) { + if (frame < 200) { + renderFrame(); + frame++; + } else { + checkImageAndExit(); + timer.stop(); + } + } +}; +timer.start(); + diff -r b9fdc55a6e28 -r c1049f63d4f5 test/script/jfx/flyingimage/flyingimage.png Binary file test/script/jfx/flyingimage/flyingimage.png has changed diff -r b9fdc55a6e28 -r c1049f63d4f5 test/script/jfx/flyingimage/golden/linux.png Binary file test/script/jfx/flyingimage/golden/linux.png has changed diff -r b9fdc55a6e28 -r c1049f63d4f5 test/script/jfx/flyingimage/golden/macosx.png Binary file test/script/jfx/flyingimage/golden/macosx.png has changed diff -r b9fdc55a6e28 -r c1049f63d4f5 test/script/jfx/flyingimage/golden/windows.png Binary file test/script/jfx/flyingimage/golden/windows.png has changed diff -r b9fdc55a6e28 -r c1049f63d4f5 test/script/jfx/kaleidoscope.js --- a/test/script/jfx/kaleidoscope.js Sun Nov 03 07:33:34 2013 +0000 +++ b/test/script/jfx/kaleidoscope.js Tue Dec 03 14:13:15 2013 +0400 @@ -30,13 +30,6 @@ */ TESTNAME = "kaleidoscope"; -WAIT = 4000; - -var Paint = Java.type("javafx.scene.paint.Paint"); -var Canvas = Java.type("javafx.scene.canvas.Canvas"); -var BorderPane = Java.type("javafx.scene.layout.BorderPane"); -var StackPane = Java.type("javafx.scene.layout.StackPane"); -var StrokeLineCap = Java.type("javafx.scene.shape.StrokeLineCap"); var WIDTH = 800; var HEIGHT = 600; @@ -56,26 +49,28 @@ var r,e; var fade; var prv_x,prv_y,prv_x2,prv_y2; +var isFrameRendered = false; function renderFrame() { - a=0.2*angle; - b=0.7*angle; - r=0; - fade=32; - for(var i=0;i<6;i++) - { - c[i]=1.0/(i+1)/2; - d[i]=1.0/(i+1)/2; - } - radius=Math.round((WIDTH+HEIGHT)/8); - e=radius*0.2; - p_x=Math.round(WIDTH/2); - p_y=Math.round(HEIGHT/2); - x=(radius*c[0])*Math.cos(a*d[1])+(radius*c[2])*Math.sin(a*d[3])+(radius*c[4])*Math.sin(a*d[5]); - y=(radius*c[5])*Math.sin(a*d[4])+(radius*c[3])*Math.cos(a*d[2])+(radius*c[1])*Math.cos(a*d[0]); - for (i = 0; i < 800; i++) { - anim(); + if (!isFrameRendered) { + a=0.2*angle; + b=0.7*angle; + r=0; + fade=32; + for(var i=0;i<6;i++) + { + c[i]=1.0/(i+1)/2; + d[i]=1.0/(i+1)/2; + } + radius=Math.round((WIDTH+HEIGHT)/8); + e=radius*0.2; + p_x=Math.round(WIDTH/2); + p_y=Math.round(HEIGHT/2); + x=(radius*c[0])*Math.cos(a*d[1])+(radius*c[2])*Math.sin(a*d[3])+(radius*c[4])*Math.sin(a*d[5]); + y=(radius*c[5])*Math.sin(a*d[4])+(radius*c[3])*Math.cos(a*d[2])+(radius*c[1])*Math.cos(a*d[0]); + isFrameRendered = true; } + anim(); } function anim() { @@ -154,9 +149,19 @@ var stack = new StackPane(); var pane = new BorderPane(); - pane.setCenter(canvas); stack.getChildren().add(pane); $STAGE.scene = new Scene(stack); -renderFrame(); -checkImageAndExit(); \ No newline at end of file +var frame = 0; +var timer = new AnimationTimerExtend() { + handle: function handle(now) { + if (frame < 800) { + renderFrame(); + frame++; + } else { + checkImageAndExit(); + timer.stop(); + } + } +}; +timer.start(); diff -r b9fdc55a6e28 -r c1049f63d4f5 test/script/jfx/kaleidoscope/golden/linux.png Binary file test/script/jfx/kaleidoscope/golden/linux.png has changed diff -r b9fdc55a6e28 -r c1049f63d4f5 test/script/jfx/kaleidoscope/golden/macosx.png Binary file test/script/jfx/kaleidoscope/golden/macosx.png has changed diff -r b9fdc55a6e28 -r c1049f63d4f5 test/script/jfx/kaleidoscope/golden/windows.png Binary file test/script/jfx/kaleidoscope/golden/windows.png has changed diff -r b9fdc55a6e28 -r c1049f63d4f5 test/script/jfx/spread.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/script/jfx/spread.js Tue Dec 03 14:13:15 2013 +0400 @@ -0,0 +1,222 @@ +/* + * Copyright (c) 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. + */ + +/** + * Testing JavaFX canvas run by Nashorn. + * + * @test/nocompare + * @run + * @fork + */ + +TESTNAME = "spread"; + +var WIDTH = 800; +var HEIGHT = 600; +var canvas = new Canvas(WIDTH, HEIGHT); +var context = canvas.graphicsContext2D; + +/* "Spread" tech demo of canvas by Tom Theisen + * + * This will animate a sequence of branch structures in a canvas element. + * Each frame, a new direction is calculated, similar to the last frame. + */ + +var start_width = 20; // starting width of each branch +var frame_time = 30; // milliseconds per frame +var straighten_factor = 0.95; // value from 0 to 1, factor applied to direction_offset every frame +var curviness = 0.2; // amount of random direction change each frame + +var color_speed = 0.03; // speed at which colors change when cycling is enabled +var branch_shrink = 0.95; // factor by which branches shrink every frame +var min_width = 1; // minimum WIDTH for branch, after which they are discontinued +var branch_opacity = 0.4; // opacity of lines drawn +var branch_count = 3; // branch count per tree +var branch_bud_size = 0.5; // ratio of original branch size at which branch will split +var branch_bud_angle = 1; // angle offset for split branch; + +var paper; // reference to graphics context +var branches = Object(); // linked list of active branches +var color_styles = []; // pre-computed list of colors as styles. format: (r,g,b,a) +var direction_offset = 0; // current direction offset in radians. this is applied to all branches. +var frame = 0; // frame counter +var timespent = 0; // total time spent so far, used to calculate average frame render duration +var frameratespan; // html span element for updating performance number + +// preferences object, contains an attribute for each user setting +var prefs = { + wrap: true, // causes branches reaching edge of viewable area to appear on opposite side + fade: false, // fade existing graphics on each frame + cycle: true, // gradually change colors each frame + new_branch_frames: 20 // number of frames elapsed between each auto-generated tree +}; + +// create tree at the specified position with number of branches +function create_tree(branches, start_width, position, branch_count) { + var angle_offset = Math.PI * 2 / branch_count; + for (var i = 0; i < branch_count; ++i) { + branch_add(branches, new Branch(position, angle_offset * i, start_width)); + } +} + +// add branch to collection +function branch_add(branches, branch) { + branch.next = branches.next; + branches.next = branch; +} + +// get the coordinates for the position of a new tree +// use the center of the canvas +function get_new_tree_center(width, height) { + return { + x: 0.5 * width, + y: 0.5 * height + }; +} + +// Branch constructor +// position has x and y properties +// direction is in radians +function Branch(position, direction, width) { + this.x = position.x; + this.y = position.y; + this.width = width; + this.original_width = width; + this.direction = direction; +} + +// update position, direction and width of a particular branch +function branch_update(branches, branch, paper) { + paper.beginPath(); + paper.lineWidth = branch.width; + paper.moveTo(branch.x, branch.y); + + branch.width *= branch_shrink; + branch.direction += direction_offset; + branch.x += Math.cos(branch.direction) * branch.width; + branch.y += Math.sin(branch.direction) * branch.width; + + paper.lineTo(branch.x, branch.y); + paper.stroke(); + + if (prefs.wrap) wrap_branch(branch, WIDTH, HEIGHT); + + if (branch.width < branch.original_width * branch_bud_size) { + branch.original_width *= branch_bud_size; + branch_add(branches, new Branch(branch, branch.direction + 1, branch.original_width)); + } +} + +function draw_frame() { + if (prefs.fade) { + paper.fillRect(0, 0, WIDTH, HEIGHT); + } + + if (prefs.cycle) { + paper.setStroke(Paint.valueOf(color_styles[frame % color_styles.length])); + } + + if (frame++ % prefs.new_branch_frames == 0) { + create_tree(branches, start_width, get_new_tree_center(WIDTH, HEIGHT), branch_count); + } + + direction_offset += (0.35 + (frame % 200) * 0.0015) * curviness - curviness / 2; + direction_offset *= straighten_factor; + + var branch = branches; + var prev_branch = branches; + while (branch = branch.next) { + branch_update(branches, branch, paper); + + if (branch.width < min_width) { + // remove branch from list + prev_branch.next = branch.next; + } + + prev_branch = branch; + } +} + +// constrain branch position to visible area by "wrapping" from edge to edge +function wrap_branch(branch, WIDTH, HEIGHT) { + branch.x = positive_mod(branch.x, WIDTH); + branch.y = positive_mod(branch.y, HEIGHT); +} + +// for a < 0, b > 0, javascript returns a negative number for a % b +// this is a variant of the % operator that adds b to the result in this case +function positive_mod(a, b) { + // ECMA 262 11.5.3: Applying the % Operator + // remainder operator does not convert operands to integers, + // although negative results are possible + + return ((a % b) + b) % b; +} + +// pre-compute color styles that will be used for color cycling +function populate_colors(color_speed, color_styles, branch_opacity) { + // used in calculation of RGB values + var two_thirds_pi = Math.PI * 2 / 3; + var four_thirds_pi = Math.PI * 4 / 3; + var two_pi = Math.PI * 2; + + // hue does represent hue, but not in the conventional HSL scheme + for(var hue = 0; hue < two_pi; hue += color_speed) { + var r = Math.floor(Math.sin(hue) * 128 + 128); + var g = Math.floor(Math.sin(hue + two_thirds_pi) * 128 + 128); + var b = Math.floor(Math.sin(hue + four_thirds_pi) * 128 + 128); + color = "rgba(" + [r, g, b, branch_opacity].join() + ")"; + + color_styles.push(color); + } +} + +// apply initial settings to canvas object +function setup_canvas() { + paper = canvas.graphicsContext2D; + paper.setFill(Paint.valueOf('rgb(0, 0, 0)')); + paper.fillRect(0, 0, WIDTH, HEIGHT); + paper.setFill(Paint.valueOf("rgba(0, 0, 0, 0.005)")); + paper.setStroke(Paint.valueOf("rgba(128, 128, 64, " + String(branch_opacity) + ")")); +} + +populate_colors(color_speed, color_styles, branch_opacity); +setup_canvas(); + +var stack = new StackPane(); +var pane = new BorderPane(); +pane.setCenter(canvas); +stack.getChildren().add(pane); +$STAGE.scene = new Scene(stack); +var timer = new AnimationTimerExtend() { + handle: function handle(now) { + if (frame < 200) { + draw_frame(); + } else { + checkImageAndExit(); + timer.stop(); + } + } +}; +timer.start(); + diff -r b9fdc55a6e28 -r c1049f63d4f5 test/script/jfx/spread/golden/linux.png Binary file test/script/jfx/spread/golden/linux.png has changed diff -r b9fdc55a6e28 -r c1049f63d4f5 test/script/jfx/spread/golden/macosx.png Binary file test/script/jfx/spread/golden/macosx.png has changed diff -r b9fdc55a6e28 -r c1049f63d4f5 test/script/jfx/spread/golden/windows.png Binary file test/script/jfx/spread/golden/windows.png has changed diff -r b9fdc55a6e28 -r c1049f63d4f5 test/src/jdk/nashorn/api/javaaccess/ConsStringTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/src/jdk/nashorn/api/javaaccess/ConsStringTest.java Tue Dec 03 14:13:15 2013 +0400 @@ -0,0 +1,99 @@ +/* + * 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ + +package jdk.nashorn.api.javaaccess; + +import static org.testng.AssertJUnit.assertEquals; + +import java.util.HashMap; +import java.util.Map; +import javax.script.Bindings; +import javax.script.ScriptContext; +import javax.script.ScriptEngine; +import javax.script.ScriptEngineManager; +import javax.script.ScriptException; +import jdk.nashorn.api.scripting.JSObject; +import org.testng.TestNG; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +public class ConsStringTest { + private static ScriptEngine e = null; + + public static void main(final String[] args) { + TestNG.main(args); + } + + @BeforeClass + public static void setUpClass() throws ScriptException { + e = new ScriptEngineManager().getEngineByName("nashorn"); + } + + @AfterClass + public static void tearDownClass() { + e = null; + } + + @Test + public void testConsStringFlattening() throws ScriptException { + final Bindings b = e.getBindings(ScriptContext.ENGINE_SCOPE); + final Map m = new HashMap<>(); + b.put("m", m); + e.eval("var x = 'f'; x += 'oo'; var y = 'b'; y += 'ar'; m.put(x, y)"); + assertEquals("bar", m.get("foo")); + } + + @Test + public void testConsStringFromMirror() throws ScriptException { + final Bindings b = e.getBindings(ScriptContext.ENGINE_SCOPE); + final Map m = new HashMap<>(); + e.eval("var x = 'f'; x += 'oo'; var obj = {x: x};"); + assertEquals("foo", ((JSObject)b.get("obj")).getMember("x")); + } + + @Test + public void testArrayConsString() throws ScriptException { + final Bindings b = e.getBindings(ScriptContext.ENGINE_SCOPE); + final ArrayHolder h = new ArrayHolder(); + b.put("h", h); + e.eval("var x = 'f'; x += 'oo'; h.array = [x];"); + assertEquals(1, h.array.length); + assertEquals("foo", h.array[0]); + } + + + public static class ArrayHolder { + private Object[] array; + + public void setArray(Object[] array) { + this.array = array; + } + + public Object[] getArray() { + return array; + } + } +} diff -r b9fdc55a6e28 -r c1049f63d4f5 test/src/jdk/nashorn/api/scripting/ScriptEngineTest.java --- a/test/src/jdk/nashorn/api/scripting/ScriptEngineTest.java Sun Nov 03 07:33:34 2013 +0000 +++ b/test/src/jdk/nashorn/api/scripting/ScriptEngineTest.java Tue Dec 03 14:13:15 2013 +0400 @@ -523,6 +523,18 @@ assertEquals(sw.toString(), println("34 true hello")); } + @Test + public void scriptObjectAutoConversionTest() throws ScriptException { + final ScriptEngineManager m = new ScriptEngineManager(); + final ScriptEngine e = m.getEngineByName("nashorn"); + e.eval("obj = { foo: 'hello' }"); + e.put("Window", e.eval("Packages.jdk.nashorn.api.scripting.Window")); + assertEquals(e.eval("Window.funcJSObject(obj)"), "hello"); + assertEquals(e.eval("Window.funcScriptObjectMirror(obj)"), "hello"); + assertEquals(e.eval("Window.funcMap(obj)"), "hello"); + assertEquals(e.eval("Window.funcJSObject(obj)"), "hello"); + } + private static final String LINE_SEPARATOR = System.getProperty("line.separator"); // Returns String that would be the result of calling PrintWriter.println diff -r b9fdc55a6e28 -r c1049f63d4f5 test/src/jdk/nashorn/api/scripting/ScriptObjectMirrorTest.java --- a/test/src/jdk/nashorn/api/scripting/ScriptObjectMirrorTest.java Sun Nov 03 07:33:34 2013 +0000 +++ b/test/src/jdk/nashorn/api/scripting/ScriptObjectMirrorTest.java Tue Dec 03 14:13:15 2013 +0400 @@ -26,6 +26,7 @@ package jdk.nashorn.api.scripting; import java.util.HashMap; +import java.util.List; import java.util.Map; import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; @@ -227,4 +228,28 @@ final Object newObj = ((ScriptObjectMirror)e2obj.getMember("foo")).newObject(); assertTrue(newObj instanceof ScriptObjectMirror); } + + @Test + public void conversionTest() throws ScriptException { + final ScriptEngineManager m = new ScriptEngineManager(); + final ScriptEngine e = m.getEngineByName("nashorn"); + final ScriptObjectMirror arr = (ScriptObjectMirror)e.eval("[33, 45, 23]"); + final int[] intArr = arr.to(int[].class); + assertEquals(intArr[0], 33); + assertEquals(intArr[1], 45); + assertEquals(intArr[2], 23); + + final List list = arr.to(List.class); + assertEquals(list.get(0), 33); + assertEquals(list.get(1), 45); + assertEquals(list.get(2), 23); + + ScriptObjectMirror obj = (ScriptObjectMirror)e.eval( + "({ valueOf: function() { return 42 } })"); + assertEquals(Double.valueOf(42.0), obj.to(Double.class)); + + obj = (ScriptObjectMirror)e.eval( + "({ toString: function() { return 'foo' } })"); + assertEquals("foo", obj.to(String.class)); + } } diff -r b9fdc55a6e28 -r c1049f63d4f5 test/src/jdk/nashorn/api/scripting/Window.java --- a/test/src/jdk/nashorn/api/scripting/Window.java Sun Nov 03 07:33:34 2013 +0000 +++ b/test/src/jdk/nashorn/api/scripting/Window.java Tue Dec 03 14:13:15 2013 +0400 @@ -25,6 +25,9 @@ package jdk.nashorn.api.scripting; +import java.util.Map; +import javax.script.Bindings; + public class Window { private String location = "http://localhost:8080/window"; @@ -63,4 +66,20 @@ System.out.println("window.setTimeout: " + delay + ", code: " + code); return 0; } + + public static Object funcJSObject(final JSObject jsobj) { + return jsobj.getMember("foo"); + } + + public static Object funcScriptObjectMirror(final ScriptObjectMirror sobj) { + return sobj.get("foo"); + } + + public static Object funcMap(final Map map) { + return map.get("foo"); + } + + public static Object funcBindings(final Bindings bindings) { + return bindings.get("foo"); + } }