1 /* 2 * Copyright 2016 Google Inc. 3 * 4 * This code is free software; you can redistribute it and/or modify it 5 * under the terms of the GNU General Public License version 2 only, as 6 * published by the Free Software Foundation. Google designates this 7 * particular file as subject to the "Classpath" exception as provided 8 * by Google in the LICENSE file that accompanied this code. 9 * 10 * This code is distributed in the hope that it will be useful, but WITHOUT 11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 13 * version 2 for more details (a copy is included in the LICENSE file that 14 * accompanied this code). 15 * 16 * You should have received a copy of the GNU General Public License version 17 * 2 along with this work; if not, write to the Free Software Foundation, 18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 19 */ 20 21 package java.lang.invoke; 22 23 import dalvik.system.EmulatedStackFrame; 24 import dalvik.system.EmulatedStackFrame.Range; 25 import dalvik.system.EmulatedStackFrame.StackFrameAccessor; 26 import dalvik.system.EmulatedStackFrame.StackFrameReader; 27 import dalvik.system.EmulatedStackFrame.StackFrameWriter; 28 import java.lang.reflect.Array; 29 import java.lang.reflect.Method; 30 import java.lang.reflect.Modifier; 31 import sun.invoke.util.Wrapper; 32 import sun.misc.Unsafe; 33 import static dalvik.system.EmulatedStackFrame.StackFrameAccessor.copyNext; 34 35 /** 36 * @hide Public for testing only. 37 */ 38 public class Transformers { 39 private Transformers() {} 40 41 static { 42 try { 43 TRANSFORM_INTERNAL = MethodHandle.class.getDeclaredMethod("transformInternal", 44 EmulatedStackFrame.class); 45 } catch (NoSuchMethodException nsme) { 46 throw new AssertionError(); 47 } 48 } 49 50 /** 51 * Method reference to the private {@code MethodHandle.transformInternal} method. This is 52 * cached here because it's the point of entry for all transformers. 53 */ 54 private static final Method TRANSFORM_INTERNAL; 55 56 /** @hide */ 57 public static abstract class Transformer extends MethodHandle implements Cloneable { 58 protected Transformer(MethodType type) { 59 super(TRANSFORM_INTERNAL.getArtMethod(), MethodHandle.INVOKE_TRANSFORM, type); 60 } 61 62 protected Transformer(MethodType type, int invokeKind) { 63 super(TRANSFORM_INTERNAL.getArtMethod(), invokeKind, type); 64 } 65 66 @Override 67 public Object clone() throws CloneNotSupportedException { 68 return super.clone(); 69 } 70 } 71 72 /** 73 * A method handle that always throws an exception of a specified type. 74 * 75 * The handle declares a nominal return type, which is immaterial to the execution 76 * of the handle because it never returns. 77 * 78 * @hide 79 */ 80 public static class AlwaysThrow extends Transformer { 81 private final Class<? extends Throwable> exceptionType; 82 83 public AlwaysThrow(Class<?> nominalReturnType, Class<? extends Throwable> exType) { 84 super(MethodType.methodType(nominalReturnType, exType)); 85 this.exceptionType = exType; 86 } 87 88 @Override 89 public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable { 90 throw emulatedStackFrame.getReference(0, exceptionType); 91 } 92 } 93 94 /** 95 * Implements {@code MethodHandles.dropArguments}. 96 */ 97 public static class DropArguments extends Transformer { 98 private final MethodHandle delegate; 99 100 private final EmulatedStackFrame.Range range1; 101 102 /** 103 * Note that {@code range2} will be null if the arguments that are being dropped 104 * are the last {@code n}. 105 */ 106 /* @Nullable */ private final EmulatedStackFrame.Range range2; 107 108 public DropArguments(MethodType type, MethodHandle delegate, 109 int startPos, int numDropped) { 110 super(type); 111 112 this.delegate = delegate; 113 114 // We pre-calculate the ranges of values we have to copy through to the delegate 115 // handle at the time of instantiation so that the actual invoke is performant. 116 this.range1 = EmulatedStackFrame.Range.of(type, 0, startPos); 117 final int numArgs = type.ptypes().length; 118 if (startPos + numDropped < numArgs) { 119 this.range2 = EmulatedStackFrame.Range.of(type, startPos + numDropped, numArgs); 120 } else { 121 this.range2 = null; 122 } 123 } 124 125 @Override 126 public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable { 127 EmulatedStackFrame calleeFrame = EmulatedStackFrame.create(delegate.type()); 128 129 emulatedStackFrame.copyRangeTo(calleeFrame, range1, 130 0 /* referencesStart */, 0 /* stackFrameStart */); 131 132 if (range2 != null) { 133 final int referencesStart = range1.numReferences; 134 final int stackFrameStart = range1.numBytes; 135 136 emulatedStackFrame.copyRangeTo(calleeFrame, range2, 137 referencesStart, stackFrameStart); 138 } 139 140 delegate.invoke(calleeFrame); 141 calleeFrame.copyReturnValueTo(emulatedStackFrame); 142 } 143 } 144 145 /** 146 * Implements {@code MethodHandles.catchException}. 147 */ 148 public static class CatchException extends Transformer { 149 private final MethodHandle target; 150 private final MethodHandle handler; 151 private final Class<?> exType; 152 153 private final EmulatedStackFrame.Range handlerArgsRange; 154 155 public CatchException(MethodHandle target, MethodHandle handler, Class<?> exType) { 156 super(target.type()); 157 158 this.target = target; 159 this.handler = handler; 160 this.exType = exType; 161 162 // We only copy the first "count" args, dropping others if required. Note that 163 // we subtract one because the first handler arg is the exception thrown by the 164 // target. 165 handlerArgsRange = EmulatedStackFrame.Range.of(target.type(), 0, 166 (handler.type().parameterCount() - 1)); 167 } 168 169 @Override 170 public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable { 171 try { 172 target.invoke(emulatedStackFrame); 173 } catch (Throwable th) { 174 if (th.getClass() == exType) { 175 // We've gotten an exception of the appropriate type, so we need to call 176 // the handler. Create a new frame of the appropriate size. 177 EmulatedStackFrame fallback = EmulatedStackFrame.create(handler.type()); 178 179 // The first argument to the handler is the actual exception. 180 fallback.setReference(0, th); 181 182 // We then copy other arguments that need to be passed through to the handler. 183 // Note that we might drop arguments at the end, if needed. Note that 184 // referencesStart == 1 because the first argument is the exception type. 185 emulatedStackFrame.copyRangeTo(fallback, handlerArgsRange, 186 1 /* referencesStart */, 0 /* stackFrameStart */); 187 188 // Perform the invoke and return the appropriate value. 189 handler.invoke(fallback); 190 fallback.copyReturnValueTo(emulatedStackFrame); 191 } else { 192 // The exception is not of the expected type, we throw it. 193 throw th; 194 } 195 } 196 } 197 } 198 199 /** 200 * Implements {@code MethodHandles.GuardWithTest}. 201 */ 202 public static class GuardWithTest extends Transformer { 203 private final MethodHandle test; 204 private final MethodHandle target; 205 private final MethodHandle fallback; 206 207 private final EmulatedStackFrame.Range testArgsRange; 208 209 public GuardWithTest(MethodHandle test, MethodHandle target, MethodHandle fallback) { 210 super(target.type()); 211 212 this.test = test; 213 this.target = target; 214 this.fallback = fallback; 215 216 // The test method might have a subset of the arguments of the handle / target. 217 testArgsRange = EmulatedStackFrame.Range.of(target.type(), 0, test.type().parameterCount()); 218 } 219 220 @Override 221 public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable { 222 EmulatedStackFrame testFrame = EmulatedStackFrame.create(test.type()); 223 emulatedStackFrame.copyRangeTo(testFrame, testArgsRange, 0, 0); 224 225 // We know that the return value for test is going to be boolean.class, so we don't have 226 // to do the copyReturnValue dance. 227 final boolean value = (boolean) test.invoke(testFrame); 228 if (value) { 229 target.invoke(emulatedStackFrame); 230 } else { 231 fallback.invoke(emulatedStackFrame); 232 } 233 } 234 } 235 236 /** 237 * Implementation of MethodHandles.arrayElementGetter for reference types. 238 */ 239 public static class ReferenceArrayElementGetter extends Transformer { 240 private final Class<?> arrayClass; 241 242 public ReferenceArrayElementGetter(Class<?> arrayClass) { 243 super(MethodType.methodType(arrayClass.getComponentType(), 244 new Class<?>[]{arrayClass, int.class})); 245 this.arrayClass = arrayClass; 246 } 247 248 @Override 249 public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable { 250 final StackFrameReader reader = new StackFrameReader(); 251 reader.attach(emulatedStackFrame); 252 253 // Read the array object and the index from the stack frame. 254 final Object[] array = (Object[]) reader.nextReference(arrayClass); 255 final int index = reader.nextInt(); 256 257 // Write the array element back to the stack frame. 258 final StackFrameWriter writer = new StackFrameWriter(); 259 writer.attach(emulatedStackFrame); 260 writer.makeReturnValueAccessor(); 261 writer.putNextReference(array[index], arrayClass.getComponentType()); 262 } 263 } 264 265 /** 266 * Implementation of MethodHandles.arrayElementSetter for reference types. 267 */ 268 public static class ReferenceArrayElementSetter extends Transformer { 269 private final Class<?> arrayClass; 270 271 public ReferenceArrayElementSetter(Class<?> arrayClass) { 272 super(MethodType.methodType(void.class, 273 new Class<?>[] { arrayClass, int.class, arrayClass.getComponentType() })); 274 this.arrayClass = arrayClass; 275 } 276 277 @Override 278 public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable { 279 final StackFrameReader reader = new StackFrameReader(); 280 reader.attach(emulatedStackFrame); 281 282 // Read the array object, index and the value to write from the stack frame. 283 final Object[] array = (Object[]) reader.nextReference(arrayClass); 284 final int index = reader.nextInt(); 285 final Object value = reader.nextReference(arrayClass.getComponentType()); 286 287 array[index] = value; 288 } 289 } 290 291 /** 292 * Implementation of MethodHandles.identity() for reference types. 293 */ 294 public static class ReferenceIdentity extends Transformer { 295 private final Class<?> type; 296 297 public ReferenceIdentity(Class<?> type) { 298 super(MethodType.methodType(type, type)); 299 this.type = type; 300 } 301 302 @Override 303 public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable { 304 final StackFrameReader reader = new StackFrameReader(); 305 reader.attach(emulatedStackFrame); 306 307 final StackFrameWriter writer = new StackFrameWriter(); 308 writer.attach(emulatedStackFrame); 309 writer.makeReturnValueAccessor(); 310 writer.putNextReference(reader.nextReference(type), type); 311 } 312 } 313 314 /** 315 * Implementation of MethodHandles.constant. 316 */ 317 public static class Constant extends Transformer { 318 private final Class<?> type; 319 320 // NOTE: This implementation turned out to be more awkward than expected becuase 321 // of the type system. We could simplify this considerably at the cost of making 322 // the emulated stack frame API uglier or by transitioning into JNI. 323 // 324 // We could consider implementing this in terms of bind() once that's implemented. 325 // This would then just become : MethodHandles.identity(type).bind(value). 326 private int asInt; 327 private long asLong; 328 private float asFloat; 329 private double asDouble; 330 private Object asReference; 331 332 private char typeChar; 333 334 public Constant(Class<?> type, Object value) { 335 super(MethodType.methodType(type)); 336 this.type = type; 337 338 if (!type.isPrimitive()) { 339 asReference = value; 340 typeChar = 'L'; 341 } else if (type == int.class) { 342 asInt = (int) value; 343 typeChar = 'I'; 344 } else if (type == char.class) { 345 asInt = (int) (char) value; 346 typeChar = 'C'; 347 } else if (type == short.class) { 348 asInt = (int) (short) value; 349 typeChar = 'S'; 350 } else if (type == byte.class) { 351 asInt = (int) (byte) value; 352 typeChar = 'B'; 353 } else if (type == boolean.class) { 354 asInt = ((boolean) value) ? 1 : 0; 355 typeChar = 'Z'; 356 } else if (type == long.class) { 357 asLong = (long) value; 358 typeChar = 'J'; 359 } else if (type == float.class) { 360 asFloat = (float) value; 361 typeChar = 'F'; 362 } else if (type == double.class) { 363 asDouble = (double) value; 364 typeChar = 'D'; 365 } else { 366 throw new AssertionError("unknown type: " + typeChar); 367 } 368 } 369 370 @Override 371 public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable { 372 final StackFrameWriter writer = new StackFrameWriter(); 373 writer.attach(emulatedStackFrame); 374 writer.makeReturnValueAccessor(); 375 376 switch (typeChar) { 377 case 'L' : { writer.putNextReference(asReference, type); break; } 378 case 'I' : { writer.putNextInt(asInt); break; } 379 case 'C' : { writer.putNextChar((char) asInt); break; } 380 case 'S' : { writer.putNextShort((short) asInt); break; } 381 case 'B' : { writer.putNextByte((byte) asInt); break; } 382 case 'Z' : { writer.putNextBoolean(asInt == 1); break; } 383 case 'J' : { writer.putNextLong(asLong); break; } 384 case 'F' : { writer.putNextFloat(asFloat); break; } 385 case 'D' : { writer.putNextDouble(asDouble); break; } 386 default: 387 throw new AssertionError("Unexpected typeChar: " + typeChar); 388 } 389 } 390 } 391 392 /*package*/ static class Construct extends Transformer { 393 private final MethodHandle constructorHandle; 394 private final EmulatedStackFrame.Range callerRange; 395 396 /*package*/ Construct(MethodHandle constructorHandle, MethodType returnedType) { 397 super(returnedType); 398 this.constructorHandle = constructorHandle; 399 this.callerRange = EmulatedStackFrame.Range.all(type()); 400 } 401 402 MethodHandle getConstructorHandle() { 403 return constructorHandle; 404 } 405 406 private static boolean isAbstract(Class<?> klass) { 407 return (klass.getModifiers() & Modifier.ABSTRACT) == Modifier.ABSTRACT; 408 } 409 410 private static void checkInstantiable(Class<?> klass) throws InstantiationException { 411 if (isAbstract(klass)) { 412 String s = klass.isInterface() ? "interface " : "abstract class "; 413 throw new InstantiationException("Can't instantiate " + s + klass); 414 } 415 } 416 417 @Override 418 public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable { 419 final Class<?> receiverType = type().rtype(); 420 checkInstantiable(receiverType); 421 422 // Allocate memory for receiver. 423 Object receiver = Unsafe.getUnsafe().allocateInstance(receiverType); 424 425 // The MethodHandle type for the caller has the form of 426 // {rtype=T,ptypes=A1..An}. The constructor MethodHandle is of 427 // the form {rtype=void,ptypes=T,A1...An}. So the frame for 428 // the constructor needs to have a slot with the receiver 429 // in position 0. 430 EmulatedStackFrame constructorFrame = 431 EmulatedStackFrame.create(constructorHandle.type()); 432 constructorFrame.setReference(0, receiver); 433 emulatedStackFrame.copyRangeTo(constructorFrame, callerRange, 1, 0); 434 constructorHandle.invoke(constructorFrame); 435 436 // Set return result for caller. 437 emulatedStackFrame.setReturnValueTo(receiver); 438 } 439 } 440 441 /** 442 * Implements MethodHandle.bindTo. 443 * 444 * @hide 445 */ 446 public static class BindTo extends Transformer { 447 private final MethodHandle delegate; 448 private final Object receiver; 449 450 private final EmulatedStackFrame.Range range; 451 452 public BindTo(MethodHandle delegate, Object receiver) { 453 super(delegate.type().dropParameterTypes(0, 1)); 454 455 this.delegate = delegate; 456 this.receiver = receiver; 457 458 this.range = EmulatedStackFrame.Range.all(this.type()); 459 } 460 461 @Override 462 public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable { 463 // Create a new emulated stack frame with the full type (including the leading 464 // receiver reference). 465 EmulatedStackFrame stackFrame = EmulatedStackFrame.create(delegate.type()); 466 467 // The first reference argument must be the receiver. 468 stackFrame.setReference(0, receiver); 469 // Copy all other arguments. 470 emulatedStackFrame.copyRangeTo(stackFrame, range, 471 1 /* referencesStart */, 0 /* stackFrameStart */); 472 473 // Perform the invoke. 474 delegate.invoke(stackFrame); 475 stackFrame.copyReturnValueTo(emulatedStackFrame); 476 } 477 } 478 479 /** 480 * Implements MethodHandle.filterReturnValue. 481 */ 482 public static class FilterReturnValue extends Transformer { 483 private final MethodHandle target; 484 private final MethodHandle filter; 485 486 private final EmulatedStackFrame.Range allArgs; 487 488 public FilterReturnValue(MethodHandle target, MethodHandle filter) { 489 super(MethodType.methodType(filter.type().rtype(), target.type().ptypes())); 490 491 this.target = target; 492 this.filter = filter; 493 494 allArgs = EmulatedStackFrame.Range.all(type()); 495 } 496 497 @Override 498 public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable { 499 // Create a new frame with the target's type and copy all arguments over. 500 // This frame differs in return type with |emulatedStackFrame| but will have 501 // the same parameter shapes. 502 EmulatedStackFrame targetFrame = EmulatedStackFrame.create(target.type()); 503 emulatedStackFrame.copyRangeTo(targetFrame, allArgs, 0, 0); 504 target.invoke(targetFrame); 505 506 // Perform the invoke. 507 final StackFrameReader returnValueReader = new StackFrameReader(); 508 returnValueReader.attach(targetFrame); 509 returnValueReader.makeReturnValueAccessor(); 510 511 // Create an emulated frame for the filter and copy all its arguments across. 512 EmulatedStackFrame filterFrame = EmulatedStackFrame.create(filter.type()); 513 final StackFrameWriter filterWriter = new StackFrameWriter(); 514 filterWriter.attach(filterFrame); 515 516 final Class<?> returnType = target.type().rtype(); 517 if (!returnType.isPrimitive()) { 518 filterWriter.putNextReference(returnValueReader.nextReference(returnType), 519 returnType); 520 } else if (returnType == boolean.class) { 521 filterWriter.putNextBoolean(returnValueReader.nextBoolean()); 522 } else if (returnType == byte.class) { 523 filterWriter.putNextByte(returnValueReader.nextByte()); 524 } else if (returnType == char.class) { 525 filterWriter.putNextChar(returnValueReader.nextChar()); 526 } else if (returnType == short.class) { 527 filterWriter.putNextShort(returnValueReader.nextShort()); 528 } else if (returnType == int.class) { 529 filterWriter.putNextInt(returnValueReader.nextInt()); 530 } else if (returnType == long.class) { 531 filterWriter.putNextLong(returnValueReader.nextLong()); 532 } else if (returnType == float.class) { 533 filterWriter.putNextFloat(returnValueReader.nextFloat()); 534 } else if (returnType == double.class) { 535 filterWriter.putNextDouble(returnValueReader.nextDouble()); 536 } 537 538 // Invoke the filter and copy its return value back to the original frame. 539 filter.invoke(filterFrame); 540 filterFrame.copyReturnValueTo(emulatedStackFrame); 541 } 542 } 543 544 /* 545 * Implements MethodHandles.permuteArguments. 546 * 547 * @hide 548 */ 549 public static class PermuteArguments extends Transformer { 550 private final MethodHandle target; 551 private final int[] reorder; 552 553 public PermuteArguments(MethodType type, MethodHandle target, int[] reorder) { 554 super(type); 555 556 this.target = target; 557 this.reorder = reorder; 558 } 559 560 @Override 561 public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable { 562 final StackFrameReader reader = new StackFrameReader(); 563 reader.attach(emulatedStackFrame); 564 565 // In the interests of simplicity, we box / unbox arguments while performing 566 // the permutation. We first iterate through the incoming stack frame and box 567 // each argument. We then unbox and write out the argument to the target frame 568 // according to the specified reordering. 569 Object[] arguments = new Object[reorder.length]; 570 final Class<?>[] ptypes = type().ptypes(); 571 for (int i = 0; i < ptypes.length; ++i) { 572 final Class<?> ptype = ptypes[i]; 573 if (!ptype.isPrimitive()) { 574 arguments[i] = reader.nextReference(ptype); 575 } else if (ptype == boolean.class) { 576 arguments[i] = reader.nextBoolean(); 577 } else if (ptype == byte.class) { 578 arguments[i] = reader.nextByte(); 579 } else if (ptype == char.class) { 580 arguments[i] = reader.nextChar(); 581 } else if (ptype == short.class) { 582 arguments[i] = reader.nextShort(); 583 } else if (ptype == int.class) { 584 arguments[i] = reader.nextInt(); 585 } else if (ptype == long.class) { 586 arguments[i] = reader.nextLong(); 587 } else if (ptype == float.class) { 588 arguments[i] = reader.nextFloat(); 589 } else if (ptype == double.class) { 590 arguments[i] = reader.nextDouble(); 591 } else { 592 throw new AssertionError("Unexpected type: " + ptype); 593 } 594 } 595 596 EmulatedStackFrame calleeFrame = EmulatedStackFrame.create(target.type()); 597 final StackFrameWriter writer = new StackFrameWriter(); 598 writer.attach(calleeFrame); 599 600 for (int i = 0; i < ptypes.length; ++i) { 601 int idx = reorder[i]; 602 final Class<?> ptype = ptypes[idx]; 603 final Object argument = arguments[idx]; 604 605 if (!ptype.isPrimitive()) { 606 writer.putNextReference(argument, ptype); 607 } else if (ptype == boolean.class) { 608 writer.putNextBoolean((boolean) argument); 609 } else if (ptype == byte.class) { 610 writer.putNextByte((byte) argument); 611 } else if (ptype == char.class) { 612 writer.putNextChar((char) argument); 613 } else if (ptype == short.class) { 614 writer.putNextShort((short) argument); 615 } else if (ptype == int.class) { 616 writer.putNextInt((int) argument); 617 } else if (ptype == long.class) { 618 writer.putNextLong((long) argument); 619 } else if (ptype == float.class) { 620 writer.putNextFloat((float) argument); 621 } else if (ptype == double.class) { 622 writer.putNextDouble((double) argument); 623 } else { 624 throw new AssertionError("Unexpected type: " + ptype); 625 } 626 } 627 628 target.invoke(calleeFrame); 629 calleeFrame.copyReturnValueTo(emulatedStackFrame); 630 } 631 } 632 633 /** 634 * Converts methods with a trailing array argument to variable arity 635 * methods. So (A,B,C[])R can be invoked with any number of convertible 636 * arguments after B, e.g. (A,B)R or (A, B, C0)R or (A, B, C0...Cn)R. 637 * 638 * @hide 639 */ 640 /*package*/ static class VarargsCollector extends Transformer { 641 final MethodHandle target; 642 643 /*package*/ VarargsCollector(MethodHandle target) { 644 super(target.type(), MethodHandle.INVOKE_CALLSITE_TRANSFORM); 645 if (!lastParameterTypeIsAnArray(target.type().ptypes())) { 646 throw new IllegalArgumentException("target does not have array as last parameter"); 647 } 648 this.target = target; 649 } 650 651 private static boolean lastParameterTypeIsAnArray(Class<?>[] parameterTypes) { 652 if (parameterTypes.length == 0) return false; 653 return parameterTypes[parameterTypes.length - 1].isArray(); 654 } 655 656 @Override 657 public boolean isVarargsCollector() { return true; } 658 659 @Override 660 public MethodHandle asFixedArity() { return target; } 661 662 @Override 663 public void transform(EmulatedStackFrame callerFrame) throws Throwable { 664 MethodType callerFrameType = callerFrame.getMethodType(); 665 Class<?>[] callerPTypes = callerFrameType.ptypes(); 666 Class<?>[] targetPTypes = type().ptypes(); 667 668 int lastTargetIndex = targetPTypes.length - 1; 669 if (callerPTypes.length == targetPTypes.length && 670 targetPTypes[lastTargetIndex].isAssignableFrom(callerPTypes[lastTargetIndex])) { 671 // Caller frame matches target frame in the arity array parameter. Invoke 672 // immediately, and let the invoke() dispatch perform any necessary conversions 673 // on the other parameters present. 674 target.invoke(callerFrame); 675 return; 676 } 677 678 if (callerPTypes.length < targetPTypes.length - 1) { 679 // Too few arguments to be compatible with variable arity invocation. 680 throwWrongMethodTypeException(callerFrameType, type()); 681 } 682 683 if (!MethodType.canConvert(type().rtype(), callerFrameType.rtype())) { 684 // Incompatible return type. 685 throwWrongMethodTypeException(callerFrameType, type()); 686 } 687 688 Class<?> elementType = targetPTypes[lastTargetIndex].getComponentType(); 689 if (!arityArgumentsConvertible(callerPTypes, lastTargetIndex, elementType)) { 690 // Wrong types to be compatible with variable arity invocation. 691 throwWrongMethodTypeException(callerFrameType, type()); 692 } 693 694 // Allocate targetFrame. 695 MethodType targetFrameType = makeTargetFrameType(callerFrameType, type()); 696 EmulatedStackFrame targetFrame = EmulatedStackFrame.create(targetFrameType); 697 prepareFrame(callerFrame, targetFrame); 698 699 // Invoke target. 700 target.invoke(targetFrame); 701 702 // Copy return value to the caller's frame. 703 targetFrame.copyReturnValueTo(callerFrame); 704 } 705 706 private static void throwWrongMethodTypeException(MethodType from, MethodType to) { 707 throw new WrongMethodTypeException("Cannot convert " + from + " to " + to); 708 } 709 710 private static boolean arityArgumentsConvertible(Class<?>[] ptypes, int arityStart, 711 Class<?> elementType) { 712 if (ptypes.length - 1 == arityStart) { 713 if (ptypes[arityStart].isArray() && 714 ptypes[arityStart].getComponentType() == elementType) { 715 // The last ptype is in the same position as the arity 716 // array and has the same type. 717 return true; 718 } 719 } 720 721 for (int i = arityStart; i < ptypes.length; ++i) { 722 if (!MethodType.canConvert(ptypes[i], elementType)) { 723 return false; 724 } 725 } 726 return true; 727 } 728 729 private static Object referenceArray(StackFrameReader reader, Class<?>[] ptypes, 730 Class<?> elementType, int offset, int length) { 731 Object arityArray = Array.newInstance(elementType, length); 732 for (int i = 0; i < length; ++i) { 733 Class<?> argumentType = ptypes[i + offset]; 734 Object o = null; 735 switch (Wrapper.basicTypeChar(argumentType)) { 736 case 'L': { o = reader.nextReference(argumentType); break; } 737 case 'I': { o = reader.nextInt(); break; } 738 case 'J': { o = reader.nextLong(); break; } 739 case 'B': { o = reader.nextByte(); break; } 740 case 'S': { o = reader.nextShort(); break; } 741 case 'C': { o = reader.nextChar(); break; } 742 case 'Z': { o = reader.nextBoolean(); break; } 743 case 'F': { o = reader.nextFloat(); break; } 744 case 'D': { o = reader.nextDouble(); break; } 745 } 746 Array.set(arityArray, i, elementType.cast(o)); 747 } 748 return arityArray; 749 } 750 751 private static Object intArray(StackFrameReader reader, Class<?> ptypes[], 752 int offset, int length) { 753 int[] arityArray = new int[length]; 754 for (int i = 0; i < length; ++i) { 755 Class<?> argumentType = ptypes[i + offset]; 756 switch (Wrapper.basicTypeChar(argumentType)) { 757 case 'I': { arityArray[i] = reader.nextInt(); break; } 758 case 'S': { arityArray[i] = reader.nextShort(); break; } 759 case 'B': { arityArray[i] = reader.nextByte(); break; } 760 default: { 761 arityArray[i] = (Integer) reader.nextReference(argumentType); 762 break; 763 } 764 } 765 } 766 return arityArray; 767 } 768 769 private static Object longArray(StackFrameReader reader, Class<?> ptypes[], 770 int offset, int length) { 771 long[] arityArray = new long[length]; 772 for (int i = 0; i < length; ++i) { 773 Class<?> argumentType = ptypes[i + offset]; 774 switch (Wrapper.basicTypeChar(argumentType)) { 775 case 'J': { arityArray[i] = reader.nextLong(); break; } 776 case 'I': { arityArray[i] = reader.nextInt(); break; } 777 case 'S': { arityArray[i] = reader.nextShort(); break; } 778 case 'B': { arityArray[i] = reader.nextByte(); break; } 779 default: { arityArray[i] = (Long) reader.nextReference(argumentType); break; } 780 } 781 } 782 return arityArray; 783 } 784 785 private static Object byteArray(StackFrameReader reader, Class<?> ptypes[], 786 int offset, int length) { 787 byte[] arityArray = new byte[length]; 788 for (int i = 0; i < length; ++i) { 789 Class<?> argumentType = ptypes[i + offset]; 790 switch (Wrapper.basicTypeChar(argumentType)) { 791 case 'B': { arityArray[i] = reader.nextByte(); break; } 792 default: { arityArray[i] = (Byte) reader.nextReference(argumentType); break; } 793 } 794 } 795 return arityArray; 796 } 797 798 private static Object shortArray(StackFrameReader reader, Class<?> ptypes[], 799 int offset, int length) { 800 short[] arityArray = new short[length]; 801 for (int i = 0; i < length; ++i) { 802 Class<?> argumentType = ptypes[i + offset]; 803 switch (Wrapper.basicTypeChar(argumentType)) { 804 case 'S': { arityArray[i] = reader.nextShort(); break; } 805 case 'B': { arityArray[i] = reader.nextByte(); break; } 806 default: { arityArray[i] = (Short) reader.nextReference(argumentType); break; } 807 } 808 } 809 return arityArray; 810 } 811 812 private static Object charArray(StackFrameReader reader, Class<?> ptypes[], 813 int offset, int length) { 814 char[] arityArray = new char[length]; 815 for (int i = 0; i < length; ++i) { 816 Class<?> argumentType = ptypes[i + offset]; 817 switch (Wrapper.basicTypeChar(argumentType)) { 818 case 'C': { arityArray[i] = reader.nextChar(); break; } 819 default: { 820 arityArray[i] = (Character) reader.nextReference(argumentType); 821 break; 822 } 823 } 824 } 825 return arityArray; 826 } 827 828 private static Object booleanArray(StackFrameReader reader, Class<?> ptypes[], 829 int offset, int length) { 830 boolean[] arityArray = new boolean[length]; 831 for (int i = 0; i < length; ++i) { 832 Class<?> argumentType = ptypes[i + offset]; 833 switch (Wrapper.basicTypeChar(argumentType)) { 834 case 'Z': { arityArray[i] = reader.nextBoolean(); break; } 835 default: 836 arityArray[i] = (Boolean) reader.nextReference(argumentType); 837 break; 838 } 839 } 840 return arityArray; 841 } 842 843 private static Object floatArray(StackFrameReader reader, Class<?> ptypes[], 844 int offset, int length) { 845 float[] arityArray = new float[length]; 846 for (int i = 0; i < length; ++i) { 847 Class<?> argumentType = ptypes[i + offset]; 848 switch (Wrapper.basicTypeChar(argumentType)) { 849 case 'F': { arityArray[i] = reader.nextFloat(); break; } 850 case 'J': { arityArray[i] = reader.nextLong(); break; } 851 case 'I': { arityArray[i] = reader.nextInt(); break; } 852 case 'S': { arityArray[i] = reader.nextShort(); break; } 853 case 'B': { arityArray[i] = reader.nextByte(); break; } 854 default: { 855 arityArray[i] = (Float) reader.nextReference(argumentType); 856 break; 857 } 858 } 859 } 860 return arityArray; 861 } 862 863 private static Object doubleArray(StackFrameReader reader, Class<?> ptypes[], 864 int offset, int length) { 865 double[] arityArray = new double[length]; 866 for (int i = 0; i < length; ++i) { 867 Class<?> argumentType = ptypes[i + offset]; 868 switch (Wrapper.basicTypeChar(argumentType)) { 869 case 'D': { arityArray[i] = reader.nextDouble(); break; } 870 case 'F': { arityArray[i] = reader.nextFloat(); break; } 871 case 'J': { arityArray[i] = reader.nextLong(); break; } 872 case 'I': { arityArray[i] = reader.nextInt(); break; } 873 case 'S': { arityArray[i] = reader.nextShort(); break; } 874 case 'B': { arityArray[i] = reader.nextByte(); break; } 875 default: { 876 arityArray[i] = (Double) reader.nextReference(argumentType); 877 break; 878 } 879 } 880 } 881 return arityArray; 882 } 883 884 private static Object makeArityArray(MethodType callerFrameType, 885 StackFrameReader callerFrameReader, 886 int indexOfArityArray, 887 Class<?> arityArrayType) { 888 int arityArrayLength = callerFrameType.ptypes().length - indexOfArityArray; 889 Class<?> elementType = arityArrayType.getComponentType(); 890 Class<?>[] callerPTypes = callerFrameType.ptypes(); 891 892 char elementBasicType = Wrapper.basicTypeChar(elementType); 893 switch (elementBasicType) { 894 case 'L': return referenceArray(callerFrameReader, callerPTypes, elementType, 895 indexOfArityArray, arityArrayLength); 896 case 'I': return intArray(callerFrameReader, callerPTypes, 897 indexOfArityArray, arityArrayLength); 898 case 'J': return longArray(callerFrameReader, callerPTypes, 899 indexOfArityArray, arityArrayLength); 900 case 'B': return byteArray(callerFrameReader, callerPTypes, 901 indexOfArityArray, arityArrayLength); 902 case 'S': return shortArray(callerFrameReader, callerPTypes, 903 indexOfArityArray, arityArrayLength); 904 case 'C': return charArray(callerFrameReader, callerPTypes, 905 indexOfArityArray, arityArrayLength); 906 case 'Z': return booleanArray(callerFrameReader, callerPTypes, 907 indexOfArityArray, arityArrayLength); 908 case 'F': return floatArray(callerFrameReader, callerPTypes, 909 indexOfArityArray, arityArrayLength); 910 case 'D': return doubleArray(callerFrameReader, callerPTypes, 911 indexOfArityArray, arityArrayLength); 912 } 913 throw new InternalError("Unexpected type: " + elementType); 914 } 915 916 public static Object collectArguments(char basicComponentType, Class<?> componentType, 917 StackFrameReader reader, Class<?>[] types, 918 int startIdx, int length) { 919 switch (basicComponentType) { 920 case 'L': return referenceArray(reader, types, componentType, startIdx, length); 921 case 'I': return intArray(reader, types, startIdx, length); 922 case 'J': return longArray(reader, types, startIdx, length); 923 case 'B': return byteArray(reader, types, startIdx, length); 924 case 'S': return shortArray(reader, types, startIdx, length); 925 case 'C': return charArray(reader, types, startIdx, length); 926 case 'Z': return booleanArray(reader, types, startIdx, length); 927 case 'F': return floatArray(reader, types, startIdx, length); 928 case 'D': return doubleArray(reader, types, startIdx, length); 929 } 930 throw new InternalError("Unexpected type: " + basicComponentType); 931 } 932 933 private static void copyParameter(StackFrameReader reader, StackFrameWriter writer, 934 Class<?> ptype) { 935 switch (Wrapper.basicTypeChar(ptype)) { 936 case 'L': { writer.putNextReference(reader.nextReference(ptype), ptype); break; } 937 case 'I': { writer.putNextInt(reader.nextInt()); break; } 938 case 'J': { writer.putNextLong(reader.nextLong()); break; } 939 case 'B': { writer.putNextByte(reader.nextByte()); break; } 940 case 'S': { writer.putNextShort(reader.nextShort()); break; } 941 case 'C': { writer.putNextChar(reader.nextChar()); break; } 942 case 'Z': { writer.putNextBoolean(reader.nextBoolean()); break; } 943 case 'F': { writer.putNextFloat(reader.nextFloat()); break; } 944 case 'D': { writer.putNextDouble(reader.nextDouble()); break; } 945 default: throw new InternalError("Unexpected type: " + ptype); 946 } 947 } 948 949 private static void prepareFrame(EmulatedStackFrame callerFrame, 950 EmulatedStackFrame targetFrame) { 951 StackFrameWriter targetWriter = new StackFrameWriter(); 952 targetWriter.attach(targetFrame); 953 StackFrameReader callerReader = new StackFrameReader(); 954 callerReader.attach(callerFrame); 955 956 // Copy parameters from |callerFrame| to |targetFrame| leaving room for arity array. 957 MethodType targetMethodType = targetFrame.getMethodType(); 958 int indexOfArityArray = targetMethodType.ptypes().length - 1; 959 for (int i = 0; i < indexOfArityArray; ++i) { 960 Class<?> ptype = targetMethodType.ptypes()[i]; 961 copyParameter(callerReader, targetWriter, ptype); 962 } 963 964 // Add arity array as last parameter in |targetFrame|. 965 Class<?> arityArrayType = targetMethodType.ptypes()[indexOfArityArray]; 966 Object arityArray = makeArityArray(callerFrame.getMethodType(), callerReader, 967 indexOfArityArray, arityArrayType); 968 targetWriter.putNextReference(arityArray, arityArrayType); 969 } 970 971 /** 972 * Computes the frame type to invoke the target method handle with. This 973 * is the same as the caller frame type, but with the trailing argument 974 * being the array type that is the trailing argument in the target method 975 * handle. 976 * 977 * Suppose the targetType is (T0, T1, T2[])RT and the callerType is (C0, C1, C2, C3)RC 978 * then the constructed type is (C0, C1, T2[])RC. 979 */ 980 private static MethodType makeTargetFrameType(MethodType callerType, 981 MethodType targetType) { 982 final int ptypesLength = targetType.ptypes().length; 983 final Class<?>[] ptypes = new Class<?>[ptypesLength]; 984 // Copy types from caller types to new methodType. 985 System.arraycopy(callerType.ptypes(), 0, ptypes, 0, ptypesLength - 1); 986 // Set the last element in the type array to be the 987 // varargs array of the target. 988 ptypes[ptypesLength - 1] = targetType.ptypes()[ptypesLength - 1]; 989 return MethodType.methodType(callerType.rtype(), ptypes); 990 } 991 } 992 993 /** 994 * Implements MethodHandles.invoker & MethodHandles.exactInvoker. 995 */ 996 static class Invoker extends Transformer { 997 private final MethodType targetType; 998 private final boolean isExactInvoker; 999 private final EmulatedStackFrame.Range copyRange; 1000 1001 Invoker(MethodType targetType, boolean isExactInvoker) { 1002 super(targetType.insertParameterTypes(0, MethodHandle.class)); 1003 this.targetType = targetType; 1004 this.isExactInvoker = isExactInvoker; 1005 copyRange = EmulatedStackFrame.Range.of(type(), 1, type().parameterCount()); 1006 } 1007 1008 @Override 1009 public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable { 1010 // We need to artifically throw a WrongMethodTypeException here because we 1011 // can't call invokeExact on the target inside the transformer. 1012 if (isExactInvoker) { 1013 // TODO: We should do the comparison by hand if this new type creation 1014 // on every invoke proves too expensive. 1015 MethodType callType = emulatedStackFrame.getCallsiteType().dropParameterTypes(0, 1); 1016 if (!targetType.equals(callType)) { 1017 throw new WrongMethodTypeException("Wrong type, Expected: " + targetType 1018 + " was: " + callType); 1019 } 1020 } 1021 1022 // The first argument to the stack frame is the handle that needs to be invoked. 1023 MethodHandle target = emulatedStackFrame.getReference(0, MethodHandle.class); 1024 1025 // All other arguments must be copied to the target frame. 1026 EmulatedStackFrame targetFrame = EmulatedStackFrame.create(targetType); 1027 emulatedStackFrame.copyRangeTo(targetFrame, copyRange, 0, 0); 1028 1029 // Finally, invoke the handle and copy the return value. 1030 target.invoke(targetFrame); 1031 targetFrame.copyReturnValueTo(emulatedStackFrame); 1032 } 1033 } 1034 1035 /** 1036 * Implements MethodHandle.asSpreader / MethodHandles.spreadInvoker. 1037 */ 1038 static class Spreader extends Transformer { 1039 /** The method handle we're delegating to. */ 1040 private final MethodHandle target; 1041 1042 /** 1043 * The offset of the trailing array argument in the list of arguments to 1044 * this transformer. The array argument is always the last argument. 1045 */ 1046 private final int arrayOffset; 1047 1048 /** 1049 * The type char of the component type of the array. 1050 */ 1051 private final char arrayTypeChar; 1052 1053 /** 1054 * The number of input arguments that will be present in the array. In other words, 1055 * this is the expected array length. 1056 */ 1057 private final int numArrayArgs; 1058 1059 /** 1060 * Range of arguments to copy verbatim from the input frame, This will cover all 1061 * arguments that aren't a part of the trailing array. 1062 */ 1063 private final Range copyRange; 1064 1065 Spreader(MethodHandle target, MethodType spreaderType, int numArrayArgs) { 1066 super(spreaderType); 1067 this.target = target; 1068 // Copy all arguments except the last argument (which is the trailing array argument 1069 // that needs to be spread). 1070 arrayOffset = spreaderType.parameterCount() - 1; 1071 1072 // Get and cache the component type of the input array. 1073 final Class<?> componentType = spreaderType.ptypes()[arrayOffset].getComponentType(); 1074 if (componentType == null) { 1075 throw new AssertionError("Trailing argument must be an array."); 1076 } 1077 arrayTypeChar = Wrapper.basicTypeChar(componentType); 1078 1079 this.numArrayArgs = numArrayArgs; 1080 // Copy all args except for the last argument. 1081 this.copyRange = EmulatedStackFrame.Range.of(spreaderType, 0, arrayOffset); 1082 } 1083 1084 @Override 1085 public void transform(EmulatedStackFrame callerFrame) throws Throwable { 1086 // Create a new stack frame for the callee. 1087 EmulatedStackFrame targetFrame = EmulatedStackFrame.create(target.type()); 1088 1089 // Copy all arguments except for the trailing array argument. 1090 callerFrame.copyRangeTo(targetFrame, copyRange, 0, 0); 1091 1092 // Attach the writer, prepare to spread the trailing array arguments into 1093 // the callee frame. 1094 StackFrameWriter writer = new StackFrameWriter(); 1095 writer.attach(targetFrame, 1096 arrayOffset, 1097 copyRange.numReferences, 1098 copyRange.numBytes); 1099 1100 // Get the array reference and check that its length is as expected. 1101 Object arrayObj = callerFrame.getReference( 1102 copyRange.numReferences, this.type().ptypes()[arrayOffset]); 1103 final int arrayLength = Array.getLength(arrayObj); 1104 if (arrayLength != numArrayArgs) { 1105 throw new IllegalArgumentException("Invalid array length: " + arrayLength); 1106 } 1107 1108 final MethodType type = target.type(); 1109 switch (arrayTypeChar) { 1110 case 'L': 1111 spreadArray((Object[]) arrayObj, writer, type, numArrayArgs, arrayOffset); 1112 break; 1113 case 'I': 1114 spreadArray((int[]) arrayObj, writer, type, numArrayArgs, arrayOffset); 1115 break; 1116 case 'J': 1117 spreadArray((long[]) arrayObj, writer, type, numArrayArgs, arrayOffset); 1118 break; 1119 case 'B': 1120 spreadArray((byte[]) arrayObj, writer, type, numArrayArgs, arrayOffset); 1121 break; 1122 case 'S': 1123 spreadArray((short[]) arrayObj, writer, type, numArrayArgs, arrayOffset); 1124 break; 1125 case 'C': 1126 spreadArray((char[]) arrayObj, writer, type, numArrayArgs, arrayOffset); 1127 break; 1128 case 'Z': 1129 spreadArray((boolean[]) arrayObj, writer, type, numArrayArgs, arrayOffset); 1130 break; 1131 case 'F': 1132 spreadArray((float[]) arrayObj, writer, type, numArrayArgs, arrayOffset); 1133 break; 1134 case 'D': 1135 spreadArray((double[]) arrayObj, writer, type, numArrayArgs, arrayOffset); 1136 break; 1137 1138 } 1139 1140 target.invoke(targetFrame); 1141 targetFrame.copyReturnValueTo(callerFrame); 1142 } 1143 1144 public static void spreadArray(Object[] array, StackFrameWriter writer, MethodType type, 1145 int numArgs, int offset) { 1146 final Class<?>[] ptypes = type.ptypes(); 1147 for (int i = 0; i < numArgs; ++i) { 1148 Class<?> argumentType = ptypes[i + offset]; 1149 Object o = array[i]; 1150 switch (Wrapper.basicTypeChar(argumentType)) { 1151 case 'L': { writer.putNextReference(o, argumentType); break; } 1152 case 'I': { writer.putNextInt((int) o); break; } 1153 case 'J': { writer.putNextLong((long) o); break; } 1154 case 'B': { writer.putNextByte((byte) o); break; } 1155 case 'S': { writer.putNextShort((short) o); break; } 1156 case 'C': { writer.putNextChar((char) o); break; } 1157 case 'Z': { writer.putNextBoolean((boolean) o); break; } 1158 case 'F': { writer.putNextFloat((float) o); break; } 1159 case 'D': { writer.putNextDouble((double) o); break; } 1160 } 1161 } 1162 } 1163 1164 public static void spreadArray(int[] array, StackFrameWriter writer, MethodType type, 1165 int numArgs, int offset) { 1166 final Class<?>[] ptypes = type.ptypes(); 1167 for (int i = 0; i < numArgs; ++i) { 1168 Class<?> argumentType = ptypes[i + offset]; 1169 int j = array[i]; 1170 switch (Wrapper.basicTypeChar(argumentType)) { 1171 case 'L': { writer.putNextReference(j, argumentType); break; } 1172 case 'I': { writer.putNextInt(j); break; } 1173 case 'J': { writer.putNextLong(j); break; } 1174 case 'F': { writer.putNextFloat(j); break; } 1175 case 'D': { writer.putNextDouble(j); break; } 1176 default : { throw new AssertionError(); } 1177 } 1178 } 1179 } 1180 1181 public static void spreadArray(long[] array, StackFrameWriter writer, MethodType type, 1182 int numArgs, int offset) { 1183 final Class<?>[] ptypes = type.ptypes(); 1184 for (int i = 0; i < numArgs; ++i) { 1185 Class<?> argumentType = ptypes[i + offset]; 1186 long l = array[i]; 1187 switch (Wrapper.basicTypeChar(argumentType)) { 1188 case 'L': { writer.putNextReference(l, argumentType); break; } 1189 case 'J': { writer.putNextLong(l); break; } 1190 case 'F': { writer.putNextFloat((float) l); break; } 1191 case 'D': { writer.putNextDouble((double) l); break; } 1192 default : { throw new AssertionError(); } 1193 } 1194 } 1195 } 1196 1197 public static void spreadArray(byte[] array, 1198 StackFrameWriter writer, MethodType type, 1199 int numArgs, int offset) { 1200 final Class<?>[] ptypes = type.ptypes(); 1201 for (int i = 0; i < numArgs; ++i) { 1202 Class<?> argumentType = ptypes[i + offset]; 1203 byte b = array[i]; 1204 switch (Wrapper.basicTypeChar(argumentType)) { 1205 case 'L': { writer.putNextReference(b, argumentType); break; } 1206 case 'I': { writer.putNextInt(b); break; } 1207 case 'J': { writer.putNextLong(b); break; } 1208 case 'B': { writer.putNextByte(b); break; } 1209 case 'S': { writer.putNextShort(b); break; } 1210 case 'F': { writer.putNextFloat(b); break; } 1211 case 'D': { writer.putNextDouble(b); break; } 1212 default : { throw new AssertionError(); } 1213 } 1214 } 1215 } 1216 1217 public static void spreadArray(short[] array, 1218 StackFrameWriter writer, MethodType type, 1219 int numArgs, int offset) { 1220 final Class<?>[] ptypes = type.ptypes(); 1221 for (int i = 0; i < numArgs; ++i) { 1222 Class<?> argumentType = ptypes[i + offset]; 1223 short s = array[i]; 1224 switch (Wrapper.basicTypeChar(argumentType)) { 1225 case 'L': { writer.putNextReference(s, argumentType); break; } 1226 case 'I': { writer.putNextInt(s); break; } 1227 case 'J': { writer.putNextLong(s); break; } 1228 case 'S': { writer.putNextShort(s); break; } 1229 case 'F': { writer.putNextFloat(s); break; } 1230 case 'D': { writer.putNextDouble(s); break; } 1231 default : { throw new AssertionError(); } 1232 } 1233 } 1234 } 1235 1236 public static void spreadArray(char[] array, 1237 StackFrameWriter writer, MethodType type, 1238 int numArgs, int offset) { 1239 final Class<?>[] ptypes = type.ptypes(); 1240 for (int i = 0; i < numArgs; ++i) { 1241 Class<?> argumentType = ptypes[i + offset]; 1242 char c = array[i]; 1243 switch (Wrapper.basicTypeChar(argumentType)) { 1244 case 'L': { writer.putNextReference(c, argumentType); break; } 1245 case 'I': { writer.putNextInt(c); break; } 1246 case 'J': { writer.putNextLong(c); break; } 1247 case 'C': { writer.putNextChar(c); break; } 1248 case 'F': { writer.putNextFloat(c); break; } 1249 case 'D': { writer.putNextDouble(c); break; } 1250 default : { throw new AssertionError(); } 1251 } 1252 } 1253 } 1254 1255 public static void spreadArray(boolean[] array, 1256 StackFrameWriter writer, MethodType type, 1257 int numArgs, int offset) { 1258 final Class<?>[] ptypes = type.ptypes(); 1259 for (int i = 0; i < numArgs; ++i) { 1260 Class<?> argumentType = ptypes[i + offset]; 1261 boolean z = array[i]; 1262 switch (Wrapper.basicTypeChar(argumentType)) { 1263 case 'L': { writer.putNextReference(z, argumentType); break; } 1264 case 'Z': { writer.putNextBoolean(z); break; } 1265 default : { throw new AssertionError(); } 1266 } 1267 } 1268 } 1269 1270 public static void spreadArray(double[] array, 1271 StackFrameWriter writer, MethodType type, 1272 int numArgs, int offset) { 1273 final Class<?>[] ptypes = type.ptypes(); 1274 for (int i = 0; i < numArgs; ++i) { 1275 Class<?> argumentType = ptypes[i + offset]; 1276 double d = array[i]; 1277 switch (Wrapper.basicTypeChar(argumentType)) { 1278 case 'L': { writer.putNextReference(d, argumentType); break; } 1279 case 'D': { writer.putNextDouble(d); break; } 1280 default : { throw new AssertionError(); } 1281 } 1282 } 1283 } 1284 1285 public static void spreadArray(float[] array, StackFrameWriter writer, MethodType type, 1286 int numArgs, int offset) { 1287 final Class<?>[] ptypes = type.ptypes(); 1288 for (int i = 0; i < numArgs; ++i) { 1289 Class<?> argumentType = ptypes[i + offset]; 1290 float f = array[i]; 1291 switch (Wrapper.basicTypeChar(argumentType)) { 1292 case 'L': { writer.putNextReference(f, argumentType); break; } 1293 case 'D': { writer.putNextDouble((double) f); break; } 1294 case 'F': { writer.putNextFloat(f); break; } 1295 default : { throw new AssertionError(); } 1296 } 1297 } 1298 } 1299 } 1300 1301 /** 1302 * Implements MethodHandle.asCollector. 1303 */ 1304 static class Collector extends Transformer { 1305 private final MethodHandle target; 1306 1307 /** 1308 * The offset of the trailing array argument in the list of arguments to 1309 * this transformer. The array argument is always the last argument. 1310 */ 1311 private final int arrayOffset; 1312 1313 /** 1314 * The number of input arguments that will be present in the array. In other words, 1315 * this is the expected array length. 1316 */ 1317 private final int numArrayArgs; 1318 1319 /** 1320 * The type char of the component type of the array. 1321 */ 1322 private final char arrayTypeChar; 1323 1324 /** 1325 * Range of arguments to copy verbatim from the input frame, This will cover all 1326 * arguments that aren't a part of the trailing array. 1327 */ 1328 private final Range copyRange; 1329 1330 Collector(MethodHandle delegate, Class<?> arrayType, int length) { 1331 super(delegate.type().asCollectorType(arrayType, length)); 1332 1333 target = delegate; 1334 // Copy all arguments except the last argument (which is the trailing array argument 1335 // that needs to be spread). 1336 arrayOffset = delegate.type().parameterCount() - 1; 1337 arrayTypeChar = Wrapper.basicTypeChar(arrayType.getComponentType()); 1338 numArrayArgs = length; 1339 1340 // Copy all args except for the last argument. 1341 copyRange = EmulatedStackFrame.Range.of(delegate.type(), 0, arrayOffset); 1342 } 1343 1344 @Override 1345 public void transform(EmulatedStackFrame callerFrame) throws Throwable { 1346 // Create a new stack frame for the callee. 1347 EmulatedStackFrame targetFrame = EmulatedStackFrame.create(target.type()); 1348 1349 // Copy all arguments except for the trailing array argument. 1350 callerFrame.copyRangeTo(targetFrame, copyRange, 0, 0); 1351 1352 // Attach the writer, prepare to spread the trailing array arguments into 1353 // the callee frame. 1354 final StackFrameWriter writer = new StackFrameWriter(); 1355 writer.attach(targetFrame, arrayOffset, copyRange.numReferences, copyRange.numBytes); 1356 final StackFrameReader reader = new StackFrameReader(); 1357 reader.attach(callerFrame, arrayOffset, copyRange.numReferences, copyRange.numBytes); 1358 1359 switch (arrayTypeChar) { 1360 case 'L': { 1361 // Reference arrays are the only case where the component type of the 1362 // array we construct might differ from the type of the reference we read 1363 // from the stack frame. 1364 final Class<?> targetType = target.type().ptypes()[arrayOffset]; 1365 final Class<?> targetComponentType = targetType.getComponentType(); 1366 final Class<?> adapterComponentType = type().lastParameterType(); 1367 1368 Object[] arr = (Object[]) Array.newInstance(targetComponentType, numArrayArgs); 1369 for (int i = 0; i < numArrayArgs; ++i) { 1370 arr[i] = reader.nextReference(adapterComponentType); 1371 } 1372 1373 writer.putNextReference(arr, targetType); 1374 break; 1375 } 1376 case 'I': { 1377 int[] array = new int[numArrayArgs]; 1378 for (int i = 0; i < numArrayArgs; ++i) { 1379 array[i] = reader.nextInt(); 1380 } 1381 writer.putNextReference(array, int[].class); 1382 break; 1383 } 1384 case 'J': { 1385 long[] array = new long[numArrayArgs]; 1386 for (int i = 0; i < numArrayArgs; ++i) { 1387 array[i] = reader.nextLong(); 1388 } 1389 writer.putNextReference(array, long[].class); 1390 break; 1391 } 1392 case 'B': { 1393 byte[] array = new byte[numArrayArgs]; 1394 for (int i = 0; i < numArrayArgs; ++i) { 1395 array[i] = reader.nextByte(); 1396 } 1397 writer.putNextReference(array, byte[].class); 1398 break; 1399 } 1400 case 'S': { 1401 short[] array = new short[numArrayArgs]; 1402 for (int i = 0; i < numArrayArgs; ++i) { 1403 array[i] = reader.nextShort(); 1404 } 1405 writer.putNextReference(array, short[].class); 1406 break; 1407 } 1408 case 'C': { 1409 char[] array = new char[numArrayArgs]; 1410 for (int i = 0; i < numArrayArgs; ++i) { 1411 array[i] = reader.nextChar(); 1412 } 1413 writer.putNextReference(array, char[].class); 1414 break; 1415 } 1416 case 'Z': { 1417 boolean[] array = new boolean[numArrayArgs]; 1418 for (int i = 0; i < numArrayArgs; ++i) { 1419 array[i] = reader.nextBoolean(); 1420 } 1421 writer.putNextReference(array, boolean[].class); 1422 break; 1423 } 1424 case 'F': { 1425 float[] array = new float[numArrayArgs]; 1426 for (int i = 0; i < numArrayArgs; ++i) { 1427 array[i] = reader.nextFloat(); 1428 } 1429 writer.putNextReference(array, float[].class); 1430 break; 1431 } 1432 case 'D': { 1433 double[] array = new double[numArrayArgs]; 1434 for (int i = 0; i < numArrayArgs; ++i) { 1435 array[i] = reader.nextDouble(); 1436 } 1437 writer.putNextReference(array, double[].class); 1438 break; 1439 } 1440 } 1441 1442 target.invoke(targetFrame); 1443 targetFrame.copyReturnValueTo(callerFrame); 1444 } 1445 } 1446 1447 /* 1448 * Implements MethodHandles.filterArguments. 1449 */ 1450 static class FilterArguments extends Transformer { 1451 /** The target handle. */ 1452 private final MethodHandle target; 1453 /** Index of the first argument to filter */ 1454 private final int pos; 1455 /** The list of filters to apply */ 1456 private final MethodHandle[] filters; 1457 1458 FilterArguments(MethodHandle target, int pos, MethodHandle[] filters) { 1459 super(deriveType(target, pos, filters)); 1460 1461 this.target = target; 1462 this.pos = pos; 1463 this.filters = filters; 1464 1465 } 1466 1467 private static MethodType deriveType(MethodHandle target, int pos, MethodHandle[] filters) { 1468 final Class<?>[] filterArgs = new Class<?>[filters.length]; 1469 for (int i = 0; i < filters.length; ++i) { 1470 filterArgs[i] = filters[i].type().parameterType(0); 1471 } 1472 1473 return target.type().replaceParameterTypes(pos, pos + filters.length, filterArgs); 1474 } 1475 1476 @Override 1477 public void transform(EmulatedStackFrame stackFrame) throws Throwable { 1478 final StackFrameReader reader = new StackFrameReader(); 1479 reader.attach(stackFrame); 1480 1481 EmulatedStackFrame transformedFrame = EmulatedStackFrame.create(target.type()); 1482 final StackFrameWriter writer = new StackFrameWriter(); 1483 writer.attach(transformedFrame); 1484 1485 final Class<?>[] ptypes = target.type().ptypes(); 1486 for (int i = 0; i < ptypes.length; ++i) { 1487 // Check whether the current argument has a filter associated with it. 1488 // If it has no filter, no further action need be taken. 1489 final Class<?> ptype = ptypes[i]; 1490 final MethodHandle filter; 1491 if (i < pos) { 1492 filter = null; 1493 } else if (i >= pos + filters.length) { 1494 filter = null; 1495 } else { 1496 filter = filters[i - pos]; 1497 } 1498 1499 if (filter != null) { 1500 // Note that filter.type() must be (ptype)ptype - this is checked before 1501 // this transformer is created. 1502 EmulatedStackFrame filterFrame = EmulatedStackFrame.create(filter.type()); 1503 1504 // Copy the next argument from the stack frame to the filter frame. 1505 final StackFrameWriter filterWriter = new StackFrameWriter(); 1506 filterWriter.attach(filterFrame); 1507 copyNext(reader, filterWriter, filter.type().ptypes()[0]); 1508 1509 filter.invoke(filterFrame); 1510 1511 // Copy the argument back from the filter frame to the stack frame. 1512 final StackFrameReader filterReader = new StackFrameReader(); 1513 filterReader.attach(filterFrame); 1514 filterReader.makeReturnValueAccessor(); 1515 copyNext(filterReader, writer, ptype); 1516 } else { 1517 // There's no filter associated with this frame, just copy the next argument 1518 // over. 1519 copyNext(reader, writer, ptype); 1520 } 1521 } 1522 1523 target.invoke(transformedFrame); 1524 transformedFrame.copyReturnValueTo(stackFrame); 1525 } 1526 } 1527 1528 /** 1529 * Implements MethodHandles.collectArguments. 1530 */ 1531 static class CollectArguments extends Transformer { 1532 private final MethodHandle target; 1533 private final MethodHandle collector; 1534 private final int pos; 1535 1536 /** The range of input arguments we copy to the collector. */ 1537 private final Range collectorRange; 1538 1539 /** 1540 * The first range of arguments we copy to the target. These are arguments 1541 * in the range [0, pos). Note that arg[pos] is the return value of the filter. 1542 */ 1543 private final Range range1; 1544 1545 /** 1546 * The second range of arguments we copy to the target. These are arguments in the range 1547 * (pos, N], where N is the number of target arguments. 1548 */ 1549 private final Range range2; 1550 1551 private final int referencesOffset; 1552 private final int stackFrameOffset; 1553 1554 CollectArguments(MethodHandle target, MethodHandle collector, int pos, 1555 MethodType adapterType) { 1556 super(adapterType); 1557 1558 this.target = target; 1559 this.collector = collector; 1560 this.pos = pos; 1561 1562 final int numFilterArgs = collector.type().parameterCount(); 1563 final int numAdapterArgs = type().parameterCount(); 1564 collectorRange = Range.of(type(), pos, pos + numFilterArgs); 1565 1566 range1 = Range.of(type(), 0, pos); 1567 if (pos + numFilterArgs < numAdapterArgs) { 1568 this.range2 = Range.of(type(), pos + numFilterArgs, numAdapterArgs); 1569 } else { 1570 this.range2 = null; 1571 } 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 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 collector.invoke(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()[0]); 1606 } 1607 1608 if (range2 != null) { 1609 stackFrame.copyRangeTo(targetFrame, range2, 1610 range1.numReferences + referencesOffset, 1611 range2.numBytes + stackFrameOffset); 1612 } 1613 1614 target.invoke(targetFrame); 1615 targetFrame.copyReturnValueTo(stackFrame); 1616 } 1617 } 1618 1619 /** 1620 * Implements MethodHandles.foldArguments. 1621 */ 1622 static class FoldArguments extends Transformer { 1623 private final MethodHandle target; 1624 private final MethodHandle combiner; 1625 1626 private final Range combinerArgs; 1627 private final Range targetArgs; 1628 1629 private final int referencesOffset; 1630 private final int stackFrameOffset; 1631 1632 FoldArguments(MethodHandle target, MethodHandle combiner) { 1633 super(deriveType(target, combiner)); 1634 1635 this.target = target; 1636 this.combiner = combiner; 1637 1638 combinerArgs = Range.all(combiner.type()); 1639 targetArgs = Range.all(type()); 1640 1641 final Class<?> combinerRType = combiner.type().rtype(); 1642 if (combinerRType == void.class) { 1643 stackFrameOffset = 0; 1644 referencesOffset = 0; 1645 } else if (combinerRType.isPrimitive()) { 1646 stackFrameOffset = EmulatedStackFrame.getSize(combinerRType); 1647 referencesOffset = 0; 1648 } else { 1649 stackFrameOffset = 0; 1650 referencesOffset = 1; 1651 } 1652 } 1653 1654 @Override 1655 public void transform(EmulatedStackFrame stackFrame) throws Throwable { 1656 // First construct the combiner frame and invoke it. 1657 EmulatedStackFrame combinerFrame = EmulatedStackFrame.create(combiner.type()); 1658 stackFrame.copyRangeTo(combinerFrame, combinerArgs, 0, 0); 1659 combiner.invoke(combinerFrame); 1660 1661 // Create the stack frame for the target. 1662 EmulatedStackFrame targetFrame = EmulatedStackFrame.create(target.type()); 1663 1664 // If one of these offsets is not zero, we have a return value to copy. 1665 if (referencesOffset != 0 || stackFrameOffset != 0) { 1666 final StackFrameReader reader = new StackFrameReader(); 1667 reader.attach(combinerFrame).makeReturnValueAccessor(); 1668 final StackFrameWriter writer = new StackFrameWriter(); 1669 writer.attach(targetFrame); 1670 copyNext(reader, writer, target.type().ptypes()[0]); 1671 } 1672 1673 stackFrame.copyRangeTo(targetFrame, targetArgs, referencesOffset, stackFrameOffset); 1674 target.invoke(targetFrame); 1675 1676 targetFrame.copyReturnValueTo(stackFrame); 1677 } 1678 1679 private static MethodType deriveType(MethodHandle target, MethodHandle combiner) { 1680 if (combiner.type().rtype() == void.class) { 1681 return target.type(); 1682 } 1683 1684 return target.type().dropParameterTypes(0, 1); 1685 } 1686 } 1687 1688 /** 1689 * Implements MethodHandles.insertArguments. 1690 */ 1691 static class InsertArguments extends Transformer { 1692 private final MethodHandle target; 1693 private final int pos; 1694 private final Object[] values; 1695 1696 private final Range range1; 1697 private final Range range2; 1698 1699 InsertArguments(MethodHandle target, int pos, Object[] values) { 1700 super(target.type().dropParameterTypes(pos, pos + values.length)); 1701 this.target = target; 1702 this.pos = pos; 1703 this.values = values; 1704 1705 final MethodType type = type(); 1706 range1 = EmulatedStackFrame.Range.of(type, 0, pos); 1707 range2 = Range.of(type, pos, type.parameterCount()); 1708 } 1709 1710 @Override 1711 public void transform(EmulatedStackFrame stackFrame) throws Throwable { 1712 EmulatedStackFrame calleeFrame = EmulatedStackFrame.create(target.type()); 1713 1714 // Copy all arguments before |pos|. 1715 stackFrame.copyRangeTo(calleeFrame, range1, 0, 0); 1716 1717 // Attach a stack frame writer so that we can copy the next |values.length| 1718 // arguments. 1719 final StackFrameWriter writer = new StackFrameWriter(); 1720 writer.attach(calleeFrame, pos, range1.numReferences, range1.numBytes); 1721 1722 // Copy all the arguments supplied in |values|. 1723 int referencesCopied = 0; 1724 int bytesCopied = 0; 1725 final Class<?>[] ptypes = target.type().ptypes(); 1726 for (int i = 0; i < values.length; ++i) { 1727 final Class<?> ptype = ptypes[i + pos]; 1728 if (ptype.isPrimitive()) { 1729 if (ptype == boolean.class) { 1730 writer.putNextBoolean((boolean) values[i]); 1731 } else if (ptype == byte.class) { 1732 writer.putNextByte((byte) values[i]); 1733 } else if (ptype == char.class) { 1734 writer.putNextChar((char) values[i]); 1735 } else if (ptype == short.class) { 1736 writer.putNextShort((short) values[i]); 1737 } else if (ptype == int.class) { 1738 writer.putNextInt((int) values[i]); 1739 } else if (ptype == long.class) { 1740 writer.putNextLong((long) values[i]); 1741 } else if (ptype == float.class) { 1742 writer.putNextFloat((float) values[i]); 1743 } else if (ptype == double.class) { 1744 writer.putNextDouble((double) values[i]); 1745 } 1746 1747 bytesCopied += EmulatedStackFrame.getSize(ptype); 1748 } else { 1749 writer.putNextReference(values[i], ptype); 1750 referencesCopied++; 1751 } 1752 } 1753 1754 // Copy all remaining arguments. 1755 if (range2 != null) { 1756 stackFrame.copyRangeTo(calleeFrame, range2, 1757 range1.numReferences + referencesCopied, 1758 range1.numBytes + bytesCopied); 1759 } 1760 1761 target.invoke(calleeFrame); 1762 calleeFrame.copyReturnValueTo(stackFrame); 1763 } 1764 } 1765 1766 1767 /** 1768 * Implements {@link java.lang.invokeMethodHandles#explicitCastArguments()}. 1769 */ 1770 public static class ExplicitCastArguments extends Transformer { 1771 private final MethodHandle target; 1772 1773 public ExplicitCastArguments(MethodHandle target, MethodType type) { 1774 super(type); 1775 this.target = target; 1776 } 1777 1778 @Override 1779 public void transform(EmulatedStackFrame callerFrame) throws Throwable { 1780 // Create a new stack frame for the target. 1781 EmulatedStackFrame targetFrame = EmulatedStackFrame.create(target.type()); 1782 1783 explicitCastArguments(callerFrame, targetFrame); 1784 target.invoke(targetFrame); 1785 explicitCastReturnValue(callerFrame, targetFrame); 1786 } 1787 1788 private void explicitCastArguments(final EmulatedStackFrame callerFrame, 1789 final EmulatedStackFrame targetFrame) { 1790 final StackFrameReader reader = new StackFrameReader(); 1791 reader.attach(callerFrame); 1792 final StackFrameWriter writer = new StackFrameWriter(); 1793 writer.attach(targetFrame); 1794 1795 final Class<?>[] fromTypes = type().ptypes(); 1796 final Class<?>[] toTypes = target.type().ptypes(); 1797 for (int i = 0; i < fromTypes.length; ++i) { 1798 explicitCast(reader, fromTypes[i], writer, toTypes[i]); 1799 } 1800 } 1801 1802 private void explicitCastReturnValue(final EmulatedStackFrame callerFrame, 1803 final EmulatedStackFrame targetFrame) { 1804 Class<?> from = target.type().rtype(); 1805 Class<?> to = type().rtype(); 1806 if (to != void.class) { 1807 final StackFrameWriter writer = new StackFrameWriter(); 1808 writer.attach(callerFrame); 1809 writer.makeReturnValueAccessor(); 1810 if (from == void.class) { 1811 if (to.isPrimitive()) { 1812 unboxNull(writer, to); 1813 } else { 1814 writer.putNextReference(null, to); 1815 } 1816 } else { 1817 final StackFrameReader reader = new StackFrameReader(); 1818 reader.attach(targetFrame); 1819 reader.makeReturnValueAccessor(); 1820 explicitCast(reader, target.type().rtype(), writer, type().rtype()); 1821 } 1822 } 1823 } 1824 1825 private static void throwUnexpectedType(final Class<?> unexpectedType) { 1826 throw new InternalError("Unexpected type: " + unexpectedType); 1827 } 1828 1829 private static void explicitCastFromBoolean(boolean fromValue, 1830 final StackFrameWriter writer, 1831 final Class<?> to) { 1832 int value = fromValue ? 1 : 0; 1833 if (to == byte.class) { 1834 writer.putNextByte((byte) value); 1835 } else if (to == char.class) { 1836 writer.putNextChar((char) value); 1837 } else if (to == short.class) { 1838 writer.putNextShort((short) value); 1839 } else if (to == int.class) { 1840 writer.putNextInt(value); 1841 } else if (to == long.class) { 1842 writer.putNextLong(value); 1843 } else if (to == float.class) { 1844 writer.putNextFloat(value); 1845 } else if (to == double.class) { 1846 writer.putNextDouble(value); 1847 } else { 1848 throwUnexpectedType(to); 1849 } 1850 } 1851 1852 /** 1853 * Converts byte value to boolean according to 1854 * {@link java.lang.invoke.MethodHandles#explicitCast()} 1855 */ 1856 private static boolean toBoolean(byte value) { 1857 return (value & 1) == 1; 1858 } 1859 1860 private static byte readPrimitiveAsByte(final StackFrameReader reader, 1861 final Class<?> from) { 1862 if (from == byte.class) { 1863 return (byte) reader.nextByte(); 1864 } else if (from == char.class) { 1865 return (byte) reader.nextChar(); 1866 } else if (from == short.class) { 1867 return (byte) reader.nextShort(); 1868 } else if (from == int.class) { 1869 return (byte) reader.nextInt(); 1870 } else if (from == long.class) { 1871 return (byte) reader.nextLong(); 1872 } else if (from == float.class) { 1873 return (byte) reader.nextFloat(); 1874 } else if (from == double.class) { 1875 return (byte) reader.nextDouble(); 1876 } else { 1877 throwUnexpectedType(from); 1878 return 0; 1879 } 1880 } 1881 1882 private static char readPrimitiveAsChar(final StackFrameReader reader, 1883 final Class<?> from) { 1884 if (from == byte.class) { 1885 return (char) reader.nextByte(); 1886 } else if (from == char.class) { 1887 return (char) reader.nextChar(); 1888 } else if (from == short.class) { 1889 return (char) reader.nextShort(); 1890 } else if (from == int.class) { 1891 return (char) reader.nextInt(); 1892 } else if (from == long.class) { 1893 return (char) reader.nextLong(); 1894 } else if (from == float.class) { 1895 return (char) reader.nextFloat(); 1896 } else if (from == double.class) { 1897 return (char) reader.nextDouble(); 1898 } else { 1899 throwUnexpectedType(from); 1900 return 0; 1901 } 1902 } 1903 1904 private static short readPrimitiveAsShort(final StackFrameReader reader, 1905 final Class<?> from) { 1906 if (from == byte.class) { 1907 return (short) reader.nextByte(); 1908 } else if (from == char.class) { 1909 return (short) reader.nextChar(); 1910 } else if (from == short.class) { 1911 return (short) reader.nextShort(); 1912 } else if (from == int.class) { 1913 return (short) reader.nextInt(); 1914 } else if (from == long.class) { 1915 return (short) reader.nextLong(); 1916 } else if (from == float.class) { 1917 return (short) reader.nextFloat(); 1918 } else if (from == double.class) { 1919 return (short) reader.nextDouble(); 1920 } else { 1921 throwUnexpectedType(from); 1922 return 0; 1923 } 1924 } 1925 1926 private static int readPrimitiveAsInt(final StackFrameReader reader, 1927 final Class<?> from) { 1928 if (from == byte.class) { 1929 return (int) reader.nextByte(); 1930 } else if (from == char.class) { 1931 return (int) reader.nextChar(); 1932 } else if (from == short.class) { 1933 return (int) reader.nextShort(); 1934 } else if (from == int.class) { 1935 return (int) reader.nextInt(); 1936 } else if (from == long.class) { 1937 return (int) reader.nextLong(); 1938 } else if (from == float.class) { 1939 return (int) reader.nextFloat(); 1940 } else if (from == double.class) { 1941 return (int) reader.nextDouble(); 1942 } else { 1943 throwUnexpectedType(from); 1944 return 0; 1945 } 1946 } 1947 1948 private static long readPrimitiveAsLong(final StackFrameReader reader, 1949 final Class<?> from) { 1950 if (from == byte.class) { 1951 return (long) reader.nextByte(); 1952 } else if (from == char.class) { 1953 return (long) reader.nextChar(); 1954 } else if (from == short.class) { 1955 return (long) reader.nextShort(); 1956 } else if (from == int.class) { 1957 return (long) reader.nextInt(); 1958 } else if (from == long.class) { 1959 return (long) reader.nextLong(); 1960 } else if (from == float.class) { 1961 return (long) reader.nextFloat(); 1962 } else if (from == double.class) { 1963 return (long) reader.nextDouble(); 1964 } else { 1965 throwUnexpectedType(from); 1966 return 0; 1967 } 1968 } 1969 1970 private static float readPrimitiveAsFloat(final StackFrameReader reader, 1971 final Class<?> from) { 1972 if (from == byte.class) { 1973 return (float) reader.nextByte(); 1974 } else if (from == char.class) { 1975 return (float) reader.nextChar(); 1976 } else if (from == short.class) { 1977 return (float) reader.nextShort(); 1978 } else if (from == int.class) { 1979 return (float) reader.nextInt(); 1980 } else if (from == long.class) { 1981 return (float) reader.nextLong(); 1982 } else if (from == float.class) { 1983 return (float) reader.nextFloat(); 1984 } else if (from == double.class) { 1985 return (float) reader.nextDouble(); 1986 } else { 1987 throwUnexpectedType(from); 1988 return 0; 1989 } 1990 } 1991 1992 private static double readPrimitiveAsDouble(final StackFrameReader reader, 1993 final Class<?> from) { 1994 if (from == byte.class) { 1995 return (double) reader.nextByte(); 1996 } else if (from == char.class) { 1997 return (double) reader.nextChar(); 1998 } else if (from == short.class) { 1999 return (double) reader.nextShort(); 2000 } else if (from == int.class) { 2001 return (double) reader.nextInt(); 2002 } else if (from == long.class) { 2003 return (double) reader.nextLong(); 2004 } else if (from == float.class) { 2005 return (double) reader.nextFloat(); 2006 } else if (from == double.class) { 2007 return (double) reader.nextDouble(); 2008 } else { 2009 throwUnexpectedType(from); 2010 return 0; 2011 } 2012 } 2013 2014 private static void explicitCastToBoolean(final StackFrameReader reader, 2015 final Class<?> from, 2016 final StackFrameWriter writer) { 2017 byte byteValue = readPrimitiveAsByte(reader, from); 2018 writer.putNextBoolean(toBoolean(byteValue)); 2019 } 2020 2021 private static void explicitCastPrimitives(final StackFrameReader reader, 2022 final Class<?> from, 2023 final StackFrameWriter writer, 2024 final Class<?> to) { 2025 if (to == byte.class) { 2026 byte value = readPrimitiveAsByte(reader, from); 2027 writer.putNextByte(value); 2028 } else if (to == char.class) { 2029 char value = readPrimitiveAsChar(reader, from); 2030 writer.putNextChar(value); 2031 } else if (to == short.class) { 2032 short value = readPrimitiveAsShort(reader, from); 2033 writer.putNextShort(value); 2034 } else if (to == int.class) { 2035 int value = readPrimitiveAsInt(reader, from); 2036 writer.putNextInt(value); 2037 } else if (to == long.class) { 2038 long value = readPrimitiveAsLong(reader, from); 2039 writer.putNextLong(value); 2040 } else if (to == float.class) { 2041 float value = readPrimitiveAsFloat(reader, from); 2042 writer.putNextFloat(value); 2043 } else if (to == double.class) { 2044 double value = readPrimitiveAsDouble(reader, from); 2045 writer.putNextDouble(value); 2046 } else { 2047 throwUnexpectedType(to); 2048 } 2049 } 2050 2051 private static void unboxNull(final StackFrameWriter writer, final Class<?> to) { 2052 if (to == boolean.class) { 2053 writer.putNextBoolean(false); 2054 } else if (to == byte.class) { 2055 writer.putNextByte((byte) 0); 2056 } else if (to == char.class) { 2057 writer.putNextChar((char) 0); 2058 } else if (to == short.class) { 2059 writer.putNextShort((short) 0); 2060 } else if (to == int.class) { 2061 writer.putNextInt((int) 0); 2062 } else if (to == long.class) { 2063 writer.putNextLong((long) 0); 2064 } else if (to == float.class) { 2065 writer.putNextFloat((float) 0); 2066 } else if (to == double.class) { 2067 writer.putNextDouble((double) 0); 2068 } else { 2069 throwUnexpectedType(to); 2070 } 2071 } 2072 2073 private static void unboxNonNull(final Object ref, final Class<?> from, 2074 final StackFrameWriter writer, final Class<?> to) { 2075 if (to == boolean.class) { 2076 if (from == Boolean.class) { 2077 writer.putNextBoolean((boolean) ref); 2078 } else if (from == Float.class || from == Double.class) { 2079 byte b = (byte) ((double) ref); 2080 writer.putNextBoolean(toBoolean(b)); 2081 } else { 2082 byte b = (byte) ((long) ref); 2083 writer.putNextBoolean(toBoolean(b)); 2084 } 2085 } else if (to == byte.class) { 2086 writer.putNextByte((byte) ref); 2087 } else if (to == char.class) { 2088 writer.putNextChar((char) ref); 2089 } else if (to == short.class) { 2090 writer.putNextShort((short) ref); 2091 } else if (to == int.class) { 2092 writer.putNextInt((int) ref); 2093 } else if (to == long.class) { 2094 writer.putNextLong((long) ref); 2095 } else if (to == float.class) { 2096 writer.putNextFloat((float) ref); 2097 } else if (to == double.class) { 2098 writer.putNextDouble((double) ref); 2099 } else { 2100 throwUnexpectedType(to); 2101 } 2102 } 2103 2104 private static void unbox(final Object ref, final Class<?> from, 2105 final StackFrameWriter writer, final Class<?> to) { 2106 if (ref == null) { 2107 unboxNull(writer, to); 2108 } else { 2109 unboxNonNull(ref, from, writer, to); 2110 } 2111 } 2112 2113 private static void box(final StackFrameReader reader, final Class<?> from, 2114 final StackFrameWriter writer, final Class<?> to) { 2115 Object boxed = null; 2116 if (from == boolean.class) { 2117 boxed = Boolean.valueOf(reader.nextBoolean()); 2118 } else if (from == byte.class) { 2119 boxed = Byte.valueOf(reader.nextByte()); 2120 } else if (from == char.class) { 2121 boxed = Character.valueOf(reader.nextChar()); 2122 } else if (from == short.class) { 2123 boxed = Short.valueOf(reader.nextShort()); 2124 } else if (from == int.class) { 2125 boxed = Integer.valueOf(reader.nextInt()); 2126 } else if (from == long.class) { 2127 boxed = Long.valueOf(reader.nextLong()); 2128 } else if (from == float.class) { 2129 boxed = Float.valueOf(reader.nextFloat()); 2130 } else if (from == double.class) { 2131 boxed = Double.valueOf(reader.nextDouble()); 2132 } else { 2133 throwUnexpectedType(from); 2134 } 2135 writer.putNextReference(to.cast(boxed), to); 2136 } 2137 2138 private static void explicitCast(final StackFrameReader reader, final Class<?> from, 2139 final StackFrameWriter writer, final Class<?> to) { 2140 if (from.equals(to)) { 2141 StackFrameAccessor.copyNext(reader, writer, from); 2142 } else if (!from.isPrimitive()) { 2143 Object ref = reader.nextReference(from); 2144 if (to.isInterface()) { 2145 // Pass from without a cast according to description for 2146 // {@link java.lang.invoke.MethodHandles#explicitCastArguments()}. 2147 writer.putNextReference(ref, to); 2148 } else if (!to.isPrimitive()) { 2149 // |to| is a reference type, perform class cast check. 2150 writer.putNextReference(to.cast(ref), to); 2151 } else { 2152 // |from| is a reference type, |to| is a primitive type, 2153 unbox(ref, from, writer, to); 2154 } 2155 } else if (to.isPrimitive()) { 2156 // |from| and |to| are primitive types. 2157 if (from == boolean.class) { 2158 explicitCastFromBoolean(reader.nextBoolean(), writer, to); 2159 } else if (to == boolean.class) { 2160 explicitCastToBoolean(reader, from, writer); 2161 } else { 2162 explicitCastPrimitives(reader, from, writer, to); 2163 } 2164 } else { 2165 // |from| is a primitive type, |to| is a reference type. 2166 box(reader, from, writer, to); 2167 } 2168 } 2169 } 2170 } 2171