1 /*
   2  * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
  22  * CA 95054 USA or visit www.sun.com if you need additional information or
  23  * have any questions.
  24  */
  25 
  26 package java.dyn;
  27 
  28 import impl.java.dyn.util.MethodHandleInvoker;
  29 import java.util.WeakHashMap;
  30 import sun.reflect.Reflection;
  31 
  32 /**
  33  * Static methods which control the linkage of invokedynamic call sites.
  34  * @author John Rose, JSR 292 EG
  35  */
  36 public class Linkage {
  37     private Linkage() {}  // do not instantiate
  38 
  39     /**
  40      * Register a bootstrap method for use for a given caller class.
  41      * The method handle must be of a type equivalent to {@link Linkage#bootstrapInvokeDynamic}.
  42      * <p>
  43      * The operation will fail with an exception if any of the following conditions hold:
  44      * <ul>
  45      * <li>The caller of this method is in a different package than the {@code callerClass},
  46      *     and there is a security manager, and its {@code checkPermission} call throws
  47      *     when passed {@link LinkagePermission}("registerBootstrapMethod",callerClass).
  48      * <li>The given class already has a bootstrap method, either from an embedded
  49      *     {@code BootstrapInvokeDynamic} classfile attribute, or from a previous
  50      *     call to this method.
  51      * <li>The given class is already fully initialized.
  52      * <li>The given class is in the process of initialization, in another thread.
  53      * </ul>
  54      * Because of these rules, a class may install its own bootstrap method in
  55      * a static initializer.
  56      */
  57     public static
  58     void registerBootstrapMethod(Class callerClass, MethodHandle mh) {
  59         Class callc = Reflection.getCallerClass(2);
  60         checkPackagePrivilege(callc, callerClass, "registerBootstrapMethod");
  61         if (mh != null && mh.type() != BOOTSTRAP_METHOD_TYPE)
  62             throw new WrongMethodTypeException(mh.type().toString());
  63         synchronized (bootstrapMethods) {
  64             if (bootstrapMethods.containsKey(callerClass))
  65                 throw new IllegalStateException("bootstrap method already declared in "+callerClass);
  66             bootstrapMethods.put(callerClass, mh);
  67         }
  68     }
  69     
  70     /**
  71      * Report the bootstrap method registered for a given class.
  72      * Returns null if the class has never yet registered a bootstrap method,
  73      * or if the class has explicitly registered a null bootstrap method.
  74      * Only callers privileged to set the bootstrap method may inquire
  75      * about it, because a bootstrap method is potentially a back-door entry
  76      * points to its class.
  77      */
  78     public static
  79     MethodHandle getBootstrapMethod(Class callerClass) {
  80         Class callc = Reflection.getCallerClass(2);
  81         checkPackagePrivilege(callc, callerClass, "registerBootstrapMethod");
  82         synchronized (bootstrapMethods) {
  83             return bootstrapMethods.get(callerClass);
  84         }
  85     }
  86 
  87     /** The type of any bootstrap method is (CallSite,Object...)Object.
  88      *  The varargs marker is required.
  89      */
  90     public static final MethodType BOOTSTRAP_METHOD_TYPE
  91             = MethodType.make(Object.class,
  92                               CallSite.class, Object[].class).changeVarArgs(true);
  93 
  94     private static MethodHandleInvoker bootstrapMethodInvoker;
  95 
  96     private static final WeakHashMap<Class, MethodHandle> bootstrapMethods =
  97             new WeakHashMap<Class, MethodHandle>();
  98 
  99     /** Determine if the caller class has declared or registered its own bootstrap method.
 100      *  If so, delegate this call to it.  Otherwise, throw an IncompatibleClassChangeError.
 101      */
 102     public static
 103     Object bootstrapInvokeDynamic(CallSite site, Object... receiverAndArguments) {
 104         Class callerClass = site.callerClass();
 105         MethodHandle mh;
 106         synchronized (bootstrapMethods) {
 107             mh = bootstrapMethods.get(callerClass);
 108         }
 109         if (mh == null)
 110             throw new IllegalStateException("no bootstrap method declared in "+callerClass);
 111 
 112         System.out.println(site+": calling bootstrap "+mh);
 113         if (bootstrapMethodInvoker == null)
 114             bootstrapMethodInvoker = MethodHandleInvoker.make(BOOTSTRAP_METHOD_TYPE);
 115         return bootstrapMethodInvoker.invoke(mh, site, receiverAndArguments);
 116     }
 117 
 118     /**
 119      * Invalidate all <code>invokedynamic</code> call sites everywhere.
 120      * <p>
 121      * When this method returns, every <code>invokedynamic</code> instruction
 122      * will invoke its bootstrap method on next call.
 123      * <p>
 124      * It is unspecified whether call sites already known to the Java
 125      * code will continue to be associated with <code>invokedynamic</code>
 126      * instructions.  If any call site is still so associated, its
 127      * {@link CallSite#getTarget()} method is guaranteed to return null
 128      * the invalidation operation completes.
 129      * <p>
 130      * Invalidation operations are likely to be slow.  Use them sparingly.
 131      */
 132     public static
 133     Object invalidateAll() {
 134         SecurityManager security = System.getSecurityManager();
 135         if (security != null) {
 136             security.checkPermission(new LinkagePermission("invalidateAll"));
 137         }
 138         throw new UnsupportedOperationException("NYI");
 139     }
 140 
 141     /**
 142      * Invalidate all <code>invokedynamic</code> call sites associated
 143      * with the given class.
 144      * (These are exactly those sites which report the given class
 145      * via the {@link CallSite#callerClass()} method.)
 146      * <p>
 147      * When this method returns, every matching <code>invokedynamic</code>
 148      * instruction will invoke its bootstrap method on next call.
 149      * <p>
 150      * For additional semantics of call site invalidation,
 151      * see {@link #invalidateAll()}.
 152      */
 153     public static
 154     Object invalidateCallerClass(Class<?> callerClass) {
 155         SecurityManager security = System.getSecurityManager();
 156         if (security != null) {
 157             security.checkPermission(new LinkagePermission("invalidateAll", callerClass));
 158         }
 159         throw new UnsupportedOperationException("NYI");
 160     }
 161 
 162     /**
 163      * Ensure the requesting class have privileges to perform invokedynamic
 164      * linkage operations on subjectClass.  True if requestingClass is
 165      * null (meaning the request originates from the JVM) or if the
 166      * classes are in the same package and have consistent class loaders.
 167      * (The subject class loader must be identical with or be a child of
 168      * the requesting class loader.)
 169      * @param requestingClass
 170      * @param subjectClass
 171      * @return
 172      */
 173     static void checkPackagePrivilege(Class requestingClass, Class subjectClass,
 174                                     String permissionName) {
 175         if (requestingClass == null)  return;
 176         if (requestingClass == subjectClass)  return;
 177         SecurityManager security = System.getSecurityManager();
 178         if (security == null)  return;  // open season
 179         ClassLoader rcl = requestingClass.getClassLoader();
 180         ClassLoader scl = subjectClass.getClassLoader();
 181         if (isParent(rcl, scl)) {
 182             String rn = requestingClass.getName();
 183             if (rn.startsWith("java.dyn."))  return;
 184             String sn = subjectClass.getName();
 185             if (samePackage(rn, sn))  return;
 186         }
 187         security.checkPermission(new LinkagePermission(permissionName, requestingClass));
 188     }
 189     
 190     static
 191     MethodHandle findBootstrapMethod(Class callerClass, Class searchBootstrapClass) {
 192         if (searchBootstrapClass != null)  throw new UnsupportedOperationException("NYI");
 193         MethodHandle mh = getBootstrapMethod(callerClass);
 194         System.out.println("reporting bootstrap method to JVM: "+mh);
 195         return mh;
 196     }
 197 
 198     private static boolean isParent(ClassLoader rcl, ClassLoader scl) {
 199         while (scl != null && scl != rcl)
 200             scl = scl.getParent();
 201         return (scl == rcl);
 202     }
 203 
 204     private static boolean samePackage(String rn, String sn) {
 205         assert((rn.indexOf('/') & sn.indexOf('/')) < 0);  // no bytecode names
 206         int lastDot  = rn.lastIndexOf('.');
 207         if (lastDot != sn.lastIndexOf('.'))  return false;
 208         return rn.startsWith(sn.substring(0, lastDot+1));
 209     }
 210 
 211 }