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