From 70c48a26d4eb2d7e0d650f3e6ec1a3d34c20178b Mon Sep 17 00:00:00 2001 From: attila Date: Wed, 7 Aug 2013 16:38:44 +0200 Subject: 8022509: Various Dynalink security enhancements Reviewed-by: jlaskey, hannesw --- src/jdk/internal/dynalink/ChainedCallSite.java | 19 +---- .../internal/dynalink/DynamicLinkerFactory.java | 21 ++++- src/jdk/internal/dynalink/beans/ClassString.java | 4 - .../internal/dynalink/beans/StaticClassLinker.java | 14 +-- src/jdk/internal/dynalink/support/Backport.java | 99 ---------------------- src/jdk/internal/dynalink/support/ClassMap.java | 23 ++--- src/jdk/internal/dynalink/support/Guards.java | 25 +++--- src/jdk/internal/dynalink/support/Lookup.java | 13 +-- .../dynalink/support/TypeConverterFactory.java | 15 +++- .../nashorn/internal/runtime/linker/Bootstrap.java | 4 + 10 files changed, 74 insertions(+), 163 deletions(-) delete mode 100644 src/jdk/internal/dynalink/support/Backport.java diff --git a/src/jdk/internal/dynalink/ChainedCallSite.java b/src/jdk/internal/dynalink/ChainedCallSite.java index c242fedf..cdadd163 100644 --- a/src/jdk/internal/dynalink/ChainedCallSite.java +++ b/src/jdk/internal/dynalink/ChainedCallSite.java @@ -85,12 +85,12 @@ package jdk.internal.dynalink; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; import java.util.Iterator; import java.util.LinkedList; import java.util.concurrent.atomic.AtomicReference; import jdk.internal.dynalink.linker.GuardedInvocation; import jdk.internal.dynalink.support.AbstractRelinkableCallSite; +import jdk.internal.dynalink.support.Lookup; /** * A relinkable call site that maintains a chain of linked method handles. In the default implementation, up to 8 method @@ -103,6 +103,9 @@ import jdk.internal.dynalink.support.AbstractRelinkableCallSite; * handle is always at the start of the chain. */ public class ChainedCallSite extends AbstractRelinkableCallSite { + private static final MethodHandle PRUNE = Lookup.findOwnSpecial(MethodHandles.lookup(), "prune", MethodHandle.class, + MethodHandle.class); + private final AtomicReference> invocations = new AtomicReference<>(); /** @@ -194,18 +197,4 @@ public class ChainedCallSite extends AbstractRelinkableCallSite { private MethodHandle prune(MethodHandle relink) { return relinkInternal(null, relink, false); } - - private static final MethodHandle PRUNE; - static { - try { - PRUNE = MethodHandles.lookup().findSpecial(ChainedCallSite.class, "prune", MethodType.methodType( - MethodHandle.class, MethodHandle.class), ChainedCallSite.class); - // NOTE: using two catch blocks so we don't introduce a reference to 1.7 ReflectiveOperationException, allowing - // Dynalink to be used on 1.6 JVMs with Remi's backport library. - } catch(IllegalAccessException e) { - throw new AssertionError(e.getMessage(), e); // Can not happen - } catch(NoSuchMethodException e) { - throw new AssertionError(e.getMessage(), e); // Can not happen - } - } } diff --git a/src/jdk/internal/dynalink/DynamicLinkerFactory.java b/src/jdk/internal/dynalink/DynamicLinkerFactory.java index 0f0a347b..3cd05200 100644 --- a/src/jdk/internal/dynalink/DynamicLinkerFactory.java +++ b/src/jdk/internal/dynalink/DynamicLinkerFactory.java @@ -84,6 +84,8 @@ package jdk.internal.dynalink; import java.lang.invoke.MutableCallSite; +import java.security.AccessController; +import java.security.PrivilegedAction; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -117,7 +119,9 @@ public class DynamicLinkerFactory { */ public static final int DEFAULT_UNSTABLE_RELINK_THRESHOLD = 8; - private ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); + private boolean classLoaderExplicitlySet = false; + private ClassLoader classLoader; + private List prioritizedLinkers; private List fallbackLinkers; private int runtimeContextArgCount = 0; @@ -126,12 +130,13 @@ public class DynamicLinkerFactory { /** * Sets the class loader for automatic discovery of available linkers. If not set explicitly, then the thread - * context class loader at the time of the constructor invocation will be used. + * context class loader at the time of {@link #createLinker()} invocation will be used. * * @param classLoader the class loader used for the autodiscovery of available linkers. */ public void setClassLoader(ClassLoader classLoader) { this.classLoader = classLoader; + classLoaderExplicitlySet = true; } /** @@ -260,7 +265,8 @@ public class DynamicLinkerFactory { addClasses(knownLinkerClasses, prioritizedLinkers); addClasses(knownLinkerClasses, fallbackLinkers); - final List discovered = AutoDiscovery.loadLinkers(classLoader); + final ClassLoader effectiveClassLoader = classLoaderExplicitlySet ? classLoader : getThreadContextClassLoader(); + final List discovered = AutoDiscovery.loadLinkers(effectiveClassLoader); // Now, concatenate ... final List linkers = new ArrayList<>(prioritizedLinkers.size() + discovered.size() @@ -303,6 +309,15 @@ public class DynamicLinkerFactory { runtimeContextArgCount, syncOnRelink, unstableRelinkThreshold); } + private static ClassLoader getThreadContextClassLoader() { + return AccessController.doPrivileged(new PrivilegedAction() { + @Override + public ClassLoader run() { + return Thread.currentThread().getContextClassLoader(); + } + }); + } + private static void addClasses(Set> knownLinkerClasses, List linkers) { for(GuardingDynamicLinker linker: linkers) { diff --git a/src/jdk/internal/dynalink/beans/ClassString.java b/src/jdk/internal/dynalink/beans/ClassString.java index 8ab45727..2afbdb4f 100644 --- a/src/jdk/internal/dynalink/beans/ClassString.java +++ b/src/jdk/internal/dynalink/beans/ClassString.java @@ -112,10 +112,6 @@ final class ClassString { this(type.parameterArray()); } - Class[] getClasses() { - return classes; - } - @Override public boolean equals(Object other) { if(!(other instanceof ClassString)) { diff --git a/src/jdk/internal/dynalink/beans/StaticClassLinker.java b/src/jdk/internal/dynalink/beans/StaticClassLinker.java index c473bb4c..5f80caea 100644 --- a/src/jdk/internal/dynalink/beans/StaticClassLinker.java +++ b/src/jdk/internal/dynalink/beans/StaticClassLinker.java @@ -189,15 +189,17 @@ class StaticClassLinker implements TypeBasedGuardingDynamicLinker { return type == StaticClass.class; } - /*private*/ static final MethodHandle GET_CLASS = new Lookup(MethodHandles.lookup()).findVirtual(StaticClass.class, - "getRepresentedClass", MethodType.methodType(Class.class)); - - /*private*/ static final MethodHandle IS_CLASS = new Lookup(MethodHandles.lookup()).findStatic(StaticClassLinker.class, - "isClass", MethodType.methodType(Boolean.TYPE, Class.class, Object.class)); - + /*private*/ static final MethodHandle GET_CLASS; + /*private*/ static final MethodHandle IS_CLASS; /*private*/ static final MethodHandle ARRAY_CTOR = Lookup.PUBLIC.findStatic(Array.class, "newInstance", MethodType.methodType(Object.class, Class.class, int.class)); + static { + final Lookup lookup = new Lookup(MethodHandles.lookup()); + GET_CLASS = lookup.findVirtual(StaticClass.class, "getRepresentedClass", MethodType.methodType(Class.class)); + IS_CLASS = lookup.findOwnStatic("isClass", Boolean.TYPE, Class.class, Object.class); + } + @SuppressWarnings("unused") private static boolean isClass(Class clazz, Object obj) { return obj instanceof StaticClass && ((StaticClass)obj).getRepresentedClass() == clazz; diff --git a/src/jdk/internal/dynalink/support/Backport.java b/src/jdk/internal/dynalink/support/Backport.java deleted file mode 100644 index 1be7dc32..00000000 --- a/src/jdk/internal/dynalink/support/Backport.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * 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. - */ - -/* - * This file is available under and governed by the GNU General Public - * License version 2 only, as published by the Free Software Foundation. - * However, the following notice accompanied the original version of this - * file, and Oracle licenses the original version of this file under the BSD - * license: - */ -/* - Copyright 2009-2013 Attila Szegedi - - Licensed under both the Apache License, Version 2.0 (the "Apache License") - and the BSD License (the "BSD License"), with licensee being free to - choose either of the two at their discretion. - - You may not use this file except in compliance with either the Apache - License or the BSD License. - - If you choose to use this file in compliance with the Apache License, the - following notice applies to you: - - You may obtain a copy of the Apache License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied. See the License for the specific language governing - permissions and limitations under the License. - - If you choose to use this file in compliance with the BSD License, the - following notice applies to you: - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * Neither the name of the copyright holder nor the names of - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER - BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -package jdk.internal.dynalink.support; - -import java.lang.invoke.MethodHandles; - -/** - * @author Attila Szegedi - */ -public class Backport { - /** - * True if Remi's JSR-292 backport agent is active; false if we're using native OpenJDK JSR-292 support. - */ - public static final boolean inUse = MethodHandles.class.getName().startsWith("jsr292"); - - private Backport() { - } -} diff --git a/src/jdk/internal/dynalink/support/ClassMap.java b/src/jdk/internal/dynalink/support/ClassMap.java index 7369d255..cf52d2e5 100644 --- a/src/jdk/internal/dynalink/support/ClassMap.java +++ b/src/jdk/internal/dynalink/support/ClassMap.java @@ -85,6 +85,8 @@ package jdk.internal.dynalink.support; import java.lang.ref.Reference; import java.lang.ref.SoftReference; +import java.security.AccessController; +import java.security.PrivilegedAction; import java.util.Map; import java.util.WeakHashMap; import java.util.concurrent.ConcurrentHashMap; @@ -121,22 +123,13 @@ public abstract class ClassMap { */ protected abstract T computeValue(Class clazz); - /** - * Returns the class loader that governs the strong referenceability of this class map. - * - * @return the class loader that governs the strong referenceability of this class map. - */ - public ClassLoader getClassLoader() { - return classLoader; - } - /** * Returns the value associated with the class * * @param clazz the class * @return the value associated with the class */ - public T get(Class clazz) { + public T get(final Class clazz) { // Check in fastest first - objects we're allowed to strongly reference final T v = map.get(clazz); if(v != null) { @@ -156,8 +149,16 @@ public abstract class ClassMap { // Not found in either place; create a new value final T newV = computeValue(clazz); assert newV != null; + + final ClassLoader clazzLoader = AccessController.doPrivileged(new PrivilegedAction() { + @Override + public ClassLoader run() { + return clazz.getClassLoader(); + } + }); + // If allowed to strongly reference, put it in the fast map - if(Guards.canReferenceDirectly(classLoader, clazz.getClassLoader())) { + if(Guards.canReferenceDirectly(classLoader, clazzLoader)) { final T oldV = map.putIfAbsent(clazz, newV); return oldV != null ? oldV : newV; } diff --git a/src/jdk/internal/dynalink/support/Guards.java b/src/jdk/internal/dynalink/support/Guards.java index bab6e1dc..661cf334 100644 --- a/src/jdk/internal/dynalink/support/Guards.java +++ b/src/jdk/internal/dynalink/support/Guards.java @@ -258,23 +258,24 @@ public class Guards { type.changeReturnType(Boolean.TYPE), new int[] { pos }); } - private static final MethodHandle IS_OF_CLASS = new Lookup(MethodHandles.lookup()).findStatic(Guards.class, - "isOfClass", MethodType.methodType(Boolean.TYPE, Class.class, Object.class)); - private static final MethodHandle IS_INSTANCE = Lookup.PUBLIC.findVirtual(Class.class, "isInstance", MethodType.methodType(Boolean.TYPE, Object.class)); - private static final MethodHandle IS_ARRAY = new Lookup(MethodHandles.lookup()).findStatic(Guards.class, "isArray", - MethodType.methodType(Boolean.TYPE, Object.class)); - - private static final MethodHandle IS_IDENTICAL = new Lookup(MethodHandles.lookup()).findStatic(Guards.class, - "isIdentical", MethodType.methodType(Boolean.TYPE, Object.class, Object.class)); + private static final MethodHandle IS_OF_CLASS; + private static final MethodHandle IS_ARRAY; + private static final MethodHandle IS_IDENTICAL; + private static final MethodHandle IS_NULL; + private static final MethodHandle IS_NOT_NULL; - private static final MethodHandle IS_NULL = new Lookup(MethodHandles.lookup()).findStatic(Guards.class, - "isNull", MethodType.methodType(Boolean.TYPE, Object.class)); + static { + final Lookup lookup = new Lookup(MethodHandles.lookup()); - private static final MethodHandle IS_NOT_NULL = new Lookup(MethodHandles.lookup()).findStatic(Guards.class, - "isNotNull", MethodType.methodType(Boolean.TYPE, Object.class)); + IS_OF_CLASS = lookup.findOwnStatic("isOfClass", Boolean.TYPE, Class.class, Object.class); + IS_ARRAY = lookup.findOwnStatic("isArray", Boolean.TYPE, Object.class); + IS_IDENTICAL = lookup.findOwnStatic("isIdentical", Boolean.TYPE, Object.class, Object.class); + IS_NULL = lookup.findOwnStatic("isNull", Boolean.TYPE, Object.class); + IS_NOT_NULL = lookup.findOwnStatic("isNotNull", Boolean.TYPE, Object.class); + } /** * Creates a guard method that tests its only argument for being of an exact particular class. diff --git a/src/jdk/internal/dynalink/support/Lookup.java b/src/jdk/internal/dynalink/support/Lookup.java index 4b21e1c4..ba4ff77c 100644 --- a/src/jdk/internal/dynalink/support/Lookup.java +++ b/src/jdk/internal/dynalink/support/Lookup.java @@ -89,7 +89,6 @@ import java.lang.invoke.MethodType; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; -import java.lang.reflect.Modifier; /** * A wrapper around MethodHandles.Lookup that masks checked exceptions in those cases when you're looking up methods @@ -235,9 +234,8 @@ public class Lookup { } /** - * Performs a findSpecial on the underlying lookup, except for the backport where it rather uses unreflect. Converts - * any encountered {@link IllegalAccessException} into an {@link IllegalAccessError} and a - * {@link NoSuchMethodException} into a {@link NoSuchMethodError}. + * Performs a findSpecial on the underlying lookup. Converts any encountered {@link IllegalAccessException} into an + * {@link IllegalAccessError} and a {@link NoSuchMethodException} into a {@link NoSuchMethodError}. * * @param declaringClass class declaring the method * @param name the name of the method @@ -248,13 +246,6 @@ public class Lookup { */ public MethodHandle findSpecial(Class declaringClass, String name, MethodType type) { try { - if(Backport.inUse) { - final Method m = declaringClass.getDeclaredMethod(name, type.parameterArray()); - if(!Modifier.isPublic(declaringClass.getModifiers()) || !Modifier.isPublic(m.getModifiers())) { - m.setAccessible(true); - } - return unreflect(m); - } return lookup.findSpecial(declaringClass, name, type, declaringClass); } catch(IllegalAccessException e) { final IllegalAccessError ee = new IllegalAccessError("Failed to access special method " + methodDescription( diff --git a/src/jdk/internal/dynalink/support/TypeConverterFactory.java b/src/jdk/internal/dynalink/support/TypeConverterFactory.java index 71fb4eb7..245afc12 100644 --- a/src/jdk/internal/dynalink/support/TypeConverterFactory.java +++ b/src/jdk/internal/dynalink/support/TypeConverterFactory.java @@ -87,6 +87,8 @@ import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; import java.lang.invoke.WrongMethodTypeException; +import java.security.AccessController; +import java.security.PrivilegedAction; import java.util.LinkedList; import java.util.List; import jdk.internal.dynalink.linker.ConversionComparator; @@ -110,7 +112,7 @@ public class TypeConverterFactory { private final ClassValue> converterMap = new ClassValue>() { @Override protected ClassMap computeValue(final Class sourceType) { - return new ClassMap(sourceType.getClassLoader()) { + return new ClassMap(getClassLoader(sourceType)) { @Override protected MethodHandle computeValue(Class targetType) { try { @@ -128,7 +130,7 @@ public class TypeConverterFactory { private final ClassValue> converterIdentityMap = new ClassValue>() { @Override protected ClassMap computeValue(final Class sourceType) { - return new ClassMap(sourceType.getClassLoader()) { + return new ClassMap(getClassLoader(sourceType)) { @Override protected MethodHandle computeValue(Class targetType) { if(!canAutoConvert(sourceType, targetType)) { @@ -143,6 +145,15 @@ public class TypeConverterFactory { } }; + private static final ClassLoader getClassLoader(final Class clazz) { + return AccessController.doPrivileged(new PrivilegedAction() { + @Override + public ClassLoader run() { + return clazz.getClassLoader(); + } + }); + } + /** * Creates a new type converter factory from the available {@link GuardingTypeConverterFactory} instances. * diff --git a/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java b/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java index 421e5f62..328e15f0 100644 --- a/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java +++ b/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java @@ -68,6 +68,10 @@ public final class Bootstrap { if (relinkThreshold > -1) { factory.setUnstableRelinkThreshold(relinkThreshold); } + + // Linkers for any additional language runtimes deployed alongside Nashorn will be picked up by the factory. + factory.setClassLoader(Bootstrap.class.getClassLoader()); + dynamicLinker = factory.createLinker(); } -- cgit v1.2.3 From 11f9c9b4de0ddffb899fd9a11b403f6e7284ded4 Mon Sep 17 00:00:00 2001 From: sundar Date: Thu, 8 Aug 2013 16:38:32 +0530 Subject: 8022524: Memory leaks in nashorn sources and tests found by jhat analysis Reviewed-by: attila, hannesw --- make/project.properties | 4 +- src/jdk/nashorn/internal/codegen/CompileUnit.java | 6 +- src/jdk/nashorn/internal/objects/Global.java | 35 +++++- src/jdk/nashorn/internal/objects/NativeArray.java | 133 ++++++++++++++++----- src/jdk/nashorn/internal/objects/NativeDate.java | 19 ++- src/jdk/nashorn/internal/objects/NativeJSON.java | 36 +++++- src/jdk/nashorn/internal/objects/NativeObject.java | 19 ++- src/jdk/nashorn/internal/runtime/GlobalObject.java | 18 +++ .../nashorn/internal/runtime/JSONFunctions.java | 18 ++- src/jdk/nashorn/internal/runtime/ListAdapter.java | 112 +++++++++++++---- .../runtime/RecompilableScriptFunctionData.java | 25 ++-- .../nashorn/internal/runtime/ScriptFunction.java | 29 +++-- .../internal/runtime/UserAccessorProperty.java | 33 ++++- .../runtime/linker/JavaAdapterClassLoader.java | 10 +- .../runtime/linker/JavaAdapterFactory.java | 5 +- test/script/basic/JDK-8020357.js | 11 -- .../nashorn/api/javaaccess/BooleanAccessTest.java | 10 +- .../nashorn/api/javaaccess/MethodAccessTest.java | 10 +- .../nashorn/api/javaaccess/NumberAccessTest.java | 10 +- .../nashorn/api/javaaccess/NumberBoxingTest.java | 10 +- .../nashorn/api/javaaccess/ObjectAccessTest.java | 10 +- .../nashorn/api/javaaccess/StringAccessTest.java | 10 +- .../jdk/nashorn/internal/codegen/CompilerTest.java | 11 +- .../jdk/nashorn/internal/parser/ParserTest.java | 22 ++-- 24 files changed, 473 insertions(+), 133 deletions(-) diff --git a/make/project.properties b/make/project.properties index 57c99866..081e27b2 100644 --- a/make/project.properties +++ b/make/project.properties @@ -223,9 +223,9 @@ run.test.user.language=tr run.test.user.country=TR # -XX:+PrintCompilation -XX:+UnlockDiagnosticVMOptions -XX:+PrintNMethods -run.test.jvmargs.main=-server -Xmx${run.test.xmx} -XX:+TieredCompilation -ea -Dfile.encoding=UTF-8 -Duser.language=${run.test.user.language} -Duser.country=${run.test.user.country} +run.test.jvmargs.main=-server -Xmx${run.test.xmx} -XX:+TieredCompilation -ea -Dfile.encoding=UTF-8 -Duser.language=${run.test.user.language} -Duser.country=${run.test.user.country} -XX:+HeapDumpOnOutOfMemoryError -#-XX:+HeapDumpOnOutOfMemoryError -XX:-UseCompressedKlassPointers -XX:+PrintHeapAtGC -XX:ClassMetaspaceSize=300M +#-XX:-UseCompressedKlassPointers -XX:+PrintHeapAtGC -XX:ClassMetaspaceSize=300M run.test.jvmargs.octane.main=-Xms${run.test.xms} ${run.test.jvmargs.main} run.test.jvmsecurityargs=-Xverify:all -Djava.security.properties=${basedir}/make/java.security.override -Djava.security.manager -Djava.security.policy=${basedir}/build/nashorn.policy diff --git a/src/jdk/nashorn/internal/codegen/CompileUnit.java b/src/jdk/nashorn/internal/codegen/CompileUnit.java index ff88fa99..0156716d 100644 --- a/src/jdk/nashorn/internal/codegen/CompileUnit.java +++ b/src/jdk/nashorn/internal/codegen/CompileUnit.java @@ -33,7 +33,7 @@ public class CompileUnit { private final String className; /** Current class generator */ - private final ClassEmitter classEmitter; + private ClassEmitter classEmitter; private long weight; @@ -64,7 +64,11 @@ public class CompileUnit { * @param clazz class with code for this compile unit */ void setCode(final Class clazz) { + clazz.getClass(); // null check this.clazz = clazz; + // Revisit this - refactor to avoid null-ed out non-final fields + // null out emitter + this.classEmitter = null; } /** diff --git a/src/jdk/nashorn/internal/objects/Global.java b/src/jdk/nashorn/internal/objects/Global.java index 62288414..891e0d7c 100644 --- a/src/jdk/nashorn/internal/objects/Global.java +++ b/src/jdk/nashorn/internal/objects/Global.java @@ -41,6 +41,8 @@ import java.util.Arrays; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.concurrent.Callable; +import java.util.concurrent.ConcurrentHashMap; import jdk.internal.dynalink.linker.GuardedInvocation; import jdk.internal.dynalink.linker.LinkRequest; import jdk.nashorn.internal.objects.annotations.Attribute; @@ -72,8 +74,8 @@ import jdk.nashorn.internal.scripts.JO; */ @ScriptClass("Global") public final class Global extends ScriptObject implements GlobalObject, Scope { - private static final InvokeByName TO_STRING = new InvokeByName("toString", ScriptObject.class); - private static final InvokeByName VALUE_OF = new InvokeByName("valueOf", ScriptObject.class); + private final InvokeByName TO_STRING = new InvokeByName("toString", ScriptObject.class); + private final InvokeByName VALUE_OF = new InvokeByName("valueOf", ScriptObject.class); /** ECMA 15.1.2.2 parseInt (string , radix) */ @Property(attributes = Attribute.NOT_ENUMERABLE) @@ -709,6 +711,35 @@ public final class Global extends ScriptObject implements GlobalObject, Scope { classCache.put(source, new SoftReference>(clazz)); } + private static T getLazilyCreatedValue(final Object key, final Callable creator, final Map map) { + final T obj = map.get(key); + if (obj != null) { + return obj; + } + + try { + final T newObj = creator.call(); + final T existingObj = map.putIfAbsent(key, newObj); + return existingObj != null ? existingObj : newObj; + } catch (final Exception exp) { + throw new RuntimeException(exp); + } + } + + private final Map namedInvokers = new ConcurrentHashMap<>(); + + @Override + public InvokeByName getInvokeByName(final Object key, final Callable creator) { + return getLazilyCreatedValue(key, creator, namedInvokers); + } + + private final Map dynamicInvokers = new ConcurrentHashMap<>(); + + @Override + public MethodHandle getDynamicInvoker(final Object key, final Callable creator) { + return getLazilyCreatedValue(key, creator, dynamicInvokers); + } + /** * This is the eval used when 'indirect' eval call is made. * diff --git a/src/jdk/nashorn/internal/objects/NativeArray.java b/src/jdk/nashorn/internal/objects/NativeArray.java index 5572cb14..e03cd8dd 100644 --- a/src/jdk/nashorn/internal/objects/NativeArray.java +++ b/src/jdk/nashorn/internal/objects/NativeArray.java @@ -39,6 +39,7 @@ import java.util.Collections; import java.util.Comparator; import java.util.Iterator; import java.util.List; +import java.util.concurrent.Callable; import jdk.nashorn.api.scripting.ScriptObjectMirror; import jdk.nashorn.internal.objects.annotations.Attribute; import jdk.nashorn.internal.objects.annotations.Constructor; @@ -68,20 +69,88 @@ import jdk.nashorn.internal.runtime.linker.InvokeByName; */ @ScriptClass("Array") public final class NativeArray extends ScriptObject { - private static final InvokeByName JOIN = new InvokeByName("join", ScriptObject.class); + private static final Object JOIN = new Object(); + private static final Object EVERY_CALLBACK_INVOKER = new Object(); + private static final Object SOME_CALLBACK_INVOKER = new Object(); + private static final Object FOREACH_CALLBACK_INVOKER = new Object(); + private static final Object MAP_CALLBACK_INVOKER = new Object(); + private static final Object FILTER_CALLBACK_INVOKER = new Object(); + private static final Object REDUCE_CALLBACK_INVOKER = new Object(); + private static final Object CALL_CMP = new Object(); + private static final Object TO_LOCALE_STRING = new Object(); + + private static InvokeByName getJOIN() { + return Global.instance().getInvokeByName(JOIN, + new Callable() { + @Override + public InvokeByName call() { + return new InvokeByName("join", ScriptObject.class); + } + }); + } + + private static MethodHandle createIteratorCallbackInvoker(final Object key, final Class rtype) { + return Global.instance().getDynamicInvoker(key, + new Callable() { + @Override + public MethodHandle call() { + return Bootstrap.createDynamicInvoker("dyn:call", rtype, Object.class, Object.class, Object.class, + long.class, Object.class); + } + }); + } - private static final MethodHandle EVERY_CALLBACK_INVOKER = createIteratorCallbackInvoker(boolean.class); - private static final MethodHandle SOME_CALLBACK_INVOKER = createIteratorCallbackInvoker(boolean.class); - private static final MethodHandle FOREACH_CALLBACK_INVOKER = createIteratorCallbackInvoker(void.class); - private static final MethodHandle MAP_CALLBACK_INVOKER = createIteratorCallbackInvoker(Object.class); - private static final MethodHandle FILTER_CALLBACK_INVOKER = createIteratorCallbackInvoker(boolean.class); + private static MethodHandle getEVERY_CALLBACK_INVOKER() { + return createIteratorCallbackInvoker(EVERY_CALLBACK_INVOKER, boolean.class); + } - private static final MethodHandle REDUCE_CALLBACK_INVOKER = Bootstrap.createDynamicInvoker("dyn:call", Object.class, - Object.class, Undefined.class, Object.class, Object.class, long.class, Object.class); - private static final MethodHandle CALL_CMP = Bootstrap.createDynamicInvoker("dyn:call", double.class, - ScriptFunction.class, Object.class, Object.class, Object.class); + private static MethodHandle getSOME_CALLBACK_INVOKER() { + return createIteratorCallbackInvoker(SOME_CALLBACK_INVOKER, boolean.class); + } - private static final InvokeByName TO_LOCALE_STRING = new InvokeByName("toLocaleString", ScriptObject.class, String.class); + private static MethodHandle getFOREACH_CALLBACK_INVOKER() { + return createIteratorCallbackInvoker(FOREACH_CALLBACK_INVOKER, void.class); + } + + private static MethodHandle getMAP_CALLBACK_INVOKER() { + return createIteratorCallbackInvoker(MAP_CALLBACK_INVOKER, Object.class); + } + + private static MethodHandle getFILTER_CALLBACK_INVOKER() { + return createIteratorCallbackInvoker(FILTER_CALLBACK_INVOKER, boolean.class); + } + + private static MethodHandle getREDUCE_CALLBACK_INVOKER() { + return Global.instance().getDynamicInvoker(REDUCE_CALLBACK_INVOKER, + new Callable() { + @Override + public MethodHandle call() { + return Bootstrap.createDynamicInvoker("dyn:call", Object.class, Object.class, + Undefined.class, Object.class, Object.class, long.class, Object.class); + } + }); + } + + private static MethodHandle getCALL_CMP() { + return Global.instance().getDynamicInvoker(CALL_CMP, + new Callable() { + @Override + public MethodHandle call() { + return Bootstrap.createDynamicInvoker("dyn:call", double.class, + ScriptFunction.class, Object.class, Object.class, Object.class); + } + }); + } + + private static InvokeByName getTO_LOCALE_STRING() { + return Global.instance().getInvokeByName(TO_LOCALE_STRING, + new Callable() { + @Override + public InvokeByName call() { + return new InvokeByName("toLocaleString", ScriptObject.class, String.class); + } + }); + } // initialized by nasgen private static PropertyMap $nasgenmap$; @@ -357,11 +426,12 @@ public final class NativeArray extends ScriptObject { public static Object toString(final Object self) { final Object obj = Global.toObject(self); if (obj instanceof ScriptObject) { + final InvokeByName joinInvoker = getJOIN(); final ScriptObject sobj = (ScriptObject)obj; try { - final Object join = JOIN.getGetter().invokeExact(sobj); + final Object join = joinInvoker.getGetter().invokeExact(sobj); if (Bootstrap.isCallable(join)) { - return JOIN.getInvoker().invokeExact(join, sobj); + return joinInvoker.getInvoker().invokeExact(join, sobj); } } catch (final RuntimeException | Error e) { throw e; @@ -393,11 +463,12 @@ public final class NativeArray extends ScriptObject { try { if (val instanceof ScriptObject) { + final InvokeByName localeInvoker = getTO_LOCALE_STRING(); final ScriptObject sobj = (ScriptObject)val; - final Object toLocaleString = TO_LOCALE_STRING.getGetter().invokeExact(sobj); + final Object toLocaleString = localeInvoker.getGetter().invokeExact(sobj); if (Bootstrap.isCallable(toLocaleString)) { - sb.append((String)TO_LOCALE_STRING.getInvoker().invokeExact(toLocaleString, sobj)); + sb.append((String)localeInvoker.getInvoker().invokeExact(toLocaleString, sobj)); } else { throw typeError("not.a.function", "toLocaleString"); } @@ -814,6 +885,7 @@ public final class NativeArray extends ScriptObject { final Object cmpThis = cmp == null || cmp.isStrict() ? ScriptRuntime.UNDEFINED : Global.instance(); Collections.sort(list, new Comparator() { + private final MethodHandle call_cmp = getCALL_CMP(); @Override public int compare(final Object x, final Object y) { if (x == ScriptRuntime.UNDEFINED && y == ScriptRuntime.UNDEFINED) { @@ -826,7 +898,7 @@ public final class NativeArray extends ScriptObject { if (cmp != null) { try { - return (int)Math.signum((double)CALL_CMP.invokeExact(cmp, cmpThis, x, y)); + return (int)Math.signum((double)call_cmp.invokeExact(cmp, cmpThis, x, y)); } catch (final RuntimeException | Error e) { throw e; } catch (final Throwable t) { @@ -1103,9 +1175,11 @@ public final class NativeArray extends ScriptObject { private static boolean applyEvery(final Object self, final Object callbackfn, final Object thisArg) { return new IteratorAction(Global.toObject(self), callbackfn, thisArg, true) { + private final MethodHandle everyInvoker = getEVERY_CALLBACK_INVOKER(); + @Override protected boolean forEach(final Object val, final long i) throws Throwable { - return (result = (boolean)EVERY_CALLBACK_INVOKER.invokeExact(callbackfn, thisArg, val, i, self)); + return (result = (boolean)everyInvoker.invokeExact(callbackfn, thisArg, val, i, self)); } }.apply(); } @@ -1121,9 +1195,11 @@ public final class NativeArray extends ScriptObject { @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1) public static Object some(final Object self, final Object callbackfn, final Object thisArg) { return new IteratorAction(Global.toObject(self), callbackfn, thisArg, false) { + private final MethodHandle someInvoker = getSOME_CALLBACK_INVOKER(); + @Override protected boolean forEach(final Object val, final long i) throws Throwable { - return !(result = (boolean)SOME_CALLBACK_INVOKER.invokeExact(callbackfn, thisArg, val, i, self)); + return !(result = (boolean)someInvoker.invokeExact(callbackfn, thisArg, val, i, self)); } }.apply(); } @@ -1139,9 +1215,11 @@ public final class NativeArray extends ScriptObject { @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1) public static Object forEach(final Object self, final Object callbackfn, final Object thisArg) { return new IteratorAction(Global.toObject(self), callbackfn, thisArg, ScriptRuntime.UNDEFINED) { + private final MethodHandle forEachInvoker = getFOREACH_CALLBACK_INVOKER(); + @Override protected boolean forEach(final Object val, final long i) throws Throwable { - FOREACH_CALLBACK_INVOKER.invokeExact(callbackfn, thisArg, val, i, self); + forEachInvoker.invokeExact(callbackfn, thisArg, val, i, self); return true; } }.apply(); @@ -1158,9 +1236,11 @@ public final class NativeArray extends ScriptObject { @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1) public static Object map(final Object self, final Object callbackfn, final Object thisArg) { return new IteratorAction(Global.toObject(self), callbackfn, thisArg, null) { + private final MethodHandle mapInvoker = getMAP_CALLBACK_INVOKER(); + @Override protected boolean forEach(final Object val, final long i) throws Throwable { - final Object r = MAP_CALLBACK_INVOKER.invokeExact(callbackfn, thisArg, val, i, self); + final Object r = mapInvoker.invokeExact(callbackfn, thisArg, val, i, self); result.defineOwnProperty(ArrayIndex.getArrayIndex(index), r); return true; } @@ -1186,10 +1266,11 @@ public final class NativeArray extends ScriptObject { public static Object filter(final Object self, final Object callbackfn, final Object thisArg) { return new IteratorAction(Global.toObject(self), callbackfn, thisArg, new NativeArray()) { private long to = 0; + private final MethodHandle filterInvoker = getFILTER_CALLBACK_INVOKER(); @Override protected boolean forEach(final Object val, final long i) throws Throwable { - if ((boolean)FILTER_CALLBACK_INVOKER.invokeExact(callbackfn, thisArg, val, i, self)) { + if ((boolean)filterInvoker.invokeExact(callbackfn, thisArg, val, i, self)) { result.defineOwnProperty(ArrayIndex.getArrayIndex(to++), val); } return true; @@ -1217,10 +1298,12 @@ public final class NativeArray extends ScriptObject { //if initial value is ScriptRuntime.UNDEFINED - step forward once. return new IteratorAction(Global.toObject(self), callbackfn, ScriptRuntime.UNDEFINED, initialValue, iter) { + private final MethodHandle reduceInvoker = getREDUCE_CALLBACK_INVOKER(); + @Override protected boolean forEach(final Object val, final long i) throws Throwable { // TODO: why can't I declare the second arg as Undefined.class? - result = REDUCE_CALLBACK_INVOKER.invokeExact(callbackfn, ScriptRuntime.UNDEFINED, result, val, i, self); + result = reduceInvoker.invokeExact(callbackfn, ScriptRuntime.UNDEFINED, result, val, i, self); return true; } }.apply(); @@ -1273,10 +1356,4 @@ public final class NativeArray extends ScriptObject { return false; } - - private static MethodHandle createIteratorCallbackInvoker(final Class rtype) { - return Bootstrap.createDynamicInvoker("dyn:call", rtype, Object.class, Object.class, Object.class, - long.class, Object.class); - - } } diff --git a/src/jdk/nashorn/internal/objects/NativeDate.java b/src/jdk/nashorn/internal/objects/NativeDate.java index e12b022e..859745f3 100644 --- a/src/jdk/nashorn/internal/objects/NativeDate.java +++ b/src/jdk/nashorn/internal/objects/NativeDate.java @@ -33,6 +33,7 @@ import static jdk.nashorn.internal.runtime.ECMAErrors.typeError; import java.util.Locale; import java.util.TimeZone; +import java.util.concurrent.Callable; import jdk.nashorn.internal.objects.annotations.Attribute; import jdk.nashorn.internal.objects.annotations.Constructor; import jdk.nashorn.internal.objects.annotations.Function; @@ -95,8 +96,17 @@ public final class NativeDate extends ScriptObject { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; - private static final InvokeByName TO_ISO_STRING = new InvokeByName("toISOString", ScriptObject.class, Object.class, - Object.class); + private static final Object TO_ISO_STRING = new Object(); + + private static InvokeByName getTO_ISO_STRING() { + return Global.instance().getInvokeByName(TO_ISO_STRING, + new Callable() { + @Override + public InvokeByName call() { + return new InvokeByName("toISOString", ScriptObject.class, Object.class, Object.class); + } + }); + } private double time; private final TimeZone timezone; @@ -861,9 +871,10 @@ public final class NativeDate extends ScriptObject { } try { - final Object func = TO_ISO_STRING.getGetter().invokeExact(sobj); + final InvokeByName toIsoString = getTO_ISO_STRING(); + final Object func = toIsoString.getGetter().invokeExact(sobj); if (Bootstrap.isCallable(func)) { - return TO_ISO_STRING.getInvoker().invokeExact(func, sobj, key); + return toIsoString.getInvoker().invokeExact(func, sobj, key); } throw typeError("not.a.function", ScriptRuntime.safeToString(func)); } catch (final RuntimeException | Error e) { diff --git a/src/jdk/nashorn/internal/objects/NativeJSON.java b/src/jdk/nashorn/internal/objects/NativeJSON.java index c7e9f1c0..b2fa46d2 100644 --- a/src/jdk/nashorn/internal/objects/NativeJSON.java +++ b/src/jdk/nashorn/internal/objects/NativeJSON.java @@ -35,6 +35,7 @@ import java.util.IdentityHashMap; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.concurrent.Callable; import jdk.nashorn.internal.objects.annotations.Attribute; import jdk.nashorn.internal.objects.annotations.Function; import jdk.nashorn.internal.objects.annotations.ScriptClass; @@ -55,9 +56,31 @@ import jdk.nashorn.internal.runtime.linker.InvokeByName; */ @ScriptClass("JSON") public final class NativeJSON extends ScriptObject { - private static final InvokeByName TO_JSON = new InvokeByName("toJSON", ScriptObject.class, Object.class, Object.class); - private static final MethodHandle REPLACER_INVOKER = Bootstrap.createDynamicInvoker("dyn:call", Object.class, - ScriptFunction.class, ScriptObject.class, Object.class, Object.class); + private static final Object TO_JSON = new Object(); + + private static InvokeByName getTO_JSON() { + return Global.instance().getInvokeByName(TO_JSON, + new Callable() { + @Override + public InvokeByName call() { + return new InvokeByName("toJSON", ScriptObject.class, Object.class, Object.class); + } + }); + } + + + private static final Object REPLACER_INVOKER = new Object(); + + private static MethodHandle getREPLACER_INVOKER() { + return Global.instance().getDynamicInvoker(REPLACER_INVOKER, + new Callable() { + @Override + public MethodHandle call() { + return Bootstrap.createDynamicInvoker("dyn:call", Object.class, + ScriptFunction.class, ScriptObject.class, Object.class, Object.class); + } + }); + } // initialized by nasgen @SuppressWarnings("unused") @@ -187,15 +210,16 @@ public final class NativeJSON extends ScriptObject { try { if (value instanceof ScriptObject) { + final InvokeByName toJSONInvoker = getTO_JSON(); final ScriptObject svalue = (ScriptObject)value; - final Object toJSON = TO_JSON.getGetter().invokeExact(svalue); + final Object toJSON = toJSONInvoker.getGetter().invokeExact(svalue); if (Bootstrap.isCallable(toJSON)) { - value = TO_JSON.getInvoker().invokeExact(toJSON, svalue, key); + value = toJSONInvoker.getInvoker().invokeExact(toJSON, svalue, key); } } if (state.replacerFunction != null) { - value = REPLACER_INVOKER.invokeExact(state.replacerFunction, holder, key, value); + value = getREPLACER_INVOKER().invokeExact(state.replacerFunction, holder, key, value); } } catch(Error|RuntimeException t) { throw t; diff --git a/src/jdk/nashorn/internal/objects/NativeObject.java b/src/jdk/nashorn/internal/objects/NativeObject.java index 65904053..ff72ce5c 100644 --- a/src/jdk/nashorn/internal/objects/NativeObject.java +++ b/src/jdk/nashorn/internal/objects/NativeObject.java @@ -36,6 +36,7 @@ import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Set; +import java.util.concurrent.Callable; import jdk.internal.dynalink.beans.BeansLinker; import jdk.internal.dynalink.beans.StaticClass; import jdk.internal.dynalink.linker.GuardedInvocation; @@ -70,7 +71,18 @@ import jdk.nashorn.internal.runtime.linker.InvokeByName; */ @ScriptClass("Object") public final class NativeObject { - private static final InvokeByName TO_STRING = new InvokeByName("toString", ScriptObject.class); + private static final Object TO_STRING = new Object(); + + private static InvokeByName getTO_STRING() { + return Global.instance().getInvokeByName(TO_STRING, + new Callable() { + @Override + public InvokeByName call() { + return new InvokeByName("toString", ScriptObject.class); + } + }); + } + private static final MethodType MIRROR_GETTER_TYPE = MethodType.methodType(Object.class, ScriptObjectMirror.class); private static final MethodType MIRROR_SETTER_TYPE = MethodType.methodType(Object.class, ScriptObjectMirror.class, Object.class); @@ -402,12 +414,13 @@ public final class NativeObject { public static Object toLocaleString(final Object self) { final Object obj = JSType.toScriptObject(self); if (obj instanceof ScriptObject) { + final InvokeByName toStringInvoker = getTO_STRING(); final ScriptObject sobj = (ScriptObject)self; try { - final Object toString = TO_STRING.getGetter().invokeExact(sobj); + final Object toString = toStringInvoker.getGetter().invokeExact(sobj); if (Bootstrap.isCallable(toString)) { - return TO_STRING.getInvoker().invokeExact(toString, sobj); + return toStringInvoker.getInvoker().invokeExact(toString, sobj); } } catch (final RuntimeException | Error e) { throw e; diff --git a/src/jdk/nashorn/internal/runtime/GlobalObject.java b/src/jdk/nashorn/internal/runtime/GlobalObject.java index 7a118290..087b3455 100644 --- a/src/jdk/nashorn/internal/runtime/GlobalObject.java +++ b/src/jdk/nashorn/internal/runtime/GlobalObject.java @@ -26,8 +26,10 @@ package jdk.nashorn.internal.runtime; import java.lang.invoke.MethodHandle; +import java.util.concurrent.Callable; import jdk.internal.dynalink.linker.GuardedInvocation; import jdk.internal.dynalink.linker.LinkRequest; +import jdk.nashorn.internal.runtime.linker.InvokeByName; /** * Runtime interface to the global scope objects. @@ -210,4 +212,20 @@ public interface GlobalObject { * @param clazz compiled Class object for the source */ public void cacheClass(Source source, Class clazz); + + /** + * Get cached InvokeByName object for the given key + * @param key key to be associated with InvokeByName object + * @param creator if InvokeByName is absent 'creator' is called to make one (lazy init) + * @return InvokeByName object associated with the key. + */ + public InvokeByName getInvokeByName(final Object key, final Callable creator); + + /** + * Get cached dynamic method handle for the given key + * @param key key to be associated with dynamic method handle + * @param creator if method handle is absent 'creator' is called to make one (lazy init) + * @return dynamic method handle associated with the key. + */ + public MethodHandle getDynamicInvoker(final Object key, final Callable creator); } diff --git a/src/jdk/nashorn/internal/runtime/JSONFunctions.java b/src/jdk/nashorn/internal/runtime/JSONFunctions.java index 2895cb85..73552cb1 100644 --- a/src/jdk/nashorn/internal/runtime/JSONFunctions.java +++ b/src/jdk/nashorn/internal/runtime/JSONFunctions.java @@ -27,6 +27,7 @@ package jdk.nashorn.internal.runtime; import java.lang.invoke.MethodHandle; import java.util.Iterator; +import java.util.concurrent.Callable; import jdk.nashorn.internal.ir.LiteralNode; import jdk.nashorn.internal.ir.Node; import jdk.nashorn.internal.ir.ObjectNode; @@ -42,8 +43,19 @@ import jdk.nashorn.internal.runtime.linker.Bootstrap; */ public final class JSONFunctions { private JSONFunctions() {} - private static final MethodHandle REVIVER_INVOKER = Bootstrap.createDynamicInvoker("dyn:call", Object.class, - ScriptFunction.class, ScriptObject.class, String.class, Object.class); + + private static final Object REVIVER_INVOKER = new Object(); + + private static MethodHandle getREVIVER_INVOKER() { + return ((GlobalObject)Context.getGlobal()).getDynamicInvoker(REVIVER_INVOKER, + new Callable() { + @Override + public MethodHandle call() { + return Bootstrap.createDynamicInvoker("dyn:call", Object.class, + ScriptFunction.class, ScriptObject.class, String.class, Object.class); + } + }); + } /** * Returns JSON-compatible quoted version of the given string. @@ -117,7 +129,7 @@ public final class JSONFunctions { try { // Object.class, ScriptFunction.class, ScriptObject.class, String.class, Object.class); - return REVIVER_INVOKER.invokeExact(reviver, holder, JSType.toString(name), val); + return getREVIVER_INVOKER().invokeExact(reviver, holder, JSType.toString(name), val); } catch(Error|RuntimeException t) { throw t; } catch(final Throwable t) { diff --git a/src/jdk/nashorn/internal/runtime/ListAdapter.java b/src/jdk/nashorn/internal/runtime/ListAdapter.java index 1d5603f6..ae6d7446 100644 --- a/src/jdk/nashorn/internal/runtime/ListAdapter.java +++ b/src/jdk/nashorn/internal/runtime/ListAdapter.java @@ -31,6 +31,7 @@ import java.util.Iterator; import java.util.ListIterator; import java.util.NoSuchElementException; import java.util.RandomAccess; +import java.util.concurrent.Callable; import jdk.nashorn.internal.runtime.linker.Bootstrap; import jdk.nashorn.internal.runtime.linker.InvokeByName; @@ -49,16 +50,73 @@ import jdk.nashorn.internal.runtime.linker.InvokeByName; */ public final class ListAdapter extends AbstractList implements RandomAccess, Deque { // These add to the back and front of the list - private static final InvokeByName PUSH = new InvokeByName("push", ScriptObject.class, void.class, Object.class); - private static final InvokeByName UNSHIFT = new InvokeByName("unshift", ScriptObject.class, void.class, Object.class); + private static final Object PUSH = new Object(); + private static InvokeByName getPUSH() { + return ((GlobalObject)Context.getGlobal()).getInvokeByName(PUSH, + new Callable() { + @Override + public InvokeByName call() { + return new InvokeByName("push", ScriptObject.class, void.class, Object.class); + } + }); + } + + private static final Object UNSHIFT = new Object(); + private static InvokeByName getUNSHIFT() { + return ((GlobalObject)Context.getGlobal()).getInvokeByName(UNSHIFT, + new Callable() { + @Override + public InvokeByName call() { + return new InvokeByName("unshift", ScriptObject.class, void.class, Object.class); + } + }); + } // These remove from the back and front of the list - private static final InvokeByName POP = new InvokeByName("pop", ScriptObject.class, Object.class); - private static final InvokeByName SHIFT = new InvokeByName("shift", ScriptObject.class, Object.class); + private static final Object POP = new Object(); + private static InvokeByName getPOP() { + return ((GlobalObject)Context.getGlobal()).getInvokeByName(POP, + new Callable() { + @Override + public InvokeByName call() { + return new InvokeByName("pop", ScriptObject.class, Object.class); + } + }); + } + + private static final Object SHIFT = new Object(); + private static InvokeByName getSHIFT() { + return ((GlobalObject)Context.getGlobal()).getInvokeByName(SHIFT, + new Callable() { + @Override + public InvokeByName call() { + return new InvokeByName("shift", ScriptObject.class, Object.class); + } + }); + } // These insert and remove in the middle of the list - private static final InvokeByName SPLICE_ADD = new InvokeByName("splice", ScriptObject.class, void.class, int.class, int.class, Object.class); - private static final InvokeByName SPLICE_REMOVE = new InvokeByName("splice", ScriptObject.class, void.class, int.class, int.class); + private static final Object SPLICE_ADD = new Object(); + private static InvokeByName getSPLICE_ADD() { + return ((GlobalObject)Context.getGlobal()).getInvokeByName(SPLICE_ADD, + new Callable() { + @Override + public InvokeByName call() { + return new InvokeByName("splice", ScriptObject.class, void.class, int.class, int.class, Object.class); + } + }); + } + + private static final Object SPLICE_REMOVE = new Object(); + private static InvokeByName getSPLICE_REMOVE() { + return ((GlobalObject)Context.getGlobal()).getInvokeByName(SPLICE_REMOVE, + new Callable() { + @Override + public InvokeByName call() { + return new InvokeByName("splice", ScriptObject.class, void.class, int.class, int.class); + } + }); + } private final ScriptObject obj; @@ -109,9 +167,10 @@ public final class ListAdapter extends AbstractList implements RandomAcc @Override public void addFirst(Object e) { try { - final Object fn = UNSHIFT.getGetter().invokeExact(obj); - checkFunction(fn, UNSHIFT); - UNSHIFT.getInvoker().invokeExact(fn, obj, e); + final InvokeByName unshiftInvoker = getUNSHIFT(); + final Object fn = unshiftInvoker.getGetter().invokeExact(obj); + checkFunction(fn, unshiftInvoker); + unshiftInvoker.getInvoker().invokeExact(fn, obj, e); } catch(RuntimeException | Error ex) { throw ex; } catch(Throwable t) { @@ -122,9 +181,10 @@ public final class ListAdapter extends AbstractList implements RandomAcc @Override public void addLast(Object e) { try { - final Object fn = PUSH.getGetter().invokeExact(obj); - checkFunction(fn, PUSH); - PUSH.getInvoker().invokeExact(fn, obj, e); + final InvokeByName pushInvoker = getPUSH(); + final Object fn = pushInvoker.getGetter().invokeExact(obj); + checkFunction(fn, pushInvoker); + pushInvoker.getInvoker().invokeExact(fn, obj, e); } catch(RuntimeException | Error ex) { throw ex; } catch(Throwable t) { @@ -142,9 +202,10 @@ public final class ListAdapter extends AbstractList implements RandomAcc } else { final int size = size(); if(index < size) { - final Object fn = SPLICE_ADD.getGetter().invokeExact(obj); - checkFunction(fn, SPLICE_ADD); - SPLICE_ADD.getInvoker().invokeExact(fn, obj, index, 0, e); + final InvokeByName spliceAddInvoker = getSPLICE_ADD(); + final Object fn = spliceAddInvoker.getGetter().invokeExact(obj); + checkFunction(fn, spliceAddInvoker); + spliceAddInvoker.getInvoker().invokeExact(fn, obj, index, 0, e); } else if(index == size) { addLast(e); } else { @@ -234,9 +295,10 @@ public final class ListAdapter extends AbstractList implements RandomAcc private Object invokeShift() { try { - final Object fn = SHIFT.getGetter().invokeExact(obj); - checkFunction(fn, SHIFT); - return SHIFT.getInvoker().invokeExact(fn, obj); + final InvokeByName shiftInvoker = getSHIFT(); + final Object fn = shiftInvoker.getGetter().invokeExact(obj); + checkFunction(fn, shiftInvoker); + return shiftInvoker.getInvoker().invokeExact(fn, obj); } catch(RuntimeException | Error ex) { throw ex; } catch(Throwable t) { @@ -246,9 +308,10 @@ public final class ListAdapter extends AbstractList implements RandomAcc private Object invokePop() { try { - final Object fn = POP.getGetter().invokeExact(obj); - checkFunction(fn, POP); - return POP.getInvoker().invokeExact(fn, obj); + final InvokeByName popInvoker = getPOP(); + final Object fn = popInvoker.getGetter().invokeExact(obj); + checkFunction(fn, popInvoker); + return popInvoker.getInvoker().invokeExact(fn, obj); } catch(RuntimeException | Error ex) { throw ex; } catch(Throwable t) { @@ -263,9 +326,10 @@ public final class ListAdapter extends AbstractList implements RandomAcc private void invokeSpliceRemove(int fromIndex, int count) { try { - final Object fn = SPLICE_REMOVE.getGetter().invokeExact(obj); - checkFunction(fn, SPLICE_REMOVE); - SPLICE_REMOVE.getInvoker().invokeExact(fn, obj, fromIndex, count); + final InvokeByName spliceRemoveInvoker = getSPLICE_REMOVE(); + final Object fn = spliceRemoveInvoker.getGetter().invokeExact(obj); + checkFunction(fn, spliceRemoveInvoker); + spliceRemoveInvoker.getInvoker().invokeExact(fn, obj, fromIndex, count); } catch(RuntimeException | Error ex) { throw ex; } catch(Throwable t) { diff --git a/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java b/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java index 226d83d1..859a688c 100644 --- a/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java +++ b/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java @@ -52,13 +52,19 @@ import jdk.nashorn.internal.parser.TokenType; public final class RecompilableScriptFunctionData extends ScriptFunctionData { /** FunctionNode with the code for this ScriptFunction */ - private FunctionNode functionNode; + private volatile FunctionNode functionNode; + + /** Source from which FunctionNode was parsed. */ + private final Source source; + + /** Token of this function within the source. */ + private final long token; /** Allocator map from makeMap() */ private final PropertyMap allocatorMap; /** Code installer used for all further recompilation/specialization of this ScriptFunction */ - private final CodeInstaller installer; + private volatile CodeInstaller installer; /** Name of class where allocator function resides */ private final String allocatorClassName; @@ -103,6 +109,8 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData { true); this.functionNode = functionNode; + this.source = functionNode.getSource(); + this.token = tokenFor(functionNode); this.installer = installer; this.allocatorClassName = allocatorClassName; this.allocatorMap = allocatorMap; @@ -110,9 +118,6 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData { @Override String toSource() { - final Source source = functionNode.getSource(); - final long token = tokenFor(functionNode); - if (source != null && token != 0) { return source.getString(Token.descPosition(token), Token.descLength(token)); } @@ -123,8 +128,6 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData { @Override public String toString() { final StringBuilder sb = new StringBuilder(); - final Source source = functionNode.getSource(); - final long token = tokenFor(functionNode); if (source != null) { sb.append(source.getName()) @@ -190,6 +193,12 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData { // code exists - look it up and add it into the automatically sorted invoker list addCode(functionNode); + + if (! functionNode.canSpecialize()) { + // allow GC to claim IR stuff that is not needed anymore + functionNode = null; + installer = null; + } } private MethodHandle addCode(final FunctionNode fn) { @@ -325,7 +334,7 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData { * footprint too large to store a parse snapshot, or if it is meaningless * to do so, such as e.g. for runScript */ - if (!functionNode.canSpecialize()) { + if (functionNode == null || !functionNode.canSpecialize()) { return mh; } diff --git a/src/jdk/nashorn/internal/runtime/ScriptFunction.java b/src/jdk/nashorn/internal/runtime/ScriptFunction.java index 50f2b074..564f1946 100644 --- a/src/jdk/nashorn/internal/runtime/ScriptFunction.java +++ b/src/jdk/nashorn/internal/runtime/ScriptFunction.java @@ -496,32 +496,24 @@ public abstract class ScriptFunction extends ScriptObject { MethodHandle boundHandle; MethodHandle guard = null; + final boolean scopeCall = NashornCallSiteDescriptor.isScope(desc); + if (data.needsCallee()) { final MethodHandle callHandle = getBestInvoker(type, request.getArguments()); - if (NashornCallSiteDescriptor.isScope(desc)) { + if (scopeCall) { // Make a handle that drops the passed "this" argument and substitutes either Global or Undefined // (callee, this, args...) => (callee, args...) boundHandle = MH.insertArguments(callHandle, 1, needsWrappedThis() ? Context.getGlobalTrusted() : ScriptRuntime.UNDEFINED); // (callee, args...) => (callee, [this], args...) boundHandle = MH.dropArguments(boundHandle, 1, Object.class); + } else { // It's already (callee, this, args...), just what we need boundHandle = callHandle; - - // For non-strict functions, check whether this-object is primitive type. - // If so add a to-object-wrapper argument filter. - // Else install a guard that will trigger a relink when the argument becomes primitive. - if (needsWrappedThis()) { - if (ScriptFunctionData.isPrimitiveThis(request.getArguments()[1])) { - boundHandle = MH.filterArguments(boundHandle, 1, WRAPFILTER); - } else { - guard = getNonStrictFunctionGuard(this); - } - } } } else { final MethodHandle callHandle = getBestInvoker(type.dropParameterTypes(0, 1), request.getArguments()); - if (NashornCallSiteDescriptor.isScope(desc)) { + if (scopeCall) { // Make a handle that drops the passed "this" argument and substitutes either Global or Undefined // (this, args...) => (args...) boundHandle = MH.bindTo(callHandle, needsWrappedThis() ? Context.getGlobalTrusted() : ScriptRuntime.UNDEFINED); @@ -533,6 +525,17 @@ public abstract class ScriptFunction extends ScriptObject { } } + // For non-strict functions, check whether this-object is primitive type. + // If so add a to-object-wrapper argument filter. + // Else install a guard that will trigger a relink when the argument becomes primitive. + if (!scopeCall && needsWrappedThis()) { + if (ScriptFunctionData.isPrimitiveThis(request.getArguments()[1])) { + boundHandle = MH.filterArguments(boundHandle, 1, WRAPFILTER); + } else { + guard = getNonStrictFunctionGuard(this); + } + } + boundHandle = pairArguments(boundHandle, type); return new GuardedInvocation(boundHandle, guard == null ? getFunctionGuard(this) : guard); diff --git a/src/jdk/nashorn/internal/runtime/UserAccessorProperty.java b/src/jdk/nashorn/internal/runtime/UserAccessorProperty.java index 7f4659c0..931d712b 100644 --- a/src/jdk/nashorn/internal/runtime/UserAccessorProperty.java +++ b/src/jdk/nashorn/internal/runtime/UserAccessorProperty.java @@ -27,6 +27,7 @@ package jdk.nashorn.internal.runtime; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; +import java.util.concurrent.Callable; import jdk.nashorn.internal.codegen.CompilerConstants; import jdk.nashorn.internal.lookup.Lookup; @@ -68,12 +69,32 @@ public final class UserAccessorProperty extends Property { "userAccessorSetter", void.class, ScriptObject.class, int.class, String.class, Object.class, Object.class); /** Dynamic invoker for getter */ - private static final MethodHandle INVOKE_UA_GETTER = Bootstrap.createDynamicInvoker("dyn:call", Object.class, - Object.class, Object.class); + private static final Object INVOKE_UA_GETTER = new Object(); + + private static MethodHandle getINVOKE_UA_GETTER() { + + return ((GlobalObject)Context.getGlobal()).getDynamicInvoker(INVOKE_UA_GETTER, + new Callable() { + @Override + public MethodHandle call() { + return Bootstrap.createDynamicInvoker("dyn:call", Object.class, + Object.class, Object.class); + } + }); + } /** Dynamic invoker for setter */ - private static final MethodHandle INVOKE_UA_SETTER = Bootstrap.createDynamicInvoker("dyn:call", void.class, - Object.class, Object.class, Object.class); + private static Object INVOKE_UA_SETTER = new Object(); + private static MethodHandle getINVOKE_UA_SETTER() { + return ((GlobalObject)Context.getGlobal()).getDynamicInvoker(INVOKE_UA_SETTER, + new Callable() { + @Override + public MethodHandle call() { + return Bootstrap.createDynamicInvoker("dyn:call", void.class, + Object.class, Object.class, Object.class); + } + }); + } /** * Constructor @@ -191,7 +212,7 @@ public final class UserAccessorProperty extends Property { if (func instanceof ScriptFunction) { try { - return INVOKE_UA_GETTER.invokeExact(func, self); + return getINVOKE_UA_GETTER().invokeExact(func, self); } catch(final Error|RuntimeException t) { throw t; } catch(final Throwable t) { @@ -208,7 +229,7 @@ public final class UserAccessorProperty extends Property { if (func instanceof ScriptFunction) { try { - INVOKE_UA_SETTER.invokeExact(func, self, value); + getINVOKE_UA_SETTER().invokeExact(func, self, value); } catch(final Error|RuntimeException t) { throw t; } catch(final Throwable t) { diff --git a/src/jdk/nashorn/internal/runtime/linker/JavaAdapterClassLoader.java b/src/jdk/nashorn/internal/runtime/linker/JavaAdapterClassLoader.java index 73c05636..059ed552 100644 --- a/src/jdk/nashorn/internal/runtime/linker/JavaAdapterClassLoader.java +++ b/src/jdk/nashorn/internal/runtime/linker/JavaAdapterClassLoader.java @@ -48,13 +48,20 @@ final class JavaAdapterClassLoader { private static final ProtectionDomain GENERATED_PROTECTION_DOMAIN = createGeneratedProtectionDomain(); private final String className; - private final byte[] classBytes; + private volatile byte[] classBytes; JavaAdapterClassLoader(String className, byte[] classBytes) { this.className = className.replace('/', '.'); this.classBytes = classBytes; } + /** + * clear classBytes after loading class. + */ + void clearClassBytes() { + this.classBytes = null; + } + /** * Loads the generated adapter class into the JVM. * @param parentLoader the parent class loader for the generated class loader @@ -103,6 +110,7 @@ final class JavaAdapterClassLoader { @Override protected Class findClass(final String name) throws ClassNotFoundException { if(name.equals(className)) { + assert classBytes != null : "what? already cleared .class bytes!!"; return defineClass(name, classBytes, 0, classBytes.length, GENERATED_PROTECTION_DOMAIN); } else { throw new ClassNotFoundException(name); diff --git a/src/jdk/nashorn/internal/runtime/linker/JavaAdapterFactory.java b/src/jdk/nashorn/internal/runtime/linker/JavaAdapterFactory.java index 93c2dd39..4c005a27 100644 --- a/src/jdk/nashorn/internal/runtime/linker/JavaAdapterFactory.java +++ b/src/jdk/nashorn/internal/runtime/linker/JavaAdapterFactory.java @@ -224,7 +224,10 @@ public final class JavaAdapterFactory { this.commonLoader = findCommonLoader(definingLoader); final JavaAdapterBytecodeGenerator gen = new JavaAdapterBytecodeGenerator(superClass, interfaces, commonLoader, false); this.autoConvertibleFromFunction = gen.isAutoConvertibleFromFunction(); - this.instanceAdapterClass = gen.createAdapterClassLoader().generateClass(commonLoader); + final JavaAdapterClassLoader jacl = gen.createAdapterClassLoader(); + this.instanceAdapterClass = jacl.generateClass(commonLoader); + // loaded Class - no need to keep class bytes around + jacl.clearClassBytes(); this.adapterGenerator = new JavaAdapterBytecodeGenerator(superClass, interfaces, commonLoader, true).createAdapterClassLoader(); this.adaptationResult = AdaptationResult.SUCCESSFUL_RESULT; } diff --git a/test/script/basic/JDK-8020357.js b/test/script/basic/JDK-8020357.js index e74bca8a..69406371 100644 --- a/test/script/basic/JDK-8020357.js +++ b/test/script/basic/JDK-8020357.js @@ -33,17 +33,6 @@ var BYTES_PER_INT_32 = 4 var limit = Math.pow(2, UNSIGNED_INT_BITS)/BYTES_PER_INT_32 -try { - // A value at or under the limit should either succeed if we have - // enough heap, or throw an OutOfMemoryError if we don't. - Int32Array(limit - 1) -} catch(e) { - if(!(e instanceof java.lang.OutOfMemoryError)) { - // Only print an unexpected result; OutOfMemoryError is expected - print(e) - } -} - // A value over the limit should throw a RangeError. try { Int32Array(limit) diff --git a/test/src/jdk/nashorn/api/javaaccess/BooleanAccessTest.java b/test/src/jdk/nashorn/api/javaaccess/BooleanAccessTest.java index 030bb1e5..19873564 100644 --- a/test/src/jdk/nashorn/api/javaaccess/BooleanAccessTest.java +++ b/test/src/jdk/nashorn/api/javaaccess/BooleanAccessTest.java @@ -33,6 +33,7 @@ import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; import javax.script.ScriptException; import org.testng.TestNG; +import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; @@ -44,7 +45,7 @@ import org.testng.annotations.Test; public class BooleanAccessTest { private static ScriptEngine e = null; - private static SharedObject o = new SharedObject(); + private static SharedObject o = null; public static void main(final String[] args) { TestNG.main(args); @@ -54,10 +55,17 @@ public class BooleanAccessTest { public static void setUpClass() throws ScriptException { final ScriptEngineManager m = new ScriptEngineManager(); e = m.getEngineByName("nashorn"); + o = new SharedObject(); e.put("o", o); e.eval("var SharedObject = Packages.jdk.nashorn.api.javaaccess.SharedObject;"); } + @AfterClass + public static void tearDownClass() { + e = null; + o = null; + } + @Test public void accessFieldBoolean() throws ScriptException { e.eval("var p_boolean = o.publicBoolean;"); diff --git a/test/src/jdk/nashorn/api/javaaccess/MethodAccessTest.java b/test/src/jdk/nashorn/api/javaaccess/MethodAccessTest.java index 6de10a54..14207b7d 100644 --- a/test/src/jdk/nashorn/api/javaaccess/MethodAccessTest.java +++ b/test/src/jdk/nashorn/api/javaaccess/MethodAccessTest.java @@ -36,6 +36,7 @@ import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; import javax.script.ScriptException; import org.testng.TestNG; +import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; @@ -47,7 +48,7 @@ import org.testng.annotations.Test; public class MethodAccessTest { private static ScriptEngine e = null; - private static SharedObject o = new SharedObject(); + private static SharedObject o = null; public static void main(final String[] args) { TestNG.main(args); @@ -57,12 +58,19 @@ public class MethodAccessTest { public static void setUpClass() throws ScriptException { final ScriptEngineManager m = new ScriptEngineManager(); e = m.getEngineByName("nashorn"); + o = new SharedObject(); o.setEngine(e); e.put("o", o); e.eval("var SharedObject = Packages.jdk.nashorn.api.javaaccess.SharedObject;"); e.eval("var Person = Packages.jdk.nashorn.api.javaaccess.Person;"); } + @AfterClass + public static void tearDownClass() { + e = null; + o = null; + } + @Test public void accessMethodthrowsCheckedException() throws ScriptException { e.eval("try {" + diff --git a/test/src/jdk/nashorn/api/javaaccess/NumberAccessTest.java b/test/src/jdk/nashorn/api/javaaccess/NumberAccessTest.java index 49f193e9..116d1cf4 100644 --- a/test/src/jdk/nashorn/api/javaaccess/NumberAccessTest.java +++ b/test/src/jdk/nashorn/api/javaaccess/NumberAccessTest.java @@ -33,6 +33,7 @@ import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; import javax.script.ScriptException; import org.testng.TestNG; +import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; @@ -44,7 +45,7 @@ import org.testng.annotations.Test; public class NumberAccessTest { private static ScriptEngine e = null; - private static SharedObject o = new SharedObject(); + private static SharedObject o = null; public static void main(final String[] args) { TestNG.main(args); @@ -54,10 +55,17 @@ public class NumberAccessTest { public static void setUpClass() throws ScriptException { final ScriptEngineManager m = new ScriptEngineManager(); e = m.getEngineByName("nashorn"); + o = new SharedObject(); e.put("o", o); e.eval("var SharedObject = Packages.jdk.nashorn.api.javaaccess.SharedObject;"); } + @AfterClass + public static void tearDownClass() { + e = null; + o = null; + } + // --------------------------------long // tests------------------------------------ @Test diff --git a/test/src/jdk/nashorn/api/javaaccess/NumberBoxingTest.java b/test/src/jdk/nashorn/api/javaaccess/NumberBoxingTest.java index 0302259e..03e30752 100644 --- a/test/src/jdk/nashorn/api/javaaccess/NumberBoxingTest.java +++ b/test/src/jdk/nashorn/api/javaaccess/NumberBoxingTest.java @@ -32,6 +32,7 @@ import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; import javax.script.ScriptException; import org.testng.TestNG; +import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; @@ -43,7 +44,7 @@ import org.testng.annotations.Test; public class NumberBoxingTest { private static ScriptEngine e = null; - private static SharedObject o = new SharedObject(); + private static SharedObject o = null; public static void main(final String[] args) { TestNG.main(args); @@ -53,10 +54,17 @@ public class NumberBoxingTest { public static void setUpClass() throws ScriptException { final ScriptEngineManager m = new ScriptEngineManager(); e = m.getEngineByName("nashorn"); + o = new SharedObject(); e.put("o", o); e.eval("var SharedObject = Packages.jdk.nashorn.api.javaaccess.SharedObject;"); } + @AfterClass + public static void tearDownClass() { + e = null; + o = null; + } + // --------------------------------long // tests------------------------------------ @Test diff --git a/test/src/jdk/nashorn/api/javaaccess/ObjectAccessTest.java b/test/src/jdk/nashorn/api/javaaccess/ObjectAccessTest.java index de0fd8ee..9c1fa114 100644 --- a/test/src/jdk/nashorn/api/javaaccess/ObjectAccessTest.java +++ b/test/src/jdk/nashorn/api/javaaccess/ObjectAccessTest.java @@ -32,6 +32,7 @@ import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; import javax.script.ScriptException; import org.testng.TestNG; +import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; @@ -43,7 +44,7 @@ import org.testng.annotations.Test; public class ObjectAccessTest { private static ScriptEngine e = null; - private static SharedObject o = new SharedObject(); + private static SharedObject o = null; public static void main(final String[] args) { TestNG.main(args); @@ -53,11 +54,18 @@ public class ObjectAccessTest { public static void setUpClass() throws ScriptException { final ScriptEngineManager m = new ScriptEngineManager(); e = m.getEngineByName("nashorn"); + o = new SharedObject(); e.put("o", o); e.eval("var SharedObject = Packages.jdk.nashorn.api.javaaccess.SharedObject;"); e.eval("var Person = Packages.jdk.nashorn.api.javaaccess.Person;"); } + @AfterClass + public static void tearDownClass() { + e = null; + o = null; + } + @Test public void accessFieldObject() throws ScriptException { e.eval("var p_object = o.publicObject;"); diff --git a/test/src/jdk/nashorn/api/javaaccess/StringAccessTest.java b/test/src/jdk/nashorn/api/javaaccess/StringAccessTest.java index 55624360..7b6a11f1 100644 --- a/test/src/jdk/nashorn/api/javaaccess/StringAccessTest.java +++ b/test/src/jdk/nashorn/api/javaaccess/StringAccessTest.java @@ -32,6 +32,7 @@ import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; import javax.script.ScriptException; import org.testng.TestNG; +import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; @@ -43,7 +44,7 @@ import org.testng.annotations.Test; public class StringAccessTest { private static ScriptEngine e = null; - private static SharedObject o = new SharedObject(); + private static SharedObject o = null; public static void main(final String[] args) { TestNG.main(args); @@ -53,10 +54,17 @@ public class StringAccessTest { public static void setUpClass() throws ScriptException { final ScriptEngineManager m = new ScriptEngineManager(); e = m.getEngineByName("nashorn"); + o = new SharedObject(); e.put("o", o); e.eval("var SharedObject = Packages.jdk.nashorn.api.javaaccess.SharedObject;"); } + @AfterClass + public static void tearDownClass() { + e = null; + o = null; + } + @Test public void accessFieldString() throws ScriptException { e.eval("var p_string = o.publicString;"); diff --git a/test/src/jdk/nashorn/internal/codegen/CompilerTest.java b/test/src/jdk/nashorn/internal/codegen/CompilerTest.java index 3cbe1ed4..00d79acb 100644 --- a/test/src/jdk/nashorn/internal/codegen/CompilerTest.java +++ b/test/src/jdk/nashorn/internal/codegen/CompilerTest.java @@ -35,6 +35,8 @@ import jdk.nashorn.internal.runtime.ScriptObject; import jdk.nashorn.internal.runtime.Source; import jdk.nashorn.internal.runtime.options.Options; import org.testng.Assert; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; /** @@ -58,7 +60,8 @@ public class CompilerTest { private Context context; private ScriptObject global; - public CompilerTest() { + @BeforeClass + public void setupTest() { final Options options = new Options("nashorn"); options.set("anon.functions", true); options.set("compile.only", true); @@ -79,6 +82,12 @@ public class CompilerTest { this.global = context.createGlobal(); } + @AfterClass + public void tearDownTest() { + this.context = null; + this.global = null; + } + @Test public void compileAllTests() { if (TEST262) { diff --git a/test/src/jdk/nashorn/internal/parser/ParserTest.java b/test/src/jdk/nashorn/internal/parser/ParserTest.java index afffe051..3e10a89e 100644 --- a/test/src/jdk/nashorn/internal/parser/ParserTest.java +++ b/test/src/jdk/nashorn/internal/parser/ParserTest.java @@ -28,10 +28,11 @@ package jdk.nashorn.internal.parser; import java.io.File; import jdk.nashorn.internal.runtime.Context; import jdk.nashorn.internal.runtime.ErrorManager; -import jdk.nashorn.internal.runtime.ScriptObject; import jdk.nashorn.internal.runtime.Source; import jdk.nashorn.internal.runtime.options.Options; import org.testng.Assert; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; /** @@ -54,9 +55,9 @@ public class ParserTest { } private Context context; - private ScriptObject global; - public ParserTest() { + @BeforeClass + public void setupTest() { final Options options = new Options("nashorn"); options.set("anon.functions", true); options.set("parse.only", true); @@ -64,7 +65,11 @@ public class ParserTest { ErrorManager errors = new ErrorManager(); this.context = new Context(options, errors, Thread.currentThread().getContextClassLoader()); - this.global = context.createGlobal(); + } + + @AfterClass + public void tearDownTest() { + this.context = null; } @Test @@ -125,8 +130,6 @@ public class ParserTest { log("Begin parsing " + file.getAbsolutePath()); } - final ScriptObject oldGlobal = Context.getGlobal(); - final boolean globalChanged = (oldGlobal != global); try { final char[] buffer = Source.readFully(file); boolean excluded = false; @@ -150,9 +153,6 @@ public class ParserTest { } }; errors.setLimit(0); - if (globalChanged) { - Context.setGlobal(global); - } final Source source = new Source(file.getAbsolutePath(), buffer); new Parser(context.getEnv(), source, errors).parse(); if (errors.getNumberOfErrors() > 0) { @@ -167,10 +167,6 @@ public class ParserTest { exp.printStackTrace(System.out); } failed++; - } finally { - if (globalChanged) { - Context.setGlobal(oldGlobal); - } } if (VERBOSE) { -- cgit v1.2.3 From 43057911b8202759b9b73f8e7cc401d21317aa23 Mon Sep 17 00:00:00 2001 From: sundar Date: Fri, 9 Aug 2013 20:48:44 +0530 Subject: 8022707: Revisit all doPrivileged blocks Reviewed-by: jlaskey, hannesw --- make/project.properties | 11 +++-- .../nashorn/api/scripting/NashornScriptEngine.java | 33 +++++++------ .../api/scripting/NashornScriptEngineFactory.java | 12 ++++- .../nashorn/api/scripting/ScriptObjectMirror.java | 15 +++++- src/jdk/nashorn/internal/objects/Global.java | 22 +++------ src/jdk/nashorn/internal/objects/NativeDebug.java | 2 +- src/jdk/nashorn/internal/runtime/Context.java | 57 ++++++++++++++++++---- src/jdk/nashorn/internal/runtime/ECMAErrors.java | 11 +---- src/jdk/nashorn/internal/runtime/Logging.java | 24 +++++++-- .../internal/runtime/linker/ClassAndLoader.java | 15 +++++- .../linker/JavaAdapterBytecodeGenerator.java | 5 +- .../runtime/linker/JavaAdapterClassLoader.java | 4 +- .../runtime/linker/JavaAdapterFactory.java | 33 +++++++------ .../runtime/linker/ReflectionCheckLinker.java | 2 +- .../nashorn/internal/runtime/options/Options.java | 29 ++++++----- src/jdk/nashorn/tools/Shell.java | 15 +----- 16 files changed, 185 insertions(+), 105 deletions(-) diff --git a/make/project.properties b/make/project.properties index 081e27b2..5523f6cb 100644 --- a/make/project.properties +++ b/make/project.properties @@ -222,11 +222,16 @@ run.test.xms=2G run.test.user.language=tr run.test.user.country=TR -# -XX:+PrintCompilation -XX:+UnlockDiagnosticVMOptions -XX:+PrintNMethods -run.test.jvmargs.main=-server -Xmx${run.test.xmx} -XX:+TieredCompilation -ea -Dfile.encoding=UTF-8 -Duser.language=${run.test.user.language} -Duser.country=${run.test.user.country} -XX:+HeapDumpOnOutOfMemoryError +run.test.jvmargs.common=-server -Xmx${run.test.xmx} -XX:+TieredCompilation -Dfile.encoding=UTF-8 -Duser.language=${run.test.user.language} -Duser.country=${run.test.user.country} -XX:+HeapDumpOnOutOfMemoryError + +#-XX:-UseCompressedKlassPointers -XX:+PrintHeapAtGC -XX:ClassMetaspaceSize=300M +# -XX:+PrintCompilation -XX:+UnlockDiagnosticVMOptions -XX:+PrintNMethods + +# turn on assertions for tests +run.test.jvmargs.main=${run.test.jvmargs.common} -ea #-XX:-UseCompressedKlassPointers -XX:+PrintHeapAtGC -XX:ClassMetaspaceSize=300M -run.test.jvmargs.octane.main=-Xms${run.test.xms} ${run.test.jvmargs.main} +run.test.jvmargs.octane.main=-Xms${run.test.xms} ${run.test.jvmargs.common} run.test.jvmsecurityargs=-Xverify:all -Djava.security.properties=${basedir}/make/java.security.override -Djava.security.manager -Djava.security.policy=${basedir}/build/nashorn.policy diff --git a/src/jdk/nashorn/api/scripting/NashornScriptEngine.java b/src/jdk/nashorn/api/scripting/NashornScriptEngine.java index 5b79846b..063bc08f 100644 --- a/src/jdk/nashorn/api/scripting/NashornScriptEngine.java +++ b/src/jdk/nashorn/api/scripting/NashornScriptEngine.java @@ -36,10 +36,13 @@ import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.net.URL; import java.nio.charset.Charset; +import java.security.AccessControlContext; import java.security.AccessController; +import java.security.Permissions; import java.security.PrivilegedAction; import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; +import java.security.ProtectionDomain; import java.text.MessageFormat; import java.util.Locale; import java.util.ResourceBundle; @@ -71,6 +74,14 @@ import jdk.nashorn.internal.runtime.options.Options; */ public final class NashornScriptEngine extends AbstractScriptEngine implements Compilable, Invocable { + private static AccessControlContext createPermAccCtxt(final String permName) { + final Permissions perms = new Permissions(); + perms.add(new RuntimePermission(permName)); + return new AccessControlContext(new ProtectionDomain[] { new ProtectionDomain(null, perms) }); + } + + private static final AccessControlContext CREATE_CONTEXT_ACC_CTXT = createPermAccCtxt(Context.NASHORN_CREATE_CONTEXT); + private static final AccessControlContext CREATE_GLOBAL_ACC_CTXT = createPermAccCtxt(Context.NASHORN_CREATE_GLOBAL); private final ScriptEngineFactory factory; private final Context nashornContext; @@ -84,16 +95,9 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C private static final String MESSAGES_RESOURCE = "jdk.nashorn.api.scripting.resources.Messages"; - // Without do privileged, under security manager messages can not be loaded. private static final ResourceBundle MESSAGES_BUNDLE; static { - MESSAGES_BUNDLE = AccessController.doPrivileged( - new PrivilegedAction() { - @Override - public ResourceBundle run() { - return ResourceBundle.getBundle(MESSAGES_RESOURCE, Locale.getDefault()); - } - }); + MESSAGES_BUNDLE = ResourceBundle.getBundle(MESSAGES_RESOURCE, Locale.getDefault()); } private static String getMessage(final String msgId, final String... args) { @@ -128,7 +132,7 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C throw e; } } - }); + }, CREATE_CONTEXT_ACC_CTXT); // create new global object this.global = createNashornGlobal(); @@ -340,7 +344,7 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C throw e; } } - }); + }, CREATE_GLOBAL_ACC_CTXT); nashornContext.initGlobal(newGlobal); @@ -362,10 +366,8 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C } private void evalEngineScript() throws ScriptException { - evalSupportScript("resources/engine.js", NashornException.ENGINE_SCRIPT_SOURCE_NAME); - } - - private void evalSupportScript(final String script, final String name) throws ScriptException { + final String script = "resources/engine.js"; + final String name = NashornException.ENGINE_SCRIPT_SOURCE_NAME; try { final InputStream is = AccessController.doPrivileged( new PrivilegedExceptionAction() { @@ -380,6 +382,9 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C eval(isr); } } catch (final PrivilegedActionException | IOException e) { + if (Context.DEBUG) { + e.printStackTrace(); + } throw new ScriptException(e); } finally { put(ScriptEngine.FILENAME, null); diff --git a/src/jdk/nashorn/api/scripting/NashornScriptEngineFactory.java b/src/jdk/nashorn/api/scripting/NashornScriptEngineFactory.java index c1005415..beb0c2a0 100644 --- a/src/jdk/nashorn/api/scripting/NashornScriptEngineFactory.java +++ b/src/jdk/nashorn/api/scripting/NashornScriptEngineFactory.java @@ -30,6 +30,7 @@ import java.util.Collections; import java.util.List; import javax.script.ScriptEngine; import javax.script.ScriptEngineFactory; +import jdk.nashorn.internal.runtime.Context; import jdk.nashorn.internal.runtime.Version; /** @@ -136,7 +137,14 @@ public final class NashornScriptEngineFactory implements ScriptEngineFactory { @Override public ScriptEngine getScriptEngine() { - return new NashornScriptEngine(this, getAppClassLoader()); + try { + return new NashornScriptEngine(this, getAppClassLoader()); + } catch (final RuntimeException e) { + if (Context.DEBUG) { + e.printStackTrace(); + } + throw e; + } } /** @@ -178,7 +186,7 @@ public final class NashornScriptEngineFactory implements ScriptEngineFactory { private static void checkConfigPermission() { final SecurityManager sm = System.getSecurityManager(); if (sm != null) { - sm.checkPermission(new RuntimePermission("nashorn.setConfig")); + sm.checkPermission(new RuntimePermission(Context.NASHORN_SET_CONFIG)); } } diff --git a/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java b/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java index 7abf142c..fd2ef88a 100644 --- a/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java +++ b/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java @@ -25,14 +25,17 @@ package jdk.nashorn.api.scripting; +import java.security.AccessControlContext; import java.security.AccessController; +import java.security.Permissions; import java.security.PrivilegedAction; +import java.security.ProtectionDomain; import java.util.AbstractMap; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; -import java.util.LinkedHashSet; import java.util.Iterator; +import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; @@ -49,6 +52,14 @@ import jdk.nashorn.internal.runtime.ScriptRuntime; * netscape.javascript.JSObject interface. */ public final class ScriptObjectMirror extends JSObject implements Bindings { + private static AccessControlContext getContextAccCtxt() { + final Permissions perms = new Permissions(); + perms.add(new RuntimePermission(Context.NASHORN_GET_CONTEXT)); + return new AccessControlContext(new ProtectionDomain[] { new ProtectionDomain(null, perms) }); + } + + private static final AccessControlContext GET_CONTEXT_ACC_CTXT = getContextAccCtxt(); + private final ScriptObject sobj; private final ScriptObject global; @@ -144,7 +155,7 @@ public final class ScriptObjectMirror extends JSObject implements Bindings { public Context run() { return Context.getContext(); } - }); + }, GET_CONTEXT_ACC_CTXT); return wrap(context.eval(global, s, null, null, false), global); } }); diff --git a/src/jdk/nashorn/internal/objects/Global.java b/src/jdk/nashorn/internal/objects/Global.java index 891e0d7c..6d7be378 100644 --- a/src/jdk/nashorn/internal/objects/Global.java +++ b/src/jdk/nashorn/internal/objects/Global.java @@ -35,8 +35,6 @@ import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.ref.SoftReference; import java.lang.reflect.Field; -import java.security.AccessController; -import java.security.PrivilegedAction; import java.util.Arrays; import java.util.LinkedHashMap; import java.util.List; @@ -420,7 +418,7 @@ public final class Global extends ScriptObject implements GlobalObject, Scope { // security check first final SecurityManager sm = System.getSecurityManager(); if (sm != null) { - sm.checkPermission(new RuntimePermission("nashorn.newGlobal")); + sm.checkPermission(new RuntimePermission(Context.NASHORN_CREATE_GLOBAL)); } // null check on context @@ -1780,19 +1778,13 @@ public final class Global extends ScriptObject implements GlobalObject, Scope { } private static void copyOptions(final ScriptObject options, final ScriptEnvironment scriptEnv) { - AccessController.doPrivileged(new PrivilegedAction() { - @Override - public Void run() { - for (Field f : scriptEnv.getClass().getFields()) { - try { - options.set(f.getName(), f.get(scriptEnv), false); - } catch (final IllegalArgumentException | IllegalAccessException exp) { - throw new RuntimeException(exp); - } - } - return null; + for (Field f : scriptEnv.getClass().getFields()) { + try { + options.set(f.getName(), f.get(scriptEnv), false); + } catch (final IllegalArgumentException | IllegalAccessException exp) { + throw new RuntimeException(exp); } - }); + } } private void initTypedArray() { diff --git a/src/jdk/nashorn/internal/objects/NativeDebug.java b/src/jdk/nashorn/internal/objects/NativeDebug.java index 82757cba..9ee7c99a 100644 --- a/src/jdk/nashorn/internal/objects/NativeDebug.java +++ b/src/jdk/nashorn/internal/objects/NativeDebug.java @@ -72,7 +72,7 @@ public final class NativeDebug extends ScriptObject { public static Object getContext(final Object self) { final SecurityManager sm = System.getSecurityManager(); if (sm != null) { - sm.checkPermission(new RuntimePermission("nashorn.getContext")); + sm.checkPermission(new RuntimePermission(Context.NASHORN_GET_CONTEXT)); } return Global.getThisContext(); } diff --git a/src/jdk/nashorn/internal/runtime/Context.java b/src/jdk/nashorn/internal/runtime/Context.java index b0e2f15f..8ff85b93 100644 --- a/src/jdk/nashorn/internal/runtime/Context.java +++ b/src/jdk/nashorn/internal/runtime/Context.java @@ -64,6 +64,31 @@ import jdk.nashorn.internal.runtime.options.Options; * This class manages the global state of execution. Context is immutable. */ public final class Context { + // nashorn specific security runtime access permission names + /** + * Permission needed to pass arbitrary nashorn command line options when creating Context. + */ + public static final String NASHORN_SET_CONFIG = "nashorn.setConfig"; + + /** + * Permission needed to create Nashorn Context instance. + */ + public static final String NASHORN_CREATE_CONTEXT = "nashorn.createContext"; + + /** + * Permission needed to create Nashorn Global instance. + */ + public static final String NASHORN_CREATE_GLOBAL = "nashorn.createGlobal"; + + /** + * Permission to get current Nashorn Context from thread local storage. + */ + public static final String NASHORN_GET_CONTEXT = "nashorn.getContext"; + + /** + * Permission to use Java reflection/jsr292 from script code. + */ + public static final String NASHORN_JAVA_REFLECTION = "nashorn.JavaReflection"; /** * ContextCodeInstaller that has the privilege of installing classes in the Context. @@ -139,7 +164,7 @@ public final class Context { public static Context getContext() { final SecurityManager sm = System.getSecurityManager(); if (sm != null) { - sm.checkPermission(new RuntimePermission("nashorn.getContext")); + sm.checkPermission(new RuntimePermission(NASHORN_GET_CONTEXT)); } return getContextTrusted(); } @@ -204,7 +229,20 @@ public final class Context { private static final ClassLoader myLoader = Context.class.getClassLoader(); private static final StructureLoader sharedLoader; - private static final AccessControlContext NO_PERMISSIONS_CONTEXT; + + private static AccessControlContext createNoPermAccCtxt() { + return new AccessControlContext(new ProtectionDomain[] { new ProtectionDomain(null, new Permissions()) }); + } + + private static AccessControlContext createPermAccCtxt(final String permName) { + final Permissions perms = new Permissions(); + perms.add(new RuntimePermission(permName)); + return new AccessControlContext(new ProtectionDomain[] { new ProtectionDomain(null, perms) }); + } + + private static final AccessControlContext NO_PERMISSIONS_ACC_CTXT = createNoPermAccCtxt(); + private static final AccessControlContext CREATE_LOADER_ACC_CTXT = createPermAccCtxt("createClassLoader"); + private static final AccessControlContext CREATE_GLOBAL_ACC_CTXT = createPermAccCtxt(NASHORN_CREATE_GLOBAL); static { sharedLoader = AccessController.doPrivileged(new PrivilegedAction() { @@ -212,8 +250,7 @@ public final class Context { public StructureLoader run() { return new StructureLoader(myLoader, null); } - }); - NO_PERMISSIONS_CONTEXT = new AccessControlContext(new ProtectionDomain[] { new ProtectionDomain(null, new Permissions()) }); + }, CREATE_LOADER_ACC_CTXT); } /** @@ -254,7 +291,7 @@ public final class Context { public Context(final Options options, final ErrorManager errors, final PrintWriter out, final PrintWriter err, final ClassLoader appLoader) { final SecurityManager sm = System.getSecurityManager(); if (sm != null) { - sm.checkPermission(new RuntimePermission("nashorn.createContext")); + sm.checkPermission(new RuntimePermission(NASHORN_CREATE_CONTEXT)); } this.env = new ScriptEnvironment(options, out, err); @@ -516,7 +553,7 @@ public final class Context { @Override public ScriptObject run() { try { - return createGlobal(); + return newGlobal(); } catch (final RuntimeException e) { if (Context.DEBUG) { e.printStackTrace(); @@ -524,7 +561,9 @@ public final class Context { throw e; } } - }); + }, CREATE_GLOBAL_ACC_CTXT); + // initialize newly created Global instance + initGlobal(newGlobal); setGlobalTrusted(newGlobal); final Object[] wrapped = args == null? ScriptRuntime.EMPTY_ARRAY : ScriptObjectMirror.wrapArray(args, oldGlobal); @@ -577,7 +616,7 @@ public final class Context { sm.checkPackageAccess(fullName.substring(0, index)); return null; } - }, NO_PERMISSIONS_CONTEXT); + }, NO_PERMISSIONS_ACC_CTXT); } } } @@ -856,7 +895,7 @@ public final class Context { public ScriptLoader run() { return new ScriptLoader(sharedLoader, Context.this); } - }); + }, CREATE_LOADER_ACC_CTXT); } private long getUniqueScriptId() { diff --git a/src/jdk/nashorn/internal/runtime/ECMAErrors.java b/src/jdk/nashorn/internal/runtime/ECMAErrors.java index 35a0f2f4..5b608f4b 100644 --- a/src/jdk/nashorn/internal/runtime/ECMAErrors.java +++ b/src/jdk/nashorn/internal/runtime/ECMAErrors.java @@ -25,8 +25,6 @@ package jdk.nashorn.internal.runtime; -import java.security.AccessController; -import java.security.PrivilegedAction; import java.text.MessageFormat; import java.util.Locale; import java.util.ResourceBundle; @@ -40,16 +38,9 @@ import jdk.nashorn.internal.scripts.JS; public final class ECMAErrors { private static final String MESSAGES_RESOURCE = "jdk.nashorn.internal.runtime.resources.Messages"; - // Without do privileged, under security manager messages can not be loaded. private static final ResourceBundle MESSAGES_BUNDLE; static { - MESSAGES_BUNDLE = AccessController.doPrivileged( - new PrivilegedAction() { - @Override - public ResourceBundle run() { - return ResourceBundle.getBundle(MESSAGES_RESOURCE, Locale.getDefault()); - } - }); + MESSAGES_BUNDLE = ResourceBundle.getBundle(MESSAGES_RESOURCE, Locale.getDefault()); } /** We assume that compiler generates script classes into the known package. */ diff --git a/src/jdk/nashorn/internal/runtime/Logging.java b/src/jdk/nashorn/internal/runtime/Logging.java index 39740dd2..54d83b79 100644 --- a/src/jdk/nashorn/internal/runtime/Logging.java +++ b/src/jdk/nashorn/internal/runtime/Logging.java @@ -25,6 +25,11 @@ package jdk.nashorn.internal.runtime; +import java.security.AccessControlContext; +import java.security.AccessController; +import java.security.Permissions; +import java.security.PrivilegedAction; +import java.security.ProtectionDomain; import java.util.HashMap; import java.util.Locale; import java.util.Map; @@ -35,6 +40,7 @@ import java.util.logging.Handler; import java.util.logging.Level; import java.util.logging.LogRecord; import java.util.logging.Logger; +import java.util.logging.LoggingPermission; /** * Logging system for getting loggers for arbitrary subsystems as @@ -50,12 +56,20 @@ public final class Logging { private static final Logger disabledLogger = Logger.getLogger("disabled"); + private static AccessControlContext createLoggerControlAccCtxt() { + final Permissions perms = new Permissions(); + perms.add(new LoggingPermission("control", null)); + return new AccessControlContext(new ProtectionDomain[] { new ProtectionDomain(null, perms) }); + } + static { - try { - Logging.disabledLogger.setLevel(Level.OFF); - } catch (final SecurityException e) { - //ignored - } + AccessController.doPrivileged(new PrivilegedAction() { + @Override + public Void run() { + Logging.disabledLogger.setLevel(Level.OFF); + return null; + } + }, createLoggerControlAccCtxt()); } /** Maps logger name to loggers. Names are typically per package */ diff --git a/src/jdk/nashorn/internal/runtime/linker/ClassAndLoader.java b/src/jdk/nashorn/internal/runtime/linker/ClassAndLoader.java index d12df47a..b139da1c 100644 --- a/src/jdk/nashorn/internal/runtime/linker/ClassAndLoader.java +++ b/src/jdk/nashorn/internal/runtime/linker/ClassAndLoader.java @@ -27,8 +27,11 @@ package jdk.nashorn.internal.runtime.linker; import static jdk.nashorn.internal.runtime.ECMAErrors.typeError; +import java.security.AccessControlContext; import java.security.AccessController; +import java.security.Permissions; import java.security.PrivilegedAction; +import java.security.ProtectionDomain; import java.util.Collection; import java.util.Iterator; import java.util.LinkedHashMap; @@ -43,6 +46,16 @@ import java.util.Map; * used to determine if one loader can see the other loader's classes. */ final class ClassAndLoader { + static AccessControlContext createPermAccCtxt(final String... permNames) { + final Permissions perms = new Permissions(); + for (final String permName : permNames) { + perms.add(new RuntimePermission(permName)); + } + return new AccessControlContext(new ProtectionDomain[] { new ProtectionDomain(null, perms) }); + } + + private static final AccessControlContext GET_LOADER_ACC_CTXT = createPermAccCtxt("getClassLoader"); + private final Class representativeClass; // Don't access this directly; most of the time, use getRetrievedLoader(), or if you know what you're doing, // getLoader(). @@ -116,7 +129,7 @@ final class ClassAndLoader { public ClassAndLoader run() { return getDefiningClassAndLoaderPrivileged(types); } - }); + }, GET_LOADER_ACC_CTXT); } static ClassAndLoader getDefiningClassAndLoaderPrivileged(final Class[] types) { diff --git a/src/jdk/nashorn/internal/runtime/linker/JavaAdapterBytecodeGenerator.java b/src/jdk/nashorn/internal/runtime/linker/JavaAdapterBytecodeGenerator.java index 2264cae5..efbf7cf6 100644 --- a/src/jdk/nashorn/internal/runtime/linker/JavaAdapterBytecodeGenerator.java +++ b/src/jdk/nashorn/internal/runtime/linker/JavaAdapterBytecodeGenerator.java @@ -49,6 +49,7 @@ import java.lang.reflect.AccessibleObject; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.lang.reflect.Modifier; +import java.security.AccessControlContext; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.Arrays; @@ -868,6 +869,8 @@ final class JavaAdapterBytecodeGenerator { } } + private static final AccessControlContext GET_DECLARED_MEMBERS_ACC_CTXT = ClassAndLoader.createPermAccCtxt("accessDeclaredMembers"); + /** * Creates a collection of methods that are not final, but we still never allow them to be overridden in adapters, * as explicitly declaring them automatically is a bad idea. Currently, this means {@code Object.finalize()} and @@ -886,7 +889,7 @@ final class JavaAdapterBytecodeGenerator { throw new AssertionError(e); } } - }); + }, GET_DECLARED_MEMBERS_ACC_CTXT); } private String getCommonSuperClass(final String type1, final String type2) { diff --git a/src/jdk/nashorn/internal/runtime/linker/JavaAdapterClassLoader.java b/src/jdk/nashorn/internal/runtime/linker/JavaAdapterClassLoader.java index 059ed552..291e4d2f 100644 --- a/src/jdk/nashorn/internal/runtime/linker/JavaAdapterClassLoader.java +++ b/src/jdk/nashorn/internal/runtime/linker/JavaAdapterClassLoader.java @@ -25,6 +25,7 @@ package jdk.nashorn.internal.runtime.linker; +import java.security.AccessControlContext; import java.security.AccessController; import java.security.AllPermission; import java.security.CodeSigner; @@ -46,6 +47,7 @@ import jdk.internal.dynalink.beans.StaticClass; @SuppressWarnings("javadoc") final class JavaAdapterClassLoader { private static final ProtectionDomain GENERATED_PROTECTION_DOMAIN = createGeneratedProtectionDomain(); + private static final AccessControlContext CREATE_LOADER_ACC_CTXT = ClassAndLoader.createPermAccCtxt("createClassLoader"); private final String className; private volatile byte[] classBytes; @@ -77,7 +79,7 @@ final class JavaAdapterClassLoader { throw new AssertionError(e); // cannot happen } } - }); + }, CREATE_LOADER_ACC_CTXT); } // Note that the adapter class is created in the protection domain of the class/interface being diff --git a/src/jdk/nashorn/internal/runtime/linker/JavaAdapterFactory.java b/src/jdk/nashorn/internal/runtime/linker/JavaAdapterFactory.java index 4c005a27..5130f3d6 100644 --- a/src/jdk/nashorn/internal/runtime/linker/JavaAdapterFactory.java +++ b/src/jdk/nashorn/internal/runtime/linker/JavaAdapterFactory.java @@ -31,9 +31,9 @@ import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; import java.lang.reflect.Modifier; +import java.security.AccessControlContext; import java.security.AccessController; import java.security.PrivilegedAction; -import java.security.PrivilegedExceptionAction; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -70,6 +70,11 @@ import jdk.nashorn.internal.runtime.ScriptObject; @SuppressWarnings("javadoc") public final class JavaAdapterFactory { + // context with permissions needs for AdapterInfo creation + private static final AccessControlContext CREATE_ADAPTER_INFO_ACC_CTXT = + ClassAndLoader.createPermAccCtxt("createClassLoader", "getClassLoader", + "accessDeclaredMembers", "accessClassInPackage.jdk.nashorn.internal.runtime"); + /** * A mapping from an original Class object to AdapterInfo representing the adapter for the class it represents. */ @@ -124,17 +129,10 @@ public final class JavaAdapterFactory { */ public static MethodHandle getConstructor(final Class sourceType, final Class targetType) throws Exception { final StaticClass adapterClass = getAdapterClassFor(new Class[] { targetType }, null); - return AccessController.doPrivileged(new PrivilegedExceptionAction() { - @Override - public MethodHandle run() throws Exception { - // NOTE: we use publicLookup(), but none of our adapter constructors are caller sensitive, so this is - // okay, we won't artificially limit access. - return MH.bindTo(Bootstrap.getLinkerServices().getGuardedInvocation(new LinkRequestImpl( - NashornCallSiteDescriptor.get(MethodHandles.publicLookup(), "dyn:new", - MethodType.methodType(targetType, StaticClass.class, sourceType), 0), false, - adapterClass, null)).getInvocation(), adapterClass); - } - }); + return MH.bindTo(Bootstrap.getLinkerServices().getGuardedInvocation(new LinkRequestImpl( + NashornCallSiteDescriptor.get(MethodHandles.publicLookup(), "dyn:new", + MethodType.methodType(targetType, StaticClass.class, sourceType), 0), false, + adapterClass, null)).getInvocation(), adapterClass); } /** @@ -171,7 +169,7 @@ public final class JavaAdapterFactory { return (List)Collections.singletonList(clazz); } - /** + /** * For a given class, create its adapter class and associated info. * @param type the class for which the adapter is created * @return the adapter info for the class. @@ -190,12 +188,19 @@ public final class JavaAdapterFactory { } superClass = t; } else { + if (interfaces.size() > 65535) { + throw new IllegalArgumentException("interface limit exceeded"); + } + interfaces.add(t); } + if(!Modifier.isPublic(mod)) { return new AdapterInfo(AdaptationResult.Outcome.ERROR_NON_PUBLIC_CLASS, t.getCanonicalName()); } } + + final Class effectiveSuperClass = superClass == null ? Object.class : superClass; return AccessController.doPrivileged(new PrivilegedAction() { @Override @@ -206,7 +211,7 @@ public final class JavaAdapterFactory { return new AdapterInfo(e.getAdaptationResult()); } } - }); + }, CREATE_ADAPTER_INFO_ACC_CTXT); } private static class AdapterInfo { diff --git a/src/jdk/nashorn/internal/runtime/linker/ReflectionCheckLinker.java b/src/jdk/nashorn/internal/runtime/linker/ReflectionCheckLinker.java index 1e540231..39f93642 100644 --- a/src/jdk/nashorn/internal/runtime/linker/ReflectionCheckLinker.java +++ b/src/jdk/nashorn/internal/runtime/linker/ReflectionCheckLinker.java @@ -88,6 +88,6 @@ final class ReflectionCheckLinker implements TypeBasedGuardingDynamicLinker{ } private static void checkReflectionPermission(final SecurityManager sm) { - sm.checkPermission(new RuntimePermission("nashorn.JavaReflection")); + sm.checkPermission(new RuntimePermission(Context.NASHORN_JAVA_REFLECTION)); } } diff --git a/src/jdk/nashorn/internal/runtime/options/Options.java b/src/jdk/nashorn/internal/runtime/options/Options.java index 737c56b4..900d9dd4 100644 --- a/src/jdk/nashorn/internal/runtime/options/Options.java +++ b/src/jdk/nashorn/internal/runtime/options/Options.java @@ -26,8 +26,11 @@ package jdk.nashorn.internal.runtime.options; import java.io.PrintWriter; +import java.security.AccessControlContext; import java.security.AccessController; +import java.security.Permissions; import java.security.PrivilegedAction; +import java.security.ProtectionDomain; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Collection; @@ -39,6 +42,7 @@ import java.util.List; import java.util.Locale; import java.util.Map; import java.util.MissingResourceException; +import java.util.PropertyPermission; import java.util.ResourceBundle; import java.util.StringTokenizer; import java.util.TimeZone; @@ -51,6 +55,15 @@ import jdk.nashorn.internal.runtime.QuotedStringTokenizer; * Manages global runtime options. */ public final class Options { + // permission to just read nashorn.* System properties + private static AccessControlContext createPropertyReadAccCtxt() { + final Permissions perms = new Permissions(); + perms.add(new PropertyPermission("nashorn.*", "read")); + return new AccessControlContext(new ProtectionDomain[] { new ProtectionDomain(null, perms) }); + } + + private static final AccessControlContext READ_PROPERTY_ACC_CTXT = createPropertyReadAccCtxt(); + /** Resource tag. */ private final String resource; @@ -144,7 +157,7 @@ public final class Options { return false; } } - }); + }, READ_PROPERTY_ACC_CTXT); } /** @@ -171,7 +184,7 @@ public final class Options { return defValue; } } - }); + }, READ_PROPERTY_ACC_CTXT); } /** @@ -198,7 +211,7 @@ public final class Options { return defValue; } } - }); + }, READ_PROPERTY_ACC_CTXT); } /** @@ -567,15 +580,7 @@ public final class Options { private static String definePropPrefix; static { - // Without do privileged, under security manager messages can not be - // loaded. - Options.bundle = AccessController.doPrivileged(new PrivilegedAction() { - @Override - public ResourceBundle run() { - return ResourceBundle.getBundle(Options.MESSAGES_RESOURCE, Locale.getDefault()); - } - }); - + Options.bundle = ResourceBundle.getBundle(Options.MESSAGES_RESOURCE, Locale.getDefault()); Options.validOptions = new TreeSet<>(); Options.usage = new HashMap<>(); diff --git a/src/jdk/nashorn/tools/Shell.java b/src/jdk/nashorn/tools/Shell.java index 55840078..08b576fb 100644 --- a/src/jdk/nashorn/tools/Shell.java +++ b/src/jdk/nashorn/tools/Shell.java @@ -34,8 +34,6 @@ import java.io.InputStreamReader; import java.io.OutputStream; import java.io.PrintStream; import java.io.PrintWriter; -import java.security.AccessController; -import java.security.PrivilegedAction; import java.util.List; import java.util.Locale; import java.util.ResourceBundle; @@ -68,18 +66,7 @@ public class Shell { /** * Shell message bundle. */ - private static ResourceBundle bundle; - - static { - // Without do privileged, under security manager messages can not be - // loaded. - bundle = AccessController.doPrivileged(new PrivilegedAction() { - @Override - public ResourceBundle run() { - return ResourceBundle.getBundle(MESSAGE_RESOURCE, Locale.getDefault()); - } - }); - } + private static final ResourceBundle bundle = ResourceBundle.getBundle(MESSAGE_RESOURCE, Locale.getDefault()); /** * Exit code for command line tool - successful -- cgit v1.2.3 From 37025a348155812ea4d87d2eca15234a902b9195 Mon Sep 17 00:00:00 2001 From: sundar Date: Mon, 12 Aug 2013 14:43:53 +0530 Subject: 8022782: publicLookup access failures in ScriptObject, ScriptFunction and ScriptFunction Reviewed-by: lagergren, attila, hannesw --- .../internal/codegen/CompilerConstants.java | 28 ------------------- src/jdk/nashorn/internal/runtime/JSType.java | 31 ++++++++++++---------- src/jdk/nashorn/internal/runtime/ScriptObject.java | 6 ++--- .../nashorn/internal/runtime/ScriptRuntime.java | 3 ++- 4 files changed, 22 insertions(+), 46 deletions(-) diff --git a/src/jdk/nashorn/internal/codegen/CompilerConstants.java b/src/jdk/nashorn/internal/codegen/CompilerConstants.java index c8ccc1ce..5207fbce 100644 --- a/src/jdk/nashorn/internal/codegen/CompilerConstants.java +++ b/src/jdk/nashorn/internal/codegen/CompilerConstants.java @@ -488,20 +488,6 @@ public enum CompilerConstants { return staticField(className(clazz), name, typeDescriptor(type)); } - /** - * Create a static call, looking up the method handle for it at the same time - * - * @param clazz the class - * @param name the name of the method - * @param rtype the return type of the method - * @param ptypes the parameter types of the method - * - * @return the call object representing the static call - */ - public static Call staticCall(final Class clazz, final String name, final Class rtype, final Class... ptypes) { - return staticCall(MethodHandles.publicLookup(), clazz, name, rtype, ptypes); - } - /** * Create a static call, given an explicit lookup, looking up the method handle for it at the same time * @@ -522,20 +508,6 @@ public enum CompilerConstants { }; } - /** - * Create a virtual call, looking up the method handle for it at the same time - * - * @param clazz the class - * @param name the name of the method - * @param rtype the return type of the method - * @param ptypes the parameter types of the method - * - * @return the call object representing the virtual call - */ - public static Call virtualCall(final Class clazz, final String name, final Class rtype, final Class... ptypes) { - return virtualCall(MethodHandles.publicLookup(), clazz, name, rtype, ptypes); - } - /** * Create a virtual call, given an explicit lookup, looking up the method handle for it at the same time * diff --git a/src/jdk/nashorn/internal/runtime/JSType.java b/src/jdk/nashorn/internal/runtime/JSType.java index 4d1d825c..f5327621 100644 --- a/src/jdk/nashorn/internal/runtime/JSType.java +++ b/src/jdk/nashorn/internal/runtime/JSType.java @@ -28,6 +28,7 @@ package jdk.nashorn.internal.runtime; import static jdk.nashorn.internal.codegen.CompilerConstants.staticCall; import static jdk.nashorn.internal.runtime.ECMAErrors.typeError; +import java.lang.invoke.MethodHandles; import java.util.Locale; import jdk.internal.dynalink.beans.BeansLinker; import jdk.internal.dynalink.beans.StaticClass; @@ -63,47 +64,49 @@ public enum JSType { /** Max value for an uint32 in JavaScript */ public static final long MAX_UINT = 0xFFFF_FFFFL; + private static final MethodHandles.Lookup myLookup = MethodHandles.lookup(); + /** JavaScript compliant conversion function from Object to boolean */ - public static final Call TO_BOOLEAN = staticCall(JSType.class, "toBoolean", boolean.class, Object.class); + public static final Call TO_BOOLEAN = staticCall(myLookup, JSType.class, "toBoolean", boolean.class, Object.class); /** JavaScript compliant conversion function from number to boolean */ - public static final Call TO_BOOLEAN_D = staticCall(JSType.class, "toBoolean", boolean.class, double.class); + public static final Call TO_BOOLEAN_D = staticCall(myLookup, JSType.class, "toBoolean", boolean.class, double.class); /** JavaScript compliant conversion function from Object to integer */ - public static final Call TO_INTEGER = staticCall(JSType.class, "toInteger", int.class, Object.class); + public static final Call TO_INTEGER = staticCall(myLookup, JSType.class, "toInteger", int.class, Object.class); /** JavaScript compliant conversion function from Object to long */ - public static final Call TO_LONG = staticCall(JSType.class, "toLong", long.class, Object.class); + public static final Call TO_LONG = staticCall(myLookup, JSType.class, "toLong", long.class, Object.class); /** JavaScript compliant conversion function from Object to number */ - public static final Call TO_NUMBER = staticCall(JSType.class, "toNumber", double.class, Object.class); + public static final Call TO_NUMBER = staticCall(myLookup, JSType.class, "toNumber", double.class, Object.class); /** JavaScript compliant conversion function from Object to int32 */ - public static final Call TO_INT32 = staticCall(JSType.class, "toInt32", int.class, Object.class); + public static final Call TO_INT32 = staticCall(myLookup, JSType.class, "toInt32", int.class, Object.class); /** JavaScript compliant conversion function from double to int32 */ - public static final Call TO_INT32_D = staticCall(JSType.class, "toInt32", int.class, double.class); + public static final Call TO_INT32_D = staticCall(myLookup, JSType.class, "toInt32", int.class, double.class); /** JavaScript compliant conversion function from Object to uint32 */ - public static final Call TO_UINT32 = staticCall(JSType.class, "toUint32", long.class, Object.class); + public static final Call TO_UINT32 = staticCall(myLookup, JSType.class, "toUint32", long.class, Object.class); /** JavaScript compliant conversion function from number to uint32 */ - public static final Call TO_UINT32_D = staticCall(JSType.class, "toUint32", long.class, double.class); + public static final Call TO_UINT32_D = staticCall(myLookup, JSType.class, "toUint32", long.class, double.class); /** JavaScript compliant conversion function from Object to int64 */ - public static final Call TO_INT64 = staticCall(JSType.class, "toInt64", long.class, Object.class); + public static final Call TO_INT64 = staticCall(myLookup, JSType.class, "toInt64", long.class, Object.class); /** JavaScript compliant conversion function from number to int64 */ - public static final Call TO_INT64_D = staticCall(JSType.class, "toInt64", long.class, double.class); + public static final Call TO_INT64_D = staticCall(myLookup, JSType.class, "toInt64", long.class, double.class); /** JavaScript compliant conversion function from Object to String */ - public static final Call TO_STRING = staticCall(JSType.class, "toString", String.class, Object.class); + public static final Call TO_STRING = staticCall(myLookup, JSType.class, "toString", String.class, Object.class); /** JavaScript compliant conversion function from number to String */ - public static final Call TO_STRING_D = staticCall(JSType.class, "toString", String.class, double.class); + public static final Call TO_STRING_D = staticCall(myLookup, JSType.class, "toString", String.class, double.class); /** JavaScript compliant conversion function from Object to primitive */ - public static final Call TO_PRIMITIVE = staticCall(JSType.class, "toPrimitive", Object.class, Object.class); + public static final Call TO_PRIMITIVE = staticCall(myLookup, JSType.class, "toPrimitive", Object.class, Object.class); private static final double INT32_LIMIT = 4294967296.0; diff --git a/src/jdk/nashorn/internal/runtime/ScriptObject.java b/src/jdk/nashorn/internal/runtime/ScriptObject.java index 099aad55..f26e30f0 100644 --- a/src/jdk/nashorn/internal/runtime/ScriptObject.java +++ b/src/jdk/nashorn/internal/runtime/ScriptObject.java @@ -138,10 +138,10 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr private static final MethodHandle KNOWNFUNCPROPGUARD = findOwnMH("knownFunctionPropertyGuard", boolean.class, Object.class, PropertyMap.class, MethodHandle.class, Object.class, ScriptFunction.class); /** Method handle for getting a function argument at a given index. Used from MapCreator */ - public static final Call GET_ARGUMENT = virtualCall(ScriptObject.class, "getArgument", Object.class, int.class); + public static final Call GET_ARGUMENT = virtualCall(MethodHandles.lookup(), ScriptObject.class, "getArgument", Object.class, int.class); /** Method handle for setting a function argument at a given index. Used from MapCreator */ - public static final Call SET_ARGUMENT = virtualCall(ScriptObject.class, "setArgument", void.class, int.class, Object.class); + public static final Call SET_ARGUMENT = virtualCall(MethodHandles.lookup(), ScriptObject.class, "setArgument", void.class, int.class, Object.class); /** Method handle for getting the proto of a ScriptObject */ public static final Call GET_PROTO = virtualCallNoLookup(ScriptObject.class, "getProto", ScriptObject.class); @@ -150,7 +150,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr public static final Call SET_PROTO = virtualCallNoLookup(ScriptObject.class, "setProto", void.class, ScriptObject.class); /** Method handle for setting the user accessors of a ScriptObject */ - public static final Call SET_USER_ACCESSORS = virtualCall(ScriptObject.class, "setUserAccessors", void.class, String.class, ScriptFunction.class, ScriptFunction.class); + public static final Call SET_USER_ACCESSORS = virtualCall(MethodHandles.lookup(), ScriptObject.class, "setUserAccessors", void.class, String.class, ScriptFunction.class, ScriptFunction.class); /** * Constructor diff --git a/src/jdk/nashorn/internal/runtime/ScriptRuntime.java b/src/jdk/nashorn/internal/runtime/ScriptRuntime.java index dbeee76a..53c4d4fe 100644 --- a/src/jdk/nashorn/internal/runtime/ScriptRuntime.java +++ b/src/jdk/nashorn/internal/runtime/ScriptRuntime.java @@ -33,6 +33,7 @@ import static jdk.nashorn.internal.runtime.ECMAErrors.typeError; import static jdk.nashorn.internal.runtime.JSType.isRepresentableAsInt; import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; import java.lang.reflect.Array; import java.util.Collections; import java.util.Iterator; @@ -100,7 +101,7 @@ public final class ScriptRuntime { * call sites that are known to be megamorphic. Using an invoke dynamic here would * lead to the JVM deoptimizing itself to death */ - public static final Call APPLY = staticCall(ScriptRuntime.class, "apply", Object.class, ScriptFunction.class, Object.class, Object[].class); + public static final Call APPLY = staticCall(MethodHandles.lookup(), ScriptRuntime.class, "apply", Object.class, ScriptFunction.class, Object.class, Object[].class); /** * Converts a switch tag value to a simple integer. deflt value if it can't. -- cgit v1.2.3 From 074937dd61cb8424034d14b64ab5a6e97452a694 Mon Sep 17 00:00:00 2001 From: attila Date: Mon, 12 Aug 2013 12:46:01 +0200 Subject: 8022789: Revisit doPrivileged blocks in Dynalink Reviewed-by: lagergren, sundar --- .../internal/dynalink/DynamicLinkerFactory.java | 3 +- .../support/ClassLoaderGetterContextProvider.java | 107 +++++++++++++++++++++ src/jdk/internal/dynalink/support/ClassMap.java | 2 +- .../dynalink/support/TypeConverterFactory.java | 2 +- 4 files changed, 111 insertions(+), 3 deletions(-) create mode 100644 src/jdk/internal/dynalink/support/ClassLoaderGetterContextProvider.java diff --git a/src/jdk/internal/dynalink/DynamicLinkerFactory.java b/src/jdk/internal/dynalink/DynamicLinkerFactory.java index 3cd05200..72fbebe3 100644 --- a/src/jdk/internal/dynalink/DynamicLinkerFactory.java +++ b/src/jdk/internal/dynalink/DynamicLinkerFactory.java @@ -99,6 +99,7 @@ import jdk.internal.dynalink.linker.GuardingTypeConverterFactory; import jdk.internal.dynalink.linker.LinkRequest; import jdk.internal.dynalink.support.AutoDiscovery; import jdk.internal.dynalink.support.BottomGuardingDynamicLinker; +import jdk.internal.dynalink.support.ClassLoaderGetterContextProvider; import jdk.internal.dynalink.support.CompositeGuardingDynamicLinker; import jdk.internal.dynalink.support.CompositeTypeBasedGuardingDynamicLinker; import jdk.internal.dynalink.support.LinkerServicesImpl; @@ -315,7 +316,7 @@ public class DynamicLinkerFactory { public ClassLoader run() { return Thread.currentThread().getContextClassLoader(); } - }); + }, ClassLoaderGetterContextProvider.GET_CLASS_LOADER_CONTEXT); } private static void addClasses(Set> knownLinkerClasses, diff --git a/src/jdk/internal/dynalink/support/ClassLoaderGetterContextProvider.java b/src/jdk/internal/dynalink/support/ClassLoaderGetterContextProvider.java new file mode 100644 index 00000000..f9470215 --- /dev/null +++ b/src/jdk/internal/dynalink/support/ClassLoaderGetterContextProvider.java @@ -0,0 +1,107 @@ +/* + * 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. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file, and Oracle licenses the original version of this file under the BSD + * license: + */ +/* + Copyright 2009-2013 Attila Szegedi + + Licensed under both the Apache License, Version 2.0 (the "Apache License") + and the BSD License (the "BSD License"), with licensee being free to + choose either of the two at their discretion. + + You may not use this file except in compliance with either the Apache + License or the BSD License. + + If you choose to use this file in compliance with the Apache License, the + following notice applies to you: + + You may obtain a copy of the Apache License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied. See the License for the specific language governing + permissions and limitations under the License. + + If you choose to use this file in compliance with the BSD License, the + following notice applies to you: + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the copyright holder nor the names of + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER + BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +package jdk.internal.dynalink.support; + +import java.security.AccessControlContext; +import java.security.Permissions; +import java.security.ProtectionDomain; + +/** + * This class exposes a canonical {@link AccessControlContext} with a single {@link RuntimePermission} for + * {@code "getClassLoader"} permission that is used by other parts of the code to narrow their set of permissions when + * they're retrieving class loaders in privileged blocks. + */ +public class ClassLoaderGetterContextProvider { + /** + * Canonical instance of {@link AccessControlContext} with a single {@link RuntimePermission} for + * {@code "getClassLoader"} permission. + */ + public static final AccessControlContext GET_CLASS_LOADER_CONTEXT; + static { + final Permissions perms = new Permissions(); + perms.add(new RuntimePermission("getClassLoader")); + GET_CLASS_LOADER_CONTEXT = new AccessControlContext( + new ProtectionDomain[] { new ProtectionDomain(null, perms) }); + } +} diff --git a/src/jdk/internal/dynalink/support/ClassMap.java b/src/jdk/internal/dynalink/support/ClassMap.java index cf52d2e5..d85b21d0 100644 --- a/src/jdk/internal/dynalink/support/ClassMap.java +++ b/src/jdk/internal/dynalink/support/ClassMap.java @@ -155,7 +155,7 @@ public abstract class ClassMap { public ClassLoader run() { return clazz.getClassLoader(); } - }); + }, ClassLoaderGetterContextProvider.GET_CLASS_LOADER_CONTEXT); // If allowed to strongly reference, put it in the fast map if(Guards.canReferenceDirectly(classLoader, clazzLoader)) { diff --git a/src/jdk/internal/dynalink/support/TypeConverterFactory.java b/src/jdk/internal/dynalink/support/TypeConverterFactory.java index 245afc12..5ab541f3 100644 --- a/src/jdk/internal/dynalink/support/TypeConverterFactory.java +++ b/src/jdk/internal/dynalink/support/TypeConverterFactory.java @@ -151,7 +151,7 @@ public class TypeConverterFactory { public ClassLoader run() { return clazz.getClassLoader(); } - }); + }, ClassLoaderGetterContextProvider.GET_CLASS_LOADER_CONTEXT); } /** -- cgit v1.2.3 From 82c558149b6aa78c03c106f9b246455521ca273f Mon Sep 17 00:00:00 2001 From: sundar Date: Mon, 12 Aug 2013 16:52:32 +0530 Subject: 8022614: Please exclude test test/script/trusted/JDK-8020809.js from Nashorn code coverage run Reviewed-by: jlaskey, lagergren --- exclude/exclude_list_cc.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/exclude/exclude_list_cc.txt b/exclude/exclude_list_cc.txt index a66476b8..79b6303e 100644 --- a/exclude/exclude_list_cc.txt +++ b/exclude/exclude_list_cc.txt @@ -3,4 +3,5 @@ + -- cgit v1.2.3 From dedd3740c1d0a85d2a6419f882c4d03df70aa844 Mon Sep 17 00:00:00 2001 From: hannesw Date: Mon, 12 Aug 2013 13:31:43 +0200 Subject: 8022731: NativeArguments has wrong implementation of isMapped() Reviewed-by: lagergren, jlaskey --- .../nashorn/internal/objects/NativeArguments.java | 452 ++++----------------- test/script/basic/JDK-8022731.js | 93 +++++ test/script/basic/JDK-8022731.js.EXPECTED | 16 + 3 files changed, 189 insertions(+), 372 deletions(-) create mode 100644 test/script/basic/JDK-8022731.js create mode 100644 test/script/basic/JDK-8022731.js.EXPECTED diff --git a/src/jdk/nashorn/internal/objects/NativeArguments.java b/src/jdk/nashorn/internal/objects/NativeArguments.java index 3bd74d52..55c79da9 100644 --- a/src/jdk/nashorn/internal/objects/NativeArguments.java +++ b/src/jdk/nashorn/internal/objects/NativeArguments.java @@ -76,36 +76,21 @@ public final class NativeArguments extends ScriptObject { private Object length; private Object callee; - private ArrayData namedArgs; - // This is lazily initialized - only when delete is invoked at all + private final int numMapped; + private final int numParams; + + // These are lazily initialized when delete is invoked on a mapped arg or an unmapped argument is set. + private ArrayData unmappedArgs; private BitSet deleted; NativeArguments(final Object[] arguments, final Object callee, final int numParams, final ScriptObject proto, final PropertyMap map) { super(proto, map); setIsArguments(); - setArray(ArrayData.allocate(arguments)); this.length = arguments.length; this.callee = callee; - - /** - * Declared number of parameters may be more or less than the actual passed - * runtime arguments count. We need to truncate or extend with undefined values. - * - * Example: - * - * // less declared params - * (function (x) { print(arguments); })(20, 44); - * - * // more declared params - * (function (x, y) { print(arguments); })(3); - */ - final Object[] newValues = new Object[numParams]; - if (numParams > arguments.length) { - Arrays.fill(newValues, UNDEFINED); - } - System.arraycopy(arguments, 0, newValues, 0, Math.min(newValues.length, arguments.length)); - this.namedArgs = ArrayData.allocate(newValues); + this.numMapped = Math.min(numParams, arguments.length); + this.numParams = numParams; } @Override @@ -118,7 +103,8 @@ public final class NativeArguments extends ScriptObject { */ @Override public Object getArgument(final int key) { - return namedArgs.has(key) ? namedArgs.getObject(key) : UNDEFINED; + assert key >= 0 && key < numParams : "invalid argument index"; + return isMapped(key) ? getArray().getObject(key) : getUnmappedArg(key); } /** @@ -126,353 +112,36 @@ public final class NativeArguments extends ScriptObject { */ @Override public void setArgument(final int key, final Object value) { - if (namedArgs.has(key)) { - namedArgs = namedArgs.set(key, value, false); - } - } - - @Override - public int getInt(final Object key) { - final int index = ArrayIndex.getArrayIndex(key); - return isMapped(index) ? namedArgs.getInt(index) : super.getInt(key); - } - - @Override - public int getInt(final double key) { - final int index = ArrayIndex.getArrayIndex(key); - return isMapped(index) ? namedArgs.getInt(index) : super.getInt(key); - } - - @Override - public int getInt(final long key) { - final int index = ArrayIndex.getArrayIndex(key); - return isMapped(index) ? namedArgs.getInt(index) : super.getInt(key); - } - - @Override - public int getInt(final int key) { - final int index = ArrayIndex.getArrayIndex(key); - return isMapped(index) ? namedArgs.getInt(index) : super.getInt(key); - } - - @Override - public long getLong(final Object key) { - final int index = ArrayIndex.getArrayIndex(key); - return isMapped(index) ? namedArgs.getLong(index) : super.getLong(key); - } - - @Override - public long getLong(final double key) { - final int index = ArrayIndex.getArrayIndex(key); - return isMapped(index) ? namedArgs.getLong(index) : super.getLong(key); - } - - @Override - public long getLong(final long key) { - final int index = ArrayIndex.getArrayIndex(key); - return isMapped(index) ? namedArgs.getLong(index) : super.getLong(key); - } - - @Override - public long getLong(final int key) { - final int index = ArrayIndex.getArrayIndex(key); - return isMapped(index) ? namedArgs.getLong(index) : super.getLong(key); - } - - @Override - public double getDouble(final Object key) { - final int index = ArrayIndex.getArrayIndex(key); - return isMapped(index) ? namedArgs.getDouble(index) : super.getDouble(key); - } - - @Override - public double getDouble(final double key) { - final int index = ArrayIndex.getArrayIndex(key); - return isMapped(index) ? namedArgs.getDouble(index) : super.getDouble(key); - } - - @Override - public double getDouble(final long key) { - final int index = ArrayIndex.getArrayIndex(key); - return isMapped(index) ? namedArgs.getDouble(index) : super.getDouble(key); - } - - @Override - public double getDouble(final int key) { - final int index = ArrayIndex.getArrayIndex(key); - return isMapped(index) ? namedArgs.getDouble(index) : super.getDouble(key); - } - - @Override - public Object get(final Object key) { - final int index = ArrayIndex.getArrayIndex(key); - return isMapped(index) ? namedArgs.getObject(index) : super.get(key); - } - - @Override - public Object get(final double key) { - final int index = ArrayIndex.getArrayIndex(key); - return isMapped(index) ? namedArgs.getObject(index) : super.get(key); - } - - @Override - public Object get(final long key) { - final int index = ArrayIndex.getArrayIndex(key); - return isMapped(index) ? namedArgs.getObject(index) : super.get(key); - } - - @Override - public Object get(final int key) { - final int index = ArrayIndex.getArrayIndex(key); - return isMapped(index) ? namedArgs.getObject(index) : super.get(key); - } - - @Override - public void set(final Object key, final int value, final boolean strict) { - final int index = ArrayIndex.getArrayIndex(key); - if (isMapped(index)) { - namedArgs = namedArgs.set(index, value, strict); + assert key >= 0 && key < numParams : "invalid argument index"; + if (isMapped(key)) { + setArray(getArray().set(key, value, false)); } else { - super.set(key, value, strict); + setUnmappedArg(key, value); } } - @Override - public void set(final Object key, final long value, final boolean strict) { - final int index = ArrayIndex.getArrayIndex(key); - if (isMapped(index)) { - namedArgs = namedArgs.set(index, value, strict); - } else { - super.set(key, value, strict); - } - } - - @Override - public void set(final Object key, final double value, final boolean strict) { - final int index = ArrayIndex.getArrayIndex(key); - if (isMapped(index)) { - namedArgs = namedArgs.set(index, value, strict); - } else { - super.set(key, value, strict); - } - } - - @Override - public void set(final Object key, final Object value, final boolean strict) { - final int index = ArrayIndex.getArrayIndex(key); - if (isMapped(index)) { - namedArgs = namedArgs.set(index, value, strict); - } else { - super.set(key, value, strict); - } - } - - @Override - public void set(final double key, final int value, final boolean strict) { - final int index = ArrayIndex.getArrayIndex(key); - if (isMapped(index)) { - namedArgs = namedArgs.set(index, value, strict); - } else { - super.set(key, value, strict); - } - } - - @Override - public void set(final double key, final long value, final boolean strict) { - final int index = ArrayIndex.getArrayIndex(key); - if (isMapped(index)) { - namedArgs = namedArgs.set(index, value, strict); - } else { - super.set(key, value, strict); - } - } - - @Override - public void set(final double key, final double value, final boolean strict) { - final int index = ArrayIndex.getArrayIndex(key); - if (isMapped(index)) { - namedArgs = namedArgs.set(index, value, strict); - } else { - super.set(key, value, strict); - } - } - - @Override - public void set(final double key, final Object value, final boolean strict) { - final int index = ArrayIndex.getArrayIndex(key); - if (isMapped(index)) { - namedArgs = namedArgs.set(index, value, strict); - } else { - super.set(key, value, strict); - } - } - - @Override - public void set(final long key, final int value, final boolean strict) { - final int index = ArrayIndex.getArrayIndex(key); - if (isMapped(index)) { - namedArgs = namedArgs.set(index, value, strict); - } else { - super.set(key, value, strict); - } - } - - @Override - public void set(final long key, final long value, final boolean strict) { - final int index = ArrayIndex.getArrayIndex(key); - if (isMapped(index)) { - namedArgs = namedArgs.set(index, value, strict); - } else { - super.set(key, value, strict); - } - } - - @Override - public void set(final long key, final double value, final boolean strict) { - final int index = ArrayIndex.getArrayIndex(key); - if (isMapped(index)) { - namedArgs = namedArgs.set(index, value, strict); - } else { - super.set(key, value, strict); - } - } - - @Override - public void set(final long key, final Object value, final boolean strict) { - final int index = ArrayIndex.getArrayIndex(key); - if (isMapped(index)) { - namedArgs = namedArgs.set(index, value, strict); - } else { - super.set(key, value, strict); - } - } - - @Override - public void set(final int key, final int value, final boolean strict) { - final int index = ArrayIndex.getArrayIndex(key); - if (isMapped(index)) { - namedArgs = namedArgs.set(index, value, strict); - } else { - super.set(key, value, strict); - } - } - - @Override - public void set(final int key, final long value, final boolean strict) { - final int index = ArrayIndex.getArrayIndex(key); - if (isMapped(index)) { - namedArgs = namedArgs.set(index, value, strict); - } else { - super.set(key, value, strict); - } - } - - @Override - public void set(final int key, final double value, final boolean strict) { - final int index = ArrayIndex.getArrayIndex(key); - if (isMapped(index)) { - namedArgs = namedArgs.set(index, value, strict); - } else { - super.set(key, value, strict); - } - } - - @Override - public void set(final int key, final Object value, final boolean strict) { - final int index = ArrayIndex.getArrayIndex(key); - if (isMapped(index)) { - namedArgs = namedArgs.set(index, value, strict); - } else { - super.set(key, value, strict); - } - } - - @Override - public boolean has(final Object key) { - final int index = ArrayIndex.getArrayIndex(key); - return isMapped(index) || super.has(key); - } - - @Override - public boolean has(final double key) { - final int index = ArrayIndex.getArrayIndex(key); - return isMapped(index) || super.has(key); - } - - @Override - public boolean has(final long key) { - final int index = ArrayIndex.getArrayIndex(key); - return isMapped(index) || super.has(key); - } - - @Override - public boolean has(final int key) { - final int index = ArrayIndex.getArrayIndex(key); - return isMapped(index) || super.has(key); - } - - @Override - public boolean hasOwnProperty(final Object key) { - final int index = ArrayIndex.getArrayIndex(key); - return isMapped(index) || super.hasOwnProperty(key); - } - - @Override - public boolean hasOwnProperty(final int key) { - final int index = ArrayIndex.getArrayIndex(key); - return isMapped(index) || super.hasOwnProperty(key); - } - - @Override - public boolean hasOwnProperty(final long key) { - final int index = ArrayIndex.getArrayIndex(key); - return isMapped(index) || super.hasOwnProperty(key); - } - - @Override - public boolean hasOwnProperty(final double key) { - final int index = ArrayIndex.getArrayIndex(key); - return isMapped(index) || super.hasOwnProperty(key); - } - @Override public boolean delete(final int key, final boolean strict) { final int index = ArrayIndex.getArrayIndex(key); - final boolean success = super.delete(key, strict); - if (success && namedArgs.has(index)) { - setDeleted(index); - } - return success; + return isMapped(index) ? deleteMapped(index, strict) : super.delete(key, strict); } @Override public boolean delete(final long key, final boolean strict) { final int index = ArrayIndex.getArrayIndex(key); - final boolean success = super.delete(key, strict); - if (success && namedArgs.has(index)) { - setDeleted(index); - } - return success; + return isMapped(index) ? deleteMapped(index, strict) : super.delete(key, strict); } @Override public boolean delete(final double key, final boolean strict) { final int index = ArrayIndex.getArrayIndex(key); - final boolean success = super.delete(key, strict); - if (success && namedArgs.has(index)) { - setDeleted(index); - } - return success; + return isMapped(index) ? deleteMapped(index, strict) : super.delete(key, strict); } @Override public boolean delete(final Object key, final boolean strict) { final int index = ArrayIndex.getArrayIndex(key); - final boolean success = super.delete(key, strict); - if (success && namedArgs.has(index)) { - setDeleted(index); - } - return success; + return isMapped(index) ? deleteMapped(index, strict) : super.delete(key, strict); } /** @@ -483,29 +152,27 @@ public final class NativeArguments extends ScriptObject { public boolean defineOwnProperty(final String key, final Object propertyDesc, final boolean reject) { final int index = ArrayIndex.getArrayIndex(key); if (index >= 0) { - final boolean allowed = super.defineOwnProperty(key, propertyDesc, false); - if (!allowed) { + final boolean isMapped = isMapped(index); + final Object oldValue = isMapped ? getArray().getObject(index) : null; + + if (!super.defineOwnProperty(key, propertyDesc, false)) { if (reject) { throw typeError("cant.redefine.property", key, ScriptRuntime.safeToString(this)); } return false; } - if (isMapped(index)) { + if (isMapped) { // When mapped argument is redefined, if new descriptor is accessor property // or data-non-writable property, we have to "unmap" (unlink). final PropertyDescriptor desc = toPropertyDescriptor(Global.instance(), propertyDesc); if (desc.type() == PropertyDescriptor.ACCESSOR) { - setDeleted(index); - } else { - // set "value" from new descriptor to named args - if (desc.has(PropertyDescriptor.VALUE)) { - namedArgs = namedArgs.set(index, desc.getValue(), false); - } - - if (desc.has(PropertyDescriptor.WRITABLE) && !desc.isWritable()) { - setDeleted(index); - } + setDeleted(index, oldValue); + } else if (desc.has(PropertyDescriptor.WRITABLE) && !desc.isWritable()) { + // delete and set value from new descriptor if it has one, otherwise use old value + setDeleted(index, desc.has(PropertyDescriptor.VALUE) ? desc.getValue() : oldValue); + } else if (desc.has(PropertyDescriptor.VALUE)) { + setArray(getArray().set(index, desc.getValue(), false)); } } @@ -519,31 +186,72 @@ public final class NativeArguments extends ScriptObject { // We track deletions using a bit set (delete arguments[index]) private boolean isDeleted(final int index) { - return (deleted != null) ? deleted.get(index) : false; + return deleted != null && deleted.get(index); } - private void setDeleted(final int index) { + private void setDeleted(final int index, final Object unmappedValue) { if (deleted == null) { - deleted = new BitSet((int)namedArgs.length()); + deleted = new BitSet(numMapped); } deleted.set(index, true); + setUnmappedArg(index, unmappedValue); + } + + private boolean deleteMapped(final int index, final boolean strict) { + final Object value = getArray().getObject(index); + final boolean success = super.delete(index, strict); + if (success) { + setDeleted(index, value); + } + return success; + } + + private Object getUnmappedArg(final int key) { + assert key >= 0 && key < numParams; + return unmappedArgs == null ? UNDEFINED : unmappedArgs.getObject(key); + } + + private void setUnmappedArg(final int key, final Object value) { + assert key >= 0 && key < numParams; + if (unmappedArgs == null) { + /* + * Declared number of parameters may be more or less than the actual passed + * runtime arguments count. We need to truncate or extend with undefined values. + * + * Example: + * + * // less declared params + * (function (x) { print(arguments); })(20, 44); + * + * // more declared params + * (function (x, y) { print(arguments); })(3); + */ + final Object[] newValues = new Object[numParams]; + System.arraycopy(getArray().asObjectArray(), 0, newValues, 0, numMapped); + if (numMapped < numParams) { + Arrays.fill(newValues, numMapped, numParams, UNDEFINED); + } + this.unmappedArgs = ArrayData.allocate(newValues); + } + // Set value of argument + unmappedArgs = unmappedArgs.set(key, value, false); } /** * Are arguments[index] and corresponding named parameter linked? * - * In non-strict mode, arguments[index] and corresponding named param - * are "linked" or "mapped". Modifications are tacked b/w each other - till - * (delete arguments[index]) is used. Once deleted, the corresponding arg - * is no longer 'mapped'. Please note that delete can happen only through - * the arguments array - named param can not be deleted. (delete is one-way). + * In non-strict mode, arguments[index] and corresponding named param are "linked" or "mapped" + * if the argument is provided by the caller. Modifications are tacked b/w each other - until + * (delete arguments[index]) is used. Once deleted, the corresponding arg is no longer 'mapped'. + * Please note that delete can happen only through the arguments array - named param can not + * be deleted. (delete is one-way). */ private boolean isMapped(final int index) { - // in named args and not marked as "deleted" - return namedArgs.has(index) && !isDeleted(index); + // in mapped named args and not marked as "deleted" + return index >= 0 && index < numMapped && !isDeleted(index); } - /** + /** * Factory to create correct Arguments object based on strict mode. * * @param arguments the actual arguments array passed diff --git a/test/script/basic/JDK-8022731.js b/test/script/basic/JDK-8022731.js new file mode 100644 index 00000000..635bd2d8 --- /dev/null +++ b/test/script/basic/JDK-8022731.js @@ -0,0 +1,93 @@ +/* + * 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-8022731: NativeArguments has wrong implementation of isMapped() + * + * @test + * @run + */ + +Object.defineProperty(Object.prototype, "0", {value: "proto"}); + +function test0(a, b) { + Object.defineProperty(arguments, "1", {get: function() { return "get" }}); + return arguments[0]; +} + +function test1(a, b) { + Object.defineProperty(arguments, "0", {get: function() { return "get" }}); + return a; +} + +function test2(a, b) { + Object.defineProperty(arguments, "0", {value: "value"}); + delete arguments[0]; + return a; +} + +function test3(a, b) { + arguments[1] = "arg1"; + return b; +} + +function test4(a, b) { + b = "b"; + return arguments[1]; +} + +function test5(a, b) { + Object.defineProperty(arguments, "0", {value: "value"}); + arguments[0] = "new"; + return a; +} + +function test6(a, b) { + Object.defineProperty(arguments, "0", {value: "value"}); + arguments[0] = "new"; + delete arguments[0]; + return a; +} + +function test7(a, b) { + Object.defineProperty(arguments, "0", {value: "value", writable: false}); + arguments[0] = "new"; + return a; +} + +print(test0()); +print(test0("p1", "p2")); +print(test1()); +print(test1("p1")); +print(test2()); +print(test2("p1")); +print(test3()); +print(test3(1, 2)); +print(test4()); +print(test4("p1", "p2")); +print(test5()); +print(test5("p1")); +print(test6()); +print(test6("p1")); +print(test7()); +print(test7("p1")); diff --git a/test/script/basic/JDK-8022731.js.EXPECTED b/test/script/basic/JDK-8022731.js.EXPECTED new file mode 100644 index 00000000..32d61309 --- /dev/null +++ b/test/script/basic/JDK-8022731.js.EXPECTED @@ -0,0 +1,16 @@ +proto +p1 +undefined +p1 +undefined +value +undefined +arg1 +undefined +b +undefined +new +undefined +new +undefined +value -- cgit v1.2.3 From 1c412e21631ae61e11d7aea26a791b047bada2cd Mon Sep 17 00:00:00 2001 From: sundar Date: Mon, 12 Aug 2013 17:08:01 +0530 Subject: 8022615: [nightly] Two nashorn print tests fail in nightly builds on Windows Reviewed-by: lagergren, jlaskey --- test/src/jdk/nashorn/api/scripting/ScriptEngineTest.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/src/jdk/nashorn/api/scripting/ScriptEngineTest.java b/test/src/jdk/nashorn/api/scripting/ScriptEngineTest.java index 53ca43a6..fe4bf39b 100644 --- a/test/src/jdk/nashorn/api/scripting/ScriptEngineTest.java +++ b/test/src/jdk/nashorn/api/scripting/ScriptEngineTest.java @@ -1235,7 +1235,8 @@ public class ScriptEngineTest { fail(t.getMessage()); } - assertEquals(sw.toString(), "hello\n"); + // dos2unix - fix line endings if running on windows + assertEquals(sw.toString().replaceAll("\r", ""), "hello\n"); } @Test @@ -1252,6 +1253,7 @@ public class ScriptEngineTest { fail(t.getMessage()); } - assertEquals(sw.toString(), "34 true hello\n"); + // dos2unix - fix line endings if running on windows + assertEquals(sw.toString().replaceAll("\r", ""), "34 true hello\n"); } } -- cgit v1.2.3 From c71516cda3e1f446d6cce1982676de00ae9b1ab5 Mon Sep 17 00:00:00 2001 From: sundar Date: Mon, 12 Aug 2013 18:16:28 +0530 Subject: 8022598: Object.getPrototypeOf should return null for host objects rather than throwing TypeError Reviewed-by: lagergren, jlaskey, attila, hannesw --- src/jdk/nashorn/internal/objects/NativeObject.java | 7 +++ test/script/basic/JDK-8022598.js | 56 ++++++++++++++++++++++ 2 files changed, 63 insertions(+) create mode 100644 test/script/basic/JDK-8022598.js diff --git a/src/jdk/nashorn/internal/objects/NativeObject.java b/src/jdk/nashorn/internal/objects/NativeObject.java index ff72ce5c..537ae1ff 100644 --- a/src/jdk/nashorn/internal/objects/NativeObject.java +++ b/src/jdk/nashorn/internal/objects/NativeObject.java @@ -113,6 +113,13 @@ public final class NativeObject { } else if (obj instanceof ScriptObjectMirror) { return ((ScriptObjectMirror)obj).getProto(); } else { + final JSType type = JSType.of(obj); + if (type == JSType.OBJECT) { + // host (Java) objects have null __proto__ + return null; + } + + // must be some JS primitive throw notAnObject(obj); } } diff --git a/test/script/basic/JDK-8022598.js b/test/script/basic/JDK-8022598.js new file mode 100644 index 00000000..95f2ab49 --- /dev/null +++ b/test/script/basic/JDK-8022598.js @@ -0,0 +1,56 @@ +/* + * 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-8022598: Object.getPrototypeOf should return null for host objects rather than throwing TypeError + * + * @test + * @run + */ + +// the following should not throw TypeError, just return null instead + +var proto = Object.getPrototypeOf(new java.lang.Object()); +if (proto !== null) { + fail("Expected 'null' __proto__ for host objects"); +} + +// on primitive should result in TypeError + +function checkTypeError(obj) { + try { + Object.getPrototypeOf(obj); + fail("Expected TypeError for Object.getPrototypeOf on " + obj); + } catch (e) { + if (! (e instanceof TypeError)) { + fail("Expected TypeError, but got " + e); + } + } +} + +checkTypeError(undefined); +checkTypeError(null); +checkTypeError(3.1415); +checkTypeError("hello"); +checkTypeError(false); +checkTypeError(true); -- cgit v1.2.3 From a3a8fdf9d75ed5a9a5149a108a3a9942e4146a36 Mon Sep 17 00:00:00 2001 From: jlaskey Date: Mon, 12 Aug 2013 18:00:17 -0300 Subject: 8022676: Confusing error message checking instanceof non-class Reviewed-by: jlaskey, sundar Contributed-by: michael.horowitz@oracle.com --- src/jdk/nashorn/internal/runtime/resources/Messages.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jdk/nashorn/internal/runtime/resources/Messages.properties b/src/jdk/nashorn/internal/runtime/resources/Messages.properties index 8ec4f7e1..dadde637 100644 --- a/src/jdk/nashorn/internal/runtime/resources/Messages.properties +++ b/src/jdk/nashorn/internal/runtime/resources/Messages.properties @@ -100,7 +100,7 @@ type.error.regex.cant.supply.flags=Cannot supply flags when constructing one Reg type.error.inconsistent.property.descriptor=inconsistent property descriptor type.error.bad.default.value=bad default value: {0} type.error.function.apply.expects.array=Function.prototype.apply expects an Array for second argument -type.error.instanceof.on.non.object=instanceof cannot be used on objects without [[HasInstance]] +type.error.instanceof.on.non.object=instanceof must be called with a javascript or java object as the right-hand argument type.error.cannot.convert.to.interface=object {0} cannot be converted to {1} due to "{2}" type.error.array.reduce.invalid.init=invalid initialValue for Array.prototype.reduce type.error.array.reduceright.invalid.init=invalid initialValue for Array.prototype.reduceRight -- cgit v1.2.3 From bbe0478e5c06a8ff8e05afb51047ad3ab95fbb18 Mon Sep 17 00:00:00 2001 From: sundar Date: Wed, 14 Aug 2013 20:51:53 +0530 Subject: 8023026: Array.prototype iterator functions like forEach, reduce should work for Java arrays, lists Reviewed-by: jlaskey, lagergren --HG-- rename : src/jdk/nashorn/internal/runtime/arrays/ReverseArrayIterator.java => src/jdk/nashorn/internal/runtime/arrays/ReverseScriptArrayIterator.java rename : src/jdk/nashorn/internal/runtime/arrays/ReverseMapIterator.java => src/jdk/nashorn/internal/runtime/arrays/ReverseScriptObjectIterator.java rename : src/jdk/nashorn/internal/runtime/arrays/ArrayIterator.java => src/jdk/nashorn/internal/runtime/arrays/ScriptArrayIterator.java rename : src/jdk/nashorn/internal/runtime/arrays/MapIterator.java => src/jdk/nashorn/internal/runtime/arrays/ScriptObjectIterator.java --- .../internal/runtime/arrays/ArrayIterator.java | 88 ---------------------- .../internal/runtime/arrays/ArrayLikeIterator.java | 27 +++++-- .../internal/runtime/arrays/JavaArrayIterator.java | 80 ++++++++++++++++++++ .../internal/runtime/arrays/JavaListIterator.java | 79 +++++++++++++++++++ .../internal/runtime/arrays/MapIterator.java | 80 -------------------- .../runtime/arrays/ReverseArrayIterator.java | 59 --------------- .../runtime/arrays/ReverseJavaArrayIterator.java | 58 ++++++++++++++ .../runtime/arrays/ReverseJavaListIterator.java | 58 ++++++++++++++ .../runtime/arrays/ReverseMapIterator.java | 55 -------------- .../runtime/arrays/ReverseScriptArrayIterator.java | 59 +++++++++++++++ .../arrays/ReverseScriptObjectIterator.java | 55 ++++++++++++++ .../runtime/arrays/ScriptArrayIterator.java | 88 ++++++++++++++++++++++ .../runtime/arrays/ScriptObjectIterator.java | 80 ++++++++++++++++++++ test/script/basic/JDK-8023026.js | 71 +++++++++++++++++ test/script/basic/JDK-8023026.js.EXPECTED | 42 +++++++++++ 15 files changed, 691 insertions(+), 288 deletions(-) delete mode 100644 src/jdk/nashorn/internal/runtime/arrays/ArrayIterator.java create mode 100644 src/jdk/nashorn/internal/runtime/arrays/JavaArrayIterator.java create mode 100644 src/jdk/nashorn/internal/runtime/arrays/JavaListIterator.java delete mode 100644 src/jdk/nashorn/internal/runtime/arrays/MapIterator.java delete mode 100644 src/jdk/nashorn/internal/runtime/arrays/ReverseArrayIterator.java create mode 100644 src/jdk/nashorn/internal/runtime/arrays/ReverseJavaArrayIterator.java create mode 100644 src/jdk/nashorn/internal/runtime/arrays/ReverseJavaListIterator.java delete mode 100644 src/jdk/nashorn/internal/runtime/arrays/ReverseMapIterator.java create mode 100644 src/jdk/nashorn/internal/runtime/arrays/ReverseScriptArrayIterator.java create mode 100644 src/jdk/nashorn/internal/runtime/arrays/ReverseScriptObjectIterator.java create mode 100644 src/jdk/nashorn/internal/runtime/arrays/ScriptArrayIterator.java create mode 100644 src/jdk/nashorn/internal/runtime/arrays/ScriptObjectIterator.java create mode 100644 test/script/basic/JDK-8023026.js create mode 100644 test/script/basic/JDK-8023026.js.EXPECTED diff --git a/src/jdk/nashorn/internal/runtime/arrays/ArrayIterator.java b/src/jdk/nashorn/internal/runtime/arrays/ArrayIterator.java deleted file mode 100644 index 8d2de2ce..00000000 --- a/src/jdk/nashorn/internal/runtime/arrays/ArrayIterator.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * 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.arrays; - -import jdk.nashorn.internal.runtime.ScriptObject; - -/** - * Iterator over a NativeArray - */ -class ArrayIterator extends ArrayLikeIterator { - - /** Array {@link ScriptObject} to iterate over */ - protected final ScriptObject array; - - /** length of array */ - protected final long length; - - /** - * Constructor - * @param array array to iterate over - * @param includeUndefined should undefined elements be included in iteration - */ - protected ArrayIterator(final ScriptObject array, final boolean includeUndefined) { - super(includeUndefined); - this.array = array; - this.length = array.getArray().length(); - } - - /** - * Is the current index still inside the array - * @return true if inside the array - */ - protected boolean indexInArray() { - return index < length; - } - - @Override - public Object next() { - return array.get(bumpIndex()); - } - - @Override - public long getLength() { - return length; - } - - @Override - public boolean hasNext() { - if (!includeUndefined) { - while (indexInArray()) { - if (array.has(index)) { - break; - } - bumpIndex(); - } - } - - return indexInArray(); - } - - @Override - public void remove() { - array.delete(index, false); - } -} diff --git a/src/jdk/nashorn/internal/runtime/arrays/ArrayLikeIterator.java b/src/jdk/nashorn/internal/runtime/arrays/ArrayLikeIterator.java index 70f74d8e..ab16d220 100644 --- a/src/jdk/nashorn/internal/runtime/arrays/ArrayLikeIterator.java +++ b/src/jdk/nashorn/internal/runtime/arrays/ArrayLikeIterator.java @@ -26,6 +26,7 @@ package jdk.nashorn.internal.runtime.arrays; import java.util.Iterator; +import java.util.List; import jdk.nashorn.api.scripting.ScriptObjectMirror; import jdk.nashorn.internal.runtime.JSType; import jdk.nashorn.internal.runtime.ScriptObject; @@ -49,7 +50,7 @@ abstract public class ArrayLikeIterator implements Iterator { * * @param includeUndefined should undefined elements be included in the iteration? */ - protected ArrayLikeIterator(final boolean includeUndefined) { + ArrayLikeIterator(final boolean includeUndefined) { this.includeUndefined = includeUndefined; this.index = 0; } @@ -118,18 +119,26 @@ abstract public class ArrayLikeIterator implements Iterator { Object obj = object; if (ScriptObject.isArray(obj)) { - return new ArrayIterator((ScriptObject) obj, includeUndefined); + return new ScriptArrayIterator((ScriptObject) obj, includeUndefined); } obj = JSType.toScriptObject(obj); if (obj instanceof ScriptObject) { - return new MapIterator((ScriptObject)obj, includeUndefined); + return new ScriptObjectIterator((ScriptObject)obj, includeUndefined); } if (obj instanceof ScriptObjectMirror) { return new ScriptObjectMirrorIterator((ScriptObjectMirror)obj, includeUndefined); } + if (obj instanceof List) { + return new JavaListIterator((List)obj, includeUndefined); + } + + if (obj != null && obj.getClass().isArray()) { + return new JavaArrayIterator(obj, includeUndefined); + } + return new EmptyArrayLikeIterator(); } @@ -143,19 +152,25 @@ abstract public class ArrayLikeIterator implements Iterator { Object obj = object; if (ScriptObject.isArray(obj)) { - return new ReverseArrayIterator((ScriptObject) obj, includeUndefined); + return new ReverseScriptArrayIterator((ScriptObject) obj, includeUndefined); } obj = JSType.toScriptObject(obj); if (obj instanceof ScriptObject) { - return new ReverseMapIterator((ScriptObject)obj, includeUndefined); + return new ReverseScriptObjectIterator((ScriptObject)obj, includeUndefined); } if (obj instanceof ScriptObjectMirror) { return new ReverseScriptObjectMirrorIterator((ScriptObjectMirror)obj, includeUndefined); } - assert !obj.getClass().isArray(); + if (obj instanceof List) { + return new ReverseJavaListIterator((List)obj, includeUndefined); + } + + if (obj != null && obj.getClass().isArray()) { + return new ReverseJavaArrayIterator(obj, includeUndefined); + } return new EmptyArrayLikeIterator(); } diff --git a/src/jdk/nashorn/internal/runtime/arrays/JavaArrayIterator.java b/src/jdk/nashorn/internal/runtime/arrays/JavaArrayIterator.java new file mode 100644 index 00000000..92a80029 --- /dev/null +++ b/src/jdk/nashorn/internal/runtime/arrays/JavaArrayIterator.java @@ -0,0 +1,80 @@ +/* + * 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.arrays; + +import java.lang.reflect.Array; + +/** + * Iterator over a Java List. + */ +class JavaArrayIterator extends ArrayLikeIterator { + + /** Array to iterate over */ + protected final Object array; + + /** length of array */ + protected final long length; + + /** + * Constructor + * @param array array to iterate over + * @param includeUndefined should undefined elements be included in iteration + */ + protected JavaArrayIterator(final Object array, final boolean includeUndefined) { + super(includeUndefined); + assert array.getClass().isArray() : "expecting Java array object"; + this.array = array; + this.length = Array.getLength(array); + } + + /** + * Is the current index still inside the array + * @return true if inside the array + */ + protected boolean indexInArray() { + return index < length; + } + + @Override + public Object next() { + return Array.get(array, (int)bumpIndex()); + } + + @Override + public long getLength() { + return length; + } + + @Override + public boolean hasNext() { + return indexInArray(); + } + + @Override + public void remove() { + throw new UnsupportedOperationException("remove"); + } +} \ No newline at end of file diff --git a/src/jdk/nashorn/internal/runtime/arrays/JavaListIterator.java b/src/jdk/nashorn/internal/runtime/arrays/JavaListIterator.java new file mode 100644 index 00000000..96a8b25b --- /dev/null +++ b/src/jdk/nashorn/internal/runtime/arrays/JavaListIterator.java @@ -0,0 +1,79 @@ +/* + * 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.arrays; + +import java.util.List; + +/** + * Iterator over a Java List. + */ +class JavaListIterator extends ArrayLikeIterator { + + /** {@link java.util.List} to iterate over */ + protected final List list; + + /** length of array */ + protected final long length; + + /** + * Constructor + * @param list list to iterate over + * @param includeUndefined should undefined elements be included in iteration + */ + protected JavaListIterator(final List list, final boolean includeUndefined) { + super(includeUndefined); + this.list = list; + this.length = list.size(); + } + + /** + * Is the current index still inside the array + * @return true if inside the array + */ + protected boolean indexInArray() { + return index < length; + } + + @Override + public Object next() { + return list.get((int)bumpIndex()); + } + + @Override + public long getLength() { + return length; + } + + @Override + public boolean hasNext() { + return indexInArray(); + } + + @Override + public void remove() { + list.remove(index); + } +} diff --git a/src/jdk/nashorn/internal/runtime/arrays/MapIterator.java b/src/jdk/nashorn/internal/runtime/arrays/MapIterator.java deleted file mode 100644 index f8b40cfe..00000000 --- a/src/jdk/nashorn/internal/runtime/arrays/MapIterator.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * 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.arrays; - -import java.util.NoSuchElementException; -import jdk.nashorn.internal.runtime.JSType; -import jdk.nashorn.internal.runtime.ScriptObject; - -/** - * Iterator over a map - */ -class MapIterator extends ArrayLikeIterator { - - protected final ScriptObject obj; - private final long length; - - MapIterator(final ScriptObject obj, final boolean includeUndefined) { - super(includeUndefined); - this.obj = obj; - this.length = JSType.toUint32(obj.getLength()); - this.index = 0; - } - - protected boolean indexInArray() { - return index < length; - } - - @Override - public long getLength() { - return length; - } - - @Override - public boolean hasNext() { - if (length == 0L) { - return false; //return empty string if toUint32(length) == 0 - } - - while (indexInArray()) { - if (obj.has(index) || includeUndefined) { - break; - } - bumpIndex(); - } - - return indexInArray(); - } - - @Override - public Object next() { - if (indexInArray()) { - return obj.get(bumpIndex()); - } - - throw new NoSuchElementException(); - } -} diff --git a/src/jdk/nashorn/internal/runtime/arrays/ReverseArrayIterator.java b/src/jdk/nashorn/internal/runtime/arrays/ReverseArrayIterator.java deleted file mode 100644 index 4746de86..00000000 --- a/src/jdk/nashorn/internal/runtime/arrays/ReverseArrayIterator.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * 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.arrays; - -import jdk.nashorn.internal.runtime.ScriptObject; - -/** - * Reverse iterator over a NativeArray - */ -final class ReverseArrayIterator extends ArrayIterator { - - /** - * Constructor - * @param array array to iterate over - * @param includeUndefined should undefined elements be included in iteration - */ - public ReverseArrayIterator(final ScriptObject array, final boolean includeUndefined) { - super(array, includeUndefined); - this.index = array.getArray().length() - 1; - } - - @Override - public boolean isReverse() { - return true; - } - - @Override - protected boolean indexInArray() { - return index >= 0; - } - - @Override - protected long bumpIndex() { - return index--; - } -} diff --git a/src/jdk/nashorn/internal/runtime/arrays/ReverseJavaArrayIterator.java b/src/jdk/nashorn/internal/runtime/arrays/ReverseJavaArrayIterator.java new file mode 100644 index 00000000..dcb37cfd --- /dev/null +++ b/src/jdk/nashorn/internal/runtime/arrays/ReverseJavaArrayIterator.java @@ -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. 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.arrays; + +import java.lang.reflect.Array; + +/** + * Reverse iterator over a array + */ +final class ReverseJavaArrayIterator extends JavaArrayIterator { + /** + * Constructor + * @param array array to iterate over + * @param includeUndefined should undefined elements be included in iteration + */ + public ReverseJavaArrayIterator(final Object array, final boolean includeUndefined) { + super(array, includeUndefined); + this.index = Array.getLength(array) - 1; + } + + @Override + public boolean isReverse() { + return true; + } + + @Override + protected boolean indexInArray() { + return index >= 0; + } + + @Override + protected long bumpIndex() { + return index--; + } +} \ No newline at end of file diff --git a/src/jdk/nashorn/internal/runtime/arrays/ReverseJavaListIterator.java b/src/jdk/nashorn/internal/runtime/arrays/ReverseJavaListIterator.java new file mode 100644 index 00000000..390858bc --- /dev/null +++ b/src/jdk/nashorn/internal/runtime/arrays/ReverseJavaListIterator.java @@ -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. 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.arrays; + +import java.util.List; + +/** + * Reverse iterator over a List + */ +final class ReverseJavaListIterator extends JavaListIterator { + /** + * Constructor + * @param list list to iterate over + * @param includeUndefined should undefined elements be included in iteration + */ + public ReverseJavaListIterator(final List list, final boolean includeUndefined) { + super(list, includeUndefined); + this.index = list.size() - 1; + } + + @Override + public boolean isReverse() { + return true; + } + + @Override + protected boolean indexInArray() { + return index >= 0; + } + + @Override + protected long bumpIndex() { + return index--; + } +} diff --git a/src/jdk/nashorn/internal/runtime/arrays/ReverseMapIterator.java b/src/jdk/nashorn/internal/runtime/arrays/ReverseMapIterator.java deleted file mode 100644 index 0822b5a4..00000000 --- a/src/jdk/nashorn/internal/runtime/arrays/ReverseMapIterator.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * 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.arrays; - -import jdk.nashorn.internal.runtime.JSType; -import jdk.nashorn.internal.runtime.ScriptObject; - -/** - * Reverse iterator over a map - */ -final class ReverseMapIterator extends MapIterator { - - ReverseMapIterator(final ScriptObject obj, final boolean includeUndefined) { - super(obj, includeUndefined); - this.index = JSType.toUint32(obj.getLength()) - 1; - } - - @Override - public boolean isReverse() { - return true; - } - - @Override - protected boolean indexInArray() { - return index >= 0; - } - - @Override - protected long bumpIndex() { - return index--; - } -} diff --git a/src/jdk/nashorn/internal/runtime/arrays/ReverseScriptArrayIterator.java b/src/jdk/nashorn/internal/runtime/arrays/ReverseScriptArrayIterator.java new file mode 100644 index 00000000..fae1a8ff --- /dev/null +++ b/src/jdk/nashorn/internal/runtime/arrays/ReverseScriptArrayIterator.java @@ -0,0 +1,59 @@ +/* + * 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.arrays; + +import jdk.nashorn.internal.runtime.ScriptObject; + +/** + * Reverse iterator over a NativeArray + */ +final class ReverseScriptArrayIterator extends ScriptArrayIterator { + + /** + * Constructor + * @param array array to iterate over + * @param includeUndefined should undefined elements be included in iteration + */ + public ReverseScriptArrayIterator(final ScriptObject array, final boolean includeUndefined) { + super(array, includeUndefined); + this.index = array.getArray().length() - 1; + } + + @Override + public boolean isReverse() { + return true; + } + + @Override + protected boolean indexInArray() { + return index >= 0; + } + + @Override + protected long bumpIndex() { + return index--; + } +} diff --git a/src/jdk/nashorn/internal/runtime/arrays/ReverseScriptObjectIterator.java b/src/jdk/nashorn/internal/runtime/arrays/ReverseScriptObjectIterator.java new file mode 100644 index 00000000..533104db --- /dev/null +++ b/src/jdk/nashorn/internal/runtime/arrays/ReverseScriptObjectIterator.java @@ -0,0 +1,55 @@ +/* + * 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.arrays; + +import jdk.nashorn.internal.runtime.JSType; +import jdk.nashorn.internal.runtime.ScriptObject; + +/** + * Reverse iterator over a map + */ +final class ReverseScriptObjectIterator extends ScriptObjectIterator { + + ReverseScriptObjectIterator(final ScriptObject obj, final boolean includeUndefined) { + super(obj, includeUndefined); + this.index = JSType.toUint32(obj.getLength()) - 1; + } + + @Override + public boolean isReverse() { + return true; + } + + @Override + protected boolean indexInArray() { + return index >= 0; + } + + @Override + protected long bumpIndex() { + return index--; + } +} diff --git a/src/jdk/nashorn/internal/runtime/arrays/ScriptArrayIterator.java b/src/jdk/nashorn/internal/runtime/arrays/ScriptArrayIterator.java new file mode 100644 index 00000000..0a617815 --- /dev/null +++ b/src/jdk/nashorn/internal/runtime/arrays/ScriptArrayIterator.java @@ -0,0 +1,88 @@ +/* + * 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.arrays; + +import jdk.nashorn.internal.runtime.ScriptObject; + +/** + * Iterator over a NativeArray + */ +class ScriptArrayIterator extends ArrayLikeIterator { + + /** Array {@link ScriptObject} to iterate over */ + protected final ScriptObject array; + + /** length of array */ + protected final long length; + + /** + * Constructor + * @param array array to iterate over + * @param includeUndefined should undefined elements be included in iteration + */ + protected ScriptArrayIterator(final ScriptObject array, final boolean includeUndefined) { + super(includeUndefined); + this.array = array; + this.length = array.getArray().length(); + } + + /** + * Is the current index still inside the array + * @return true if inside the array + */ + protected boolean indexInArray() { + return index < length; + } + + @Override + public Object next() { + return array.get(bumpIndex()); + } + + @Override + public long getLength() { + return length; + } + + @Override + public boolean hasNext() { + if (!includeUndefined) { + while (indexInArray()) { + if (array.has(index)) { + break; + } + bumpIndex(); + } + } + + return indexInArray(); + } + + @Override + public void remove() { + array.delete(index, false); + } +} diff --git a/src/jdk/nashorn/internal/runtime/arrays/ScriptObjectIterator.java b/src/jdk/nashorn/internal/runtime/arrays/ScriptObjectIterator.java new file mode 100644 index 00000000..73b4c1f5 --- /dev/null +++ b/src/jdk/nashorn/internal/runtime/arrays/ScriptObjectIterator.java @@ -0,0 +1,80 @@ +/* + * 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.arrays; + +import java.util.NoSuchElementException; +import jdk.nashorn.internal.runtime.JSType; +import jdk.nashorn.internal.runtime.ScriptObject; + +/** + * Iterator over a map + */ +class ScriptObjectIterator extends ArrayLikeIterator { + + protected final ScriptObject obj; + private final long length; + + ScriptObjectIterator(final ScriptObject obj, final boolean includeUndefined) { + super(includeUndefined); + this.obj = obj; + this.length = JSType.toUint32(obj.getLength()); + this.index = 0; + } + + protected boolean indexInArray() { + return index < length; + } + + @Override + public long getLength() { + return length; + } + + @Override + public boolean hasNext() { + if (length == 0L) { + return false; //return empty string if toUint32(length) == 0 + } + + while (indexInArray()) { + if (obj.has(index) || includeUndefined) { + break; + } + bumpIndex(); + } + + return indexInArray(); + } + + @Override + public Object next() { + if (indexInArray()) { + return obj.get(bumpIndex()); + } + + throw new NoSuchElementException(); + } +} diff --git a/test/script/basic/JDK-8023026.js b/test/script/basic/JDK-8023026.js new file mode 100644 index 00000000..9080ec8c --- /dev/null +++ b/test/script/basic/JDK-8023026.js @@ -0,0 +1,71 @@ +/* + * 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-8023026: Array.prototype iterator functions like forEach, reduce should work for Java arrays, lists + * + * @test + * @run + */ + +function checkIterations(obj) { + if (typeof obj.getClass == 'function') { + print("iterating on an object of " + obj.getClass()); + } else { + print("iterating on " + String(obj)); + } + + Array.prototype.forEach.call(obj, + function(x) { print("forEach " + x); }); + + print("left sum " + Array.prototype.reduce.call(obj, + function(x, y) { print("reduce", x, y); return x + y; })); + + print("right sum " + Array.prototype.reduceRight.call(obj, + function(x, y) { print("reduceRight", x, y); return x + y; })); + + print("squared " + Array.prototype.map.call(obj, + function(x) x*x)); +} + +var array = new (Java.type("[I"))(4); +for (var i in array) { + array[i] = i; +} + +checkIterations(array); + +var list = new java.util.ArrayList(); +list.add(1); +list.add(3); +list.add(5); +list.add(7); + +checkIterations(list); + +var mirror = loadWithNewGlobal({ + name: "test", + script: "[2, 4, 6, 8]" +}); + +checkIterations(mirror); diff --git a/test/script/basic/JDK-8023026.js.EXPECTED b/test/script/basic/JDK-8023026.js.EXPECTED new file mode 100644 index 00000000..333a1ab4 --- /dev/null +++ b/test/script/basic/JDK-8023026.js.EXPECTED @@ -0,0 +1,42 @@ +iterating on an object of class [I +forEach 0 +forEach 1 +forEach 2 +forEach 3 +reduce 0 1 +reduce 1 2 +reduce 3 3 +left sum 6 +reduceRight 3 2 +reduceRight 5 1 +reduceRight 6 0 +right sum 6 +squared 0,1,4,9 +iterating on an object of class java.util.ArrayList +forEach 1 +forEach 3 +forEach 5 +forEach 7 +reduce 1 3 +reduce 4 5 +reduce 9 7 +left sum 16 +reduceRight 7 5 +reduceRight 12 3 +reduceRight 15 1 +right sum 16 +squared 1,9,25,49 +iterating on [object Array] +forEach 2 +forEach 4 +forEach 6 +forEach 8 +reduce 2 4 +reduce 6 6 +reduce 12 8 +left sum 20 +reduceRight 8 6 +reduceRight 14 4 +reduceRight 18 2 +right sum 20 +squared 4,16,36,64 -- cgit v1.2.3 From 1469c6fc425a52647d14cbf318a379ab49084eb7 Mon Sep 17 00:00:00 2001 From: sundar Date: Fri, 16 Aug 2013 15:04:36 +0530 Subject: 8020355: bind on built-in constructors don't use bound argument values Reviewed-by: lagergren, hannesw --- .../internal/runtime/ScriptFunctionData.java | 11 +++- test/script/basic/JDK-8020355.js | 63 ++++++++++++++++++++++ 2 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 test/script/basic/JDK-8020355.js diff --git a/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java b/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java index c1c1de6e..06a12c00 100644 --- a/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java +++ b/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java @@ -250,9 +250,18 @@ public abstract class ScriptFunctionData { final int length = args == null ? 0 : args.length; CompiledFunctions boundList = new CompiledFunctions(); - for (final CompiledFunction inv : code) { + if (code.size() == 1) { + // only one variant - bind that + boundList.add(bind(code.first(), fn, self, allArgs)); + } else { + // There are specialized versions. Get the most generic one. + // This is to avoid ambiguous overloaded versions of bound and + // specialized variants and choosing wrong overload. + final MethodHandle genInvoker = getGenericInvoker(); + final CompiledFunction inv = new CompiledFunction(genInvoker.type(), genInvoker, getGenericConstructor()); boundList.add(bind(inv, fn, self, allArgs)); } + ScriptFunctionData boundData = new FinalScriptFunctionData(name, arity == -1 ? -1 : Math.max(0, arity - length), boundList, isStrict(), isBuiltin(), isConstructor()); return boundData; } diff --git a/test/script/basic/JDK-8020355.js b/test/script/basic/JDK-8020355.js new file mode 100644 index 00000000..262c458a --- /dev/null +++ b/test/script/basic/JDK-8020355.js @@ -0,0 +1,63 @@ +/* + * 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-8020355: bind on built-in constructors don't use bound argument values + * + * @test + * @run + */ + +if (Array.bind(null, 2)().length != 2) { + fail("Expected Array.bind(null, 2)().length to be 2"); +} + +if (RegExp.bind(null, "a")().source.length != 1) { + fail("Expected RegExp.bind(null, 'a')().source.length to be 1"); +} + +// check user defined functions as well + +var res = (function(x, y) { return x*y }).bind(null, 20, 30)(); +if (res != 600) { + fail("Expected 600, but got " + res); +} + +var obj = new ((function(x, y) { this.foo = x*y }).bind({}, 20, 30))(); +if (obj.foo != 600) { + fail("Expected this.foo = 600, but got " + res); +} + +// try variadic function as well + +var res = (function() { return arguments[0]*arguments[1] }).bind(null, 20, 30)(); +if (res != 600) { + fail("Expected 600, but got " + res); +} + +var obj = new ((function(x, y) { this.foo = arguments[0]*arguments[1] }).bind({}, 20, 30))(); +if (obj.foo != 600) { + fail("Expected this.foo = 600, but got " + res); +} + + -- cgit v1.2.3 From 7b14a93a120dd22e1b48f5b7802c0ea6c96619c2 Mon Sep 17 00:00:00 2001 From: hannesw Date: Fri, 16 Aug 2013 13:42:44 +0200 Subject: 8019985: Date.parse("2000-01-01T00:00:00.Z") should return NaN Reviewed-by: sundar, jlaskey --- src/jdk/nashorn/internal/parser/DateParser.java | 31 ++++++++++----- test/script/basic/JDK-8019985.js | 50 +++++++++++++++++++++++++ 2 files changed, 71 insertions(+), 10 deletions(-) create mode 100644 test/script/basic/JDK-8019985.js diff --git a/src/jdk/nashorn/internal/parser/DateParser.java b/src/jdk/nashorn/internal/parser/DateParser.java index 34832bb1..b5f7a2a2 100644 --- a/src/jdk/nashorn/internal/parser/DateParser.java +++ b/src/jdk/nashorn/internal/parser/DateParser.java @@ -141,7 +141,7 @@ public class DateParser { * Try parsing the date string according to the rules laid out in ES5 15.9.1.15. * The date string must conform to the following format: * - *
  [('-'|'+')yy]yyyy[-MM[-dd]][hh:mm[:ss[.sss]][Z|(+|-)hh:mm]] 
+ *
  [('-'|'+')yy]yyyy[-MM[-dd]][Thh:mm[:ss[.sss]][Z|(+|-)hh:mm]] 
* *

If the string does not contain a time zone offset, the TIMEZONE field * is set to 0 (GMT).

@@ -249,7 +249,7 @@ public class DateParser { switch (token) { case NUMBER: - if (skip(':')) { + if (skipDelimiter(':')) { // A number followed by ':' is parsed as time if (!setTimeField(numValue)) { return false; @@ -260,14 +260,14 @@ public class DateParser { if (token != Token.NUMBER || !setTimeField(numValue)) { return false; } - } while (skip(isSet(SECOND) ? '.' : ':')); + } while (skipDelimiter(isSet(SECOND) ? '.' : ':')); } else { // Parse as date token if (!setDateField(numValue)) { return false; } - skip('-'); + skipDelimiter('-'); } break; @@ -297,7 +297,7 @@ public class DateParser { break; } if (nameValue.type != Name.TIMEZONE_ID) { - skip('-'); + skipDelimiter('-'); } break; @@ -359,7 +359,18 @@ public class DateParser { return pos < length ? string.charAt(pos) : -1; } - private boolean skip(final char c) { + // Skip delimiter if followed by a number. Used for ISO 8601 formatted dates + private boolean skipNumberDelimiter(final char c) { + if (pos < length - 1 && string.charAt(pos) == c + && Character.getType(string.charAt(pos + 1)) == DECIMAL_DIGIT_NUMBER) { + token = null; + pos++; + return true; + } + return false; + } + + private boolean skipDelimiter(final char c) { if (pos < length && string.charAt(pos) == c) { token = null; pos++; @@ -452,14 +463,14 @@ public class DateParser { switch (currentField) { case YEAR: case MONTH: - return skip('-') || peek() == 'T' || peek() == -1; + return skipNumberDelimiter('-') || peek() == 'T' || peek() == -1; case DAY: return peek() == 'T' || peek() == -1; case HOUR: case MINUTE: - return skip(':') || endOfTime(); + return skipNumberDelimiter(':') || endOfTime(); case SECOND: - return skip('.') || endOfTime(); + return skipNumberDelimiter('.') || endOfTime(); default: return true; } @@ -515,7 +526,7 @@ public class DateParser { private int readTimeZoneOffset() { final int sign = string.charAt(pos - 1) == '+' ? 1 : -1; int offset = readNumber(2); - skip(':'); + skipDelimiter(':'); offset = offset * 60 + readNumber(2); return sign * offset; } diff --git a/test/script/basic/JDK-8019985.js b/test/script/basic/JDK-8019985.js new file mode 100644 index 00000000..adc7fbf6 --- /dev/null +++ b/test/script/basic/JDK-8019985.js @@ -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-8019985: Date.parse("2000-01-01T00:00:00.Z") should return NaN + * + * @test + * @run + */ + +function testFail(str) { + if (!isNaN(Date.parse(str))) { + throw new Error("Parsed invalid date string: " + str); + } +} + +function testOk(str) { + if (isNaN(Date.parse(str))) { + throw new Error("Failed to parse valid date string: " + str); + } +} + +testFail("2000-01-01T00:00:00.Z"); +testFail("2000-01-01T00:00:Z"); +testFail("2000-01-01T00:Z"); +testFail("2000-01-01T00Z"); +testOk("2000-01-01T00:00:00.000Z"); +testOk("2000-01-01T00:00:00.0Z"); +testOk("2000-01-01T00:00:00Z"); +testOk("2000-01-01T00:00Z"); -- cgit v1.2.3 From 2e2ab765bd72952c212ab22582de2f9e8cbdc89a Mon Sep 17 00:00:00 2001 From: lagergren Date: Fri, 16 Aug 2013 18:51:53 +0200 Subject: 8023017: SUB missing for widest op == number for BinaryNode Reviewed-by: sundar, jlaskey --- .../internal/codegen/ObjectClassGenerator.java | 3 ++- .../nashorn/internal/codegen/ObjectCreator.java | 8 +++++--- src/jdk/nashorn/internal/ir/BinaryNode.java | 1 + src/jdk/nashorn/internal/ir/BreakableNode.java | 8 ++++++++ src/jdk/nashorn/internal/ir/IdentNode.java | 4 ++-- .../nashorn/internal/ir/LexicalContextNode.java | 8 +++++++- .../nashorn/internal/objects/NativeArguments.java | 3 +-- src/jdk/nashorn/internal/objects/NativeArray.java | 4 ++-- src/jdk/nashorn/internal/parser/Parser.java | 6 +++--- src/jdk/nashorn/internal/runtime/Context.java | 2 ++ .../runtime/RecompilableScriptFunctionData.java | 2 +- .../nashorn/internal/runtime/ScriptFunction.java | 23 +++++++++++----------- src/jdk/nashorn/internal/runtime/ScriptObject.java | 17 +++++++++++++--- .../internal/runtime/arrays/ArrayLikeIterator.java | 4 ++-- .../internal/runtime/arrays/LongArrayData.java | 3 +-- .../internal/runtime/arrays/SparseArrayData.java | 2 +- .../runtime/linker/BoundDynamicMethod.java | 2 +- .../runtime/linker/BoundDynamicMethodLinker.java | 2 +- .../runtime/linker/JavaAdapterClassLoader.java | 3 +-- 19 files changed, 66 insertions(+), 39 deletions(-) diff --git a/src/jdk/nashorn/internal/codegen/ObjectClassGenerator.java b/src/jdk/nashorn/internal/codegen/ObjectClassGenerator.java index fa3d19e5..21cc3c5e 100644 --- a/src/jdk/nashorn/internal/codegen/ObjectClassGenerator.java +++ b/src/jdk/nashorn/internal/codegen/ObjectClassGenerator.java @@ -317,7 +317,8 @@ public final class ObjectClassGenerator { final String className = getClassName(fieldCount); final String superName = className(ScriptObject.class); final ClassEmitter classEmitter = newClassEmitter(className, superName); - final List initFields = addFields(classEmitter, fieldCount); + + addFields(classEmitter, fieldCount); final MethodEmitter init = newInitMethod(classEmitter); init.returnVoid(); diff --git a/src/jdk/nashorn/internal/codegen/ObjectCreator.java b/src/jdk/nashorn/internal/codegen/ObjectCreator.java index 2a8ebba7..d129d591 100644 --- a/src/jdk/nashorn/internal/codegen/ObjectCreator.java +++ b/src/jdk/nashorn/internal/codegen/ObjectCreator.java @@ -45,9 +45,11 @@ public abstract class ObjectCreator { /** Code generator */ protected final CodeGenerator codegen; - private final boolean isScope; - private final boolean hasArguments; - protected PropertyMap propertyMap; + /** Property map */ + protected PropertyMap propertyMap; + + private final boolean isScope; + private final boolean hasArguments; /** * Constructor diff --git a/src/jdk/nashorn/internal/ir/BinaryNode.java b/src/jdk/nashorn/internal/ir/BinaryNode.java index 1576fb93..169772d7 100644 --- a/src/jdk/nashorn/internal/ir/BinaryNode.java +++ b/src/jdk/nashorn/internal/ir/BinaryNode.java @@ -99,6 +99,7 @@ public final class BinaryNode extends Expression implements Assignment * - *
{@code
+     * 
      *   try {
      *     return 2;
      *   } finally {
      *     return 3;
      *   }
-     * }
+ * } * * @return true if can have callsite type */ diff --git a/src/jdk/nashorn/internal/ir/LexicalContextNode.java b/src/jdk/nashorn/internal/ir/LexicalContextNode.java index bb6a681d..b53d9f6b 100644 --- a/src/jdk/nashorn/internal/ir/LexicalContextNode.java +++ b/src/jdk/nashorn/internal/ir/LexicalContextNode.java @@ -44,8 +44,14 @@ public interface LexicalContextNode { Node accept(final LexicalContext lc, final NodeVisitor visitor); // Would be a default method on Java 8 + /** + * Helper class for accept for items of this lexical context, delegates to the + * subclass accept and makes sure that the node is on the context before accepting + * and gets popped after accepting (and that the stack is consistent in that the + * node has been replaced with the possible new node resulting in visitation) + */ static class Acceptor { - static Node accept(LexicalContextNode node, final NodeVisitor visitor) { + static Node accept(final LexicalContextNode node, final NodeVisitor visitor) { final LexicalContext lc = visitor.getLexicalContext(); lc.push(node); final LexicalContextNode newNode = (LexicalContextNode)node.accept(lc, visitor); diff --git a/src/jdk/nashorn/internal/objects/NativeArguments.java b/src/jdk/nashorn/internal/objects/NativeArguments.java index 55c79da9..3a853eff 100644 --- a/src/jdk/nashorn/internal/objects/NativeArguments.java +++ b/src/jdk/nashorn/internal/objects/NativeArguments.java @@ -266,9 +266,8 @@ public final class NativeArguments extends ScriptObject { final ScriptObject proto = global.getObjectPrototype(); if (isStrict) { return new NativeStrictArguments(arguments, numParams, proto, global.getStrictArgumentsMap()); - } else { - return new NativeArguments(arguments, callee, numParams, proto, global.getArgumentsMap()); } + return new NativeArguments(arguments, callee, numParams, proto, global.getArgumentsMap()); } /** diff --git a/src/jdk/nashorn/internal/objects/NativeArray.java b/src/jdk/nashorn/internal/objects/NativeArray.java index e03cd8dd..34691194 100644 --- a/src/jdk/nashorn/internal/objects/NativeArray.java +++ b/src/jdk/nashorn/internal/objects/NativeArray.java @@ -638,9 +638,9 @@ public final class NativeArray extends ScriptObject { if (isScriptArray || obj instanceof Iterable || (obj != null && obj.getClass().isArray())) { final Iterator iter = arrayLikeIterator(obj, true); if (iter.hasNext()) { - for(int i = 0; iter.hasNext(); ++i) { + for (int i = 0; iter.hasNext(); ++i) { final Object value = iter.next(); - if(value == ScriptRuntime.UNDEFINED && isScriptObject && !((ScriptObject)obj).has(i)) { + if (value == ScriptRuntime.UNDEFINED && isScriptObject && !((ScriptObject)obj).has(i)) { // TODO: eventually rewrite arrayLikeIterator to use a three-state enum for handling // UNDEFINED instead of an "includeUndefined" boolean with states SKIP, INCLUDE, // RETURN_EMPTY. Until then, this is how we'll make sure that empty elements don't make it diff --git a/src/jdk/nashorn/internal/parser/Parser.java b/src/jdk/nashorn/internal/parser/Parser.java index fd97adde..ab008900 100644 --- a/src/jdk/nashorn/internal/parser/Parser.java +++ b/src/jdk/nashorn/internal/parser/Parser.java @@ -160,10 +160,10 @@ public class Parser extends AbstractParser { if (this.scripting) { this.lineInfoReceiver = new Lexer.LineInfoReceiver() { @Override - public void lineInfo(final int line, final int linePosition) { + public void lineInfo(final int receiverLine, final int receiverLinePosition) { // update the parser maintained line information - Parser.this.line = line; - Parser.this.linePosition = linePosition; + Parser.this.line = receiverLine; + Parser.this.linePosition = receiverLinePosition; } }; } else { diff --git a/src/jdk/nashorn/internal/runtime/Context.java b/src/jdk/nashorn/internal/runtime/Context.java index 8ff85b93..8834592a 100644 --- a/src/jdk/nashorn/internal/runtime/Context.java +++ b/src/jdk/nashorn/internal/runtime/Context.java @@ -48,6 +48,7 @@ import java.security.Permissions; import java.security.PrivilegedAction; import java.security.ProtectionDomain; import java.util.Map; + import jdk.internal.org.objectweb.asm.ClassReader; import jdk.internal.org.objectweb.asm.util.CheckClassAdapter; import jdk.nashorn.api.scripting.ScriptObjectMirror; @@ -888,6 +889,7 @@ public final class Context { return script; } + @SuppressWarnings("static-method") private ScriptLoader createNewLoader() { return AccessController.doPrivileged( new PrivilegedAction() { diff --git a/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java b/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java index 859a688c..a64479a5 100644 --- a/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java +++ b/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java @@ -47,7 +47,7 @@ import jdk.nashorn.internal.parser.TokenType; * This is a subclass that represents a script function that may be regenerated, * for example with specialization based on call site types, or lazily generated. * The common denominator is that it can get new invokers during its lifespan, - * unlike {@link FinalScriptFunctionData} + * unlike {@code FinalScriptFunctionData} */ public final class RecompilableScriptFunctionData extends ScriptFunctionData { diff --git a/src/jdk/nashorn/internal/runtime/ScriptFunction.java b/src/jdk/nashorn/internal/runtime/ScriptFunction.java index 564f1946..14aab756 100644 --- a/src/jdk/nashorn/internal/runtime/ScriptFunction.java +++ b/src/jdk/nashorn/internal/runtime/ScriptFunction.java @@ -553,19 +553,18 @@ public abstract class ScriptFunction extends ScriptObject { private static MethodHandle bindToNameIfNeeded(final MethodHandle methodHandle, final String bindName) { if (bindName == null) { return methodHandle; - } else { - // if it is vararg method, we need to extend argument array with - // a new zeroth element that is set to bindName value. - final MethodType methodType = methodHandle.type(); - final int parameterCount = methodType.parameterCount(); - final boolean isVarArg = parameterCount > 0 && methodType.parameterType(parameterCount - 1).isArray(); - - if (isVarArg) { - return MH.filterArguments(methodHandle, 1, MH.insertArguments(ADD_ZEROTH_ELEMENT, 1, bindName)); - } else { - return MH.insertArguments(methodHandle, 1, bindName); - } } + + // if it is vararg method, we need to extend argument array with + // a new zeroth element that is set to bindName value. + final MethodType methodType = methodHandle.type(); + final int parameterCount = methodType.parameterCount(); + final boolean isVarArg = parameterCount > 0 && methodType.parameterType(parameterCount - 1).isArray(); + + if (isVarArg) { + return MH.filterArguments(methodHandle, 1, MH.insertArguments(ADD_ZEROTH_ELEMENT, 1, bindName)); + } + return MH.insertArguments(methodHandle, 1, bindName); } /** diff --git a/src/jdk/nashorn/internal/runtime/ScriptObject.java b/src/jdk/nashorn/internal/runtime/ScriptObject.java index f26e30f0..1087005b 100644 --- a/src/jdk/nashorn/internal/runtime/ScriptObject.java +++ b/src/jdk/nashorn/internal/runtime/ScriptObject.java @@ -2012,9 +2012,10 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr final boolean scopeAccess = isScope() && NashornCallSiteDescriptor.isScope(desc); if (find != null) { - final Object value = getObjectValue(find); - ScriptFunction func = null; - MethodHandle methodHandle = null; + final Object value = getObjectValue(find); + ScriptFunction func = null; + MethodHandle methodHandle = null; + if (value instanceof ScriptFunction) { func = (ScriptFunction)value; methodHandle = getCallMethodHandle(func, desc.getMethodType(), name); @@ -3219,6 +3220,11 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr return property; } + /** + * Write a value to a spill slot + * @param slot the slot index + * @param value the value + */ protected final void setSpill(final int slot, final Object value) { if (spill == null) { // create new spill. @@ -3233,6 +3239,11 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr spill[slot] = value; } + /** + * Get a value from a spill slot + * @param slot the slot index + * @return the value in the spill slot with the given index + */ protected Object getSpill(final int slot) { return spill != null && slot < spill.length ? spill[slot] : null; } diff --git a/src/jdk/nashorn/internal/runtime/arrays/ArrayLikeIterator.java b/src/jdk/nashorn/internal/runtime/arrays/ArrayLikeIterator.java index ab16d220..044b21d5 100644 --- a/src/jdk/nashorn/internal/runtime/arrays/ArrayLikeIterator.java +++ b/src/jdk/nashorn/internal/runtime/arrays/ArrayLikeIterator.java @@ -132,7 +132,7 @@ abstract public class ArrayLikeIterator implements Iterator { } if (obj instanceof List) { - return new JavaListIterator((List)obj, includeUndefined); + return new JavaListIterator((List)obj, includeUndefined); } if (obj != null && obj.getClass().isArray()) { @@ -165,7 +165,7 @@ abstract public class ArrayLikeIterator implements Iterator { } if (obj instanceof List) { - return new ReverseJavaListIterator((List)obj, includeUndefined); + return new ReverseJavaListIterator((List)obj, includeUndefined); } if (obj != null && obj.getClass().isArray()) { diff --git a/src/jdk/nashorn/internal/runtime/arrays/LongArrayData.java b/src/jdk/nashorn/internal/runtime/arrays/LongArrayData.java index a72ef4a0..59a63155 100644 --- a/src/jdk/nashorn/internal/runtime/arrays/LongArrayData.java +++ b/src/jdk/nashorn/internal/runtime/arrays/LongArrayData.java @@ -98,9 +98,8 @@ final class LongArrayData extends ArrayData { final int length = (int) length(); if (type == Double.class) { return new NumberArrayData(LongArrayData.toDoubleArray(array, length), length); - } else { - return new ObjectArrayData(LongArrayData.toObjectArray(array, length), length); } + return new ObjectArrayData(LongArrayData.toObjectArray(array, length), length); } @Override diff --git a/src/jdk/nashorn/internal/runtime/arrays/SparseArrayData.java b/src/jdk/nashorn/internal/runtime/arrays/SparseArrayData.java index 0fc466d4..ed99ce1c 100644 --- a/src/jdk/nashorn/internal/runtime/arrays/SparseArrayData.java +++ b/src/jdk/nashorn/internal/runtime/arrays/SparseArrayData.java @@ -60,7 +60,7 @@ class SparseArrayData extends ArrayData { @Override public ArrayData copy() { - return new SparseArrayData(underlying.copy(), length(), new TreeMap(sparseMap)); + return new SparseArrayData(underlying.copy(), length(), new TreeMap<>(sparseMap)); } @Override diff --git a/src/jdk/nashorn/internal/runtime/linker/BoundDynamicMethod.java b/src/jdk/nashorn/internal/runtime/linker/BoundDynamicMethod.java index 213f2b4f..f2089d5a 100644 --- a/src/jdk/nashorn/internal/runtime/linker/BoundDynamicMethod.java +++ b/src/jdk/nashorn/internal/runtime/linker/BoundDynamicMethod.java @@ -29,7 +29,7 @@ import jdk.internal.dynalink.beans.BeansLinker; /** * Represents a Dynalink dynamic method bound to a receiver. Note that objects of this class are just the tuples of - * a method and a bound this, without any behavior. All the behavior is defined in the {@link BoundDynamicMethodLinker}. + * a method and a bound this, without any behavior. All the behavior is defined in the {@code BoundDynamicMethodLinker}. */ final class BoundDynamicMethod { private final Object dynamicMethod; diff --git a/src/jdk/nashorn/internal/runtime/linker/BoundDynamicMethodLinker.java b/src/jdk/nashorn/internal/runtime/linker/BoundDynamicMethodLinker.java index 03bde629..7a2bc419 100644 --- a/src/jdk/nashorn/internal/runtime/linker/BoundDynamicMethodLinker.java +++ b/src/jdk/nashorn/internal/runtime/linker/BoundDynamicMethodLinker.java @@ -37,7 +37,7 @@ import jdk.internal.dynalink.linker.TypeBasedGuardingDynamicLinker; import jdk.internal.dynalink.support.Guards; /** - * Links {@link BoundDynamicMethod} objects. Passes through to Dynalink's BeansLinker for linking a dynamic method + * Links {@code BoundDynamicMethod} objects. Passes through to Dynalink's BeansLinker for linking a dynamic method * (they only respond to "dyn:call"), and modifies the returned invocation to deal with the receiver binding. */ final class BoundDynamicMethodLinker implements TypeBasedGuardingDynamicLinker { diff --git a/src/jdk/nashorn/internal/runtime/linker/JavaAdapterClassLoader.java b/src/jdk/nashorn/internal/runtime/linker/JavaAdapterClassLoader.java index 291e4d2f..a499aa61 100644 --- a/src/jdk/nashorn/internal/runtime/linker/JavaAdapterClassLoader.java +++ b/src/jdk/nashorn/internal/runtime/linker/JavaAdapterClassLoader.java @@ -114,9 +114,8 @@ final class JavaAdapterClassLoader { if(name.equals(className)) { assert classBytes != null : "what? already cleared .class bytes!!"; return defineClass(name, classBytes, 0, classBytes.length, GENERATED_PROTECTION_DOMAIN); - } else { - throw new ClassNotFoundException(name); } + throw new ClassNotFoundException(name); } }; } -- cgit v1.2.3 From 1b0921ea380784d113993ea29309a6bbc2e35438 Mon Sep 17 00:00:00 2001 From: sundar Date: Mon, 19 Aug 2013 17:16:54 +0530 Subject: 8023210: jjs tools should support a mode where it will load few command line scripts and then entering into interactive shell Reviewed-by: hannesw, attila, lagergren, jlaskey --- src/jdk/nashorn/internal/runtime/options/Options.java | 17 +++++++++-------- src/jdk/nashorn/tools/Shell.java | 8 ++++++++ 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/src/jdk/nashorn/internal/runtime/options/Options.java b/src/jdk/nashorn/internal/runtime/options/Options.java index 900d9dd4..cd774bb3 100644 --- a/src/jdk/nashorn/internal/runtime/options/Options.java +++ b/src/jdk/nashorn/internal/runtime/options/Options.java @@ -408,13 +408,13 @@ public final class Options { final LinkedList argList = new LinkedList<>(); Collections.addAll(argList, args); - final String extra = getStringProperty(NASHORN_ARGS_PROPERTY, null); - if (extra != null) { - final StringTokenizer st = new StringTokenizer(extra); - while (st.hasMoreTokens()) { - argList.add(st.nextToken()); + final String extra = getStringProperty(NASHORN_ARGS_PROPERTY, null); + if (extra != null) { + final StringTokenizer st = new StringTokenizer(extra); + while (st.hasMoreTokens()) { + argList.add(st.nextToken()); + } } - } while (!argList.isEmpty()) { final String arg = argList.remove(0); @@ -431,8 +431,9 @@ public final class Options { continue; } - // if it doesn't start with -, it's a file - if (!arg.startsWith("-")) { + // If it doesn't start with -, it's a file. But, if it is just "-", + // then it is a file representing standard input. + if (!arg.startsWith("-") || arg.length() == 1) { files.add(arg); continue; } diff --git a/src/jdk/nashorn/tools/Shell.java b/src/jdk/nashorn/tools/Shell.java index 08b576fb..713f92c4 100644 --- a/src/jdk/nashorn/tools/Shell.java +++ b/src/jdk/nashorn/tools/Shell.java @@ -292,6 +292,14 @@ public class Shell { // For each file on the command line. for (final String fileName : files) { + if ("-".equals(fileName)) { + final int res = readEvalPrint(context, global); + if (res != SUCCESS) { + return res; + } + continue; + } + final File file = new File(fileName); final ScriptFunction script = context.compileScript(new Source(fileName, file.toURI().toURL()), global); if (script == null || errors.getNumberOfErrors() != 0) { -- cgit v1.2.3