1 /* |
|
2 * Copyright (c) 2008, 2010, 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 |
|
26 package sun.dyn; |
|
27 |
|
28 import java.dyn.*; |
|
29 import static sun.dyn.MemberName.uncaughtException; |
|
30 |
|
31 /** |
|
32 * Parts of CallSite known to the JVM. |
|
33 * @author jrose |
|
34 */ |
|
35 public class CallSiteImpl { |
|
36 // this implements the upcall from the JVM, MethodHandleNatives.makeDynamicCallSite: |
|
37 static CallSite makeSite(MethodHandle bootstrapMethod, |
|
38 // Callee information: |
|
39 String name, MethodType type, |
|
40 // Extra arguments for BSM, if any: |
|
41 Object info, |
|
42 // Caller information: |
|
43 MemberName callerMethod, int callerBCI) { |
|
44 Class<?> callerClass = callerMethod.getDeclaringClass(); |
|
45 Object caller; |
|
46 if (bootstrapMethod.type().parameterType(0) == Class.class && TRANSITIONAL_BEFORE_PFD) |
|
47 caller = callerClass; // remove for PFD |
|
48 else |
|
49 caller = MethodHandleImpl.IMPL_LOOKUP.in(callerClass); |
|
50 if (bootstrapMethod == null && TRANSITIONAL_BEFORE_PFD) { |
|
51 // If there is no bootstrap method, throw IncompatibleClassChangeError. |
|
52 // This is a valid generic error type for resolution (JLS 12.3.3). |
|
53 throw new IncompatibleClassChangeError |
|
54 ("Class "+callerClass.getName()+" has not declared a bootstrap method for invokedynamic"); |
|
55 } |
|
56 CallSite site; |
|
57 try { |
|
58 Object binding; |
|
59 info = maybeReBox(info); |
|
60 if (info == null) { |
|
61 binding = bootstrapMethod.invokeGeneric(caller, name, type); |
|
62 } else if (!info.getClass().isArray()) { |
|
63 binding = bootstrapMethod.invokeGeneric(caller, name, type, info); |
|
64 } else { |
|
65 Object[] argv = (Object[]) info; |
|
66 if (3 + argv.length > 255) |
|
67 new InvokeDynamicBootstrapError("too many bootstrap method arguments"); |
|
68 MethodType bsmType = bootstrapMethod.type(); |
|
69 if (bsmType.parameterCount() == 4 && bsmType.parameterType(3) == Object[].class) |
|
70 binding = bootstrapMethod.invokeGeneric(caller, name, type, argv); |
|
71 else |
|
72 binding = MethodHandles.spreadInvoker(bsmType, 3) |
|
73 .invokeGeneric(bootstrapMethod, caller, name, type, argv); |
|
74 } |
|
75 //System.out.println("BSM for "+name+type+" => "+binding); |
|
76 if (binding instanceof CallSite) { |
|
77 site = (CallSite) binding; |
|
78 } else if (binding instanceof MethodHandle && TRANSITIONAL_BEFORE_PFD) { |
|
79 // Transitional! |
|
80 MethodHandle target = (MethodHandle) binding; |
|
81 site = new ConstantCallSite(target); |
|
82 } else { |
|
83 throw new ClassCastException("bootstrap method failed to produce a CallSite"); |
|
84 } |
|
85 if (TRANSITIONAL_BEFORE_PFD) |
|
86 PRIVATE_INITIALIZE_CALL_SITE.invokeExact(site, name, type, |
|
87 callerMethod, callerBCI); |
|
88 assert(site.getTarget() != null); |
|
89 assert(site.getTarget().type().equals(type)); |
|
90 } catch (Throwable ex) { |
|
91 InvokeDynamicBootstrapError bex; |
|
92 if (ex instanceof InvokeDynamicBootstrapError) |
|
93 bex = (InvokeDynamicBootstrapError) ex; |
|
94 else |
|
95 bex = new InvokeDynamicBootstrapError("call site initialization exception", ex); |
|
96 throw bex; |
|
97 } |
|
98 return site; |
|
99 } |
|
100 |
|
101 private static boolean TRANSITIONAL_BEFORE_PFD = true; // FIXME: remove for PFD |
|
102 |
|
103 private static Object maybeReBox(Object x) { |
|
104 if (x instanceof Integer) { |
|
105 int xi = (int) x; |
|
106 if (xi == (byte) xi) |
|
107 x = xi; // must rebox; see JLS 5.1.7 |
|
108 return x; |
|
109 } else if (x instanceof Object[]) { |
|
110 Object[] xa = (Object[]) x; |
|
111 for (int i = 0; i < xa.length; i++) { |
|
112 if (xa[i] instanceof Integer) |
|
113 xa[i] = maybeReBox(xa[i]); |
|
114 } |
|
115 return xa; |
|
116 } else { |
|
117 return x; |
|
118 } |
|
119 } |
|
120 |
|
121 // This method is private in CallSite because it touches private fields in CallSite. |
|
122 // These private fields (vmmethod, vmindex) are specific to the JVM. |
|
123 private static final MethodHandle PRIVATE_INITIALIZE_CALL_SITE; |
|
124 static { |
|
125 try { |
|
126 PRIVATE_INITIALIZE_CALL_SITE = |
|
127 !TRANSITIONAL_BEFORE_PFD ? null : |
|
128 MethodHandleImpl.IMPL_LOOKUP.findVirtual(CallSite.class, "initializeFromJVM", |
|
129 MethodType.methodType(void.class, |
|
130 String.class, MethodType.class, |
|
131 MemberName.class, int.class)); |
|
132 } catch (ReflectiveOperationException ex) { |
|
133 throw uncaughtException(ex); |
|
134 } |
|
135 } |
|
136 |
|
137 public static void setCallSiteTarget(Access token, CallSite site, MethodHandle target) { |
|
138 Access.check(token); |
|
139 MethodHandleNatives.setCallSiteTarget(site, target); |
|
140 } |
|
141 } |
|