102 * (a0:L, a1:L)=>{ t2:L = FilterMethodHandle#filter(a0);
103 * t3:L = MethodHandle#invoke(t2, a1);
104 * t4:L = FilterMethodHandle#target(a0);
105 * t5:L = MethodHandle#invoke(t4, t3); t5 }
106 * == general invoker for unary filterArgument combination
107 * (a0:L, a1:L)=>{ ...(same as previous example)...
108 * t5:L = MethodHandle#invoke(t4, t3, a1); t5 }
109 * == general invoker for unary/unary foldArgument combination
110 * (a0:L, a1:I)=>{ t2:I = identity(long).asType((int)->long)(a1); t2 }
111 * == invoker for identity method handle which performs i2l
112 * (a0:L, a1:L)=>{ t2:L = BoundMethodHandle#argument(a0);
113 * t3:L = Class#cast(t2,a1); t3 }
114 * == invoker for identity method handle which performs cast
115 * }</pre></blockquote>
116 * <p>
117 * @author John Rose, JSR 292 EG
118 */
119 class LambdaForm {
120 final int arity;
121 final int result;
122 @Stable final Name[] names;
123 final String debugName;
124 MemberName vmentry; // low-level behavior, or null if not yet prepared
125 private boolean isCompiled;
126
127 Object transformCache; // managed by LambdaFormEditor
128
129 public static final int VOID_RESULT = -1, LAST_RESULT = -2;
130
131 enum BasicType {
132 L_TYPE('L', Object.class, Wrapper.OBJECT), // all reference types
133 I_TYPE('I', int.class, Wrapper.INT),
134 J_TYPE('J', long.class, Wrapper.LONG),
135 F_TYPE('F', float.class, Wrapper.FLOAT),
136 D_TYPE('D', double.class, Wrapper.DOUBLE), // all primitive types
137 V_TYPE('V', void.class, Wrapper.VOID); // not valid in all contexts
138
139 static final BasicType[] ALL_TYPES = BasicType.values();
140 static final BasicType[] ARG_TYPES = Arrays.copyOf(ALL_TYPES, ALL_TYPES.length-1);
141
226 return "LIJFD".indexOf(c) >= 0;
227 }
228
229 static { assert(checkBasicType()); }
230 private static boolean checkBasicType() {
231 for (int i = 0; i < ARG_TYPE_LIMIT; i++) {
232 assert ARG_TYPES[i].ordinal() == i;
233 assert ARG_TYPES[i] == ALL_TYPES[i];
234 }
235 for (int i = 0; i < TYPE_LIMIT; i++) {
236 assert ALL_TYPES[i].ordinal() == i;
237 }
238 assert ALL_TYPES[TYPE_LIMIT - 1] == V_TYPE;
239 assert !Arrays.asList(ARG_TYPES).contains(V_TYPE);
240 return true;
241 }
242 }
243
244 LambdaForm(String debugName,
245 int arity, Name[] names, int result) {
246 assert(namesOK(arity, names));
247 this.arity = arity;
248 this.result = fixResult(result, names);
249 this.names = names.clone();
250 this.debugName = fixDebugName(debugName);
251 int maxOutArity = normalize();
252 if (maxOutArity > MethodType.MAX_MH_INVOKER_ARITY) {
253 // Cannot use LF interpreter on very high arity expressions.
254 assert(maxOutArity <= MethodType.MAX_JVM_ARITY);
255 compileToBytecode();
256 }
257 }
258
259 LambdaForm(String debugName,
260 int arity, Name[] names) {
261 this(debugName,
262 arity, names, LAST_RESULT);
263 }
264
265 LambdaForm(String debugName,
266 Name[] formals, Name[] temps, Name result) {
267 this(debugName,
268 formals.length, buildNames(formals, temps, result), LAST_RESULT);
269 }
270
271 private static Name[] buildNames(Name[] formals, Name[] temps, Name result) {
272 int arity = formals.length;
273 int length = arity + temps.length + (result == null ? 0 : 1);
274 Name[] names = Arrays.copyOf(formals, length);
275 System.arraycopy(temps, 0, names, arity, temps.length);
276 if (result != null)
277 names[length - 1] = result;
278 return names;
279 }
280
281 private LambdaForm(String sig) {
282 // Make a blank lambda form, which returns a constant zero or null.
283 // It is used as a template for managing the invocation of similar forms that are non-empty.
284 // Called only from getPreparedForm.
285 assert(isValidSignature(sig));
286 this.arity = signatureArity(sig);
287 this.result = (signatureReturn(sig) == V_TYPE ? -1 : arity);
288 this.names = buildEmptyNames(arity, sig);
289 this.debugName = "LF.zero";
290 assert(nameRefsAreLegal());
291 assert(isEmpty());
292 assert(sig.equals(basicTypeSignature())) : sig + " != " + basicTypeSignature();
293 }
294
295 private static Name[] buildEmptyNames(int arity, String basicTypeSignature) {
296 assert(isValidSignature(basicTypeSignature));
297 int resultPos = arity + 1; // skip '_'
298 if (arity < 0 || basicTypeSignature.length() != resultPos+1)
299 throw new IllegalArgumentException("bad arity for "+basicTypeSignature);
300 int numRes = (basicType(basicTypeSignature.charAt(resultPos)) == V_TYPE ? 0 : 1);
301 Name[] names = arguments(numRes, basicTypeSignature.substring(0, arity));
302 for (int i = 0; i < numRes; i++) {
303 Name zero = new Name(constantZero(basicType(basicTypeSignature.charAt(resultPos + i))));
304 names[arity + i] = zero.newIndex(arity + i);
305 }
306 return names;
307 }
308
309 private static int fixResult(int result, Name[] names) {
|
102 * (a0:L, a1:L)=>{ t2:L = FilterMethodHandle#filter(a0);
103 * t3:L = MethodHandle#invoke(t2, a1);
104 * t4:L = FilterMethodHandle#target(a0);
105 * t5:L = MethodHandle#invoke(t4, t3); t5 }
106 * == general invoker for unary filterArgument combination
107 * (a0:L, a1:L)=>{ ...(same as previous example)...
108 * t5:L = MethodHandle#invoke(t4, t3, a1); t5 }
109 * == general invoker for unary/unary foldArgument combination
110 * (a0:L, a1:I)=>{ t2:I = identity(long).asType((int)->long)(a1); t2 }
111 * == invoker for identity method handle which performs i2l
112 * (a0:L, a1:L)=>{ t2:L = BoundMethodHandle#argument(a0);
113 * t3:L = Class#cast(t2,a1); t3 }
114 * == invoker for identity method handle which performs cast
115 * }</pre></blockquote>
116 * <p>
117 * @author John Rose, JSR 292 EG
118 */
119 class LambdaForm {
120 final int arity;
121 final int result;
122 final boolean forceInline;
123 @Stable final Name[] names;
124 final String debugName;
125 MemberName vmentry; // low-level behavior, or null if not yet prepared
126 private boolean isCompiled;
127
128 Object transformCache; // managed by LambdaFormEditor
129
130 public static final int VOID_RESULT = -1, LAST_RESULT = -2;
131
132 enum BasicType {
133 L_TYPE('L', Object.class, Wrapper.OBJECT), // all reference types
134 I_TYPE('I', int.class, Wrapper.INT),
135 J_TYPE('J', long.class, Wrapper.LONG),
136 F_TYPE('F', float.class, Wrapper.FLOAT),
137 D_TYPE('D', double.class, Wrapper.DOUBLE), // all primitive types
138 V_TYPE('V', void.class, Wrapper.VOID); // not valid in all contexts
139
140 static final BasicType[] ALL_TYPES = BasicType.values();
141 static final BasicType[] ARG_TYPES = Arrays.copyOf(ALL_TYPES, ALL_TYPES.length-1);
142
227 return "LIJFD".indexOf(c) >= 0;
228 }
229
230 static { assert(checkBasicType()); }
231 private static boolean checkBasicType() {
232 for (int i = 0; i < ARG_TYPE_LIMIT; i++) {
233 assert ARG_TYPES[i].ordinal() == i;
234 assert ARG_TYPES[i] == ALL_TYPES[i];
235 }
236 for (int i = 0; i < TYPE_LIMIT; i++) {
237 assert ALL_TYPES[i].ordinal() == i;
238 }
239 assert ALL_TYPES[TYPE_LIMIT - 1] == V_TYPE;
240 assert !Arrays.asList(ARG_TYPES).contains(V_TYPE);
241 return true;
242 }
243 }
244
245 LambdaForm(String debugName,
246 int arity, Name[] names, int result) {
247 this(debugName, arity, names, result, true);
248 }
249 LambdaForm(String debugName,
250 int arity, Name[] names, int result, boolean forceInline) {
251 assert(namesOK(arity, names));
252 this.arity = arity;
253 this.result = fixResult(result, names);
254 this.names = names.clone();
255 this.debugName = fixDebugName(debugName);
256 this.forceInline = forceInline;
257 int maxOutArity = normalize();
258 if (maxOutArity > MethodType.MAX_MH_INVOKER_ARITY) {
259 // Cannot use LF interpreter on very high arity expressions.
260 assert(maxOutArity <= MethodType.MAX_JVM_ARITY);
261 compileToBytecode();
262 }
263 }
264 LambdaForm(String debugName,
265 int arity, Name[] names) {
266 this(debugName, arity, names, LAST_RESULT, true);
267 }
268 LambdaForm(String debugName,
269 int arity, Name[] names, boolean forceInline) {
270 this(debugName, arity, names, LAST_RESULT, forceInline);
271 }
272 LambdaForm(String debugName,
273 Name[] formals, Name[] temps, Name result) {
274 this(debugName,
275 formals.length, buildNames(formals, temps, result), LAST_RESULT, true);
276 }
277 LambdaForm(String debugName,
278 Name[] formals, Name[] temps, Name result, boolean forceInline) {
279 this(debugName,
280 formals.length, buildNames(formals, temps, result), LAST_RESULT, forceInline);
281 }
282
283 private static Name[] buildNames(Name[] formals, Name[] temps, Name result) {
284 int arity = formals.length;
285 int length = arity + temps.length + (result == null ? 0 : 1);
286 Name[] names = Arrays.copyOf(formals, length);
287 System.arraycopy(temps, 0, names, arity, temps.length);
288 if (result != null)
289 names[length - 1] = result;
290 return names;
291 }
292
293 private LambdaForm(String sig) {
294 this(sig, true);
295 }
296
297 private LambdaForm(String sig, boolean forceInline) {
298 // Make a blank lambda form, which returns a constant zero or null.
299 // It is used as a template for managing the invocation of similar forms that are non-empty.
300 // Called only from getPreparedForm.
301 assert(isValidSignature(sig));
302 this.arity = signatureArity(sig);
303 this.result = (signatureReturn(sig) == V_TYPE ? -1 : arity);
304 this.names = buildEmptyNames(arity, sig);
305 this.debugName = "LF.zero";
306 this.forceInline = forceInline;
307 assert(nameRefsAreLegal());
308 assert(isEmpty());
309 assert(sig.equals(basicTypeSignature())) : sig + " != " + basicTypeSignature();
310 }
311
312 private static Name[] buildEmptyNames(int arity, String basicTypeSignature) {
313 assert(isValidSignature(basicTypeSignature));
314 int resultPos = arity + 1; // skip '_'
315 if (arity < 0 || basicTypeSignature.length() != resultPos+1)
316 throw new IllegalArgumentException("bad arity for "+basicTypeSignature);
317 int numRes = (basicType(basicTypeSignature.charAt(resultPos)) == V_TYPE ? 0 : 1);
318 Name[] names = arguments(numRes, basicTypeSignature.substring(0, arity));
319 for (int i = 0; i < numRes; i++) {
320 Name zero = new Name(constantZero(basicType(basicTypeSignature.charAt(resultPos + i))));
321 names[arity + i] = zero.newIndex(arity + i);
322 }
323 return names;
324 }
325
326 private static int fixResult(int result, Name[] names) {
|