1 /*
2 * Copyright (c) 2008, 2018, 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 java.lang.invoke;
27
28 import jdk.internal.vm.annotation.Stable;
29 import sun.invoke.util.Wrapper;
30
31 import java.lang.ref.SoftReference;
32
33 import static java.lang.invoke.MethodHandleStatics.newIllegalArgumentException;
34
35 /**
36 * Shared information for a group of method types, which differ
37 * only by reference types, and therefore share a common erasure
38 * and wrapping.
39 * <p>
40 * For an empirical discussion of the structure of method types,
41 * see <a href="http://groups.google.com/group/jvm-languages/browse_thread/thread/ac9308ae74da9b7e/">
42 * the thread "Avoiding Boxing" on jvm-languages</a>.
43 * There are approximately 2000 distinct erased method types in the JDK.
44 * There are a little over 10 times that number of unerased types.
45 * No more than half of these are likely to be loaded at once.
46 * @author John Rose
47 */
48 final class MethodTypeForm {
49 final int[] argToSlotTable, slotToArgTable;
50 final long argCounts; // packed slot & value counts
51 final long primCounts; // packed prim & double counts
52 final MethodType erasedType; // the canonical erasure
53 final MethodType basicType; // the canonical erasure, with primitives simplified
54
55 // Cached adapter information:
56 @Stable final SoftReference<MethodHandle>[] methodHandles;
57 // Indexes into methodHandles:
58 static final int
59 MH_BASIC_INV = 0, // cached instance of MH.invokeBasic
60 MH_NF_INV = 1, // cached helper for LF.NamedFunction
61 MH_UNINIT_CS = 2, // uninitialized call site
62 MH_LIMIT = 3;
63
64 // Cached lambda form information, for basic types only:
65 final @Stable SoftReference<LambdaForm>[] lambdaForms;
66 // Indexes into lambdaForms:
67 static final int
68 LF_INVVIRTUAL = 0, // DMH invokeVirtual
69 LF_INVSTATIC = 1,
70 LF_INVSPECIAL = 2,
71 LF_NEWINVSPECIAL = 3,
72 LF_INVINTERFACE = 4,
73 LF_INVSTATIC_INIT = 5, // DMH invokeStatic with <clinit> barrier
74 LF_INTERPRET = 6, // LF interpreter
75 LF_REBIND = 7, // BoundMethodHandle
76 LF_DELEGATE = 8, // DelegatingMethodHandle
77 LF_DELEGATE_BLOCK_INLINING = 9, // Counting DelegatingMethodHandle w/ @DontInline
78 LF_EX_LINKER = 10, // invokeExact_MT (for invokehandle)
79 LF_EX_INVOKER = 11, // MHs.invokeExact
80 LF_GEN_LINKER = 12, // generic invoke_MT (for invokehandle)
81 LF_GEN_INVOKER = 13, // generic MHs.invoke
82 LF_CS_LINKER = 14, // linkToCallSite_CS
83 LF_MH_LINKER = 15, // linkToCallSite_MH
84 LF_GWC = 16, // guardWithCatch (catchException)
85 LF_GWT = 17, // guardWithTest
86 LF_TF = 18, // tryFinally
87 LF_LOOP = 19, // loop
88 LF_INVSPECIAL_IFC = 20, // DMH invokeSpecial of (private) interface method
89 LF_LIMIT = 21;
90
91 /** Return the type corresponding uniquely (1-1) to this MT-form.
92 * It might have any primitive returns or arguments, but will have no references except Object.
93 */
94 public MethodType erasedType() {
95 return erasedType;
96 }
97
98 /** Return the basic type derived from the erased type of this MT-form.
99 * A basic type is erased (all references Object) and also has all primitive
100 * types (except int, long, float, double, void) normalized to int.
101 * Such basic types correspond to low-level JVM calling sequences.
102 */
103 public MethodType basicType() {
104 return basicType;
105 }
106
107 private boolean assertIsBasicType() {
108 // primitives must be flattened also
109 assert(erasedType == basicType)
110 : "erasedType: " + erasedType + " != basicType: " + basicType;
111 return true;
112 }
113
114 public MethodHandle cachedMethodHandle(int which) {
115 assert(assertIsBasicType());
116 SoftReference<MethodHandle> entry = methodHandles[which];
117 return (entry != null) ? entry.get() : null;
118 }
119
120 public synchronized MethodHandle setCachedMethodHandle(int which, MethodHandle mh) {
121 // Simulate a CAS, to avoid racy duplication of results.
122 SoftReference<MethodHandle> entry = methodHandles[which];
123 if (entry != null) {
124 MethodHandle prev = entry.get();
125 if (prev != null) {
126 return prev;
127 }
128 }
129 methodHandles[which] = new SoftReference<>(mh);
130 return mh;
131 }
132
133 public LambdaForm cachedLambdaForm(int which) {
134 assert(assertIsBasicType());
135 SoftReference<LambdaForm> entry = lambdaForms[which];
136 return (entry != null) ? entry.get() : null;
137 }
138
139 public synchronized LambdaForm setCachedLambdaForm(int which, LambdaForm form) {
140 // Simulate a CAS, to avoid racy duplication of results.
141 SoftReference<LambdaForm> entry = lambdaForms[which];
142 if (entry != null) {
143 LambdaForm prev = entry.get();
144 if (prev != null) {
145 return prev;
146 }
147 }
148 lambdaForms[which] = new SoftReference<>(form);
149 return form;
150 }
151
152 /**
153 * Build an MTF for a given type, which must have all references erased to Object.
154 * This MTF will stand for that type and all un-erased variations.
155 * Eagerly compute some basic properties of the type, common to all variations.
156 */
157 @SuppressWarnings({"rawtypes", "unchecked"})
158 protected MethodTypeForm(MethodType erasedType) {
159 this.erasedType = erasedType;
160
161 Class<?>[] ptypes = erasedType.ptypes();
162 int ptypeCount = ptypes.length;
163 int pslotCount = ptypeCount; // temp. estimate
164 int rtypeCount = 1; // temp. estimate
165 int rslotCount = 1; // temp. estimate
166
167 int[] argToSlotTab = null, slotToArgTab = null;
168
169 // Walk the argument types, looking for primitives.
170 int pac = 0, lac = 0, prc = 0, lrc = 0;
171 Class<?>[] epts = ptypes;
172 Class<?>[] bpts = epts;
173 for (int i = 0; i < epts.length; i++) {
174 Class<?> pt = epts[i];
175 if (pt != Object.class) {
176 ++pac;
177 Wrapper w = Wrapper.forPrimitiveType(pt);
178 if (w.isDoubleWord()) ++lac;
179 if (w.isSubwordOrInt() && pt != int.class) {
180 if (bpts == epts)
181 bpts = bpts.clone();
182 bpts[i] = int.class;
183 }
184 }
185 }
186 pslotCount += lac; // #slots = #args + #longs
187 Class<?> rt = erasedType.returnType();
188 Class<?> bt = rt;
189 if (rt != Object.class) {
190 ++prc; // even void.class counts as a prim here
191 Wrapper w = Wrapper.forPrimitiveType(rt);
192 if (w.isDoubleWord()) ++lrc;
193 if (w.isSubwordOrInt() && rt != int.class)
194 bt = int.class;
195 // adjust #slots, #args
196 if (rt == void.class)
197 rtypeCount = rslotCount = 0;
198 else
199 rslotCount += lrc;
200 }
201 if (epts == bpts && bt == rt) {
202 this.basicType = erasedType;
203 } else {
204 this.basicType = MethodType.makeImpl(bt, bpts, true);
205 // fill in rest of data from the basic type:
206 MethodTypeForm that = this.basicType.form();
207 assert(this != that);
208 this.primCounts = that.primCounts;
209 this.argCounts = that.argCounts;
210 this.argToSlotTable = that.argToSlotTable;
211 this.slotToArgTable = that.slotToArgTable;
212 this.methodHandles = null;
213 this.lambdaForms = null;
214 return;
215 }
216 if (lac != 0) {
217 int slot = ptypeCount + lac;
218 slotToArgTab = new int[slot+1];
219 argToSlotTab = new int[1+ptypeCount];
220 argToSlotTab[0] = slot; // argument "-1" is past end of slots
221 for (int i = 0; i < epts.length; i++) {
222 Class<?> pt = epts[i];
223 Wrapper w = Wrapper.forBasicType(pt);
224 if (w.isDoubleWord()) --slot;
225 --slot;
226 slotToArgTab[slot] = i+1; // "+1" see argSlotToParameter note
227 argToSlotTab[1+i] = slot;
228 }
229 assert(slot == 0); // filled the table
230 } else if (pac != 0) {
231 // have primitives but no long primitives; share slot counts with generic
232 assert(ptypeCount == pslotCount);
233 MethodTypeForm that = MethodType.genericMethodType(ptypeCount).form();
234 assert(this != that);
235 slotToArgTab = that.slotToArgTable;
236 argToSlotTab = that.argToSlotTable;
237 } else {
238 int slot = ptypeCount; // first arg is deepest in stack
239 slotToArgTab = new int[slot+1];
240 argToSlotTab = new int[1+ptypeCount];
241 argToSlotTab[0] = slot; // argument "-1" is past end of slots
242 for (int i = 0; i < ptypeCount; i++) {
243 --slot;
244 slotToArgTab[slot] = i+1; // "+1" see argSlotToParameter note
245 argToSlotTab[1+i] = slot;
246 }
247 }
248 this.primCounts = pack(lrc, prc, lac, pac);
249 this.argCounts = pack(rslotCount, rtypeCount, pslotCount, ptypeCount);
250 this.argToSlotTable = argToSlotTab;
251 this.slotToArgTable = slotToArgTab;
252
253 if (pslotCount >= 256) throw newIllegalArgumentException("too many arguments");
254
255 // Initialize caches, but only for basic types
256 assert(basicType == erasedType);
257 this.lambdaForms = new SoftReference[LF_LIMIT];
258 this.methodHandles = new SoftReference[MH_LIMIT];
259 }
260
261 private static long pack(int a, int b, int c, int d) {
262 assert(((a|b|c|d) & ~0xFFFF) == 0);
263 long hw = ((a << 16) | b), lw = ((c << 16) | d);
264 return (hw << 32) | lw;
265 }
266 private static char unpack(long packed, int word) { // word==0 => return a, ==3 => return d
267 assert(word <= 3);
268 return (char)(packed >> ((3-word) * 16));
269 }
270
271 public int parameterCount() { // # outgoing values
272 return unpack(argCounts, 3);
273 }
274 public int parameterSlotCount() { // # outgoing interpreter slots
275 return unpack(argCounts, 2);
276 }
277 public int returnCount() { // = 0 (V), or 1
278 return unpack(argCounts, 1);
279 }
280 public int returnSlotCount() { // = 0 (V), 2 (J/D), or 1
281 return unpack(argCounts, 0);
282 }
283 public int primitiveParameterCount() {
284 return unpack(primCounts, 3);
285 }
286 public int longPrimitiveParameterCount() {
287 return unpack(primCounts, 2);
288 }
289 public int primitiveReturnCount() { // = 0 (obj), or 1
290 return unpack(primCounts, 1);
291 }
292 public int longPrimitiveReturnCount() { // = 1 (J/D), or 0
293 return unpack(primCounts, 0);
294 }
295 public boolean hasPrimitives() {
296 return primCounts != 0;
297 }
298 public boolean hasNonVoidPrimitives() {
299 if (primCounts == 0) return false;
300 if (primitiveParameterCount() != 0) return true;
301 return (primitiveReturnCount() != 0 && returnCount() != 0);
302 }
303 public boolean hasLongPrimitives() {
304 return (longPrimitiveParameterCount() | longPrimitiveReturnCount()) != 0;
305 }
306 public int parameterToArgSlot(int i) {
307 return argToSlotTable[1+i];
308 }
309 public int argSlotToParameter(int argSlot) {
310 // Note: Empty slots are represented by zero in this table.
311 // Valid arguments slots contain incremented entries, so as to be non-zero.
312 // We return -1 the caller to mean an empty slot.
313 return slotToArgTable[argSlot] - 1;
314 }
315
316 static MethodTypeForm findForm(MethodType mt) {
317 MethodType erased = canonicalize(mt, ERASE, ERASE);
318 if (erased == null) {
319 // It is already erased. Make a new MethodTypeForm.
320 return new MethodTypeForm(mt);
321 } else {
322 // Share the MethodTypeForm with the erased version.
323 return erased.form();
324 }
325 }
326
327 /** Codes for {@link #canonicalize(java.lang.Class, int)}.
328 * ERASE means change every reference to {@code Object}.
329 * WRAP means convert primitives (including {@code void} to their
330 * corresponding wrapper types. UNWRAP means the reverse of WRAP.
331 * INTS means convert all non-void primitive types to int or long,
332 * according to size. LONGS means convert all non-void primitives
333 * to long, regardless of size. RAW_RETURN means convert a type
334 * (assumed to be a return type) to int if it is smaller than an int,
335 * or if it is void.
336 */
337 public static final int NO_CHANGE = 0, ERASE = 1, WRAP = 2, UNWRAP = 3, INTS = 4, LONGS = 5, RAW_RETURN = 6;
338
339 /** Canonicalize the types in the given method type.
340 * If any types change, intern the new type, and return it.
341 * Otherwise return null.
342 */
343 public static MethodType canonicalize(MethodType mt, int howRet, int howArgs) {
344 Class<?>[] ptypes = mt.ptypes();
345 Class<?>[] ptc = MethodTypeForm.canonicalizeAll(ptypes, howArgs);
346 Class<?> rtype = mt.returnType();
347 Class<?> rtc = MethodTypeForm.canonicalize(rtype, howRet);
348 if (ptc == null && rtc == null) {
349 // It is already canonical.
350 return null;
351 }
352 // Find the erased version of the method type:
353 if (rtc == null) rtc = rtype;
354 if (ptc == null) ptc = ptypes;
355 return MethodType.makeImpl(rtc, ptc, true);
356 }
357
358 /** Canonicalize the given return or param type.
359 * Return null if the type is already canonicalized.
360 */
361 static Class<?> canonicalize(Class<?> t, int how) {
362 Class<?> ct;
363 if (t == Object.class) {
364 // no change, ever
365 } else if (!t.isPrimitive()) {
366 switch (how) {
367 case UNWRAP:
368 ct = Wrapper.asPrimitiveType(t);
369 if (ct != t) return ct;
370 break;
371 case RAW_RETURN:
372 case ERASE:
373 return Object.class;
374 }
375 } else if (t == void.class) {
376 // no change, usually
377 switch (how) {
378 case RAW_RETURN:
379 return int.class;
380 case WRAP:
381 return Void.class;
382 }
383 } else {
384 // non-void primitive
385 switch (how) {
386 case WRAP:
387 return Wrapper.asWrapperType(t);
388 case INTS:
389 if (t == int.class || t == long.class)
390 return null; // no change
391 if (t == double.class)
392 return long.class;
393 return int.class;
394 case LONGS:
395 if (t == long.class)
396 return null; // no change
397 return long.class;
398 case RAW_RETURN:
399 if (t == int.class || t == long.class ||
400 t == float.class || t == double.class)
401 return null; // no change
402 // everything else returns as an int
403 return int.class;
404 }
405 }
406 // no change; return null to signify
407 return null;
408 }
409
410 /** Canonicalize each param type in the given array.
411 * Return null if all types are already canonicalized.
412 */
413 static Class<?>[] canonicalizeAll(Class<?>[] ts, int how) {
414 Class<?>[] cs = null;
415 for (int imax = ts.length, i = 0; i < imax; i++) {
416 Class<?> c = canonicalize(ts[i], how);
417 if (c == void.class)
418 c = null; // a Void parameter was unwrapped to void; ignore
419 if (c != null) {
420 if (cs == null)
421 cs = ts.clone();
422 cs[i] = c;
423 }
424 }
425 return cs;
426 }
427
428 @Override
429 public String toString() {
430 return "Form"+erasedType;
431 }
432 }
433