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 }