1 /*
2  * Copyright (c) 2008, 2019, 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 sun.invoke.util.Wrapper;
29 
30 import java.lang.ref.SoftReference;
31 
32 import static java.lang.invoke.MethodHandleStatics.newIllegalArgumentException;
33 
34 /**
35  * Shared information for a group of method types, which differ
36  * only by reference types, and therefore share a common erasure
37  * and wrapping.
38  * <p>
39  * For an empirical discussion of the structure of method types,
40  * see <a href="http://groups.google.com/group/jvm-languages/browse_thread/thread/ac9308ae74da9b7e/">
41  * the thread "Avoiding Boxing" on jvm-languages</a>.
42  * There are approximately 2000 distinct erased method types in the JDK.
43  * There are a little over 10 times that number of unerased types.
44  * No more than half of these are likely to be loaded at once.
45  * @author John Rose
46  */
47 final class MethodTypeForm {
48     final short parameterSlotCount;
49     final short primitiveCount;
50     final MethodType erasedType;        // the canonical erasure
51     final MethodType basicType;         // the canonical erasure, with primitives simplified
52 
53     // Cached adapter information:
54     final SoftReference<MethodHandle>[] methodHandles;
55 
56     // Indexes into methodHandles:
57     static final int
58             MH_BASIC_INV      =  0,  // cached instance of MH.invokeBasic
59             MH_NF_INV         =  1,  // cached helper for LF.NamedFunction
60             MH_UNINIT_CS      =  2,  // uninitialized call site
61             MH_LIMIT          =  3;
62 
63     // Cached lambda form information, for basic types only:
64     final SoftReference<LambdaForm>[] lambdaForms;
65 
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      */
erasedType()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      */
basicType()103     public MethodType basicType() {
104         return basicType;
105     }
106 
cachedMethodHandle(int which)107     public MethodHandle cachedMethodHandle(int which) {
108         SoftReference<MethodHandle> entry = methodHandles[which];
109         return (entry != null) ? entry.get() : null;
110     }
111 
setCachedMethodHandle(int which, MethodHandle mh)112     public synchronized MethodHandle setCachedMethodHandle(int which, MethodHandle mh) {
113         // Simulate a CAS, to avoid racy duplication of results.
114         SoftReference<MethodHandle> entry = methodHandles[which];
115         if (entry != null) {
116             MethodHandle prev = entry.get();
117             if (prev != null) {
118                 return prev;
119             }
120         }
121         methodHandles[which] = new SoftReference<>(mh);
122         return mh;
123     }
124 
cachedLambdaForm(int which)125     public LambdaForm cachedLambdaForm(int which) {
126         SoftReference<LambdaForm> entry = lambdaForms[which];
127         return (entry != null) ? entry.get() : null;
128     }
129 
setCachedLambdaForm(int which, LambdaForm form)130     public synchronized LambdaForm setCachedLambdaForm(int which, LambdaForm form) {
131         // Simulate a CAS, to avoid racy duplication of results.
132         SoftReference<LambdaForm> entry = lambdaForms[which];
133         if (entry != null) {
134             LambdaForm prev = entry.get();
135             if (prev != null) {
136                 return prev;
137             }
138         }
139         lambdaForms[which] = new SoftReference<>(form);
140         return form;
141     }
142 
143     /**
144      * Build an MTF for a given type, which must have all references erased to Object.
145      * This MTF will stand for that type and all un-erased variations.
146      * Eagerly compute some basic properties of the type, common to all variations.
147      */
148     @SuppressWarnings({"rawtypes", "unchecked"})
MethodTypeForm(MethodType erasedType)149     protected MethodTypeForm(MethodType erasedType) {
150         this.erasedType = erasedType;
151 
152         Class<?>[] ptypes = erasedType.ptypes();
153         int pslotCount = ptypes.length;
154 
155         // Walk the argument types, looking for primitives.
156         short primitiveCount = 0, longArgCount = 0;
157         Class<?>[] erasedPtypes = ptypes;
158         Class<?>[] basicPtypes = erasedPtypes;
159         for (int i = 0; i < erasedPtypes.length; i++) {
160             Class<?> ptype = erasedPtypes[i];
161             if (ptype != Object.class) {
162                 ++primitiveCount;
163                 Wrapper w = Wrapper.forPrimitiveType(ptype);
164                 if (w.isDoubleWord())  ++longArgCount;
165                 if (w.isSubwordOrInt() && ptype != int.class) {
166                     if (basicPtypes == erasedPtypes)
167                         basicPtypes = basicPtypes.clone();
168                     basicPtypes[i] = int.class;
169                 }
170             }
171         }
172         pslotCount += longArgCount;                  // #slots = #args + #longs
173         Class<?> returnType = erasedType.returnType();
174         Class<?> basicReturnType = returnType;
175         if (returnType != Object.class) {
176             ++primitiveCount; // even void.class counts as a prim here
177             Wrapper w = Wrapper.forPrimitiveType(returnType);
178             if (w.isSubwordOrInt() && returnType != int.class)
179                 basicReturnType = int.class;
180         }
181         if (erasedPtypes == basicPtypes && basicReturnType == returnType) {
182             // Basic type
183             this.basicType = erasedType;
184 
185             if (pslotCount >= 256)  throw newIllegalArgumentException("too many arguments");
186 
187             this.primitiveCount = primitiveCount;
188             this.parameterSlotCount = (short)pslotCount;
189             this.lambdaForms   = new SoftReference[LF_LIMIT];
190             this.methodHandles = new SoftReference[MH_LIMIT];
191         } else {
192             this.basicType = MethodType.makeImpl(basicReturnType, basicPtypes, true);
193             // fill in rest of data from the basic type:
194             MethodTypeForm that = this.basicType.form();
195             assert(this != that);
196 
197             this.parameterSlotCount = that.parameterSlotCount;
198             this.primitiveCount = that.primitiveCount;
199             this.methodHandles = null;
200             this.lambdaForms = null;
201         }
202     }
203 
parameterCount()204     public int parameterCount() {
205         return erasedType.parameterCount();
206     }
parameterSlotCount()207     public int parameterSlotCount() {
208         return parameterSlotCount;
209     }
hasPrimitives()210     public boolean hasPrimitives() {
211         return primitiveCount != 0;
212     }
213 
findForm(MethodType mt)214     static MethodTypeForm findForm(MethodType mt) {
215         MethodType erased = canonicalize(mt, ERASE, ERASE);
216         if (erased == null) {
217             // It is already erased.  Make a new MethodTypeForm.
218             return new MethodTypeForm(mt);
219         } else {
220             // Share the MethodTypeForm with the erased version.
221             return erased.form();
222         }
223     }
224 
225     /** Codes for {@link #canonicalize(java.lang.Class, int)}.
226      * ERASE means change every reference to {@code Object}.
227      * WRAP means convert primitives (including {@code void} to their
228      * corresponding wrapper types.  UNWRAP means the reverse of WRAP.
229      * INTS means convert all non-void primitive types to int or long,
230      * according to size.  LONGS means convert all non-void primitives
231      * to long, regardless of size.  RAW_RETURN means convert a type
232      * (assumed to be a return type) to int if it is smaller than an int,
233      * or if it is void.
234      */
235     public static final int ERASE = 1, WRAP = 2, UNWRAP = 3, INTS = 4, LONGS = 5, RAW_RETURN = 6;
236 
237     /** Canonicalize the types in the given method type.
238      * If any types change, intern the new type, and return it.
239      * Otherwise return null.
240      */
canonicalize(MethodType mt, int howRet, int howArgs)241     public static MethodType canonicalize(MethodType mt, int howRet, int howArgs) {
242         Class<?>[] ptypes = mt.ptypes();
243         Class<?>[] ptypesCanonical = canonicalizeAll(ptypes, howArgs);
244         Class<?> rtype = mt.returnType();
245         Class<?> rtypeCanonical = canonicalize(rtype, howRet);
246         if (ptypesCanonical == null && rtypeCanonical == null) {
247             // It is already canonical.
248             return null;
249         }
250         // Find the erased version of the method type:
251         if (rtypeCanonical == null)  rtypeCanonical = rtype;
252         if (ptypesCanonical == null)  ptypesCanonical = ptypes;
253         return MethodType.makeImpl(rtypeCanonical, ptypesCanonical, true);
254     }
255 
256     /** Canonicalize the given return or param type.
257      *  Return null if the type is already canonicalized.
258      */
canonicalize(Class<?> t, int how)259     static Class<?> canonicalize(Class<?> t, int how) {
260         Class<?> ct;
261         if (t == Object.class) {
262             // no change, ever
263         } else if (!t.isPrimitive()) {
264             switch (how) {
265                 case UNWRAP:
266                     ct = Wrapper.asPrimitiveType(t);
267                     if (ct != t)  return ct;
268                     break;
269                 case RAW_RETURN:
270                 case ERASE:
271                     return Object.class;
272             }
273         } else if (t == void.class) {
274             // no change, usually
275             switch (how) {
276                 case RAW_RETURN:
277                     return int.class;
278                 case WRAP:
279                     return Void.class;
280             }
281         } else {
282             // non-void primitive
283             switch (how) {
284                 case WRAP:
285                     return Wrapper.asWrapperType(t);
286                 case INTS:
287                     if (t == int.class || t == long.class)
288                         return null;  // no change
289                     if (t == double.class)
290                         return long.class;
291                     return int.class;
292                 case LONGS:
293                     if (t == long.class)
294                         return null;  // no change
295                     return long.class;
296                 case RAW_RETURN:
297                     if (t == int.class || t == long.class ||
298                         t == float.class || t == double.class)
299                         return null;  // no change
300                     // everything else returns as an int
301                     return int.class;
302             }
303         }
304         // no change; return null to signify
305         return null;
306     }
307 
308     /** Canonicalize each param type in the given array.
309      *  Return null if all types are already canonicalized.
310      */
canonicalizeAll(Class<?>[] ts, int how)311     static Class<?>[] canonicalizeAll(Class<?>[] ts, int how) {
312         Class<?>[] cs = null;
313         for (int imax = ts.length, i = 0; i < imax; i++) {
314             Class<?> c = canonicalize(ts[i], how);
315             // Void parameters may be unwrapped to void; ignore those
316             if (c != null && c != void.class) {
317                 if (cs == null)
318                     cs = ts.clone();
319                 cs[i] = c;
320             }
321         }
322         return cs;
323     }
324 
325     @Override
toString()326     public String toString() {
327         return "Form"+erasedType;
328     }
329 }
330