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 filterArgs[i] = filters[i].type().parameterType(0); 1580 } 1581 1582 return target.type().replaceParameterTypes(pos, pos + filters.length, filterArgs); 1583 } 1584 1585 @Override transform(EmulatedStackFrame stackFrame)1586 public void transform(EmulatedStackFrame stackFrame) throws Throwable { 1587 final StackFrameReader reader = new StackFrameReader(); 1588 reader.attach(stackFrame); 1589 1590 EmulatedStackFrame transformedFrame = EmulatedStackFrame.create(target.type()); 1591 final StackFrameWriter writer = new StackFrameWriter(); 1592 writer.attach(transformedFrame); 1593 1594 final Class<?>[] ptypes = target.type().ptypes(); 1595 for (int i = 0; i < ptypes.length; ++i) { 1596 // Check whether the current argument has a filter associated with it. 1597 // If it has no filter, no further action need be taken. 1598 final Class<?> ptype = ptypes[i]; 1599 final MethodHandle filter; 1600 if (i < pos) { 1601 filter = null; 1602 } else if (i >= pos + filters.length) { 1603 filter = null; 1604 } else { 1605 filter = filters[i - pos]; 1606 } 1607 1608 if (filter != null) { 1609 // Note that filter.type() must be (ptype)ptype - this is checked before 1610 // this transformer is created. 1611 EmulatedStackFrame filterFrame = EmulatedStackFrame.create(filter.type()); 1612 1613 // Copy the next argument from the stack frame to the filter frame. 1614 final StackFrameWriter filterWriter = new StackFrameWriter(); 1615 filterWriter.attach(filterFrame); 1616 copyNext(reader, filterWriter, filter.type().ptypes()[0]); 1617 1618 invokeFromTransform(filter, filterFrame); 1619 1620 // Copy the argument back from the filter frame to the stack frame. 1621 final StackFrameReader filterReader = new StackFrameReader(); 1622 filterReader.attach(filterFrame); 1623 filterReader.makeReturnValueAccessor(); 1624 copyNext(filterReader, writer, ptype); 1625 } else { 1626 // There's no filter associated with this frame, just copy the next argument 1627 // over. 1628 copyNext(reader, writer, ptype); 1629 } 1630 } 1631 1632 invokeFromTransform(target, transformedFrame); 1633 transformedFrame.copyReturnValueTo(stackFrame); 1634 } 1635 } 1636 1637 /** Implements {@code MethodHandles.collectArguments}. */ 1638 static class CollectArguments extends Transformer { 1639 private final MethodHandle target; 1640 private final MethodHandle collector; 1641 private final int pos; 1642 1643 /** The range of input arguments we copy to the collector. */ 1644 private final Range collectorRange; 1645 1646 /** 1647 * The first range of arguments we copy to the target. These are arguments in the range [0, 1648 * pos). Note that arg[pos] is the return value of the filter. 1649 */ 1650 private final Range range1; 1651 1652 /** 1653 * The second range of arguments we copy to the target. These are arguments in the range 1654 * (pos, N], where N is the number of target arguments. 1655 */ 1656 private final Range range2; 1657 1658 private final int referencesOffset; 1659 private final int stackFrameOffset; 1660 CollectArguments( MethodHandle target, MethodHandle collector, int pos, MethodType adapterType)1661 CollectArguments( 1662 MethodHandle target, MethodHandle collector, int pos, MethodType adapterType) { 1663 super(adapterType); 1664 1665 this.target = target; 1666 this.collector = collector; 1667 this.pos = pos; 1668 1669 final int numFilterArgs = collector.type().parameterCount(); 1670 collectorRange = Range.of(type(), pos, pos + numFilterArgs); 1671 1672 range1 = Range.of(type(), 0, pos); 1673 this.range2 = Range.from(type(), pos + numFilterArgs); 1674 1675 // Calculate the number of primitive bytes (or references) we copy to the 1676 // target frame based on the return value of the combiner. 1677 final Class<?> collectorRType = collector.type().rtype(); 1678 if (collectorRType == void.class) { 1679 stackFrameOffset = 0; 1680 referencesOffset = 0; 1681 } else if (collectorRType.isPrimitive()) { 1682 stackFrameOffset = EmulatedStackFrame.getSize(collectorRType); 1683 referencesOffset = 0; 1684 } else { 1685 stackFrameOffset = 0; 1686 referencesOffset = 1; 1687 } 1688 } 1689 1690 @Override transform(EmulatedStackFrame stackFrame)1691 public void transform(EmulatedStackFrame stackFrame) throws Throwable { 1692 // First invoke the collector. 1693 EmulatedStackFrame filterFrame = EmulatedStackFrame.create(collector.type()); 1694 stackFrame.copyRangeTo(filterFrame, collectorRange, 0, 0); 1695 invokeFromTransform(collector, filterFrame); 1696 1697 // Start constructing the target frame. 1698 EmulatedStackFrame targetFrame = EmulatedStackFrame.create(target.type()); 1699 stackFrame.copyRangeTo(targetFrame, range1, 0, 0); 1700 1701 // If one of these offsets is not zero, we have a return value to copy. 1702 if (referencesOffset != 0 || stackFrameOffset != 0) { 1703 final StackFrameReader reader = new StackFrameReader(); 1704 reader.attach(filterFrame).makeReturnValueAccessor(); 1705 final StackFrameWriter writer = new StackFrameWriter(); 1706 writer.attach(targetFrame, pos, range1.numReferences, range1.numBytes); 1707 copyNext(reader, writer, target.type().ptypes()[pos]); 1708 } 1709 1710 stackFrame.copyRangeTo( 1711 targetFrame, 1712 range2, 1713 range1.numReferences + referencesOffset, 1714 range1.numBytes + stackFrameOffset); 1715 1716 invokeFromTransform(target, targetFrame); 1717 targetFrame.copyReturnValueTo(stackFrame); 1718 } 1719 } 1720 1721 /** Implements {@code MethodHandles.foldArguments}. */ 1722 static class FoldArguments extends Transformer { 1723 private final MethodHandle target; 1724 private final MethodHandle combiner; 1725 private final int position; 1726 1727 /** The range of arguments in our frame passed to the combiner. */ 1728 private final Range combinerArgs; 1729 1730 /** The range of arguments in our frame copied to the start of the target frame. */ 1731 private final Range leadingArgs; 1732 1733 /** The range of arguments in our frame copied to the end of the target frame. */ 1734 private final Range trailingArgs; 1735 1736 private final int referencesOffset; 1737 private final int stackFrameOffset; 1738 FoldArguments(MethodHandle target, int position, MethodHandle combiner)1739 FoldArguments(MethodHandle target, int position, MethodHandle combiner) { 1740 super(deriveType(target, position, combiner)); 1741 1742 this.target = target; 1743 this.combiner = combiner; 1744 this.position = position; 1745 1746 this.combinerArgs = 1747 Range.of(type(), position, position + combiner.type().parameterCount()); 1748 this.leadingArgs = Range.of(type(), 0, position); 1749 this.trailingArgs = Range.from(type(), position); 1750 1751 final Class<?> combinerRType = combiner.type().rtype(); 1752 if (combinerRType == void.class) { 1753 stackFrameOffset = 0; 1754 referencesOffset = 0; 1755 } else if (combinerRType.isPrimitive()) { 1756 stackFrameOffset = EmulatedStackFrame.getSize(combinerRType); 1757 referencesOffset = 0; 1758 } else { 1759 // combinerRType is a reference. 1760 stackFrameOffset = 0; 1761 referencesOffset = 1; 1762 } 1763 } 1764 1765 @Override transform(EmulatedStackFrame stackFrame)1766 public void transform(EmulatedStackFrame stackFrame) throws Throwable { 1767 // First construct the combiner frame and invoke the combiner. 1768 EmulatedStackFrame combinerFrame = EmulatedStackFrame.create(combiner.type()); 1769 stackFrame.copyRangeTo(combinerFrame, combinerArgs, 0, 0); 1770 invokeExactFromTransform(combiner, combinerFrame); 1771 1772 // Create the stack frame for the target and copy leading arguments to it. 1773 EmulatedStackFrame targetFrame = EmulatedStackFrame.create(target.type()); 1774 stackFrame.copyRangeTo(targetFrame, leadingArgs, 0, 0); 1775 1776 // If one of these offsets is not zero, we have to slot the return value from the 1777 // combiner into the target frame. 1778 if (referencesOffset != 0 || stackFrameOffset != 0) { 1779 final StackFrameReader reader = new StackFrameReader(); 1780 reader.attach(combinerFrame).makeReturnValueAccessor(); 1781 final StackFrameWriter writer = new StackFrameWriter(); 1782 writer.attach(targetFrame, 1783 position, 1784 leadingArgs.numReferences, 1785 leadingArgs.numBytes); 1786 copyNext(reader, writer, target.type().ptypes()[position]); 1787 } 1788 1789 // Copy the arguments provided to the combiner to the tail of the target frame. 1790 stackFrame.copyRangeTo( 1791 targetFrame, 1792 trailingArgs, 1793 leadingArgs.numReferences + referencesOffset, 1794 leadingArgs.numBytes + stackFrameOffset); 1795 1796 // Call the target and propagate return value. 1797 invokeExactFromTransform(target, targetFrame); 1798 targetFrame.copyReturnValueTo(stackFrame); 1799 } 1800 deriveType(MethodHandle target, int position, MethodHandle combiner)1801 private static MethodType deriveType(MethodHandle target, 1802 int position, 1803 MethodHandle combiner) { 1804 if (combiner.type().rtype() == void.class) { 1805 return target.type(); 1806 } 1807 return target.type().dropParameterTypes(position, position + 1); 1808 } 1809 } 1810 1811 /** Implements {@code MethodHandles.insertArguments}. */ 1812 static class InsertArguments extends Transformer { 1813 private final MethodHandle target; 1814 private final int pos; 1815 private final Object[] values; 1816 1817 private final Range range1; 1818 private final Range range2; 1819 InsertArguments(MethodHandle target, int pos, Object[] values)1820 InsertArguments(MethodHandle target, int pos, Object[] values) { 1821 super(target.type().dropParameterTypes(pos, pos + values.length)); 1822 this.target = target; 1823 this.pos = pos; 1824 this.values = values; 1825 1826 final MethodType type = type(); 1827 range1 = EmulatedStackFrame.Range.of(type, 0, pos); 1828 range2 = Range.of(type, pos, type.parameterCount()); 1829 } 1830 1831 @Override transform(EmulatedStackFrame stackFrame)1832 public void transform(EmulatedStackFrame stackFrame) throws Throwable { 1833 EmulatedStackFrame calleeFrame = EmulatedStackFrame.create(target.type()); 1834 1835 // Copy all arguments before |pos|. 1836 stackFrame.copyRangeTo(calleeFrame, range1, 0, 0); 1837 1838 // Attach a stack frame writer so that we can copy the next |values.length| 1839 // arguments. 1840 final StackFrameWriter writer = new StackFrameWriter(); 1841 writer.attach(calleeFrame, pos, range1.numReferences, range1.numBytes); 1842 1843 // Copy all the arguments supplied in |values|. 1844 int referencesCopied = 0; 1845 int bytesCopied = 0; 1846 final Class<?>[] ptypes = target.type().ptypes(); 1847 for (int i = 0; i < values.length; ++i) { 1848 final Class<?> ptype = ptypes[i + pos]; 1849 final char typeChar = Wrapper.basicTypeChar(ptype); 1850 if (typeChar == 'L') { 1851 writer.putNextReference(values[i], ptype); 1852 referencesCopied++; 1853 } else { 1854 switch (typeChar) { 1855 case 'Z': 1856 writer.putNextBoolean((boolean) values[i]); 1857 break; 1858 case 'B': 1859 writer.putNextByte((byte) values[i]); 1860 break; 1861 case 'C': 1862 writer.putNextChar((char) values[i]); 1863 break; 1864 case 'S': 1865 writer.putNextShort((short) values[i]); 1866 break; 1867 case 'I': 1868 writer.putNextInt((int) values[i]); 1869 break; 1870 case 'J': 1871 writer.putNextLong((long) values[i]); 1872 break; 1873 case 'F': 1874 writer.putNextFloat((float) values[i]); 1875 break; 1876 case 'D': 1877 writer.putNextDouble((double) values[i]); 1878 break; 1879 } 1880 bytesCopied += EmulatedStackFrame.getSize(ptype); 1881 } 1882 } 1883 1884 // Copy all remaining arguments. 1885 if (range2 != null) { 1886 stackFrame.copyRangeTo( 1887 calleeFrame, 1888 range2, 1889 range1.numReferences + referencesCopied, 1890 range1.numBytes + bytesCopied); 1891 } 1892 1893 invokeFromTransform(target, calleeFrame); 1894 calleeFrame.copyReturnValueTo(stackFrame); 1895 } 1896 } 1897 1898 /** Implements {@code MethodHandle.asType}. */ 1899 static class AsTypeAdapter extends Transformer { 1900 private final MethodHandle target; 1901 AsTypeAdapter(MethodHandle target, MethodType type)1902 AsTypeAdapter(MethodHandle target, MethodType type) { 1903 super(type); 1904 this.target = target; 1905 } 1906 1907 @Override transform(EmulatedStackFrame callerFrame)1908 public void transform(EmulatedStackFrame callerFrame) throws Throwable { 1909 final EmulatedStackFrame targetFrame = EmulatedStackFrame.create(target.type()); 1910 final StackFrameReader reader = new StackFrameReader(); 1911 final StackFrameWriter writer = new StackFrameWriter(); 1912 1913 // Adapt arguments 1914 reader.attach(callerFrame); 1915 writer.attach(targetFrame); 1916 adaptArguments(reader, writer); 1917 1918 // Invoke target 1919 invokeFromTransform(target, targetFrame); 1920 1921 if (callerFrame.getMethodType().rtype() != void.class) { 1922 // Adapt return value 1923 reader.attach(targetFrame).makeReturnValueAccessor(); 1924 writer.attach(callerFrame).makeReturnValueAccessor(); 1925 adaptReturnValue(reader, writer); 1926 } 1927 } 1928 adaptArguments(final StackFrameReader reader, final StackFrameWriter writer)1929 private void adaptArguments(final StackFrameReader reader, final StackFrameWriter writer) { 1930 final Class<?>[] fromTypes = type().ptypes(); 1931 final Class<?>[] toTypes = target.type().ptypes(); 1932 for (int i = 0; i < fromTypes.length; ++i) { 1933 adaptArgument(reader, fromTypes[i], writer, toTypes[i]); 1934 } 1935 } 1936 adaptReturnValue( final StackFrameReader reader, final StackFrameWriter writer)1937 private void adaptReturnValue( 1938 final StackFrameReader reader, final StackFrameWriter writer) { 1939 final Class<?> fromType = target.type().rtype(); 1940 final Class<?> toType = type().rtype(); 1941 adaptArgument(reader, fromType, writer, toType); 1942 } 1943 throwWrongMethodTypeException()1944 private void throwWrongMethodTypeException() throws WrongMethodTypeException { 1945 throw new WrongMethodTypeException( 1946 "Cannot convert from " + type() + " to " + target.type()); 1947 } 1948 throwClassCastException(Class from, Class to)1949 private static void throwClassCastException(Class from, Class to) 1950 throws ClassCastException { 1951 throw new ClassCastException("Cannot cast from " + from + " to " + to); 1952 } 1953 writePrimitiveByteAs(final StackFrameWriter writer, char baseType, byte value)1954 private void writePrimitiveByteAs(final StackFrameWriter writer, char baseType, byte value) 1955 throws WrongMethodTypeException { 1956 switch (baseType) { 1957 case 'B': 1958 writer.putNextByte(value); 1959 return; 1960 case 'S': 1961 writer.putNextShort((short) value); 1962 return; 1963 case 'I': 1964 writer.putNextInt((int) value); 1965 return; 1966 case 'J': 1967 writer.putNextLong((long) value); 1968 return; 1969 case 'F': 1970 writer.putNextFloat((float) value); 1971 return; 1972 case 'D': 1973 writer.putNextDouble((double) value); 1974 return; 1975 default: 1976 throwWrongMethodTypeException(); 1977 } 1978 } 1979 writePrimitiveShortAs( final StackFrameWriter writer, char baseType, short value)1980 private void writePrimitiveShortAs( 1981 final StackFrameWriter writer, char baseType, short value) 1982 throws WrongMethodTypeException { 1983 switch (baseType) { 1984 case 'S': 1985 writer.putNextShort(value); 1986 return; 1987 case 'I': 1988 writer.putNextInt((int) value); 1989 return; 1990 case 'J': 1991 writer.putNextLong((long) value); 1992 return; 1993 case 'F': 1994 writer.putNextFloat((float) value); 1995 return; 1996 case 'D': 1997 writer.putNextDouble((double) value); 1998 return; 1999 default: 2000 throwWrongMethodTypeException(); 2001 } 2002 } 2003 writePrimitiveCharAs(final StackFrameWriter writer, char baseType, char value)2004 private void writePrimitiveCharAs(final StackFrameWriter writer, char baseType, char value) 2005 throws WrongMethodTypeException { 2006 switch (baseType) { 2007 case 'C': 2008 writer.putNextChar(value); 2009 return; 2010 case 'I': 2011 writer.putNextInt((int) value); 2012 return; 2013 case 'J': 2014 writer.putNextLong((long) value); 2015 return; 2016 case 'F': 2017 writer.putNextFloat((float) value); 2018 return; 2019 case 'D': 2020 writer.putNextDouble((double) value); 2021 return; 2022 default: 2023 throwWrongMethodTypeException(); 2024 } 2025 } 2026 writePrimitiveIntAs(final StackFrameWriter writer, char baseType, int value)2027 private void writePrimitiveIntAs(final StackFrameWriter writer, char baseType, int value) 2028 throws WrongMethodTypeException { 2029 switch (baseType) { 2030 case 'I': 2031 writer.putNextInt(value); 2032 return; 2033 case 'J': 2034 writer.putNextLong((long) value); 2035 return; 2036 case 'F': 2037 writer.putNextFloat((float) value); 2038 return; 2039 case 'D': 2040 writer.putNextDouble((double) value); 2041 return; 2042 default: 2043 throwWrongMethodTypeException(); 2044 } 2045 throwWrongMethodTypeException(); 2046 } 2047 writePrimitiveLongAs(final StackFrameWriter writer, char baseType, long value)2048 private void writePrimitiveLongAs(final StackFrameWriter writer, char baseType, long value) 2049 throws WrongMethodTypeException { 2050 switch (baseType) { 2051 case 'J': 2052 writer.putNextLong(value); 2053 return; 2054 case 'F': 2055 writer.putNextFloat((float) value); 2056 return; 2057 case 'D': 2058 writer.putNextDouble((double) value); 2059 return; 2060 default: 2061 throwWrongMethodTypeException(); 2062 } 2063 } 2064 writePrimitiveFloatAs( final StackFrameWriter writer, char baseType, float value)2065 private void writePrimitiveFloatAs( 2066 final StackFrameWriter writer, char baseType, float value) 2067 throws WrongMethodTypeException { 2068 switch (baseType) { 2069 case 'F': 2070 writer.putNextFloat(value); 2071 return; 2072 case 'D': 2073 writer.putNextDouble((double) value); 2074 return; 2075 default: 2076 throwWrongMethodTypeException(); 2077 } 2078 } 2079 writePrimitiveDoubleAs( final StackFrameWriter writer, char baseType, double value)2080 private void writePrimitiveDoubleAs( 2081 final StackFrameWriter writer, char baseType, double value) 2082 throws WrongMethodTypeException { 2083 switch (baseType) { 2084 case 'D': 2085 writer.putNextDouble(value); 2086 return; 2087 default: 2088 throwWrongMethodTypeException(); 2089 } 2090 } 2091 writePrimitiveVoidAs(final StackFrameWriter writer, char baseType)2092 private void writePrimitiveVoidAs(final StackFrameWriter writer, char baseType) { 2093 switch (baseType) { 2094 case 'Z': 2095 writer.putNextBoolean(false); 2096 return; 2097 case 'B': 2098 writer.putNextByte((byte) 0); 2099 return; 2100 case 'S': 2101 writer.putNextShort((short) 0); 2102 return; 2103 case 'C': 2104 writer.putNextChar((char) 0); 2105 return; 2106 case 'I': 2107 writer.putNextInt(0); 2108 return; 2109 case 'J': 2110 writer.putNextLong(0L); 2111 return; 2112 case 'F': 2113 writer.putNextFloat(0.0f); 2114 return; 2115 case 'D': 2116 writer.putNextDouble(0.0); 2117 return; 2118 default: 2119 throwWrongMethodTypeException(); 2120 } 2121 } 2122 getBoxedPrimitiveClass(char baseType)2123 private static Class getBoxedPrimitiveClass(char baseType) { 2124 switch (baseType) { 2125 case 'Z': 2126 return Boolean.class; 2127 case 'B': 2128 return Byte.class; 2129 case 'S': 2130 return Short.class; 2131 case 'C': 2132 return Character.class; 2133 case 'I': 2134 return Integer.class; 2135 case 'J': 2136 return Long.class; 2137 case 'F': 2138 return Float.class; 2139 case 'D': 2140 return Double.class; 2141 default: 2142 return null; 2143 } 2144 } 2145 adaptArgument( final StackFrameReader reader, final Class<?> from, final StackFrameWriter writer, final Class<?> to)2146 private void adaptArgument( 2147 final StackFrameReader reader, 2148 final Class<?> from, 2149 final StackFrameWriter writer, 2150 final Class<?> to) { 2151 if (from.equals(to)) { 2152 StackFrameAccessor.copyNext(reader, writer, from); 2153 return; 2154 } 2155 2156 if (to.isPrimitive()) { 2157 if (from.isPrimitive()) { 2158 final char fromBaseType = Wrapper.basicTypeChar(from); 2159 final char toBaseType = Wrapper.basicTypeChar(to); 2160 switch (fromBaseType) { 2161 case 'B': 2162 writePrimitiveByteAs(writer, toBaseType, reader.nextByte()); 2163 return; 2164 case 'S': 2165 writePrimitiveShortAs(writer, toBaseType, reader.nextShort()); 2166 return; 2167 case 'C': 2168 writePrimitiveCharAs(writer, toBaseType, reader.nextChar()); 2169 return; 2170 case 'I': 2171 writePrimitiveIntAs(writer, toBaseType, reader.nextInt()); 2172 return; 2173 case 'J': 2174 writePrimitiveLongAs(writer, toBaseType, reader.nextLong()); 2175 return; 2176 case 'F': 2177 writePrimitiveFloatAs(writer, toBaseType, reader.nextFloat()); 2178 return; 2179 case 'V': 2180 writePrimitiveVoidAs(writer, toBaseType); 2181 return; 2182 default: 2183 throwWrongMethodTypeException(); 2184 } 2185 } else { 2186 final Object value = reader.nextReference(Object.class); 2187 if (to == void.class) { 2188 return; 2189 } 2190 if (value == null) { 2191 throw new NullPointerException(); 2192 } 2193 if (!Wrapper.isWrapperType(value.getClass())) { 2194 throwClassCastException(value.getClass(), to); 2195 } 2196 final Wrapper fromWrapper = Wrapper.forWrapperType(value.getClass()); 2197 final Wrapper toWrapper = Wrapper.forPrimitiveType(to); 2198 if (!toWrapper.isConvertibleFrom(fromWrapper)) { 2199 throwClassCastException(from, to); 2200 } 2201 2202 final char toChar = toWrapper.basicTypeChar(); 2203 switch (fromWrapper.basicTypeChar()) { 2204 case 'Z': 2205 writer.putNextBoolean(((Boolean) value).booleanValue()); 2206 return; 2207 case 'B': 2208 writePrimitiveByteAs(writer, toChar, ((Byte) value).byteValue()); 2209 return; 2210 case 'S': 2211 writePrimitiveShortAs(writer, toChar, ((Short) value).shortValue()); 2212 return; 2213 case 'C': 2214 writePrimitiveCharAs(writer, toChar, ((Character) value).charValue()); 2215 return; 2216 case 'I': 2217 writePrimitiveIntAs(writer, toChar, ((Integer) value).intValue()); 2218 return; 2219 case 'J': 2220 writePrimitiveLongAs(writer, toChar, ((Long) value).longValue()); 2221 return; 2222 case 'F': 2223 writePrimitiveFloatAs(writer, toChar, ((Float) value).floatValue()); 2224 return; 2225 case 'D': 2226 writePrimitiveDoubleAs(writer, toChar, ((Double) value).doubleValue()); 2227 return; 2228 default: 2229 throw new IllegalStateException(); 2230 } 2231 } 2232 } else { 2233 if (from.isPrimitive()) { 2234 // Boxing conversion 2235 final char fromBaseType = Wrapper.basicTypeChar(from); 2236 final Class fromBoxed = getBoxedPrimitiveClass(fromBaseType); 2237 // 'to' maybe a super class of the boxed `from` type, e.g. Number. 2238 if (fromBoxed != null && !to.isAssignableFrom(fromBoxed)) { 2239 throwWrongMethodTypeException(); 2240 } 2241 2242 Object boxed; 2243 switch (fromBaseType) { 2244 case 'Z': 2245 boxed = Boolean.valueOf(reader.nextBoolean()); 2246 break; 2247 case 'B': 2248 boxed = Byte.valueOf(reader.nextByte()); 2249 break; 2250 case 'S': 2251 boxed = Short.valueOf(reader.nextShort()); 2252 break; 2253 case 'C': 2254 boxed = Character.valueOf(reader.nextChar()); 2255 break; 2256 case 'I': 2257 boxed = Integer.valueOf(reader.nextInt()); 2258 break; 2259 case 'J': 2260 boxed = Long.valueOf(reader.nextLong()); 2261 break; 2262 case 'F': 2263 boxed = Float.valueOf(reader.nextFloat()); 2264 break; 2265 case 'D': 2266 boxed = Double.valueOf(reader.nextDouble()); 2267 break; 2268 case 'V': 2269 boxed = null; 2270 break; 2271 default: 2272 throw new IllegalStateException(); 2273 } 2274 writer.putNextReference(boxed, to); 2275 return; 2276 } else { 2277 // Cast 2278 Object value = reader.nextReference(Object.class); 2279 if (value != null && !to.isAssignableFrom(value.getClass())) { 2280 throwClassCastException(value.getClass(), to); 2281 } 2282 writer.putNextReference(value, to); 2283 } 2284 } 2285 } 2286 } 2287 2288 /** Implements {@code MethodHandles.explicitCastArguments}. */ 2289 static class ExplicitCastArguments extends Transformer { 2290 private final MethodHandle target; 2291 ExplicitCastArguments(MethodHandle target, MethodType type)2292 ExplicitCastArguments(MethodHandle target, MethodType type) { 2293 super(type); 2294 this.target = target; 2295 } 2296 2297 @Override transform(EmulatedStackFrame callerFrame)2298 public void transform(EmulatedStackFrame callerFrame) throws Throwable { 2299 // Create a new stack frame for the target. 2300 EmulatedStackFrame targetFrame = EmulatedStackFrame.create(target.type()); 2301 2302 explicitCastArguments(callerFrame, targetFrame); 2303 invokeFromTransform(target, targetFrame); 2304 explicitCastReturnValue(callerFrame, targetFrame); 2305 } 2306 explicitCastArguments( final EmulatedStackFrame callerFrame, final EmulatedStackFrame targetFrame)2307 private void explicitCastArguments( 2308 final EmulatedStackFrame callerFrame, final EmulatedStackFrame targetFrame) { 2309 final StackFrameReader reader = new StackFrameReader(); 2310 reader.attach(callerFrame); 2311 final StackFrameWriter writer = new StackFrameWriter(); 2312 writer.attach(targetFrame); 2313 2314 final Class<?>[] fromTypes = type().ptypes(); 2315 final Class<?>[] toTypes = target.type().ptypes(); 2316 for (int i = 0; i < fromTypes.length; ++i) { 2317 explicitCast(reader, fromTypes[i], writer, toTypes[i]); 2318 } 2319 } 2320 explicitCastReturnValue( final EmulatedStackFrame callerFrame, final EmulatedStackFrame targetFrame)2321 private void explicitCastReturnValue( 2322 final EmulatedStackFrame callerFrame, final EmulatedStackFrame targetFrame) { 2323 Class<?> from = target.type().rtype(); 2324 Class<?> to = type().rtype(); 2325 if (to != void.class) { 2326 final StackFrameWriter writer = new StackFrameWriter(); 2327 writer.attach(callerFrame); 2328 writer.makeReturnValueAccessor(); 2329 if (from == void.class) { 2330 if (to.isPrimitive()) { 2331 unboxNull(writer, to); 2332 } else { 2333 writer.putNextReference(null, to); 2334 } 2335 } else { 2336 final StackFrameReader reader = new StackFrameReader(); 2337 reader.attach(targetFrame); 2338 reader.makeReturnValueAccessor(); 2339 explicitCast(reader, target.type().rtype(), writer, type().rtype()); 2340 } 2341 } 2342 } 2343 throwUnexpectedType(final Class<?> unexpectedType)2344 private static void throwUnexpectedType(final Class<?> unexpectedType) { 2345 throw new InternalError("Unexpected type: " + unexpectedType); 2346 } 2347 2348 @SuppressWarnings("unchecked") badCast(final Class<?> from, final Class<?> to)2349 private static void badCast(final Class<?> from, final Class<?> to) { 2350 throw new ClassCastException("Cannot cast " + from.getName() + " to " + to.getName()); 2351 } 2352 2353 /** 2354 * Converts byte value to boolean according to {@link 2355 * java.lang.invoke.MethodHandles#explicitCast()} 2356 */ toBoolean(byte value)2357 private static boolean toBoolean(byte value) { 2358 return (value & 1) == 1; 2359 } 2360 readPrimitiveAsByte( final StackFrameReader reader, final Class<?> from)2361 private static byte readPrimitiveAsByte( 2362 final StackFrameReader reader, final Class<?> from) { 2363 switch (Wrapper.basicTypeChar(from)) { 2364 case 'B': 2365 return (byte) reader.nextByte(); 2366 case 'C': 2367 return (byte) reader.nextChar(); 2368 case 'S': 2369 return (byte) reader.nextShort(); 2370 case 'I': 2371 return (byte) reader.nextInt(); 2372 case 'J': 2373 return (byte) reader.nextLong(); 2374 case 'F': 2375 return (byte) reader.nextFloat(); 2376 case 'D': 2377 return (byte) reader.nextDouble(); 2378 case 'Z': 2379 return reader.nextBoolean() ? (byte) 1 : (byte) 0; 2380 default: 2381 throwUnexpectedType(from); 2382 return 0; 2383 } 2384 } 2385 readPrimitiveAsChar( final StackFrameReader reader, final Class<?> from)2386 private static char readPrimitiveAsChar( 2387 final StackFrameReader reader, final Class<?> from) { 2388 switch (Wrapper.basicTypeChar(from)) { 2389 case 'B': 2390 return (char) reader.nextByte(); 2391 case 'C': 2392 return (char) reader.nextChar(); 2393 case 'S': 2394 return (char) reader.nextShort(); 2395 case 'I': 2396 return (char) reader.nextInt(); 2397 case 'J': 2398 return (char) reader.nextLong(); 2399 case 'F': 2400 return (char) reader.nextFloat(); 2401 case 'D': 2402 return (char) reader.nextDouble(); 2403 case 'Z': 2404 return reader.nextBoolean() ? (char) 1 : (char) 0; 2405 default: 2406 throwUnexpectedType(from); 2407 return 0; 2408 } 2409 } 2410 readPrimitiveAsShort( final StackFrameReader reader, final Class<?> from)2411 private static short readPrimitiveAsShort( 2412 final StackFrameReader reader, final Class<?> from) { 2413 switch (Wrapper.basicTypeChar(from)) { 2414 case 'B': 2415 return (short) reader.nextByte(); 2416 case 'C': 2417 return (short) reader.nextChar(); 2418 case 'S': 2419 return (short) reader.nextShort(); 2420 case 'I': 2421 return (short) reader.nextInt(); 2422 case 'J': 2423 return (short) reader.nextLong(); 2424 case 'F': 2425 return (short) reader.nextFloat(); 2426 case 'D': 2427 return (short) reader.nextDouble(); 2428 case 'Z': 2429 return reader.nextBoolean() ? (short) 1 : (short) 0; 2430 default: 2431 throwUnexpectedType(from); 2432 return 0; 2433 } 2434 } 2435 readPrimitiveAsInt(final StackFrameReader reader, final Class<?> from)2436 private static int readPrimitiveAsInt(final StackFrameReader reader, final Class<?> from) { 2437 switch (Wrapper.basicTypeChar(from)) { 2438 case 'B': 2439 return (int) reader.nextByte(); 2440 case 'C': 2441 return (int) reader.nextChar(); 2442 case 'S': 2443 return (int) reader.nextShort(); 2444 case 'I': 2445 return (int) reader.nextInt(); 2446 case 'J': 2447 return (int) reader.nextLong(); 2448 case 'F': 2449 return (int) reader.nextFloat(); 2450 case 'D': 2451 return (int) reader.nextDouble(); 2452 case 'Z': 2453 return reader.nextBoolean() ? 1 : 0; 2454 default: 2455 throwUnexpectedType(from); 2456 return 0; 2457 } 2458 } 2459 readPrimitiveAsLong( final StackFrameReader reader, final Class<?> from)2460 private static long readPrimitiveAsLong( 2461 final StackFrameReader reader, final Class<?> from) { 2462 switch (Wrapper.basicTypeChar(from)) { 2463 case 'B': 2464 return (long) reader.nextByte(); 2465 case 'C': 2466 return (long) reader.nextChar(); 2467 case 'S': 2468 return (long) reader.nextShort(); 2469 case 'I': 2470 return (long) reader.nextInt(); 2471 case 'J': 2472 return (long) reader.nextLong(); 2473 case 'F': 2474 return (long) reader.nextFloat(); 2475 case 'D': 2476 return (long) reader.nextDouble(); 2477 case 'Z': 2478 return reader.nextBoolean() ? 1L : 0L; 2479 default: 2480 throwUnexpectedType(from); 2481 return 0; 2482 } 2483 } 2484 readPrimitiveAsFloat( final StackFrameReader reader, final Class<?> from)2485 private static float readPrimitiveAsFloat( 2486 final StackFrameReader reader, final Class<?> from) { 2487 switch (Wrapper.basicTypeChar(from)) { 2488 case 'B': 2489 return (float) reader.nextByte(); 2490 case 'C': 2491 return (float) reader.nextChar(); 2492 case 'S': 2493 return (float) reader.nextShort(); 2494 case 'I': 2495 return (float) reader.nextInt(); 2496 case 'J': 2497 return (float) reader.nextLong(); 2498 case 'F': 2499 return (float) reader.nextFloat(); 2500 case 'D': 2501 return (float) reader.nextDouble(); 2502 case 'Z': 2503 return reader.nextBoolean() ? 1.0f : 0.0f; 2504 default: 2505 throwUnexpectedType(from); 2506 return 0; 2507 } 2508 } 2509 readPrimitiveAsDouble( final StackFrameReader reader, final Class<?> from)2510 private static double readPrimitiveAsDouble( 2511 final StackFrameReader reader, final Class<?> from) { 2512 switch (Wrapper.basicTypeChar(from)) { 2513 case 'B': 2514 return (double) reader.nextByte(); 2515 case 'C': 2516 return (double) reader.nextChar(); 2517 case 'S': 2518 return (double) reader.nextShort(); 2519 case 'I': 2520 return (double) reader.nextInt(); 2521 case 'J': 2522 return (double) reader.nextLong(); 2523 case 'F': 2524 return (double) reader.nextFloat(); 2525 case 'D': 2526 return (double) reader.nextDouble(); 2527 case 'Z': 2528 return reader.nextBoolean() ? 1.0 : 0.0; 2529 default: 2530 throwUnexpectedType(from); 2531 return 0; 2532 } 2533 } 2534 explicitCastPrimitives( final StackFrameReader reader, final Class<?> from, final StackFrameWriter writer, final Class<?> to)2535 private static void explicitCastPrimitives( 2536 final StackFrameReader reader, 2537 final Class<?> from, 2538 final StackFrameWriter writer, 2539 final Class<?> to) { 2540 switch (Wrapper.basicTypeChar(to)) { 2541 case 'B': 2542 writer.putNextByte(readPrimitiveAsByte(reader, from)); 2543 break; 2544 case 'C': 2545 writer.putNextChar(readPrimitiveAsChar(reader, from)); 2546 break; 2547 case 'S': 2548 writer.putNextShort(readPrimitiveAsShort(reader, from)); 2549 break; 2550 case 'I': 2551 writer.putNextInt(readPrimitiveAsInt(reader, from)); 2552 break; 2553 case 'J': 2554 writer.putNextLong(readPrimitiveAsLong(reader, from)); 2555 break; 2556 case 'F': 2557 writer.putNextFloat(readPrimitiveAsFloat(reader, from)); 2558 break; 2559 case 'D': 2560 writer.putNextDouble(readPrimitiveAsDouble(reader, from)); 2561 break; 2562 case 'Z': 2563 writer.putNextBoolean(toBoolean(readPrimitiveAsByte(reader, from))); 2564 break; 2565 default: 2566 throwUnexpectedType(to); 2567 break; 2568 } 2569 } 2570 unboxNull(final StackFrameWriter writer, final Class<?> to)2571 private static void unboxNull(final StackFrameWriter writer, final Class<?> to) { 2572 switch (Wrapper.basicTypeChar(to)) { 2573 case 'Z': 2574 writer.putNextBoolean(false); 2575 break; 2576 case 'B': 2577 writer.putNextByte((byte) 0); 2578 break; 2579 case 'C': 2580 writer.putNextChar((char) 0); 2581 break; 2582 case 'S': 2583 writer.putNextShort((short) 0); 2584 break; 2585 case 'I': 2586 writer.putNextInt((int) 0); 2587 break; 2588 case 'J': 2589 writer.putNextLong((long) 0); 2590 break; 2591 case 'F': 2592 writer.putNextFloat((float) 0); 2593 break; 2594 case 'D': 2595 writer.putNextDouble((double) 0); 2596 break; 2597 default: 2598 throwUnexpectedType(to); 2599 break; 2600 } 2601 } 2602 unboxNonNull( final Object ref, final StackFrameWriter writer, final Class<?> to)2603 private static void unboxNonNull( 2604 final Object ref, 2605 final StackFrameWriter writer, 2606 final Class<?> to) { 2607 final Class<?> from = ref.getClass(); 2608 final Class<?> unboxedFromType = Wrapper.asPrimitiveType(from); 2609 switch (Wrapper.basicTypeChar(unboxedFromType)) { 2610 case 'Z': 2611 boolean z = (boolean) ref; 2612 switch (Wrapper.basicTypeChar(to)) { 2613 case 'Z': 2614 writer.putNextBoolean(z); 2615 break; 2616 case 'B': 2617 writer.putNextByte(z ? (byte) 1 : (byte) 0); 2618 break; 2619 case 'S': 2620 writer.putNextShort(z ? (short) 1 : (short) 0); 2621 break; 2622 case 'C': 2623 writer.putNextChar(z ? (char) 1 : (char) 0); 2624 break; 2625 case 'I': 2626 writer.putNextInt(z ? 1 : 0); 2627 break; 2628 case 'J': 2629 writer.putNextLong(z ? 1l : 0l); 2630 break; 2631 case 'F': 2632 writer.putNextFloat(z ? 1.0f : 0.0f); 2633 break; 2634 case 'D': 2635 writer.putNextDouble(z ? 1.0 : 0.0); 2636 break; 2637 default: 2638 badCast(from, to); 2639 break; 2640 } 2641 break; 2642 case 'B': 2643 byte b = (byte) ref; 2644 switch (Wrapper.basicTypeChar(to)) { 2645 case 'B': 2646 writer.putNextByte(b); 2647 break; 2648 case 'Z': 2649 writer.putNextBoolean(toBoolean(b)); 2650 break; 2651 case 'S': 2652 writer.putNextShort((short) b); 2653 break; 2654 case 'C': 2655 writer.putNextChar((char) b); 2656 break; 2657 case 'I': 2658 writer.putNextInt((int) b); 2659 break; 2660 case 'J': 2661 writer.putNextLong((long) b); 2662 break; 2663 case 'F': 2664 writer.putNextFloat((float) b); 2665 break; 2666 case 'D': 2667 writer.putNextDouble((double) b); 2668 break; 2669 default: 2670 badCast(from, to); 2671 break; 2672 } 2673 break; 2674 case 'S': 2675 short s = (short) ref; 2676 switch (Wrapper.basicTypeChar(to)) { 2677 case 'Z': 2678 writer.putNextBoolean((s & 1) == 1); 2679 break; 2680 case 'B': 2681 writer.putNextByte((byte) s); 2682 break; 2683 case 'S': 2684 writer.putNextShort(s); 2685 break; 2686 case 'C': 2687 writer.putNextChar((char) s); 2688 break; 2689 case 'I': 2690 writer.putNextInt((int) s); 2691 break; 2692 case 'J': 2693 writer.putNextLong((long) s); 2694 break; 2695 case 'F': 2696 writer.putNextFloat((float) s); 2697 break; 2698 case 'D': 2699 writer.putNextDouble((double) s); 2700 break; 2701 default: 2702 badCast(from, to); 2703 break; 2704 } 2705 break; 2706 case 'C': 2707 char c = (char) ref; 2708 switch (Wrapper.basicTypeChar(to)) { 2709 case 'Z': 2710 writer.putNextBoolean((c & (char) 1) == (char) 1); 2711 break; 2712 case 'B': 2713 writer.putNextByte((byte) c); 2714 break; 2715 case 'S': 2716 writer.putNextShort((short) c); 2717 break; 2718 case 'C': 2719 writer.putNextChar(c); 2720 break; 2721 case 'I': 2722 writer.putNextInt((int) c); 2723 break; 2724 case 'J': 2725 writer.putNextLong((long) c); 2726 break; 2727 case 'F': 2728 writer.putNextFloat((float) c); 2729 break; 2730 case 'D': 2731 writer.putNextDouble((double) c); 2732 break; 2733 default: 2734 badCast(from, to); 2735 break; 2736 } 2737 break; 2738 case 'I': 2739 int i = (int) ref; 2740 switch (Wrapper.basicTypeChar(to)) { 2741 case 'Z': 2742 writer.putNextBoolean((i & 1) == 1); 2743 break; 2744 case 'B': 2745 writer.putNextByte((byte) i); 2746 break; 2747 case 'S': 2748 writer.putNextShort((short) i); 2749 break; 2750 case 'C': 2751 writer.putNextChar((char) i); 2752 break; 2753 case 'I': 2754 writer.putNextInt(i); 2755 break; 2756 case 'J': 2757 writer.putNextLong((long) i); 2758 break; 2759 case 'F': 2760 writer.putNextFloat((float) i); 2761 break; 2762 case 'D': 2763 writer.putNextDouble((double) i); 2764 break; 2765 default: 2766 badCast(from, to); 2767 } 2768 break; 2769 case 'J': 2770 long j = (long) ref; 2771 switch (Wrapper.basicTypeChar(to)) { 2772 case 'Z': 2773 writer.putNextBoolean((j & 1l) == 1l); 2774 break; 2775 case 'B': 2776 writer.putNextByte((byte) j); 2777 break; 2778 case 'S': 2779 writer.putNextShort((short) j); 2780 break; 2781 case 'C': 2782 writer.putNextChar((char) j); 2783 break; 2784 case 'I': 2785 writer.putNextInt((int) j); 2786 break; 2787 case 'J': 2788 writer.putNextLong(j); 2789 break; 2790 case 'F': 2791 writer.putNextFloat((float) j); 2792 break; 2793 case 'D': 2794 writer.putNextDouble((double) j); 2795 break; 2796 default: 2797 badCast(from, to); 2798 break; 2799 } 2800 break; 2801 case 'F': 2802 float f = (float) ref; 2803 switch (Wrapper.basicTypeChar(to)) { 2804 case 'Z': 2805 writer.putNextBoolean(((byte) f & 1) != 0); 2806 break; 2807 case 'B': 2808 writer.putNextByte((byte) f); 2809 break; 2810 case 'S': 2811 writer.putNextShort((short) f); 2812 break; 2813 case 'C': 2814 writer.putNextChar((char) f); 2815 break; 2816 case 'I': 2817 writer.putNextInt((int) f); 2818 break; 2819 case 'J': 2820 writer.putNextLong((long) f); 2821 break; 2822 case 'F': 2823 writer.putNextFloat(f); 2824 break; 2825 case 'D': 2826 writer.putNextDouble((double) f); 2827 break; 2828 default: 2829 badCast(from, to); 2830 break; 2831 } 2832 break; 2833 case 'D': 2834 double d = (double) ref; 2835 switch (Wrapper.basicTypeChar(to)) { 2836 case 'Z': 2837 writer.putNextBoolean(((byte) d & 1) != 0); 2838 break; 2839 case 'B': 2840 writer.putNextByte((byte) d); 2841 break; 2842 case 'S': 2843 writer.putNextShort((short) d); 2844 break; 2845 case 'C': 2846 writer.putNextChar((char) d); 2847 break; 2848 case 'I': 2849 writer.putNextInt((int) d); 2850 break; 2851 case 'J': 2852 writer.putNextLong((long) d); 2853 break; 2854 case 'F': 2855 writer.putNextFloat((float) d); 2856 break; 2857 case 'D': 2858 writer.putNextDouble(d); 2859 break; 2860 default: 2861 badCast(from, to); 2862 break; 2863 } 2864 break; 2865 default: 2866 badCast(from, to); 2867 break; 2868 } 2869 } 2870 unbox( final Object ref, final StackFrameWriter writer, final Class<?> to)2871 private static void unbox( 2872 final Object ref, 2873 final StackFrameWriter writer, 2874 final Class<?> to) { 2875 if (ref == null) { 2876 unboxNull(writer, to); 2877 } else { 2878 unboxNonNull(ref, writer, to); 2879 } 2880 } 2881 box( final StackFrameReader reader, final Class<?> from, final StackFrameWriter writer, final Class<?> to)2882 private static void box( 2883 final StackFrameReader reader, 2884 final Class<?> from, 2885 final StackFrameWriter writer, 2886 final Class<?> to) { 2887 Object boxed = null; 2888 switch (Wrapper.basicTypeChar(from)) { 2889 case 'Z': 2890 boxed = Boolean.valueOf(reader.nextBoolean()); 2891 break; 2892 case 'B': 2893 boxed = Byte.valueOf(reader.nextByte()); 2894 break; 2895 case 'C': 2896 boxed = Character.valueOf(reader.nextChar()); 2897 break; 2898 case 'S': 2899 boxed = Short.valueOf(reader.nextShort()); 2900 break; 2901 case 'I': 2902 boxed = Integer.valueOf(reader.nextInt()); 2903 break; 2904 case 'J': 2905 boxed = Long.valueOf(reader.nextLong()); 2906 break; 2907 case 'F': 2908 boxed = Float.valueOf(reader.nextFloat()); 2909 break; 2910 case 'D': 2911 boxed = Double.valueOf(reader.nextDouble()); 2912 break; 2913 default: 2914 throwUnexpectedType(from); 2915 break; 2916 } 2917 writer.putNextReference(to.cast(boxed), to); 2918 } 2919 explicitCast( final StackFrameReader reader, final Class<?> from, final StackFrameWriter writer, final Class<?> to)2920 private static void explicitCast( 2921 final StackFrameReader reader, 2922 final Class<?> from, 2923 final StackFrameWriter writer, 2924 final Class<?> to) { 2925 if (from.equals(to)) { 2926 StackFrameAccessor.copyNext(reader, writer, from); 2927 return; 2928 } 2929 2930 if (from.isPrimitive()) { 2931 if (to.isPrimitive()) { 2932 // |from| and |to| are primitive types. 2933 explicitCastPrimitives(reader, from, writer, to); 2934 } else { 2935 // |from| is a primitive type, |to| is a reference type. 2936 box(reader, from, writer, to); 2937 } 2938 } else { 2939 // |from| is a reference type. 2940 Object ref = reader.nextReference(from); 2941 if (to.isPrimitive()) { 2942 // |from| is a reference type, |to| is a primitive type, 2943 unbox(ref, writer, to); 2944 } else if (to.isInterface()) { 2945 // Pass from without a cast according to description for 2946 // {@link java.lang.invoke.MethodHandles#explicitCastArguments()}. 2947 writer.putNextReference(ref, to); 2948 } else { 2949 // |to| and from |from| are reference types, perform class cast check. 2950 writer.putNextReference(to.cast(ref), to); 2951 } 2952 } 2953 } 2954 } 2955 2956 /** Implements {@code MethodHandles.loop}. */ 2957 static class Loop extends Transformer { 2958 2959 /** Loop variable initialization methods. */ 2960 final MethodHandle[] inits; 2961 2962 /** Loop variable step methods. */ 2963 final MethodHandle[] steps; 2964 2965 /** Loop variable predicate methods. */ 2966 final MethodHandle[] preds; 2967 2968 /** Loop return value calculating methods. */ 2969 final MethodHandle[] finis; 2970 2971 /** Synthetic method type for frame used to hold loop variables. */ 2972 final MethodType loopVarsType; 2973 2974 /** Range of loop variables in the frame used for loop variables. */ 2975 final Range loopVarsRange; 2976 2977 /** Range of suffix variables in the caller frame. */ 2978 final Range suffixRange; 2979 Loop(Class<?> loopReturnType, List<Class<?>> commonSuffix, MethodHandle[] finit, MethodHandle[] fstep, MethodHandle[] fpred, MethodHandle[] ffini)2980 public Loop(Class<?> loopReturnType, 2981 List<Class<?>> commonSuffix, 2982 MethodHandle[] finit, 2983 MethodHandle[] fstep, 2984 MethodHandle[] fpred, 2985 MethodHandle[] ffini) { 2986 super(MethodType.methodType(loopReturnType, commonSuffix)); 2987 2988 inits = finit; 2989 steps = fstep; 2990 preds = fpred; 2991 finis = ffini; 2992 2993 loopVarsType = deduceLoopVarsType(finit); 2994 loopVarsRange = EmulatedStackFrame.Range.all(loopVarsType); 2995 suffixRange = EmulatedStackFrame.Range.all(type()); 2996 } 2997 2998 @Override transform(EmulatedStackFrame callerFrame)2999 public void transform(EmulatedStackFrame callerFrame) throws Throwable { 3000 final EmulatedStackFrame loopVarsFrame = EmulatedStackFrame.create(loopVarsType); 3001 final StackFrameWriter loopVarsWriter = new StackFrameWriter(); 3002 3003 init(callerFrame, loopVarsFrame, loopVarsWriter); 3004 3005 for (;;) { 3006 loopVarsWriter.attach(loopVarsFrame); 3007 for (int i = 0; i < steps.length; ++i) { 3008 // Future optimization opportunity: there is a good deal of StackFrame 3009 // allocation here, one is allocated per MH invocation. Consider caching 3010 // frames <method-type:stack-frame> and passing the cache on the stack. 3011 doStep(steps[i], callerFrame, loopVarsFrame, loopVarsWriter); 3012 boolean keepGoing = doPredicate(preds[i], callerFrame, loopVarsFrame); 3013 if (!keepGoing) { 3014 doFinish(finis[i], callerFrame, loopVarsFrame); 3015 return; 3016 } 3017 } 3018 } 3019 } 3020 deduceLoopVarsType(final MethodHandle[] inits)3021 private static MethodType deduceLoopVarsType(final MethodHandle[] inits) { 3022 List<Class<?>> loopVarTypes = new ArrayList(inits.length); 3023 for (MethodHandle init : inits) { 3024 Class<?> returnType = init.type().returnType(); 3025 if (returnType != void.class) { 3026 loopVarTypes.add(returnType); 3027 } 3028 } 3029 return MethodType.methodType(void.class, loopVarTypes); 3030 } 3031 init(final EmulatedStackFrame callerFrame, final EmulatedStackFrame loopVarsFrame, final StackFrameWriter loopVarsWriter)3032 private void init(final EmulatedStackFrame callerFrame, 3033 final EmulatedStackFrame loopVarsFrame, 3034 final StackFrameWriter loopVarsWriter) throws Throwable { 3035 loopVarsWriter.attach(loopVarsFrame); 3036 for (MethodHandle init : inits) { 3037 EmulatedStackFrame initFrame = EmulatedStackFrame.create(init.type()); 3038 callerFrame.copyRangeTo(initFrame, suffixRange, 0, 0); 3039 3040 invokeExactFromTransform(init, initFrame); 3041 3042 final Class<?> loopVarType = init.type().returnType(); 3043 if (loopVarType != void.class) { 3044 StackFrameReader initReader = new StackFrameReader(); 3045 initReader.attach(initFrame).makeReturnValueAccessor(); 3046 copyNext(initReader, loopVarsWriter, loopVarType); 3047 } 3048 } 3049 } 3050 3051 /** 3052 * Creates a frame for invoking a method of specified type. 3053 * 3054 * The frame arguments are the loop variables followed by the arguments provided to the 3055 * loop MethodHandle. 3056 * 3057 * @param mt the type of the method to be invoked. 3058 * @param callerFrame the frame invoking the loop MethodHandle. 3059 * @param loopVarsFrame the frame holding loop variables. 3060 * @return an EmulatedStackFrame initialized with the required arguments. 3061 */ prepareFrame(final MethodType mt, final EmulatedStackFrame callerFrame, final EmulatedStackFrame loopVarsFrame)3062 private EmulatedStackFrame prepareFrame(final MethodType mt, 3063 final EmulatedStackFrame callerFrame, 3064 final EmulatedStackFrame loopVarsFrame) { 3065 EmulatedStackFrame frame = EmulatedStackFrame.create(mt); 3066 3067 // Copy loop variables. 3068 loopVarsFrame.copyRangeTo(frame, loopVarsRange, 0, 0); 3069 3070 // Copy arguments provided in the loop invoke(). 3071 callerFrame.copyRangeTo(frame, 3072 suffixRange, 3073 loopVarsRange.numReferences, 3074 loopVarsRange.numBytes); 3075 return frame; 3076 } 3077 doStep(final MethodHandle step, final EmulatedStackFrame callerFrame, final EmulatedStackFrame loopVarsFrame, final StackFrameWriter loopVarsWriter)3078 private void doStep(final MethodHandle step, 3079 final EmulatedStackFrame callerFrame, 3080 final EmulatedStackFrame loopVarsFrame, 3081 final StackFrameWriter loopVarsWriter) throws Throwable { 3082 final EmulatedStackFrame stepFrame = 3083 prepareFrame(step.type(), callerFrame, loopVarsFrame); 3084 invokeExactFromTransform(step, stepFrame); 3085 3086 final Class<?> loopVarType = step.type().returnType(); 3087 if (loopVarType != void.class) { 3088 final StackFrameReader stepReader = new StackFrameReader(); 3089 stepReader.attach(stepFrame).makeReturnValueAccessor(); 3090 copyNext(stepReader, loopVarsWriter, loopVarType); 3091 } 3092 } 3093 doPredicate(final MethodHandle pred, final EmulatedStackFrame callerFrame, final EmulatedStackFrame loopVarsFrame)3094 private boolean doPredicate(final MethodHandle pred, 3095 final EmulatedStackFrame callerFrame, 3096 final EmulatedStackFrame loopVarsFrame) throws Throwable { 3097 final EmulatedStackFrame predFrame = 3098 prepareFrame(pred.type(), callerFrame, loopVarsFrame); 3099 invokeExactFromTransform(pred, predFrame); 3100 3101 final StackFrameReader predReader = new StackFrameReader(); 3102 predReader.attach(predFrame).makeReturnValueAccessor(); 3103 return predReader.nextBoolean(); 3104 } 3105 doFinish(final MethodHandle fini, final EmulatedStackFrame callerFrame, final EmulatedStackFrame loopVarsFrame)3106 private void doFinish(final MethodHandle fini, 3107 final EmulatedStackFrame callerFrame, 3108 final EmulatedStackFrame loopVarsFrame) throws Throwable { 3109 final EmulatedStackFrame finiFrame = 3110 prepareFrame(fini.type(), callerFrame, loopVarsFrame); 3111 invokeExactFromTransform(fini, finiFrame); 3112 finiFrame.copyReturnValueTo(callerFrame); 3113 } 3114 } 3115 3116 /** Implements {@code MethodHandles.tableSwitch}. */ 3117 static class TableSwitch extends Transformer { 3118 private final MethodHandle fallback; 3119 private final MethodHandle[] targets; 3120 TableSwitch(MethodType type, MethodHandle fallback, MethodHandle[] targets)3121 TableSwitch(MethodType type, MethodHandle fallback, MethodHandle[] targets) { 3122 super(type); 3123 this.fallback = fallback; 3124 this.targets = targets; 3125 } 3126 3127 @Override transform(EmulatedStackFrame callerFrame)3128 public void transform(EmulatedStackFrame callerFrame) throws Throwable { 3129 final MethodHandle selected = selectMethodHandle(callerFrame); 3130 invokeExactFromTransform(selected, callerFrame); 3131 } 3132 selectMethodHandle(EmulatedStackFrame callerFrame)3133 private MethodHandle selectMethodHandle(EmulatedStackFrame callerFrame) { 3134 StackFrameReader reader = new StackFrameReader(); 3135 reader.attach(callerFrame); 3136 final int index = reader.nextInt(); 3137 3138 if (index >= 0 && index < targets.length) { 3139 return targets[index]; 3140 } else { 3141 return fallback; 3142 } 3143 } 3144 } 3145 } 3146