1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * This code is free software; you can redistribute it and/or modify it 5 * under the terms of the GNU General Public License version 2 only, as 6 * published by the Free Software Foundation. The Android Open Source 7 * Project designates this particular file as subject to the "Classpath" 8 * exception as provided by The Android Open Source Project in the LICENSE 9 * 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 22 package java.lang.invoke; 23 24 import static dalvik.system.EmulatedStackFrame.StackFrameAccessor.copyNext; 25 26 import dalvik.system.EmulatedStackFrame; 27 import dalvik.system.EmulatedStackFrame.Range; 28 import dalvik.system.EmulatedStackFrame.RandomOrderStackFrameReader; 29 import dalvik.system.EmulatedStackFrame.StackFrameAccessor; 30 import dalvik.system.EmulatedStackFrame.StackFrameReader; 31 import dalvik.system.EmulatedStackFrame.StackFrameWriter; 32 33 import sun.invoke.util.Wrapper; 34 import sun.misc.Unsafe; 35 36 import java.lang.reflect.Array; 37 import java.lang.reflect.Method; 38 import java.lang.reflect.Modifier; 39 import java.util.ArrayList; 40 import java.util.List; 41 42 /** @hide Public for testing only. */ 43 public class Transformers { Transformers()44 private Transformers() {} 45 46 static { 47 try { 48 TRANSFORM_INTERNAL = 49 MethodHandle.class.getDeclaredMethod( 50 "transformInternal", EmulatedStackFrame.class); 51 } catch (NoSuchMethodException nsme) { 52 throw new AssertionError(); 53 } 54 } 55 56 /** 57 * Method reference to the private {@code MethodHandle.transformInternal} method. This is cached 58 * here because it's the point of entry for all transformers. 59 */ 60 private static final Method TRANSFORM_INTERNAL; 61 62 /** @hide */ 63 public abstract static class Transformer extends MethodHandle implements Cloneable { Transformer(MethodType type)64 protected Transformer(MethodType type) { 65 super(TRANSFORM_INTERNAL.getArtMethod(), MethodHandle.INVOKE_TRANSFORM, type); 66 } 67 Transformer(MethodType type, int invokeKind)68 protected Transformer(MethodType type, int invokeKind) { 69 super(TRANSFORM_INTERNAL.getArtMethod(), invokeKind, type); 70 } 71 72 @Override clone()73 public Object clone() throws CloneNotSupportedException { 74 return super.clone(); 75 } 76 77 /** 78 * Performs a MethodHandle.invoke() call with arguments held in an 79 * EmulatedStackFrame. 80 * @param target the method handle to invoke 81 * @param stackFrame the stack frame containing arguments for the invocation 82 */ invokeFromTransform(MethodHandle target, EmulatedStackFrame stackFrame)83 protected static void invokeFromTransform(MethodHandle target, 84 EmulatedStackFrame stackFrame) throws Throwable { 85 if (target instanceof Transformer) { 86 ((Transformer) target).transform(stackFrame); 87 } else { 88 final MethodHandle adaptedTarget = target.asType(stackFrame.getMethodType()); 89 adaptedTarget.invokeExactWithFrame(stackFrame); 90 } 91 } 92 93 /** 94 * Performs a MethodHandle.invokeExact() call with arguments held in an 95 * EmulatedStackFrame. 96 * @param target the method handle to invoke 97 * @param stackFrame the stack frame containing arguments for the invocation 98 */ invokeExactFromTransform(MethodHandle target, EmulatedStackFrame stackFrame)99 protected void invokeExactFromTransform(MethodHandle target, 100 EmulatedStackFrame stackFrame) throws Throwable { 101 if (target instanceof Transformer) { 102 ((Transformer) target).transform(stackFrame); 103 } else { 104 target.invokeExactWithFrame(stackFrame); 105 } 106 } 107 } 108 109 /** Implements {@code MethodHandles.throwException}. */ 110 static class AlwaysThrow extends Transformer { 111 private final Class<? extends Throwable> exceptionType; 112 AlwaysThrow(Class<?> nominalReturnType, Class<? extends Throwable> exType)113 AlwaysThrow(Class<?> nominalReturnType, Class<? extends Throwable> exType) { 114 super(MethodType.methodType(nominalReturnType, exType)); 115 this.exceptionType = exType; 116 } 117 118 @Override transform(EmulatedStackFrame emulatedStackFrame)119 public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable { 120 throw emulatedStackFrame.getReference(0, exceptionType); 121 } 122 } 123 124 /** Implements {@code MethodHandles.dropArguments}. */ 125 static class DropArguments extends Transformer { 126 private final MethodHandle delegate; 127 private final EmulatedStackFrame.Range range1; 128 private final EmulatedStackFrame.Range range2; 129 DropArguments(MethodType type, MethodHandle delegate, int startPos, int numDropped)130 DropArguments(MethodType type, MethodHandle delegate, int startPos, int numDropped) { 131 super(type); 132 133 this.delegate = delegate; 134 135 // We pre-calculate the ranges of values we have to copy through to the delegate 136 // handle at the time of instantiation so that the actual invoke is performant. 137 this.range1 = EmulatedStackFrame.Range.of(type, 0, startPos); 138 this.range2 = EmulatedStackFrame.Range.from(type, startPos + numDropped); 139 } 140 141 @Override transform(EmulatedStackFrame emulatedStackFrame)142 public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable { 143 EmulatedStackFrame calleeFrame = EmulatedStackFrame.create(delegate.type()); 144 145 emulatedStackFrame.copyRangeTo( 146 calleeFrame, range1, 0 /* referencesStart */, 0 /* stackFrameStart */); 147 emulatedStackFrame.copyRangeTo( 148 calleeFrame, range2, range1.numReferences, range1.numBytes); 149 150 invokeFromTransform(delegate, calleeFrame); 151 calleeFrame.copyReturnValueTo(emulatedStackFrame); 152 } 153 } 154 155 /** Implements {@code MethodHandles.catchException}. */ 156 static class CatchException extends Transformer { 157 private final MethodHandle target; 158 private final MethodHandle handler; 159 private final Class<?> exType; 160 161 private final EmulatedStackFrame.Range handlerArgsRange; 162 CatchException(MethodHandle target, MethodHandle handler, Class<?> exType)163 CatchException(MethodHandle target, MethodHandle handler, Class<?> exType) { 164 super(target.type()); 165 166 this.target = target; 167 this.handler = handler; 168 this.exType = exType; 169 170 // We only copy the first "count" args, dropping others if required. Note that 171 // we subtract one because the first handler arg is the exception thrown by the 172 // target. 173 handlerArgsRange = 174 EmulatedStackFrame.Range.of( 175 target.type(), 0, (handler.type().parameterCount() - 1)); 176 } 177 178 @Override transform(EmulatedStackFrame emulatedStackFrame)179 public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable { 180 try { 181 invokeFromTransform(target, emulatedStackFrame); 182 } catch (Throwable th) { 183 if (th.getClass() == exType) { 184 // We've gotten an exception of the appropriate type, so we need to call 185 // the handler. Create a new frame of the appropriate size. 186 EmulatedStackFrame fallback = EmulatedStackFrame.create(handler.type()); 187 188 // The first argument to the handler is the actual exception. 189 fallback.setReference(0, th); 190 191 // We then copy other arguments that need to be passed through to the handler. 192 // Note that we might drop arguments at the end, if needed. Note that 193 // referencesStart == 1 because the first argument is the exception type. 194 emulatedStackFrame.copyRangeTo( 195 fallback, 196 handlerArgsRange, 197 1 /* referencesStart */, 198 0 /* stackFrameStart */); 199 200 // Perform the invoke and return the appropriate value. 201 invokeFromTransform(handler, fallback); 202 fallback.copyReturnValueTo(emulatedStackFrame); 203 } else { 204 // The exception is not of the expected type, we throw it. 205 throw th; 206 } 207 } 208 } 209 } 210 211 /** Implements {@code MethodHandles.tryFinally}. */ 212 static class TryFinally extends Transformer { 213 /** The target handle to try. */ 214 private final MethodHandle target; 215 216 /** The cleanup handle to invoke after the target. */ 217 private final MethodHandle cleanup; 218 TryFinally(MethodHandle target, MethodHandle cleanup)219 TryFinally(MethodHandle target, MethodHandle cleanup) { 220 super(target.type()); 221 this.target = target; 222 this.cleanup = cleanup; 223 } 224 225 @Override transform(EmulatedStackFrame callerFrame)226 protected void transform(EmulatedStackFrame callerFrame) throws Throwable { 227 Throwable throwable = null; 228 try { 229 invokeExactFromTransform(target, callerFrame); 230 } catch (Throwable t) { 231 throwable = t; 232 throw t; 233 } finally { 234 final EmulatedStackFrame cleanupFrame = prepareCleanupFrame(callerFrame, throwable); 235 invokeExactFromTransform(cleanup, cleanupFrame); 236 if (cleanup.type().returnType() != void.class) { 237 cleanupFrame.copyReturnValueTo(callerFrame); 238 } 239 } 240 } 241 242 /** Prepares the frame used to invoke the cleanup handle. */ prepareCleanupFrame(final EmulatedStackFrame callerFrame, final Throwable throwable)243 private EmulatedStackFrame prepareCleanupFrame(final EmulatedStackFrame callerFrame, 244 final Throwable throwable) { 245 final EmulatedStackFrame cleanupFrame = EmulatedStackFrame.create(cleanup.type()); 246 final StackFrameWriter cleanupWriter = new StackFrameWriter(); 247 cleanupWriter.attach(cleanupFrame); 248 249 // The first argument to `cleanup` is (any) pending exception kind. 250 cleanupWriter.putNextReference(throwable, Throwable.class); 251 int added = 1; 252 253 // The second argument to `cleanup` is the result from `target` (if not void). 254 Class<?> targetReturnType = target.type().returnType(); 255 StackFrameReader targetReader = new StackFrameReader(); 256 targetReader.attach(callerFrame); 257 if (targetReturnType != void.class) { 258 targetReader.makeReturnValueAccessor(); 259 copyNext(targetReader, cleanupWriter, targetReturnType); 260 added += 1; 261 // Reset `targetReader` to reference the arguments in `callerFrame`. 262 targetReader.attach(callerFrame); 263 } 264 265 // The final arguments from the invocation of target. As many are copied as the cleanup 266 // handle expects (it may be fewer than the arguments provided to target). 267 Class<?> [] cleanupTypes = cleanup.type().parameterArray(); 268 for (; added != cleanupTypes.length; ++added) { 269 copyNext(targetReader, cleanupWriter, cleanupTypes[added]); 270 } 271 return cleanupFrame; 272 } 273 } 274 275 /** Implements {@code MethodHandles.GuardWithTest}. */ 276 static class GuardWithTest extends Transformer { 277 private final MethodHandle test; 278 private final MethodHandle target; 279 private final MethodHandle fallback; 280 281 private final EmulatedStackFrame.Range testArgsRange; 282 GuardWithTest(MethodHandle test, MethodHandle target, MethodHandle fallback)283 GuardWithTest(MethodHandle test, MethodHandle target, MethodHandle fallback) { 284 super(target.type()); 285 286 this.test = test; 287 this.target = target; 288 this.fallback = fallback; 289 290 // The test method might have a subset of the arguments of the handle / target. 291 testArgsRange = 292 EmulatedStackFrame.Range.of(target.type(), 0, test.type().parameterCount()); 293 } 294 295 @Override transform(EmulatedStackFrame emulatedStackFrame)296 public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable { 297 EmulatedStackFrame testFrame = EmulatedStackFrame.create(test.type()); 298 emulatedStackFrame.copyRangeTo(testFrame, testArgsRange, 0, 0); 299 300 // We know that the return value for test is going to be boolean.class. 301 StackFrameReader reader = new StackFrameReader(); 302 reader.attach(testFrame); 303 reader.makeReturnValueAccessor(); 304 invokeFromTransform(test, testFrame); 305 final boolean testResult = (boolean) reader.nextBoolean(); 306 if (testResult) { 307 invokeFromTransform(target, emulatedStackFrame); 308 } else { 309 invokeFromTransform(fallback, emulatedStackFrame); 310 } 311 } 312 } 313 314 /** Implements {@code MethodHandles.arrayElementGetter}. */ 315 static class ReferenceArrayElementGetter extends Transformer { 316 private final Class<?> arrayClass; 317 ReferenceArrayElementGetter(Class<?> arrayClass)318 ReferenceArrayElementGetter(Class<?> arrayClass) { 319 super( 320 MethodType.methodType( 321 arrayClass.getComponentType(), new Class<?>[] {arrayClass, int.class})); 322 this.arrayClass = arrayClass; 323 } 324 325 @Override transform(EmulatedStackFrame emulatedStackFrame)326 public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable { 327 final StackFrameReader reader = new StackFrameReader(); 328 reader.attach(emulatedStackFrame); 329 330 // Read the array object and the index from the stack frame. 331 final Object[] array = (Object[]) reader.nextReference(arrayClass); 332 final int index = reader.nextInt(); 333 334 // Write the array element back to the stack frame. 335 final StackFrameWriter writer = new StackFrameWriter(); 336 writer.attach(emulatedStackFrame); 337 writer.makeReturnValueAccessor(); 338 writer.putNextReference(array[index], arrayClass.getComponentType()); 339 } 340 } 341 342 /** Implements {@code MethodHandles.arrayElementSetter}. */ 343 static class ReferenceArrayElementSetter extends Transformer { 344 private final Class<?> arrayClass; 345 ReferenceArrayElementSetter(Class<?> arrayClass)346 ReferenceArrayElementSetter(Class<?> arrayClass) { 347 super( 348 MethodType.methodType( 349 void.class, 350 new Class<?>[] {arrayClass, int.class, arrayClass.getComponentType()})); 351 this.arrayClass = arrayClass; 352 } 353 354 @Override transform(EmulatedStackFrame emulatedStackFrame)355 public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable { 356 final StackFrameReader reader = new StackFrameReader(); 357 reader.attach(emulatedStackFrame); 358 359 // Read the array object, index and the value to write from the stack frame. 360 final Object[] array = (Object[]) reader.nextReference(arrayClass); 361 final int index = reader.nextInt(); 362 final Object value = reader.nextReference(arrayClass.getComponentType()); 363 364 array[index] = value; 365 } 366 } 367 368 /** Implements {@code MethodHandles.identity}. */ 369 static class ReferenceIdentity extends Transformer { 370 private final Class<?> type; 371 ReferenceIdentity(Class<?> type)372 ReferenceIdentity(Class<?> type) { 373 super(MethodType.methodType(type, type)); 374 this.type = type; 375 } 376 377 @Override transform(EmulatedStackFrame emulatedStackFrame)378 public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable { 379 final StackFrameReader reader = new StackFrameReader(); 380 reader.attach(emulatedStackFrame); 381 382 final StackFrameWriter writer = new StackFrameWriter(); 383 writer.attach(emulatedStackFrame); 384 writer.makeReturnValueAccessor(); 385 writer.putNextReference(reader.nextReference(type), type); 386 } 387 } 388 389 /** Implements {@code MethodHandles.makeZero}. */ 390 static class ZeroValue extends Transformer { ZeroValue(Class<?> type)391 public ZeroValue(Class<?> type) { 392 super(MethodType.methodType(type)); 393 } 394 395 @Override transform(EmulatedStackFrame emulatedStackFrame)396 public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable { 397 // Return-value is zero-initialized in emulatedStackFrame. 398 } 399 } 400 401 /** Implements {@code MethodHandles.arrayConstructor}. */ 402 static class ArrayConstructor extends Transformer { 403 private final Class<?> componentType; 404 ArrayConstructor(Class<?> arrayType)405 ArrayConstructor(Class<?> arrayType) { 406 super(MethodType.methodType(arrayType, int.class)); 407 componentType = arrayType.getComponentType(); 408 } 409 410 @Override transform(EmulatedStackFrame emulatedStackFrame)411 public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable { 412 final StackFrameReader reader = new StackFrameReader(); 413 reader.attach(emulatedStackFrame); 414 final int length = reader.nextInt(); 415 final Object array = Array.newInstance(componentType, length); 416 emulatedStackFrame.setReturnValueTo(array); 417 } 418 } 419 420 /** Implements {@code MethodHandles.arrayLength}. */ 421 static class ArrayLength extends Transformer { 422 private final Class<?> arrayType; 423 ArrayLength(Class<?> arrayType)424 ArrayLength(Class<?> arrayType) { 425 super(MethodType.methodType(int.class, arrayType)); 426 this.arrayType = arrayType; 427 } 428 429 @Override transform(EmulatedStackFrame emulatedStackFrame)430 public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable { 431 final StackFrameReader reader = new StackFrameReader(); 432 reader.attach(emulatedStackFrame); 433 final Object arrayObject = reader.nextReference(arrayType); 434 435 int length; 436 switch (Wrapper.basicTypeChar(arrayType.getComponentType())) { 437 case 'L': 438 length = ((Object[]) arrayObject).length; 439 break; 440 case 'Z': 441 length = ((boolean[]) arrayObject).length; 442 break; 443 case 'B': 444 length = ((byte[]) arrayObject).length; 445 break; 446 case 'C': 447 length = ((char[]) arrayObject).length; 448 break; 449 case 'S': 450 length = ((short[]) arrayObject).length; 451 break; 452 case 'I': 453 length = ((int[]) arrayObject).length; 454 break; 455 case 'J': 456 length = ((long[]) arrayObject).length; 457 break; 458 case 'F': 459 length = ((float[]) arrayObject).length; 460 break; 461 case 'D': 462 length = ((double[]) arrayObject).length; 463 break; 464 default: 465 throw new IllegalStateException("Unsupported type: " + arrayType); 466 } 467 468 final StackFrameWriter writer = new StackFrameWriter(); 469 writer.attach(emulatedStackFrame).makeReturnValueAccessor(); 470 writer.putNextInt(length); 471 } 472 } 473 474 /** Implements {@code MethodHandles.createMethodHandleForConstructor}. */ 475 static class Construct extends Transformer { 476 private final MethodHandle constructorHandle; 477 private final EmulatedStackFrame.Range callerRange; 478 Construct(MethodHandle constructorHandle, MethodType returnedType)479 Construct(MethodHandle constructorHandle, MethodType returnedType) { 480 super(returnedType); 481 this.constructorHandle = constructorHandle; 482 this.callerRange = EmulatedStackFrame.Range.all(type()); 483 } 484 getConstructorHandle()485 MethodHandle getConstructorHandle() { 486 return constructorHandle; 487 } 488 isAbstract(Class<?> klass)489 private static boolean isAbstract(Class<?> klass) { 490 return (klass.getModifiers() & Modifier.ABSTRACT) == Modifier.ABSTRACT; 491 } 492 checkInstantiable(Class<?> klass)493 private static void checkInstantiable(Class<?> klass) throws InstantiationException { 494 if (isAbstract(klass)) { 495 String s = klass.isInterface() ? "interface " : "abstract class "; 496 throw new InstantiationException("Can't instantiate " + s + klass); 497 } 498 } 499 500 @Override transform(EmulatedStackFrame emulatedStackFrame)501 public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable { 502 final Class<?> receiverType = constructorHandle.type().parameterType(0); 503 checkInstantiable(receiverType); 504 505 // Allocate memory for receiver. 506 Object receiver = Unsafe.getUnsafe().allocateInstance(receiverType); 507 508 // The MethodHandle type for the caller has the form of 509 // {rtype=T,ptypes=A1..An}. The constructor MethodHandle is of 510 // the form {rtype=void,ptypes=T,A1...An}. So the frame for 511 // the constructor needs to have a slot with the receiver 512 // in position 0. 513 EmulatedStackFrame constructorFrame = 514 EmulatedStackFrame.create(constructorHandle.type()); 515 constructorFrame.setReference(0, receiver); 516 emulatedStackFrame.copyRangeTo(constructorFrame, callerRange, 1, 0); 517 invokeExactFromTransform(constructorHandle, constructorFrame); 518 519 // Set return result for caller. 520 emulatedStackFrame.setReturnValueTo(receiver); 521 } 522 } 523 524 /** Implements {@code MethodHandle.bindTo}. */ 525 static class BindTo extends Transformer { 526 private final MethodHandle delegate; 527 private final Object receiver; 528 529 private final EmulatedStackFrame.Range range; 530 BindTo(MethodHandle delegate, Object receiver)531 BindTo(MethodHandle delegate, Object receiver) { 532 super(delegate.type().dropParameterTypes(0, 1)); 533 534 this.delegate = delegate; 535 this.receiver = receiver; 536 537 this.range = EmulatedStackFrame.Range.all(this.type()); 538 } 539 540 @Override transform(EmulatedStackFrame emulatedStackFrame)541 public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable { 542 // Create a new emulated stack frame with the full type (including the leading 543 // receiver reference). 544 EmulatedStackFrame stackFrame = EmulatedStackFrame.create(delegate.type()); 545 546 // The first reference argument must be the receiver. 547 stackFrame.setReference(0, receiver); 548 // Copy all other arguments. 549 emulatedStackFrame.copyRangeTo( 550 stackFrame, range, 1 /* referencesStart */, 0 /* stackFrameStart */); 551 552 // Perform the invoke. 553 invokeFromTransform(delegate, stackFrame); 554 stackFrame.copyReturnValueTo(emulatedStackFrame); 555 } 556 } 557 558 /** Implements {@code MethodHandle.filterReturnValue}. */ 559 static class FilterReturnValue extends Transformer { 560 private final MethodHandle target; 561 private final MethodHandle filter; 562 563 private final EmulatedStackFrame.Range allArgs; 564 FilterReturnValue(MethodHandle target, MethodHandle filter)565 FilterReturnValue(MethodHandle target, MethodHandle filter) { 566 super(MethodType.methodType(filter.type().rtype(), target.type().ptypes())); 567 568 this.target = target; 569 this.filter = filter; 570 571 allArgs = EmulatedStackFrame.Range.all(type()); 572 } 573 574 @Override transform(EmulatedStackFrame emulatedStackFrame)575 public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable { 576 // Create a new frame with the target's type and copy all arguments over. 577 // This frame differs in return type with |emulatedStackFrame| but will have 578 // the same parameter shapes. 579 EmulatedStackFrame targetFrame = EmulatedStackFrame.create(target.type()); 580 emulatedStackFrame.copyRangeTo(targetFrame, allArgs, 0, 0); 581 invokeFromTransform(target, targetFrame); 582 583 // Create an emulated frame for the filter and move the return value from 584 // target to the argument of the filter. 585 final EmulatedStackFrame filterFrame = EmulatedStackFrame.create(filter.type()); 586 final Class<?> filterArgumentType = target.type().rtype(); 587 if (filterArgumentType != void.class) { 588 final StackFrameReader returnValueReader = new StackFrameReader(); 589 returnValueReader.attach(targetFrame).makeReturnValueAccessor(); 590 591 final StackFrameWriter filterWriter = new StackFrameWriter(); 592 filterWriter.attach(filterFrame); 593 StackFrameAccessor.copyNext(returnValueReader, filterWriter, filterArgumentType); 594 } 595 596 // Invoke the filter and copy its return value back to the original frame. 597 invokeExactFromTransform(filter, filterFrame); 598 filterFrame.copyReturnValueTo(emulatedStackFrame); 599 } 600 } 601 602 /** Implements {@code MethodHandles.permuteArguments}. */ 603 static class PermuteArguments extends Transformer { 604 private final MethodHandle target; 605 private final int[] reorder; 606 PermuteArguments(MethodType type, MethodHandle target, int[] reorder)607 PermuteArguments(MethodType type, MethodHandle target, int[] reorder) { 608 super(type); 609 610 this.target = target; 611 this.reorder = reorder; 612 } 613 614 @Override transform(EmulatedStackFrame emulatedStackFrame)615 public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable { 616 final RandomOrderStackFrameReader reader = new RandomOrderStackFrameReader(); 617 reader.attach(emulatedStackFrame); 618 619 final EmulatedStackFrame calleeFrame = EmulatedStackFrame.create(target.type()); 620 final StackFrameWriter writer = new StackFrameWriter(); 621 writer.attach(calleeFrame); 622 623 final Class<?> [] ptypes = emulatedStackFrame.getMethodType().parameterArray(); 624 for (int i = 0; i < reorder.length; ++i) { 625 final int readerIndex = reorder[i]; 626 reader.moveTo(readerIndex); 627 StackFrameAccessor.copyNext(reader, writer, ptypes[readerIndex]); 628 } 629 630 invokeFromTransform(target, calleeFrame); 631 calleeFrame.copyReturnValueTo(emulatedStackFrame); 632 } 633 } 634 635 /** Implements {@code MethodHandle.asVarargsCollector}. */ 636 static class VarargsCollector extends Transformer { 637 final MethodHandle target; 638 private final Class<?> arrayType; 639 VarargsCollector(MethodHandle target)640 VarargsCollector(MethodHandle target) { 641 super(target.type()); 642 643 Class<?>[] parameterTypes = target.type().ptypes(); 644 if (!lastParameterTypeIsAnArray(parameterTypes)) { 645 throw new IllegalArgumentException("target does not have array as last parameter"); 646 } 647 this.target = target; 648 this.arrayType = parameterTypes[parameterTypes.length - 1]; 649 } 650 lastParameterTypeIsAnArray(Class<?>[] parameterTypes)651 private static boolean lastParameterTypeIsAnArray(Class<?>[] parameterTypes) { 652 if (parameterTypes.length == 0) return false; 653 return parameterTypes[parameterTypes.length - 1].isArray(); 654 } 655 656 @Override isVarargsCollector()657 public boolean isVarargsCollector() { 658 return true; 659 } 660 661 @Override asFixedArity()662 public MethodHandle asFixedArity() { 663 return target; 664 } 665 666 @Override asTypeUncached(MethodType newType)667 MethodHandle asTypeUncached(MethodType newType) { 668 // asType() behavior is specialized per: 669 // 670 // https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/invoke/MethodHandle.html#asVarargsCollector(java.lang.Class) 671 // 672 // "The behavior of asType is also specialized for variable arity adapters, to maintain 673 // the invariant that plain, inexact invoke is always equivalent to an asType call to 674 // adjust the target type, followed by invokeExact. Therefore, a variable arity 675 // adapter responds to an asType request by building a fixed arity collector, if and 676 // only if the adapter and requested type differ either in arity or trailing argument 677 // type. The resulting fixed arity collector has its type further adjusted 678 // (if necessary) to the requested type by pairwise conversion, as if by another 679 // application of asType." 680 final MethodType currentType = type(); 681 final MethodHandle currentFixedArity = asFixedArity(); 682 if (currentType.parameterCount() == newType.parameterCount() 683 && currentType 684 .lastParameterType() 685 .isAssignableFrom(newType.lastParameterType())) { 686 return asTypeCache = currentFixedArity.asType(newType); 687 } 688 689 final int arrayLength = newType.parameterCount() - currentType.parameterCount() + 1; 690 if (arrayLength < 0) { 691 // arrayType is definitely array per VarargsCollector constructor. 692 throwWrongMethodTypeException(currentType, newType); 693 } 694 695 MethodHandle collector = null; 696 try { 697 collector = currentFixedArity.asCollector(arrayType, arrayLength).asType(newType); 698 } catch (IllegalArgumentException ex) { 699 throwWrongMethodTypeException(currentType, newType); 700 } 701 return asTypeCache = collector; 702 } 703 704 @Override transform(EmulatedStackFrame callerFrame)705 public void transform(EmulatedStackFrame callerFrame) throws Throwable { 706 MethodType callerFrameType = callerFrame.getMethodType(); 707 Class<?>[] callerPTypes = callerFrameType.ptypes(); 708 Class<?>[] targetPTypes = type().ptypes(); 709 710 int lastTargetIndex = targetPTypes.length - 1; 711 if (callerPTypes.length == targetPTypes.length 712 && targetPTypes[lastTargetIndex].isAssignableFrom( 713 callerPTypes[lastTargetIndex])) { 714 // Caller frame matches target frame in the arity array parameter. Invoke 715 // immediately, and let the invoke() dispatch perform any necessary conversions 716 // on the other parameters present. 717 invokeFromTransform(target, callerFrame); 718 return; 719 } 720 721 if (callerPTypes.length < targetPTypes.length - 1) { 722 // Too few arguments to be compatible with variable arity invocation. 723 throwWrongMethodTypeException(callerFrameType, type()); 724 } 725 726 if (!MethodType.canConvert(type().rtype(), callerFrameType.rtype())) { 727 // Incompatible return type. 728 throwWrongMethodTypeException(callerFrameType, type()); 729 } 730 731 Class<?> elementType = targetPTypes[lastTargetIndex].getComponentType(); 732 if (!arityArgumentsConvertible(callerPTypes, lastTargetIndex, elementType)) { 733 // Wrong types to be compatible with variable arity invocation. 734 throwWrongMethodTypeException(callerFrameType, type()); 735 } 736 737 // Allocate targetFrame. 738 MethodType targetFrameType = makeTargetFrameType(callerFrameType, type()); 739 EmulatedStackFrame targetFrame = EmulatedStackFrame.create(targetFrameType); 740 prepareFrame(callerFrame, targetFrame); 741 742 // Invoke target. 743 invokeExactFromTransform(target, targetFrame); 744 745 // Copy return value to the caller's frame. 746 targetFrame.copyReturnValueTo(callerFrame); 747 } 748 749 @Override withVarargs(boolean makeVarargs)750 public MethodHandle withVarargs(boolean makeVarargs) { 751 return makeVarargs ? this : target; 752 } 753 throwWrongMethodTypeException(MethodType from, MethodType to)754 private static void throwWrongMethodTypeException(MethodType from, MethodType to) { 755 throw new WrongMethodTypeException("Cannot convert " + from + " to " + to); 756 } 757 arityArgumentsConvertible( Class<?>[] ptypes, int arityStart, Class<?> elementType)758 private static boolean arityArgumentsConvertible( 759 Class<?>[] ptypes, int arityStart, Class<?> elementType) { 760 if (ptypes.length - 1 == arityStart) { 761 if (ptypes[arityStart].isArray() 762 && ptypes[arityStart].getComponentType() == elementType) { 763 // The last ptype is in the same position as the arity 764 // array and has the same type. 765 return true; 766 } 767 } 768 769 for (int i = arityStart; i < ptypes.length; ++i) { 770 if (!MethodType.canConvert(ptypes[i], elementType)) { 771 return false; 772 } 773 } 774 return true; 775 } 776 referenceArray( StackFrameReader reader, Class<?>[] ptypes, Class<?> elementType, int offset, int length)777 private static Object referenceArray( 778 StackFrameReader reader, 779 Class<?>[] ptypes, 780 Class<?> elementType, 781 int offset, 782 int length) { 783 Object arityArray = Array.newInstance(elementType, length); 784 for (int i = 0; i < length; ++i) { 785 Class<?> argumentType = ptypes[i + offset]; 786 Object o = null; 787 switch (Wrapper.basicTypeChar(argumentType)) { 788 case 'L': 789 o = reader.nextReference(argumentType); 790 break; 791 case 'I': 792 o = reader.nextInt(); 793 break; 794 case 'J': 795 o = reader.nextLong(); 796 break; 797 case 'B': 798 o = reader.nextByte(); 799 break; 800 case 'S': 801 o = reader.nextShort(); 802 break; 803 case 'C': 804 o = reader.nextChar(); 805 break; 806 case 'Z': 807 o = reader.nextBoolean(); 808 break; 809 case 'F': 810 o = reader.nextFloat(); 811 break; 812 case 'D': 813 o = reader.nextDouble(); 814 break; 815 } 816 Array.set(arityArray, i, elementType.cast(o)); 817 } 818 return arityArray; 819 } 820 intArray( StackFrameReader reader, Class<?> ptypes[], int offset, int length)821 private static Object intArray( 822 StackFrameReader reader, Class<?> ptypes[], int offset, int length) { 823 int[] arityArray = new int[length]; 824 for (int i = 0; i < length; ++i) { 825 Class<?> argumentType = ptypes[i + offset]; 826 switch (Wrapper.basicTypeChar(argumentType)) { 827 case 'I': 828 arityArray[i] = reader.nextInt(); 829 break; 830 case 'S': 831 arityArray[i] = reader.nextShort(); 832 break; 833 case 'B': 834 arityArray[i] = reader.nextByte(); 835 break; 836 default: 837 arityArray[i] = (Integer) reader.nextReference(argumentType); 838 break; 839 } 840 } 841 return arityArray; 842 } 843 longArray( StackFrameReader reader, Class<?> ptypes[], int offset, int length)844 private static Object longArray( 845 StackFrameReader reader, Class<?> ptypes[], int offset, int length) { 846 long[] arityArray = new long[length]; 847 for (int i = 0; i < length; ++i) { 848 Class<?> argumentType = ptypes[i + offset]; 849 switch (Wrapper.basicTypeChar(argumentType)) { 850 case 'J': 851 arityArray[i] = reader.nextLong(); 852 break; 853 case 'I': 854 arityArray[i] = reader.nextInt(); 855 break; 856 case 'S': 857 arityArray[i] = reader.nextShort(); 858 break; 859 case 'B': 860 arityArray[i] = reader.nextByte(); 861 break; 862 default: 863 arityArray[i] = (Long) reader.nextReference(argumentType); 864 break; 865 } 866 } 867 return arityArray; 868 } 869 byteArray( StackFrameReader reader, Class<?> ptypes[], int offset, int length)870 private static Object byteArray( 871 StackFrameReader reader, Class<?> ptypes[], int offset, int length) { 872 byte[] arityArray = new byte[length]; 873 for (int i = 0; i < length; ++i) { 874 Class<?> argumentType = ptypes[i + offset]; 875 switch (Wrapper.basicTypeChar(argumentType)) { 876 case 'B': 877 arityArray[i] = reader.nextByte(); 878 break; 879 default: 880 arityArray[i] = (Byte) reader.nextReference(argumentType); 881 break; 882 } 883 } 884 return arityArray; 885 } 886 shortArray( StackFrameReader reader, Class<?> ptypes[], int offset, int length)887 private static Object shortArray( 888 StackFrameReader reader, Class<?> ptypes[], int offset, int length) { 889 short[] arityArray = new short[length]; 890 for (int i = 0; i < length; ++i) { 891 Class<?> argumentType = ptypes[i + offset]; 892 switch (Wrapper.basicTypeChar(argumentType)) { 893 case 'S': 894 arityArray[i] = reader.nextShort(); 895 break; 896 case 'B': 897 arityArray[i] = reader.nextByte(); 898 break; 899 default: 900 arityArray[i] = (Short) reader.nextReference(argumentType); 901 break; 902 } 903 } 904 return arityArray; 905 } 906 charArray( StackFrameReader reader, Class<?> ptypes[], int offset, int length)907 private static Object charArray( 908 StackFrameReader reader, Class<?> ptypes[], int offset, int length) { 909 char[] arityArray = new char[length]; 910 for (int i = 0; i < length; ++i) { 911 Class<?> argumentType = ptypes[i + offset]; 912 switch (Wrapper.basicTypeChar(argumentType)) { 913 case 'C': 914 arityArray[i] = reader.nextChar(); 915 break; 916 default: 917 arityArray[i] = (Character) reader.nextReference(argumentType); 918 break; 919 } 920 } 921 return arityArray; 922 } 923 booleanArray( StackFrameReader reader, Class<?> ptypes[], int offset, int length)924 private static Object booleanArray( 925 StackFrameReader reader, Class<?> ptypes[], int offset, int length) { 926 boolean[] arityArray = new boolean[length]; 927 for (int i = 0; i < length; ++i) { 928 Class<?> argumentType = ptypes[i + offset]; 929 switch (Wrapper.basicTypeChar(argumentType)) { 930 case 'Z': 931 arityArray[i] = reader.nextBoolean(); 932 break; 933 default: 934 arityArray[i] = (Boolean) reader.nextReference(argumentType); 935 break; 936 } 937 } 938 return arityArray; 939 } 940 floatArray( StackFrameReader reader, Class<?> ptypes[], int offset, int length)941 private static Object floatArray( 942 StackFrameReader reader, Class<?> ptypes[], int offset, int length) { 943 float[] arityArray = new float[length]; 944 for (int i = 0; i < length; ++i) { 945 Class<?> argumentType = ptypes[i + offset]; 946 switch (Wrapper.basicTypeChar(argumentType)) { 947 case 'F': 948 arityArray[i] = reader.nextFloat(); 949 break; 950 case 'J': 951 arityArray[i] = reader.nextLong(); 952 break; 953 case 'I': 954 arityArray[i] = reader.nextInt(); 955 break; 956 case 'S': 957 arityArray[i] = reader.nextShort(); 958 break; 959 case 'B': 960 arityArray[i] = reader.nextByte(); 961 break; 962 default: 963 arityArray[i] = (Float) reader.nextReference(argumentType); 964 break; 965 } 966 } 967 return arityArray; 968 } 969 doubleArray( StackFrameReader reader, Class<?> ptypes[], int offset, int length)970 private static Object doubleArray( 971 StackFrameReader reader, Class<?> ptypes[], int offset, int length) { 972 double[] arityArray = new double[length]; 973 for (int i = 0; i < length; ++i) { 974 Class<?> argumentType = ptypes[i + offset]; 975 switch (Wrapper.basicTypeChar(argumentType)) { 976 case 'D': 977 arityArray[i] = reader.nextDouble(); 978 break; 979 case 'F': 980 arityArray[i] = reader.nextFloat(); 981 break; 982 case 'J': 983 arityArray[i] = reader.nextLong(); 984 break; 985 case 'I': 986 arityArray[i] = reader.nextInt(); 987 break; 988 case 'S': 989 arityArray[i] = reader.nextShort(); 990 break; 991 case 'B': 992 arityArray[i] = reader.nextByte(); 993 break; 994 default: 995 arityArray[i] = (Double) reader.nextReference(argumentType); 996 break; 997 } 998 } 999 return arityArray; 1000 } 1001 makeArityArray( MethodType callerFrameType, StackFrameReader callerFrameReader, int indexOfArityArray, Class<?> arityArrayType)1002 private static Object makeArityArray( 1003 MethodType callerFrameType, 1004 StackFrameReader callerFrameReader, 1005 int indexOfArityArray, 1006 Class<?> arityArrayType) { 1007 int arityArrayLength = callerFrameType.ptypes().length - indexOfArityArray; 1008 Class<?> elementType = arityArrayType.getComponentType(); 1009 Class<?>[] callerPTypes = callerFrameType.ptypes(); 1010 1011 char elementBasicType = Wrapper.basicTypeChar(elementType); 1012 switch (elementBasicType) { 1013 case 'L': 1014 return referenceArray( 1015 callerFrameReader, 1016 callerPTypes, 1017 elementType, 1018 indexOfArityArray, 1019 arityArrayLength); 1020 case 'I': 1021 return intArray( 1022 callerFrameReader, callerPTypes, 1023 indexOfArityArray, arityArrayLength); 1024 case 'J': 1025 return longArray( 1026 callerFrameReader, callerPTypes, 1027 indexOfArityArray, arityArrayLength); 1028 case 'B': 1029 return byteArray( 1030 callerFrameReader, callerPTypes, 1031 indexOfArityArray, arityArrayLength); 1032 case 'S': 1033 return shortArray( 1034 callerFrameReader, callerPTypes, 1035 indexOfArityArray, arityArrayLength); 1036 case 'C': 1037 return charArray( 1038 callerFrameReader, callerPTypes, 1039 indexOfArityArray, arityArrayLength); 1040 case 'Z': 1041 return booleanArray( 1042 callerFrameReader, callerPTypes, 1043 indexOfArityArray, arityArrayLength); 1044 case 'F': 1045 return floatArray( 1046 callerFrameReader, callerPTypes, 1047 indexOfArityArray, arityArrayLength); 1048 case 'D': 1049 return doubleArray( 1050 callerFrameReader, callerPTypes, 1051 indexOfArityArray, arityArrayLength); 1052 } 1053 throw new InternalError("Unexpected type: " + elementType); 1054 } 1055 collectArguments( char basicComponentType, Class<?> componentType, StackFrameReader reader, Class<?>[] types, int startIdx, int length)1056 public static Object collectArguments( 1057 char basicComponentType, 1058 Class<?> componentType, 1059 StackFrameReader reader, 1060 Class<?>[] types, 1061 int startIdx, 1062 int length) { 1063 switch (basicComponentType) { 1064 case 'L': 1065 return referenceArray(reader, types, componentType, startIdx, length); 1066 case 'I': 1067 return intArray(reader, types, startIdx, length); 1068 case 'J': 1069 return longArray(reader, types, startIdx, length); 1070 case 'B': 1071 return byteArray(reader, types, startIdx, length); 1072 case 'S': 1073 return shortArray(reader, types, startIdx, length); 1074 case 'C': 1075 return charArray(reader, types, startIdx, length); 1076 case 'Z': 1077 return booleanArray(reader, types, startIdx, length); 1078 case 'F': 1079 return floatArray(reader, types, startIdx, length); 1080 case 'D': 1081 return doubleArray(reader, types, startIdx, length); 1082 } 1083 throw new InternalError("Unexpected type: " + basicComponentType); 1084 } 1085 copyParameter( StackFrameReader reader, StackFrameWriter writer, Class<?> ptype)1086 private static void copyParameter( 1087 StackFrameReader reader, StackFrameWriter writer, Class<?> ptype) { 1088 switch (Wrapper.basicTypeChar(ptype)) { 1089 case 'L': 1090 writer.putNextReference(reader.nextReference(ptype), ptype); 1091 break; 1092 case 'I': 1093 writer.putNextInt(reader.nextInt()); 1094 break; 1095 case 'J': 1096 writer.putNextLong(reader.nextLong()); 1097 break; 1098 case 'B': 1099 writer.putNextByte(reader.nextByte()); 1100 break; 1101 case 'S': 1102 writer.putNextShort(reader.nextShort()); 1103 break; 1104 case 'C': 1105 writer.putNextChar(reader.nextChar()); 1106 break; 1107 case 'Z': 1108 writer.putNextBoolean(reader.nextBoolean()); 1109 break; 1110 case 'F': 1111 writer.putNextFloat(reader.nextFloat()); 1112 break; 1113 case 'D': 1114 writer.putNextDouble(reader.nextDouble()); 1115 break; 1116 default: 1117 throw new InternalError("Unexpected type: " + ptype); 1118 } 1119 } 1120 prepareFrame( EmulatedStackFrame callerFrame, EmulatedStackFrame targetFrame)1121 private static void prepareFrame( 1122 EmulatedStackFrame callerFrame, EmulatedStackFrame targetFrame) { 1123 StackFrameWriter targetWriter = new StackFrameWriter(); 1124 targetWriter.attach(targetFrame); 1125 StackFrameReader callerReader = new StackFrameReader(); 1126 callerReader.attach(callerFrame); 1127 1128 // Copy parameters from |callerFrame| to |targetFrame| leaving room for arity array. 1129 MethodType targetMethodType = targetFrame.getMethodType(); 1130 int indexOfArityArray = targetMethodType.ptypes().length - 1; 1131 for (int i = 0; i < indexOfArityArray; ++i) { 1132 Class<?> ptype = targetMethodType.ptypes()[i]; 1133 copyParameter(callerReader, targetWriter, ptype); 1134 } 1135 1136 // Add arity array as last parameter in |targetFrame|. 1137 Class<?> arityArrayType = targetMethodType.ptypes()[indexOfArityArray]; 1138 Object arityArray = 1139 makeArityArray( 1140 callerFrame.getMethodType(), 1141 callerReader, 1142 indexOfArityArray, 1143 arityArrayType); 1144 targetWriter.putNextReference(arityArray, arityArrayType); 1145 } 1146 1147 /** 1148 * Computes the frame type to invoke the target method handle with. This is the same as the 1149 * caller frame type, but with the trailing argument being the array type that is the 1150 * trailing argument in the target method handle. 1151 * 1152 * <p>Suppose the targetType is (T0, T1, T2[])RT and the callerType is (C0, C1, C2, C3)RC 1153 * then the constructed type is (C0, C1, T2[])RC. 1154 */ makeTargetFrameType( MethodType callerType, MethodType targetType)1155 private static MethodType makeTargetFrameType( 1156 MethodType callerType, MethodType targetType) { 1157 final int ptypesLength = targetType.ptypes().length; 1158 final Class<?>[] ptypes = new Class<?>[ptypesLength]; 1159 // Copy types from caller types to new methodType. 1160 System.arraycopy(callerType.ptypes(), 0, ptypes, 0, ptypesLength - 1); 1161 // Set the last element in the type array to be the 1162 // varargs array of the target. 1163 ptypes[ptypesLength - 1] = targetType.ptypes()[ptypesLength - 1]; 1164 return MethodType.methodType(callerType.rtype(), ptypes); 1165 } 1166 } 1167 1168 /** Implements {@code MethodHandles.invoker} and {@code MethodHandles.exactInvoker}. */ 1169 static class Invoker extends Transformer { 1170 private final MethodType targetType; 1171 private final boolean isExactInvoker; 1172 private final EmulatedStackFrame.Range copyRange; 1173 Invoker(MethodType targetType, boolean isExactInvoker)1174 Invoker(MethodType targetType, boolean isExactInvoker) { 1175 super(targetType.insertParameterTypes(0, MethodHandle.class)); 1176 this.targetType = targetType; 1177 this.isExactInvoker = isExactInvoker; 1178 copyRange = EmulatedStackFrame.Range.from(type(), 1); 1179 } 1180 1181 @Override transform(EmulatedStackFrame emulatedStackFrame)1182 public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable { 1183 // The first argument to the stack frame is the handle that needs to be invoked. 1184 MethodHandle target = emulatedStackFrame.getReference(0, MethodHandle.class); 1185 1186 // All other arguments must be copied to the target frame. 1187 EmulatedStackFrame targetFrame = EmulatedStackFrame.create(targetType); 1188 emulatedStackFrame.copyRangeTo(targetFrame, copyRange, 0, 0); 1189 1190 // Finally, invoke the handle and copy the return value. 1191 if (isExactInvoker) { 1192 invokeExactFromTransform(target, targetFrame); 1193 } else { 1194 invokeFromTransform(target, targetFrame); 1195 } 1196 targetFrame.copyReturnValueTo(emulatedStackFrame); 1197 } 1198 1199 /** 1200 * Checks whether two method types are compatible as an exact match. The exact match is 1201 * based on the erased form (all reference types treated as Object). 1202 * 1203 * @param callsiteType the MethodType associated with the invocation. 1204 * @param targetType the MethodType of the MethodHandle being invoked. 1205 * @return true if {@code callsiteType} and {@code targetType} are an exact match. 1206 */ exactMatch(MethodType callsiteType, MethodType targetType)1207 private static boolean exactMatch(MethodType callsiteType, MethodType targetType) { 1208 final int parameterCount = callsiteType.parameterCount(); 1209 if (callsiteType.parameterCount() != targetType.parameterCount()) { 1210 return false; 1211 } 1212 1213 for (int i = 0; i < parameterCount; ++i) { 1214 Class argumentType = callsiteType.parameterType(i); 1215 Class parameterType = targetType.parameterType(i); 1216 if (!exactMatch(argumentType, parameterType)) { 1217 return false; 1218 } 1219 } 1220 // Check return type, noting it's always okay to discard the return value. 1221 return callsiteType.returnType() == Void.TYPE 1222 || exactMatch(callsiteType.returnType(), targetType.returnType()); 1223 } 1224 1225 /** 1226 * Checks whether two types are an exact match. The exact match is based on the erased types 1227 * so any two reference types match, but primitive types must be the same. 1228 * 1229 * @param lhs first class to compare. 1230 * @param rhs second class to compare. 1231 * @return true if both classes satisfy the exact match criteria. 1232 */ exactMatch(Class lhs, Class rhs)1233 private static boolean exactMatch(Class lhs, Class rhs) { 1234 if (lhs.isPrimitive() || rhs.isPrimitive()) { 1235 return lhs == rhs; 1236 } 1237 return true; // Both types are references, compatibility is checked at the point of use. 1238 } 1239 } 1240 1241 /** Implements {@code MethodHandle.asSpreader}. */ 1242 static class Spreader extends Transformer { 1243 /** The method handle we're delegating to. */ 1244 private final MethodHandle target; 1245 1246 /** 1247 * The offset of the trailing array argument in the list of arguments to this transformer. 1248 * The array argument is always the last argument. 1249 */ 1250 private final int arrayOffset; 1251 1252 /** The component type of the array. */ 1253 private final Class<?> componentType; 1254 1255 /** 1256 * The number of input arguments that will be present in the array. In other words, this is 1257 * the expected array length. 1258 */ 1259 private final int numArrayArgs; 1260 1261 /** 1262 * Range of arguments to copy verbatim from the input frame, This will cover all arguments 1263 * that aren't a part of the trailing array. 1264 */ 1265 private final Range leadingRange; 1266 private final Range trailingRange; 1267 Spreader(MethodHandle target, MethodType spreaderType, int spreadArgPos, int numArrayArgs)1268 Spreader(MethodHandle target, MethodType spreaderType, int spreadArgPos, int numArrayArgs) { 1269 super(spreaderType); 1270 this.target = target; 1271 arrayOffset = spreadArgPos; 1272 componentType = spreaderType.ptypes()[arrayOffset].getComponentType(); 1273 if (componentType == null) { 1274 throw new AssertionError("Argument " + spreadArgPos + " must be an array."); 1275 } 1276 this.numArrayArgs = numArrayArgs; 1277 // Copy all args except the spreader array. 1278 leadingRange = EmulatedStackFrame.Range.of(spreaderType, 0, arrayOffset); 1279 trailingRange = EmulatedStackFrame.Range.from(spreaderType, arrayOffset + 1); 1280 } 1281 1282 @Override transform(EmulatedStackFrame callerFrame)1283 public void transform(EmulatedStackFrame callerFrame) throws Throwable { 1284 // Get the array reference and check that its length is as expected. 1285 final Class<?> arrayType = type().parameterType(arrayOffset); 1286 final Object arrayObj = callerFrame.getReference(arrayOffset, arrayType); 1287 1288 // The incoming array may be null if the expected number of array arguments is zero. 1289 final int arrayLength = 1290 (numArrayArgs == 0 && arrayObj == null) ? 0 : Array.getLength(arrayObj); 1291 if (arrayLength != numArrayArgs) { 1292 throw new IllegalArgumentException( 1293 "Invalid array length " + arrayLength + " expected " + numArrayArgs); 1294 } 1295 1296 // Create a new stack frame for the callee. 1297 EmulatedStackFrame targetFrame = EmulatedStackFrame.create(target.type()); 1298 1299 // Copy ranges not affected by the spreading. 1300 callerFrame.copyRangeTo(targetFrame, leadingRange, 0, 0); 1301 if (componentType.isPrimitive()) { 1302 final int elementBytes = EmulatedStackFrame.getSize(componentType); 1303 final int spreadBytes = elementBytes * arrayLength; 1304 callerFrame.copyRangeTo(targetFrame, trailingRange, 1305 leadingRange.numReferences, leadingRange.numBytes + spreadBytes); 1306 } else { 1307 callerFrame.copyRangeTo(targetFrame, trailingRange, 1308 leadingRange.numReferences + numArrayArgs, leadingRange.numBytes); 1309 } 1310 1311 if (arrayLength != 0) { 1312 StackFrameWriter writer = new StackFrameWriter(); 1313 writer.attach(targetFrame, 1314 arrayOffset, 1315 leadingRange.numReferences, 1316 leadingRange.numBytes); 1317 spreadArray(arrayType, arrayObj, writer); 1318 } 1319 1320 invokeExactFromTransform(target, targetFrame); 1321 targetFrame.copyReturnValueTo(callerFrame); 1322 } 1323 spreadArray(Class<?> arrayType, Object arrayObj, StackFrameWriter writer)1324 private void spreadArray(Class<?> arrayType, Object arrayObj, StackFrameWriter writer) { 1325 final Class<?> componentType = arrayType.getComponentType(); 1326 switch (Wrapper.basicTypeChar(componentType)) { 1327 case 'L': 1328 { 1329 final Object[] array = (Object[]) arrayObj; 1330 for (int i = 0; i < array.length; ++i) { 1331 writer.putNextReference(array[i], componentType); 1332 } 1333 break; 1334 } 1335 case 'I': 1336 { 1337 final int[] array = (int[]) arrayObj; 1338 for (int i = 0; i < array.length; ++i) { 1339 writer.putNextInt(array[i]); 1340 } 1341 break; 1342 } 1343 case 'J': 1344 { 1345 final long[] array = (long[]) arrayObj; 1346 for (int i = 0; i < array.length; ++i) { 1347 writer.putNextLong(array[i]); 1348 } 1349 break; 1350 } 1351 case 'B': 1352 { 1353 final byte[] array = (byte[]) arrayObj; 1354 for (int i = 0; i < array.length; ++i) { 1355 writer.putNextByte(array[i]); 1356 } 1357 break; 1358 } 1359 case 'S': 1360 { 1361 final short[] array = (short[]) arrayObj; 1362 for (int i = 0; i < array.length; ++i) { 1363 writer.putNextShort(array[i]); 1364 } 1365 break; 1366 } 1367 case 'C': 1368 { 1369 final char[] array = (char[]) arrayObj; 1370 for (int i = 0; i < array.length; ++i) { 1371 writer.putNextChar(array[i]); 1372 } 1373 break; 1374 } 1375 case 'Z': 1376 { 1377 final boolean[] array = (boolean[]) arrayObj; 1378 for (int i = 0; i < array.length; ++i) { 1379 writer.putNextBoolean(array[i]); 1380 } 1381 break; 1382 } 1383 case 'F': 1384 { 1385 final float[] array = (float[]) arrayObj; 1386 for (int i = 0; i < array.length; ++i) { 1387 writer.putNextFloat(array[i]); 1388 } 1389 break; 1390 } 1391 case 'D': 1392 { 1393 final double[] array = (double[]) arrayObj; 1394 for (int i = 0; i < array.length; ++i) { 1395 writer.putNextDouble(array[i]); 1396 } 1397 break; 1398 } 1399 } 1400 } 1401 } 1402 1403 /** Implements {@code MethodHandle.asCollector}. */ 1404 static class Collector extends Transformer { 1405 private final MethodHandle target; 1406 1407 /** 1408 * The array start is the position in the target outputs of the array collecting arguments 1409 * and the position in the source inputs where collection starts. 1410 */ 1411 private final int arrayOffset; 1412 1413 /** 1414 * The array length is the number of arguments to be collected. 1415 */ 1416 private final int arrayLength; 1417 1418 /** The type of the array. */ 1419 private final Class arrayType; 1420 1421 /** 1422 * Range of arguments to copy verbatim from the start of the input frame. 1423 */ 1424 private final Range leadingRange; 1425 1426 /** 1427 * Range of arguments to copy verbatim from the end of the input frame. 1428 */ 1429 private final Range trailingRange; 1430 Collector(MethodHandle delegate, Class<?> arrayType, int start, int length)1431 Collector(MethodHandle delegate, Class<?> arrayType, int start, int length) { 1432 super(delegate.type().asCollectorType(arrayType, start, length)); 1433 this.target = delegate; 1434 this.arrayOffset = start; 1435 this.arrayLength = length; 1436 this.arrayType = arrayType; 1437 1438 // Build ranges of arguments to be copied. 1439 leadingRange = EmulatedStackFrame.Range.of(type(), 0, arrayOffset); 1440 trailingRange = EmulatedStackFrame.Range.from(type(), arrayOffset + arrayLength); 1441 } 1442 1443 @Override transform(EmulatedStackFrame callerFrame)1444 public void transform(EmulatedStackFrame callerFrame) throws Throwable { 1445 // Create a new stack frame for the callee. 1446 final EmulatedStackFrame targetFrame = EmulatedStackFrame.create(target.type()); 1447 1448 // Copy arguments before the collector array. 1449 callerFrame.copyRangeTo(targetFrame, leadingRange, 0, 0); 1450 1451 // Copy arguments after the collector array. 1452 callerFrame.copyRangeTo(targetFrame, trailingRange, 1453 leadingRange.numReferences + 1, leadingRange.numBytes); 1454 1455 // Collect arguments between arrayOffset and arrayOffset + arrayLength. 1456 final StackFrameWriter writer = new StackFrameWriter(); 1457 writer.attach(targetFrame, arrayOffset, leadingRange.numReferences, leadingRange.numBytes); 1458 final StackFrameReader reader = new StackFrameReader(); 1459 reader.attach(callerFrame, arrayOffset, leadingRange.numReferences, leadingRange.numBytes); 1460 1461 final char arrayTypeChar = Wrapper.basicTypeChar(arrayType.getComponentType()); 1462 switch (arrayTypeChar) { 1463 case 'L': 1464 { 1465 // Reference arrays are the only case where the component type of the 1466 // array we construct might differ from the type of the reference we read 1467 // from the stack frame. 1468 final Class<?> targetType = target.type().ptypes()[arrayOffset]; 1469 final Class<?> arrayComponentType = arrayType.getComponentType(); 1470 Object[] arr = 1471 (Object[]) Array.newInstance(arrayComponentType, arrayLength); 1472 for (int i = 0; i < arrayLength; ++i) { 1473 arr[i] = reader.nextReference(arrayComponentType); 1474 } 1475 writer.putNextReference(arr, targetType); 1476 break; 1477 } 1478 case 'I': 1479 { 1480 int[] array = new int[arrayLength]; 1481 for (int i = 0; i < arrayLength; ++i) { 1482 array[i] = reader.nextInt(); 1483 } 1484 writer.putNextReference(array, int[].class); 1485 break; 1486 } 1487 case 'J': 1488 { 1489 long[] array = new long[arrayLength]; 1490 for (int i = 0; i < arrayLength; ++i) { 1491 array[i] = reader.nextLong(); 1492 } 1493 writer.putNextReference(array, long[].class); 1494 break; 1495 } 1496 case 'B': 1497 { 1498 byte[] array = new byte[arrayLength]; 1499 for (int i = 0; i < arrayLength; ++i) { 1500 array[i] = reader.nextByte(); 1501 } 1502 writer.putNextReference(array, byte[].class); 1503 break; 1504 } 1505 case 'S': 1506 { 1507 short[] array = new short[arrayLength]; 1508 for (int i = 0; i < arrayLength; ++i) { 1509 array[i] = reader.nextShort(); 1510 } 1511 writer.putNextReference(array, short[].class); 1512 break; 1513 } 1514 case 'C': 1515 { 1516 char[] array = new char[arrayLength]; 1517 for (int i = 0; i < arrayLength; ++i) { 1518 array[i] = reader.nextChar(); 1519 } 1520 writer.putNextReference(array, char[].class); 1521 break; 1522 } 1523 case 'Z': 1524 { 1525 boolean[] array = new boolean[arrayLength]; 1526 for (int i = 0; i < arrayLength; ++i) { 1527 array[i] = reader.nextBoolean(); 1528 } 1529 writer.putNextReference(array, boolean[].class); 1530 break; 1531 } 1532 case 'F': 1533 { 1534 float[] array = new float[arrayLength]; 1535 for (int i = 0; i < arrayLength; ++i) { 1536 array[i] = reader.nextFloat(); 1537 } 1538 writer.putNextReference(array, float[].class); 1539 break; 1540 } 1541 case 'D': 1542 { 1543 double[] array = new double[arrayLength]; 1544 for (int i = 0; i < arrayLength; ++i) { 1545 array[i] = reader.nextDouble(); 1546 } 1547 writer.putNextReference(array, double[].class); 1548 break; 1549 } 1550 } 1551 1552 invokeFromTransform(target, targetFrame); 1553 targetFrame.copyReturnValueTo(callerFrame); 1554 } 1555 } 1556 1557 /** Implements {@code MethodHandles.filterArguments}. */ 1558 static class FilterArguments extends Transformer { 1559 /** The target handle. */ 1560 private final MethodHandle target; 1561 /** Index of the first argument to filter */ 1562 private final int pos; 1563 /** The list of filters to apply */ 1564 private final MethodHandle[] filters; 1565 FilterArguments(MethodHandle target, int pos, MethodHandle... filters)1566 FilterArguments(MethodHandle target, int pos, MethodHandle... filters) { 1567 super(deriveType(target, pos, filters)); 1568 1569 this.target = target; 1570 this.pos = pos; 1571 this.filters = filters; 1572 } 1573 deriveType(MethodHandle target, int pos, MethodHandle[] filters)1574 private static MethodType deriveType(MethodHandle target, int pos, MethodHandle[] filters) { 1575 final Class<?>[] filterArgs = new Class<?>[filters.length]; 1576 for (int i = 0; i < filters.length; ++i) { 1577 filterArgs[i] = filters[i].type().parameterType(0); 1578 } 1579 1580 return target.type().replaceParameterTypes(pos, pos + filters.length, filterArgs); 1581 } 1582 1583 @Override transform(EmulatedStackFrame stackFrame)1584 public void transform(EmulatedStackFrame stackFrame) throws Throwable { 1585 final StackFrameReader reader = new StackFrameReader(); 1586 reader.attach(stackFrame); 1587 1588 EmulatedStackFrame transformedFrame = EmulatedStackFrame.create(target.type()); 1589 final StackFrameWriter writer = new StackFrameWriter(); 1590 writer.attach(transformedFrame); 1591 1592 final Class<?>[] ptypes = target.type().ptypes(); 1593 for (int i = 0; i < ptypes.length; ++i) { 1594 // Check whether the current argument has a filter associated with it. 1595 // If it has no filter, no further action need be taken. 1596 final Class<?> ptype = ptypes[i]; 1597 final MethodHandle filter; 1598 if (i < pos) { 1599 filter = null; 1600 } else if (i >= pos + filters.length) { 1601 filter = null; 1602 } else { 1603 filter = filters[i - pos]; 1604 } 1605 1606 if (filter != null) { 1607 // Note that filter.type() must be (ptype)ptype - this is checked before 1608 // this transformer is created. 1609 EmulatedStackFrame filterFrame = EmulatedStackFrame.create(filter.type()); 1610 1611 // Copy the next argument from the stack frame to the filter frame. 1612 final StackFrameWriter filterWriter = new StackFrameWriter(); 1613 filterWriter.attach(filterFrame); 1614 copyNext(reader, filterWriter, filter.type().ptypes()[0]); 1615 1616 invokeFromTransform(filter, filterFrame); 1617 1618 // Copy the argument back from the filter frame to the stack frame. 1619 final StackFrameReader filterReader = new StackFrameReader(); 1620 filterReader.attach(filterFrame); 1621 filterReader.makeReturnValueAccessor(); 1622 copyNext(filterReader, writer, ptype); 1623 } else { 1624 // There's no filter associated with this frame, just copy the next argument 1625 // over. 1626 copyNext(reader, writer, ptype); 1627 } 1628 } 1629 1630 invokeFromTransform(target, transformedFrame); 1631 transformedFrame.copyReturnValueTo(stackFrame); 1632 } 1633 } 1634 1635 /** Implements {@code MethodHandles.collectArguments}. */ 1636 static class CollectArguments extends Transformer { 1637 private final MethodHandle target; 1638 private final MethodHandle collector; 1639 private final int pos; 1640 1641 /** The range of input arguments we copy to the collector. */ 1642 private final Range collectorRange; 1643 1644 /** 1645 * The first range of arguments we copy to the target. These are arguments in the range [0, 1646 * pos). Note that arg[pos] is the return value of the filter. 1647 */ 1648 private final Range range1; 1649 1650 /** 1651 * The second range of arguments we copy to the target. These are arguments in the range 1652 * (pos, N], where N is the number of target arguments. 1653 */ 1654 private final Range range2; 1655 1656 private final int referencesOffset; 1657 private final int stackFrameOffset; 1658 CollectArguments( MethodHandle target, MethodHandle collector, int pos, MethodType adapterType)1659 CollectArguments( 1660 MethodHandle target, MethodHandle collector, int pos, MethodType adapterType) { 1661 super(adapterType); 1662 1663 this.target = target; 1664 this.collector = collector; 1665 this.pos = pos; 1666 1667 final int numFilterArgs = collector.type().parameterCount(); 1668 collectorRange = Range.of(type(), pos, pos + numFilterArgs); 1669 1670 range1 = Range.of(type(), 0, pos); 1671 this.range2 = Range.from(type(), pos + numFilterArgs); 1672 1673 // Calculate the number of primitive bytes (or references) we copy to the 1674 // target frame based on the return value of the combiner. 1675 final Class<?> collectorRType = collector.type().rtype(); 1676 if (collectorRType == void.class) { 1677 stackFrameOffset = 0; 1678 referencesOffset = 0; 1679 } else if (collectorRType.isPrimitive()) { 1680 stackFrameOffset = EmulatedStackFrame.getSize(collectorRType); 1681 referencesOffset = 0; 1682 } else { 1683 stackFrameOffset = 0; 1684 referencesOffset = 1; 1685 } 1686 } 1687 1688 @Override transform(EmulatedStackFrame stackFrame)1689 public void transform(EmulatedStackFrame stackFrame) throws Throwable { 1690 // First invoke the collector. 1691 EmulatedStackFrame filterFrame = EmulatedStackFrame.create(collector.type()); 1692 stackFrame.copyRangeTo(filterFrame, collectorRange, 0, 0); 1693 invokeFromTransform(collector, filterFrame); 1694 1695 // Start constructing the target frame. 1696 EmulatedStackFrame targetFrame = EmulatedStackFrame.create(target.type()); 1697 stackFrame.copyRangeTo(targetFrame, range1, 0, 0); 1698 1699 // If one of these offsets is not zero, we have a return value to copy. 1700 if (referencesOffset != 0 || stackFrameOffset != 0) { 1701 final StackFrameReader reader = new StackFrameReader(); 1702 reader.attach(filterFrame).makeReturnValueAccessor(); 1703 final StackFrameWriter writer = new StackFrameWriter(); 1704 writer.attach(targetFrame, pos, range1.numReferences, range1.numBytes); 1705 copyNext(reader, writer, target.type().ptypes()[0]); 1706 } 1707 1708 stackFrame.copyRangeTo( 1709 targetFrame, 1710 range2, 1711 range1.numReferences + referencesOffset, 1712 range2.numBytes + stackFrameOffset); 1713 1714 invokeFromTransform(target, targetFrame); 1715 targetFrame.copyReturnValueTo(stackFrame); 1716 } 1717 } 1718 1719 /** Implements {@code MethodHandles.foldArguments}. */ 1720 static class FoldArguments extends Transformer { 1721 private final MethodHandle target; 1722 private final MethodHandle combiner; 1723 private final int position; 1724 1725 /** The range of arguments in our frame passed to the combiner. */ 1726 private final Range combinerArgs; 1727 1728 /** The range of arguments in our frame copied to the start of the target frame. */ 1729 private final Range leadingArgs; 1730 1731 /** The range of arguments in our frame copied to the end of the target frame. */ 1732 private final Range trailingArgs; 1733 1734 private final int referencesOffset; 1735 private final int stackFrameOffset; 1736 FoldArguments(MethodHandle target, int position, MethodHandle combiner)1737 FoldArguments(MethodHandle target, int position, MethodHandle combiner) { 1738 super(deriveType(target, position, combiner)); 1739 1740 this.target = target; 1741 this.combiner = combiner; 1742 this.position = position; 1743 1744 this.combinerArgs = 1745 Range.of(type(), position, position + combiner.type().parameterCount()); 1746 this.leadingArgs = Range.of(type(), 0, position); 1747 this.trailingArgs = Range.from(type(), position); 1748 1749 final Class<?> combinerRType = combiner.type().rtype(); 1750 if (combinerRType == void.class) { 1751 stackFrameOffset = 0; 1752 referencesOffset = 0; 1753 } else if (combinerRType.isPrimitive()) { 1754 stackFrameOffset = EmulatedStackFrame.getSize(combinerRType); 1755 referencesOffset = 0; 1756 } else { 1757 // combinerRType is a reference. 1758 stackFrameOffset = 0; 1759 referencesOffset = 1; 1760 } 1761 } 1762 1763 @Override transform(EmulatedStackFrame stackFrame)1764 public void transform(EmulatedStackFrame stackFrame) throws Throwable { 1765 // First construct the combiner frame and invoke the combiner. 1766 EmulatedStackFrame combinerFrame = EmulatedStackFrame.create(combiner.type()); 1767 stackFrame.copyRangeTo(combinerFrame, combinerArgs, 0, 0); 1768 invokeExactFromTransform(combiner, combinerFrame); 1769 1770 // Create the stack frame for the target and copy leading arguments to it. 1771 EmulatedStackFrame targetFrame = EmulatedStackFrame.create(target.type()); 1772 stackFrame.copyRangeTo(targetFrame, leadingArgs, 0, 0); 1773 1774 // If one of these offsets is not zero, we have to slot the return value from the 1775 // combiner into the target frame. 1776 if (referencesOffset != 0 || stackFrameOffset != 0) { 1777 final StackFrameReader reader = new StackFrameReader(); 1778 reader.attach(combinerFrame).makeReturnValueAccessor(); 1779 final StackFrameWriter writer = new StackFrameWriter(); 1780 writer.attach(targetFrame, 1781 position, 1782 leadingArgs.numReferences, 1783 leadingArgs.numBytes); 1784 copyNext(reader, writer, target.type().ptypes()[position]); 1785 } 1786 1787 // Copy the arguments provided to the combiner to the tail of the target frame. 1788 stackFrame.copyRangeTo( 1789 targetFrame, 1790 trailingArgs, 1791 leadingArgs.numReferences + referencesOffset, 1792 leadingArgs.numBytes + stackFrameOffset); 1793 1794 // Call the target and propagate return value. 1795 invokeExactFromTransform(target, targetFrame); 1796 targetFrame.copyReturnValueTo(stackFrame); 1797 } 1798 deriveType(MethodHandle target, int position, MethodHandle combiner)1799 private static MethodType deriveType(MethodHandle target, 1800 int position, 1801 MethodHandle combiner) { 1802 if (combiner.type().rtype() == void.class) { 1803 return target.type(); 1804 } 1805 return target.type().dropParameterTypes(position, position + 1); 1806 } 1807 } 1808 1809 /** Implements {@code MethodHandles.insertArguments}. */ 1810 static class InsertArguments extends Transformer { 1811 private final MethodHandle target; 1812 private final int pos; 1813 private final Object[] values; 1814 1815 private final Range range1; 1816 private final Range range2; 1817 InsertArguments(MethodHandle target, int pos, Object[] values)1818 InsertArguments(MethodHandle target, int pos, Object[] values) { 1819 super(target.type().dropParameterTypes(pos, pos + values.length)); 1820 this.target = target; 1821 this.pos = pos; 1822 this.values = values; 1823 1824 final MethodType type = type(); 1825 range1 = EmulatedStackFrame.Range.of(type, 0, pos); 1826 range2 = Range.of(type, pos, type.parameterCount()); 1827 } 1828 1829 @Override transform(EmulatedStackFrame stackFrame)1830 public void transform(EmulatedStackFrame stackFrame) throws Throwable { 1831 EmulatedStackFrame calleeFrame = EmulatedStackFrame.create(target.type()); 1832 1833 // Copy all arguments before |pos|. 1834 stackFrame.copyRangeTo(calleeFrame, range1, 0, 0); 1835 1836 // Attach a stack frame writer so that we can copy the next |values.length| 1837 // arguments. 1838 final StackFrameWriter writer = new StackFrameWriter(); 1839 writer.attach(calleeFrame, pos, range1.numReferences, range1.numBytes); 1840 1841 // Copy all the arguments supplied in |values|. 1842 int referencesCopied = 0; 1843 int bytesCopied = 0; 1844 final Class<?>[] ptypes = target.type().ptypes(); 1845 for (int i = 0; i < values.length; ++i) { 1846 final Class<?> ptype = ptypes[i + pos]; 1847 final char typeChar = Wrapper.basicTypeChar(ptype); 1848 if (typeChar == 'L') { 1849 writer.putNextReference(values[i], ptype); 1850 referencesCopied++; 1851 } else { 1852 switch (typeChar) { 1853 case 'Z': 1854 writer.putNextBoolean((boolean) values[i]); 1855 break; 1856 case 'B': 1857 writer.putNextByte((byte) values[i]); 1858 break; 1859 case 'C': 1860 writer.putNextChar((char) values[i]); 1861 break; 1862 case 'S': 1863 writer.putNextShort((short) values[i]); 1864 break; 1865 case 'I': 1866 writer.putNextInt((int) values[i]); 1867 break; 1868 case 'J': 1869 writer.putNextLong((long) values[i]); 1870 break; 1871 case 'F': 1872 writer.putNextFloat((float) values[i]); 1873 break; 1874 case 'D': 1875 writer.putNextDouble((double) values[i]); 1876 break; 1877 } 1878 bytesCopied += EmulatedStackFrame.getSize(ptype); 1879 } 1880 } 1881 1882 // Copy all remaining arguments. 1883 if (range2 != null) { 1884 stackFrame.copyRangeTo( 1885 calleeFrame, 1886 range2, 1887 range1.numReferences + referencesCopied, 1888 range1.numBytes + bytesCopied); 1889 } 1890 1891 invokeFromTransform(target, calleeFrame); 1892 calleeFrame.copyReturnValueTo(stackFrame); 1893 } 1894 } 1895 1896 /** Implements {@code MethodHandle.asType}. */ 1897 static class AsTypeAdapter extends Transformer { 1898 private final MethodHandle target; 1899 AsTypeAdapter(MethodHandle target, MethodType type)1900 AsTypeAdapter(MethodHandle target, MethodType type) { 1901 super(type); 1902 this.target = target; 1903 } 1904 1905 @Override transform(EmulatedStackFrame callerFrame)1906 public void transform(EmulatedStackFrame callerFrame) throws Throwable { 1907 final EmulatedStackFrame targetFrame = EmulatedStackFrame.create(target.type()); 1908 final StackFrameReader reader = new StackFrameReader(); 1909 final StackFrameWriter writer = new StackFrameWriter(); 1910 1911 // Adapt arguments 1912 reader.attach(callerFrame); 1913 writer.attach(targetFrame); 1914 adaptArguments(reader, writer); 1915 1916 // Invoke target 1917 invokeFromTransform(target, targetFrame); 1918 1919 if (callerFrame.getMethodType().rtype() != void.class) { 1920 // Adapt return value 1921 reader.attach(targetFrame).makeReturnValueAccessor(); 1922 writer.attach(callerFrame).makeReturnValueAccessor(); 1923 adaptReturnValue(reader, writer); 1924 } 1925 } 1926 adaptArguments(final StackFrameReader reader, final StackFrameWriter writer)1927 private void adaptArguments(final StackFrameReader reader, final StackFrameWriter writer) { 1928 final Class<?>[] fromTypes = type().ptypes(); 1929 final Class<?>[] toTypes = target.type().ptypes(); 1930 for (int i = 0; i < fromTypes.length; ++i) { 1931 adaptArgument(reader, fromTypes[i], writer, toTypes[i]); 1932 } 1933 } 1934 adaptReturnValue( final StackFrameReader reader, final StackFrameWriter writer)1935 private void adaptReturnValue( 1936 final StackFrameReader reader, final StackFrameWriter writer) { 1937 final Class<?> fromType = target.type().rtype(); 1938 final Class<?> toType = type().rtype(); 1939 adaptArgument(reader, fromType, writer, toType); 1940 } 1941 throwWrongMethodTypeException()1942 private void throwWrongMethodTypeException() throws WrongMethodTypeException { 1943 throw new WrongMethodTypeException( 1944 "Cannot convert from " + type() + " to " + target.type()); 1945 } 1946 throwClassCastException(Class from, Class to)1947 private static void throwClassCastException(Class from, Class to) 1948 throws ClassCastException { 1949 throw new ClassCastException("Cannot cast from " + from + " to " + to); 1950 } 1951 writePrimitiveByteAs(final StackFrameWriter writer, char baseType, byte value)1952 private void writePrimitiveByteAs(final StackFrameWriter writer, char baseType, byte value) 1953 throws WrongMethodTypeException { 1954 switch (baseType) { 1955 case 'B': 1956 writer.putNextByte(value); 1957 return; 1958 case 'S': 1959 writer.putNextShort((short) value); 1960 return; 1961 case 'I': 1962 writer.putNextInt((int) value); 1963 return; 1964 case 'J': 1965 writer.putNextLong((long) value); 1966 return; 1967 case 'F': 1968 writer.putNextFloat((float) value); 1969 return; 1970 case 'D': 1971 writer.putNextDouble((double) value); 1972 return; 1973 default: 1974 throwWrongMethodTypeException(); 1975 } 1976 } 1977 writePrimitiveShortAs( final StackFrameWriter writer, char baseType, short value)1978 private void writePrimitiveShortAs( 1979 final StackFrameWriter writer, char baseType, short value) 1980 throws WrongMethodTypeException { 1981 switch (baseType) { 1982 case 'S': 1983 writer.putNextShort(value); 1984 return; 1985 case 'I': 1986 writer.putNextInt((int) value); 1987 return; 1988 case 'J': 1989 writer.putNextLong((long) value); 1990 return; 1991 case 'F': 1992 writer.putNextFloat((float) value); 1993 return; 1994 case 'D': 1995 writer.putNextDouble((double) value); 1996 return; 1997 default: 1998 throwWrongMethodTypeException(); 1999 } 2000 } 2001 writePrimitiveCharAs(final StackFrameWriter writer, char baseType, char value)2002 private void writePrimitiveCharAs(final StackFrameWriter writer, char baseType, char value) 2003 throws WrongMethodTypeException { 2004 switch (baseType) { 2005 case 'C': 2006 writer.putNextChar(value); 2007 return; 2008 case 'I': 2009 writer.putNextInt((int) value); 2010 return; 2011 case 'J': 2012 writer.putNextLong((long) value); 2013 return; 2014 case 'F': 2015 writer.putNextFloat((float) value); 2016 return; 2017 case 'D': 2018 writer.putNextDouble((double) value); 2019 return; 2020 default: 2021 throwWrongMethodTypeException(); 2022 } 2023 } 2024 writePrimitiveIntAs(final StackFrameWriter writer, char baseType, int value)2025 private void writePrimitiveIntAs(final StackFrameWriter writer, char baseType, int value) 2026 throws WrongMethodTypeException { 2027 switch (baseType) { 2028 case 'I': 2029 writer.putNextInt(value); 2030 return; 2031 case 'J': 2032 writer.putNextLong((long) value); 2033 return; 2034 case 'F': 2035 writer.putNextFloat((float) value); 2036 return; 2037 case 'D': 2038 writer.putNextDouble((double) value); 2039 return; 2040 default: 2041 throwWrongMethodTypeException(); 2042 } 2043 throwWrongMethodTypeException(); 2044 } 2045 writePrimitiveLongAs(final StackFrameWriter writer, char baseType, long value)2046 private void writePrimitiveLongAs(final StackFrameWriter writer, char baseType, long value) 2047 throws WrongMethodTypeException { 2048 switch (baseType) { 2049 case 'J': 2050 writer.putNextLong(value); 2051 return; 2052 case 'F': 2053 writer.putNextFloat((float) value); 2054 return; 2055 case 'D': 2056 writer.putNextDouble((double) value); 2057 return; 2058 default: 2059 throwWrongMethodTypeException(); 2060 } 2061 } 2062 writePrimitiveFloatAs( final StackFrameWriter writer, char baseType, float value)2063 private void writePrimitiveFloatAs( 2064 final StackFrameWriter writer, char baseType, float value) 2065 throws WrongMethodTypeException { 2066 switch (baseType) { 2067 case 'F': 2068 writer.putNextFloat(value); 2069 return; 2070 case 'D': 2071 writer.putNextDouble((double) value); 2072 return; 2073 default: 2074 throwWrongMethodTypeException(); 2075 } 2076 } 2077 writePrimitiveDoubleAs( final StackFrameWriter writer, char baseType, double value)2078 private void writePrimitiveDoubleAs( 2079 final StackFrameWriter writer, char baseType, double value) 2080 throws WrongMethodTypeException { 2081 switch (baseType) { 2082 case 'D': 2083 writer.putNextDouble(value); 2084 return; 2085 default: 2086 throwWrongMethodTypeException(); 2087 } 2088 } 2089 writePrimitiveVoidAs(final StackFrameWriter writer, char baseType)2090 private void writePrimitiveVoidAs(final StackFrameWriter writer, char baseType) { 2091 switch (baseType) { 2092 case 'Z': 2093 writer.putNextBoolean(false); 2094 return; 2095 case 'B': 2096 writer.putNextByte((byte) 0); 2097 return; 2098 case 'S': 2099 writer.putNextShort((short) 0); 2100 return; 2101 case 'C': 2102 writer.putNextChar((char) 0); 2103 return; 2104 case 'I': 2105 writer.putNextInt(0); 2106 return; 2107 case 'J': 2108 writer.putNextLong(0L); 2109 return; 2110 case 'F': 2111 writer.putNextFloat(0.0f); 2112 return; 2113 case 'D': 2114 writer.putNextDouble(0.0); 2115 return; 2116 default: 2117 throwWrongMethodTypeException(); 2118 } 2119 } 2120 getBoxedPrimitiveClass(char baseType)2121 private static Class getBoxedPrimitiveClass(char baseType) { 2122 switch (baseType) { 2123 case 'Z': 2124 return Boolean.class; 2125 case 'B': 2126 return Byte.class; 2127 case 'S': 2128 return Short.class; 2129 case 'C': 2130 return Character.class; 2131 case 'I': 2132 return Integer.class; 2133 case 'J': 2134 return Long.class; 2135 case 'F': 2136 return Float.class; 2137 case 'D': 2138 return Double.class; 2139 default: 2140 return null; 2141 } 2142 } 2143 adaptArgument( final StackFrameReader reader, final Class<?> from, final StackFrameWriter writer, final Class<?> to)2144 private void adaptArgument( 2145 final StackFrameReader reader, 2146 final Class<?> from, 2147 final StackFrameWriter writer, 2148 final Class<?> to) { 2149 if (from.equals(to)) { 2150 StackFrameAccessor.copyNext(reader, writer, from); 2151 return; 2152 } 2153 2154 if (to.isPrimitive()) { 2155 if (from.isPrimitive()) { 2156 final char fromBaseType = Wrapper.basicTypeChar(from); 2157 final char toBaseType = Wrapper.basicTypeChar(to); 2158 switch (fromBaseType) { 2159 case 'B': 2160 writePrimitiveByteAs(writer, toBaseType, reader.nextByte()); 2161 return; 2162 case 'S': 2163 writePrimitiveShortAs(writer, toBaseType, reader.nextShort()); 2164 return; 2165 case 'C': 2166 writePrimitiveCharAs(writer, toBaseType, reader.nextChar()); 2167 return; 2168 case 'I': 2169 writePrimitiveIntAs(writer, toBaseType, reader.nextInt()); 2170 return; 2171 case 'J': 2172 writePrimitiveLongAs(writer, toBaseType, reader.nextLong()); 2173 return; 2174 case 'F': 2175 writePrimitiveFloatAs(writer, toBaseType, reader.nextFloat()); 2176 return; 2177 case 'V': 2178 writePrimitiveVoidAs(writer, toBaseType); 2179 return; 2180 default: 2181 throwWrongMethodTypeException(); 2182 } 2183 } else { 2184 final Object value = reader.nextReference(Object.class); 2185 if (to == void.class) { 2186 return; 2187 } 2188 if (value == null) { 2189 throw new NullPointerException(); 2190 } 2191 if (!Wrapper.isWrapperType(value.getClass())) { 2192 throwClassCastException(value.getClass(), to); 2193 } 2194 final Wrapper fromWrapper = Wrapper.forWrapperType(value.getClass()); 2195 final Wrapper toWrapper = Wrapper.forPrimitiveType(to); 2196 if (!toWrapper.isConvertibleFrom(fromWrapper)) { 2197 throwClassCastException(from, to); 2198 } 2199 2200 final char toChar = toWrapper.basicTypeChar(); 2201 switch (fromWrapper.basicTypeChar()) { 2202 case 'Z': 2203 writer.putNextBoolean(((Boolean) value).booleanValue()); 2204 return; 2205 case 'B': 2206 writePrimitiveByteAs(writer, toChar, ((Byte) value).byteValue()); 2207 return; 2208 case 'S': 2209 writePrimitiveShortAs(writer, toChar, ((Short) value).shortValue()); 2210 return; 2211 case 'C': 2212 writePrimitiveCharAs(writer, toChar, ((Character) value).charValue()); 2213 return; 2214 case 'I': 2215 writePrimitiveIntAs(writer, toChar, ((Integer) value).intValue()); 2216 return; 2217 case 'J': 2218 writePrimitiveLongAs(writer, toChar, ((Long) value).longValue()); 2219 return; 2220 case 'F': 2221 writePrimitiveFloatAs(writer, toChar, ((Float) value).floatValue()); 2222 return; 2223 case 'D': 2224 writePrimitiveDoubleAs(writer, toChar, ((Double) value).doubleValue()); 2225 return; 2226 default: 2227 throw new IllegalStateException(); 2228 } 2229 } 2230 } else { 2231 if (from.isPrimitive()) { 2232 // Boxing conversion 2233 final char fromBaseType = Wrapper.basicTypeChar(from); 2234 final Class fromBoxed = getBoxedPrimitiveClass(fromBaseType); 2235 // 'to' maybe a super class of the boxed `from` type, e.g. Number. 2236 if (fromBoxed != null && !to.isAssignableFrom(fromBoxed)) { 2237 throwWrongMethodTypeException(); 2238 } 2239 2240 Object boxed; 2241 switch (fromBaseType) { 2242 case 'Z': 2243 boxed = Boolean.valueOf(reader.nextBoolean()); 2244 break; 2245 case 'B': 2246 boxed = Byte.valueOf(reader.nextByte()); 2247 break; 2248 case 'S': 2249 boxed = Short.valueOf(reader.nextShort()); 2250 break; 2251 case 'C': 2252 boxed = Character.valueOf(reader.nextChar()); 2253 break; 2254 case 'I': 2255 boxed = Integer.valueOf(reader.nextInt()); 2256 break; 2257 case 'J': 2258 boxed = Long.valueOf(reader.nextLong()); 2259 break; 2260 case 'F': 2261 boxed = Float.valueOf(reader.nextFloat()); 2262 break; 2263 case 'D': 2264 boxed = Double.valueOf(reader.nextDouble()); 2265 break; 2266 case 'V': 2267 boxed = null; 2268 break; 2269 default: 2270 throw new IllegalStateException(); 2271 } 2272 writer.putNextReference(boxed, to); 2273 return; 2274 } else { 2275 // Cast 2276 Object value = reader.nextReference(Object.class); 2277 if (value != null && !to.isAssignableFrom(value.getClass())) { 2278 throwClassCastException(value.getClass(), to); 2279 } 2280 writer.putNextReference(value, to); 2281 } 2282 } 2283 } 2284 } 2285 2286 /** Implements {@code MethodHandles.explicitCastArguments}. */ 2287 static class ExplicitCastArguments extends Transformer { 2288 private final MethodHandle target; 2289 ExplicitCastArguments(MethodHandle target, MethodType type)2290 ExplicitCastArguments(MethodHandle target, MethodType type) { 2291 super(type); 2292 this.target = target; 2293 } 2294 2295 @Override transform(EmulatedStackFrame callerFrame)2296 public void transform(EmulatedStackFrame callerFrame) throws Throwable { 2297 // Create a new stack frame for the target. 2298 EmulatedStackFrame targetFrame = EmulatedStackFrame.create(target.type()); 2299 2300 explicitCastArguments(callerFrame, targetFrame); 2301 invokeFromTransform(target, targetFrame); 2302 explicitCastReturnValue(callerFrame, targetFrame); 2303 } 2304 explicitCastArguments( final EmulatedStackFrame callerFrame, final EmulatedStackFrame targetFrame)2305 private void explicitCastArguments( 2306 final EmulatedStackFrame callerFrame, final EmulatedStackFrame targetFrame) { 2307 final StackFrameReader reader = new StackFrameReader(); 2308 reader.attach(callerFrame); 2309 final StackFrameWriter writer = new StackFrameWriter(); 2310 writer.attach(targetFrame); 2311 2312 final Class<?>[] fromTypes = type().ptypes(); 2313 final Class<?>[] toTypes = target.type().ptypes(); 2314 for (int i = 0; i < fromTypes.length; ++i) { 2315 explicitCast(reader, fromTypes[i], writer, toTypes[i]); 2316 } 2317 } 2318 explicitCastReturnValue( final EmulatedStackFrame callerFrame, final EmulatedStackFrame targetFrame)2319 private void explicitCastReturnValue( 2320 final EmulatedStackFrame callerFrame, final EmulatedStackFrame targetFrame) { 2321 Class<?> from = target.type().rtype(); 2322 Class<?> to = type().rtype(); 2323 if (to != void.class) { 2324 final StackFrameWriter writer = new StackFrameWriter(); 2325 writer.attach(callerFrame); 2326 writer.makeReturnValueAccessor(); 2327 if (from == void.class) { 2328 if (to.isPrimitive()) { 2329 unboxNull(writer, to); 2330 } else { 2331 writer.putNextReference(null, to); 2332 } 2333 } else { 2334 final StackFrameReader reader = new StackFrameReader(); 2335 reader.attach(targetFrame); 2336 reader.makeReturnValueAccessor(); 2337 explicitCast(reader, target.type().rtype(), writer, type().rtype()); 2338 } 2339 } 2340 } 2341 throwUnexpectedType(final Class<?> unexpectedType)2342 private static void throwUnexpectedType(final Class<?> unexpectedType) { 2343 throw new InternalError("Unexpected type: " + unexpectedType); 2344 } 2345 2346 @SuppressWarnings("unchecked") badCast(final Class<?> from, final Class<?> to)2347 private static void badCast(final Class<?> from, final Class<?> to) { 2348 throw new ClassCastException("Cannot cast " + from.getName() + " to " + to.getName()); 2349 } 2350 2351 /** 2352 * Converts byte value to boolean according to {@link 2353 * java.lang.invoke.MethodHandles#explicitCast()} 2354 */ toBoolean(byte value)2355 private static boolean toBoolean(byte value) { 2356 return (value & 1) == 1; 2357 } 2358 readPrimitiveAsByte( final StackFrameReader reader, final Class<?> from)2359 private static byte readPrimitiveAsByte( 2360 final StackFrameReader reader, final Class<?> from) { 2361 switch (Wrapper.basicTypeChar(from)) { 2362 case 'B': 2363 return (byte) reader.nextByte(); 2364 case 'C': 2365 return (byte) reader.nextChar(); 2366 case 'S': 2367 return (byte) reader.nextShort(); 2368 case 'I': 2369 return (byte) reader.nextInt(); 2370 case 'J': 2371 return (byte) reader.nextLong(); 2372 case 'F': 2373 return (byte) reader.nextFloat(); 2374 case 'D': 2375 return (byte) reader.nextDouble(); 2376 case 'Z': 2377 return reader.nextBoolean() ? (byte) 1 : (byte) 0; 2378 default: 2379 throwUnexpectedType(from); 2380 return 0; 2381 } 2382 } 2383 readPrimitiveAsChar( final StackFrameReader reader, final Class<?> from)2384 private static char readPrimitiveAsChar( 2385 final StackFrameReader reader, final Class<?> from) { 2386 switch (Wrapper.basicTypeChar(from)) { 2387 case 'B': 2388 return (char) reader.nextByte(); 2389 case 'C': 2390 return (char) reader.nextChar(); 2391 case 'S': 2392 return (char) reader.nextShort(); 2393 case 'I': 2394 return (char) reader.nextInt(); 2395 case 'J': 2396 return (char) reader.nextLong(); 2397 case 'F': 2398 return (char) reader.nextFloat(); 2399 case 'D': 2400 return (char) reader.nextDouble(); 2401 case 'Z': 2402 return reader.nextBoolean() ? (char) 1 : (char) 0; 2403 default: 2404 throwUnexpectedType(from); 2405 return 0; 2406 } 2407 } 2408 readPrimitiveAsShort( final StackFrameReader reader, final Class<?> from)2409 private static short readPrimitiveAsShort( 2410 final StackFrameReader reader, final Class<?> from) { 2411 switch (Wrapper.basicTypeChar(from)) { 2412 case 'B': 2413 return (short) reader.nextByte(); 2414 case 'C': 2415 return (short) reader.nextChar(); 2416 case 'S': 2417 return (short) reader.nextShort(); 2418 case 'I': 2419 return (short) reader.nextInt(); 2420 case 'J': 2421 return (short) reader.nextLong(); 2422 case 'F': 2423 return (short) reader.nextFloat(); 2424 case 'D': 2425 return (short) reader.nextDouble(); 2426 case 'Z': 2427 return reader.nextBoolean() ? (short) 1 : (short) 0; 2428 default: 2429 throwUnexpectedType(from); 2430 return 0; 2431 } 2432 } 2433 readPrimitiveAsInt(final StackFrameReader reader, final Class<?> from)2434 private static int readPrimitiveAsInt(final StackFrameReader reader, final Class<?> from) { 2435 switch (Wrapper.basicTypeChar(from)) { 2436 case 'B': 2437 return (int) reader.nextByte(); 2438 case 'C': 2439 return (int) reader.nextChar(); 2440 case 'S': 2441 return (int) reader.nextShort(); 2442 case 'I': 2443 return (int) reader.nextInt(); 2444 case 'J': 2445 return (int) reader.nextLong(); 2446 case 'F': 2447 return (int) reader.nextFloat(); 2448 case 'D': 2449 return (int) reader.nextDouble(); 2450 case 'Z': 2451 return reader.nextBoolean() ? 1 : 0; 2452 default: 2453 throwUnexpectedType(from); 2454 return 0; 2455 } 2456 } 2457 readPrimitiveAsLong( final StackFrameReader reader, final Class<?> from)2458 private static long readPrimitiveAsLong( 2459 final StackFrameReader reader, final Class<?> from) { 2460 switch (Wrapper.basicTypeChar(from)) { 2461 case 'B': 2462 return (long) reader.nextByte(); 2463 case 'C': 2464 return (long) reader.nextChar(); 2465 case 'S': 2466 return (long) reader.nextShort(); 2467 case 'I': 2468 return (long) reader.nextInt(); 2469 case 'J': 2470 return (long) reader.nextLong(); 2471 case 'F': 2472 return (long) reader.nextFloat(); 2473 case 'D': 2474 return (long) reader.nextDouble(); 2475 case 'Z': 2476 return reader.nextBoolean() ? 1L : 0L; 2477 default: 2478 throwUnexpectedType(from); 2479 return 0; 2480 } 2481 } 2482 readPrimitiveAsFloat( final StackFrameReader reader, final Class<?> from)2483 private static float readPrimitiveAsFloat( 2484 final StackFrameReader reader, final Class<?> from) { 2485 switch (Wrapper.basicTypeChar(from)) { 2486 case 'B': 2487 return (float) reader.nextByte(); 2488 case 'C': 2489 return (float) reader.nextChar(); 2490 case 'S': 2491 return (float) reader.nextShort(); 2492 case 'I': 2493 return (float) reader.nextInt(); 2494 case 'J': 2495 return (float) reader.nextLong(); 2496 case 'F': 2497 return (float) reader.nextFloat(); 2498 case 'D': 2499 return (float) reader.nextDouble(); 2500 case 'Z': 2501 return reader.nextBoolean() ? 1.0f : 0.0f; 2502 default: 2503 throwUnexpectedType(from); 2504 return 0; 2505 } 2506 } 2507 readPrimitiveAsDouble( final StackFrameReader reader, final Class<?> from)2508 private static double readPrimitiveAsDouble( 2509 final StackFrameReader reader, final Class<?> from) { 2510 switch (Wrapper.basicTypeChar(from)) { 2511 case 'B': 2512 return (double) reader.nextByte(); 2513 case 'C': 2514 return (double) reader.nextChar(); 2515 case 'S': 2516 return (double) reader.nextShort(); 2517 case 'I': 2518 return (double) reader.nextInt(); 2519 case 'J': 2520 return (double) reader.nextLong(); 2521 case 'F': 2522 return (double) reader.nextFloat(); 2523 case 'D': 2524 return (double) reader.nextDouble(); 2525 case 'Z': 2526 return reader.nextBoolean() ? 1.0 : 0.0; 2527 default: 2528 throwUnexpectedType(from); 2529 return 0; 2530 } 2531 } 2532 explicitCastPrimitives( final StackFrameReader reader, final Class<?> from, final StackFrameWriter writer, final Class<?> to)2533 private static void explicitCastPrimitives( 2534 final StackFrameReader reader, 2535 final Class<?> from, 2536 final StackFrameWriter writer, 2537 final Class<?> to) { 2538 switch (Wrapper.basicTypeChar(to)) { 2539 case 'B': 2540 writer.putNextByte(readPrimitiveAsByte(reader, from)); 2541 break; 2542 case 'C': 2543 writer.putNextChar(readPrimitiveAsChar(reader, from)); 2544 break; 2545 case 'S': 2546 writer.putNextShort(readPrimitiveAsShort(reader, from)); 2547 break; 2548 case 'I': 2549 writer.putNextInt(readPrimitiveAsInt(reader, from)); 2550 break; 2551 case 'J': 2552 writer.putNextLong(readPrimitiveAsLong(reader, from)); 2553 break; 2554 case 'F': 2555 writer.putNextFloat(readPrimitiveAsFloat(reader, from)); 2556 break; 2557 case 'D': 2558 writer.putNextDouble(readPrimitiveAsDouble(reader, from)); 2559 break; 2560 case 'Z': 2561 writer.putNextBoolean(toBoolean(readPrimitiveAsByte(reader, from))); 2562 break; 2563 default: 2564 throwUnexpectedType(to); 2565 break; 2566 } 2567 } 2568 unboxNull(final StackFrameWriter writer, final Class<?> to)2569 private static void unboxNull(final StackFrameWriter writer, final Class<?> to) { 2570 switch (Wrapper.basicTypeChar(to)) { 2571 case 'Z': 2572 writer.putNextBoolean(false); 2573 break; 2574 case 'B': 2575 writer.putNextByte((byte) 0); 2576 break; 2577 case 'C': 2578 writer.putNextChar((char) 0); 2579 break; 2580 case 'S': 2581 writer.putNextShort((short) 0); 2582 break; 2583 case 'I': 2584 writer.putNextInt((int) 0); 2585 break; 2586 case 'J': 2587 writer.putNextLong((long) 0); 2588 break; 2589 case 'F': 2590 writer.putNextFloat((float) 0); 2591 break; 2592 case 'D': 2593 writer.putNextDouble((double) 0); 2594 break; 2595 default: 2596 throwUnexpectedType(to); 2597 break; 2598 } 2599 } 2600 unboxNonNull( final Object ref, final StackFrameWriter writer, final Class<?> to)2601 private static void unboxNonNull( 2602 final Object ref, 2603 final StackFrameWriter writer, 2604 final Class<?> to) { 2605 final Class<?> from = ref.getClass(); 2606 final Class<?> unboxedFromType = Wrapper.asPrimitiveType(from); 2607 switch (Wrapper.basicTypeChar(unboxedFromType)) { 2608 case 'Z': 2609 boolean z = (boolean) ref; 2610 switch (Wrapper.basicTypeChar(to)) { 2611 case 'Z': 2612 writer.putNextBoolean(z); 2613 break; 2614 case 'B': 2615 writer.putNextByte(z ? (byte) 1 : (byte) 0); 2616 break; 2617 case 'S': 2618 writer.putNextShort(z ? (short) 1 : (short) 0); 2619 break; 2620 case 'C': 2621 writer.putNextChar(z ? (char) 1 : (char) 0); 2622 break; 2623 case 'I': 2624 writer.putNextInt(z ? 1 : 0); 2625 break; 2626 case 'J': 2627 writer.putNextLong(z ? 1l : 0l); 2628 break; 2629 case 'F': 2630 writer.putNextFloat(z ? 1.0f : 0.0f); 2631 break; 2632 case 'D': 2633 writer.putNextDouble(z ? 1.0 : 0.0); 2634 break; 2635 default: 2636 badCast(from, to); 2637 break; 2638 } 2639 break; 2640 case 'B': 2641 byte b = (byte) ref; 2642 switch (Wrapper.basicTypeChar(to)) { 2643 case 'B': 2644 writer.putNextByte(b); 2645 break; 2646 case 'Z': 2647 writer.putNextBoolean(toBoolean(b)); 2648 break; 2649 case 'S': 2650 writer.putNextShort((short) b); 2651 break; 2652 case 'C': 2653 writer.putNextChar((char) b); 2654 break; 2655 case 'I': 2656 writer.putNextInt((int) b); 2657 break; 2658 case 'J': 2659 writer.putNextLong((long) b); 2660 break; 2661 case 'F': 2662 writer.putNextFloat((float) b); 2663 break; 2664 case 'D': 2665 writer.putNextDouble((double) b); 2666 break; 2667 default: 2668 badCast(from, to); 2669 break; 2670 } 2671 break; 2672 case 'S': 2673 short s = (short) ref; 2674 switch (Wrapper.basicTypeChar(to)) { 2675 case 'Z': 2676 writer.putNextBoolean((s & 1) == 1); 2677 break; 2678 case 'B': 2679 writer.putNextByte((byte) s); 2680 break; 2681 case 'S': 2682 writer.putNextShort(s); 2683 break; 2684 case 'C': 2685 writer.putNextChar((char) s); 2686 break; 2687 case 'I': 2688 writer.putNextInt((int) s); 2689 break; 2690 case 'J': 2691 writer.putNextLong((long) s); 2692 break; 2693 case 'F': 2694 writer.putNextFloat((float) s); 2695 break; 2696 case 'D': 2697 writer.putNextDouble((double) s); 2698 break; 2699 default: 2700 badCast(from, to); 2701 break; 2702 } 2703 break; 2704 case 'C': 2705 char c = (char) ref; 2706 switch (Wrapper.basicTypeChar(to)) { 2707 case 'Z': 2708 writer.putNextBoolean((c & (char) 1) == (char) 1); 2709 break; 2710 case 'B': 2711 writer.putNextByte((byte) c); 2712 break; 2713 case 'S': 2714 writer.putNextShort((short) c); 2715 break; 2716 case 'C': 2717 writer.putNextChar(c); 2718 break; 2719 case 'I': 2720 writer.putNextInt((int) c); 2721 break; 2722 case 'J': 2723 writer.putNextLong((long) c); 2724 break; 2725 case 'F': 2726 writer.putNextFloat((float) c); 2727 break; 2728 case 'D': 2729 writer.putNextDouble((double) c); 2730 break; 2731 default: 2732 badCast(from, to); 2733 break; 2734 } 2735 break; 2736 case 'I': 2737 int i = (int) ref; 2738 switch (Wrapper.basicTypeChar(to)) { 2739 case 'Z': 2740 writer.putNextBoolean((i & 1) == 1); 2741 break; 2742 case 'B': 2743 writer.putNextByte((byte) i); 2744 break; 2745 case 'S': 2746 writer.putNextShort((short) i); 2747 break; 2748 case 'C': 2749 writer.putNextChar((char) i); 2750 break; 2751 case 'I': 2752 writer.putNextInt(i); 2753 break; 2754 case 'J': 2755 writer.putNextLong((long) i); 2756 break; 2757 case 'F': 2758 writer.putNextFloat((float) i); 2759 break; 2760 case 'D': 2761 writer.putNextDouble((double) i); 2762 break; 2763 default: 2764 badCast(from, to); 2765 } 2766 break; 2767 case 'J': 2768 long j = (long) ref; 2769 switch (Wrapper.basicTypeChar(to)) { 2770 case 'Z': 2771 writer.putNextBoolean((j & 1l) == 1l); 2772 break; 2773 case 'B': 2774 writer.putNextByte((byte) j); 2775 break; 2776 case 'S': 2777 writer.putNextShort((short) j); 2778 break; 2779 case 'C': 2780 writer.putNextChar((char) j); 2781 break; 2782 case 'I': 2783 writer.putNextInt((int) j); 2784 break; 2785 case 'J': 2786 writer.putNextLong(j); 2787 break; 2788 case 'F': 2789 writer.putNextFloat((float) j); 2790 break; 2791 case 'D': 2792 writer.putNextDouble((double) j); 2793 break; 2794 default: 2795 badCast(from, to); 2796 break; 2797 } 2798 break; 2799 case 'F': 2800 float f = (float) ref; 2801 switch (Wrapper.basicTypeChar(to)) { 2802 case 'Z': 2803 writer.putNextBoolean(((byte) f & 1) != 0); 2804 break; 2805 case 'B': 2806 writer.putNextByte((byte) f); 2807 break; 2808 case 'S': 2809 writer.putNextShort((short) f); 2810 break; 2811 case 'C': 2812 writer.putNextChar((char) f); 2813 break; 2814 case 'I': 2815 writer.putNextInt((int) f); 2816 break; 2817 case 'J': 2818 writer.putNextLong((long) f); 2819 break; 2820 case 'F': 2821 writer.putNextFloat(f); 2822 break; 2823 case 'D': 2824 writer.putNextDouble((double) f); 2825 break; 2826 default: 2827 badCast(from, to); 2828 break; 2829 } 2830 break; 2831 case 'D': 2832 double d = (double) ref; 2833 switch (Wrapper.basicTypeChar(to)) { 2834 case 'Z': 2835 writer.putNextBoolean(((byte) d & 1) != 0); 2836 break; 2837 case 'B': 2838 writer.putNextByte((byte) d); 2839 break; 2840 case 'S': 2841 writer.putNextShort((short) d); 2842 break; 2843 case 'C': 2844 writer.putNextChar((char) d); 2845 break; 2846 case 'I': 2847 writer.putNextInt((int) d); 2848 break; 2849 case 'J': 2850 writer.putNextLong((long) d); 2851 break; 2852 case 'F': 2853 writer.putNextFloat((float) d); 2854 break; 2855 case 'D': 2856 writer.putNextDouble(d); 2857 break; 2858 default: 2859 badCast(from, to); 2860 break; 2861 } 2862 break; 2863 default: 2864 badCast(from, to); 2865 break; 2866 } 2867 } 2868 unbox( final Object ref, final StackFrameWriter writer, final Class<?> to)2869 private static void unbox( 2870 final Object ref, 2871 final StackFrameWriter writer, 2872 final Class<?> to) { 2873 if (ref == null) { 2874 unboxNull(writer, to); 2875 } else { 2876 unboxNonNull(ref, writer, to); 2877 } 2878 } 2879 box( final StackFrameReader reader, final Class<?> from, final StackFrameWriter writer, final Class<?> to)2880 private static void box( 2881 final StackFrameReader reader, 2882 final Class<?> from, 2883 final StackFrameWriter writer, 2884 final Class<?> to) { 2885 Object boxed = null; 2886 switch (Wrapper.basicTypeChar(from)) { 2887 case 'Z': 2888 boxed = Boolean.valueOf(reader.nextBoolean()); 2889 break; 2890 case 'B': 2891 boxed = Byte.valueOf(reader.nextByte()); 2892 break; 2893 case 'C': 2894 boxed = Character.valueOf(reader.nextChar()); 2895 break; 2896 case 'S': 2897 boxed = Short.valueOf(reader.nextShort()); 2898 break; 2899 case 'I': 2900 boxed = Integer.valueOf(reader.nextInt()); 2901 break; 2902 case 'J': 2903 boxed = Long.valueOf(reader.nextLong()); 2904 break; 2905 case 'F': 2906 boxed = Float.valueOf(reader.nextFloat()); 2907 break; 2908 case 'D': 2909 boxed = Double.valueOf(reader.nextDouble()); 2910 break; 2911 default: 2912 throwUnexpectedType(from); 2913 break; 2914 } 2915 writer.putNextReference(to.cast(boxed), to); 2916 } 2917 explicitCast( final StackFrameReader reader, final Class<?> from, final StackFrameWriter writer, final Class<?> to)2918 private static void explicitCast( 2919 final StackFrameReader reader, 2920 final Class<?> from, 2921 final StackFrameWriter writer, 2922 final Class<?> to) { 2923 if (from.equals(to)) { 2924 StackFrameAccessor.copyNext(reader, writer, from); 2925 return; 2926 } 2927 2928 if (from.isPrimitive()) { 2929 if (to.isPrimitive()) { 2930 // |from| and |to| are primitive types. 2931 explicitCastPrimitives(reader, from, writer, to); 2932 } else { 2933 // |from| is a primitive type, |to| is a reference type. 2934 box(reader, from, writer, to); 2935 } 2936 } else { 2937 // |from| is a reference type. 2938 Object ref = reader.nextReference(from); 2939 if (to.isPrimitive()) { 2940 // |from| is a reference type, |to| is a primitive type, 2941 unbox(ref, writer, to); 2942 } else if (to.isInterface()) { 2943 // Pass from without a cast according to description for 2944 // {@link java.lang.invoke.MethodHandles#explicitCastArguments()}. 2945 writer.putNextReference(ref, to); 2946 } else { 2947 // |to| and from |from| are reference types, perform class cast check. 2948 writer.putNextReference(to.cast(ref), to); 2949 } 2950 } 2951 } 2952 } 2953 2954 /** Implements {@code MethodHandles.loop}. */ 2955 static class Loop extends Transformer { 2956 2957 /** Loop variable initialization methods. */ 2958 final MethodHandle[] inits; 2959 2960 /** Loop variable step methods. */ 2961 final MethodHandle[] steps; 2962 2963 /** Loop variable predicate methods. */ 2964 final MethodHandle[] preds; 2965 2966 /** Loop return value calculating methods. */ 2967 final MethodHandle[] finis; 2968 2969 /** Synthetic method type for frame used to hold loop variables. */ 2970 final MethodType loopVarsType; 2971 2972 /** Range of loop variables in the frame used for loop variables. */ 2973 final Range loopVarsRange; 2974 2975 /** Range of suffix variables in the caller frame. */ 2976 final Range suffixRange; 2977 Loop(Class<?> loopReturnType, List<Class<?>> commonSuffix, MethodHandle[] finit, MethodHandle[] fstep, MethodHandle[] fpred, MethodHandle[] ffini)2978 public Loop(Class<?> loopReturnType, 2979 List<Class<?>> commonSuffix, 2980 MethodHandle[] finit, 2981 MethodHandle[] fstep, 2982 MethodHandle[] fpred, 2983 MethodHandle[] ffini) { 2984 super(MethodType.methodType(loopReturnType, commonSuffix)); 2985 2986 inits = finit; 2987 steps = fstep; 2988 preds = fpred; 2989 finis = ffini; 2990 2991 loopVarsType = deduceLoopVarsType(finit); 2992 loopVarsRange = EmulatedStackFrame.Range.all(loopVarsType); 2993 suffixRange = EmulatedStackFrame.Range.all(type()); 2994 } 2995 2996 @Override transform(EmulatedStackFrame callerFrame)2997 public void transform(EmulatedStackFrame callerFrame) throws Throwable { 2998 final EmulatedStackFrame loopVarsFrame = EmulatedStackFrame.create(loopVarsType); 2999 final StackFrameWriter loopVarsWriter = new StackFrameWriter(); 3000 3001 init(callerFrame, loopVarsFrame, loopVarsWriter); 3002 3003 for (;;) { 3004 loopVarsWriter.attach(loopVarsFrame); 3005 for (int i = 0; i < steps.length; ++i) { 3006 // Future optimization opportunity: there is a good deal of StackFrame 3007 // allocation here, one is allocated per MH invocation. Consider caching 3008 // frames <method-type:stack-frame> and passing the cache on the stack. 3009 doStep(steps[i], callerFrame, loopVarsFrame, loopVarsWriter); 3010 boolean keepGoing = doPredicate(preds[i], callerFrame, loopVarsFrame); 3011 if (!keepGoing) { 3012 doFinish(finis[i], callerFrame, loopVarsFrame); 3013 return; 3014 } 3015 } 3016 } 3017 } 3018 deduceLoopVarsType(final MethodHandle[] inits)3019 private static MethodType deduceLoopVarsType(final MethodHandle[] inits) { 3020 List<Class<?>> loopVarTypes = new ArrayList(inits.length); 3021 for (MethodHandle init : inits) { 3022 Class<?> returnType = init.type().returnType(); 3023 if (returnType != void.class) { 3024 loopVarTypes.add(returnType); 3025 } 3026 } 3027 return MethodType.methodType(void.class, loopVarTypes); 3028 } 3029 init(final EmulatedStackFrame callerFrame, final EmulatedStackFrame loopVarsFrame, final StackFrameWriter loopVarsWriter)3030 private void init(final EmulatedStackFrame callerFrame, 3031 final EmulatedStackFrame loopVarsFrame, 3032 final StackFrameWriter loopVarsWriter) throws Throwable { 3033 loopVarsWriter.attach(loopVarsFrame); 3034 for (MethodHandle init : inits) { 3035 EmulatedStackFrame initFrame = EmulatedStackFrame.create(init.type()); 3036 callerFrame.copyRangeTo(initFrame, suffixRange, 0, 0); 3037 3038 invokeExactFromTransform(init, initFrame); 3039 3040 final Class<?> loopVarType = init.type().returnType(); 3041 if (loopVarType != void.class) { 3042 StackFrameReader initReader = new StackFrameReader(); 3043 initReader.attach(initFrame).makeReturnValueAccessor(); 3044 copyNext(initReader, loopVarsWriter, loopVarType); 3045 } 3046 } 3047 } 3048 3049 /** 3050 * Creates a frame for invoking a method of specified type. 3051 * 3052 * The frame arguments are the loop variables followed by the arguments provided to the 3053 * loop MethodHandle. 3054 * 3055 * @param mt the type of the method to be invoked. 3056 * @param callerFrame the frame invoking the loop MethodHandle. 3057 * @param loopVarsFrame the frame holding loop variables. 3058 * @return an EmulatedStackFrame initialized with the required arguments. 3059 */ prepareFrame(final MethodType mt, final EmulatedStackFrame callerFrame, final EmulatedStackFrame loopVarsFrame)3060 private EmulatedStackFrame prepareFrame(final MethodType mt, 3061 final EmulatedStackFrame callerFrame, 3062 final EmulatedStackFrame loopVarsFrame) { 3063 EmulatedStackFrame frame = EmulatedStackFrame.create(mt); 3064 3065 // Copy loop variables. 3066 loopVarsFrame.copyRangeTo(frame, loopVarsRange, 0, 0); 3067 3068 // Copy arguments provided in the loop invoke(). 3069 callerFrame.copyRangeTo(frame, 3070 suffixRange, 3071 loopVarsRange.numReferences, 3072 loopVarsRange.numBytes); 3073 return frame; 3074 } 3075 doStep(final MethodHandle step, final EmulatedStackFrame callerFrame, final EmulatedStackFrame loopVarsFrame, final StackFrameWriter loopVarsWriter)3076 private void doStep(final MethodHandle step, 3077 final EmulatedStackFrame callerFrame, 3078 final EmulatedStackFrame loopVarsFrame, 3079 final StackFrameWriter loopVarsWriter) throws Throwable { 3080 final EmulatedStackFrame stepFrame = 3081 prepareFrame(step.type(), callerFrame, loopVarsFrame); 3082 invokeExactFromTransform(step, stepFrame); 3083 3084 final Class<?> loopVarType = step.type().returnType(); 3085 if (loopVarType != void.class) { 3086 final StackFrameReader stepReader = new StackFrameReader(); 3087 stepReader.attach(stepFrame).makeReturnValueAccessor(); 3088 copyNext(stepReader, loopVarsWriter, loopVarType); 3089 } 3090 } 3091 doPredicate(final MethodHandle pred, final EmulatedStackFrame callerFrame, final EmulatedStackFrame loopVarsFrame)3092 private boolean doPredicate(final MethodHandle pred, 3093 final EmulatedStackFrame callerFrame, 3094 final EmulatedStackFrame loopVarsFrame) throws Throwable { 3095 final EmulatedStackFrame predFrame = 3096 prepareFrame(pred.type(), callerFrame, loopVarsFrame); 3097 invokeExactFromTransform(pred, predFrame); 3098 3099 final StackFrameReader predReader = new StackFrameReader(); 3100 predReader.attach(predFrame).makeReturnValueAccessor(); 3101 return predReader.nextBoolean(); 3102 } 3103 doFinish(final MethodHandle fini, final EmulatedStackFrame callerFrame, final EmulatedStackFrame loopVarsFrame)3104 private void doFinish(final MethodHandle fini, 3105 final EmulatedStackFrame callerFrame, 3106 final EmulatedStackFrame loopVarsFrame) throws Throwable { 3107 final EmulatedStackFrame finiFrame = 3108 prepareFrame(fini.type(), callerFrame, loopVarsFrame); 3109 invokeExactFromTransform(fini, finiFrame); 3110 finiFrame.copyReturnValueTo(callerFrame); 3111 } 3112 } 3113 } 3114