--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/DynamicLinkerFactory.java Tue Oct 20 23:33:39 2015 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/DynamicLinkerFactory.java Tue Oct 20 23:34:16 2015 +0200
@@ -94,6 +94,7 @@
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
+import java.util.Objects;
import java.util.ServiceLoader;
import java.util.Set;
import jdk.internal.dynalink.beans.BeansLinker;
@@ -107,17 +108,20 @@
import jdk.internal.dynalink.linker.MethodTypeConversionStrategy;
import jdk.internal.dynalink.linker.support.CompositeGuardingDynamicLinker;
import jdk.internal.dynalink.linker.support.CompositeTypeBasedGuardingDynamicLinker;
+import jdk.internal.dynalink.linker.support.DefaultInternalObjectFilter;
import jdk.internal.dynalink.linker.support.TypeUtilities;
/**
- * A factory class for creating {@link DynamicLinker} objects. The usual dynamic
- * linker is a linker composed of all {@link GuardingDynamicLinker} objects
- * known and pre-created by the caller as well as any guarding linkers
- * automatically discovered as declared in
- * {@code /META-INF/services/jdk.internal.dynalink.linker.GuardingDynamicLinker}
- * resources in the classpath (see {@link ServiceLoader} for the description of
- * this mechanism), and the standard fallback {@link BeansLinker}.
- * See {@link DynamicLinker} documentation for tips on how to use this class.
+ * A factory class for creating {@link DynamicLinker} objects. Dynamic linkers
+ * are the central objects in Dynalink; these are composed of several
+ * {@link GuardingDynamicLinker} objects and coordinate linking of call sites
+ * with them. The usual dynamic linker is a linker
+ * composed of all {@link GuardingDynamicLinker} objects explicitly pre-created
+ * by the user of the factory and configured with
+ * {@link #setPrioritizedLinkers(List)}, as well as any
+ * {@link #setClassLoader(ClassLoader) automatically discovered} ones, and
+ * finally the ones configured with {@link #setFallbackLinkers(List)}; this last
+ * category usually includes {@link BeansLinker}.
*/
public final class DynamicLinkerFactory {
/**
@@ -147,9 +151,18 @@
}
/**
- * Sets the class loader for automatic discovery of available linkers. If
- * not set explicitly, then the thread context class loader of the thread
- * invoking {@link #createLinker()} invocation will be used.
+ * Sets the class loader for automatic discovery of available guarding
+ * dynamic linkers. Guarding dynamic linker classes declared in
+ * {@code /META-INF/services/jdk.internal.dynalink.linker.GuardingDynamicLinker}
+ * resources available through this class loader will be automatically
+ * instantiated using the {@link ServiceLoader} mechanism and incorporated
+ * into {@code DynamicLinker}s that this factory creates. This allows for
+ * cross-language interoperability where call sites belonging to this language
+ * runtime can be linked by linkers from these autodiscovered runtimes if
+ * their native objects are passed to this runtime. If class loader is not
+ * set explicitly, then the thread context class loader of the thread
+ * invoking {@link #createLinker()} will be used. Can be invoked with null
+ * to signify system class loader.
*
* @param classLoader the class loader used for the automatic discovery of
* available linkers.
@@ -160,73 +173,84 @@
}
/**
- * Sets the prioritized linkers. Language runtimes using this framework will usually precreate at least the linker
- * for their own language. These linkers will be consulted first in the resulting dynamic linker, before any
- * autodiscovered linkers. If the framework also autodiscovers a linker of the same class as one of the prioritized
- * linkers, it will be ignored and the explicit prioritized instance will be used.
+ * Sets the prioritized guarding dynamic linkers. Language runtimes using
+ * Dynalink will usually have at least one linker for their own language.
+ * These linkers will be consulted first by the resulting dynamic linker
+ * when it is linking call sites, before any autodiscovered and fallback
+ * linkers. If the factory also autodiscovers a linker class matching one
+ * of the prioritized linkers, the autodiscovered class will be ignored and
+ * the explicit prioritized instance will be used.
*
- * @param prioritizedLinkers the list of prioritized linkers. Null can be passed to indicate no prioritized linkers
- * (this is also the default value).
+ * @param prioritizedLinkers the list of prioritized linkers. Can be null.
+ * @throws NullPointerException if any of the list elements are null.
*/
public void setPrioritizedLinkers(final List<? extends GuardingDynamicLinker> prioritizedLinkers) {
- this.prioritizedLinkers =
- prioritizedLinkers == null ? null : new ArrayList<>(prioritizedLinkers);
+ this.prioritizedLinkers = reqireNonNullElements(prioritizedLinkers);
}
/**
- * Sets the prioritized linkers. Language runtimes using this framework will usually precreate at least the linker
- * for their own language. These linkers will be consulted first in the resulting dynamic linker, before any
- * autodiscovered linkers. If the framework also autodiscovers a linker of the same class as one of the prioritized
- * linkers, it will be ignored and the explicit prioritized instance will be used.
+ * Sets the prioritized guarding dynamic linkers. Identical to calling
+ * {@link #setPrioritizedLinkers(List)} with
+ * {@code Arrays.asList(prioritizedLinkers)}.
*
- * @param prioritizedLinkers a list of prioritized linkers.
+ * @param prioritizedLinkers an array of prioritized linkers. Can be null.
+ * @throws NullPointerException if any of the array elements are null.
*/
public void setPrioritizedLinkers(final GuardingDynamicLinker... prioritizedLinkers) {
- setPrioritizedLinkers(Arrays.asList(prioritizedLinkers));
+ setPrioritizedLinkers(prioritizedLinkers == null ? null : Arrays.asList(prioritizedLinkers));
+ }
+
+ /**
+ * Sets a single prioritized linker. Identical to calling
+ * {@link #setPrioritizedLinkers(List)} with a single-element list.
+ *
+ * @param prioritizedLinker the single prioritized linker. Must not be null.
+ * @throws NullPointerException if null is passed.
+ */
+ public void setPrioritizedLinker(final GuardingDynamicLinker prioritizedLinker) {
+ this.prioritizedLinkers = Collections.singletonList(Objects.requireNonNull(prioritizedLinker));
}
/**
- * Sets a single prioritized linker. Identical to calling {@link #setPrioritizedLinkers(List)} with a single-element
- * list.
+ * Sets the fallback guarding dynamic linkers. These linkers will be
+ * consulted last by the resulting dynamic linker when it is linking call
+ * sites, after any autodiscovered and prioritized linkers. If the factory
+ * also autodiscovers a linker class matching one of the fallback linkers,
+ * the autodiscovered class will be ignored and the explicit fallback
+ * instance will be used.
*
- * @param prioritizedLinker the single prioritized linker. Must not be null.
- * @throws IllegalArgumentException if null is passed.
+ * @param fallbackLinkers the list of fallback linkers. Can be empty to
+ * indicate the caller wishes to set no fallback linkers. Note that if this
+ * method is not invoked explicitly or is passed null, then the factory
+ * will create an instance of {@link BeansLinker} to serve as the default
+ * fallback linker.
+ * @throws NullPointerException if any of the list elements are null.
*/
- public void setPrioritizedLinker(final GuardingDynamicLinker prioritizedLinker) {
- if(prioritizedLinker == null) {
- throw new IllegalArgumentException("prioritizedLinker == null");
- }
- this.prioritizedLinkers = Collections.singletonList(prioritizedLinker);
+ public void setFallbackLinkers(final List<? extends GuardingDynamicLinker> fallbackLinkers) {
+ this.fallbackLinkers = reqireNonNullElements(fallbackLinkers);
}
/**
- * Sets the fallback linkers. These linkers will be consulted last in the resulting composite linker, after any
- * autodiscovered linkers. If the framework also autodiscovers a linker of the same class as one of the fallback
- * linkers, it will be ignored and the explicit fallback instance will be used.
+ * Sets the fallback guarding dynamic linkers. Identical to calling
+ * {@link #setFallbackLinkers(List)} with
+ * {@code Arrays.asList(fallbackLinkers)}.
*
- * @param fallbackLinkers the list of fallback linkers. Can be empty to indicate the caller wishes to set no
- * fallback linkers.
+ * @param fallbackLinkers an array of fallback linkers. Can be empty to
+ * indicate the caller wishes to set no fallback linkers. Note that if this
+ * method is not invoked explicitly or is passed null, then the factory
+ * will create an instance of {@link BeansLinker} to serve as the default
+ * fallback linker.
+ * @throws NullPointerException if any of the array elements are null.
*/
- public void setFallbackLinkers(final List<? extends GuardingDynamicLinker> fallbackLinkers) {
- this.fallbackLinkers = fallbackLinkers == null ? null : new ArrayList<>(fallbackLinkers);
+ public void setFallbackLinkers(final GuardingDynamicLinker... fallbackLinkers) {
+ setFallbackLinkers(fallbackLinkers == null ? null : Arrays.asList(fallbackLinkers));
}
/**
- * Sets the fallback linkers. These linkers will be consulted last in the resulting composite linker, after any
- * autodiscovered linkers. If the framework also autodiscovers a linker of the same class as one of the fallback
- * linkers, it will be ignored and the explicit fallback instance will be used.
- *
- * @param fallbackLinkers the list of fallback linkers. Can be empty to indicate the caller wishes to set no
- * fallback linkers. If it is left as null, the standard fallback {@link BeansLinker} will be used.
- */
- public void setFallbackLinkers(final GuardingDynamicLinker... fallbackLinkers) {
- setFallbackLinkers(Arrays.asList(fallbackLinkers));
- }
-
- /**
- * Sets whether the linker created by this factory will invoke {@link MutableCallSite#syncAll(MutableCallSite[])}
- * after a call site is relinked. Defaults to false. You probably want to set it to true if your runtime supports
- * multithreaded execution of dynamically linked code.
+ * Sets whether the dynamic linker created by this factory will invoke
+ * {@link MutableCallSite#syncAll(MutableCallSite[])} after a call site is
+ * relinked. Defaults to false. You probably want to set it to true if your
+ * runtime supports multithreaded execution of dynamically linked code.
* @param syncOnRelink true for invoking sync on relink, false otherwise.
*/
public void setSyncOnRelink(final boolean syncOnRelink) {
@@ -234,10 +258,12 @@
}
/**
- * Sets the unstable relink threshold; the number of times a call site is relinked after which it will be
- * considered unstable, and subsequent link requests for it will indicate this.
- * @param unstableRelinkThreshold the new threshold. Must not be less than zero. The value of zero means that
- * call sites will never be considered unstable.
+ * Sets the unstable relink threshold; the number of times a call site is
+ * relinked after which it will be considered unstable, and subsequent link
+ * requests for it will indicate this.
+ * @param unstableRelinkThreshold the new threshold. Must not be less than
+ * zero. The value of zero means that call sites will never be considered
+ * unstable.
* @see LinkRequest#isCallSiteUnstable()
*/
public void setUnstableRelinkThreshold(final int unstableRelinkThreshold) {
@@ -248,53 +274,80 @@
}
/**
- * Set the pre-link transformer. This is a {@link GuardedInvocationTransformer} that will get the final chance to modify the
- * guarded invocation after it has been created by a component linker and before the dynamic linker links it into
- * the call site. It is normally used to adapt the return value type of the invocation to the type of the call site.
- * When not set explicitly, a default pre-link transformer will be used that simply calls
- * {@link GuardedInvocation#asType(LinkerServices, MethodType)}
- * @param prelinkTransformer the pre-link transformer for the dynamic linker.
+ * Set the pre-link transformer. This is a
+ * {@link GuardedInvocationTransformer} that will get the final chance to
+ * modify the guarded invocation after it has been created by a component
+ * linker and before the dynamic linker links it into the call site. It is
+ * normally used to adapt the return value type of the invocation to the
+ * type of the call site. When not set explicitly, a default pre-link
+ * transformer will be used that simply calls
+ * {@link GuardedInvocation#asType(LinkerServices, MethodType)}. Customized
+ * pre-link transformers are rarely needed; they are mostly used as a
+ * building block for implementing advanced techniques such as code
+ * deoptimization strategies.
+ * @param prelinkTransformer the pre-link transformer for the dynamic
+ * linker. Can be null to have the factory use the default transformer.
*/
public void setPrelinkTransformer(final GuardedInvocationTransformer prelinkTransformer) {
this.prelinkTransformer = prelinkTransformer;
}
/**
- * Sets an object representing the conversion strategy for automatic type conversions. After
- * {@link TypeConverterFactory#asType(MethodHandle, MethodType)} has
- * applied all custom conversions to a method handle, it still needs to effect
- * {@link TypeUtilities#isMethodInvocationConvertible(Class, Class) method invocation conversions} that
- * can usually be automatically applied as per
- * {@link java.lang.invoke.MethodHandle#asType(MethodType)}.
- * However, sometimes language runtimes will want to customize even those conversions for their own call
- * sites. A typical example is allowing unboxing of null return values, which is by default prohibited by
- * ordinary {@code MethodHandles.asType}. In this case, a language runtime can install its own custom
- * automatic conversion strategy, that can deal with null values. Note that when the strategy's
+ * Sets an object representing the conversion strategy for automatic type
+ * conversions. After
+ * {@link LinkerServices#asType(MethodHandle, MethodType)} has applied all
+ * custom conversions to a method handle, it still needs to effect
+ * {@link TypeUtilities#isMethodInvocationConvertible(Class, Class) method
+ * invocation conversions} that can usually be automatically applied as per
+ * {@link MethodHandle#asType(MethodType)}. However, sometimes language
+ * runtimes will want to customize even those conversions for their own call
+ * sites. A typical example is allowing unboxing of null return values,
+ * which is by default prohibited by ordinary
+ * {@code MethodHandles.asType()}. In this case, a language runtime can
+ * install its own custom automatic conversion strategy, that can deal with
+ * null values. Note that when the strategy's
* {@link MethodTypeConversionStrategy#asType(MethodHandle, MethodType)}
- * is invoked, the custom language conversions will already have been applied to the method handle, so by
- * design the difference between the handle's current method type and the desired final type will always
- * only be ones that can be subjected to method invocation conversions. The strategy also doesn't need to
- * invoke a final {@code MethodHandle.asType()} as the converter factory will do that as the final step.
- * @param autoConversionStrategy the strategy for applying method invocation conversions for the linker
- * created by this factory.
+ * is invoked, the custom language conversions will already have been
+ * applied to the method handle, so by design the difference between the
+ * handle's current method type and the desired final type will always only
+ * be ones that can be subjected to method invocation conversions. The
+ * strategy also doesn't need to invoke a final
+ * {@code MethodHandle.asType()} as that will be done internally as the
+ * final step.
+ * @param autoConversionStrategy the strategy for applying method invocation
+ * conversions for the linker created by this factory. Can be null for no
+ * custom strategy.
*/
public void setAutoConversionStrategy(final MethodTypeConversionStrategy autoConversionStrategy) {
this.autoConversionStrategy = autoConversionStrategy;
}
/**
- * Sets a method handle transformer that is supposed to act as the implementation of this linker factory's linkers'
- * services {@link LinkerServices#filterInternalObjects(java.lang.invoke.MethodHandle)} method.
- * @param internalObjectsFilter a method handle transformer filtering out internal objects, or null.
+ * Sets a method handle transformer that is supposed to act as the
+ * implementation of
+ * {@link LinkerServices#filterInternalObjects(MethodHandle)} for linker
+ * services of dynamic linkers created by this factory. Some language
+ * runtimes can have internal objects that should not escape their scope.
+ * They can add a transformer here that will modify the method handle so
+ * that any parameters that can receive potentially internal language
+ * runtime objects will have a filter added on them to prevent them from
+ * escaping, potentially by wrapping them. The transformer can also
+ * potentially add an unwrapping filter to the return value.
+ * {@link DefaultInternalObjectFilter} is provided as a convenience class
+ * for easily creating such filtering transformers.
+ * @param internalObjectsFilter a method handle transformer filtering out
+ * internal objects, or null.
*/
public void setInternalObjectsFilter(final MethodHandleTransformer internalObjectsFilter) {
this.internalObjectsFilter = internalObjectsFilter;
}
/**
- * Creates a new dynamic linker consisting of all the prioritized, autodiscovered, and fallback linkers as well as
- * the pre-link transformer.
- *
+ * Creates a new dynamic linker based on the current configuration. This
+ * method can be invoked more than once to create multiple dynamic linkers.
+ * Autodiscovered linkers are newly instantiated on every invocation of this
+ * method. It is allowed to change the factory's configuration between
+ * invocations. The method is not thread safe.
* @return the new dynamic Linker
*/
public DynamicLinker createLinker() {
@@ -382,4 +435,15 @@
knownLinkerClasses.add(linker.getClass());
}
}
+
+ private static <T> List<T> reqireNonNullElements(final List<T> list) {
+ if (list == null) {
+ return null;
+ }
+ for(final T t: list) {
+ Objects.requireNonNull(t);
+ }
+ return new ArrayList<>(list);
+ }
+
}