Path: blob/master/src/jdk.dynalink/share/classes/jdk/dynalink/DynamicLinkerFactory.java
41154 views
/*1* Copyright (c) 2010, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425/*26* This file is available under and governed by the GNU General Public27* License version 2 only, as published by the Free Software Foundation.28* However, the following notice accompanied the original version of this29* file, and Oracle licenses the original version of this file under the BSD30* license:31*/32/*33Copyright 2009-2013 Attila Szegedi3435Redistribution and use in source and binary forms, with or without36modification, are permitted provided that the following conditions are37met:38* Redistributions of source code must retain the above copyright39notice, this list of conditions and the following disclaimer.40* Redistributions in binary form must reproduce the above copyright41notice, this list of conditions and the following disclaimer in the42documentation and/or other materials provided with the distribution.43* Neither the name of the copyright holder nor the names of44contributors may be used to endorse or promote products derived from45this software without specific prior written permission.4647THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS48IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED49TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A50PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER51BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR52CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF53SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR54BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,55WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR56OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF57ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.58*/5960package jdk.dynalink;6162import java.lang.invoke.MethodHandle;63import java.lang.invoke.MethodType;64import java.lang.invoke.MutableCallSite;65import java.security.AccessControlContext;66import java.security.AccessController;67import java.security.PrivilegedAction;68import java.util.ArrayList;69import java.util.Arrays;70import java.util.Collections;71import java.util.HashSet;72import java.util.Iterator;73import java.util.LinkedList;74import java.util.List;75import java.util.Objects;76import java.util.ServiceConfigurationError;77import java.util.ServiceLoader;78import java.util.Set;79import java.util.function.Supplier;80import jdk.dynalink.beans.BeansLinker;81import jdk.dynalink.internal.AccessControlContextFactory;82import jdk.dynalink.linker.GuardedInvocation;83import jdk.dynalink.linker.GuardedInvocationTransformer;84import jdk.dynalink.linker.GuardingDynamicLinker;85import jdk.dynalink.linker.GuardingDynamicLinkerExporter;86import jdk.dynalink.linker.GuardingTypeConverterFactory;87import jdk.dynalink.linker.LinkRequest;88import jdk.dynalink.linker.LinkerServices;89import jdk.dynalink.linker.MethodHandleTransformer;90import jdk.dynalink.linker.MethodTypeConversionStrategy;91import jdk.dynalink.linker.support.CompositeGuardingDynamicLinker;92import jdk.dynalink.linker.support.CompositeTypeBasedGuardingDynamicLinker;93import jdk.dynalink.linker.support.DefaultInternalObjectFilter;94import jdk.dynalink.linker.support.TypeUtilities;9596/**97* A factory class for creating {@link DynamicLinker} objects. Dynamic linkers98* are the central objects in Dynalink; these are composed of several99* {@link GuardingDynamicLinker} objects and coordinate linking of call sites100* with them. The usual dynamic linker is a linker101* composed of all {@link GuardingDynamicLinker} objects explicitly pre-created102* by the user of the factory and configured with103* {@link #setPrioritizedLinkers(List)}, as well as any104* {@link #setClassLoader(ClassLoader) automatically discovered} ones, and105* finally the ones configured with {@link #setFallbackLinkers(List)}; this last106* category usually includes {@link BeansLinker}.107*/108public final class DynamicLinkerFactory {109@SuppressWarnings("removal")110private static final AccessControlContext GET_CLASS_LOADER_CONTEXT =111AccessControlContextFactory.createAccessControlContext("getClassLoader");112113/**114* Default value for {@link #setUnstableRelinkThreshold(int) unstable relink115* threshold}.116*/117private static final int DEFAULT_UNSTABLE_RELINK_THRESHOLD = 8;118119private boolean classLoaderExplicitlySet = false;120private ClassLoader classLoader;121122private List<? extends GuardingDynamicLinker> prioritizedLinkers;123private List<? extends GuardingDynamicLinker> fallbackLinkers;124private boolean syncOnRelink = false;125private int unstableRelinkThreshold = DEFAULT_UNSTABLE_RELINK_THRESHOLD;126private GuardedInvocationTransformer prelinkTransformer;127private MethodTypeConversionStrategy autoConversionStrategy;128private MethodHandleTransformer internalObjectsFilter;129130private List<ServiceConfigurationError> autoLoadingErrors = Collections.emptyList();131132/**133* Creates a new dynamic linker factory with default configuration. Upon134* creation, the factory can be configured using various {@code setXxx()}135* methods and used to create one or more dynamic linkers according to its136* current configuration using {@link #createLinker()}.137*/138public DynamicLinkerFactory() {139}140141/**142* Sets the class loader for automatic discovery of available guarding143* dynamic linkers. {@link GuardingDynamicLinkerExporter} implementations144* available through this class loader will be automatically instantiated145* using the {@link ServiceLoader} mechanism and the linkers they provide146* will be incorporated into {@code DynamicLinker}s that this factory147* creates. This allows for cross-language interoperability where call sites148* belonging to this language runtime can be linked by linkers from these149* automatically discovered runtimes if their native objects are passed to150* this runtime. If class loader is not set explicitly by invoking this151* method, then the thread context class loader of the thread invoking152* {@link #createLinker()} will be used. If this method is invoked153* explicitly with null then {@link ServiceLoader#loadInstalled(Class)} will154* be used to load the linkers.155*156* @param classLoader the class loader used for the automatic discovery of157* available linkers.158*/159public void setClassLoader(final ClassLoader classLoader) {160this.classLoader = classLoader;161classLoaderExplicitlySet = true;162}163164/**165* Sets the prioritized guarding dynamic linkers. Language runtimes using166* Dynalink will usually have at least one linker for their own language.167* These linkers will be consulted first by the resulting dynamic linker168* when it is linking call sites, before any autodiscovered and fallback169* linkers. If the factory also autodiscovers a linker class matching one170* of the prioritized linkers, the autodiscovered class will be ignored and171* the explicit prioritized instance will be used.172*173* @param prioritizedLinkers the list of prioritized linkers. Can be null.174* @throws NullPointerException if any of the list elements are null.175*/176public void setPrioritizedLinkers(final List<? extends GuardingDynamicLinker> prioritizedLinkers) {177this.prioritizedLinkers = copyListRequireNonNullElements(prioritizedLinkers);178}179180/**181* Sets the prioritized guarding dynamic linkers. Identical to calling182* {@link #setPrioritizedLinkers(List)} with183* {@code Arrays.asList(prioritizedLinkers)}.184*185* @param prioritizedLinkers an array of prioritized linkers. Can be null.186* @throws NullPointerException if any of the array elements are null.187*/188public void setPrioritizedLinkers(final GuardingDynamicLinker... prioritizedLinkers) {189setPrioritizedLinkers(prioritizedLinkers == null ? null : Arrays.asList(prioritizedLinkers));190}191192/**193* Sets a single prioritized linker. Identical to calling194* {@link #setPrioritizedLinkers(List)} with a single-element list.195*196* @param prioritizedLinker the single prioritized linker. Must not be null.197* @throws NullPointerException if null is passed.198*/199public void setPrioritizedLinker(final GuardingDynamicLinker prioritizedLinker) {200this.prioritizedLinkers = Collections.singletonList(Objects.requireNonNull(prioritizedLinker));201}202203/**204* Sets the fallback guarding dynamic linkers. These linkers will be205* consulted last by the resulting dynamic linker when it is linking call206* sites, after any autodiscovered and prioritized linkers. If the factory207* also autodiscovers a linker class matching one of the fallback linkers,208* the autodiscovered class will be ignored and the explicit fallback209* instance will be used.210*211* @param fallbackLinkers the list of fallback linkers. Can be empty to212* indicate the caller wishes to set no fallback linkers. Note that if this213* method is not invoked explicitly or is passed null, then the factory214* will create an instance of {@link BeansLinker} to serve as the default215* fallback linker.216* @throws NullPointerException if any of the list elements are null.217*/218public void setFallbackLinkers(final List<? extends GuardingDynamicLinker> fallbackLinkers) {219this.fallbackLinkers = copyListRequireNonNullElements(fallbackLinkers);220}221222/**223* Sets the fallback guarding dynamic linkers. Identical to calling224* {@link #setFallbackLinkers(List)} with225* {@code Arrays.asList(fallbackLinkers)}.226*227* @param fallbackLinkers an array of fallback linkers. Can be empty to228* indicate the caller wishes to set no fallback linkers. Note that if this229* method is not invoked explicitly or is passed null, then the factory230* will create an instance of {@link BeansLinker} to serve as the default231* fallback linker.232* @throws NullPointerException if any of the array elements are null.233*/234public void setFallbackLinkers(final GuardingDynamicLinker... fallbackLinkers) {235setFallbackLinkers(fallbackLinkers == null ? null : Arrays.asList(fallbackLinkers));236}237238/**239* Sets whether the dynamic linker created by this factory will invoke240* {@link MutableCallSite#syncAll(MutableCallSite[])} after a call site is241* relinked. Defaults to false. You probably want to set it to true if your242* runtime supports multithreaded execution of dynamically linked code.243* @param syncOnRelink true for invoking sync on relink, false otherwise.244*/245public void setSyncOnRelink(final boolean syncOnRelink) {246this.syncOnRelink = syncOnRelink;247}248249/**250* Sets the unstable relink threshold; the number of times a call site is251* relinked after which it will be considered unstable, and subsequent link252* requests for it will indicate this. Defaults to 8 when not set explicitly.253* @param unstableRelinkThreshold the new threshold. Must not be less than254* zero. The value of zero means that call sites will never be considered255* unstable.256* @see LinkRequest#isCallSiteUnstable()257*/258public void setUnstableRelinkThreshold(final int unstableRelinkThreshold) {259if(unstableRelinkThreshold < 0) {260throw new IllegalArgumentException("unstableRelinkThreshold < 0");261}262this.unstableRelinkThreshold = unstableRelinkThreshold;263}264265/**266* Set the pre-link transformer. This is a267* {@link GuardedInvocationTransformer} that will get the final chance to268* modify the guarded invocation after it has been created by a component269* linker and before the dynamic linker links it into the call site. It is270* normally used to adapt the return value type of the invocation to the271* type of the call site. When not set explicitly, a default pre-link272* transformer will be used that simply calls273* {@link GuardedInvocation#asType(LinkerServices, MethodType)}. Customized274* pre-link transformers are rarely needed; they are mostly used as a275* building block for implementing advanced techniques such as code276* deoptimization strategies.277* @param prelinkTransformer the pre-link transformer for the dynamic278* linker. Can be null to have the factory use the default transformer.279*/280public void setPrelinkTransformer(final GuardedInvocationTransformer prelinkTransformer) {281this.prelinkTransformer = prelinkTransformer;282}283284/**285* Sets an object representing the conversion strategy for automatic type286* conversions. After287* {@link LinkerServices#asType(MethodHandle, MethodType)} has applied all288* custom conversions to a method handle, it still needs to effect289* {@link TypeUtilities#isMethodInvocationConvertible(Class, Class) method290* invocation conversions} that can usually be automatically applied as per291* {@link MethodHandle#asType(MethodType)}. However, sometimes language292* runtimes will want to customize even those conversions for their own call293* sites. A typical example is allowing unboxing of null return values,294* which is by default prohibited by ordinary295* {@code MethodHandles.asType()}. In this case, a language runtime can296* install its own custom automatic conversion strategy, that can deal with297* null values. Note that when the strategy's298* {@link MethodTypeConversionStrategy#asType(MethodHandle, MethodType)}299* is invoked, the custom language conversions will already have been300* applied to the method handle, so by design the difference between the301* handle's current method type and the desired final type will always only302* be ones that can be subjected to method invocation conversions. The303* strategy also doesn't need to invoke a final304* {@code MethodHandle.asType()} as that will be done internally as the305* final step.306* @param autoConversionStrategy the strategy for applying method invocation307* conversions for the linker created by this factory. Can be null for no308* custom strategy.309*/310public void setAutoConversionStrategy(final MethodTypeConversionStrategy autoConversionStrategy) {311this.autoConversionStrategy = autoConversionStrategy;312}313314/**315* Sets a method handle transformer that is supposed to act as the316* implementation of317* {@link LinkerServices#filterInternalObjects(MethodHandle)} for linker318* services of dynamic linkers created by this factory. Some language319* runtimes can have internal objects that should not escape their scope.320* They can add a transformer here that will modify the method handle so321* that any parameters that can receive potentially internal language322* runtime objects will have a filter added on them to prevent them from323* escaping, potentially by wrapping them. The transformer can also324* potentially add an unwrapping filter to the return value.325* {@link DefaultInternalObjectFilter} is provided as a convenience class326* for easily creating such filtering transformers.327* @param internalObjectsFilter a method handle transformer filtering out328* internal objects, or null.329*/330public void setInternalObjectsFilter(final MethodHandleTransformer internalObjectsFilter) {331this.internalObjectsFilter = internalObjectsFilter;332}333334/**335* Creates a new dynamic linker based on the current configuration. This336* method can be invoked more than once to create multiple dynamic linkers.337* Automatically discovered linkers are newly instantiated on every338* invocation of this method. It is allowed to change the factory's339* configuration between invocations. The method is not thread safe. After340* invocation, callers can invoke {@link #getAutoLoadingErrors()} to341* retrieve a list of {@link ServiceConfigurationError}s that occurred while342* trying to load automatically discovered linkers. These are never thrown343* from the call to this method as it makes every effort to recover from344* them and ignore the failing linkers.345* @return the new dynamic Linker346*/347public DynamicLinker createLinker() {348// Treat nulls appropriately349if(prioritizedLinkers == null) {350prioritizedLinkers = Collections.emptyList();351}352if(fallbackLinkers == null) {353fallbackLinkers = Collections.singletonList(new BeansLinker());354}355356// Gather classes of all precreated (prioritized and fallback) linkers.357// We'll filter out any discovered linkers of the same class.358final Set<Class<? extends GuardingDynamicLinker>> knownLinkerClasses =359new HashSet<>();360addClasses(knownLinkerClasses, prioritizedLinkers);361addClasses(knownLinkerClasses, fallbackLinkers);362363final List<GuardingDynamicLinker> discovered = discoverAutoLoadLinkers();364// Now, concatenate ...365final List<GuardingDynamicLinker> linkers =366new ArrayList<>(prioritizedLinkers.size() + discovered.size()367+ fallbackLinkers.size());368// ... prioritized linkers, ...369linkers.addAll(prioritizedLinkers);370// ... filtered discovered linkers, ...371for(final GuardingDynamicLinker linker: discovered) {372if(!knownLinkerClasses.contains(linker.getClass())) {373linkers.add(linker);374}375}376// ... and finally fallback linkers.377linkers.addAll(fallbackLinkers);378final List<GuardingDynamicLinker> optimized = CompositeTypeBasedGuardingDynamicLinker.optimize(linkers);379final GuardingDynamicLinker composite;380switch(linkers.size()) {381case 0: {382composite = (r, s) -> null; // linker that can't link anything383break;384}385case 1: {386composite = optimized.get(0);387break;388}389default: {390composite = new CompositeGuardingDynamicLinker(optimized);391break;392}393}394395final List<GuardingTypeConverterFactory> typeConverters = new LinkedList<>();396for(final GuardingDynamicLinker linker: linkers) {397if(linker instanceof GuardingTypeConverterFactory) {398typeConverters.add((GuardingTypeConverterFactory)linker);399}400}401402if(prelinkTransformer == null) {403prelinkTransformer = (inv, request, linkerServices) -> inv.asType(linkerServices, request.getCallSiteDescriptor().getMethodType());404}405406return new DynamicLinker(new LinkerServicesImpl(new TypeConverterFactory(typeConverters,407autoConversionStrategy), composite, internalObjectsFilter), prelinkTransformer,408syncOnRelink, unstableRelinkThreshold);409}410411/**412* Returns a list of {@link ServiceConfigurationError}s that were413* encountered while loading automatically discovered linkers during the414* last invocation of {@link #createLinker()}. They can be any non-Dynalink415* specific service configuration issues, as well as some Dynalink-specific416* errors when an exporter that the factory tried to automatically load:417* <ul>418* <li>did not have the runtime permission named419* {@link GuardingDynamicLinkerExporter#AUTOLOAD_PERMISSION_NAME} in a420* system with a security manager, or</li>421* <li>returned null from {@link GuardingDynamicLinkerExporter#get()}, or</li>422* <li>the list returned from {@link GuardingDynamicLinkerExporter#get()}423* had a null element.</li>424* </ul>425* @return an immutable list of encountered426* {@link ServiceConfigurationError}s. Can be empty.427*/428public List<ServiceConfigurationError> getAutoLoadingErrors() {429return Collections.unmodifiableList(autoLoadingErrors);430}431432private List<GuardingDynamicLinker> discoverAutoLoadLinkers() {433autoLoadingErrors = new LinkedList<>();434final ClassLoader effectiveClassLoader = classLoaderExplicitlySet ? classLoader : getThreadContextClassLoader();435final List<GuardingDynamicLinker> discovered = new LinkedList<>();436try {437@SuppressWarnings("removal")438final ServiceLoader<GuardingDynamicLinkerExporter> linkerLoader =439AccessController.doPrivileged((PrivilegedAction<ServiceLoader<GuardingDynamicLinkerExporter>>)()-> {440if (effectiveClassLoader == null) {441return ServiceLoader.loadInstalled(GuardingDynamicLinkerExporter.class);442}443return ServiceLoader.load(GuardingDynamicLinkerExporter.class, effectiveClassLoader);444});445446for(final Iterator<GuardingDynamicLinkerExporter> it = linkerLoader.iterator(); it.hasNext();) {447try {448final GuardingDynamicLinkerExporter autoLoader = it.next();449try {450discovered.addAll(requireNonNullElements(451Objects.requireNonNull(autoLoader.get(),452()->(autoLoader.getClass().getName() + " returned null from get()")),453()->(autoLoader.getClass().getName() + " returned a list with at least one null element")));454} catch (final ServiceConfigurationError|VirtualMachineError e) {455// Don't wrap a SCE in another SCE. Also, don't ignore456// any VME (e.g. StackOverflowError or OutOfMemoryError).457throw e;458} catch (final Throwable t) {459throw new ServiceConfigurationError(t.getMessage(), t);460}461} catch (final ServiceConfigurationError e) {462// Catch SCE with an individual exporter, carry on with it.hasNext().463autoLoadingErrors.add(e);464}465}466} catch (final ServiceConfigurationError e) {467// Catch a top-level SCE; one either in ServiceLoader.load(),468// ServiceLoader.iterator(), or Iterator.hasNext().469autoLoadingErrors.add(e);470}471return discovered;472}473474@SuppressWarnings("removal")475private static ClassLoader getThreadContextClassLoader() {476return AccessController.doPrivileged(477(PrivilegedAction<ClassLoader>) () -> Thread.currentThread().getContextClassLoader(),478GET_CLASS_LOADER_CONTEXT);479}480481private static void addClasses(final Set<Class<? extends GuardingDynamicLinker>> knownLinkerClasses,482final List<? extends GuardingDynamicLinker> linkers) {483for(final GuardingDynamicLinker linker: linkers) {484knownLinkerClasses.add(linker.getClass());485}486}487488private static <T> List<T> copyListRequireNonNullElements(final List<T> list) {489if (list == null) {490return null;491}492return new ArrayList<>(requireNonNullElements(list, ()->"List has at least one null element"));493}494495private static <T> List<T> requireNonNullElements(final List<T> list, final Supplier<String> msgSupplier) {496for(final T t: list) {497Objects.requireNonNull(t, msgSupplier);498}499return list;500}501502}503504505