This commit is contained in:
Athijegannathan Sundararajan 2013-08-08 18:19:29 +05:30
commit 23ec0c1cc7
34 changed files with 547 additions and 296 deletions

View file

@ -223,9 +223,9 @@ run.test.user.language=tr
run.test.user.country=TR run.test.user.country=TR
# -XX:+PrintCompilation -XX:+UnlockDiagnosticVMOptions -XX:+PrintNMethods # -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.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 run.test.jvmsecurityargs=-Xverify:all -Djava.security.properties=${basedir}/make/java.security.override -Djava.security.manager -Djava.security.policy=${basedir}/build/nashorn.policy

View file

@ -85,12 +85,12 @@ package jdk.internal.dynalink;
import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.util.Iterator; import java.util.Iterator;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
import jdk.internal.dynalink.linker.GuardedInvocation; import jdk.internal.dynalink.linker.GuardedInvocation;
import jdk.internal.dynalink.support.AbstractRelinkableCallSite; 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 * 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. * handle is always at the start of the chain.
*/ */
public class ChainedCallSite extends AbstractRelinkableCallSite { public class ChainedCallSite extends AbstractRelinkableCallSite {
private static final MethodHandle PRUNE = Lookup.findOwnSpecial(MethodHandles.lookup(), "prune", MethodHandle.class,
MethodHandle.class);
private final AtomicReference<LinkedList<GuardedInvocation>> invocations = new AtomicReference<>(); private final AtomicReference<LinkedList<GuardedInvocation>> invocations = new AtomicReference<>();
/** /**
@ -194,18 +197,4 @@ public class ChainedCallSite extends AbstractRelinkableCallSite {
private MethodHandle prune(MethodHandle relink) { private MethodHandle prune(MethodHandle relink) {
return relinkInternal(null, relink, false); 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
}
}
} }

View file

@ -84,6 +84,8 @@
package jdk.internal.dynalink; package jdk.internal.dynalink;
import java.lang.invoke.MutableCallSite; import java.lang.invoke.MutableCallSite;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
@ -117,7 +119,9 @@ public class DynamicLinkerFactory {
*/ */
public static final int DEFAULT_UNSTABLE_RELINK_THRESHOLD = 8; public static final int DEFAULT_UNSTABLE_RELINK_THRESHOLD = 8;
private ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); private boolean classLoaderExplicitlySet = false;
private ClassLoader classLoader;
private List<? extends GuardingDynamicLinker> prioritizedLinkers; private List<? extends GuardingDynamicLinker> prioritizedLinkers;
private List<? extends GuardingDynamicLinker> fallbackLinkers; private List<? extends GuardingDynamicLinker> fallbackLinkers;
private int runtimeContextArgCount = 0; 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 * 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. * @param classLoader the class loader used for the autodiscovery of available linkers.
*/ */
public void setClassLoader(ClassLoader classLoader) { public void setClassLoader(ClassLoader classLoader) {
this.classLoader = classLoader; this.classLoader = classLoader;
classLoaderExplicitlySet = true;
} }
/** /**
@ -260,7 +265,8 @@ public class DynamicLinkerFactory {
addClasses(knownLinkerClasses, prioritizedLinkers); addClasses(knownLinkerClasses, prioritizedLinkers);
addClasses(knownLinkerClasses, fallbackLinkers); addClasses(knownLinkerClasses, fallbackLinkers);
final List<GuardingDynamicLinker> discovered = AutoDiscovery.loadLinkers(classLoader); final ClassLoader effectiveClassLoader = classLoaderExplicitlySet ? classLoader : getThreadContextClassLoader();
final List<GuardingDynamicLinker> discovered = AutoDiscovery.loadLinkers(effectiveClassLoader);
// Now, concatenate ... // Now, concatenate ...
final List<GuardingDynamicLinker> linkers = final List<GuardingDynamicLinker> linkers =
new ArrayList<>(prioritizedLinkers.size() + discovered.size() new ArrayList<>(prioritizedLinkers.size() + discovered.size()
@ -303,6 +309,15 @@ public class DynamicLinkerFactory {
runtimeContextArgCount, syncOnRelink, unstableRelinkThreshold); runtimeContextArgCount, syncOnRelink, unstableRelinkThreshold);
} }
private static ClassLoader getThreadContextClassLoader() {
return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
@Override
public ClassLoader run() {
return Thread.currentThread().getContextClassLoader();
}
});
}
private static void addClasses(Set<Class<? extends GuardingDynamicLinker>> knownLinkerClasses, private static void addClasses(Set<Class<? extends GuardingDynamicLinker>> knownLinkerClasses,
List<? extends GuardingDynamicLinker> linkers) { List<? extends GuardingDynamicLinker> linkers) {
for(GuardingDynamicLinker linker: linkers) { for(GuardingDynamicLinker linker: linkers) {

View file

@ -112,10 +112,6 @@ final class ClassString {
this(type.parameterArray()); this(type.parameterArray());
} }
Class<?>[] getClasses() {
return classes;
}
@Override @Override
public boolean equals(Object other) { public boolean equals(Object other) {
if(!(other instanceof ClassString)) { if(!(other instanceof ClassString)) {

View file

@ -189,15 +189,17 @@ class StaticClassLinker implements TypeBasedGuardingDynamicLinker {
return type == StaticClass.class; return type == StaticClass.class;
} }
/*private*/ static final MethodHandle GET_CLASS = new Lookup(MethodHandles.lookup()).findVirtual(StaticClass.class, /*private*/ static final MethodHandle GET_CLASS;
"getRepresentedClass", MethodType.methodType(Class.class)); /*private*/ static final MethodHandle IS_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 ARRAY_CTOR = Lookup.PUBLIC.findStatic(Array.class, "newInstance", /*private*/ static final MethodHandle ARRAY_CTOR = Lookup.PUBLIC.findStatic(Array.class, "newInstance",
MethodType.methodType(Object.class, Class.class, int.class)); 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") @SuppressWarnings("unused")
private static boolean isClass(Class<?> clazz, Object obj) { private static boolean isClass(Class<?> clazz, Object obj) {
return obj instanceof StaticClass && ((StaticClass)obj).getRepresentedClass() == clazz; return obj instanceof StaticClass && ((StaticClass)obj).getRepresentedClass() == clazz;

View file

@ -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() {
}
}

View file

@ -85,6 +85,8 @@ package jdk.internal.dynalink.support;
import java.lang.ref.Reference; import java.lang.ref.Reference;
import java.lang.ref.SoftReference; import java.lang.ref.SoftReference;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Map; import java.util.Map;
import java.util.WeakHashMap; import java.util.WeakHashMap;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
@ -121,22 +123,13 @@ public abstract class ClassMap<T> {
*/ */
protected abstract T computeValue(Class<?> clazz); 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 * Returns the value associated with the class
* *
* @param clazz the class * @param clazz the class
* @return the value associated with 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 // Check in fastest first - objects we're allowed to strongly reference
final T v = map.get(clazz); final T v = map.get(clazz);
if(v != null) { if(v != null) {
@ -156,8 +149,16 @@ public abstract class ClassMap<T> {
// Not found in either place; create a new value // Not found in either place; create a new value
final T newV = computeValue(clazz); final T newV = computeValue(clazz);
assert newV != null; assert newV != null;
final ClassLoader clazzLoader = AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
@Override
public ClassLoader run() {
return clazz.getClassLoader();
}
});
// If allowed to strongly reference, put it in the fast map // 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); final T oldV = map.putIfAbsent(clazz, newV);
return oldV != null ? oldV : newV; return oldV != null ? oldV : newV;
} }

View file

@ -258,23 +258,24 @@ public class Guards {
type.changeReturnType(Boolean.TYPE), new int[] { pos }); 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", private static final MethodHandle IS_INSTANCE = Lookup.PUBLIC.findVirtual(Class.class, "isInstance",
MethodType.methodType(Boolean.TYPE, Object.class)); MethodType.methodType(Boolean.TYPE, Object.class));
private static final MethodHandle IS_ARRAY = new Lookup(MethodHandles.lookup()).findStatic(Guards.class, "isArray", private static final MethodHandle IS_OF_CLASS;
MethodType.methodType(Boolean.TYPE, Object.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, static {
"isIdentical", MethodType.methodType(Boolean.TYPE, Object.class, Object.class)); final Lookup lookup = new Lookup(MethodHandles.lookup());
private static final MethodHandle IS_NULL = new Lookup(MethodHandles.lookup()).findStatic(Guards.class, IS_OF_CLASS = lookup.findOwnStatic("isOfClass", Boolean.TYPE, Class.class, Object.class);
"isNull", MethodType.methodType(Boolean.TYPE, Object.class)); IS_ARRAY = lookup.findOwnStatic("isArray", Boolean.TYPE, Object.class);
IS_IDENTICAL = lookup.findOwnStatic("isIdentical", Boolean.TYPE, Object.class, Object.class);
private static final MethodHandle IS_NOT_NULL = new Lookup(MethodHandles.lookup()).findStatic(Guards.class, IS_NULL = lookup.findOwnStatic("isNull", Boolean.TYPE, Object.class);
"isNotNull", MethodType.methodType(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. * Creates a guard method that tests its only argument for being of an exact particular class.

View file

@ -89,7 +89,6 @@ import java.lang.invoke.MethodType;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method; 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 * 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 * Performs a findSpecial on the underlying lookup. Converts any encountered {@link IllegalAccessException} into an
* any encountered {@link IllegalAccessException} into an {@link IllegalAccessError} and a * {@link IllegalAccessError} and a {@link NoSuchMethodException} into a {@link NoSuchMethodError}.
* {@link NoSuchMethodException} into a {@link NoSuchMethodError}.
* *
* @param declaringClass class declaring the method * @param declaringClass class declaring the method
* @param name the name of 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) { public MethodHandle findSpecial(Class<?> declaringClass, String name, MethodType type) {
try { 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); return lookup.findSpecial(declaringClass, name, type, declaringClass);
} catch(IllegalAccessException e) { } catch(IllegalAccessException e) {
final IllegalAccessError ee = new IllegalAccessError("Failed to access special method " + methodDescription( final IllegalAccessError ee = new IllegalAccessError("Failed to access special method " + methodDescription(

View file

@ -87,6 +87,8 @@ import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType; import java.lang.invoke.MethodType;
import java.lang.invoke.WrongMethodTypeException; import java.lang.invoke.WrongMethodTypeException;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import jdk.internal.dynalink.linker.ConversionComparator; import jdk.internal.dynalink.linker.ConversionComparator;
@ -110,7 +112,7 @@ public class TypeConverterFactory {
private final ClassValue<ClassMap<MethodHandle>> converterMap = new ClassValue<ClassMap<MethodHandle>>() { private final ClassValue<ClassMap<MethodHandle>> converterMap = new ClassValue<ClassMap<MethodHandle>>() {
@Override @Override
protected ClassMap<MethodHandle> computeValue(final Class<?> sourceType) { protected ClassMap<MethodHandle> computeValue(final Class<?> sourceType) {
return new ClassMap<MethodHandle>(sourceType.getClassLoader()) { return new ClassMap<MethodHandle>(getClassLoader(sourceType)) {
@Override @Override
protected MethodHandle computeValue(Class<?> targetType) { protected MethodHandle computeValue(Class<?> targetType) {
try { try {
@ -128,7 +130,7 @@ public class TypeConverterFactory {
private final ClassValue<ClassMap<MethodHandle>> converterIdentityMap = new ClassValue<ClassMap<MethodHandle>>() { private final ClassValue<ClassMap<MethodHandle>> converterIdentityMap = new ClassValue<ClassMap<MethodHandle>>() {
@Override @Override
protected ClassMap<MethodHandle> computeValue(final Class<?> sourceType) { protected ClassMap<MethodHandle> computeValue(final Class<?> sourceType) {
return new ClassMap<MethodHandle>(sourceType.getClassLoader()) { return new ClassMap<MethodHandle>(getClassLoader(sourceType)) {
@Override @Override
protected MethodHandle computeValue(Class<?> targetType) { protected MethodHandle computeValue(Class<?> targetType) {
if(!canAutoConvert(sourceType, 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<ClassLoader>() {
@Override
public ClassLoader run() {
return clazz.getClassLoader();
}
});
}
/** /**
* Creates a new type converter factory from the available {@link GuardingTypeConverterFactory} instances. * Creates a new type converter factory from the available {@link GuardingTypeConverterFactory} instances.
* *

View file

@ -33,7 +33,7 @@ public class CompileUnit {
private final String className; private final String className;
/** Current class generator */ /** Current class generator */
private final ClassEmitter classEmitter; private ClassEmitter classEmitter;
private long weight; private long weight;
@ -64,7 +64,11 @@ public class CompileUnit {
* @param clazz class with code for this compile unit * @param clazz class with code for this compile unit
*/ */
void setCode(final Class<?> clazz) { void setCode(final Class<?> clazz) {
clazz.getClass(); // null check
this.clazz = clazz; this.clazz = clazz;
// Revisit this - refactor to avoid null-ed out non-final fields
// null out emitter
this.classEmitter = null;
} }
/** /**

View file

@ -41,6 +41,8 @@ import java.util.Arrays;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; 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.GuardedInvocation;
import jdk.internal.dynalink.linker.LinkRequest; import jdk.internal.dynalink.linker.LinkRequest;
import jdk.nashorn.internal.objects.annotations.Attribute; import jdk.nashorn.internal.objects.annotations.Attribute;
@ -72,8 +74,8 @@ import jdk.nashorn.internal.scripts.JO;
*/ */
@ScriptClass("Global") @ScriptClass("Global")
public final class Global extends ScriptObject implements GlobalObject, Scope { public final class Global extends ScriptObject implements GlobalObject, Scope {
private static final InvokeByName TO_STRING = new InvokeByName("toString", ScriptObject.class); private final InvokeByName TO_STRING = new InvokeByName("toString", ScriptObject.class);
private static final InvokeByName VALUE_OF = new InvokeByName("valueOf", ScriptObject.class); private final InvokeByName VALUE_OF = new InvokeByName("valueOf", ScriptObject.class);
/** ECMA 15.1.2.2 parseInt (string , radix) */ /** ECMA 15.1.2.2 parseInt (string , radix) */
@Property(attributes = Attribute.NOT_ENUMERABLE) @Property(attributes = Attribute.NOT_ENUMERABLE)
@ -709,6 +711,35 @@ public final class Global extends ScriptObject implements GlobalObject, Scope {
classCache.put(source, new SoftReference<Class<?>>(clazz)); classCache.put(source, new SoftReference<Class<?>>(clazz));
} }
private static <T> T getLazilyCreatedValue(final Object key, final Callable<T> creator, final Map<Object, T> 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<Object, InvokeByName> namedInvokers = new ConcurrentHashMap<>();
@Override
public InvokeByName getInvokeByName(final Object key, final Callable<InvokeByName> creator) {
return getLazilyCreatedValue(key, creator, namedInvokers);
}
private final Map<Object, MethodHandle> dynamicInvokers = new ConcurrentHashMap<>();
@Override
public MethodHandle getDynamicInvoker(final Object key, final Callable<MethodHandle> creator) {
return getLazilyCreatedValue(key, creator, dynamicInvokers);
}
/** /**
* This is the eval used when 'indirect' eval call is made. * This is the eval used when 'indirect' eval call is made.
* *

View file

@ -39,6 +39,7 @@ import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.concurrent.Callable;
import jdk.nashorn.api.scripting.ScriptObjectMirror; import jdk.nashorn.api.scripting.ScriptObjectMirror;
import jdk.nashorn.internal.objects.annotations.Attribute; import jdk.nashorn.internal.objects.annotations.Attribute;
import jdk.nashorn.internal.objects.annotations.Constructor; import jdk.nashorn.internal.objects.annotations.Constructor;
@ -68,20 +69,88 @@ import jdk.nashorn.internal.runtime.linker.InvokeByName;
*/ */
@ScriptClass("Array") @ScriptClass("Array")
public final class NativeArray extends ScriptObject { 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 InvokeByName getJOIN() {
private static final MethodHandle SOME_CALLBACK_INVOKER = createIteratorCallbackInvoker(boolean.class); return Global.instance().getInvokeByName(JOIN,
private static final MethodHandle FOREACH_CALLBACK_INVOKER = createIteratorCallbackInvoker(void.class); new Callable<InvokeByName>() {
private static final MethodHandle MAP_CALLBACK_INVOKER = createIteratorCallbackInvoker(Object.class); @Override
private static final MethodHandle FILTER_CALLBACK_INVOKER = createIteratorCallbackInvoker(boolean.class); public InvokeByName call() {
return new InvokeByName("join", ScriptObject.class);
}
});
}
private static final MethodHandle REDUCE_CALLBACK_INVOKER = Bootstrap.createDynamicInvoker("dyn:call", Object.class, private static MethodHandle createIteratorCallbackInvoker(final Object key, final Class<?> rtype) {
Object.class, Undefined.class, Object.class, Object.class, long.class, Object.class); return Global.instance().getDynamicInvoker(key,
private static final MethodHandle CALL_CMP = Bootstrap.createDynamicInvoker("dyn:call", double.class, new Callable<MethodHandle>() {
@Override
public MethodHandle call() {
return Bootstrap.createDynamicInvoker("dyn:call", rtype, Object.class, Object.class, Object.class,
long.class, Object.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<MethodHandle>() {
@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<MethodHandle>() {
@Override
public MethodHandle call() {
return Bootstrap.createDynamicInvoker("dyn:call", double.class,
ScriptFunction.class, Object.class, Object.class, Object.class); ScriptFunction.class, Object.class, Object.class, Object.class);
}
});
}
private static final InvokeByName TO_LOCALE_STRING = new InvokeByName("toLocaleString", ScriptObject.class, String.class); private static InvokeByName getTO_LOCALE_STRING() {
return Global.instance().getInvokeByName(TO_LOCALE_STRING,
new Callable<InvokeByName>() {
@Override
public InvokeByName call() {
return new InvokeByName("toLocaleString", ScriptObject.class, String.class);
}
});
}
// initialized by nasgen // initialized by nasgen
private static PropertyMap $nasgenmap$; private static PropertyMap $nasgenmap$;
@ -357,11 +426,12 @@ public final class NativeArray extends ScriptObject {
public static Object toString(final Object self) { public static Object toString(final Object self) {
final Object obj = Global.toObject(self); final Object obj = Global.toObject(self);
if (obj instanceof ScriptObject) { if (obj instanceof ScriptObject) {
final InvokeByName joinInvoker = getJOIN();
final ScriptObject sobj = (ScriptObject)obj; final ScriptObject sobj = (ScriptObject)obj;
try { try {
final Object join = JOIN.getGetter().invokeExact(sobj); final Object join = joinInvoker.getGetter().invokeExact(sobj);
if (Bootstrap.isCallable(join)) { if (Bootstrap.isCallable(join)) {
return JOIN.getInvoker().invokeExact(join, sobj); return joinInvoker.getInvoker().invokeExact(join, sobj);
} }
} catch (final RuntimeException | Error e) { } catch (final RuntimeException | Error e) {
throw e; throw e;
@ -393,11 +463,12 @@ public final class NativeArray extends ScriptObject {
try { try {
if (val instanceof ScriptObject) { if (val instanceof ScriptObject) {
final InvokeByName localeInvoker = getTO_LOCALE_STRING();
final ScriptObject sobj = (ScriptObject)val; 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)) { if (Bootstrap.isCallable(toLocaleString)) {
sb.append((String)TO_LOCALE_STRING.getInvoker().invokeExact(toLocaleString, sobj)); sb.append((String)localeInvoker.getInvoker().invokeExact(toLocaleString, sobj));
} else { } else {
throw typeError("not.a.function", "toLocaleString"); 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(); final Object cmpThis = cmp == null || cmp.isStrict() ? ScriptRuntime.UNDEFINED : Global.instance();
Collections.sort(list, new Comparator<Object>() { Collections.sort(list, new Comparator<Object>() {
private final MethodHandle call_cmp = getCALL_CMP();
@Override @Override
public int compare(final Object x, final Object y) { public int compare(final Object x, final Object y) {
if (x == ScriptRuntime.UNDEFINED && y == ScriptRuntime.UNDEFINED) { if (x == ScriptRuntime.UNDEFINED && y == ScriptRuntime.UNDEFINED) {
@ -826,7 +898,7 @@ public final class NativeArray extends ScriptObject {
if (cmp != null) { if (cmp != null) {
try { 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) { } catch (final RuntimeException | Error e) {
throw e; throw e;
} catch (final Throwable t) { } 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) { private static boolean applyEvery(final Object self, final Object callbackfn, final Object thisArg) {
return new IteratorAction<Boolean>(Global.toObject(self), callbackfn, thisArg, true) { return new IteratorAction<Boolean>(Global.toObject(self), callbackfn, thisArg, true) {
private final MethodHandle everyInvoker = getEVERY_CALLBACK_INVOKER();
@Override @Override
protected boolean forEach(final Object val, final long i) throws Throwable { 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(); }.apply();
} }
@ -1121,9 +1195,11 @@ public final class NativeArray extends ScriptObject {
@Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1) @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1)
public static Object some(final Object self, final Object callbackfn, final Object thisArg) { public static Object some(final Object self, final Object callbackfn, final Object thisArg) {
return new IteratorAction<Boolean>(Global.toObject(self), callbackfn, thisArg, false) { return new IteratorAction<Boolean>(Global.toObject(self), callbackfn, thisArg, false) {
private final MethodHandle someInvoker = getSOME_CALLBACK_INVOKER();
@Override @Override
protected boolean forEach(final Object val, final long i) throws Throwable { 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(); }.apply();
} }
@ -1139,9 +1215,11 @@ public final class NativeArray extends ScriptObject {
@Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1) @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1)
public static Object forEach(final Object self, final Object callbackfn, final Object thisArg) { public static Object forEach(final Object self, final Object callbackfn, final Object thisArg) {
return new IteratorAction<Object>(Global.toObject(self), callbackfn, thisArg, ScriptRuntime.UNDEFINED) { return new IteratorAction<Object>(Global.toObject(self), callbackfn, thisArg, ScriptRuntime.UNDEFINED) {
private final MethodHandle forEachInvoker = getFOREACH_CALLBACK_INVOKER();
@Override @Override
protected boolean forEach(final Object val, final long i) throws Throwable { 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; return true;
} }
}.apply(); }.apply();
@ -1158,9 +1236,11 @@ public final class NativeArray extends ScriptObject {
@Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1) @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1)
public static Object map(final Object self, final Object callbackfn, final Object thisArg) { public static Object map(final Object self, final Object callbackfn, final Object thisArg) {
return new IteratorAction<NativeArray>(Global.toObject(self), callbackfn, thisArg, null) { return new IteratorAction<NativeArray>(Global.toObject(self), callbackfn, thisArg, null) {
private final MethodHandle mapInvoker = getMAP_CALLBACK_INVOKER();
@Override @Override
protected boolean forEach(final Object val, final long i) throws Throwable { 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); result.defineOwnProperty(ArrayIndex.getArrayIndex(index), r);
return true; 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) { public static Object filter(final Object self, final Object callbackfn, final Object thisArg) {
return new IteratorAction<NativeArray>(Global.toObject(self), callbackfn, thisArg, new NativeArray()) { return new IteratorAction<NativeArray>(Global.toObject(self), callbackfn, thisArg, new NativeArray()) {
private long to = 0; private long to = 0;
private final MethodHandle filterInvoker = getFILTER_CALLBACK_INVOKER();
@Override @Override
protected boolean forEach(final Object val, final long i) throws Throwable { 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); result.defineOwnProperty(ArrayIndex.getArrayIndex(to++), val);
} }
return true; return true;
@ -1217,10 +1298,12 @@ public final class NativeArray extends ScriptObject {
//if initial value is ScriptRuntime.UNDEFINED - step forward once. //if initial value is ScriptRuntime.UNDEFINED - step forward once.
return new IteratorAction<Object>(Global.toObject(self), callbackfn, ScriptRuntime.UNDEFINED, initialValue, iter) { return new IteratorAction<Object>(Global.toObject(self), callbackfn, ScriptRuntime.UNDEFINED, initialValue, iter) {
private final MethodHandle reduceInvoker = getREDUCE_CALLBACK_INVOKER();
@Override @Override
protected boolean forEach(final Object val, final long i) throws Throwable { protected boolean forEach(final Object val, final long i) throws Throwable {
// TODO: why can't I declare the second arg as Undefined.class? // 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; return true;
} }
}.apply(); }.apply();
@ -1273,10 +1356,4 @@ public final class NativeArray extends ScriptObject {
return false; 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);
}
} }

View file

@ -33,6 +33,7 @@ import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
import java.util.Locale; import java.util.Locale;
import java.util.TimeZone; import java.util.TimeZone;
import java.util.concurrent.Callable;
import jdk.nashorn.internal.objects.annotations.Attribute; import jdk.nashorn.internal.objects.annotations.Attribute;
import jdk.nashorn.internal.objects.annotations.Constructor; import jdk.nashorn.internal.objects.annotations.Constructor;
import jdk.nashorn.internal.objects.annotations.Function; 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" "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, private static final Object TO_ISO_STRING = new Object();
Object.class);
private static InvokeByName getTO_ISO_STRING() {
return Global.instance().getInvokeByName(TO_ISO_STRING,
new Callable<InvokeByName>() {
@Override
public InvokeByName call() {
return new InvokeByName("toISOString", ScriptObject.class, Object.class, Object.class);
}
});
}
private double time; private double time;
private final TimeZone timezone; private final TimeZone timezone;
@ -861,9 +871,10 @@ public final class NativeDate extends ScriptObject {
} }
try { 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)) { 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)); throw typeError("not.a.function", ScriptRuntime.safeToString(func));
} catch (final RuntimeException | Error e) { } catch (final RuntimeException | Error e) {

View file

@ -35,6 +35,7 @@ import java.util.IdentityHashMap;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.Callable;
import jdk.nashorn.internal.objects.annotations.Attribute; import jdk.nashorn.internal.objects.annotations.Attribute;
import jdk.nashorn.internal.objects.annotations.Function; import jdk.nashorn.internal.objects.annotations.Function;
import jdk.nashorn.internal.objects.annotations.ScriptClass; import jdk.nashorn.internal.objects.annotations.ScriptClass;
@ -55,9 +56,31 @@ import jdk.nashorn.internal.runtime.linker.InvokeByName;
*/ */
@ScriptClass("JSON") @ScriptClass("JSON")
public final class NativeJSON extends ScriptObject { public final class NativeJSON extends ScriptObject {
private static final InvokeByName TO_JSON = new InvokeByName("toJSON", ScriptObject.class, Object.class, Object.class); private static final Object TO_JSON = new Object();
private static final MethodHandle REPLACER_INVOKER = Bootstrap.createDynamicInvoker("dyn:call", Object.class,
private static InvokeByName getTO_JSON() {
return Global.instance().getInvokeByName(TO_JSON,
new Callable<InvokeByName>() {
@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<MethodHandle>() {
@Override
public MethodHandle call() {
return Bootstrap.createDynamicInvoker("dyn:call", Object.class,
ScriptFunction.class, ScriptObject.class, Object.class, Object.class); ScriptFunction.class, ScriptObject.class, Object.class, Object.class);
}
});
}
// initialized by nasgen // initialized by nasgen
@SuppressWarnings("unused") @SuppressWarnings("unused")
@ -187,15 +210,16 @@ public final class NativeJSON extends ScriptObject {
try { try {
if (value instanceof ScriptObject) { if (value instanceof ScriptObject) {
final InvokeByName toJSONInvoker = getTO_JSON();
final ScriptObject svalue = (ScriptObject)value; final ScriptObject svalue = (ScriptObject)value;
final Object toJSON = TO_JSON.getGetter().invokeExact(svalue); final Object toJSON = toJSONInvoker.getGetter().invokeExact(svalue);
if (Bootstrap.isCallable(toJSON)) { if (Bootstrap.isCallable(toJSON)) {
value = TO_JSON.getInvoker().invokeExact(toJSON, svalue, key); value = toJSONInvoker.getInvoker().invokeExact(toJSON, svalue, key);
} }
} }
if (state.replacerFunction != null) { 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) { } catch(Error|RuntimeException t) {
throw t; throw t;

View file

@ -36,6 +36,7 @@ import java.util.Collection;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.concurrent.Callable;
import jdk.internal.dynalink.beans.BeansLinker; import jdk.internal.dynalink.beans.BeansLinker;
import jdk.internal.dynalink.beans.StaticClass; import jdk.internal.dynalink.beans.StaticClass;
import jdk.internal.dynalink.linker.GuardedInvocation; import jdk.internal.dynalink.linker.GuardedInvocation;
@ -70,7 +71,18 @@ import jdk.nashorn.internal.runtime.linker.InvokeByName;
*/ */
@ScriptClass("Object") @ScriptClass("Object")
public final class NativeObject { 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<InvokeByName>() {
@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_GETTER_TYPE = MethodType.methodType(Object.class, ScriptObjectMirror.class);
private static final MethodType MIRROR_SETTER_TYPE = MethodType.methodType(Object.class, ScriptObjectMirror.class, Object.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) { public static Object toLocaleString(final Object self) {
final Object obj = JSType.toScriptObject(self); final Object obj = JSType.toScriptObject(self);
if (obj instanceof ScriptObject) { if (obj instanceof ScriptObject) {
final InvokeByName toStringInvoker = getTO_STRING();
final ScriptObject sobj = (ScriptObject)self; final ScriptObject sobj = (ScriptObject)self;
try { try {
final Object toString = TO_STRING.getGetter().invokeExact(sobj); final Object toString = toStringInvoker.getGetter().invokeExact(sobj);
if (Bootstrap.isCallable(toString)) { if (Bootstrap.isCallable(toString)) {
return TO_STRING.getInvoker().invokeExact(toString, sobj); return toStringInvoker.getInvoker().invokeExact(toString, sobj);
} }
} catch (final RuntimeException | Error e) { } catch (final RuntimeException | Error e) {
throw e; throw e;

View file

@ -26,8 +26,10 @@
package jdk.nashorn.internal.runtime; package jdk.nashorn.internal.runtime;
import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandle;
import java.util.concurrent.Callable;
import jdk.internal.dynalink.linker.GuardedInvocation; import jdk.internal.dynalink.linker.GuardedInvocation;
import jdk.internal.dynalink.linker.LinkRequest; import jdk.internal.dynalink.linker.LinkRequest;
import jdk.nashorn.internal.runtime.linker.InvokeByName;
/** /**
* Runtime interface to the global scope objects. * Runtime interface to the global scope objects.
@ -210,4 +212,20 @@ public interface GlobalObject {
* @param clazz compiled Class object for the source * @param clazz compiled Class object for the source
*/ */
public void cacheClass(Source source, Class<?> clazz); 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<InvokeByName> 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<MethodHandle> creator);
} }

View file

@ -27,6 +27,7 @@ package jdk.nashorn.internal.runtime;
import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandle;
import java.util.Iterator; import java.util.Iterator;
import java.util.concurrent.Callable;
import jdk.nashorn.internal.ir.LiteralNode; import jdk.nashorn.internal.ir.LiteralNode;
import jdk.nashorn.internal.ir.Node; import jdk.nashorn.internal.ir.Node;
import jdk.nashorn.internal.ir.ObjectNode; import jdk.nashorn.internal.ir.ObjectNode;
@ -42,8 +43,19 @@ import jdk.nashorn.internal.runtime.linker.Bootstrap;
*/ */
public final class JSONFunctions { public final class JSONFunctions {
private JSONFunctions() {} private JSONFunctions() {}
private static final MethodHandle REVIVER_INVOKER = Bootstrap.createDynamicInvoker("dyn:call", Object.class,
private static final Object REVIVER_INVOKER = new Object();
private static MethodHandle getREVIVER_INVOKER() {
return ((GlobalObject)Context.getGlobal()).getDynamicInvoker(REVIVER_INVOKER,
new Callable<MethodHandle>() {
@Override
public MethodHandle call() {
return Bootstrap.createDynamicInvoker("dyn:call", Object.class,
ScriptFunction.class, ScriptObject.class, String.class, Object.class); ScriptFunction.class, ScriptObject.class, String.class, Object.class);
}
});
}
/** /**
* Returns JSON-compatible quoted version of the given string. * Returns JSON-compatible quoted version of the given string.
@ -117,7 +129,7 @@ public final class JSONFunctions {
try { try {
// Object.class, ScriptFunction.class, ScriptObject.class, String.class, Object.class); // 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) { } catch(Error|RuntimeException t) {
throw t; throw t;
} catch(final Throwable t) { } catch(final Throwable t) {

View file

@ -31,6 +31,7 @@ import java.util.Iterator;
import java.util.ListIterator; import java.util.ListIterator;
import java.util.NoSuchElementException; import java.util.NoSuchElementException;
import java.util.RandomAccess; import java.util.RandomAccess;
import java.util.concurrent.Callable;
import jdk.nashorn.internal.runtime.linker.Bootstrap; import jdk.nashorn.internal.runtime.linker.Bootstrap;
import jdk.nashorn.internal.runtime.linker.InvokeByName; import jdk.nashorn.internal.runtime.linker.InvokeByName;
@ -49,16 +50,73 @@ import jdk.nashorn.internal.runtime.linker.InvokeByName;
*/ */
public final class ListAdapter extends AbstractList<Object> implements RandomAccess, Deque<Object> { public final class ListAdapter extends AbstractList<Object> implements RandomAccess, Deque<Object> {
// These add to the back and front of the list // 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 Object PUSH = new Object();
private static final InvokeByName UNSHIFT = new InvokeByName("unshift", ScriptObject.class, void.class, Object.class); private static InvokeByName getPUSH() {
return ((GlobalObject)Context.getGlobal()).getInvokeByName(PUSH,
new Callable<InvokeByName>() {
@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<InvokeByName>() {
@Override
public InvokeByName call() {
return new InvokeByName("unshift", ScriptObject.class, void.class, Object.class);
}
});
}
// These remove from the back and front of the list // 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 Object POP = new Object();
private static final InvokeByName SHIFT = new InvokeByName("shift", ScriptObject.class, Object.class); private static InvokeByName getPOP() {
return ((GlobalObject)Context.getGlobal()).getInvokeByName(POP,
new Callable<InvokeByName>() {
@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<InvokeByName>() {
@Override
public InvokeByName call() {
return new InvokeByName("shift", ScriptObject.class, Object.class);
}
});
}
// These insert and remove in the middle of the list // 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 Object SPLICE_ADD = new Object();
private static final InvokeByName SPLICE_REMOVE = new InvokeByName("splice", ScriptObject.class, void.class, int.class, int.class); private static InvokeByName getSPLICE_ADD() {
return ((GlobalObject)Context.getGlobal()).getInvokeByName(SPLICE_ADD,
new Callable<InvokeByName>() {
@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<InvokeByName>() {
@Override
public InvokeByName call() {
return new InvokeByName("splice", ScriptObject.class, void.class, int.class, int.class);
}
});
}
private final ScriptObject obj; private final ScriptObject obj;
@ -109,9 +167,10 @@ public final class ListAdapter extends AbstractList<Object> implements RandomAcc
@Override @Override
public void addFirst(Object e) { public void addFirst(Object e) {
try { try {
final Object fn = UNSHIFT.getGetter().invokeExact(obj); final InvokeByName unshiftInvoker = getUNSHIFT();
checkFunction(fn, UNSHIFT); final Object fn = unshiftInvoker.getGetter().invokeExact(obj);
UNSHIFT.getInvoker().invokeExact(fn, obj, e); checkFunction(fn, unshiftInvoker);
unshiftInvoker.getInvoker().invokeExact(fn, obj, e);
} catch(RuntimeException | Error ex) { } catch(RuntimeException | Error ex) {
throw ex; throw ex;
} catch(Throwable t) { } catch(Throwable t) {
@ -122,9 +181,10 @@ public final class ListAdapter extends AbstractList<Object> implements RandomAcc
@Override @Override
public void addLast(Object e) { public void addLast(Object e) {
try { try {
final Object fn = PUSH.getGetter().invokeExact(obj); final InvokeByName pushInvoker = getPUSH();
checkFunction(fn, PUSH); final Object fn = pushInvoker.getGetter().invokeExact(obj);
PUSH.getInvoker().invokeExact(fn, obj, e); checkFunction(fn, pushInvoker);
pushInvoker.getInvoker().invokeExact(fn, obj, e);
} catch(RuntimeException | Error ex) { } catch(RuntimeException | Error ex) {
throw ex; throw ex;
} catch(Throwable t) { } catch(Throwable t) {
@ -142,9 +202,10 @@ public final class ListAdapter extends AbstractList<Object> implements RandomAcc
} else { } else {
final int size = size(); final int size = size();
if(index < size) { if(index < size) {
final Object fn = SPLICE_ADD.getGetter().invokeExact(obj); final InvokeByName spliceAddInvoker = getSPLICE_ADD();
checkFunction(fn, SPLICE_ADD); final Object fn = spliceAddInvoker.getGetter().invokeExact(obj);
SPLICE_ADD.getInvoker().invokeExact(fn, obj, index, 0, e); checkFunction(fn, spliceAddInvoker);
spliceAddInvoker.getInvoker().invokeExact(fn, obj, index, 0, e);
} else if(index == size) { } else if(index == size) {
addLast(e); addLast(e);
} else { } else {
@ -234,9 +295,10 @@ public final class ListAdapter extends AbstractList<Object> implements RandomAcc
private Object invokeShift() { private Object invokeShift() {
try { try {
final Object fn = SHIFT.getGetter().invokeExact(obj); final InvokeByName shiftInvoker = getSHIFT();
checkFunction(fn, SHIFT); final Object fn = shiftInvoker.getGetter().invokeExact(obj);
return SHIFT.getInvoker().invokeExact(fn, obj); checkFunction(fn, shiftInvoker);
return shiftInvoker.getInvoker().invokeExact(fn, obj);
} catch(RuntimeException | Error ex) { } catch(RuntimeException | Error ex) {
throw ex; throw ex;
} catch(Throwable t) { } catch(Throwable t) {
@ -246,9 +308,10 @@ public final class ListAdapter extends AbstractList<Object> implements RandomAcc
private Object invokePop() { private Object invokePop() {
try { try {
final Object fn = POP.getGetter().invokeExact(obj); final InvokeByName popInvoker = getPOP();
checkFunction(fn, POP); final Object fn = popInvoker.getGetter().invokeExact(obj);
return POP.getInvoker().invokeExact(fn, obj); checkFunction(fn, popInvoker);
return popInvoker.getInvoker().invokeExact(fn, obj);
} catch(RuntimeException | Error ex) { } catch(RuntimeException | Error ex) {
throw ex; throw ex;
} catch(Throwable t) { } catch(Throwable t) {
@ -263,9 +326,10 @@ public final class ListAdapter extends AbstractList<Object> implements RandomAcc
private void invokeSpliceRemove(int fromIndex, int count) { private void invokeSpliceRemove(int fromIndex, int count) {
try { try {
final Object fn = SPLICE_REMOVE.getGetter().invokeExact(obj); final InvokeByName spliceRemoveInvoker = getSPLICE_REMOVE();
checkFunction(fn, SPLICE_REMOVE); final Object fn = spliceRemoveInvoker.getGetter().invokeExact(obj);
SPLICE_REMOVE.getInvoker().invokeExact(fn, obj, fromIndex, count); checkFunction(fn, spliceRemoveInvoker);
spliceRemoveInvoker.getInvoker().invokeExact(fn, obj, fromIndex, count);
} catch(RuntimeException | Error ex) { } catch(RuntimeException | Error ex) {
throw ex; throw ex;
} catch(Throwable t) { } catch(Throwable t) {

View file

@ -52,13 +52,19 @@ import jdk.nashorn.internal.parser.TokenType;
public final class RecompilableScriptFunctionData extends ScriptFunctionData { public final class RecompilableScriptFunctionData extends ScriptFunctionData {
/** FunctionNode with the code for this ScriptFunction */ /** 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() */ /** Allocator map from makeMap() */
private final PropertyMap allocatorMap; private final PropertyMap allocatorMap;
/** Code installer used for all further recompilation/specialization of this ScriptFunction */ /** Code installer used for all further recompilation/specialization of this ScriptFunction */
private final CodeInstaller<ScriptEnvironment> installer; private volatile CodeInstaller<ScriptEnvironment> installer;
/** Name of class where allocator function resides */ /** Name of class where allocator function resides */
private final String allocatorClassName; private final String allocatorClassName;
@ -103,6 +109,8 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData {
true); true);
this.functionNode = functionNode; this.functionNode = functionNode;
this.source = functionNode.getSource();
this.token = tokenFor(functionNode);
this.installer = installer; this.installer = installer;
this.allocatorClassName = allocatorClassName; this.allocatorClassName = allocatorClassName;
this.allocatorMap = allocatorMap; this.allocatorMap = allocatorMap;
@ -110,9 +118,6 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData {
@Override @Override
String toSource() { String toSource() {
final Source source = functionNode.getSource();
final long token = tokenFor(functionNode);
if (source != null && token != 0) { if (source != null && token != 0) {
return source.getString(Token.descPosition(token), Token.descLength(token)); return source.getString(Token.descPosition(token), Token.descLength(token));
} }
@ -123,8 +128,6 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData {
@Override @Override
public String toString() { public String toString() {
final StringBuilder sb = new StringBuilder(); final StringBuilder sb = new StringBuilder();
final Source source = functionNode.getSource();
final long token = tokenFor(functionNode);
if (source != null) { if (source != null) {
sb.append(source.getName()) 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 // code exists - look it up and add it into the automatically sorted invoker list
addCode(functionNode); 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) { 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 * footprint too large to store a parse snapshot, or if it is meaningless
* to do so, such as e.g. for runScript * to do so, such as e.g. for runScript
*/ */
if (!functionNode.canSpecialize()) { if (functionNode == null || !functionNode.canSpecialize()) {
return mh; return mh;
} }

View file

@ -496,32 +496,24 @@ public abstract class ScriptFunction extends ScriptObject {
MethodHandle boundHandle; MethodHandle boundHandle;
MethodHandle guard = null; MethodHandle guard = null;
final boolean scopeCall = NashornCallSiteDescriptor.isScope(desc);
if (data.needsCallee()) { if (data.needsCallee()) {
final MethodHandle callHandle = getBestInvoker(type, request.getArguments()); 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 // Make a handle that drops the passed "this" argument and substitutes either Global or Undefined
// (callee, this, args...) => (callee, args...) // (callee, this, args...) => (callee, args...)
boundHandle = MH.insertArguments(callHandle, 1, needsWrappedThis() ? Context.getGlobalTrusted() : ScriptRuntime.UNDEFINED); boundHandle = MH.insertArguments(callHandle, 1, needsWrappedThis() ? Context.getGlobalTrusted() : ScriptRuntime.UNDEFINED);
// (callee, args...) => (callee, [this], args...) // (callee, args...) => (callee, [this], args...)
boundHandle = MH.dropArguments(boundHandle, 1, Object.class); boundHandle = MH.dropArguments(boundHandle, 1, Object.class);
} else { } else {
// It's already (callee, this, args...), just what we need // It's already (callee, this, args...), just what we need
boundHandle = callHandle; 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 { } else {
final MethodHandle callHandle = getBestInvoker(type.dropParameterTypes(0, 1), request.getArguments()); 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 // Make a handle that drops the passed "this" argument and substitutes either Global or Undefined
// (this, args...) => (args...) // (this, args...) => (args...)
boundHandle = MH.bindTo(callHandle, needsWrappedThis() ? Context.getGlobalTrusted() : ScriptRuntime.UNDEFINED); 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); boundHandle = pairArguments(boundHandle, type);
return new GuardedInvocation(boundHandle, guard == null ? getFunctionGuard(this) : guard); return new GuardedInvocation(boundHandle, guard == null ? getFunctionGuard(this) : guard);

View file

@ -27,6 +27,7 @@ package jdk.nashorn.internal.runtime;
import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodHandles;
import java.util.concurrent.Callable;
import jdk.nashorn.internal.codegen.CompilerConstants; import jdk.nashorn.internal.codegen.CompilerConstants;
import jdk.nashorn.internal.lookup.Lookup; 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); "userAccessorSetter", void.class, ScriptObject.class, int.class, String.class, Object.class, Object.class);
/** Dynamic invoker for getter */ /** Dynamic invoker for getter */
private static final MethodHandle INVOKE_UA_GETTER = Bootstrap.createDynamicInvoker("dyn:call", 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<MethodHandle>() {
@Override
public MethodHandle call() {
return Bootstrap.createDynamicInvoker("dyn:call", Object.class,
Object.class, Object.class); Object.class, Object.class);
}
});
}
/** Dynamic invoker for setter */ /** Dynamic invoker for setter */
private static final MethodHandle INVOKE_UA_SETTER = Bootstrap.createDynamicInvoker("dyn:call", void.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<MethodHandle>() {
@Override
public MethodHandle call() {
return Bootstrap.createDynamicInvoker("dyn:call", void.class,
Object.class, Object.class, Object.class); Object.class, Object.class, Object.class);
}
});
}
/** /**
* Constructor * Constructor
@ -191,7 +212,7 @@ public final class UserAccessorProperty extends Property {
if (func instanceof ScriptFunction) { if (func instanceof ScriptFunction) {
try { try {
return INVOKE_UA_GETTER.invokeExact(func, self); return getINVOKE_UA_GETTER().invokeExact(func, self);
} catch(final Error|RuntimeException t) { } catch(final Error|RuntimeException t) {
throw t; throw t;
} catch(final Throwable t) { } catch(final Throwable t) {
@ -208,7 +229,7 @@ public final class UserAccessorProperty extends Property {
if (func instanceof ScriptFunction) { if (func instanceof ScriptFunction) {
try { try {
INVOKE_UA_SETTER.invokeExact(func, self, value); getINVOKE_UA_SETTER().invokeExact(func, self, value);
} catch(final Error|RuntimeException t) { } catch(final Error|RuntimeException t) {
throw t; throw t;
} catch(final Throwable t) { } catch(final Throwable t) {

View file

@ -68,6 +68,10 @@ public final class Bootstrap {
if (relinkThreshold > -1) { if (relinkThreshold > -1) {
factory.setUnstableRelinkThreshold(relinkThreshold); 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(); dynamicLinker = factory.createLinker();
} }

View file

@ -48,13 +48,20 @@ final class JavaAdapterClassLoader {
private static final ProtectionDomain GENERATED_PROTECTION_DOMAIN = createGeneratedProtectionDomain(); private static final ProtectionDomain GENERATED_PROTECTION_DOMAIN = createGeneratedProtectionDomain();
private final String className; private final String className;
private final byte[] classBytes; private volatile byte[] classBytes;
JavaAdapterClassLoader(String className, byte[] classBytes) { JavaAdapterClassLoader(String className, byte[] classBytes) {
this.className = className.replace('/', '.'); this.className = className.replace('/', '.');
this.classBytes = classBytes; this.classBytes = classBytes;
} }
/**
* clear classBytes after loading class.
*/
void clearClassBytes() {
this.classBytes = null;
}
/** /**
* Loads the generated adapter class into the JVM. * Loads the generated adapter class into the JVM.
* @param parentLoader the parent class loader for the generated class loader * @param parentLoader the parent class loader for the generated class loader
@ -103,6 +110,7 @@ final class JavaAdapterClassLoader {
@Override @Override
protected Class<?> findClass(final String name) throws ClassNotFoundException { protected Class<?> findClass(final String name) throws ClassNotFoundException {
if(name.equals(className)) { if(name.equals(className)) {
assert classBytes != null : "what? already cleared .class bytes!!";
return defineClass(name, classBytes, 0, classBytes.length, GENERATED_PROTECTION_DOMAIN); return defineClass(name, classBytes, 0, classBytes.length, GENERATED_PROTECTION_DOMAIN);
} else { } else {
throw new ClassNotFoundException(name); throw new ClassNotFoundException(name);

View file

@ -224,7 +224,10 @@ public final class JavaAdapterFactory {
this.commonLoader = findCommonLoader(definingLoader); this.commonLoader = findCommonLoader(definingLoader);
final JavaAdapterBytecodeGenerator gen = new JavaAdapterBytecodeGenerator(superClass, interfaces, commonLoader, false); final JavaAdapterBytecodeGenerator gen = new JavaAdapterBytecodeGenerator(superClass, interfaces, commonLoader, false);
this.autoConvertibleFromFunction = gen.isAutoConvertibleFromFunction(); 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.adapterGenerator = new JavaAdapterBytecodeGenerator(superClass, interfaces, commonLoader, true).createAdapterClassLoader();
this.adaptationResult = AdaptationResult.SUCCESSFUL_RESULT; this.adaptationResult = AdaptationResult.SUCCESSFUL_RESULT;
} }

View file

@ -33,17 +33,6 @@ var BYTES_PER_INT_32 = 4
var limit = Math.pow(2, UNSIGNED_INT_BITS)/BYTES_PER_INT_32 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. // A value over the limit should throw a RangeError.
try { try {
Int32Array(limit) Int32Array(limit)

View file

@ -33,6 +33,7 @@ import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager; import javax.script.ScriptEngineManager;
import javax.script.ScriptException; import javax.script.ScriptException;
import org.testng.TestNG; import org.testng.TestNG;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass; import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test; import org.testng.annotations.Test;
@ -44,7 +45,7 @@ import org.testng.annotations.Test;
public class BooleanAccessTest { public class BooleanAccessTest {
private static ScriptEngine e = null; private static ScriptEngine e = null;
private static SharedObject o = new SharedObject(); private static SharedObject o = null;
public static void main(final String[] args) { public static void main(final String[] args) {
TestNG.main(args); TestNG.main(args);
@ -54,10 +55,17 @@ public class BooleanAccessTest {
public static void setUpClass() throws ScriptException { public static void setUpClass() throws ScriptException {
final ScriptEngineManager m = new ScriptEngineManager(); final ScriptEngineManager m = new ScriptEngineManager();
e = m.getEngineByName("nashorn"); e = m.getEngineByName("nashorn");
o = new SharedObject();
e.put("o", o); e.put("o", o);
e.eval("var SharedObject = Packages.jdk.nashorn.api.javaaccess.SharedObject;"); e.eval("var SharedObject = Packages.jdk.nashorn.api.javaaccess.SharedObject;");
} }
@AfterClass
public static void tearDownClass() {
e = null;
o = null;
}
@Test @Test
public void accessFieldBoolean() throws ScriptException { public void accessFieldBoolean() throws ScriptException {
e.eval("var p_boolean = o.publicBoolean;"); e.eval("var p_boolean = o.publicBoolean;");

View file

@ -36,6 +36,7 @@ import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager; import javax.script.ScriptEngineManager;
import javax.script.ScriptException; import javax.script.ScriptException;
import org.testng.TestNG; import org.testng.TestNG;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass; import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test; import org.testng.annotations.Test;
@ -47,7 +48,7 @@ import org.testng.annotations.Test;
public class MethodAccessTest { public class MethodAccessTest {
private static ScriptEngine e = null; private static ScriptEngine e = null;
private static SharedObject o = new SharedObject(); private static SharedObject o = null;
public static void main(final String[] args) { public static void main(final String[] args) {
TestNG.main(args); TestNG.main(args);
@ -57,12 +58,19 @@ public class MethodAccessTest {
public static void setUpClass() throws ScriptException { public static void setUpClass() throws ScriptException {
final ScriptEngineManager m = new ScriptEngineManager(); final ScriptEngineManager m = new ScriptEngineManager();
e = m.getEngineByName("nashorn"); e = m.getEngineByName("nashorn");
o = new SharedObject();
o.setEngine(e); o.setEngine(e);
e.put("o", o); e.put("o", o);
e.eval("var SharedObject = Packages.jdk.nashorn.api.javaaccess.SharedObject;"); e.eval("var SharedObject = Packages.jdk.nashorn.api.javaaccess.SharedObject;");
e.eval("var Person = Packages.jdk.nashorn.api.javaaccess.Person;"); e.eval("var Person = Packages.jdk.nashorn.api.javaaccess.Person;");
} }
@AfterClass
public static void tearDownClass() {
e = null;
o = null;
}
@Test @Test
public void accessMethodthrowsCheckedException() throws ScriptException { public void accessMethodthrowsCheckedException() throws ScriptException {
e.eval("try {" + e.eval("try {" +

View file

@ -33,6 +33,7 @@ import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager; import javax.script.ScriptEngineManager;
import javax.script.ScriptException; import javax.script.ScriptException;
import org.testng.TestNG; import org.testng.TestNG;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass; import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test; import org.testng.annotations.Test;
@ -44,7 +45,7 @@ import org.testng.annotations.Test;
public class NumberAccessTest { public class NumberAccessTest {
private static ScriptEngine e = null; private static ScriptEngine e = null;
private static SharedObject o = new SharedObject(); private static SharedObject o = null;
public static void main(final String[] args) { public static void main(final String[] args) {
TestNG.main(args); TestNG.main(args);
@ -54,10 +55,17 @@ public class NumberAccessTest {
public static void setUpClass() throws ScriptException { public static void setUpClass() throws ScriptException {
final ScriptEngineManager m = new ScriptEngineManager(); final ScriptEngineManager m = new ScriptEngineManager();
e = m.getEngineByName("nashorn"); e = m.getEngineByName("nashorn");
o = new SharedObject();
e.put("o", o); e.put("o", o);
e.eval("var SharedObject = Packages.jdk.nashorn.api.javaaccess.SharedObject;"); e.eval("var SharedObject = Packages.jdk.nashorn.api.javaaccess.SharedObject;");
} }
@AfterClass
public static void tearDownClass() {
e = null;
o = null;
}
// --------------------------------long // --------------------------------long
// tests------------------------------------ // tests------------------------------------
@Test @Test

View file

@ -32,6 +32,7 @@ import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager; import javax.script.ScriptEngineManager;
import javax.script.ScriptException; import javax.script.ScriptException;
import org.testng.TestNG; import org.testng.TestNG;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass; import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test; import org.testng.annotations.Test;
@ -43,7 +44,7 @@ import org.testng.annotations.Test;
public class NumberBoxingTest { public class NumberBoxingTest {
private static ScriptEngine e = null; private static ScriptEngine e = null;
private static SharedObject o = new SharedObject(); private static SharedObject o = null;
public static void main(final String[] args) { public static void main(final String[] args) {
TestNG.main(args); TestNG.main(args);
@ -53,10 +54,17 @@ public class NumberBoxingTest {
public static void setUpClass() throws ScriptException { public static void setUpClass() throws ScriptException {
final ScriptEngineManager m = new ScriptEngineManager(); final ScriptEngineManager m = new ScriptEngineManager();
e = m.getEngineByName("nashorn"); e = m.getEngineByName("nashorn");
o = new SharedObject();
e.put("o", o); e.put("o", o);
e.eval("var SharedObject = Packages.jdk.nashorn.api.javaaccess.SharedObject;"); e.eval("var SharedObject = Packages.jdk.nashorn.api.javaaccess.SharedObject;");
} }
@AfterClass
public static void tearDownClass() {
e = null;
o = null;
}
// --------------------------------long // --------------------------------long
// tests------------------------------------ // tests------------------------------------
@Test @Test

View file

@ -32,6 +32,7 @@ import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager; import javax.script.ScriptEngineManager;
import javax.script.ScriptException; import javax.script.ScriptException;
import org.testng.TestNG; import org.testng.TestNG;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass; import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test; import org.testng.annotations.Test;
@ -43,7 +44,7 @@ import org.testng.annotations.Test;
public class ObjectAccessTest { public class ObjectAccessTest {
private static ScriptEngine e = null; private static ScriptEngine e = null;
private static SharedObject o = new SharedObject(); private static SharedObject o = null;
public static void main(final String[] args) { public static void main(final String[] args) {
TestNG.main(args); TestNG.main(args);
@ -53,11 +54,18 @@ public class ObjectAccessTest {
public static void setUpClass() throws ScriptException { public static void setUpClass() throws ScriptException {
final ScriptEngineManager m = new ScriptEngineManager(); final ScriptEngineManager m = new ScriptEngineManager();
e = m.getEngineByName("nashorn"); e = m.getEngineByName("nashorn");
o = new SharedObject();
e.put("o", o); e.put("o", o);
e.eval("var SharedObject = Packages.jdk.nashorn.api.javaaccess.SharedObject;"); e.eval("var SharedObject = Packages.jdk.nashorn.api.javaaccess.SharedObject;");
e.eval("var Person = Packages.jdk.nashorn.api.javaaccess.Person;"); e.eval("var Person = Packages.jdk.nashorn.api.javaaccess.Person;");
} }
@AfterClass
public static void tearDownClass() {
e = null;
o = null;
}
@Test @Test
public void accessFieldObject() throws ScriptException { public void accessFieldObject() throws ScriptException {
e.eval("var p_object = o.publicObject;"); e.eval("var p_object = o.publicObject;");

View file

@ -32,6 +32,7 @@ import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager; import javax.script.ScriptEngineManager;
import javax.script.ScriptException; import javax.script.ScriptException;
import org.testng.TestNG; import org.testng.TestNG;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass; import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test; import org.testng.annotations.Test;
@ -43,7 +44,7 @@ import org.testng.annotations.Test;
public class StringAccessTest { public class StringAccessTest {
private static ScriptEngine e = null; private static ScriptEngine e = null;
private static SharedObject o = new SharedObject(); private static SharedObject o = null;
public static void main(final String[] args) { public static void main(final String[] args) {
TestNG.main(args); TestNG.main(args);
@ -53,10 +54,17 @@ public class StringAccessTest {
public static void setUpClass() throws ScriptException { public static void setUpClass() throws ScriptException {
final ScriptEngineManager m = new ScriptEngineManager(); final ScriptEngineManager m = new ScriptEngineManager();
e = m.getEngineByName("nashorn"); e = m.getEngineByName("nashorn");
o = new SharedObject();
e.put("o", o); e.put("o", o);
e.eval("var SharedObject = Packages.jdk.nashorn.api.javaaccess.SharedObject;"); e.eval("var SharedObject = Packages.jdk.nashorn.api.javaaccess.SharedObject;");
} }
@AfterClass
public static void tearDownClass() {
e = null;
o = null;
}
@Test @Test
public void accessFieldString() throws ScriptException { public void accessFieldString() throws ScriptException {
e.eval("var p_string = o.publicString;"); e.eval("var p_string = o.publicString;");

View file

@ -35,6 +35,8 @@ import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.Source; import jdk.nashorn.internal.runtime.Source;
import jdk.nashorn.internal.runtime.options.Options; import jdk.nashorn.internal.runtime.options.Options;
import org.testng.Assert; import org.testng.Assert;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test; import org.testng.annotations.Test;
/** /**
@ -58,7 +60,8 @@ public class CompilerTest {
private Context context; private Context context;
private ScriptObject global; private ScriptObject global;
public CompilerTest() { @BeforeClass
public void setupTest() {
final Options options = new Options("nashorn"); final Options options = new Options("nashorn");
options.set("anon.functions", true); options.set("anon.functions", true);
options.set("compile.only", true); options.set("compile.only", true);
@ -79,6 +82,12 @@ public class CompilerTest {
this.global = context.createGlobal(); this.global = context.createGlobal();
} }
@AfterClass
public void tearDownTest() {
this.context = null;
this.global = null;
}
@Test @Test
public void compileAllTests() { public void compileAllTests() {
if (TEST262) { if (TEST262) {

View file

@ -28,10 +28,11 @@ package jdk.nashorn.internal.parser;
import java.io.File; import java.io.File;
import jdk.nashorn.internal.runtime.Context; import jdk.nashorn.internal.runtime.Context;
import jdk.nashorn.internal.runtime.ErrorManager; import jdk.nashorn.internal.runtime.ErrorManager;
import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.Source; import jdk.nashorn.internal.runtime.Source;
import jdk.nashorn.internal.runtime.options.Options; import jdk.nashorn.internal.runtime.options.Options;
import org.testng.Assert; import org.testng.Assert;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test; import org.testng.annotations.Test;
/** /**
@ -54,9 +55,9 @@ public class ParserTest {
} }
private Context context; private Context context;
private ScriptObject global;
public ParserTest() { @BeforeClass
public void setupTest() {
final Options options = new Options("nashorn"); final Options options = new Options("nashorn");
options.set("anon.functions", true); options.set("anon.functions", true);
options.set("parse.only", true); options.set("parse.only", true);
@ -64,7 +65,11 @@ public class ParserTest {
ErrorManager errors = new ErrorManager(); ErrorManager errors = new ErrorManager();
this.context = new Context(options, errors, Thread.currentThread().getContextClassLoader()); this.context = new Context(options, errors, Thread.currentThread().getContextClassLoader());
this.global = context.createGlobal(); }
@AfterClass
public void tearDownTest() {
this.context = null;
} }
@Test @Test
@ -125,8 +130,6 @@ public class ParserTest {
log("Begin parsing " + file.getAbsolutePath()); log("Begin parsing " + file.getAbsolutePath());
} }
final ScriptObject oldGlobal = Context.getGlobal();
final boolean globalChanged = (oldGlobal != global);
try { try {
final char[] buffer = Source.readFully(file); final char[] buffer = Source.readFully(file);
boolean excluded = false; boolean excluded = false;
@ -150,9 +153,6 @@ public class ParserTest {
} }
}; };
errors.setLimit(0); errors.setLimit(0);
if (globalChanged) {
Context.setGlobal(global);
}
final Source source = new Source(file.getAbsolutePath(), buffer); final Source source = new Source(file.getAbsolutePath(), buffer);
new Parser(context.getEnv(), source, errors).parse(); new Parser(context.getEnv(), source, errors).parse();
if (errors.getNumberOfErrors() > 0) { if (errors.getNumberOfErrors() > 0) {
@ -167,10 +167,6 @@ public class ParserTest {
exp.printStackTrace(System.out); exp.printStackTrace(System.out);
} }
failed++; failed++;
} finally {
if (globalChanged) {
Context.setGlobal(oldGlobal);
}
} }
if (VERBOSE) { if (VERBOSE) {