rev 15544 : imported patch fold_select
rev 15545 : imported patch noperm
1 /*
2 * Copyright (c) 2014, 2016, Oracle and/or its affiliates. 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. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package java.lang.invoke;
27
28 import sun.invoke.util.Wrapper;
29
30 import java.lang.ref.SoftReference;
31 import java.util.Arrays;
32 import java.util.Collections;
33 import java.util.concurrent.ConcurrentHashMap;
34
35 import static java.lang.invoke.LambdaForm.*;
36 import static java.lang.invoke.LambdaForm.BasicType.*;
37 import static java.lang.invoke.MethodHandleImpl.Intrinsic;
38 import static java.lang.invoke.MethodHandleImpl.NF_loop;
39
40 /** Transforms on LFs.
41 * A lambda-form editor can derive new LFs from its base LF.
42 * The editor can cache derived LFs, which simplifies the reuse of their underlying bytecodes.
43 * To support this caching, a LF has an optional pointer to its editor.
44 */
45 class LambdaFormEditor {
46 final LambdaForm lambdaForm;
47
48 private LambdaFormEditor(LambdaForm lambdaForm) {
49 this.lambdaForm = lambdaForm;
50 }
51
52 // Factory method.
53 static LambdaFormEditor lambdaFormEditor(LambdaForm lambdaForm) {
54 // TO DO: Consider placing intern logic here, to cut down on duplication.
55 // lambdaForm = findPreexistingEquivalent(lambdaForm)
56
57 // Always use uncustomized version for editing.
58 // It helps caching and customized LambdaForms reuse transformCache field to keep a link to uncustomized version.
59 return new LambdaFormEditor(lambdaForm.uncustomize());
60 }
61
62 /** A description of a cached transform, possibly associated with the result of the transform.
63 * The logical content is a sequence of byte values, starting with a kind value.
64 * The sequence is unterminated, ending with an indefinite number of zero bytes.
65 * Sequences that are simple (short enough and with small enough values) pack into a 64-bit long.
66 */
67 private static final class Transform extends SoftReference<LambdaForm> {
68 final long packedBytes;
69 final byte[] fullBytes;
70
71 // maybe add more for guard with test, catch exception, pointwise type conversions
72 private static final byte
73 BIND_ARG = 1,
74 ADD_ARG = 2,
75 DUP_ARG = 3,
76 SPREAD_ARGS = 4,
77 FILTER_ARG = 5,
78 FILTER_RETURN = 6,
79 FILTER_RETURN_TO_ZERO = 7,
80 COLLECT_ARGS = 8,
81 COLLECT_ARGS_TO_VOID = 9,
82 COLLECT_ARGS_TO_ARRAY = 10,
83 FOLD_ARGS = 11,
84 FOLD_ARGS_TO_VOID = 12,
85 PERMUTE_ARGS = 13,
86 LOCAL_TYPES = 14;
87
88 private static final boolean STRESS_TEST = false; // turn on to disable most packing
89 private static final int
90 PACKED_BYTE_SIZE = (STRESS_TEST ? 2 : 4),
91 PACKED_BYTE_MASK = (1 << PACKED_BYTE_SIZE) - 1,
92 PACKED_BYTE_MAX_LENGTH = (STRESS_TEST ? 3 : 64 / PACKED_BYTE_SIZE);
93
94 private static long packedBytes(byte[] bytes) {
95 if (bytes.length > PACKED_BYTE_MAX_LENGTH) return 0;
96 long pb = 0;
97 int bitset = 0;
98 for (int i = 0; i < bytes.length; i++) {
99 int b = bytes[i] & 0xFF;
100 bitset |= b;
101 pb |= (long)b << (i * PACKED_BYTE_SIZE);
102 }
103 if (!inRange(bitset))
104 return 0;
105 return pb;
106 }
107 private static long packedBytes(int b0, int b1) {
108 assert(inRange(b0 | b1));
109 return ( (b0 << 0*PACKED_BYTE_SIZE)
110 | (b1 << 1*PACKED_BYTE_SIZE));
111 }
112 private static long packedBytes(int b0, int b1, int b2) {
113 assert(inRange(b0 | b1 | b2));
114 return ( (b0 << 0*PACKED_BYTE_SIZE)
115 | (b1 << 1*PACKED_BYTE_SIZE)
116 | (b2 << 2*PACKED_BYTE_SIZE));
117 }
118 private static long packedBytes(int b0, int b1, int b2, int b3) {
119 assert(inRange(b0 | b1 | b2 | b3));
120 return ( (b0 << 0*PACKED_BYTE_SIZE)
121 | (b1 << 1*PACKED_BYTE_SIZE)
122 | (b2 << 2*PACKED_BYTE_SIZE)
123 | (b3 << 3*PACKED_BYTE_SIZE));
124 }
125 private static boolean inRange(int bitset) {
126 assert((bitset & 0xFF) == bitset); // incoming values must fit in *unsigned* byte
127 return ((bitset & ~PACKED_BYTE_MASK) == 0);
128 }
129 private static byte[] fullBytes(int... byteValues) {
130 byte[] bytes = new byte[byteValues.length];
131 int i = 0;
132 for (int bv : byteValues) {
133 bytes[i++] = bval(bv);
134 }
135 assert(packedBytes(bytes) == 0);
136 return bytes;
137 }
138
139 private Transform(long packedBytes, byte[] fullBytes, LambdaForm result) {
140 super(result);
141 this.packedBytes = packedBytes;
142 this.fullBytes = fullBytes;
143 }
144 private Transform(long packedBytes) {
145 this(packedBytes, null, null);
146 assert(packedBytes != 0);
147 }
148 private Transform(byte[] fullBytes) {
149 this(0, fullBytes, null);
150 }
151
152 private static byte bval(int b) {
153 assert((b & 0xFF) == b); // incoming value must fit in *unsigned* byte
154 return (byte)b;
155 }
156 static Transform of(byte k, int b1) {
157 byte b0 = bval(k);
158 if (inRange(b0 | b1))
159 return new Transform(packedBytes(b0, b1));
160 else
161 return new Transform(fullBytes(b0, b1));
162 }
163 static Transform of(byte b0, int b1, int b2) {
164 if (inRange(b0 | b1 | b2))
165 return new Transform(packedBytes(b0, b1, b2));
166 else
167 return new Transform(fullBytes(b0, b1, b2));
168 }
169 static Transform of(byte b0, int b1, int b2, int b3) {
170 if (inRange(b0 | b1 | b2 | b3))
171 return new Transform(packedBytes(b0, b1, b2, b3));
172 else
173 return new Transform(fullBytes(b0, b1, b2, b3));
174 }
175 private static final byte[] NO_BYTES = {};
176 static Transform of(byte kind, int... b123) {
177 return ofBothArrays(kind, b123, NO_BYTES);
178 }
179 static Transform of(byte kind, int b1, byte[] b234) {
180 return ofBothArrays(kind, new int[]{ b1 }, b234);
181 }
182 static Transform of(byte kind, int b1, int b2, byte[] b345) {
183 return ofBothArrays(kind, new int[]{ b1, b2 }, b345);
184 }
185 private static Transform ofBothArrays(byte kind, int[] b123, byte[] b456) {
186 byte[] fullBytes = new byte[1 + b123.length + b456.length];
187 int i = 0;
188 fullBytes[i++] = bval(kind);
189 for (int bv : b123) {
190 fullBytes[i++] = bval(bv);
191 }
192 for (byte bv : b456) {
193 fullBytes[i++] = bv;
194 }
195 long packedBytes = packedBytes(fullBytes);
196 if (packedBytes != 0)
197 return new Transform(packedBytes);
198 else
199 return new Transform(fullBytes);
200 }
201
202 Transform withResult(LambdaForm result) {
203 return new Transform(this.packedBytes, this.fullBytes, result);
204 }
205
206 @Override
207 public boolean equals(Object obj) {
208 return obj instanceof Transform && equals((Transform)obj);
209 }
210 public boolean equals(Transform that) {
211 return this.packedBytes == that.packedBytes && Arrays.equals(this.fullBytes, that.fullBytes);
212 }
213 @Override
214 public int hashCode() {
215 if (packedBytes != 0) {
216 assert(fullBytes == null);
217 return Long.hashCode(packedBytes);
218 }
219 return Arrays.hashCode(fullBytes);
220 }
221 @Override
222 public String toString() {
223 StringBuilder buf = new StringBuilder();
224 long bits = packedBytes;
225 if (bits != 0) {
226 buf.append("(");
227 while (bits != 0) {
228 buf.append(bits & PACKED_BYTE_MASK);
229 bits >>>= PACKED_BYTE_SIZE;
230 if (bits != 0) buf.append(",");
231 }
232 buf.append(")");
233 }
234 if (fullBytes != null) {
235 buf.append("unpacked");
236 buf.append(Arrays.toString(fullBytes));
237 }
238 LambdaForm result = get();
239 if (result != null) {
240 buf.append(" result=");
241 buf.append(result);
242 }
243 return buf.toString();
244 }
245 }
246
247 /** Find a previously cached transform equivalent to the given one, and return its result. */
248 private LambdaForm getInCache(Transform key) {
249 assert(key.get() == null);
250 // The transformCache is one of null, Transform, Transform[], or ConcurrentHashMap.
251 Object c = lambdaForm.transformCache;
252 Transform k = null;
253 if (c instanceof ConcurrentHashMap) {
254 @SuppressWarnings("unchecked")
255 ConcurrentHashMap<Transform,Transform> m = (ConcurrentHashMap<Transform,Transform>) c;
256 k = m.get(key);
257 } else if (c == null) {
258 return null;
259 } else if (c instanceof Transform) {
260 // one-element cache avoids overhead of an array
261 Transform t = (Transform)c;
262 if (t.equals(key)) k = t;
263 } else {
264 Transform[] ta = (Transform[])c;
265 for (int i = 0; i < ta.length; i++) {
266 Transform t = ta[i];
267 if (t == null) break;
268 if (t.equals(key)) { k = t; break; }
269 }
270 }
271 assert(k == null || key.equals(k));
272 return (k != null) ? k.get() : null;
273 }
274
275 /** Arbitrary but reasonable limits on Transform[] size for cache. */
276 private static final int MIN_CACHE_ARRAY_SIZE = 4, MAX_CACHE_ARRAY_SIZE = 16;
277
278 /** Cache a transform with its result, and return that result.
279 * But if an equivalent transform has already been cached, return its result instead.
280 */
281 private LambdaForm putInCache(Transform key, LambdaForm form) {
282 key = key.withResult(form);
283 for (int pass = 0; ; pass++) {
284 Object c = lambdaForm.transformCache;
285 if (c instanceof ConcurrentHashMap) {
286 @SuppressWarnings("unchecked")
287 ConcurrentHashMap<Transform,Transform> m = (ConcurrentHashMap<Transform,Transform>) c;
288 Transform k = m.putIfAbsent(key, key);
289 if (k == null) return form;
290 LambdaForm result = k.get();
291 if (result != null) {
292 return result;
293 } else {
294 if (m.replace(key, k, key)) {
295 return form;
296 } else {
297 continue;
298 }
299 }
300 }
301 assert(pass == 0);
302 synchronized (lambdaForm) {
303 c = lambdaForm.transformCache;
304 if (c instanceof ConcurrentHashMap)
305 continue;
306 if (c == null) {
307 lambdaForm.transformCache = key;
308 return form;
309 }
310 Transform[] ta;
311 if (c instanceof Transform) {
312 Transform k = (Transform)c;
313 if (k.equals(key)) {
314 LambdaForm result = k.get();
315 if (result == null) {
316 lambdaForm.transformCache = key;
317 return form;
318 } else {
319 return result;
320 }
321 } else if (k.get() == null) { // overwrite stale entry
322 lambdaForm.transformCache = key;
323 return form;
324 }
325 // expand one-element cache to small array
326 ta = new Transform[MIN_CACHE_ARRAY_SIZE];
327 ta[0] = k;
328 lambdaForm.transformCache = ta;
329 } else {
330 // it is already expanded
331 ta = (Transform[])c;
332 }
333 int len = ta.length;
334 int stale = -1;
335 int i;
336 for (i = 0; i < len; i++) {
337 Transform k = ta[i];
338 if (k == null) {
339 break;
340 }
341 if (k.equals(key)) {
342 LambdaForm result = k.get();
343 if (result == null) {
344 ta[i] = key;
345 return form;
346 } else {
347 return result;
348 }
349 } else if (stale < 0 && k.get() == null) {
350 stale = i; // remember 1st stale entry index
351 }
352 }
353 if (i < len || stale >= 0) {
354 // just fall through to cache update
355 } else if (len < MAX_CACHE_ARRAY_SIZE) {
356 len = Math.min(len * 2, MAX_CACHE_ARRAY_SIZE);
357 ta = Arrays.copyOf(ta, len);
358 lambdaForm.transformCache = ta;
359 } else {
360 ConcurrentHashMap<Transform, Transform> m = new ConcurrentHashMap<>(MAX_CACHE_ARRAY_SIZE * 2);
361 for (Transform k : ta) {
362 m.put(k, k);
363 }
364 lambdaForm.transformCache = m;
365 // The second iteration will update for this query, concurrently.
366 continue;
367 }
368 int idx = (stale >= 0) ? stale : i;
369 ta[idx] = key;
370 return form;
371 }
372 }
373 }
374
375 private LambdaFormBuffer buffer() {
376 return new LambdaFormBuffer(lambdaForm);
377 }
378
379 /// Editing methods for method handles. These need to have fast paths.
380
381 private BoundMethodHandle.SpeciesData oldSpeciesData() {
382 return BoundMethodHandle.speciesData(lambdaForm);
383 }
384 private BoundMethodHandle.SpeciesData newSpeciesData(BasicType type) {
385 return oldSpeciesData().extendWith(type);
386 }
387
388 BoundMethodHandle bindArgumentL(BoundMethodHandle mh, int pos, Object value) {
389 assert(mh.speciesData() == oldSpeciesData());
390 BasicType bt = L_TYPE;
391 MethodType type2 = bindArgumentType(mh, pos, bt);
392 LambdaForm form2 = bindArgumentForm(1+pos);
393 return mh.copyWithExtendL(type2, form2, value);
394 }
395 BoundMethodHandle bindArgumentI(BoundMethodHandle mh, int pos, int value) {
396 assert(mh.speciesData() == oldSpeciesData());
397 BasicType bt = I_TYPE;
398 MethodType type2 = bindArgumentType(mh, pos, bt);
399 LambdaForm form2 = bindArgumentForm(1+pos);
400 return mh.copyWithExtendI(type2, form2, value);
401 }
402
403 BoundMethodHandle bindArgumentJ(BoundMethodHandle mh, int pos, long value) {
404 assert(mh.speciesData() == oldSpeciesData());
405 BasicType bt = J_TYPE;
406 MethodType type2 = bindArgumentType(mh, pos, bt);
407 LambdaForm form2 = bindArgumentForm(1+pos);
408 return mh.copyWithExtendJ(type2, form2, value);
409 }
410
411 BoundMethodHandle bindArgumentF(BoundMethodHandle mh, int pos, float value) {
412 assert(mh.speciesData() == oldSpeciesData());
413 BasicType bt = F_TYPE;
414 MethodType type2 = bindArgumentType(mh, pos, bt);
415 LambdaForm form2 = bindArgumentForm(1+pos);
416 return mh.copyWithExtendF(type2, form2, value);
417 }
418
419 BoundMethodHandle bindArgumentD(BoundMethodHandle mh, int pos, double value) {
420 assert(mh.speciesData() == oldSpeciesData());
421 BasicType bt = D_TYPE;
422 MethodType type2 = bindArgumentType(mh, pos, bt);
423 LambdaForm form2 = bindArgumentForm(1+pos);
424 return mh.copyWithExtendD(type2, form2, value);
425 }
426
427 private MethodType bindArgumentType(BoundMethodHandle mh, int pos, BasicType bt) {
428 assert(mh.form.uncustomize() == lambdaForm);
429 assert(mh.form.names[1+pos].type == bt);
430 assert(BasicType.basicType(mh.type().parameterType(pos)) == bt);
431 return mh.type().dropParameterTypes(pos, pos+1);
432 }
433
434 /// Editing methods for lambda forms.
435 // Each editing method can (potentially) cache the edited LF so that it can be reused later.
436
437 LambdaForm bindArgumentForm(int pos) {
438 Transform key = Transform.of(Transform.BIND_ARG, pos);
439 LambdaForm form = getInCache(key);
440 if (form != null) {
441 assert(form.parameterConstraint(0) == newSpeciesData(lambdaForm.parameterType(pos)));
442 return form;
443 }
444 LambdaFormBuffer buf = buffer();
445 buf.startEdit();
446
447 BoundMethodHandle.SpeciesData oldData = oldSpeciesData();
448 BoundMethodHandle.SpeciesData newData = newSpeciesData(lambdaForm.parameterType(pos));
449 Name oldBaseAddress = lambdaForm.parameter(0); // BMH holding the values
450 Name newBaseAddress;
451 NamedFunction getter = newData.getterFunction(oldData.fieldCount());
452
453 if (pos != 0) {
454 // The newly created LF will run with a different BMH.
455 // Switch over any pre-existing BMH field references to the new BMH class.
456 buf.replaceFunctions(oldData.getterFunctions(), newData.getterFunctions(), oldBaseAddress);
457 newBaseAddress = oldBaseAddress.withConstraint(newData);
458 buf.renameParameter(0, newBaseAddress);
459 buf.replaceParameterByNewExpression(pos, new Name(getter, newBaseAddress));
460 } else {
461 // cannot bind the MH arg itself, unless oldData is empty
462 assert(oldData == BoundMethodHandle.SpeciesData.EMPTY);
463 newBaseAddress = new Name(L_TYPE).withConstraint(newData);
464 buf.replaceParameterByNewExpression(0, new Name(getter, newBaseAddress));
465 buf.insertParameter(0, newBaseAddress);
466 }
467
468 form = buf.endEdit();
469 return putInCache(key, form);
470 }
471
472 LambdaForm addArgumentForm(int pos, BasicType type) {
473 Transform key = Transform.of(Transform.ADD_ARG, pos, type.ordinal());
474 LambdaForm form = getInCache(key);
475 if (form != null) {
476 assert(form.arity == lambdaForm.arity+1);
477 assert(form.parameterType(pos) == type);
478 return form;
479 }
480 LambdaFormBuffer buf = buffer();
481 buf.startEdit();
482
483 buf.insertParameter(pos, new Name(type));
484
485 form = buf.endEdit();
486 return putInCache(key, form);
487 }
488
489 LambdaForm dupArgumentForm(int srcPos, int dstPos) {
490 Transform key = Transform.of(Transform.DUP_ARG, srcPos, dstPos);
491 LambdaForm form = getInCache(key);
492 if (form != null) {
493 assert(form.arity == lambdaForm.arity-1);
494 return form;
495 }
496 LambdaFormBuffer buf = buffer();
497 buf.startEdit();
498
499 assert(lambdaForm.parameter(srcPos).constraint == null);
500 assert(lambdaForm.parameter(dstPos).constraint == null);
501 buf.replaceParameterByCopy(dstPos, srcPos);
502
503 form = buf.endEdit();
504 return putInCache(key, form);
505 }
506
507 LambdaForm spreadArgumentsForm(int pos, Class<?> arrayType, int arrayLength) {
508 Class<?> elementType = arrayType.getComponentType();
509 Class<?> erasedArrayType = arrayType;
510 if (!elementType.isPrimitive())
511 erasedArrayType = Object[].class;
512 BasicType bt = basicType(elementType);
513 int elementTypeKey = bt.ordinal();
514 if (bt.basicTypeClass() != elementType) {
515 if (elementType.isPrimitive()) {
516 elementTypeKey = TYPE_LIMIT + Wrapper.forPrimitiveType(elementType).ordinal();
517 }
518 }
519 Transform key = Transform.of(Transform.SPREAD_ARGS, pos, elementTypeKey, arrayLength);
520 LambdaForm form = getInCache(key);
521 if (form != null) {
522 assert(form.arity == lambdaForm.arity - arrayLength + 1);
523 return form;
524 }
525 LambdaFormBuffer buf = buffer();
526 buf.startEdit();
527
528 assert(pos <= MethodType.MAX_JVM_ARITY);
529 assert(pos + arrayLength <= lambdaForm.arity);
530 assert(pos > 0); // cannot spread the MH arg itself
531
532 Name spreadParam = new Name(L_TYPE);
533 Name checkSpread = new Name(MethodHandleImpl.NF_checkSpreadArgument, spreadParam, arrayLength);
534
535 // insert the new expressions
536 int exprPos = lambdaForm.arity();
537 buf.insertExpression(exprPos++, checkSpread);
538 // adjust the arguments
539 MethodHandle aload = MethodHandles.arrayElementGetter(erasedArrayType);
540 for (int i = 0; i < arrayLength; i++) {
541 Name loadArgument = new Name(aload, spreadParam, i);
542 buf.insertExpression(exprPos + i, loadArgument);
543 buf.replaceParameterByCopy(pos + i, exprPos + i);
544 }
545 buf.insertParameter(pos, spreadParam);
546
547 form = buf.endEdit();
548 return putInCache(key, form);
549 }
550
551 LambdaForm collectArgumentsForm(int pos, MethodType collectorType) {
552 int collectorArity = collectorType.parameterCount();
553 boolean dropResult = (collectorType.returnType() == void.class);
554 if (collectorArity == 1 && !dropResult) {
555 return filterArgumentForm(pos, basicType(collectorType.parameterType(0)));
556 }
557 byte[] newTypes = BasicType.basicTypesOrd(collectorType.parameterArray());
558 byte kind = (dropResult
559 ? Transform.COLLECT_ARGS_TO_VOID
560 : Transform.COLLECT_ARGS);
561 if (dropResult && collectorArity == 0) pos = 1; // pure side effect
562 Transform key = Transform.of(kind, pos, collectorArity, newTypes);
563 LambdaForm form = getInCache(key);
564 if (form != null) {
565 assert(form.arity == lambdaForm.arity - (dropResult ? 0 : 1) + collectorArity);
566 return form;
567 }
568 form = makeArgumentCombinationForm(pos, collectorType, false, dropResult);
569 return putInCache(key, form);
570 }
571
572 LambdaForm collectArgumentArrayForm(int pos, MethodHandle arrayCollector) {
573 MethodType collectorType = arrayCollector.type();
574 int collectorArity = collectorType.parameterCount();
575 assert(arrayCollector.intrinsicName() == Intrinsic.NEW_ARRAY);
576 Class<?> arrayType = collectorType.returnType();
577 Class<?> elementType = arrayType.getComponentType();
578 BasicType argType = basicType(elementType);
579 int argTypeKey = argType.ordinal();
580 if (argType.basicTypeClass() != elementType) {
581 // return null if it requires more metadata (like String[].class)
582 if (!elementType.isPrimitive())
583 return null;
584 argTypeKey = TYPE_LIMIT + Wrapper.forPrimitiveType(elementType).ordinal();
585 }
586 assert(collectorType.parameterList().equals(Collections.nCopies(collectorArity, elementType)));
587 byte kind = Transform.COLLECT_ARGS_TO_ARRAY;
588 Transform key = Transform.of(kind, pos, collectorArity, argTypeKey);
589 LambdaForm form = getInCache(key);
590 if (form != null) {
591 assert(form.arity == lambdaForm.arity - 1 + collectorArity);
592 return form;
593 }
594 LambdaFormBuffer buf = buffer();
595 buf.startEdit();
596
597 assert(pos + 1 <= lambdaForm.arity);
598 assert(pos > 0); // cannot filter the MH arg itself
599
600 Name[] newParams = new Name[collectorArity];
601 for (int i = 0; i < collectorArity; i++) {
602 newParams[i] = new Name(pos + i, argType);
603 }
604 Name callCombiner = new Name(arrayCollector, (Object[]) /*...*/ newParams);
605
606 // insert the new expression
607 int exprPos = lambdaForm.arity();
608 buf.insertExpression(exprPos, callCombiner);
609
610 // insert new arguments
611 int argPos = pos + 1; // skip result parameter
612 for (Name newParam : newParams) {
613 buf.insertParameter(argPos++, newParam);
614 }
615 assert(buf.lastIndexOf(callCombiner) == exprPos+newParams.length);
616 buf.replaceParameterByCopy(pos, exprPos+newParams.length);
617
618 form = buf.endEdit();
619 return putInCache(key, form);
620 }
621
622 LambdaForm filterArgumentForm(int pos, BasicType newType) {
623 Transform key = Transform.of(Transform.FILTER_ARG, pos, newType.ordinal());
624 LambdaForm form = getInCache(key);
625 if (form != null) {
626 assert(form.arity == lambdaForm.arity);
627 assert(form.parameterType(pos) == newType);
628 return form;
629 }
630
631 BasicType oldType = lambdaForm.parameterType(pos);
632 MethodType filterType = MethodType.methodType(oldType.basicTypeClass(),
633 newType.basicTypeClass());
634 form = makeArgumentCombinationForm(pos, filterType, false, false);
635 return putInCache(key, form);
636 }
637
638 private LambdaForm makeArgumentCombinationForm(int pos,
639 MethodType combinerType,
640 boolean keepArguments, boolean dropResult) {
641 LambdaFormBuffer buf = buffer();
642 buf.startEdit();
643 int combinerArity = combinerType.parameterCount();
644 int resultArity = (dropResult ? 0 : 1);
645
646 assert(pos <= MethodType.MAX_JVM_ARITY);
647 assert(pos + resultArity + (keepArguments ? combinerArity : 0) <= lambdaForm.arity);
648 assert(pos > 0); // cannot filter the MH arg itself
649 assert(combinerType == combinerType.basicType());
650 assert(combinerType.returnType() != void.class || dropResult);
651
652 BoundMethodHandle.SpeciesData oldData = oldSpeciesData();
653 BoundMethodHandle.SpeciesData newData = newSpeciesData(L_TYPE);
654
655 // The newly created LF will run with a different BMH.
656 // Switch over any pre-existing BMH field references to the new BMH class.
657 Name oldBaseAddress = lambdaForm.parameter(0); // BMH holding the values
658 buf.replaceFunctions(oldData.getterFunctions(), newData.getterFunctions(), oldBaseAddress);
659 Name newBaseAddress = oldBaseAddress.withConstraint(newData);
660 buf.renameParameter(0, newBaseAddress);
661
662 Name getCombiner = new Name(newData.getterFunction(oldData.fieldCount()), newBaseAddress);
663 Object[] combinerArgs = new Object[1 + combinerArity];
664 combinerArgs[0] = getCombiner;
665 Name[] newParams;
666 if (keepArguments) {
667 newParams = new Name[0];
668 System.arraycopy(lambdaForm.names, pos + resultArity,
669 combinerArgs, 1, combinerArity);
670 } else {
671 newParams = new Name[combinerArity];
672 for (int i = 0; i < newParams.length; i++) {
673 newParams[i] = new Name(pos + i, basicType(combinerType.parameterType(i)));
674 }
675 System.arraycopy(newParams, 0,
676 combinerArgs, 1, combinerArity);
677 }
678 Name callCombiner = new Name(combinerType, combinerArgs);
679
680 // insert the two new expressions
681 int exprPos = lambdaForm.arity();
682 buf.insertExpression(exprPos+0, getCombiner);
683 buf.insertExpression(exprPos+1, callCombiner);
684
685 // insert new arguments, if needed
686 int argPos = pos + resultArity; // skip result parameter
687 for (Name newParam : newParams) {
688 buf.insertParameter(argPos++, newParam);
689 }
690 assert(buf.lastIndexOf(callCombiner) == exprPos+1+newParams.length);
691 if (!dropResult) {
692 buf.replaceParameterByCopy(pos, exprPos+1+newParams.length);
693 }
694
695 return buf.endEdit();
696 }
697
698 LambdaForm filterReturnForm(BasicType newType, boolean constantZero) {
699 byte kind = (constantZero ? Transform.FILTER_RETURN_TO_ZERO : Transform.FILTER_RETURN);
700 Transform key = Transform.of(kind, newType.ordinal());
701 LambdaForm form = getInCache(key);
702 if (form != null) {
703 assert(form.arity == lambdaForm.arity);
704 assert(form.returnType() == newType);
705 return form;
706 }
707 LambdaFormBuffer buf = buffer();
708 buf.startEdit();
709
710 int insPos = lambdaForm.names.length;
711 Name callFilter;
712 if (constantZero) {
713 // Synthesize a constant zero value for the given type.
714 if (newType == V_TYPE)
715 callFilter = null;
716 else
717 callFilter = new Name(constantZero(newType));
718 } else {
719 BoundMethodHandle.SpeciesData oldData = oldSpeciesData();
720 BoundMethodHandle.SpeciesData newData = newSpeciesData(L_TYPE);
721
722 // The newly created LF will run with a different BMH.
723 // Switch over any pre-existing BMH field references to the new BMH class.
724 Name oldBaseAddress = lambdaForm.parameter(0); // BMH holding the values
725 buf.replaceFunctions(oldData.getterFunctions(), newData.getterFunctions(), oldBaseAddress);
726 Name newBaseAddress = oldBaseAddress.withConstraint(newData);
727 buf.renameParameter(0, newBaseAddress);
728
729 Name getFilter = new Name(newData.getterFunction(oldData.fieldCount()), newBaseAddress);
730 buf.insertExpression(insPos++, getFilter);
731 BasicType oldType = lambdaForm.returnType();
732 if (oldType == V_TYPE) {
733 MethodType filterType = MethodType.methodType(newType.basicTypeClass());
734 callFilter = new Name(filterType, getFilter);
735 } else {
736 MethodType filterType = MethodType.methodType(newType.basicTypeClass(), oldType.basicTypeClass());
737 callFilter = new Name(filterType, getFilter, lambdaForm.names[lambdaForm.result]);
738 }
739 }
740
741 if (callFilter != null)
742 buf.insertExpression(insPos++, callFilter);
743 buf.setResult(callFilter);
744
745 form = buf.endEdit();
746 return putInCache(key, form);
747 }
748
749 LambdaForm foldArgumentsForm(int foldPos, boolean dropResult, MethodType combinerType) {
750 int combinerArity = combinerType.parameterCount();
751 byte kind = (dropResult ? Transform.FOLD_ARGS_TO_VOID : Transform.FOLD_ARGS);
752 Transform key = Transform.of(kind, foldPos, combinerArity);
753 LambdaForm form = getInCache(key);
754 if (form != null) {
755 assert(form.arity == lambdaForm.arity - (kind == Transform.FOLD_ARGS ? 1 : 0));
756 return form;
757 }
758 form = makeArgumentCombinationForm(foldPos, combinerType, true, dropResult);
759 return putInCache(key, form);
760 }
761
762 LambdaForm permuteArgumentsForm(int skip, int[] reorder) {
763 assert(skip == 1); // skip only the leading MH argument, names[0]
764 int length = lambdaForm.names.length;
765 int outArgs = reorder.length;
766 int inTypes = 0;
767 boolean nullPerm = true;
768 for (int i = 0; i < reorder.length; i++) {
769 int inArg = reorder[i];
770 if (inArg != i) nullPerm = false;
771 inTypes = Math.max(inTypes, inArg+1);
772 }
773 assert(skip + reorder.length == lambdaForm.arity);
774 if (nullPerm) return lambdaForm; // do not bother to cache
775 Transform key = Transform.of(Transform.PERMUTE_ARGS, reorder);
776 LambdaForm form = getInCache(key);
777 if (form != null) {
778 assert(form.arity == skip+inTypes) : form;
779 return form;
780 }
781
782 BasicType[] types = new BasicType[inTypes];
783 for (int i = 0; i < outArgs; i++) {
784 int inArg = reorder[i];
785 types[inArg] = lambdaForm.names[skip + i].type;
786 }
787 assert (skip + outArgs == lambdaForm.arity);
788 assert (permutedTypesMatch(reorder, types, lambdaForm.names, skip));
789 int pos = 0;
790 while (pos < outArgs && reorder[pos] == pos) {
791 pos += 1;
792 }
793 Name[] names2 = new Name[length - outArgs + inTypes];
794 System.arraycopy(lambdaForm.names, 0, names2, 0, skip + pos);
795 int bodyLength = length - lambdaForm.arity;
796 System.arraycopy(lambdaForm.names, skip + outArgs, names2, skip + inTypes, bodyLength);
797 int arity2 = names2.length - bodyLength;
798 int result2 = lambdaForm.result;
799 if (result2 >= 0) {
800 if (result2 < skip + outArgs) {
801 result2 = reorder[result2 - skip];
802 } else {
803 result2 = result2 - outArgs + inTypes;
804 }
805 }
806 for (int j = pos; j < outArgs; j++) {
807 Name n = lambdaForm.names[skip + j];
808 int i = reorder[j];
809 Name n2 = names2[skip + i];
810 if (n2 == null) {
811 names2[skip + i] = n2 = new Name(types[i]);
812 } else {
813 assert (n2.type == types[i]);
814 }
815 for (int k = arity2; k < names2.length; k++) {
816 names2[k] = names2[k].replaceName(n, n2);
817 }
818 }
819 for (int i = skip + pos; i < arity2; i++) {
820 if (names2[i] == null) {
821 names2[i] = argument(i, types[i - skip]);
822 }
823 }
824 for (int j = lambdaForm.arity; j < lambdaForm.names.length; j++) {
825 int i = j - lambdaForm.arity + arity2;
826 Name n = lambdaForm.names[j];
827 Name n2 = names2[i];
828 if (n != n2) {
829 for (int k = i + 1; k < names2.length; k++) {
830 names2[k] = names2[k].replaceName(n, n2);
831 }
832 }
833 }
834
835 form = new LambdaForm(lambdaForm.debugName, arity2, names2, result2);
836 return putInCache(key, form);
837 }
838
839 LambdaForm noteLoopLocalTypesForm(int pos, BasicType[] localTypes) {
840 assert(lambdaForm.isLoop(pos));
841 int[] desc = BasicType.basicTypeOrds(localTypes);
842 desc = Arrays.copyOf(desc, desc.length + 1);
843 desc[desc.length - 1] = pos;
844 Transform key = Transform.of(Transform.LOCAL_TYPES, desc);
845 LambdaForm form = getInCache(key);
846 if (form != null) {
847 return form;
848 }
849
850 // replace the null entry in the MHImpl.loop invocation with localTypes
851 Name invokeLoop = lambdaForm.names[pos + 1];
852 assert(invokeLoop.function == NF_loop);
853 Object[] args = Arrays.copyOf(invokeLoop.arguments, invokeLoop.arguments.length);
854 assert(args[0] == null);
855 args[0] = localTypes;
856
857 LambdaFormBuffer buf = buffer();
858 buf.startEdit();
859 buf.changeName(pos + 1, new Name(NF_loop, args));
860 form = buf.endEdit();
861
862 return putInCache(key, form);
863 }
864
865 static boolean permutedTypesMatch(int[] reorder, BasicType[] types, Name[] names, int skip) {
866 for (int i = 0; i < reorder.length; i++) {
867 assert (names[skip + i].isParam());
868 assert (names[skip + i].type == types[reorder[i]]);
869 }
870 return true;
871 }
872 }
--- EOF ---