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