# HG changeset patch # User jlaskey # Date 1375971614 10800 # Node ID 14ea21d58f833765e29be319d902651d67d73f89 # Parent ab90c566272d15fe821b07d4aa710f5170601e55# Parent dd79c04ef7dfadc67cc800f5741ad0a08f864f7b Merge diff -r ab90c566272d -r 14ea21d58f83 make/project.properties --- a/make/project.properties Tue Aug 06 17:01:56 2013 -0700 +++ b/make/project.properties Thu Aug 08 11:20:14 2013 -0300 @@ -223,9 +223,9 @@ 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 -r ab90c566272d -r 14ea21d58f83 src/jdk/internal/dynalink/ChainedCallSite.java --- a/src/jdk/internal/dynalink/ChainedCallSite.java Tue Aug 06 17:01:56 2013 -0700 +++ b/src/jdk/internal/dynalink/ChainedCallSite.java Thu Aug 08 11:20:14 2013 -0300 @@ -85,12 +85,12 @@ 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 @@ * 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 @@ 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 -r ab90c566272d -r 14ea21d58f83 src/jdk/internal/dynalink/DynamicLinkerFactory.java --- a/src/jdk/internal/dynalink/DynamicLinkerFactory.java Tue Aug 06 17:01:56 2013 -0700 +++ b/src/jdk/internal/dynalink/DynamicLinkerFactory.java Thu Aug 08 11:20:14 2013 -0300 @@ -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 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 @@ /** * 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 @@ 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 @@ 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 -r ab90c566272d -r 14ea21d58f83 src/jdk/internal/dynalink/beans/ClassString.java --- a/src/jdk/internal/dynalink/beans/ClassString.java Tue Aug 06 17:01:56 2013 -0700 +++ b/src/jdk/internal/dynalink/beans/ClassString.java Thu Aug 08 11:20:14 2013 -0300 @@ -112,10 +112,6 @@ this(type.parameterArray()); } - Class[] getClasses() { - return classes; - } - @Override public boolean equals(Object other) { if(!(other instanceof ClassString)) { diff -r ab90c566272d -r 14ea21d58f83 src/jdk/internal/dynalink/beans/StaticClassLinker.java --- a/src/jdk/internal/dynalink/beans/StaticClassLinker.java Tue Aug 06 17:01:56 2013 -0700 +++ b/src/jdk/internal/dynalink/beans/StaticClassLinker.java Thu Aug 08 11:20:14 2013 -0300 @@ -189,15 +189,17 @@ 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 -r ab90c566272d -r 14ea21d58f83 src/jdk/internal/dynalink/support/Backport.java --- a/src/jdk/internal/dynalink/support/Backport.java Tue Aug 06 17:01:56 2013 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -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 -r ab90c566272d -r 14ea21d58f83 src/jdk/internal/dynalink/support/ClassMap.java --- a/src/jdk/internal/dynalink/support/ClassMap.java Tue Aug 06 17:01:56 2013 -0700 +++ b/src/jdk/internal/dynalink/support/ClassMap.java Thu Aug 08 11:20:14 2013 -0300 @@ -85,6 +85,8 @@ 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; @@ -122,21 +124,12 @@ 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 @@ // 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 -r ab90c566272d -r 14ea21d58f83 src/jdk/internal/dynalink/support/Guards.java --- a/src/jdk/internal/dynalink/support/Guards.java Tue Aug 06 17:01:56 2013 -0700 +++ b/src/jdk/internal/dynalink/support/Guards.java Thu Aug 08 11:20:14 2013 -0300 @@ -258,23 +258,24 @@ 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_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_IDENTICAL = new Lookup(MethodHandles.lookup()).findStatic(Guards.class, - "isIdentical", MethodType.methodType(Boolean.TYPE, Object.class, Object.class)); + static { + final Lookup lookup = new Lookup(MethodHandles.lookup()); - private static final MethodHandle IS_NULL = new Lookup(MethodHandles.lookup()).findStatic(Guards.class, - "isNull", MethodType.methodType(Boolean.TYPE, Object.class)); - - 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 -r ab90c566272d -r 14ea21d58f83 src/jdk/internal/dynalink/support/Lookup.java --- a/src/jdk/internal/dynalink/support/Lookup.java Tue Aug 06 17:01:56 2013 -0700 +++ b/src/jdk/internal/dynalink/support/Lookup.java Thu Aug 08 11:20:14 2013 -0300 @@ -89,7 +89,6 @@ 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 @@ } /** - * 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 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 -r ab90c566272d -r 14ea21d58f83 src/jdk/internal/dynalink/support/TypeConverterFactory.java --- a/src/jdk/internal/dynalink/support/TypeConverterFactory.java Tue Aug 06 17:01:56 2013 -0700 +++ b/src/jdk/internal/dynalink/support/TypeConverterFactory.java Thu Aug 08 11:20:14 2013 -0300 @@ -87,6 +87,8 @@ 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 @@ 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 @@ 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 @@ } }; + 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 -r ab90c566272d -r 14ea21d58f83 src/jdk/nashorn/internal/codegen/CompileUnit.java --- a/src/jdk/nashorn/internal/codegen/CompileUnit.java Tue Aug 06 17:01:56 2013 -0700 +++ b/src/jdk/nashorn/internal/codegen/CompileUnit.java Thu Aug 08 11:20:14 2013 -0300 @@ -33,7 +33,7 @@ private final String className; /** Current class generator */ - private final ClassEmitter classEmitter; + private ClassEmitter classEmitter; private long weight; @@ -64,7 +64,11 @@ * @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 -r ab90c566272d -r 14ea21d58f83 src/jdk/nashorn/internal/objects/Global.java --- a/src/jdk/nashorn/internal/objects/Global.java Tue Aug 06 17:01:56 2013 -0700 +++ b/src/jdk/nashorn/internal/objects/Global.java Thu Aug 08 11:20:14 2013 -0300 @@ -41,6 +41,8 @@ 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 @@ */ @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 @@ 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 -r ab90c566272d -r 14ea21d58f83 src/jdk/nashorn/internal/objects/NativeArray.java --- a/src/jdk/nashorn/internal/objects/NativeArray.java Tue Aug 06 17:01:56 2013 -0700 +++ b/src/jdk/nashorn/internal/objects/NativeArray.java Thu Aug 08 11:20:14 2013 -0300 @@ -39,6 +39,7 @@ 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 @@ */ @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 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 InvokeByName getJOIN() { + return Global.instance().getInvokeByName(JOIN, + new Callable() { + @Override + public InvokeByName call() { + return new InvokeByName("join", ScriptObject.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 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 InvokeByName TO_LOCALE_STRING = new InvokeByName("toLocaleString", ScriptObject.class, String.class); + private static MethodHandle getEVERY_CALLBACK_INVOKER() { + return createIteratorCallbackInvoker(EVERY_CALLBACK_INVOKER, boolean.class); + } + + private static MethodHandle getSOME_CALLBACK_INVOKER() { + return createIteratorCallbackInvoker(SOME_CALLBACK_INVOKER, boolean.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 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ @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 @@ @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 @@ @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 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 @@ //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 @@ 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 -r ab90c566272d -r 14ea21d58f83 src/jdk/nashorn/internal/objects/NativeDate.java --- a/src/jdk/nashorn/internal/objects/NativeDate.java Tue Aug 06 17:01:56 2013 -0700 +++ b/src/jdk/nashorn/internal/objects/NativeDate.java Thu Aug 08 11:20:14 2013 -0300 @@ -33,6 +33,7 @@ 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 @@ "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 @@ } 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 -r ab90c566272d -r 14ea21d58f83 src/jdk/nashorn/internal/objects/NativeJSON.java --- a/src/jdk/nashorn/internal/objects/NativeJSON.java Tue Aug 06 17:01:56 2013 -0700 +++ b/src/jdk/nashorn/internal/objects/NativeJSON.java Thu Aug 08 11:20:14 2013 -0300 @@ -35,6 +35,7 @@ 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 @@ */ @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 @@ 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 -r ab90c566272d -r 14ea21d58f83 src/jdk/nashorn/internal/objects/NativeObject.java --- a/src/jdk/nashorn/internal/objects/NativeObject.java Tue Aug 06 17:01:56 2013 -0700 +++ b/src/jdk/nashorn/internal/objects/NativeObject.java Thu Aug 08 11:20:14 2013 -0300 @@ -36,6 +36,7 @@ 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 @@ */ @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 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 -r ab90c566272d -r 14ea21d58f83 src/jdk/nashorn/internal/runtime/GlobalObject.java --- a/src/jdk/nashorn/internal/runtime/GlobalObject.java Tue Aug 06 17:01:56 2013 -0700 +++ b/src/jdk/nashorn/internal/runtime/GlobalObject.java Thu Aug 08 11:20:14 2013 -0300 @@ -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 @@ * @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 -r ab90c566272d -r 14ea21d58f83 src/jdk/nashorn/internal/runtime/JSONFunctions.java --- a/src/jdk/nashorn/internal/runtime/JSONFunctions.java Tue Aug 06 17:01:56 2013 -0700 +++ b/src/jdk/nashorn/internal/runtime/JSONFunctions.java Thu Aug 08 11:20:14 2013 -0300 @@ -27,6 +27,7 @@ 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 @@ */ 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 @@ 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 -r ab90c566272d -r 14ea21d58f83 src/jdk/nashorn/internal/runtime/ListAdapter.java --- a/src/jdk/nashorn/internal/runtime/ListAdapter.java Tue Aug 06 17:01:56 2013 -0700 +++ b/src/jdk/nashorn/internal/runtime/ListAdapter.java Thu Aug 08 11:20:14 2013 -0300 @@ -31,6 +31,7 @@ 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 @@ */ 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 @@ @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 @@ @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 @@ } 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 @@ 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 @@ 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 @@ 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 -r ab90c566272d -r 14ea21d58f83 src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java --- a/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java Tue Aug 06 17:01:56 2013 -0700 +++ b/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java Thu Aug 08 11:20:14 2013 -0300 @@ -52,13 +52,19 @@ 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 @@ 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 @@ @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 @@ @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 @@ // 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 @@ * 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 -r ab90c566272d -r 14ea21d58f83 src/jdk/nashorn/internal/runtime/ScriptFunction.java --- a/src/jdk/nashorn/internal/runtime/ScriptFunction.java Tue Aug 06 17:01:56 2013 -0700 +++ b/src/jdk/nashorn/internal/runtime/ScriptFunction.java Thu Aug 08 11:20:14 2013 -0300 @@ -496,32 +496,24 @@ 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 @@ } } + // 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 -r ab90c566272d -r 14ea21d58f83 src/jdk/nashorn/internal/runtime/UserAccessorProperty.java --- a/src/jdk/nashorn/internal/runtime/UserAccessorProperty.java Tue Aug 06 17:01:56 2013 -0700 +++ b/src/jdk/nashorn/internal/runtime/UserAccessorProperty.java Thu Aug 08 11:20:14 2013 -0300 @@ -27,6 +27,7 @@ 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 @@ "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 @@ 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 @@ 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 -r ab90c566272d -r 14ea21d58f83 src/jdk/nashorn/internal/runtime/linker/Bootstrap.java --- a/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java Tue Aug 06 17:01:56 2013 -0700 +++ b/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java Thu Aug 08 11:20:14 2013 -0300 @@ -68,6 +68,10 @@ 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(); } diff -r ab90c566272d -r 14ea21d58f83 src/jdk/nashorn/internal/runtime/linker/JavaAdapterClassLoader.java --- a/src/jdk/nashorn/internal/runtime/linker/JavaAdapterClassLoader.java Tue Aug 06 17:01:56 2013 -0700 +++ b/src/jdk/nashorn/internal/runtime/linker/JavaAdapterClassLoader.java Thu Aug 08 11:20:14 2013 -0300 @@ -48,7 +48,7 @@ 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('/', '.'); @@ -56,6 +56,13 @@ } /** + * 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 * @return the generated adapter class @@ -103,6 +110,7 @@ @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 -r ab90c566272d -r 14ea21d58f83 src/jdk/nashorn/internal/runtime/linker/JavaAdapterFactory.java --- a/src/jdk/nashorn/internal/runtime/linker/JavaAdapterFactory.java Tue Aug 06 17:01:56 2013 -0700 +++ b/src/jdk/nashorn/internal/runtime/linker/JavaAdapterFactory.java Thu Aug 08 11:20:14 2013 -0300 @@ -224,7 +224,10 @@ 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 -r ab90c566272d -r 14ea21d58f83 test/script/basic/JDK-8020357.js --- a/test/script/basic/JDK-8020357.js Tue Aug 06 17:01:56 2013 -0700 +++ b/test/script/basic/JDK-8020357.js Thu Aug 08 11:20:14 2013 -0300 @@ -33,17 +33,6 @@ 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 -r ab90c566272d -r 14ea21d58f83 test/src/jdk/nashorn/api/javaaccess/BooleanAccessTest.java --- a/test/src/jdk/nashorn/api/javaaccess/BooleanAccessTest.java Tue Aug 06 17:01:56 2013 -0700 +++ b/test/src/jdk/nashorn/api/javaaccess/BooleanAccessTest.java Thu Aug 08 11:20:14 2013 -0300 @@ -33,6 +33,7 @@ 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 @@ 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 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 -r ab90c566272d -r 14ea21d58f83 test/src/jdk/nashorn/api/javaaccess/MethodAccessTest.java --- a/test/src/jdk/nashorn/api/javaaccess/MethodAccessTest.java Tue Aug 06 17:01:56 2013 -0700 +++ b/test/src/jdk/nashorn/api/javaaccess/MethodAccessTest.java Thu Aug 08 11:20:14 2013 -0300 @@ -36,6 +36,7 @@ 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 @@ 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 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 -r ab90c566272d -r 14ea21d58f83 test/src/jdk/nashorn/api/javaaccess/NumberAccessTest.java --- a/test/src/jdk/nashorn/api/javaaccess/NumberAccessTest.java Tue Aug 06 17:01:56 2013 -0700 +++ b/test/src/jdk/nashorn/api/javaaccess/NumberAccessTest.java Thu Aug 08 11:20:14 2013 -0300 @@ -33,6 +33,7 @@ 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 @@ 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 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 -r ab90c566272d -r 14ea21d58f83 test/src/jdk/nashorn/api/javaaccess/NumberBoxingTest.java --- a/test/src/jdk/nashorn/api/javaaccess/NumberBoxingTest.java Tue Aug 06 17:01:56 2013 -0700 +++ b/test/src/jdk/nashorn/api/javaaccess/NumberBoxingTest.java Thu Aug 08 11:20:14 2013 -0300 @@ -32,6 +32,7 @@ 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 @@ 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 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 -r ab90c566272d -r 14ea21d58f83 test/src/jdk/nashorn/api/javaaccess/ObjectAccessTest.java --- a/test/src/jdk/nashorn/api/javaaccess/ObjectAccessTest.java Tue Aug 06 17:01:56 2013 -0700 +++ b/test/src/jdk/nashorn/api/javaaccess/ObjectAccessTest.java Thu Aug 08 11:20:14 2013 -0300 @@ -32,6 +32,7 @@ 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 @@ 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 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 -r ab90c566272d -r 14ea21d58f83 test/src/jdk/nashorn/api/javaaccess/StringAccessTest.java --- a/test/src/jdk/nashorn/api/javaaccess/StringAccessTest.java Tue Aug 06 17:01:56 2013 -0700 +++ b/test/src/jdk/nashorn/api/javaaccess/StringAccessTest.java Thu Aug 08 11:20:14 2013 -0300 @@ -32,6 +32,7 @@ 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 @@ 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 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 -r ab90c566272d -r 14ea21d58f83 test/src/jdk/nashorn/internal/codegen/CompilerTest.java --- a/test/src/jdk/nashorn/internal/codegen/CompilerTest.java Tue Aug 06 17:01:56 2013 -0700 +++ b/test/src/jdk/nashorn/internal/codegen/CompilerTest.java Thu Aug 08 11:20:14 2013 -0300 @@ -35,6 +35,8 @@ 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 @@ 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 @@ this.global = context.createGlobal(); } + @AfterClass + public void tearDownTest() { + this.context = null; + this.global = null; + } + @Test public void compileAllTests() { if (TEST262) { diff -r ab90c566272d -r 14ea21d58f83 test/src/jdk/nashorn/internal/parser/ParserTest.java --- a/test/src/jdk/nashorn/internal/parser/ParserTest.java Tue Aug 06 17:01:56 2013 -0700 +++ b/test/src/jdk/nashorn/internal/parser/ParserTest.java Thu Aug 08 11:20:14 2013 -0300 @@ -28,10 +28,11 @@ 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 @@ } 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 @@ 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 @@ 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 @@ } }; 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 @@ exp.printStackTrace(System.out); } failed++; - } finally { - if (globalChanged) { - Context.setGlobal(oldGlobal); - } } if (VERBOSE) {