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