1/*
2 * Copyright (c) 2008, 2016, Oracle and/or its affiliates. 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.  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 * 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package java.lang.invoke;
27
28import static java.lang.invoke.MethodHandleStatics.*;
29import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
30
31import jdk.internal.vm.annotation.Stable;
32
33/**
34 * A {@code CallSite} is a holder for a variable {@link MethodHandle},
35 * which is called its {@code target}.
36 * An {@code invokedynamic} instruction linked to a {@code CallSite} delegates
37 * all calls to the site's current target.
38 * A {@code CallSite} may be associated with several {@code invokedynamic}
39 * instructions, or it may be "free floating", associated with none.
40 * In any case, it may be invoked through an associated method handle
41 * called its {@linkplain #dynamicInvoker dynamic invoker}.
42 * <p>
43 * {@code CallSite} is an abstract class which does not allow
44 * direct subclassing by users.  It has three immediate,
45 * concrete subclasses that may be either instantiated or subclassed.
46 * <ul>
47 * <li>If a mutable target is not required, an {@code invokedynamic} instruction
48 * may be permanently bound by means of a {@linkplain ConstantCallSite constant call site}.
49 * <li>If a mutable target is required which has volatile variable semantics,
50 * because updates to the target must be immediately and reliably witnessed by other threads,
51 * a {@linkplain VolatileCallSite volatile call site} may be used.
52 * <li>Otherwise, if a mutable target is required,
53 * a {@linkplain MutableCallSite mutable call site} may be used.
54 * </ul>
55 * <p>
56 * A non-constant call site may be <em>relinked</em> by changing its target.
57 * The new target must have the same {@linkplain MethodHandle#type() type}
58 * as the previous target.
59 * Thus, though a call site can be relinked to a series of
60 * successive targets, it cannot change its type.
61 * <p>
62 * Here is a sample use of call sites and bootstrap methods which links every
63 * dynamic call site to print its arguments:
64<blockquote><pre>{@code
65static void test() throws Throwable {
66    // THE FOLLOWING LINE IS PSEUDOCODE FOR A JVM INSTRUCTION
67    InvokeDynamic[#bootstrapDynamic].baz("baz arg", 2, 3.14);
68}
69private static void printArgs(Object... args) {
70  System.out.println(java.util.Arrays.deepToString(args));
71}
72private static final MethodHandle printArgs;
73static {
74  MethodHandles.Lookup lookup = MethodHandles.lookup();
75  Class thisClass = lookup.lookupClass();  // (who am I?)
76  printArgs = lookup.findStatic(thisClass,
77      "printArgs", MethodType.methodType(void.class, Object[].class));
78}
79private static CallSite bootstrapDynamic(MethodHandles.Lookup caller, String name, MethodType type) {
80  // ignore caller and name, but match the type:
81  return new ConstantCallSite(printArgs.asType(type));
82}
83}</pre></blockquote>
84 * @author John Rose, JSR 292 EG
85 * @since 1.7
86 */
87abstract
88public class CallSite {
89
90    // The actual payload of this call site:
91    /*package-private*/
92    MethodHandle target;    // Note: This field is known to the JVM.  Do not change.
93
94    /**
95     * Make a blank call site object with the given method type.
96     * An initial target method is supplied which will throw
97     * an {@link IllegalStateException} if called.
98     * <p>
99     * Before this {@code CallSite} object is returned from a bootstrap method,
100     * it is usually provided with a more useful target method,
101     * via a call to {@link CallSite#setTarget(MethodHandle) setTarget}.
102     * @throws NullPointerException if the proposed type is null
103     */
104    /*package-private*/
105    CallSite(MethodType type) {
106        target = makeUninitializedCallSite(type);
107    }
108
109    /**
110     * Make a call site object equipped with an initial target method handle.
111     * @param target the method handle which will be the initial target of the call site
112     * @throws NullPointerException if the proposed target is null
113     */
114    /*package-private*/
115    CallSite(MethodHandle target) {
116        target.type();  // null check
117        this.target = target;
118    }
119
120    /**
121     * Make a call site object equipped with an initial target method handle.
122     * @param targetType the desired type of the call site
123     * @param createTargetHook a hook which will bind the call site to the target method handle
124     * @throws WrongMethodTypeException if the hook cannot be invoked on the required arguments,
125     *         or if the target returned by the hook is not of the given {@code targetType}
126     * @throws NullPointerException if the hook returns a null value
127     * @throws ClassCastException if the hook returns something other than a {@code MethodHandle}
128     * @throws Throwable anything else thrown by the hook function
129     */
130    /*package-private*/
131    CallSite(MethodType targetType, MethodHandle createTargetHook) throws Throwable {
132        this(targetType);
133        ConstantCallSite selfCCS = (ConstantCallSite) this;
134        MethodHandle boundTarget = (MethodHandle) createTargetHook.invokeWithArguments(selfCCS);
135        checkTargetChange(this.target, boundTarget);
136        this.target = boundTarget;
137    }
138
139    /**
140     * {@code CallSite} dependency context.
141     * JVM uses CallSite.context to store nmethod dependencies on the call site target.
142     */
143    private final MethodHandleNatives.CallSiteContext context = MethodHandleNatives.CallSiteContext.make(this);
144
145    /**
146     * Returns the type of this call site's target.
147     * Although targets may change, any call site's type is permanent, and can never change to an unequal type.
148     * The {@code setTarget} method enforces this invariant by refusing any new target that does
149     * not have the previous target's type.
150     * @return the type of the current target, which is also the type of any future target
151     */
152    public MethodType type() {
153        // warning:  do not call getTarget here, because CCS.getTarget can throw IllegalStateException
154        return target.type();
155    }
156
157    /**
158     * Returns the target method of the call site, according to the
159     * behavior defined by this call site's specific class.
160     * The immediate subclasses of {@code CallSite} document the
161     * class-specific behaviors of this method.
162     *
163     * @return the current linkage state of the call site, its target method handle
164     * @see ConstantCallSite
165     * @see VolatileCallSite
166     * @see #setTarget
167     * @see ConstantCallSite#getTarget
168     * @see MutableCallSite#getTarget
169     * @see VolatileCallSite#getTarget
170     */
171    public abstract MethodHandle getTarget();
172
173    /**
174     * Updates the target method of this call site, according to the
175     * behavior defined by this call site's specific class.
176     * The immediate subclasses of {@code CallSite} document the
177     * class-specific behaviors of this method.
178     * <p>
179     * The type of the new target must be {@linkplain MethodType#equals equal to}
180     * the type of the old target.
181     *
182     * @param newTarget the new target
183     * @throws NullPointerException if the proposed new target is null
184     * @throws WrongMethodTypeException if the proposed new target
185     *         has a method type that differs from the previous target
186     * @see CallSite#getTarget
187     * @see ConstantCallSite#setTarget
188     * @see MutableCallSite#setTarget
189     * @see VolatileCallSite#setTarget
190     */
191    public abstract void setTarget(MethodHandle newTarget);
192
193    void checkTargetChange(MethodHandle oldTarget, MethodHandle newTarget) {
194        MethodType oldType = oldTarget.type();
195        MethodType newType = newTarget.type();  // null check!
196        if (!newType.equals(oldType))
197            throw wrongTargetType(newTarget, oldType);
198    }
199
200    private static WrongMethodTypeException wrongTargetType(MethodHandle target, MethodType type) {
201        return new WrongMethodTypeException(String.valueOf(target)+" should be of type "+type);
202    }
203
204    /**
205     * Produces a method handle equivalent to an invokedynamic instruction
206     * which has been linked to this call site.
207     * <p>
208     * This method is equivalent to the following code:
209     * <blockquote><pre>{@code
210     * MethodHandle getTarget, invoker, result;
211     * getTarget = MethodHandles.publicLookup().bind(this, "getTarget", MethodType.methodType(MethodHandle.class));
212     * invoker = MethodHandles.exactInvoker(this.type());
213     * result = MethodHandles.foldArguments(invoker, getTarget)
214     * }</pre></blockquote>
215     *
216     * @return a method handle which always invokes this call site's current target
217     */
218    public abstract MethodHandle dynamicInvoker();
219
220    /*non-public*/ MethodHandle makeDynamicInvoker() {
221        MethodHandle getTarget = getTargetHandle().bindArgumentL(0, this);
222        MethodHandle invoker = MethodHandles.exactInvoker(this.type());
223        return MethodHandles.foldArguments(invoker, getTarget);
224    }
225
226    private static @Stable MethodHandle GET_TARGET;
227    private static MethodHandle getTargetHandle() {
228        MethodHandle handle = GET_TARGET;
229        if (handle != null) {
230            return handle;
231        }
232        try {
233            return GET_TARGET = IMPL_LOOKUP.
234                    findVirtual(CallSite.class, "getTarget",
235                                MethodType.methodType(MethodHandle.class));
236        } catch (ReflectiveOperationException e) {
237            throw newInternalError(e);
238        }
239    }
240
241    private static @Stable MethodHandle THROW_UCS;
242    private static MethodHandle uninitializedCallSiteHandle() {
243        MethodHandle handle = THROW_UCS;
244        if (handle != null) {
245            return handle;
246        }
247        try {
248            return THROW_UCS = IMPL_LOOKUP.
249                findStatic(CallSite.class, "uninitializedCallSite",
250                           MethodType.methodType(Object.class, Object[].class));
251        } catch (ReflectiveOperationException e) {
252            throw newInternalError(e);
253        }
254    }
255
256    /** This guy is rolled into the default target if a MethodType is supplied to the constructor. */
257    private static Object uninitializedCallSite(Object... ignore) {
258        throw new IllegalStateException("uninitialized call site");
259    }
260
261    private MethodHandle makeUninitializedCallSite(MethodType targetType) {
262        MethodType basicType = targetType.basicType();
263        MethodHandle invoker = basicType.form().cachedMethodHandle(MethodTypeForm.MH_UNINIT_CS);
264        if (invoker == null) {
265            invoker = uninitializedCallSiteHandle().asType(basicType);
266            invoker = basicType.form().setCachedMethodHandle(MethodTypeForm.MH_UNINIT_CS, invoker);
267        }
268        // unchecked view is OK since no values will be received or returned
269        return invoker.viewAsType(targetType, false);
270    }
271
272    // unsafe stuff:
273    private static @Stable long TARGET_OFFSET;
274    private static long getTargetOffset() {
275        long offset = TARGET_OFFSET;
276        if (offset > 0) {
277            return offset;
278        }
279        offset = TARGET_OFFSET = UNSAFE.objectFieldOffset(CallSite.class, "target");
280        assert(offset > 0);
281        return offset;
282    }
283
284    /*package-private*/
285    void setTargetNormal(MethodHandle newTarget) {
286        MethodHandleNatives.setCallSiteTargetNormal(this, newTarget);
287    }
288    /*package-private*/
289    MethodHandle getTargetVolatile() {
290        return (MethodHandle) UNSAFE.getObjectVolatile(this, getTargetOffset());
291    }
292    /*package-private*/
293    void setTargetVolatile(MethodHandle newTarget) {
294        MethodHandleNatives.setCallSiteTargetVolatile(this, newTarget);
295    }
296
297    // this implements the upcall from the JVM, MethodHandleNatives.linkCallSite:
298    static CallSite makeSite(MethodHandle bootstrapMethod,
299                             // Callee information:
300                             String name, MethodType type,
301                             // Extra arguments for BSM, if any:
302                             Object info,
303                             // Caller information:
304                             Class<?> callerClass) {
305        MethodHandles.Lookup caller = IMPL_LOOKUP.in(callerClass);
306        CallSite site;
307        try {
308            Object binding;
309            info = maybeReBox(info);
310            if (info == null) {
311                binding = bootstrapMethod.invoke(caller, name, type);
312            } else if (!info.getClass().isArray()) {
313                binding = bootstrapMethod.invoke(caller, name, type, info);
314            } else {
315                Object[] argv = (Object[]) info;
316                maybeReBoxElements(argv);
317                switch (argv.length) {
318                    case 0:
319                        binding = bootstrapMethod.invoke(caller, name, type);
320                        break;
321                    case 1:
322                        binding = bootstrapMethod.invoke(caller, name, type,
323                                                         argv[0]);
324                        break;
325                    case 2:
326                        binding = bootstrapMethod.invoke(caller, name, type,
327                                                         argv[0], argv[1]);
328                        break;
329                    case 3:
330                        binding = bootstrapMethod.invoke(caller, name, type,
331                                                         argv[0], argv[1], argv[2]);
332                        break;
333                    case 4:
334                        binding = bootstrapMethod.invoke(caller, name, type,
335                                                         argv[0], argv[1], argv[2], argv[3]);
336                        break;
337                    case 5:
338                        binding = bootstrapMethod.invoke(caller, name, type,
339                                                         argv[0], argv[1], argv[2], argv[3], argv[4]);
340                        break;
341                    case 6:
342                        binding = bootstrapMethod.invoke(caller, name, type,
343                                                         argv[0], argv[1], argv[2], argv[3], argv[4], argv[5]);
344                        break;
345                    default:
346                        final int NON_SPREAD_ARG_COUNT = 3;  // (caller, name, type)
347                        if (NON_SPREAD_ARG_COUNT + argv.length > MethodType.MAX_MH_ARITY)
348                            throw new BootstrapMethodError("too many bootstrap method arguments");
349
350                        MethodType invocationType = MethodType.genericMethodType(NON_SPREAD_ARG_COUNT + argv.length);
351                        MethodHandle typedBSM = bootstrapMethod.asType(invocationType);
352                        MethodHandle spreader = invocationType.invokers().spreadInvoker(NON_SPREAD_ARG_COUNT);
353                        binding = spreader.invokeExact(typedBSM, (Object) caller, (Object) name, (Object) type, argv);
354                }
355            }
356            if (binding instanceof CallSite) {
357                site = (CallSite) binding;
358            } else {
359                // See the "Linking Exceptions" section for the invokedynamic
360                // instruction in JVMS 6.5.
361                // Throws a runtime exception defining the cause that is then
362                // in the "catch (Throwable ex)" a few lines below wrapped in
363                // BootstrapMethodError
364                throw new ClassCastException("bootstrap method failed to produce a CallSite");
365            }
366            if (!site.getTarget().type().equals(type)) {
367                // See the "Linking Exceptions" section for the invokedynamic
368                // instruction in JVMS 6.5.
369                // Throws a runtime exception defining the cause that is then
370                // in the "catch (Throwable ex)" a few lines below wrapped in
371                // BootstrapMethodError
372                throw wrongTargetType(site.getTarget(), type);
373            }
374        } catch (Error e) {
375            // Pass through an Error, including BootstrapMethodError, any other
376            // form of linkage error, such as IllegalAccessError if the bootstrap
377            // method is inaccessible, or say ThreadDeath/OutOfMemoryError
378            // See the "Linking Exceptions" section for the invokedynamic
379            // instruction in JVMS 6.5.
380            throw e;
381        } catch (Throwable ex) {
382            // Wrap anything else in BootstrapMethodError
383            throw new BootstrapMethodError("call site initialization exception", ex);
384        }
385        return site;
386    }
387
388    private static Object maybeReBox(Object x) {
389        if (x instanceof Integer) {
390            int xi = (int) x;
391            if (xi == (byte) xi)
392                x = xi;  // must rebox; see JLS 5.1.7
393        }
394        return x;
395    }
396    private static void maybeReBoxElements(Object[] xa) {
397        for (int i = 0; i < xa.length; i++) {
398            xa[i] = maybeReBox(xa[i]);
399        }
400    }
401}
402