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
# -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

View file

@ -85,12 +85,12 @@ package jdk.internal.dynalink;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.concurrent.atomic.AtomicReference;
import jdk.internal.dynalink.linker.GuardedInvocation;
import jdk.internal.dynalink.support.AbstractRelinkableCallSite;
import jdk.internal.dynalink.support.Lookup;
/**
* A relinkable call site that maintains a chain of linked method handles. In the default implementation, up to 8 method
@ -103,6 +103,9 @@ import jdk.internal.dynalink.support.AbstractRelinkableCallSite;
* handle is always at the start of the chain.
*/
public class ChainedCallSite extends AbstractRelinkableCallSite {
private static final MethodHandle PRUNE = Lookup.findOwnSpecial(MethodHandles.lookup(), "prune", MethodHandle.class,
MethodHandle.class);
private final AtomicReference<LinkedList<GuardedInvocation>> invocations = new AtomicReference<>();
/**
@ -194,18 +197,4 @@ public class ChainedCallSite extends AbstractRelinkableCallSite {
private MethodHandle prune(MethodHandle relink) {
return relinkInternal(null, relink, false);
}
private static final MethodHandle PRUNE;
static {
try {
PRUNE = MethodHandles.lookup().findSpecial(ChainedCallSite.class, "prune", MethodType.methodType(
MethodHandle.class, MethodHandle.class), ChainedCallSite.class);
// NOTE: using two catch blocks so we don't introduce a reference to 1.7 ReflectiveOperationException, allowing
// Dynalink to be used on 1.6 JVMs with Remi's backport library.
} catch(IllegalAccessException e) {
throw new AssertionError(e.getMessage(), e); // Can not happen
} catch(NoSuchMethodException e) {
throw new AssertionError(e.getMessage(), e); // Can not happen
}
}
}

View file

@ -84,6 +84,8 @@
package jdk.internal.dynalink;
import java.lang.invoke.MutableCallSite;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@ -117,7 +119,9 @@ public class DynamicLinkerFactory {
*/
public static final int DEFAULT_UNSTABLE_RELINK_THRESHOLD = 8;
private ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
private boolean classLoaderExplicitlySet = false;
private ClassLoader classLoader;
private List<? extends GuardingDynamicLinker> prioritizedLinkers;
private List<? extends GuardingDynamicLinker> fallbackLinkers;
private int runtimeContextArgCount = 0;
@ -126,12 +130,13 @@ public class DynamicLinkerFactory {
/**
* Sets the class loader for automatic discovery of available linkers. If not set explicitly, then the thread
* context class loader at the time of the constructor invocation will be used.
* context class loader at the time of {@link #createLinker()} invocation will be used.
*
* @param classLoader the class loader used for the autodiscovery of available linkers.
*/
public void setClassLoader(ClassLoader classLoader) {
this.classLoader = classLoader;
classLoaderExplicitlySet = true;
}
/**
@ -260,7 +265,8 @@ public class DynamicLinkerFactory {
addClasses(knownLinkerClasses, prioritizedLinkers);
addClasses(knownLinkerClasses, fallbackLinkers);
final List<GuardingDynamicLinker> discovered = AutoDiscovery.loadLinkers(classLoader);
final ClassLoader effectiveClassLoader = classLoaderExplicitlySet ? classLoader : getThreadContextClassLoader();
final List<GuardingDynamicLinker> discovered = AutoDiscovery.loadLinkers(effectiveClassLoader);
// Now, concatenate ...
final List<GuardingDynamicLinker> linkers =
new ArrayList<>(prioritizedLinkers.size() + discovered.size()
@ -303,6 +309,15 @@ public class DynamicLinkerFactory {
runtimeContextArgCount, syncOnRelink, unstableRelinkThreshold);
}
private static ClassLoader getThreadContextClassLoader() {
return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
@Override
public ClassLoader run() {
return Thread.currentThread().getContextClassLoader();
}
});
}
private static void addClasses(Set<Class<? extends GuardingDynamicLinker>> knownLinkerClasses,
List<? extends GuardingDynamicLinker> linkers) {
for(GuardingDynamicLinker linker: linkers) {

View file

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

View file

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

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.SoftReference;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.concurrent.ConcurrentHashMap;
@ -121,22 +123,13 @@ public abstract class ClassMap<T> {
*/
protected abstract T computeValue(Class<?> clazz);
/**
* Returns the class loader that governs the strong referenceability of this class map.
*
* @return the class loader that governs the strong referenceability of this class map.
*/
public ClassLoader getClassLoader() {
return classLoader;
}
/**
* Returns the value associated with the class
*
* @param clazz the class
* @return the value associated with the class
*/
public T get(Class<?> clazz) {
public T get(final Class<?> clazz) {
// Check in fastest first - objects we're allowed to strongly reference
final T v = map.get(clazz);
if(v != null) {
@ -156,8 +149,16 @@ public abstract class ClassMap<T> {
// Not found in either place; create a new value
final T newV = computeValue(clazz);
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(Guards.canReferenceDirectly(classLoader, clazz.getClassLoader())) {
if(Guards.canReferenceDirectly(classLoader, clazzLoader)) {
final T oldV = map.putIfAbsent(clazz, newV);
return oldV != null ? oldV : newV;
}

View file

@ -258,23 +258,24 @@ public class Guards {
type.changeReturnType(Boolean.TYPE), new int[] { pos });
}
private static final MethodHandle IS_OF_CLASS = new Lookup(MethodHandles.lookup()).findStatic(Guards.class,
"isOfClass", MethodType.methodType(Boolean.TYPE, Class.class, Object.class));
private static final MethodHandle IS_INSTANCE = Lookup.PUBLIC.findVirtual(Class.class, "isInstance",
MethodType.methodType(Boolean.TYPE, Object.class));
private static final MethodHandle IS_ARRAY = new Lookup(MethodHandles.lookup()).findStatic(Guards.class, "isArray",
MethodType.methodType(Boolean.TYPE, Object.class));
private static final MethodHandle IS_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.

View file

@ -89,7 +89,6 @@ import java.lang.invoke.MethodType;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
/**
* A wrapper around MethodHandles.Lookup that masks checked exceptions in those cases when you're looking up methods
@ -235,9 +234,8 @@ public class Lookup {
}
/**
* Performs a findSpecial on the underlying lookup, except for the backport where it rather uses unreflect. Converts
* any encountered {@link IllegalAccessException} into an {@link IllegalAccessError} and a
* {@link NoSuchMethodException} into a {@link NoSuchMethodError}.
* Performs a findSpecial on the underlying lookup. Converts any encountered {@link IllegalAccessException} into an
* {@link IllegalAccessError} and a {@link NoSuchMethodException} into a {@link NoSuchMethodError}.
*
* @param declaringClass class declaring the method
* @param name the name of the method
@ -248,13 +246,6 @@ public class Lookup {
*/
public MethodHandle findSpecial(Class<?> declaringClass, String name, MethodType type) {
try {
if(Backport.inUse) {
final Method m = declaringClass.getDeclaredMethod(name, type.parameterArray());
if(!Modifier.isPublic(declaringClass.getModifiers()) || !Modifier.isPublic(m.getModifiers())) {
m.setAccessible(true);
}
return unreflect(m);
}
return lookup.findSpecial(declaringClass, name, type, declaringClass);
} catch(IllegalAccessException e) {
final IllegalAccessError ee = new IllegalAccessError("Failed to access special method " + methodDescription(

View file

@ -87,6 +87,8 @@ import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.invoke.WrongMethodTypeException;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.LinkedList;
import java.util.List;
import jdk.internal.dynalink.linker.ConversionComparator;
@ -110,7 +112,7 @@ public class TypeConverterFactory {
private final ClassValue<ClassMap<MethodHandle>> converterMap = new ClassValue<ClassMap<MethodHandle>>() {
@Override
protected ClassMap<MethodHandle> computeValue(final Class<?> sourceType) {
return new ClassMap<MethodHandle>(sourceType.getClassLoader()) {
return new ClassMap<MethodHandle>(getClassLoader(sourceType)) {
@Override
protected MethodHandle computeValue(Class<?> targetType) {
try {
@ -128,7 +130,7 @@ public class TypeConverterFactory {
private final ClassValue<ClassMap<MethodHandle>> converterIdentityMap = new ClassValue<ClassMap<MethodHandle>>() {
@Override
protected ClassMap<MethodHandle> computeValue(final Class<?> sourceType) {
return new ClassMap<MethodHandle>(sourceType.getClassLoader()) {
return new ClassMap<MethodHandle>(getClassLoader(sourceType)) {
@Override
protected MethodHandle computeValue(Class<?> targetType) {
if(!canAutoConvert(sourceType, targetType)) {
@ -143,6 +145,15 @@ public class TypeConverterFactory {
}
};
private static final ClassLoader getClassLoader(final Class<?> clazz) {
return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
@Override
public ClassLoader run() {
return clazz.getClassLoader();
}
});
}
/**
* 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;
/** Current class generator */
private final ClassEmitter classEmitter;
private ClassEmitter classEmitter;
private long weight;
@ -64,7 +64,11 @@ public class CompileUnit {
* @param clazz class with code for this compile unit
*/
void setCode(final Class<?> clazz) {
clazz.getClass(); // null check
this.clazz = clazz;
// Revisit this - refactor to avoid null-ed out non-final fields
// null out emitter
this.classEmitter = null;
}
/**

View file

@ -41,6 +41,8 @@ import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import jdk.internal.dynalink.linker.GuardedInvocation;
import jdk.internal.dynalink.linker.LinkRequest;
import jdk.nashorn.internal.objects.annotations.Attribute;
@ -72,8 +74,8 @@ import jdk.nashorn.internal.scripts.JO;
*/
@ScriptClass("Global")
public final class Global extends ScriptObject implements GlobalObject, Scope {
private static final InvokeByName TO_STRING = new InvokeByName("toString", ScriptObject.class);
private static final InvokeByName VALUE_OF = new InvokeByName("valueOf", ScriptObject.class);
private final InvokeByName TO_STRING = new InvokeByName("toString", ScriptObject.class);
private final InvokeByName VALUE_OF = new InvokeByName("valueOf", ScriptObject.class);
/** ECMA 15.1.2.2 parseInt (string , radix) */
@Property(attributes = Attribute.NOT_ENUMERABLE)
@ -709,6 +711,35 @@ public final class Global extends ScriptObject implements GlobalObject, Scope {
classCache.put(source, new SoftReference<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.
*

View file

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

View file

@ -33,6 +33,7 @@ import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
import java.util.Locale;
import java.util.TimeZone;
import java.util.concurrent.Callable;
import jdk.nashorn.internal.objects.annotations.Attribute;
import jdk.nashorn.internal.objects.annotations.Constructor;
import jdk.nashorn.internal.objects.annotations.Function;
@ -95,8 +96,17 @@ public final class NativeDate extends ScriptObject {
"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};
private static final InvokeByName TO_ISO_STRING = new InvokeByName("toISOString", ScriptObject.class, Object.class,
Object.class);
private static final Object TO_ISO_STRING = new Object();
private static InvokeByName getTO_ISO_STRING() {
return Global.instance().getInvokeByName(TO_ISO_STRING,
new Callable<InvokeByName>() {
@Override
public InvokeByName call() {
return new InvokeByName("toISOString", ScriptObject.class, Object.class, Object.class);
}
});
}
private double time;
private final TimeZone timezone;
@ -861,9 +871,10 @@ public final class NativeDate extends ScriptObject {
}
try {
final Object func = TO_ISO_STRING.getGetter().invokeExact(sobj);
final InvokeByName toIsoString = getTO_ISO_STRING();
final Object func = toIsoString.getGetter().invokeExact(sobj);
if (Bootstrap.isCallable(func)) {
return TO_ISO_STRING.getInvoker().invokeExact(func, sobj, key);
return toIsoString.getInvoker().invokeExact(func, sobj, key);
}
throw typeError("not.a.function", ScriptRuntime.safeToString(func));
} catch (final RuntimeException | Error e) {

View file

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

View file

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

View file

@ -26,8 +26,10 @@
package jdk.nashorn.internal.runtime;
import java.lang.invoke.MethodHandle;
import java.util.concurrent.Callable;
import jdk.internal.dynalink.linker.GuardedInvocation;
import jdk.internal.dynalink.linker.LinkRequest;
import jdk.nashorn.internal.runtime.linker.InvokeByName;
/**
* Runtime interface to the global scope objects.
@ -210,4 +212,20 @@ public interface GlobalObject {
* @param clazz compiled Class object for the source
*/
public void cacheClass(Source source, Class<?> clazz);
/**
* Get cached InvokeByName object for the given key
* @param key key to be associated with InvokeByName object
* @param creator if InvokeByName is absent 'creator' is called to make one (lazy init)
* @return InvokeByName object associated with the key.
*/
public InvokeByName getInvokeByName(final Object key, final Callable<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.util.Iterator;
import java.util.concurrent.Callable;
import jdk.nashorn.internal.ir.LiteralNode;
import jdk.nashorn.internal.ir.Node;
import jdk.nashorn.internal.ir.ObjectNode;
@ -42,8 +43,19 @@ import jdk.nashorn.internal.runtime.linker.Bootstrap;
*/
public final class JSONFunctions {
private JSONFunctions() {}
private static final MethodHandle REVIVER_INVOKER = Bootstrap.createDynamicInvoker("dyn:call", Object.class,
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);
}
});
}
/**
* Returns JSON-compatible quoted version of the given string.
@ -117,7 +129,7 @@ public final class JSONFunctions {
try {
// Object.class, ScriptFunction.class, ScriptObject.class, String.class, Object.class);
return REVIVER_INVOKER.invokeExact(reviver, holder, JSType.toString(name), val);
return getREVIVER_INVOKER().invokeExact(reviver, holder, JSType.toString(name), val);
} catch(Error|RuntimeException t) {
throw t;
} catch(final Throwable t) {

View file

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

View file

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

View file

@ -496,32 +496,24 @@ public abstract class ScriptFunction extends ScriptObject {
MethodHandle boundHandle;
MethodHandle guard = null;
final boolean scopeCall = NashornCallSiteDescriptor.isScope(desc);
if (data.needsCallee()) {
final MethodHandle callHandle = getBestInvoker(type, request.getArguments());
if (NashornCallSiteDescriptor.isScope(desc)) {
if (scopeCall) {
// Make a handle that drops the passed "this" argument and substitutes either Global or Undefined
// (callee, this, args...) => (callee, args...)
boundHandle = MH.insertArguments(callHandle, 1, needsWrappedThis() ? Context.getGlobalTrusted() : ScriptRuntime.UNDEFINED);
// (callee, args...) => (callee, [this], args...)
boundHandle = MH.dropArguments(boundHandle, 1, Object.class);
} else {
// It's already (callee, this, args...), just what we need
boundHandle = callHandle;
// For non-strict functions, check whether this-object is primitive type.
// If so add a to-object-wrapper argument filter.
// Else install a guard that will trigger a relink when the argument becomes primitive.
if (needsWrappedThis()) {
if (ScriptFunctionData.isPrimitiveThis(request.getArguments()[1])) {
boundHandle = MH.filterArguments(boundHandle, 1, WRAPFILTER);
} else {
guard = getNonStrictFunctionGuard(this);
}
}
}
} else {
final MethodHandle callHandle = getBestInvoker(type.dropParameterTypes(0, 1), request.getArguments());
if (NashornCallSiteDescriptor.isScope(desc)) {
if (scopeCall) {
// Make a handle that drops the passed "this" argument and substitutes either Global or Undefined
// (this, args...) => (args...)
boundHandle = MH.bindTo(callHandle, needsWrappedThis() ? Context.getGlobalTrusted() : ScriptRuntime.UNDEFINED);
@ -533,6 +525,17 @@ public abstract class ScriptFunction extends ScriptObject {
}
}
// For non-strict functions, check whether this-object is primitive type.
// If so add a to-object-wrapper argument filter.
// Else install a guard that will trigger a relink when the argument becomes primitive.
if (!scopeCall && needsWrappedThis()) {
if (ScriptFunctionData.isPrimitiveThis(request.getArguments()[1])) {
boundHandle = MH.filterArguments(boundHandle, 1, WRAPFILTER);
} else {
guard = getNonStrictFunctionGuard(this);
}
}
boundHandle = pairArguments(boundHandle, type);
return new GuardedInvocation(boundHandle, guard == null ? getFunctionGuard(this) : guard);

View file

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

View file

@ -68,6 +68,10 @@ public final class Bootstrap {
if (relinkThreshold > -1) {
factory.setUnstableRelinkThreshold(relinkThreshold);
}
// Linkers for any additional language runtimes deployed alongside Nashorn will be picked up by the factory.
factory.setClassLoader(Bootstrap.class.getClassLoader());
dynamicLinker = factory.createLinker();
}

View file

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

View file

@ -224,7 +224,10 @@ public final class JavaAdapterFactory {
this.commonLoader = findCommonLoader(definingLoader);
final JavaAdapterBytecodeGenerator gen = new JavaAdapterBytecodeGenerator(superClass, interfaces, commonLoader, false);
this.autoConvertibleFromFunction = gen.isAutoConvertibleFromFunction();
this.instanceAdapterClass = gen.createAdapterClassLoader().generateClass(commonLoader);
final JavaAdapterClassLoader jacl = gen.createAdapterClassLoader();
this.instanceAdapterClass = jacl.generateClass(commonLoader);
// loaded Class - no need to keep class bytes around
jacl.clearClassBytes();
this.adapterGenerator = new JavaAdapterBytecodeGenerator(superClass, interfaces, commonLoader, true).createAdapterClassLoader();
this.adaptationResult = AdaptationResult.SUCCESSFUL_RESULT;
}

View file

@ -33,17 +33,6 @@ var BYTES_PER_INT_32 = 4
var limit = Math.pow(2, UNSIGNED_INT_BITS)/BYTES_PER_INT_32
try {
// A value at or under the limit should either succeed if we have
// enough heap, or throw an OutOfMemoryError if we don't.
Int32Array(limit - 1)
} catch(e) {
if(!(e instanceof java.lang.OutOfMemoryError)) {
// Only print an unexpected result; OutOfMemoryError is expected
print(e)
}
}
// A value over the limit should throw a RangeError.
try {
Int32Array(limit)

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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