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 */
46 final 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
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
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);
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);
|
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 */
46 final 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 final MethodHandle[] methodHandles;
55 // Indexes into methodHandles:
56 static final int
57 MH_BASIC_INV = 0, // cached instance of MH.invokeBasic
58 MH_NF_INV = 1, // cached helper for LF.NamedFunction
59 MH_UNINIT_CS = 2, // uninitialized call site
60 MH_LIMIT = 3;
61
62 // Cached lambda form information, for basic types only:
63 final @Stable LambdaForm[] lambdaForms;
64 // Indexes into lambdaForms:
65 static final int
66 LF_INVVIRTUAL = 0, // DMH invokeVirtual
67 LF_INVSTATIC = 1,
68 LF_INVSPECIAL = 2,
69 LF_NEWINVSPECIAL = 3,
70 LF_INVINTERFACE = 4,
71 LF_INVSTATIC_INIT = 5, // DMH invokeStatic with <clinit> barrier
72 LF_INTERPRET = 6, // LF interpreter
73 LF_COUNTER = 7, // CMH wrapper
74 LF_REINVOKE = 8, // other wrapper
75 LF_EX_LINKER = 9, // invokeExact_MT (for invokehandle)
76 LF_EX_INVOKER = 10, // MHs.invokeExact
77 LF_GEN_LINKER = 11, // generic invoke_MT (for invokehandle)
78 LF_GEN_INVOKER = 12, // generic MHs.invoke
79 LF_CS_LINKER = 13, // linkToCallSite_CS
80 LF_MH_LINKER = 14, // linkToCallSite_MH
87 public MethodType erasedType() {
88 return erasedType;
89 }
90
91 /** Return the basic type derived from the erased type of this MT-form.
92 * A basic type is erased (all references Object) and also has all primitive
93 * types (except int, long, float, double, void) normalized to int.
94 * Such basic types correspond to low-level JVM calling sequences.
95 */
96 public MethodType basicType() {
97 return basicType;
98 }
99
100 private boolean assertIsBasicType() {
101 // primitives must be flattened also
102 assert(erasedType == basicType)
103 : "erasedType: " + erasedType + " != basicType: " + basicType;
104 return true;
105 }
106
107 public MethodHandle cachedMethodHandle(int which) {
108 assert(assertIsBasicType());
109 return methodHandles[which];
110 }
111
112 synchronized public MethodHandle setCachedMethodHandle(int which, MethodHandle mh) {
113 // Simulate a CAS, to avoid racy duplication of results.
114 MethodHandle prev = methodHandles[which];
115 if (prev != null) return prev;
116 return methodHandles[which] = mh;
117 }
118
119 public LambdaForm cachedLambdaForm(int which) {
120 assert(assertIsBasicType());
121 return lambdaForms[which];
122 }
123
124 synchronized public LambdaForm setCachedLambdaForm(int which, LambdaForm form) {
125 // Simulate a CAS, to avoid racy duplication of results.
126 LambdaForm prev = lambdaForms[which];
127 if (prev != null) return prev;
128 return lambdaForms[which] = form;
129 }
130
131 /**
132 * Build an MTF for a given type, which must have all references erased to Object.
133 * This MTF will stand for that type and all un-erased variations.
134 * Eagerly compute some basic properties of the type, common to all variations.
135 */
136 protected MethodTypeForm(MethodType erasedType) {
137 this.erasedType = erasedType;
138
170 if (w.isDoubleWord()) ++lrc;
171 if (w.isSubwordOrInt() && rt != int.class)
172 bt = int.class;
173 // adjust #slots, #args
174 if (rt == void.class)
175 rtypeCount = rslotCount = 0;
176 else
177 rslotCount += lrc;
178 }
179 if (epts == bpts && bt == rt) {
180 this.basicType = erasedType;
181 } else {
182 this.basicType = MethodType.makeImpl(bt, bpts, true);
183 // fill in rest of data from the basic type:
184 MethodTypeForm that = this.basicType.form();
185 assert(this != that);
186 this.primCounts = that.primCounts;
187 this.argCounts = that.argCounts;
188 this.argToSlotTable = that.argToSlotTable;
189 this.slotToArgTable = that.slotToArgTable;
190 this.methodHandles = null;
191 this.lambdaForms = null;
192 return;
193 }
194 if (lac != 0) {
195 int slot = ptypeCount + lac;
196 slotToArgTab = new int[slot+1];
197 argToSlotTab = new int[1+ptypeCount];
198 argToSlotTab[0] = slot; // argument "-1" is past end of slots
199 for (int i = 0; i < epts.length; i++) {
200 Class<?> pt = epts[i];
201 Wrapper w = Wrapper.forBasicType(pt);
202 if (w.isDoubleWord()) --slot;
203 --slot;
204 slotToArgTab[slot] = i+1; // "+1" see argSlotToParameter note
205 argToSlotTab[1+i] = slot;
206 }
207 assert(slot == 0); // filled the table
208 } else if (pac != 0) {
209 // have primitives but no long primitives; share slot counts with generic
210 assert(ptypeCount == pslotCount);
216 int slot = ptypeCount; // first arg is deepest in stack
217 slotToArgTab = new int[slot+1];
218 argToSlotTab = new int[1+ptypeCount];
219 argToSlotTab[0] = slot; // argument "-1" is past end of slots
220 for (int i = 0; i < ptypeCount; i++) {
221 --slot;
222 slotToArgTab[slot] = i+1; // "+1" see argSlotToParameter note
223 argToSlotTab[1+i] = slot;
224 }
225 }
226 this.primCounts = pack(lrc, prc, lac, pac);
227 this.argCounts = pack(rslotCount, rtypeCount, pslotCount, ptypeCount);
228 this.argToSlotTable = argToSlotTab;
229 this.slotToArgTable = slotToArgTab;
230
231 if (pslotCount >= 256) throw newIllegalArgumentException("too many arguments");
232
233 // Initialize caches, but only for basic types
234 assert(basicType == erasedType);
235 this.lambdaForms = new LambdaForm[LF_LIMIT];
236 this.methodHandles = new MethodHandle[MH_LIMIT];
237 }
238
239 private static long pack(int a, int b, int c, int d) {
240 assert(((a|b|c|d) & ~0xFFFF) == 0);
241 long hw = ((a << 16) | b), lw = ((c << 16) | d);
242 return (hw << 32) | lw;
243 }
244 private static char unpack(long packed, int word) { // word==0 => return a, ==3 => return d
245 assert(word <= 3);
246 return (char)(packed >> ((3-word) * 16));
247 }
248
249 public int parameterCount() { // # outgoing values
250 return unpack(argCounts, 3);
251 }
252 public int parameterSlotCount() { // # outgoing interpreter slots
253 return unpack(argCounts, 2);
254 }
255 public int returnCount() { // = 0 (V), or 1
256 return unpack(argCounts, 1);
|