Linkage.java 10.2 KB
Newer Older
1
/*
2
 * Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved.
3 4 5 6
 * 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
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 12 13 14 15 16 17 18 19 20
 *
 * 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.
 *
21 22 23
 * 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.
24 25 26 27
 */

package java.dyn;

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

/**
37 38 39
 * This class consists exclusively of static methods that control
 * the linkage of {@code invokedynamic} instructions, and specifically
 * their reification as {@link CallSite} objects.
40 41 42
 * @author John Rose, JSR 292 EG
 */
public class Linkage {
43 44
    private static final Access IMPL_TOKEN = Access.getToken();

45 46 47
    private Linkage() {}  // do not instantiate

    /**
48
     * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
49 50 51 52 53 54 55 56 57 58 59
     * Register a <em>bootstrap method</em> to use when linking dynamic call sites within
     * a given caller class.
     * <p>
     * A bootstrap method must be a method handle with a return type of {@link CallSite}
     * and the following arguments:
     * <ul>
     * <li>the class containing the {@code invokedynamic} instruction, for which the bootstrap method was registered
     * <li>the name of the method being invoked (a {@link String})
     * <li>the type of the method being invoked (a {@link MethodType})
     * </ul>
     * The bootstrap method acts as a factory method which accepts the given arguments
60
     * and returns a {@code CallSite} object (possibly of a subclass of {@code CallSite}).
61
     * <p>
62 63 64
     * 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:
65
     * <ul>
66
     * <li>The immediate caller of this method is in a different package than the given caller class,
67 68
     *     and there is a security manager, and its {@code checkPermission} call throws
     *     when passed {@link LinkagePermission}("registerBootstrapMethod",callerClass).
69 70 71
     * <li>The given caller class already has a bootstrap method registered.
     * <li>The given caller class is already fully initialized.
     * <li>The given caller class is in the process of initialization, in another thread.
72 73 74
     * </ul>
     * Because of these rules, a class may install its own bootstrap method in
     * a static initializer.
75 76
     * @param callerClass a class that may have {@code invokedynamic} sites
     * @param bootstrapMethod the method to use to bootstrap all such sites
77 78 79 80 81 82 83
     * @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"
84
     * @deprecated Use @{@link BootstrapMethod} annotations instead
85 86
     */
    public static
87
    void registerBootstrapMethod(Class callerClass, MethodHandle bootstrapMethod) {
88 89
        Class callc = Reflection.getCallerClass(2);
        checkBootstrapPrivilege(callc, callerClass, "registerBootstrapMethod");
90
        checkBSM(bootstrapMethod);
91
        MethodHandleImpl.registerBootstrap(IMPL_TOKEN, callerClass, bootstrapMethod);
92 93
    }

94 95 96 97
    static private void checkBSM(MethodHandle mh) {
        if (mh == null)  throw newIllegalArgumentException("null bootstrap method");
        if (mh.type() == BOOTSTRAP_METHOD_TYPE)  return;
        throw new WrongMethodTypeException(mh.toString());
98 99 100
    }

    /**
101
     * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
102
     * Simplified version of {@code registerBootstrapMethod} for self-registration,
103
     * to be called from a static initializer.
104
     * Finds a static method of the required type in the
105 106 107 108
     * 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
109
     * @deprecated Use @{@link BootstrapMethod} annotations instead
110 111 112
     */
    public static
    void registerBootstrapMethod(Class<?> runtime, String name) {
113 114
        Class callerClass = Reflection.getCallerClass(2);
        registerBootstrapMethodLookup(callerClass, runtime, name);
115 116 117
    }

    /**
118
     * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
119
     * Simplified version of {@code registerBootstrapMethod} for self-registration,
120
     * to be called from a static initializer.
121
     * Finds a static method of the required type in the
122
     * caller class itself, and installs it on the caller class.
123
     * @throws IllegalArgumentException if there is no such method
124 125
     * @throws IllegalStateException if the caller class's static initializer
     *         has already run, or is already running in another thread
126
     * @deprecated Use @{@link BootstrapMethod} annotations instead
127 128 129
     */
    public static
    void registerBootstrapMethod(String name) {
130 131 132 133 134 135 136 137 138
        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 {
139
            bootstrapMethod = lookup.findStatic(runtime, name, BOOTSTRAP_METHOD_TYPE);
140
        } catch (NoAccessException ex) {
141
            throw new IllegalArgumentException("no such bootstrap method in "+runtime+": "+name, ex);
142
        }
143
        checkBSM(bootstrapMethod);
144
        MethodHandleImpl.registerBootstrap(IMPL_TOKEN, callerClass, bootstrapMethod);
145 146 147
    }

    /**
148
     * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
149
     * Report the bootstrap method registered for a given caller class.
150
     * Returns null if the class has never yet registered a bootstrap method.
151 152 153
     * 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.
154 155 156 157 158 159
     * @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"
160
     * @deprecated
161 162 163 164
     */
    public static
    MethodHandle getBootstrapMethod(Class callerClass) {
        Class callc = Reflection.getCallerClass(2);
165 166
        checkBootstrapPrivilege(callc, callerClass, "getBootstrapMethod");
        return MethodHandleImpl.getBootstrap(IMPL_TOKEN, callerClass);
167 168
    }

169 170 171 172
    /**
     * <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}.
173 174
     */
    public static final MethodType BOOTSTRAP_METHOD_TYPE
175 176
            = MethodType.methodType(CallSite.class,
                                    Class.class, String.class, MethodType.class);
177 178

    /**
179
     * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202
     * 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");
    }

    /**
203
     * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
204
     * Invalidate all {@code invokedynamic} call sites in the bytecodes
205
     * of any methods of the given class.
206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221
     * <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");
    }
}