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 FOLD_SELECT_ARGS = 15, 88 FOLD_SELECT_ARGS_TO_VOID = 16; 89 90 private static final boolean STRESS_TEST = false; // turn on to disable most packing 91 private static final int 92 PACKED_BYTE_SIZE = (STRESS_TEST ? 2 : 4), 93 PACKED_BYTE_MASK = (1 << PACKED_BYTE_SIZE) - 1, 94 PACKED_BYTE_MAX_LENGTH = (STRESS_TEST ? 3 : 64 / PACKED_BYTE_SIZE); 95 96 private static long packedBytes(byte[] bytes) { 97 if (bytes.length > PACKED_BYTE_MAX_LENGTH) return 0; 98 long pb = 0; 99 int bitset = 0; 100 for (int i = 0; i < bytes.length; i++) { 101 int b = bytes[i] & 0xFF; 102 bitset |= b; 103 pb |= (long)b << (i * PACKED_BYTE_SIZE); 104 } 105 if (!inRange(bitset)) 106 return 0; 107 return pb; 108 } 109 private static long packedBytes(int b0, int b1) { 110 assert(inRange(b0 | b1)); 111 return ( (b0 << 0*PACKED_BYTE_SIZE) 112 | (b1 << 1*PACKED_BYTE_SIZE)); 113 } 114 private static long packedBytes(int b0, int b1, int b2) { 115 assert(inRange(b0 | b1 | b2)); 116 return ( (b0 << 0*PACKED_BYTE_SIZE) 117 | (b1 << 1*PACKED_BYTE_SIZE) 118 | (b2 << 2*PACKED_BYTE_SIZE)); 119 } 120 private static long packedBytes(int b0, int b1, int b2, int b3) { 121 assert(inRange(b0 | b1 | b2 | b3)); 122 return ( (b0 << 0*PACKED_BYTE_SIZE) 123 | (b1 << 1*PACKED_BYTE_SIZE) 124 | (b2 << 2*PACKED_BYTE_SIZE) 125 | (b3 << 3*PACKED_BYTE_SIZE)); 126 } 127 private static boolean inRange(int bitset) { 128 assert((bitset & 0xFF) == bitset); // incoming values must fit in *unsigned* byte 129 return ((bitset & ~PACKED_BYTE_MASK) == 0); 130 } 131 private static byte[] fullBytes(int... byteValues) { 132 byte[] bytes = new byte[byteValues.length]; 133 int i = 0; 134 for (int bv : byteValues) { 135 bytes[i++] = bval(bv); 136 } 137 assert(packedBytes(bytes) == 0); 138 return bytes; 139 } 140 141 private Transform(long packedBytes, byte[] fullBytes, LambdaForm result) { 142 super(result); 143 this.packedBytes = packedBytes; 144 this.fullBytes = fullBytes; 145 } 146 private Transform(long packedBytes) { 147 this(packedBytes, null, null); 148 assert(packedBytes != 0); 149 } 150 private Transform(byte[] fullBytes) { 151 this(0, fullBytes, null); 152 } 153 154 private static byte bval(int b) { 155 assert((b & 0xFF) == b); // incoming value must fit in *unsigned* byte 156 return (byte)b; 157 } 158 static Transform of(byte k, int b1) { 159 byte b0 = bval(k); 160 if (inRange(b0 | b1)) 161 return new Transform(packedBytes(b0, b1)); 162 else 163 return new Transform(fullBytes(b0, b1)); 164 } 165 static Transform of(byte b0, int b1, int b2) { 166 if (inRange(b0 | b1 | b2)) 167 return new Transform(packedBytes(b0, b1, b2)); 168 else 169 return new Transform(fullBytes(b0, b1, b2)); 170 } 171 static Transform of(byte b0, int b1, int b2, int b3) { 172 if (inRange(b0 | b1 | b2 | b3)) 173 return new Transform(packedBytes(b0, b1, b2, b3)); 174 else 175 return new Transform(fullBytes(b0, b1, b2, b3)); 176 } 177 private static final byte[] NO_BYTES = {}; 178 static Transform of(byte kind, int... b123) { 179 return ofBothArrays(kind, b123, NO_BYTES); 180 } 181 static Transform of(byte kind, int b1, byte[] b234) { 182 return ofBothArrays(kind, new int[]{ b1 }, b234); 183 } 184 static Transform of(byte kind, int b1, int b2, byte[] b345) { 185 return ofBothArrays(kind, new int[]{ b1, b2 }, b345); 186 } 187 private static Transform ofBothArrays(byte kind, int[] b123, byte[] b456) { 188 byte[] fullBytes = new byte[1 + b123.length + b456.length]; 189 int i = 0; 190 fullBytes[i++] = bval(kind); 191 for (int bv : b123) { 192 fullBytes[i++] = bval(bv); 193 } 194 for (byte bv : b456) { 195 fullBytes[i++] = bv; 196 } 197 long packedBytes = packedBytes(fullBytes); 198 if (packedBytes != 0) 199 return new Transform(packedBytes); 200 else 201 return new Transform(fullBytes); 202 } 203 204 Transform withResult(LambdaForm result) { 205 return new Transform(this.packedBytes, this.fullBytes, result); 206 } 207 208 @Override 209 public boolean equals(Object obj) { 210 return obj instanceof Transform && equals((Transform)obj); 211 } 212 public boolean equals(Transform that) { 213 return this.packedBytes == that.packedBytes && Arrays.equals(this.fullBytes, that.fullBytes); 214 } 215 @Override 216 public int hashCode() { 217 if (packedBytes != 0) { 218 assert(fullBytes == null); 219 return Long.hashCode(packedBytes); 220 } 221 return Arrays.hashCode(fullBytes); 222 } 223 @Override 224 public String toString() { 225 StringBuilder buf = new StringBuilder(); 226 long bits = packedBytes; 227 if (bits != 0) { 228 buf.append("("); 229 while (bits != 0) { 230 buf.append(bits & PACKED_BYTE_MASK); 231 bits >>>= PACKED_BYTE_SIZE; 232 if (bits != 0) buf.append(","); 233 } 234 buf.append(")"); 235 } 236 if (fullBytes != null) { 237 buf.append("unpacked"); 238 buf.append(Arrays.toString(fullBytes)); 239 } 240 LambdaForm result = get(); 241 if (result != null) { 242 buf.append(" result="); 243 buf.append(result); 244 } 245 return buf.toString(); 246 } 247 } 248 249 /** Find a previously cached transform equivalent to the given one, and return its result. */ 250 private LambdaForm getInCache(Transform key) { 251 assert(key.get() == null); 252 // The transformCache is one of null, Transform, Transform[], or ConcurrentHashMap. 253 Object c = lambdaForm.transformCache; 254 Transform k = null; 255 if (c instanceof ConcurrentHashMap) { 256 @SuppressWarnings("unchecked") 257 ConcurrentHashMap<Transform,Transform> m = (ConcurrentHashMap<Transform,Transform>) c; 258 k = m.get(key); 259 } else if (c == null) { 260 return null; 261 } else if (c instanceof Transform) { 262 // one-element cache avoids overhead of an array 263 Transform t = (Transform)c; 264 if (t.equals(key)) k = t; 265 } else { 266 Transform[] ta = (Transform[])c; 267 for (int i = 0; i < ta.length; i++) { 268 Transform t = ta[i]; 269 if (t == null) break; 270 if (t.equals(key)) { k = t; break; } 271 } 272 } 273 assert(k == null || key.equals(k)); 274 return (k != null) ? k.get() : null; 275 } 276 277 /** Arbitrary but reasonable limits on Transform[] size for cache. */ 278 private static final int MIN_CACHE_ARRAY_SIZE = 4, MAX_CACHE_ARRAY_SIZE = 16; 279 280 /** Cache a transform with its result, and return that result. 281 * But if an equivalent transform has already been cached, return its result instead. 282 */ 283 private LambdaForm putInCache(Transform key, LambdaForm form) { 284 key = key.withResult(form); 285 for (int pass = 0; ; pass++) { 286 Object c = lambdaForm.transformCache; 287 if (c instanceof ConcurrentHashMap) { 288 @SuppressWarnings("unchecked") 289 ConcurrentHashMap<Transform,Transform> m = (ConcurrentHashMap<Transform,Transform>) c; 290 Transform k = m.putIfAbsent(key, key); 291 if (k == null) return form; 292 LambdaForm result = k.get(); 293 if (result != null) { 294 return result; 295 } else { 296 if (m.replace(key, k, key)) { 297 return form; 298 } else { 299 continue; 300 } 301 } 302 } 303 assert(pass == 0); 304 synchronized (lambdaForm) { 305 c = lambdaForm.transformCache; 306 if (c instanceof ConcurrentHashMap) 307 continue; 308 if (c == null) { 309 lambdaForm.transformCache = key; 310 return form; 311 } 312 Transform[] ta; 313 if (c instanceof Transform) { 314 Transform k = (Transform)c; 315 if (k.equals(key)) { 316 LambdaForm result = k.get(); 317 if (result == null) { 318 lambdaForm.transformCache = key; 319 return form; 320 } else { 321 return result; 322 } 323 } else if (k.get() == null) { // overwrite stale entry 324 lambdaForm.transformCache = key; 325 return form; 326 } 327 // expand one-element cache to small array 328 ta = new Transform[MIN_CACHE_ARRAY_SIZE]; 329 ta[0] = k; 330 lambdaForm.transformCache = ta; 331 } else { 332 // it is already expanded 333 ta = (Transform[])c; 334 } 335 int len = ta.length; 336 int stale = -1; 337 int i; 338 for (i = 0; i < len; i++) { 339 Transform k = ta[i]; 340 if (k == null) { 341 break; 342 } 343 if (k.equals(key)) { 344 LambdaForm result = k.get(); 345 if (result == null) { 346 ta[i] = key; 347 return form; 348 } else { 349 return result; 350 } 351 } else if (stale < 0 && k.get() == null) { 352 stale = i; // remember 1st stale entry index 353 } 354 } 355 if (i < len || stale >= 0) { 356 // just fall through to cache update 357 } else if (len < MAX_CACHE_ARRAY_SIZE) { 358 len = Math.min(len * 2, MAX_CACHE_ARRAY_SIZE); 359 ta = Arrays.copyOf(ta, len); 360 lambdaForm.transformCache = ta; 361 } else { 362 ConcurrentHashMap<Transform, Transform> m = new ConcurrentHashMap<>(MAX_CACHE_ARRAY_SIZE * 2); 363 for (Transform k : ta) { 364 m.put(k, k); 365 } 366 lambdaForm.transformCache = m; 367 // The second iteration will update for this query, concurrently. 368 continue; 369 } 370 int idx = (stale >= 0) ? stale : i; 371 ta[idx] = key; 372 return form; 373 } 374 } 375 } 376 377 private LambdaFormBuffer buffer() { 378 return new LambdaFormBuffer(lambdaForm); 379 } 380 381 /// Editing methods for method handles. These need to have fast paths. 382 383 private BoundMethodHandle.SpeciesData oldSpeciesData() { 384 return BoundMethodHandle.speciesData(lambdaForm); 385 } 386 private BoundMethodHandle.SpeciesData newSpeciesData(BasicType type) { 387 return oldSpeciesData().extendWith(type); 388 } 389 390 BoundMethodHandle bindArgumentQ(BoundMethodHandle mh, int pos, Object value, MethodHandle unbox) { 391 assert(mh.speciesData() == oldSpeciesData()); 392 BasicType bt = Q_TYPE; 393 MethodType type2 = bindArgumentType(mh, pos, bt); 394 LambdaForm form2 = bindArgumentForm(1+pos); 395 return mh.copyWithExtendL(type2, form2, value) 396 .copyWithExtendL(type2, form2, unbox); 397 } 398 BoundMethodHandle bindArgumentL(BoundMethodHandle mh, int pos, Object value) { 399 assert(mh.speciesData() == oldSpeciesData()); 400 BasicType bt = L_TYPE; 401 MethodType type2 = bindArgumentType(mh, pos, bt); 402 LambdaForm form2 = bindArgumentForm(1+pos); 403 return mh.copyWithExtendL(type2, form2, value); 404 } 405 BoundMethodHandle bindArgumentI(BoundMethodHandle mh, int pos, int value) { 406 assert(mh.speciesData() == oldSpeciesData()); 407 BasicType bt = I_TYPE; 408 MethodType type2 = bindArgumentType(mh, pos, bt); 409 LambdaForm form2 = bindArgumentForm(1+pos); 410 return mh.copyWithExtendI(type2, form2, value); 411 } 412 413 BoundMethodHandle bindArgumentJ(BoundMethodHandle mh, int pos, long value) { 414 assert(mh.speciesData() == oldSpeciesData()); 415 BasicType bt = J_TYPE; 416 MethodType type2 = bindArgumentType(mh, pos, bt); 417 LambdaForm form2 = bindArgumentForm(1+pos); 418 return mh.copyWithExtendJ(type2, form2, value); 419 } 420 421 BoundMethodHandle bindArgumentF(BoundMethodHandle mh, int pos, float value) { 422 assert(mh.speciesData() == oldSpeciesData()); 423 BasicType bt = F_TYPE; 424 MethodType type2 = bindArgumentType(mh, pos, bt); 425 LambdaForm form2 = bindArgumentForm(1+pos); 426 return mh.copyWithExtendF(type2, form2, value); 427 } 428 429 BoundMethodHandle bindArgumentD(BoundMethodHandle mh, int pos, double value) { 430 assert(mh.speciesData() == oldSpeciesData()); 431 BasicType bt = D_TYPE; 432 MethodType type2 = bindArgumentType(mh, pos, bt); 433 LambdaForm form2 = bindArgumentForm(1+pos); 434 return mh.copyWithExtendD(type2, form2, value); 435 } 436 437 private MethodType bindArgumentType(BoundMethodHandle mh, int pos, BasicType bt) { 438 assert(mh.form.uncustomize() == lambdaForm); 439 assert(mh.form.names[1+pos].type == bt); 440 assert(BasicType.basicType(mh.type().parameterType(pos)) == bt); 441 return mh.type().dropParameterTypes(pos, pos+1); 442 } 443 444 /// Editing methods for lambda forms. 445 // Each editing method can (potentially) cache the edited LF so that it can be reused later. 446 447 LambdaForm bindArgumentForm(int pos) { 448 Transform key = Transform.of(Transform.BIND_ARG, pos); 449 LambdaForm form = getInCache(key); 450 if (form != null) { 451 assert(form.parameterConstraint(0) == newSpeciesData(lambdaForm.parameterType(pos))); 452 return form; 453 } 454 LambdaFormBuffer buf = buffer(); 455 buf.startEdit(); 456 457 BoundMethodHandle.SpeciesData oldData = oldSpeciesData(); 458 BasicType ptype = lambdaForm.parameterType(pos); 459 BoundMethodHandle.SpeciesData newData = (ptype != Q_TYPE) ? newSpeciesData(ptype) 460 : oldData.extendWith(L_TYPE).extendWith(L_TYPE); // value + unbox MH 461 Name oldBaseAddress = lambdaForm.parameter(0); // BMH holding the values 462 Name newBaseAddress; 463 NamedFunction getter = newData.getterFunction(oldData.fieldCount()); 464 465 if (pos != 0) { 466 // The newly created LF will run with a different BMH. 467 // Switch over any pre-existing BMH field references to the new BMH class. 468 buf.replaceFunctions(oldData.getterFunctions(), newData.getterFunctions(), oldBaseAddress); 469 newBaseAddress = oldBaseAddress.withConstraint(newData); 470 buf.renameParameter(0, newBaseAddress); 471 if (ptype == Q_TYPE) { 472 // Q-types are stored in boxed form. Unboxing step is required. 473 int exprPos = lambdaForm.arity(); 474 int UNBOX_MH = exprPos++; 475 int BOXED_VALUE = exprPos++; 476 int UNBOXED_VALUE = exprPos++; 477 NamedFunction unboxGetter = newData.getterFunction(oldData.fieldCount()+1); 478 buf.insertExpression(UNBOX_MH, new Name(unboxGetter, newBaseAddress)); 479 buf.insertExpression(BOXED_VALUE, new Name(getter, newBaseAddress)); 480 MethodType unboxInvokerType = MethodType.methodType(Q_TYPE.basicTypeClass(), L_TYPE.basicTypeClass()); 481 Name unbox = new Name(unboxInvokerType, buf.name(UNBOX_MH), buf.name(BOXED_VALUE)); 482 buf.insertExpression(UNBOXED_VALUE, unbox); 483 buf.replaceParameterByCopy(pos, UNBOXED_VALUE); 484 } else { 485 buf.replaceParameterByNewExpression(pos, new Name(getter, newBaseAddress)); 486 } 487 } else { 488 // cannot bind the MH arg itself, unless oldData is empty 489 assert(oldData == BoundMethodHandle.SpeciesData.EMPTY); 490 newBaseAddress = new Name(L_TYPE).withConstraint(newData); 491 buf.replaceParameterByNewExpression(0, new Name(getter, newBaseAddress)); 492 buf.insertParameter(0, newBaseAddress); 493 } 494 495 form = buf.endEdit(); 496 return putInCache(key, form); 497 } 498 499 LambdaForm addArgumentForm(int pos, BasicType type) { 500 Transform key = Transform.of(Transform.ADD_ARG, pos, type.ordinal()); 501 LambdaForm form = getInCache(key); 502 if (form != null) { 503 assert(form.arity == lambdaForm.arity+1); 504 assert(form.parameterType(pos) == type); 505 return form; 506 } 507 LambdaFormBuffer buf = buffer(); 508 buf.startEdit(); 509 510 buf.insertParameter(pos, new Name(type)); 511 512 form = buf.endEdit(); 513 return putInCache(key, form); 514 } 515 516 LambdaForm dupArgumentForm(int srcPos, int dstPos) { 517 Transform key = Transform.of(Transform.DUP_ARG, srcPos, dstPos); 518 LambdaForm form = getInCache(key); 519 if (form != null) { 520 assert(form.arity == lambdaForm.arity-1); 521 return form; 522 } 523 LambdaFormBuffer buf = buffer(); 524 buf.startEdit(); 525 526 assert(lambdaForm.parameter(srcPos).constraint == null); 527 assert(lambdaForm.parameter(dstPos).constraint == null); 528 buf.replaceParameterByCopy(dstPos, srcPos); 529 530 form = buf.endEdit(); 531 return putInCache(key, form); 532 } 533 534 LambdaForm spreadArgumentsForm(int pos, Class<?> arrayType, int arrayLength) { 535 Class<?> elementType = arrayType.getComponentType(); 536 Class<?> erasedArrayType = arrayType; 537 if (!elementType.isPrimitive()) 538 erasedArrayType = Object[].class; 539 BasicType bt = basicType(elementType); 540 int elementTypeKey = bt.ordinal(); 541 if (bt.basicTypeClass() != elementType) { 542 if (elementType.isPrimitive()) { 543 elementTypeKey = TYPE_LIMIT + Wrapper.forPrimitiveType(elementType).ordinal(); 544 } 545 } 546 Transform key = Transform.of(Transform.SPREAD_ARGS, pos, elementTypeKey, arrayLength); 547 LambdaForm form = getInCache(key); 548 if (form != null) { 549 assert(form.arity == lambdaForm.arity - arrayLength + 1); 550 return form; 551 } 552 LambdaFormBuffer buf = buffer(); 553 buf.startEdit(); 554 555 assert(pos <= MethodType.MAX_JVM_ARITY); 556 assert(pos + arrayLength <= lambdaForm.arity); 557 assert(pos > 0); // cannot spread the MH arg itself 558 559 Name spreadParam = new Name(L_TYPE); 560 Name checkSpread = new Name(MethodHandleImpl.getFunction(MethodHandleImpl.NF_checkSpreadArgument), 561 spreadParam, arrayLength); 562 563 // insert the new expressions 564 int exprPos = lambdaForm.arity(); 565 buf.insertExpression(exprPos++, checkSpread); 566 // adjust the arguments 567 MethodHandle aload = MethodHandles.arrayElementGetter(erasedArrayType); 568 for (int i = 0; i < arrayLength; i++) { 569 Name loadArgument = new Name(aload, spreadParam, i); 570 buf.insertExpression(exprPos + i, loadArgument); 571 buf.replaceParameterByCopy(pos + i, exprPos + i); 572 } 573 buf.insertParameter(pos, spreadParam); 574 575 form = buf.endEdit(); 576 return putInCache(key, form); 577 } 578 579 LambdaForm collectArgumentsForm(int pos, MethodType collectorType) { 580 int collectorArity = collectorType.parameterCount(); 581 boolean dropResult = (collectorType.returnType() == void.class); 582 if (collectorArity == 1 && !dropResult) { 583 return filterArgumentForm(pos, basicType(collectorType.parameterType(0))); 584 } 585 byte[] newTypes = BasicType.basicTypesOrd(collectorType.parameterArray()); 586 byte kind = (dropResult 587 ? Transform.COLLECT_ARGS_TO_VOID 588 : Transform.COLLECT_ARGS); 589 if (dropResult && collectorArity == 0) pos = 1; // pure side effect 590 Transform key = Transform.of(kind, pos, collectorArity, newTypes); 591 LambdaForm form = getInCache(key); 592 if (form != null) { 593 assert(form.arity == lambdaForm.arity - (dropResult ? 0 : 1) + collectorArity); 594 return form; 595 } 596 form = makeArgumentCombinationForm(pos, collectorType, false, dropResult); 597 return putInCache(key, form); 598 } 599 600 LambdaForm collectArgumentArrayForm(int pos, MethodHandle arrayCollector) { 601 MethodType collectorType = arrayCollector.type(); 602 int collectorArity = collectorType.parameterCount(); 603 assert(arrayCollector.intrinsicName() == Intrinsic.NEW_ARRAY); 604 Class<?> arrayType = collectorType.returnType(); 605 Class<?> elementType = arrayType.getComponentType(); 606 BasicType argType = basicType(elementType); 607 int argTypeKey = argType.ordinal(); 608 if (argType.basicTypeClass() != elementType) { 609 // return null if it requires more metadata (like String[].class) 610 if (!elementType.isPrimitive()) 611 return null; 612 argTypeKey = TYPE_LIMIT + Wrapper.forPrimitiveType(elementType).ordinal(); 613 } 614 assert(collectorType.parameterList().equals(Collections.nCopies(collectorArity, elementType))); 615 byte kind = Transform.COLLECT_ARGS_TO_ARRAY; 616 Transform key = Transform.of(kind, pos, collectorArity, argTypeKey); 617 LambdaForm form = getInCache(key); 618 if (form != null) { 619 assert(form.arity == lambdaForm.arity - 1 + collectorArity); 620 return form; 621 } 622 LambdaFormBuffer buf = buffer(); 623 buf.startEdit(); 624 625 assert(pos + 1 <= lambdaForm.arity); 626 assert(pos > 0); // cannot filter the MH arg itself 627 628 Name[] newParams = new Name[collectorArity]; 629 for (int i = 0; i < collectorArity; i++) { 630 newParams[i] = new Name(pos + i, argType); 631 } 632 Name callCombiner = new Name(arrayCollector, (Object[]) /*...*/ newParams); 633 634 // insert the new expression 635 int exprPos = lambdaForm.arity(); 636 buf.insertExpression(exprPos, callCombiner); 637 638 // insert new arguments 639 int argPos = pos + 1; // skip result parameter 640 for (Name newParam : newParams) { 641 buf.insertParameter(argPos++, newParam); 642 } 643 assert(buf.lastIndexOf(callCombiner) == exprPos+newParams.length); 644 buf.replaceParameterByCopy(pos, exprPos+newParams.length); 645 646 form = buf.endEdit(); 647 return putInCache(key, form); 648 } 649 650 LambdaForm filterArgumentForm(int pos, BasicType newType) { 651 Transform key = Transform.of(Transform.FILTER_ARG, pos, newType.ordinal()); 652 LambdaForm form = getInCache(key); 653 if (form != null) { 654 assert(form.arity == lambdaForm.arity); 655 assert(form.parameterType(pos) == newType); 656 return form; 657 } 658 659 BasicType oldType = lambdaForm.parameterType(pos); 660 MethodType filterType = MethodType.methodType(oldType.basicTypeClass(), 661 newType.basicTypeClass()); 662 form = makeArgumentCombinationForm(pos, filterType, false, false); 663 return putInCache(key, form); 664 } 665 666 private LambdaForm makeArgumentCombinationForm(int pos, 667 MethodType combinerType, 668 boolean keepArguments, boolean dropResult) { 669 LambdaFormBuffer buf = buffer(); 670 buf.startEdit(); 671 int combinerArity = combinerType.parameterCount(); 672 int resultArity = (dropResult ? 0 : 1); 673 674 assert(pos <= MethodType.MAX_JVM_ARITY); 675 assert(pos + resultArity + (keepArguments ? combinerArity : 0) <= lambdaForm.arity); 676 assert(pos > 0); // cannot filter the MH arg itself 677 assert(combinerType == combinerType.basicType()); 678 assert(combinerType.returnType() != void.class || dropResult); 679 680 BoundMethodHandle.SpeciesData oldData = oldSpeciesData(); 681 BoundMethodHandle.SpeciesData newData = newSpeciesData(L_TYPE); 682 683 // The newly created LF will run with a different BMH. 684 // Switch over any pre-existing BMH field references to the new BMH class. 685 Name oldBaseAddress = lambdaForm.parameter(0); // BMH holding the values 686 buf.replaceFunctions(oldData.getterFunctions(), newData.getterFunctions(), oldBaseAddress); 687 Name newBaseAddress = oldBaseAddress.withConstraint(newData); 688 buf.renameParameter(0, newBaseAddress); 689 690 Name getCombiner = new Name(newData.getterFunction(oldData.fieldCount()), newBaseAddress); 691 Object[] combinerArgs = new Object[1 + combinerArity]; 692 combinerArgs[0] = getCombiner; 693 Name[] newParams; 694 if (keepArguments) { 695 newParams = new Name[0]; 696 System.arraycopy(lambdaForm.names, pos + resultArity, 697 combinerArgs, 1, combinerArity); 698 } else { 699 newParams = new Name[combinerArity]; 700 for (int i = 0; i < newParams.length; i++) { 701 newParams[i] = new Name(pos + i, basicType(combinerType.parameterType(i))); 702 } 703 System.arraycopy(newParams, 0, 704 combinerArgs, 1, combinerArity); 705 } 706 Name callCombiner = new Name(combinerType, combinerArgs); 707 708 // insert the two new expressions 709 int exprPos = lambdaForm.arity(); 710 buf.insertExpression(exprPos+0, getCombiner); 711 buf.insertExpression(exprPos+1, callCombiner); 712 713 // insert new arguments, if needed 714 int argPos = pos + resultArity; // skip result parameter 715 for (Name newParam : newParams) { 716 buf.insertParameter(argPos++, newParam); 717 } 718 assert(buf.lastIndexOf(callCombiner) == exprPos+1+newParams.length); 719 if (!dropResult) { 720 buf.replaceParameterByCopy(pos, exprPos+1+newParams.length); 721 } 722 723 return buf.endEdit(); 724 } 725 726 private LambdaForm makeArgumentCombinationForm(int pos, 727 MethodType combinerType, 728 int[] argPositions, 729 boolean keepArguments, 730 boolean dropResult) { 731 LambdaFormBuffer buf = buffer(); 732 buf.startEdit(); 733 int combinerArity = combinerType.parameterCount(); 734 assert(combinerArity == argPositions.length); 735 736 int resultArity = (dropResult ? 0 : 1); 737 738 assert(pos <= lambdaForm.arity); 739 assert(pos > 0); // cannot filter the MH arg itself 740 assert(combinerType == combinerType.basicType()); 741 assert(combinerType.returnType() != void.class || dropResult); 742 743 BoundMethodHandle.SpeciesData oldData = oldSpeciesData(); 744 BoundMethodHandle.SpeciesData newData = newSpeciesData(L_TYPE); 745 746 // The newly created LF will run with a different BMH. 747 // Switch over any pre-existing BMH field references to the new BMH class. 748 Name oldBaseAddress = lambdaForm.parameter(0); // BMH holding the values 749 buf.replaceFunctions(oldData.getterFunctions(), newData.getterFunctions(), oldBaseAddress); 750 Name newBaseAddress = oldBaseAddress.withConstraint(newData); 751 buf.renameParameter(0, newBaseAddress); 752 753 Name getCombiner = new Name(newData.getterFunction(oldData.fieldCount()), newBaseAddress); 754 Object[] combinerArgs = new Object[1 + combinerArity]; 755 combinerArgs[0] = getCombiner; 756 Name[] newParams; 757 if (keepArguments) { 758 newParams = new Name[0]; 759 for (int i = 0; i < combinerArity; i++) { 760 combinerArgs[i + 1] = lambdaForm.parameter(1 + argPositions[i]); 761 assert (basicType(combinerType.parameterType(i)) == lambdaForm.parameterType(1 + argPositions[i])); 762 } 763 } else { 764 newParams = new Name[combinerArity]; 765 for (int i = 0; i < newParams.length; i++) { 766 newParams[i] = lambdaForm.parameter(1 + argPositions[i]); 767 assert (basicType(combinerType.parameterType(i)) == lambdaForm.parameterType(1 + argPositions[i])); 768 } 769 System.arraycopy(newParams, 0, 770 combinerArgs, 1, combinerArity); 771 } 772 Name callCombiner = new Name(combinerType, combinerArgs); 773 774 // insert the two new expressions 775 int exprPos = lambdaForm.arity(); 776 buf.insertExpression(exprPos+0, getCombiner); 777 buf.insertExpression(exprPos+1, callCombiner); 778 779 // insert new arguments, if needed 780 int argPos = pos + resultArity; // skip result parameter 781 for (Name newParam : newParams) { 782 buf.insertParameter(argPos++, newParam); 783 } 784 assert(buf.lastIndexOf(callCombiner) == exprPos+1+newParams.length); 785 if (!dropResult) { 786 buf.replaceParameterByCopy(pos, exprPos+1+newParams.length); 787 } 788 789 return buf.endEdit(); 790 } 791 792 LambdaForm filterReturnForm(BasicType newType, boolean constantZero) { 793 byte kind = (constantZero ? Transform.FILTER_RETURN_TO_ZERO : Transform.FILTER_RETURN); 794 Transform key = Transform.of(kind, newType.ordinal()); 795 LambdaForm form = getInCache(key); 796 if (form != null) { 797 assert(form.arity == lambdaForm.arity); 798 assert(form.returnType() == newType); 799 return form; 800 } 801 LambdaFormBuffer buf = buffer(); 802 buf.startEdit(); 803 804 int insPos = lambdaForm.names.length; 805 Name callFilter; 806 if (constantZero) { 807 // Synthesize a constant zero value for the given type. 808 if (newType == V_TYPE) 809 callFilter = null; 810 else 811 callFilter = new Name(constantZero(newType)); 812 } else { 813 BoundMethodHandle.SpeciesData oldData = oldSpeciesData(); 814 BoundMethodHandle.SpeciesData newData = newSpeciesData(L_TYPE); 815 816 // The newly created LF will run with a different BMH. 817 // Switch over any pre-existing BMH field references to the new BMH class. 818 Name oldBaseAddress = lambdaForm.parameter(0); // BMH holding the values 819 buf.replaceFunctions(oldData.getterFunctions(), newData.getterFunctions(), oldBaseAddress); 820 Name newBaseAddress = oldBaseAddress.withConstraint(newData); 821 buf.renameParameter(0, newBaseAddress); 822 823 Name getFilter = new Name(newData.getterFunction(oldData.fieldCount()), newBaseAddress); 824 buf.insertExpression(insPos++, getFilter); 825 BasicType oldType = lambdaForm.returnType(); 826 if (oldType == V_TYPE) { 827 MethodType filterType = MethodType.methodType(newType.basicTypeClass()); 828 callFilter = new Name(filterType, getFilter); 829 } else { 830 MethodType filterType = MethodType.methodType(newType.basicTypeClass(), oldType.basicTypeClass()); 831 callFilter = new Name(filterType, getFilter, lambdaForm.names[lambdaForm.result]); 832 } 833 } 834 835 if (callFilter != null) 836 buf.insertExpression(insPos++, callFilter); 837 buf.setResult(callFilter); 838 839 form = buf.endEdit(); 840 return putInCache(key, form); 841 } 842 843 LambdaForm foldArgumentsForm(int foldPos, boolean dropResult, MethodType combinerType) { 844 int combinerArity = combinerType.parameterCount(); 845 byte kind = (dropResult ? Transform.FOLD_ARGS_TO_VOID : Transform.FOLD_ARGS); 846 Transform key = Transform.of(kind, foldPos, combinerArity); 847 LambdaForm form = getInCache(key); 848 if (form != null) { 849 assert(form.arity == lambdaForm.arity - (kind == Transform.FOLD_ARGS ? 1 : 0)); 850 return form; 851 } 852 form = makeArgumentCombinationForm(foldPos, combinerType, true, dropResult); 853 return putInCache(key, form); 854 } 855 856 LambdaForm foldArgumentsForm(int foldPos, boolean dropResult, MethodType combinerType, int ... argPositions) { 857 byte kind = (dropResult ? Transform.FOLD_SELECT_ARGS_TO_VOID 858 : Transform.FOLD_SELECT_ARGS); 859 int[] keyArgs = Arrays.copyOf(argPositions, argPositions.length + 1); 860 keyArgs[argPositions.length] = foldPos; 861 Transform key = Transform.of(kind, keyArgs); 862 LambdaForm form = getInCache(key); 863 if (form != null) { 864 assert(form.arity == lambdaForm.arity - (kind == Transform.FOLD_SELECT_ARGS ? 1 : 0)); 865 return form; 866 } 867 form = makeArgumentCombinationForm(foldPos, combinerType, argPositions, true, dropResult); 868 return putInCache(key, form); 869 } 870 871 LambdaForm permuteArgumentsForm(int skip, int[] reorder) { 872 assert(skip == 1); // skip only the leading MH argument, names[0] 873 int length = lambdaForm.names.length; 874 int outArgs = reorder.length; 875 int inTypes = 0; 876 boolean nullPerm = true; 877 for (int i = 0; i < reorder.length; i++) { 878 int inArg = reorder[i]; 879 if (inArg != i) nullPerm = false; 880 inTypes = Math.max(inTypes, inArg+1); 881 } 882 assert(skip + reorder.length == lambdaForm.arity); 883 if (nullPerm) return lambdaForm; // do not bother to cache 884 Transform key = Transform.of(Transform.PERMUTE_ARGS, reorder); 885 LambdaForm form = getInCache(key); 886 if (form != null) { 887 assert(form.arity == skip+inTypes) : form; 888 return form; 889 } 890 891 BasicType[] types = new BasicType[inTypes]; 892 for (int i = 0; i < outArgs; i++) { 893 int inArg = reorder[i]; 894 types[inArg] = lambdaForm.names[skip + i].type; 895 } 896 assert (skip + outArgs == lambdaForm.arity); 897 assert (permutedTypesMatch(reorder, types, lambdaForm.names, skip)); 898 int pos = 0; 899 while (pos < outArgs && reorder[pos] == pos) { 900 pos += 1; 901 } 902 Name[] names2 = new Name[length - outArgs + inTypes]; 903 System.arraycopy(lambdaForm.names, 0, names2, 0, skip + pos); 904 int bodyLength = length - lambdaForm.arity; 905 System.arraycopy(lambdaForm.names, skip + outArgs, names2, skip + inTypes, bodyLength); 906 int arity2 = names2.length - bodyLength; 907 int result2 = lambdaForm.result; 908 if (result2 >= 0) { 909 if (result2 < skip + outArgs) { 910 result2 = reorder[result2 - skip]; 911 } else { 912 result2 = result2 - outArgs + inTypes; 913 } 914 } 915 for (int j = pos; j < outArgs; j++) { 916 Name n = lambdaForm.names[skip + j]; 917 int i = reorder[j]; 918 Name n2 = names2[skip + i]; 919 if (n2 == null) { 920 names2[skip + i] = n2 = new Name(types[i]); 921 } else { 922 assert (n2.type == types[i]); 923 } 924 for (int k = arity2; k < names2.length; k++) { 925 names2[k] = names2[k].replaceName(n, n2); 926 } 927 } 928 for (int i = skip + pos; i < arity2; i++) { 929 if (names2[i] == null) { 930 names2[i] = argument(i, types[i - skip]); 931 } 932 } 933 for (int j = lambdaForm.arity; j < lambdaForm.names.length; j++) { 934 int i = j - lambdaForm.arity + arity2; 935 Name n = lambdaForm.names[j]; 936 Name n2 = names2[i]; 937 if (n != n2) { 938 for (int k = i + 1; k < names2.length; k++) { 939 names2[k] = names2[k].replaceName(n, n2); 940 } 941 } 942 } 943 944 form = new LambdaForm(arity2, names2, result2); 945 return putInCache(key, form); 946 } 947 948 LambdaForm noteLoopLocalTypesForm(int pos, BasicType[] localTypes) { 949 assert(lambdaForm.isLoop(pos)); 950 int[] desc = BasicType.basicTypeOrds(localTypes); 951 desc = Arrays.copyOf(desc, desc.length + 1); 952 desc[desc.length - 1] = pos; 953 Transform key = Transform.of(Transform.LOCAL_TYPES, desc); 954 LambdaForm form = getInCache(key); 955 if (form != null) { 956 return form; 957 } 958 959 // replace the null entry in the MHImpl.loop invocation with localTypes 960 Name invokeLoop = lambdaForm.names[pos + 1]; 961 assert(invokeLoop.function.equals(MethodHandleImpl.getFunction(NF_loop))); 962 Object[] args = Arrays.copyOf(invokeLoop.arguments, invokeLoop.arguments.length); 963 assert(args[0] == null); 964 args[0] = localTypes; 965 966 LambdaFormBuffer buf = buffer(); 967 buf.startEdit(); 968 buf.changeName(pos + 1, new Name(MethodHandleImpl.getFunction(NF_loop), args)); 969 form = buf.endEdit(); 970 971 return putInCache(key, form); 972 } 973 974 static boolean permutedTypesMatch(int[] reorder, BasicType[] types, Name[] names, int skip) { 975 for (int i = 0; i < reorder.length; i++) { 976 assert (names[skip + i].isParam()); 977 assert (names[skip + i].type == types[reorder[i]]); 978 } 979 return true; 980 } 981 }