DynamicLinkerFactory.java revision 1643:133ea8746b37
1/* 2 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26/* 27 * This file is available under and governed by the GNU General Public 28 * License version 2 only, as published by the Free Software Foundation. 29 * However, the following notice accompanied the original version of this 30 * file, and Oracle licenses the original version of this file under the BSD 31 * license: 32 */ 33/* 34 Copyright 2009-2013 Attila Szegedi 35 36 Licensed under both the Apache License, Version 2.0 (the "Apache License") 37 and the BSD License (the "BSD License"), with licensee being free to 38 choose either of the two at their discretion. 39 40 You may not use this file except in compliance with either the Apache 41 License or the BSD License. 42 43 If you choose to use this file in compliance with the Apache License, the 44 following notice applies to you: 45 46 You may obtain a copy of the Apache License at 47 48 http://www.apache.org/licenses/LICENSE-2.0 49 50 Unless required by applicable law or agreed to in writing, software 51 distributed under the License is distributed on an "AS IS" BASIS, 52 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 53 implied. See the License for the specific language governing 54 permissions and limitations under the License. 55 56 If you choose to use this file in compliance with the BSD License, the 57 following notice applies to you: 58 59 Redistribution and use in source and binary forms, with or without 60 modification, are permitted provided that the following conditions are 61 met: 62 * Redistributions of source code must retain the above copyright 63 notice, this list of conditions and the following disclaimer. 64 * Redistributions in binary form must reproduce the above copyright 65 notice, this list of conditions and the following disclaimer in the 66 documentation and/or other materials provided with the distribution. 67 * Neither the name of the copyright holder nor the names of 68 contributors may be used to endorse or promote products derived from 69 this software without specific prior written permission. 70 71 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 72 IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 73 TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 74 PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER 75 BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 76 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 77 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 78 BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 79 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 80 OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 81 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 82*/ 83 84package jdk.dynalink; 85 86import java.lang.invoke.MethodHandle; 87import java.lang.invoke.MethodType; 88import java.lang.invoke.MutableCallSite; 89import java.security.AccessControlContext; 90import java.security.AccessController; 91import java.security.PrivilegedAction; 92import java.util.ArrayList; 93import java.util.Arrays; 94import java.util.Collections; 95import java.util.HashSet; 96import java.util.Iterator; 97import java.util.LinkedList; 98import java.util.List; 99import java.util.Objects; 100import java.util.ServiceConfigurationError; 101import java.util.ServiceLoader; 102import java.util.Set; 103import java.util.function.Supplier; 104import jdk.dynalink.beans.BeansLinker; 105import jdk.dynalink.internal.AccessControlContextFactory; 106import jdk.dynalink.linker.GuardedInvocation; 107import jdk.dynalink.linker.GuardedInvocationTransformer; 108import jdk.dynalink.linker.GuardingDynamicLinker; 109import jdk.dynalink.linker.GuardingDynamicLinkerExporter; 110import jdk.dynalink.linker.GuardingTypeConverterFactory; 111import jdk.dynalink.linker.LinkRequest; 112import jdk.dynalink.linker.LinkerServices; 113import jdk.dynalink.linker.MethodHandleTransformer; 114import jdk.dynalink.linker.MethodTypeConversionStrategy; 115import jdk.dynalink.linker.support.CompositeGuardingDynamicLinker; 116import jdk.dynalink.linker.support.CompositeTypeBasedGuardingDynamicLinker; 117import jdk.dynalink.linker.support.DefaultInternalObjectFilter; 118import jdk.dynalink.linker.support.TypeUtilities; 119 120/** 121 * A factory class for creating {@link DynamicLinker} objects. Dynamic linkers 122 * are the central objects in Dynalink; these are composed of several 123 * {@link GuardingDynamicLinker} objects and coordinate linking of call sites 124 * with them. The usual dynamic linker is a linker 125 * composed of all {@link GuardingDynamicLinker} objects explicitly pre-created 126 * by the user of the factory and configured with 127 * {@link #setPrioritizedLinkers(List)}, as well as any 128 * {@link #setClassLoader(ClassLoader) automatically discovered} ones, and 129 * finally the ones configured with {@link #setFallbackLinkers(List)}; this last 130 * category usually includes {@link BeansLinker}. 131 */ 132public final class DynamicLinkerFactory { 133 private static final AccessControlContext GET_CLASS_LOADER_CONTEXT = 134 AccessControlContextFactory.createAccessControlContext("getClassLoader"); 135 136 /** 137 * Default value for {@link #setUnstableRelinkThreshold(int) unstable relink 138 * threshold}. 139 */ 140 private static final int DEFAULT_UNSTABLE_RELINK_THRESHOLD = 8; 141 142 private boolean classLoaderExplicitlySet = false; 143 private ClassLoader classLoader; 144 145 private List<? extends GuardingDynamicLinker> prioritizedLinkers; 146 private List<? extends GuardingDynamicLinker> fallbackLinkers; 147 private boolean syncOnRelink = false; 148 private int unstableRelinkThreshold = DEFAULT_UNSTABLE_RELINK_THRESHOLD; 149 private GuardedInvocationTransformer prelinkTransformer; 150 private MethodTypeConversionStrategy autoConversionStrategy; 151 private MethodHandleTransformer internalObjectsFilter; 152 153 private List<ServiceConfigurationError> autoLoadingErrors = Collections.emptyList(); 154 155 /** 156 * Creates a new dynamic linker factory with default configuration. Upon 157 * creation, the factory can be configured using various {@code setXxx()} 158 * methods and used to create one or more dynamic linkers according to its 159 * current configuration using {@link #createLinker()}. 160 */ 161 public DynamicLinkerFactory() { 162 } 163 164 /** 165 * Sets the class loader for automatic discovery of available guarding 166 * dynamic linkers. {@link GuardingDynamicLinkerExporter} implementations 167 * available through this class loader will be automatically instantiated 168 * using the {@link ServiceLoader} mechanism and the linkers they provide 169 * will be incorporated into {@code DynamicLinker}s that this factory 170 * creates. This allows for cross-language interoperability where call sites 171 * belonging to this language runtime can be linked by linkers from these 172 * automatically discovered runtimes if their native objects are passed to 173 * this runtime. If class loader is not set explicitly by invoking this 174 * method, then the thread context class loader of the thread invoking 175 * {@link #createLinker()} will be used. If this method is invoked 176 * explicitly with null then {@link ServiceLoader#loadInstalled(Class)} will 177 * be used to load the linkers. 178 * 179 * @param classLoader the class loader used for the automatic discovery of 180 * available linkers. 181 */ 182 public void setClassLoader(final ClassLoader classLoader) { 183 this.classLoader = classLoader; 184 classLoaderExplicitlySet = true; 185 } 186 187 /** 188 * Sets the prioritized guarding dynamic linkers. Language runtimes using 189 * Dynalink will usually have at least one linker for their own language. 190 * These linkers will be consulted first by the resulting dynamic linker 191 * when it is linking call sites, before any autodiscovered and fallback 192 * linkers. If the factory also autodiscovers a linker class matching one 193 * of the prioritized linkers, the autodiscovered class will be ignored and 194 * the explicit prioritized instance will be used. 195 * 196 * @param prioritizedLinkers the list of prioritized linkers. Can be null. 197 * @throws NullPointerException if any of the list elements are null. 198 */ 199 public void setPrioritizedLinkers(final List<? extends GuardingDynamicLinker> prioritizedLinkers) { 200 this.prioritizedLinkers = copyListRequireNonNullElements(prioritizedLinkers); 201 } 202 203 /** 204 * Sets the prioritized guarding dynamic linkers. Identical to calling 205 * {@link #setPrioritizedLinkers(List)} with 206 * {@code Arrays.asList(prioritizedLinkers)}. 207 * 208 * @param prioritizedLinkers an array of prioritized linkers. Can be null. 209 * @throws NullPointerException if any of the array elements are null. 210 */ 211 public void setPrioritizedLinkers(final GuardingDynamicLinker... prioritizedLinkers) { 212 setPrioritizedLinkers(prioritizedLinkers == null ? null : Arrays.asList(prioritizedLinkers)); 213 } 214 215 /** 216 * Sets a single prioritized linker. Identical to calling 217 * {@link #setPrioritizedLinkers(List)} with a single-element list. 218 * 219 * @param prioritizedLinker the single prioritized linker. Must not be null. 220 * @throws NullPointerException if null is passed. 221 */ 222 public void setPrioritizedLinker(final GuardingDynamicLinker prioritizedLinker) { 223 this.prioritizedLinkers = Collections.singletonList(Objects.requireNonNull(prioritizedLinker)); 224 } 225 226 /** 227 * Sets the fallback guarding dynamic linkers. These linkers will be 228 * consulted last by the resulting dynamic linker when it is linking call 229 * sites, after any autodiscovered and prioritized linkers. If the factory 230 * also autodiscovers a linker class matching one of the fallback linkers, 231 * the autodiscovered class will be ignored and the explicit fallback 232 * instance will be used. 233 * 234 * @param fallbackLinkers the list of fallback linkers. Can be empty to 235 * indicate the caller wishes to set no fallback linkers. Note that if this 236 * method is not invoked explicitly or is passed null, then the factory 237 * will create an instance of {@link BeansLinker} to serve as the default 238 * fallback linker. 239 * @throws NullPointerException if any of the list elements are null. 240 */ 241 public void setFallbackLinkers(final List<? extends GuardingDynamicLinker> fallbackLinkers) { 242 this.fallbackLinkers = copyListRequireNonNullElements(fallbackLinkers); 243 } 244 245 /** 246 * Sets the fallback guarding dynamic linkers. Identical to calling 247 * {@link #setFallbackLinkers(List)} with 248 * {@code Arrays.asList(fallbackLinkers)}. 249 * 250 * @param fallbackLinkers an array of fallback linkers. Can be empty to 251 * indicate the caller wishes to set no fallback linkers. Note that if this 252 * method is not invoked explicitly or is passed null, then the factory 253 * will create an instance of {@link BeansLinker} to serve as the default 254 * fallback linker. 255 * @throws NullPointerException if any of the array elements are null. 256 */ 257 public void setFallbackLinkers(final GuardingDynamicLinker... fallbackLinkers) { 258 setFallbackLinkers(fallbackLinkers == null ? null : Arrays.asList(fallbackLinkers)); 259 } 260 261 /** 262 * Sets whether the dynamic linker created by this factory will invoke 263 * {@link MutableCallSite#syncAll(MutableCallSite[])} after a call site is 264 * relinked. Defaults to false. You probably want to set it to true if your 265 * runtime supports multithreaded execution of dynamically linked code. 266 * @param syncOnRelink true for invoking sync on relink, false otherwise. 267 */ 268 public void setSyncOnRelink(final boolean syncOnRelink) { 269 this.syncOnRelink = syncOnRelink; 270 } 271 272 /** 273 * Sets the unstable relink threshold; the number of times a call site is 274 * relinked after which it will be considered unstable, and subsequent link 275 * requests for it will indicate this. Defaults to 8 when not set explicitly. 276 * @param unstableRelinkThreshold the new threshold. Must not be less than 277 * zero. The value of zero means that call sites will never be considered 278 * unstable. 279 * @see LinkRequest#isCallSiteUnstable() 280 */ 281 public void setUnstableRelinkThreshold(final int unstableRelinkThreshold) { 282 if(unstableRelinkThreshold < 0) { 283 throw new IllegalArgumentException("unstableRelinkThreshold < 0"); 284 } 285 this.unstableRelinkThreshold = unstableRelinkThreshold; 286 } 287 288 /** 289 * Set the pre-link transformer. This is a 290 * {@link GuardedInvocationTransformer} that will get the final chance to 291 * modify the guarded invocation after it has been created by a component 292 * linker and before the dynamic linker links it into the call site. It is 293 * normally used to adapt the return value type of the invocation to the 294 * type of the call site. When not set explicitly, a default pre-link 295 * transformer will be used that simply calls 296 * {@link GuardedInvocation#asType(LinkerServices, MethodType)}. Customized 297 * pre-link transformers are rarely needed; they are mostly used as a 298 * building block for implementing advanced techniques such as code 299 * deoptimization strategies. 300 * @param prelinkTransformer the pre-link transformer for the dynamic 301 * linker. Can be null to have the factory use the default transformer. 302 */ 303 public void setPrelinkTransformer(final GuardedInvocationTransformer prelinkTransformer) { 304 this.prelinkTransformer = prelinkTransformer; 305 } 306 307 /** 308 * Sets an object representing the conversion strategy for automatic type 309 * conversions. After 310 * {@link LinkerServices#asType(MethodHandle, MethodType)} has applied all 311 * custom conversions to a method handle, it still needs to effect 312 * {@link TypeUtilities#isMethodInvocationConvertible(Class, Class) method 313 * invocation conversions} that can usually be automatically applied as per 314 * {@link MethodHandle#asType(MethodType)}. However, sometimes language 315 * runtimes will want to customize even those conversions for their own call 316 * sites. A typical example is allowing unboxing of null return values, 317 * which is by default prohibited by ordinary 318 * {@code MethodHandles.asType()}. In this case, a language runtime can 319 * install its own custom automatic conversion strategy, that can deal with 320 * null values. Note that when the strategy's 321 * {@link MethodTypeConversionStrategy#asType(MethodHandle, MethodType)} 322 * is invoked, the custom language conversions will already have been 323 * applied to the method handle, so by design the difference between the 324 * handle's current method type and the desired final type will always only 325 * be ones that can be subjected to method invocation conversions. The 326 * strategy also doesn't need to invoke a final 327 * {@code MethodHandle.asType()} as that will be done internally as the 328 * final step. 329 * @param autoConversionStrategy the strategy for applying method invocation 330 * conversions for the linker created by this factory. Can be null for no 331 * custom strategy. 332 */ 333 public void setAutoConversionStrategy(final MethodTypeConversionStrategy autoConversionStrategy) { 334 this.autoConversionStrategy = autoConversionStrategy; 335 } 336 337 /** 338 * Sets a method handle transformer that is supposed to act as the 339 * implementation of 340 * {@link LinkerServices#filterInternalObjects(MethodHandle)} for linker 341 * services of dynamic linkers created by this factory. Some language 342 * runtimes can have internal objects that should not escape their scope. 343 * They can add a transformer here that will modify the method handle so 344 * that any parameters that can receive potentially internal language 345 * runtime objects will have a filter added on them to prevent them from 346 * escaping, potentially by wrapping them. The transformer can also 347 * potentially add an unwrapping filter to the return value. 348 * {@link DefaultInternalObjectFilter} is provided as a convenience class 349 * for easily creating such filtering transformers. 350 * @param internalObjectsFilter a method handle transformer filtering out 351 * internal objects, or null. 352 */ 353 public void setInternalObjectsFilter(final MethodHandleTransformer internalObjectsFilter) { 354 this.internalObjectsFilter = internalObjectsFilter; 355 } 356 357 /** 358 * Creates a new dynamic linker based on the current configuration. This 359 * method can be invoked more than once to create multiple dynamic linkers. 360 * Automatically discovered linkers are newly instantiated on every 361 * invocation of this method. It is allowed to change the factory's 362 * configuration between invocations. The method is not thread safe. After 363 * invocation, callers can invoke {@link #getAutoLoadingErrors()} to 364 * retrieve a list of {@link ServiceConfigurationError}s that occurred while 365 * trying to load automatically discovered linkers. These are never thrown 366 * from the call to this method as it makes every effort to recover from 367 * them and ignore the failing linkers. 368 * @return the new dynamic Linker 369 */ 370 public DynamicLinker createLinker() { 371 // Treat nulls appropriately 372 if(prioritizedLinkers == null) { 373 prioritizedLinkers = Collections.emptyList(); 374 } 375 if(fallbackLinkers == null) { 376 fallbackLinkers = Collections.singletonList(new BeansLinker()); 377 } 378 379 // Gather classes of all precreated (prioritized and fallback) linkers. 380 // We'll filter out any discovered linkers of the same class. 381 final Set<Class<? extends GuardingDynamicLinker>> knownLinkerClasses = 382 new HashSet<>(); 383 addClasses(knownLinkerClasses, prioritizedLinkers); 384 addClasses(knownLinkerClasses, fallbackLinkers); 385 386 final List<GuardingDynamicLinker> discovered = discoverAutoLoadLinkers(); 387 // Now, concatenate ... 388 final List<GuardingDynamicLinker> linkers = 389 new ArrayList<>(prioritizedLinkers.size() + discovered.size() 390 + fallbackLinkers.size()); 391 // ... prioritized linkers, ... 392 linkers.addAll(prioritizedLinkers); 393 // ... filtered discovered linkers, ... 394 for(final GuardingDynamicLinker linker: discovered) { 395 if(!knownLinkerClasses.contains(linker.getClass())) { 396 linkers.add(linker); 397 } 398 } 399 // ... and finally fallback linkers. 400 linkers.addAll(fallbackLinkers); 401 final List<GuardingDynamicLinker> optimized = CompositeTypeBasedGuardingDynamicLinker.optimize(linkers); 402 final GuardingDynamicLinker composite; 403 switch(linkers.size()) { 404 case 0: { 405 composite = (r, s) -> null; // linker that can't link anything 406 break; 407 } 408 case 1: { 409 composite = optimized.get(0); 410 break; 411 } 412 default: { 413 composite = new CompositeGuardingDynamicLinker(optimized); 414 break; 415 } 416 } 417 418 final List<GuardingTypeConverterFactory> typeConverters = new LinkedList<>(); 419 for(final GuardingDynamicLinker linker: linkers) { 420 if(linker instanceof GuardingTypeConverterFactory) { 421 typeConverters.add((GuardingTypeConverterFactory)linker); 422 } 423 } 424 425 if(prelinkTransformer == null) { 426 prelinkTransformer = (inv, request, linkerServices) -> inv.asType(linkerServices, request.getCallSiteDescriptor().getMethodType()); 427 } 428 429 return new DynamicLinker(new LinkerServicesImpl(new TypeConverterFactory(typeConverters, 430 autoConversionStrategy), composite, internalObjectsFilter), prelinkTransformer, 431 syncOnRelink, unstableRelinkThreshold); 432 } 433 434 /** 435 * Returns a list of {@link ServiceConfigurationError}s that were 436 * encountered while loading automatically discovered linkers during the 437 * last invocation of {@link #createLinker()}. They can be any non-Dynalink 438 * specific service configuration issues, as well as some Dynalink-specific 439 * errors when an exporter that the factory tried to automatically load: 440 * <ul> 441 * <li>did not have the runtime permission named 442 * {@link GuardingDynamicLinkerExporter#AUTOLOAD_PERMISSION_NAME} in a 443 * system with a security manager, or</li> 444 * <li>returned null from {@link GuardingDynamicLinkerExporter#get()}, or</li> 445 * <li>the list returned from {@link GuardingDynamicLinkerExporter#get()} 446 * had a null element.</li> 447 * </ul> 448 * @return an immutable list of encountered 449 * {@link ServiceConfigurationError}s. Can be empty. 450 */ 451 public List<ServiceConfigurationError> getAutoLoadingErrors() { 452 return Collections.unmodifiableList(autoLoadingErrors); 453 } 454 455 private List<GuardingDynamicLinker> discoverAutoLoadLinkers() { 456 autoLoadingErrors = new LinkedList<>(); 457 final ClassLoader effectiveClassLoader = classLoaderExplicitlySet ? classLoader : getThreadContextClassLoader(); 458 final List<GuardingDynamicLinker> discovered = new LinkedList<>(); 459 try { 460 final ServiceLoader<GuardingDynamicLinkerExporter> linkerLoader = 461 AccessController.doPrivileged((PrivilegedAction<ServiceLoader<GuardingDynamicLinkerExporter>>)()-> { 462 if (effectiveClassLoader == null) { 463 return ServiceLoader.loadInstalled(GuardingDynamicLinkerExporter.class); 464 } 465 return ServiceLoader.load(GuardingDynamicLinkerExporter.class, effectiveClassLoader); 466 }); 467 468 for(final Iterator<GuardingDynamicLinkerExporter> it = linkerLoader.iterator(); it.hasNext();) { 469 try { 470 final GuardingDynamicLinkerExporter autoLoader = it.next(); 471 try { 472 discovered.addAll(requireNonNullElements( 473 Objects.requireNonNull(autoLoader.get(), 474 ()->(autoLoader.getClass().getName() + " returned null from get()")), 475 ()->(autoLoader.getClass().getName() + " returned a list with at least one null element"))); 476 } catch (final ServiceConfigurationError|VirtualMachineError e) { 477 // Don't wrap a SCE in another SCE. Also, don't ignore 478 // any VME (e.g. StackOverflowError or OutOfMemoryError). 479 throw e; 480 } catch (final Throwable t) { 481 throw new ServiceConfigurationError(t.getMessage(), t); 482 } 483 } catch (final ServiceConfigurationError e) { 484 // Catch SCE with an individual exporter, carry on with it.hasNext(). 485 autoLoadingErrors.add(e); 486 } 487 } 488 } catch (final ServiceConfigurationError e) { 489 // Catch a top-level SCE; one either in ServiceLoader.load(), 490 // ServiceLoader.iterator(), or Iterator.hasNext(). 491 autoLoadingErrors.add(e); 492 } 493 return discovered; 494 } 495 496 private static ClassLoader getThreadContextClassLoader() { 497 return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() { 498 @Override 499 public ClassLoader run() { 500 return Thread.currentThread().getContextClassLoader(); 501 } 502 }, GET_CLASS_LOADER_CONTEXT); 503 } 504 505 private static void addClasses(final Set<Class<? extends GuardingDynamicLinker>> knownLinkerClasses, 506 final List<? extends GuardingDynamicLinker> linkers) { 507 for(final GuardingDynamicLinker linker: linkers) { 508 knownLinkerClasses.add(linker.getClass()); 509 } 510 } 511 512 private static <T> List<T> copyListRequireNonNullElements(final List<T> list) { 513 if (list == null) { 514 return null; 515 } 516 return new ArrayList<>(requireNonNullElements(list, ()->"List has at least one null element")); 517 } 518 519 private static <T> List<T> requireNonNullElements(final List<T> list, final Supplier<String> msgSupplier) { 520 for(final T t: list) { 521 Objects.requireNonNull(t, msgSupplier); 522 } 523 return list; 524 } 525 526} 527