Linkage.java 9.5 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
/*
 * 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;

28
import java.dyn.MethodHandles.Lookup;
29
import java.util.WeakHashMap;
30
import sun.dyn.Access;
31 32 33 34 35 36 37 38
import sun.reflect.Reflection;
import static sun.dyn.util.VerifyAccess.checkBootstrapPrivilege;

/**
 * Static methods which control the linkage of invokedynamic call sites.
 * @author John Rose, JSR 292 EG
 */
public class Linkage {
39 40
    private static final Access IMPL_TOKEN = Access.getToken();

41 42 43
    private Linkage() {}  // do not instantiate

    /**
44 45 46 47 48 49
     * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
     * Register a <em>bootstrap method</em> to use when linking a given caller class.
     * It must be a method handle of a type equivalent to {@link CallSite#CallSite}.
     * In other words, it must act as a factory method which accepts the arguments
     * to {@code CallSite}'s constructor (a class, a string, and a method type),
     * and returns a {@code CallSite} object (possibly of a subclass of {@code CallSite}).
50
     * <p>
51
     * The registration will fail with an {@code IllegalStateException} if any of the following conditions hold:
52 53 54 55
     * <ul>
     * <li>The caller of this method is in a different package than the {@code callerClass},
     *     and there is a security manager, and its {@code checkPermission} call throws
     *     when passed {@link LinkagePermission}("registerBootstrapMethod",callerClass).
56
     * <li>The given class already has a bootstrap method from a previous
57 58 59
     *     call to this method.
     * <li>The given class is already fully initialized.
     * <li>The given class is in the process of initialization, in another thread.
60 61
     * <li>The same {@code CallSite} object has already been returned from
     * a bootstrap method call to another {@code invokedynamic} call site.
62 63 64
     * </ul>
     * Because of these rules, a class may install its own bootstrap method in
     * a static initializer.
65 66
     * @param callerClass a class that may have {@code invokedynamic} sites
     * @param bootstrapMethod the method to use to bootstrap all such sites
67 68
     */
    public static
69
    void registerBootstrapMethod(Class callerClass, MethodHandle bootstrapMethod) {
70 71
        Class callc = Reflection.getCallerClass(2);
        checkBootstrapPrivilege(callc, callerClass, "registerBootstrapMethod");
72
        checkBSM(bootstrapMethod);
73 74 75
        synchronized (bootstrapMethods) {
            if (bootstrapMethods.containsKey(callerClass))
                throw new IllegalStateException("bootstrap method already declared in "+callerClass);
76
            bootstrapMethods.put(callerClass, bootstrapMethod);
77 78 79 80 81 82 83 84 85 86 87 88
        }
    }

    static void checkBSM(MethodHandle mh) {
        if (mh == null)  throw new IllegalArgumentException("null bootstrap method");
        if (mh.type() == OLD_BOOTSTRAP_METHOD_TYPE) // FIXME: delete at EDR/PFD
            throw new WrongMethodTypeException("bootstrap method must be a CallSite factory");
        if (mh.type() != BOOTSTRAP_METHOD_TYPE)
            throw new WrongMethodTypeException(mh.toString());
    }

    /**
89
     * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
90 91
     * Simplified version of registerBootstrapMethod for self-registration,
     * to be called from a static initializer.
92
     * Finds a static method of the required type in the
93 94 95 96 97 98
     * given class, and installs it on the caller.
     * @throws IllegalArgumentException if there is no such method
     */
    public static
    void registerBootstrapMethod(Class<?> runtime, String name) {
        Class callc = Reflection.getCallerClass(2);
99
        Lookup lookup = new Lookup(IMPL_TOKEN, callc);
100
        MethodHandle bootstrapMethod =
101
            lookup.findStatic(runtime, name, BOOTSTRAP_METHOD_TYPE);
102 103 104 105 106 107
        // FIXME: exception processing wrong here
        checkBSM(bootstrapMethod);
        Linkage.registerBootstrapMethod(callc, bootstrapMethod);
    }

    /**
108
     * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
109 110
     * Simplified version of registerBootstrapMethod for self-registration,
     * to be called from a static initializer.
111
     * Finds a static method of the required type in the
112 113 114 115 116 117
     * caller's class, and installs it on the caller.
     * @throws IllegalArgumentException if there is no such method
     */
    public static
    void registerBootstrapMethod(String name) {
        Class callc = Reflection.getCallerClass(2);
118
        Lookup lookup = new Lookup(IMPL_TOKEN, callc);
119
        MethodHandle bootstrapMethod =
120
            lookup.findStatic(callc, name, BOOTSTRAP_METHOD_TYPE);
121 122 123 124 125 126
        // FIXME: exception processing wrong here
        checkBSM(bootstrapMethod);
        Linkage.registerBootstrapMethod(callc, bootstrapMethod);
    }

    /**
127
     * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
128
     * Report the bootstrap method registered for a given class.
129
     * Returns null if the class has never yet registered a bootstrap method.
130 131 132 133 134 135 136 137 138 139 140 141 142
     * 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.
     */
    public static
    MethodHandle getBootstrapMethod(Class callerClass) {
        Class callc = Reflection.getCallerClass(2);
        checkBootstrapPrivilege(callc, callerClass, "registerBootstrapMethod");
        synchronized (bootstrapMethods) {
            return bootstrapMethods.get(callerClass);
        }
    }

143 144 145 146
    /**
     * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
     * The type of any bootstrap method is a three-argument method
     * {@code (Class, String, MethodType)} returning a {@code CallSite}.
147 148
     */
    public static final MethodType BOOTSTRAP_METHOD_TYPE
149 150
            = MethodType.methodType(CallSite.class,
                                    Class.class, String.class, MethodType.class);
151 152

    private static final MethodType OLD_BOOTSTRAP_METHOD_TYPE
153 154
            = MethodType.methodType(Object.class,
                                    CallSite.class, Object[].class);
155 156 157 158 159

    private static final WeakHashMap<Class, MethodHandle> bootstrapMethods =
            new WeakHashMap<Class, MethodHandle>();

    /**
160
     * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183
     * Invalidate all <code>invokedynamic</code> call sites everywhere.
     * <p>
     * When this method returns, every <code>invokedynamic</code> instruction
     * will invoke its bootstrap method on next call.
     * <p>
     * It is unspecified whether call sites already known to the Java
     * code will continue to be associated with <code>invokedynamic</code>
     * instructions.  If any call site is still so associated, its
     * {@link CallSite#getTarget()} method is guaranteed to return null
     * the invalidation operation completes.
     * <p>
     * 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");
    }

    /**
184
     * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
185 186
     * Invalidate all <code>invokedynamic</code> call sites in the bytecodes
     * of any methods of the given class.
187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218
     * (These are exactly those sites which report the given class
     * via the {@link CallSite#callerClass()} method.)
     * <p>
     * When this method returns, every matching <code>invokedynamic</code>
     * instruction will invoke its bootstrap method on next call.
     * <p>
     * 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");
    }

    private static Object doNotBootstrap(CallSite site, Object... arguments) {
        throw new UnsupportedOperationException("call site must not have null target: "+site);
    }

    private static final MethodHandle DO_NOT_BOOTSTRAP =
            MethodHandles.Lookup.IMPL_LOOKUP.findStatic(Linkage.class, "doNotBootstrap",
                OLD_BOOTSTRAP_METHOD_TYPE);

    // Up-call from the JVM.  Obsolete.  FIXME: Delete from VM then from here.
    static
    MethodHandle findBootstrapMethod(Class callerClass, Class searchBootstrapClass) {
        return DO_NOT_BOOTSTRAP;
    }
}