1 /*
2 * Copyright 2008-2009 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26 package java.dyn;
27
28 import impl.java.dyn.util.Wrappers;
29
30 /**
31 * Shared information for a group of method types, which differ
32 * only by reference types, and therefore share a common erasure
33 * and wrapping.
34 * <p>
35 * For an empirical discussion of the structure of method types,
36 * see <a href="http://groups.google.com/group/jvm-languages/browse_thread/thread/ac9308ae74da9b7e/">
37 * the thread "Avoiding Boxing" on jvm-languages</a>.
38 * There are approximately 2000 distinct erased method types in the JDK.
39 * There are a little over 10 times that number of unerased types.
40 * No more than half of these are likely to be loaded at once.
41 * @author John Rose
42 */
43 class MethodTypeForm {
44 final int[] argToSlotTable, slotToArgTable;
45 final long argCounts; // packed slot & value counts
46 final long primCounts; // packed prim & double counts
47 final int vmslots; // total number of parameter slots
48 final MethodType erasedType; // the canonical erasure
49 final MethodType wrappedType; // erasure, with primitives wrapped
50
51 public static MethodTypeForm of(MethodType type) {
52 return type.form;
53 }
54
55 private MethodTypeForm(MethodType erase) {
56 this.erasedType = erase;
57 MethodType wt = canonType(erase, WRAP);
58 this.wrappedType = (wt == null) ? erase : wt;
59
60 int ptypeCount = erase.ptypes.length;
61 int pslotCount = ptypeCount; // temp. estimate
62 int rtypeCount = 1; // temp. estimate
63 int rslotCount = 1; // temp. estimate
64
65 int[] argToSlotTab = null, slotToArgTab = null;
66
67 // Walk the argument types, looking for primitives.
68 if (wt != null) {
69 int pac = 0, lac = 0, prc = 0, lrc = 0;
70 Class<?> epts[] = erase.ptypes;
71 for (int i = 0; i < epts.length; i++) {
72 Class<?> pt = epts[i];
73 if (pt != Object.class) {
74 assert(pt.isPrimitive());
75 ++pac;
76 if (hasTwoArgSlots(pt)) ++lac;
77 }
78 }
79 pslotCount += lac; // #slots = #args + #longs
80 Class<?> rt = erase.rtype;
81 if (rt != Object.class) {
82 ++prc; // even void.class counts as a prim here
83 if (hasTwoArgSlots(rt)) ++lrc;
84 // adjust #slots, #args
85 if (rt == void.class)
86 rtypeCount = rslotCount = 0;
87 else
88 rslotCount += lrc;
89 }
90 if (lac != 0) {
91 int slot = ptypeCount + lac;
92 slotToArgTab = new int[slot+1];
93 argToSlotTab = new int[1+ptypeCount];
94 argToSlotTab[0] = slot; // argument "-1" is past end of slots
95 for (int i = 0; i < epts.length; i++) {
96 Class<?> pt = epts[i];
97 if (hasTwoArgSlots(pt)) --slot;
98 --slot;
99 slotToArgTab[slot] = i+1; // "+1" see argSlotToParameter note
100 argToSlotTab[1+i] = slot;
101 }
102 assert(slot == 0); // filled the table
103 }
104 this.primCounts = pack(lrc, prc, lac, pac);
105 } else {
106 this.primCounts = 0;
107 }
108 this.argCounts = pack(rslotCount, rtypeCount, pslotCount, ptypeCount);
109 if (slotToArgTab == null) {
110 int slot = ptypeCount; // first arg is deepest in stack
111 slotToArgTab = new int[slot+1];
112 argToSlotTab = new int[1+ptypeCount];
113 argToSlotTab[0] = slot; // argument "-1" is past end of slots
114 for (int i = 0; i < ptypeCount; i++) {
115 --slot;
116 slotToArgTab[slot] = i+1; // "+1" see argSlotToParameter note
117 argToSlotTab[1+i] = slot;
118 }
119 }
120 this.argToSlotTable = argToSlotTab;
121 this.slotToArgTable = slotToArgTab;
122
123 if (pslotCount >= 256) throw new IllegalArgumentException("too many arguments");
124
125 // send a few bits down to the JVM:
126 this.vmslots = parameterSlotCount();
127 }
128
129 private static boolean hasTwoArgSlots(Class<?> type) {
130 return type == long.class || type == double.class;
131 }
132
133 private static long pack(int a, int b, int c, int d) {
134 assert(((a|b|c|d) & ~0xFFFF) == 0);
135 long hw = ((a << 16) | b), lw = ((c << 16) | d);
136 return (hw << 32) | lw;
137 }
138 private static char unpack(long packed, int word) { // word==0 => return a, ==3 => return d
139 assert(word <= 3);
140 return (char)(packed >> ((3-word) * 16));
141 }
142
143 public int parameterCount() { // # outgoing values
144 return unpack(argCounts, 3);
145 }
146 public int parameterSlotCount() { // # outgoing interpreter slots
147 return unpack(argCounts, 2);
148 }
149 public int returnCount() { // = 0 (V), or 1
150 return unpack(argCounts, 1);
151 }
152 public int returnSlotCount() { // = 0 (V), 2 (J/D), or 1
153 return unpack(argCounts, 0);
154 }
155 public int primitiveParameterCount() {
156 return unpack(primCounts, 3);
157 }
158 public int longPrimitiveParameterCount() {
159 return unpack(primCounts, 2);
160 }
161 public int primitiveReturnCount() { // = 0 (obj), or 1
162 return unpack(primCounts, 1);
163 }
164 public int longPrimitiveReturnCount() { // = 1 (J/D), or 0
165 return unpack(primCounts, 0);
166 }
167 public int parameterToArgSlot(int i) {
168 return argToSlotTable[1+i];
169 }
170 public int argSlotToParameter(int argSlot) {
171 // Note: Empty slots are represented by zero in this table.
172 // Valid arguments slots contain incremented entries, so as to be non-zero.
173 // We return -1 the caller to mean an empty slot.
174 return slotToArgTable[argSlot] - 1;
175 }
176
177 static final int ERASE = 1, WRAP = 2, UNWRAP = 4, ARGS_ONLY = 8;
178
179 static MethodTypeForm findForm(MethodType mt) {
180 MethodType erased = canonType(mt, ERASE);
181 if (erased == null) {
182 // It is already erased. Make a new MethodTypeForm.
183 return new MethodTypeForm(mt);
184 } else {
185 // Share the MethodTypeForm with the erased version.
186 return erased.form;
187 }
188 }
189
190 /** Canonicalize the types in the given method type.
191 * If any types change, intern the new type, and return it.
192 * Otherwise return null.
193 */
194 static MethodType canonType(MethodType mt, int how) {
195 Class<?>[] ptc = MethodTypeForm.canonTypes(mt.ptypes, how);
196 Class<?> rtc = null;
197 if ((how & ARGS_ONLY) == 0)
198 rtc = MethodTypeForm.canonType(mt.rtype, how);
199 if (ptc == null && rtc == null) {
200 // It is already canonical.
201 return null;
202 }
203 // Find the erased version of the method type:
204 if (rtc == null) rtc = mt.rtype;
205 if (ptc == null) ptc = mt.ptypes;
206 return MethodType.makeImpl(rtc, ptc, true);
207 }
208
209 /** Canonicalize the given return or param type.
210 * Return null if the type is already canonicalized.
211 */
212 static Class<?> canonType(Class<?> t, int how) {
213 if (t == Object.class) {
214 // no change, ever
215 } else if (!t.isPrimitive()) {
216 if ((how & UNWRAP) != 0) {
217 Class<?> pt = Wrappers.asPrimitiveType(t);
218 if (pt != t)
219 return pt;
220 }
221 if ((how & ERASE) != 0)
222 return Object.class;
223 } else {
224 if ((how & WRAP) != 0) {
225 if ((how & ERASE) != 0)
226 return Object.class;
227 return Wrappers.asWrapperType(t);
228 }
229 }
230 // no change; return null to signify
231 return null;
232 }
233
234 /** Canonicalize each param type in the given array.
235 * Return null if all types are already canonicalized.
236 */
237 static Class<?>[] canonTypes(Class<?>[] ts, int how) {
238 Class<?>[] cs = null;
239 for (int imax = ts.length, i = 0; i < imax; i++) {
240 Class<?> c = canonType(ts[i], how);
241 if (c != null) {
242 if (cs == null)
243 cs = ts.clone();
244 cs[i] = c;
245 }
246 }
247 return cs;
248 }
249 }