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