nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/DynamicLinkerFactory.java
changeset 33339 334cd3ebfa5e
parent 33337 af3fea63e008
child 33340 6c945c826f36
--- 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);
+    }
+
 }