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 volatile 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, /*forceInline=*/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, /*forceInline=*/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, /*forceInline=*/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 // Make a blank lambda form, which returns a constant zero or null.
295 // It is used as a template for managing the invocation of similar forms that are non-empty.
296 // Called only from getPreparedForm.
297 assert(isValidSignature(sig));
298 this.arity = signatureArity(sig);
299 this.result = (signatureReturn(sig) == V_TYPE ? -1 : arity);
300 this.names = buildEmptyNames(arity, sig);
301 this.debugName = "LF.zero";
302 this.forceInline = true;
303 assert(nameRefsAreLegal());
304 assert(isEmpty());
305 assert(sig.equals(basicTypeSignature())) : sig + " != " + basicTypeSignature();
306 }
307
308 private static Name[] buildEmptyNames(int arity, String basicTypeSignature) {
309 assert(isValidSignature(basicTypeSignature));
310 int resultPos = arity + 1; // skip '_'
311 if (arity < 0 || basicTypeSignature.length() != resultPos+1)
312 throw new IllegalArgumentException("bad arity for "+basicTypeSignature);
313 int numRes = (basicType(basicTypeSignature.charAt(resultPos)) == V_TYPE ? 0 : 1);
314 Name[] names = arguments(numRes, basicTypeSignature.substring(0, arity));
315 for (int i = 0; i < numRes; i++) {
316 Name zero = new Name(constantZero(basicType(basicTypeSignature.charAt(resultPos + i))));
317 names[arity + i] = zero.newIndex(arity + i);
318 }
319 return names;
320 }
321
322 private static int fixResult(int result, Name[] names) {
396 startFixing = changesStart+1;
397 for (int i = startFixing; i < names.length; i++) {
398 Name fixed = names[i].replaceNames(oldNames, names, changesStart, i);
399 names[i] = fixed.newIndex(i);
400 }
401 }
402 assert(nameRefsAreLegal());
403 int maxInterned = Math.min(arity, INTERNED_ARGUMENT_LIMIT);
404 boolean needIntern = false;
405 for (int i = 0; i < maxInterned; i++) {
406 Name n = names[i], n2 = internArgument(n);
407 if (n != n2) {
408 names[i] = n2;
409 needIntern = true;
410 }
411 }
412 if (needIntern) {
413 for (int i = arity; i < names.length; i++) {
414 names[i].internArguments();
415 }
416 assert(nameRefsAreLegal());
417 }
418 return maxOutArity;
419 }
420
421 /**
422 * Check that all embedded Name references are localizable to this lambda,
423 * and are properly ordered after their corresponding definitions.
424 * <p>
425 * Note that a Name can be local to multiple lambdas, as long as
426 * it possesses the same index in each use site.
427 * This allows Name references to be freely reused to construct
428 * fresh lambdas, without confusion.
429 */
430 boolean nameRefsAreLegal() {
431 assert(arity >= 0 && arity <= names.length);
432 assert(result >= -1 && result < names.length);
433 // Do all names possess an index consistent with their local definition order?
434 for (int i = 0; i < arity; i++) {
435 Name n = names[i];
436 assert(n.index() == i) : Arrays.asList(n.index(), i);
437 assert(n.isParam());
|
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 final MethodHandle customized;
124 @Stable final Name[] names;
125 final String debugName;
126 MemberName vmentry; // low-level behavior, or null if not yet prepared
127 private boolean isCompiled;
128
129 volatile Object transformCache; // managed by LambdaFormEditor
130
131 public static final int VOID_RESULT = -1, LAST_RESULT = -2;
132
133 enum BasicType {
134 L_TYPE('L', Object.class, Wrapper.OBJECT), // all reference types
135 I_TYPE('I', int.class, Wrapper.INT),
136 J_TYPE('J', long.class, Wrapper.LONG),
137 F_TYPE('F', float.class, Wrapper.FLOAT),
138 D_TYPE('D', double.class, Wrapper.DOUBLE), // all primitive types
139 V_TYPE('V', void.class, Wrapper.VOID); // not valid in all contexts
140
141 static final BasicType[] ALL_TYPES = BasicType.values();
142 static final BasicType[] ARG_TYPES = Arrays.copyOf(ALL_TYPES, ALL_TYPES.length-1);
143
228 return "LIJFD".indexOf(c) >= 0;
229 }
230
231 static { assert(checkBasicType()); }
232 private static boolean checkBasicType() {
233 for (int i = 0; i < ARG_TYPE_LIMIT; i++) {
234 assert ARG_TYPES[i].ordinal() == i;
235 assert ARG_TYPES[i] == ALL_TYPES[i];
236 }
237 for (int i = 0; i < TYPE_LIMIT; i++) {
238 assert ALL_TYPES[i].ordinal() == i;
239 }
240 assert ALL_TYPES[TYPE_LIMIT - 1] == V_TYPE;
241 assert !Arrays.asList(ARG_TYPES).contains(V_TYPE);
242 return true;
243 }
244 }
245
246 LambdaForm(String debugName,
247 int arity, Name[] names, int result) {
248 this(debugName, arity, names, result, /*forceInline=*/true, /*customized=*/null);
249 }
250 LambdaForm(String debugName,
251 int arity, Name[] names, int result, boolean forceInline, MethodHandle customized) {
252 assert(namesOK(arity, names));
253 this.arity = arity;
254 this.result = fixResult(result, names);
255 this.names = names.clone();
256 this.debugName = fixDebugName(debugName);
257 this.forceInline = forceInline;
258 this.customized = customized;
259 int maxOutArity = normalize();
260 if (maxOutArity > MethodType.MAX_MH_INVOKER_ARITY) {
261 // Cannot use LF interpreter on very high arity expressions.
262 assert(maxOutArity <= MethodType.MAX_JVM_ARITY);
263 compileToBytecode();
264 }
265 }
266 LambdaForm(String debugName,
267 int arity, Name[] names) {
268 this(debugName, arity, names, LAST_RESULT, /*forceInline=*/true, /*customized=*/null);
269 }
270 LambdaForm(String debugName,
271 int arity, Name[] names, boolean forceInline) {
272 this(debugName, arity, names, LAST_RESULT, forceInline, /*customized=*/null);
273 }
274 LambdaForm(String debugName,
275 Name[] formals, Name[] temps, Name result) {
276 this(debugName,
277 formals.length, buildNames(formals, temps, result), LAST_RESULT, /*forceInline=*/true, /*customized=*/null);
278 }
279 LambdaForm(String debugName,
280 Name[] formals, Name[] temps, Name result, boolean forceInline) {
281 this(debugName,
282 formals.length, buildNames(formals, temps, result), LAST_RESULT, forceInline, /*customized=*/null);
283 }
284
285 private static Name[] buildNames(Name[] formals, Name[] temps, Name result) {
286 int arity = formals.length;
287 int length = arity + temps.length + (result == null ? 0 : 1);
288 Name[] names = Arrays.copyOf(formals, length);
289 System.arraycopy(temps, 0, names, arity, temps.length);
290 if (result != null)
291 names[length - 1] = result;
292 return names;
293 }
294
295 private LambdaForm(String sig) {
296 // Make a blank lambda form, which returns a constant zero or null.
297 // It is used as a template for managing the invocation of similar forms that are non-empty.
298 // Called only from getPreparedForm.
299 assert(isValidSignature(sig));
300 this.arity = signatureArity(sig);
301 this.result = (signatureReturn(sig) == V_TYPE ? -1 : arity);
302 this.names = buildEmptyNames(arity, sig);
303 this.debugName = "LF.zero";
304 this.forceInline = true;
305 this.customized = null;
306 assert(nameRefsAreLegal());
307 assert(isEmpty());
308 assert(sig.equals(basicTypeSignature())) : sig + " != " + basicTypeSignature();
309 }
310
311 private static Name[] buildEmptyNames(int arity, String basicTypeSignature) {
312 assert(isValidSignature(basicTypeSignature));
313 int resultPos = arity + 1; // skip '_'
314 if (arity < 0 || basicTypeSignature.length() != resultPos+1)
315 throw new IllegalArgumentException("bad arity for "+basicTypeSignature);
316 int numRes = (basicType(basicTypeSignature.charAt(resultPos)) == V_TYPE ? 0 : 1);
317 Name[] names = arguments(numRes, basicTypeSignature.substring(0, arity));
318 for (int i = 0; i < numRes; i++) {
319 Name zero = new Name(constantZero(basicType(basicTypeSignature.charAt(resultPos + i))));
320 names[arity + i] = zero.newIndex(arity + i);
321 }
322 return names;
323 }
324
325 private static int fixResult(int result, Name[] names) {
399 startFixing = changesStart+1;
400 for (int i = startFixing; i < names.length; i++) {
401 Name fixed = names[i].replaceNames(oldNames, names, changesStart, i);
402 names[i] = fixed.newIndex(i);
403 }
404 }
405 assert(nameRefsAreLegal());
406 int maxInterned = Math.min(arity, INTERNED_ARGUMENT_LIMIT);
407 boolean needIntern = false;
408 for (int i = 0; i < maxInterned; i++) {
409 Name n = names[i], n2 = internArgument(n);
410 if (n != n2) {
411 names[i] = n2;
412 needIntern = true;
413 }
414 }
415 if (needIntern) {
416 for (int i = arity; i < names.length; i++) {
417 names[i].internArguments();
418 }
419 }
420 assert(nameRefsAreLegal());
421 return maxOutArity;
422 }
423
424 /**
425 * Check that all embedded Name references are localizable to this lambda,
426 * and are properly ordered after their corresponding definitions.
427 * <p>
428 * Note that a Name can be local to multiple lambdas, as long as
429 * it possesses the same index in each use site.
430 * This allows Name references to be freely reused to construct
431 * fresh lambdas, without confusion.
432 */
433 boolean nameRefsAreLegal() {
434 assert(arity >= 0 && arity <= names.length);
435 assert(result >= -1 && result < names.length);
436 // Do all names possess an index consistent with their local definition order?
437 for (int i = 0; i < arity; i++) {
438 Name n = names[i];
439 assert(n.index() == i) : Arrays.asList(n.index(), i);
440 assert(n.isParam());
|