44 * There are a little over 10 times that number of unerased types. |
43 * 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. |
44 * No more than half of these are likely to be loaded at once. |
46 * @author John Rose |
45 * @author John Rose |
47 */ |
46 */ |
48 final class MethodTypeForm { |
47 final class MethodTypeForm { |
49 final int[] argToSlotTable, slotToArgTable; |
48 final short parameterSlotCount; |
50 final long argCounts; // packed slot & value counts |
49 final short primitiveCount; |
51 final long primCounts; // packed prim & double counts |
|
52 final MethodType erasedType; // the canonical erasure |
50 final MethodType erasedType; // the canonical erasure |
53 final MethodType basicType; // the canonical erasure, with primitives simplified |
51 final MethodType basicType; // the canonical erasure, with primitives simplified |
54 |
52 |
55 // Cached adapter information: |
53 // Cached adapter information: |
56 @Stable final SoftReference<MethodHandle>[] methodHandles; |
54 final SoftReference<MethodHandle>[] methodHandles; |
|
55 |
57 // Indexes into methodHandles: |
56 // Indexes into methodHandles: |
58 static final int |
57 static final int |
59 MH_BASIC_INV = 0, // cached instance of MH.invokeBasic |
58 MH_BASIC_INV = 0, // cached instance of MH.invokeBasic |
60 MH_NF_INV = 1, // cached helper for LF.NamedFunction |
59 MH_NF_INV = 1, // cached helper for LF.NamedFunction |
61 MH_UNINIT_CS = 2, // uninitialized call site |
60 MH_UNINIT_CS = 2, // uninitialized call site |
62 MH_LIMIT = 3; |
61 MH_LIMIT = 3; |
63 |
62 |
64 // Cached lambda form information, for basic types only: |
63 // Cached lambda form information, for basic types only: |
65 final @Stable SoftReference<LambdaForm>[] lambdaForms; |
64 final SoftReference<LambdaForm>[] lambdaForms; |
|
65 |
66 // Indexes into lambdaForms: |
66 // Indexes into lambdaForms: |
67 static final int |
67 static final int |
68 LF_INVVIRTUAL = 0, // DMH invokeVirtual |
68 LF_INVVIRTUAL = 0, // DMH invokeVirtual |
69 LF_INVSTATIC = 1, |
69 LF_INVSTATIC = 1, |
70 LF_INVSPECIAL = 2, |
70 LF_INVSPECIAL = 2, |
157 @SuppressWarnings({"rawtypes", "unchecked"}) |
148 @SuppressWarnings({"rawtypes", "unchecked"}) |
158 protected MethodTypeForm(MethodType erasedType) { |
149 protected MethodTypeForm(MethodType erasedType) { |
159 this.erasedType = erasedType; |
150 this.erasedType = erasedType; |
160 |
151 |
161 Class<?>[] ptypes = erasedType.ptypes(); |
152 Class<?>[] ptypes = erasedType.ptypes(); |
162 int ptypeCount = ptypes.length; |
153 int pslotCount = 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 |
154 |
169 // Walk the argument types, looking for primitives. |
155 // Walk the argument types, looking for primitives. |
170 int pac = 0, lac = 0, prc = 0, lrc = 0; |
156 short primitiveCount = 0, longArgCount = 0; |
171 Class<?>[] epts = ptypes; |
157 Class<?>[] erasedPtypes = ptypes; |
172 Class<?>[] bpts = epts; |
158 Class<?>[] basicPtypes = erasedPtypes; |
173 for (int i = 0; i < epts.length; i++) { |
159 for (int i = 0; i < erasedPtypes.length; i++) { |
174 Class<?> pt = epts[i]; |
160 Class<?> ptype = erasedPtypes[i]; |
175 if (pt != Object.class) { |
161 if (ptype != Object.class) { |
176 ++pac; |
162 ++primitiveCount; |
177 Wrapper w = Wrapper.forPrimitiveType(pt); |
163 Wrapper w = Wrapper.forPrimitiveType(ptype); |
178 if (w.isDoubleWord()) ++lac; |
164 if (w.isDoubleWord()) ++longArgCount; |
179 if (w.isSubwordOrInt() && pt != int.class) { |
165 if (w.isSubwordOrInt() && ptype != int.class) { |
180 if (bpts == epts) |
166 if (basicPtypes == erasedPtypes) |
181 bpts = bpts.clone(); |
167 basicPtypes = basicPtypes.clone(); |
182 bpts[i] = int.class; |
168 basicPtypes[i] = int.class; |
183 } |
169 } |
184 } |
170 } |
185 } |
171 } |
186 pslotCount += lac; // #slots = #args + #longs |
172 pslotCount += longArgCount; // #slots = #args + #longs |
187 Class<?> rt = erasedType.returnType(); |
173 Class<?> returnType = erasedType.returnType(); |
188 Class<?> bt = rt; |
174 Class<?> basicReturnType = returnType; |
189 if (rt != Object.class) { |
175 if (returnType != Object.class) { |
190 ++prc; // even void.class counts as a prim here |
176 ++primitiveCount; // even void.class counts as a prim here |
191 Wrapper w = Wrapper.forPrimitiveType(rt); |
177 Wrapper w = Wrapper.forPrimitiveType(returnType); |
192 if (w.isDoubleWord()) ++lrc; |
178 if (w.isSubwordOrInt() && returnType != int.class) |
193 if (w.isSubwordOrInt() && rt != int.class) |
179 basicReturnType = int.class; |
194 bt = int.class; |
180 } |
195 // adjust #slots, #args |
181 if (erasedPtypes == basicPtypes && basicReturnType == returnType) { |
196 if (rt == void.class) |
182 // Basic type |
197 rtypeCount = rslotCount = 0; |
|
198 else |
|
199 rslotCount += lrc; |
|
200 } |
|
201 if (epts == bpts && bt == rt) { |
|
202 this.basicType = erasedType; |
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]; |
203 } else { |
191 } else { |
204 this.basicType = MethodType.makeImpl(bt, bpts, true); |
192 this.basicType = MethodType.makeImpl(basicReturnType, basicPtypes, true); |
205 // fill in rest of data from the basic type: |
193 // fill in rest of data from the basic type: |
206 MethodTypeForm that = this.basicType.form(); |
194 MethodTypeForm that = this.basicType.form(); |
207 assert(this != that); |
195 assert(this != that); |
208 this.primCounts = that.primCounts; |
196 |
209 this.argCounts = that.argCounts; |
197 this.parameterSlotCount = that.parameterSlotCount; |
210 this.argToSlotTable = that.argToSlotTable; |
198 this.primitiveCount = that.primitiveCount; |
211 this.slotToArgTable = that.slotToArgTable; |
|
212 this.methodHandles = null; |
199 this.methodHandles = null; |
213 this.lambdaForms = null; |
200 this.lambdaForms = null; |
214 return; |
201 } |
215 } |
202 } |
216 if (lac != 0) { |
203 |
217 int slot = ptypeCount + lac; |
204 public int parameterCount() { |
218 slotToArgTab = new int[slot+1]; |
205 return erasedType.parameterCount(); |
219 argToSlotTab = new int[1+ptypeCount]; |
206 } |
220 argToSlotTab[0] = slot; // argument "-1" is past end of slots |
207 public int parameterSlotCount() { |
221 for (int i = 0; i < epts.length; i++) { |
208 return parameterSlotCount; |
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 } |
209 } |
295 public boolean hasPrimitives() { |
210 public boolean hasPrimitives() { |
296 return primCounts != 0; |
211 return primitiveCount != 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 } |
212 } |
315 |
213 |
316 static MethodTypeForm findForm(MethodType mt) { |
214 static MethodTypeForm findForm(MethodType mt) { |
317 MethodType erased = canonicalize(mt, ERASE, ERASE); |
215 MethodType erased = canonicalize(mt, ERASE, ERASE); |
318 if (erased == null) { |
216 if (erased == null) { |
332 * according to size. LONGS means convert all non-void primitives |
230 * according to size. LONGS means convert all non-void primitives |
333 * to long, regardless of size. RAW_RETURN means convert a type |
231 * 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, |
232 * (assumed to be a return type) to int if it is smaller than an int, |
335 * or if it is void. |
233 * or if it is void. |
336 */ |
234 */ |
337 public static final int NO_CHANGE = 0, ERASE = 1, WRAP = 2, UNWRAP = 3, INTS = 4, LONGS = 5, RAW_RETURN = 6; |
235 public static final int ERASE = 1, WRAP = 2, UNWRAP = 3, INTS = 4, LONGS = 5, RAW_RETURN = 6; |
338 |
236 |
339 /** Canonicalize the types in the given method type. |
237 /** Canonicalize the types in the given method type. |
340 * If any types change, intern the new type, and return it. |
238 * If any types change, intern the new type, and return it. |
341 * Otherwise return null. |
239 * Otherwise return null. |
342 */ |
240 */ |
343 public static MethodType canonicalize(MethodType mt, int howRet, int howArgs) { |
241 public static MethodType canonicalize(MethodType mt, int howRet, int howArgs) { |
344 Class<?>[] ptypes = mt.ptypes(); |
242 Class<?>[] ptypes = mt.ptypes(); |
345 Class<?>[] ptc = MethodTypeForm.canonicalizeAll(ptypes, howArgs); |
243 Class<?>[] ptypesCanonical = canonicalizeAll(ptypes, howArgs); |
346 Class<?> rtype = mt.returnType(); |
244 Class<?> rtype = mt.returnType(); |
347 Class<?> rtc = MethodTypeForm.canonicalize(rtype, howRet); |
245 Class<?> rtypeCanonical = canonicalize(rtype, howRet); |
348 if (ptc == null && rtc == null) { |
246 if (ptypesCanonical == null && rtypeCanonical == null) { |
349 // It is already canonical. |
247 // It is already canonical. |
350 return null; |
248 return null; |
351 } |
249 } |
352 // Find the erased version of the method type: |
250 // Find the erased version of the method type: |
353 if (rtc == null) rtc = rtype; |
251 if (rtypeCanonical == null) rtypeCanonical = rtype; |
354 if (ptc == null) ptc = ptypes; |
252 if (ptypesCanonical == null) ptypesCanonical = ptypes; |
355 return MethodType.makeImpl(rtc, ptc, true); |
253 return MethodType.makeImpl(rtypeCanonical, ptypesCanonical, true); |
356 } |
254 } |
357 |
255 |
358 /** Canonicalize the given return or param type. |
256 /** Canonicalize the given return or param type. |
359 * Return null if the type is already canonicalized. |
257 * Return null if the type is already canonicalized. |
360 */ |
258 */ |