/* * Copyright 2008-2009 Sun Microsystems, Inc. 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. Sun designates this * particular file as subject to the "Classpath" exception as provided * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, * CA 95054 USA or visit www.sun.com if you need additional information or * have any questions. */ package java.dyn; import sun.dyn.util.MethodHandleInvoker; import java.util.WeakHashMap; import sun.reflect.Reflection; /** * Static methods which control the linkage of invokedynamic call sites. * @author John Rose, JSR 292 EG */ public class Linkage { private Linkage() {} // do not instantiate /** * Register a bootstrap method for use for a given caller class. * The method handle must be of a type equivalent to {@link Linkage#bootstrapInvokeDynamic}. *
* The operation will fail with an exception if any of the following conditions hold: *
* This routine, or an equivalent sequence of actions, is called from the * JVM when an {@code invokedynamic} instruction is executed * but its call site is unlinked (has a null target method). *
* This routine can be called from Java code whether or not the call site * currently has a target, and will invoke the bootstrap method regardless * of he call site's linkage state. *
* Although invoking the bootstrap method does not in and of itself cause * state change in the call site, the actions eventually performed by * the bootstrap method may include installed a new target on the call site. *
* Note that linkage state changes are individually atomic, but are not
* serialized in any way with respect to calls to the bootstrap method,
* or executions of the {@code invokedynamic} instruction. Therefore,
* an {@code invokedynamic} call site may be linked several times if
* several threads concurrently execute it in an unlinked state.
* It is up to the user-defined bootstrap method to make sure this
* race condition is resolved safely, either by performing linkage
* decisions under suitable locks (as the JVM does) or by ensuring
* that all racing threads come to the same conclusion, and independently
* install equivalent target methods.
*/
public static
Object bootstrapInvokeDynamic(CallSite site, Object... arguments) {
Class callerClass = site.callerClass();
MethodHandle mh;
synchronized (bootstrapMethods) {
mh = bootstrapMethods.get(callerClass);
}
if (mh == null)
throw new IllegalStateException("no bootstrap method declared in "+callerClass);
System.out.println(site+": calling bootstrap "+mh); // FIXME
if (bootstrapMethodInvoker == null)
bootstrapMethodInvoker = MethodHandleInvoker.make(BOOTSTRAP_METHOD_TYPE);
return bootstrapMethodInvoker.invoke(mh, site, arguments);
}
/**
* 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");
}
/**
* Invalidate all invokedynamic call sites associated
* with the given class.
* (These are exactly those sites which report the given class
* via the {@link CallSite#callerClass()} method.)
*
* 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"); } /** * Ensure the requesting class have privileges to perform invokedynamic * linkage operations on subjectClass. True if requestingClass is * null (meaning the request originates from the JVM) or if the * classes are in the same package and have consistent class loaders. * (The subject class loader must be identical with or be a child of * the requesting class loader.) * @param requestingClass * @param subjectClass */ // FIXME: factor this logic into sun.dyn.util.VerifyAccess static void checkPackagePrivilege(Class requestingClass, Class subjectClass, String permissionName) { if (requestingClass == null) return; if (requestingClass == subjectClass) return; SecurityManager security = System.getSecurityManager(); if (security == null) return; // open season ClassLoader rcl = requestingClass.getClassLoader(); ClassLoader scl = subjectClass.getClassLoader(); if (isParent(rcl, scl)) { String rn = requestingClass.getName(); if (rn.startsWith("java.dyn.")) return; String sn = subjectClass.getName(); if (samePackage(rn, sn)) return; } security.checkPermission(new LinkagePermission(permissionName, requestingClass)); } static MethodHandle findBootstrapMethod(Class callerClass, Class searchBootstrapClass) { if (searchBootstrapClass != null) throw new UnsupportedOperationException("NYI"); MethodHandle mh = getBootstrapMethod(callerClass); System.out.println("reporting bootstrap method to JVM: "+mh); //FIXME return mh; } private static boolean isParent(ClassLoader rcl, ClassLoader scl) { while (scl != null && scl != rcl) scl = scl.getParent(); return (scl == rcl); } private static boolean samePackage(String rn, String sn) { assert((rn.indexOf('/') & sn.indexOf('/')) < 0); // no bytecode names int lastDot = rn.lastIndexOf('.'); if (lastDot != sn.lastIndexOf('.')) return false; return rn.startsWith(sn.substring(0, lastDot+1)); } }