/* * Copyright (c) 2008, 2009, 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. */ package java.dyn; import java.lang.annotation.Annotation; import java.dyn.MethodHandles.Lookup; import java.util.WeakHashMap; import sun.dyn.Access; import sun.dyn.MethodHandleImpl; import sun.reflect.Reflection; import static sun.dyn.util.VerifyAccess.checkBootstrapPrivilege; import static sun.dyn.MemberName.newIllegalArgumentException; /** * This class consists exclusively of static methods that control * the linkage of {@code invokedynamic} instructions, and specifically * their reification as {@link CallSite} objects. * @author John Rose, JSR 292 EG */ public class Linkage { private static final Access IMPL_TOKEN = Access.getToken(); private Linkage() {} // do not instantiate /** * PROVISIONAL API, WORK IN PROGRESS: * Register a bootstrap method to use when linking dynamic call sites within * a given caller class. *

* A bootstrap method must be a method handle with a return type of {@link CallSite} * and the following arguments: *

* (TBD: The final argument type may be missing from the method handle's type. * Additional arguments may be added in the future.) * The bootstrap method acts as a factory method which accepts the given arguments * and returns a {@code CallSite} object (possibly of a subclass of {@code CallSite}). *

* The registration must take place exactly once, either before the class has begun * being initialized, or from within the class's static initializer. * Registration will fail with an exception if any of the following conditions hold: *

* Because of these rules, a class may install its own bootstrap method in * a static initializer. * @param callerClass a class that may have {@code invokedynamic} sites * @param bootstrapMethod the method to use to bootstrap all such sites * @exception IllegalArgumentException if the class argument is null or * a primitive class, or if the bootstrap method is the wrong type * @exception IllegalStateException if the class already has a bootstrap * method, or if the its static initializer has already run * or is already running in another thread * @exception SecurityException if there is a security manager installed, * and a {@link LinkagePermission} check fails for "registerBootstrapMethod" */ public static void registerBootstrapMethod(Class callerClass, MethodHandle bootstrapMethod) { Class callc = Reflection.getCallerClass(2); checkBootstrapPrivilege(callc, callerClass, "registerBootstrapMethod"); checkBSM(bootstrapMethod); MethodHandleImpl.registerBootstrap(IMPL_TOKEN, callerClass, bootstrapMethod); } static private void checkBSM(MethodHandle mh) { if (mh == null) throw newIllegalArgumentException("null bootstrap method"); if (mh.type() == BOOTSTRAP_METHOD_TYPE_2) // For now, always pass an empty array for the Annotations argument mh = MethodHandles.insertArguments(mh, BOOTSTRAP_METHOD_TYPE_2.parameterCount()-1, (Object)NO_ANNOTATIONS); if (mh.type() == BOOTSTRAP_METHOD_TYPE) return; throw new WrongMethodTypeException(mh.toString()); } static private final Annotation[] NO_ANNOTATIONS = { }; /** * PROVISIONAL API, WORK IN PROGRESS: * Simplified version of {@code registerBootstrapMethod} for self-registration, * to be called from a static initializer. * Finds a static method of the required type in the * given runtime class, and installs it on the caller class. * @throws NoSuchMethodException if there is no such method * @throws IllegalStateException if the caller class's static initializer * has already run, or is already running in another thread */ public static void registerBootstrapMethod(Class runtime, String name) { Class callerClass = Reflection.getCallerClass(2); registerBootstrapMethodLookup(callerClass, runtime, name); } /** * PROVISIONAL API, WORK IN PROGRESS: * Simplified version of {@code registerBootstrapMethod} for self-registration, * to be called from a static initializer. * Finds a static method of the required type in the * caller class itself, and installs it on the caller class. * @throws IllegalArgumentException if there is no such method * @throws IllegalStateException if the caller class's static initializer * has already run, or is already running in another thread */ public static void registerBootstrapMethod(String name) { Class callerClass = Reflection.getCallerClass(2); registerBootstrapMethodLookup(callerClass, callerClass, name); } private static void registerBootstrapMethodLookup(Class callerClass, Class runtime, String name) { Lookup lookup = new Lookup(IMPL_TOKEN, callerClass); MethodHandle bootstrapMethod; // Try both types. TBD try { bootstrapMethod = lookup.findStatic(runtime, name, BOOTSTRAP_METHOD_TYPE_2); } catch (NoAccessException ex) { bootstrapMethod = null; } if (bootstrapMethod == null) { try { bootstrapMethod = lookup.findStatic(runtime, name, BOOTSTRAP_METHOD_TYPE); } catch (NoAccessException ex) { throw new IllegalArgumentException("no such bootstrap method in "+runtime+": "+name, ex); } } checkBSM(bootstrapMethod); MethodHandleImpl.registerBootstrap(IMPL_TOKEN, callerClass, bootstrapMethod); } /** * PROVISIONAL API, WORK IN PROGRESS: * Report the bootstrap method registered for a given caller class. * Returns null if the class has never yet registered a bootstrap method. * Only callers privileged to set the bootstrap method may inquire * about it, because a bootstrap method is potentially a back-door entry * point into its class. * @exception IllegalArgumentException if the argument is null or * a primitive class * @exception SecurityException if there is a security manager installed, * and the immediate caller of this method is not in the same * package as the caller class * and a {@link LinkagePermission} check fails for "getBootstrapMethod" */ public static MethodHandle getBootstrapMethod(Class callerClass) { Class callc = Reflection.getCallerClass(2); checkBootstrapPrivilege(callc, callerClass, "getBootstrapMethod"); return MethodHandleImpl.getBootstrap(IMPL_TOKEN, callerClass); } /** * PROVISIONAL API, WORK IN PROGRESS: * The type of any bootstrap method is a three-argument method * {@code (Class, String, MethodType)} returning a {@code CallSite}. */ public static final MethodType BOOTSTRAP_METHOD_TYPE = MethodType.methodType(CallSite.class, Class.class, String.class, MethodType.class); static final MethodType BOOTSTRAP_METHOD_TYPE_2 = MethodType.methodType(CallSite.class, Class.class, String.class, MethodType.class, Annotation[].class); /** * PROVISIONAL API, WORK IN PROGRESS: * Invalidate all invokedynamic call sites everywhere. *

* When this method returns, every invokedynamic instruction * will invoke its bootstrap method on next call. *

* It is unspecified whether call sites already known to the Java * code will continue to be associated with invokedynamic * instructions. If any call site is still so associated, its * {@link CallSite#getTarget()} method is guaranteed to return null * the invalidation operation completes. *

* Invalidation operations are likely to be slow. Use them sparingly. */ public static Object invalidateAll() { SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkPermission(new LinkagePermission("invalidateAll")); } throw new UnsupportedOperationException("NYI"); } /** * PROVISIONAL API, WORK IN PROGRESS: * Invalidate all {@code invokedynamic} call sites in the bytecodes * of any methods of the given class. *

* When this method returns, every matching invokedynamic * instruction will invoke its bootstrap method on next call. *

* For additional semantics of call site invalidation, * see {@link #invalidateAll()}. */ public static Object invalidateCallerClass(Class callerClass) { SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkPermission(new LinkagePermission("invalidateAll", callerClass)); } throw new UnsupportedOperationException("NYI"); } }