1 /* 2 * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE 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 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package java.lang.invoke; 27 28 import jdk.internal.org.objectweb.asm.*; 29 import sun.invoke.util.BytecodeDescriptor; 30 import sun.security.action.GetPropertyAction; 31 import sun.security.action.GetBooleanAction; 32 33 import java.io.FilePermission; 34 import java.io.Serializable; 35 import java.lang.invoke.MethodHandles.Lookup; 36 import java.lang.reflect.Constructor; 37 import java.lang.reflect.Modifier; 38 import java.security.AccessController; 39 import java.security.PrivilegedAction; 40 import java.util.LinkedHashSet; 41 import java.util.concurrent.atomic.AtomicInteger; 42 import java.util.PropertyPermission; 43 import java.util.Set; 44 45 import static java.lang.invoke.MethodHandles.Lookup.ClassOption.NESTMATE; 46 import static java.lang.invoke.MethodHandles.Lookup.ClassOption.STRONG; 47 import static jdk.internal.org.objectweb.asm.Opcodes.*; 48 49 /** 50 * Lambda metafactory implementation which dynamically creates an 51 * inner-class-like class per lambda callsite. 52 * 53 * @see LambdaMetafactory 54 */ 55 /* package */ final class InnerClassLambdaMetafactory extends AbstractValidatingLambdaMetafactory { 56 private static final int CLASSFILE_VERSION = 52; 57 private static final String METHOD_DESCRIPTOR_VOID = Type.getMethodDescriptor(Type.VOID_TYPE); 58 private static final String JAVA_LANG_OBJECT = "java/lang/Object"; 59 private static final String NAME_CTOR = "<init>"; 60 61 //Serialization support 62 private static final String NAME_SERIALIZED_LAMBDA = "java/lang/invoke/SerializedLambda"; 63 private static final String NAME_NOT_SERIALIZABLE_EXCEPTION = "java/io/NotSerializableException"; 64 private static final String DESCR_METHOD_WRITE_REPLACE = "()Ljava/lang/Object;"; 65 private static final String DESCR_METHOD_WRITE_OBJECT = "(Ljava/io/ObjectOutputStream;)V"; 66 private static final String DESCR_METHOD_READ_OBJECT = "(Ljava/io/ObjectInputStream;)V"; 67 private static final String DESCR_SET_IMPL_METHOD = "(Ljava/lang/invoke/MethodHandle;)V"; 68 69 private static final String NAME_METHOD_WRITE_REPLACE = "writeReplace"; 70 private static final String NAME_METHOD_READ_OBJECT = "readObject"; 71 private static final String NAME_METHOD_WRITE_OBJECT = "writeObject"; 72 private static final String NAME_FIELD_IMPL_METHOD = "protectedImplMethod"; 73 74 private static final String DESCR_CLASS = "Ljava/lang/Class;"; 75 private static final String DESCR_STRING = "Ljava/lang/String;"; 76 private static final String DESCR_OBJECT = "Ljava/lang/Object;"; 77 private static final String DESCR_METHOD_HANDLE = "Ljava/lang/invoke/MethodHandle;"; 78 private static final String DESCR_CTOR_SERIALIZED_LAMBDA 79 = "(" + DESCR_CLASS + DESCR_STRING + DESCR_STRING + DESCR_STRING + "I" 80 + DESCR_STRING + DESCR_STRING + DESCR_STRING + DESCR_STRING + "[" + DESCR_OBJECT + ")V"; 81 82 private static final String DESCR_CTOR_NOT_SERIALIZABLE_EXCEPTION = "(Ljava/lang/String;)V"; 83 private static final String[] SER_HOSTILE_EXCEPTIONS = new String[] {NAME_NOT_SERIALIZABLE_EXCEPTION}; 84 85 private static final String[] EMPTY_STRING_ARRAY = new String[0]; 86 87 // Used to ensure that each spun class name is unique 88 private static final AtomicInteger counter = new AtomicInteger(0); 89 90 // For dumping generated classes to disk, for debugging purposes 91 private static final ProxyClassesDumper dumper; 92 93 private static final boolean disableEagerInitialization; 94 95 static { 96 final String dumpProxyClassesKey = "jdk.internal.lambda.dumpProxyClasses"; 97 String dumpPath = GetPropertyAction.privilegedGetProperty(dumpProxyClassesKey); 98 dumper = (null == dumpPath) ? null : ProxyClassesDumper.getInstance(dumpPath); 99 100 final String disableEagerInitializationKey = "jdk.internal.lambda.disableEagerInitialization"; 101 disableEagerInitialization = GetBooleanAction.privilegedGetProperty(disableEagerInitializationKey); 102 } 103 104 // See context values in AbstractValidatingLambdaMetafactory 105 private final String implMethodClassName; // Name of type containing implementation "CC" 106 private final String implMethodName; // Name of implementation method "impl" 107 private final String implMethodDesc; // Type descriptor for implementation methods "(I)Ljava/lang/String;" 108 private final MethodType constructorType; // Generated class constructor type "(CC)void" 109 private final ClassWriter cw; // ASM class writer 110 private final String[] argNames; // Generated names for the constructor arguments 111 private final String[] argDescs; // Type descriptors for the constructor arguments 112 private final String lambdaClassName; // Generated name for the generated class "X$$Lambda$1" 113 private final boolean useImplMethodHandle; // use MethodHandle invocation instead of symbolic bytecode invocation 114 115 /** 116 * General meta-factory constructor, supporting both standard cases and 117 * allowing for uncommon options such as serialization or bridging. 118 * 119 * @param caller Stacked automatically by VM; represents a lookup context 120 * with the accessibility privileges of the caller. 121 * @param invokedType Stacked automatically by VM; the signature of the 122 * invoked method, which includes the expected static 123 * type of the returned lambda object, and the static 124 * types of the captured arguments for the lambda. In 125 * the event that the implementation method is an 126 * instance method, the first argument in the invocation 127 * signature will correspond to the receiver. 128 * @param samMethodName Name of the method in the functional interface to 129 * which the lambda or method reference is being 130 * converted, represented as a String. 131 * @param samMethodType Type of the method in the functional interface to 132 * which the lambda or method reference is being 133 * converted, represented as a MethodType. 134 * @param implMethod The implementation method which should be called (with 135 * suitable adaptation of argument types, return types, 136 * and adjustment for captured arguments) when methods of 137 * the resulting functional interface instance are invoked. 138 * @param instantiatedMethodType The signature of the primary functional 139 * interface method after type variables are 140 * substituted with their instantiation from 141 * the capture site 142 * @param isSerializable Should the lambda be made serializable? If set, 143 * either the target type or one of the additional SAM 144 * types must extend {@code Serializable}. 145 * @param markerInterfaces Additional interfaces which the lambda object 146 * should implement. 147 * @param additionalBridges Method types for additional signatures to be 148 * bridged to the implementation method 149 * @throws LambdaConversionException If any of the meta-factory protocol 150 * invariants are violated 151 */ 152 public InnerClassLambdaMetafactory(MethodHandles.Lookup caller, 153 MethodType invokedType, 154 String samMethodName, 155 MethodType samMethodType, 156 MethodHandle implMethod, 157 MethodType instantiatedMethodType, 158 boolean isSerializable, 159 Class<?>[] markerInterfaces, 160 MethodType[] additionalBridges) 161 throws LambdaConversionException { 162 super(caller, invokedType, samMethodName, samMethodType, 163 implMethod, instantiatedMethodType, 164 isSerializable, markerInterfaces, additionalBridges); 165 implMethodClassName = implClass.getName().replace('.', '/'); 166 implMethodName = implInfo.getName(); 167 implMethodDesc = implInfo.getMethodType().toMethodDescriptorString(); 168 constructorType = invokedType.changeReturnType(Void.TYPE); 169 lambdaClassName = lambdaClassName(targetClass); 170 useImplMethodHandle = !implClass.getPackageName().equals(implInfo.getDeclaringClass().getPackageName()) 171 && !Modifier.isPublic(implInfo.getModifiers()); 172 cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); 173 int parameterCount = invokedType.parameterCount(); 174 if (parameterCount > 0) { 175 argNames = new String[parameterCount]; 176 argDescs = new String[parameterCount]; 177 for (int i = 0; i < parameterCount; i++) { 178 argNames[i] = "arg$" + (i + 1); 179 argDescs[i] = BytecodeDescriptor.unparse(invokedType.parameterType(i)); 180 } 181 } else { 182 argNames = argDescs = EMPTY_STRING_ARRAY; 183 } 184 } 185 186 private static String lambdaClassName(Class<?> targetClass) { 187 String name = targetClass.getName(); 188 if (targetClass.isHidden()) { 189 // use the original class name 190 name = name.replace('/', '_'); 191 } 192 return name.replace('.', '/') + "$$Lambda$" + counter.incrementAndGet(); 193 } 194 195 /** 196 * Build the CallSite. Generate a class file which implements the functional 197 * interface, define the class, if there are no parameters create an instance 198 * of the class which the CallSite will return, otherwise, generate handles 199 * which will call the class' constructor. 200 * 201 * @return a CallSite, which, when invoked, will return an instance of the 202 * functional interface 203 * @throws ReflectiveOperationException 204 * @throws LambdaConversionException If properly formed functional interface 205 * is not found 206 */ 207 @Override 208 CallSite buildCallSite() throws LambdaConversionException { 209 final Class<?> innerClass = spinInnerClass(); 210 if (invokedType.parameterCount() == 0 && !disableEagerInitialization) { 211 // In the case of a non-capturing lambda, we optimize linkage by pre-computing a single instance, 212 // unless we've suppressed eager initialization 213 final Constructor<?>[] ctrs = AccessController.doPrivileged( 214 new PrivilegedAction<>() { 215 @Override 216 public Constructor<?>[] run() { 217 Constructor<?>[] ctrs = innerClass.getDeclaredConstructors(); 218 if (ctrs.length == 1) { 219 // The lambda implementing inner class constructor is private, set 220 // it accessible (by us) before creating the constant sole instance 221 ctrs[0].setAccessible(true); 222 } 223 return ctrs; 224 } 225 }); 226 if (ctrs.length != 1) { 227 throw new LambdaConversionException("Expected one lambda constructor for " 228 + innerClass.getCanonicalName() + ", got " + ctrs.length); 229 } 230 231 try { 232 Object inst = ctrs[0].newInstance(); 233 return new ConstantCallSite(MethodHandles.constant(samBase, inst)); 234 } catch (ReflectiveOperationException e) { 235 throw new LambdaConversionException("Exception instantiating lambda object", e); 236 } 237 } else { 238 try { 239 MethodHandle mh = caller.findConstructor(innerClass, invokedType.changeReturnType(void.class)); 240 return new ConstantCallSite(mh.asType(invokedType)); 241 } catch (ReflectiveOperationException e) { 242 throw new LambdaConversionException("Exception finding constructor", e); 243 } 244 } 245 } 246 247 /** Spins the lambda proxy class. 248 * 249 * This first checks if a lambda proxy class can be loaded from CDS archive. 250 * Otherwise, generate the lambda proxy class. If CDS dumping is enabled, it 251 * registers the lambda proxy class for including into the CDS archive. 252 */ 253 private Class<?> spinInnerClass() throws LambdaConversionException { 254 // include lambda proxy class in CDS archive at dump time 255 if (LambdaProxyClassArchive.isDumpArchive()) { 256 Class<?> innerClass = generateInnerClass(); 257 LambdaProxyClassArchive.register(targetClass, 258 samMethodName, 259 invokedType, 260 samMethodType, 261 implMethod, 262 instantiatedMethodType, 263 isSerializable, 264 markerInterfaces, 265 additionalBridges, 266 innerClass); 267 return innerClass; 268 } 269 270 // load from CDS archive if present 271 Class<?> innerClass = LambdaProxyClassArchive.find(targetClass, 272 samMethodName, 273 invokedType, 274 samMethodType, 275 implMethod, 276 instantiatedMethodType, 277 isSerializable, 278 markerInterfaces, 279 additionalBridges, 280 !disableEagerInitialization); 281 if (innerClass == null) { 282 innerClass = generateInnerClass(); 283 } 284 return innerClass; 285 } 286 287 /** 288 * Generate a class file which implements the functional 289 * interface, define and return the class. 290 * 291 * @implNote The class that is generated does not include signature 292 * information for exceptions that may be present on the SAM method. 293 * This is to reduce classfile size, and is harmless as checked exceptions 294 * are erased anyway, no one will ever compile against this classfile, 295 * and we make no guarantees about the reflective properties of lambda 296 * objects. 297 * 298 * @return a Class which implements the functional interface 299 * @throws LambdaConversionException If properly formed functional interface 300 * is not found 301 */ 302 private Class<?> generateInnerClass() throws LambdaConversionException { 303 String[] interfaces; 304 String samIntf = samBase.getName().replace('.', '/'); 305 boolean accidentallySerializable = !isSerializable && Serializable.class.isAssignableFrom(samBase); 306 if (markerInterfaces.length == 0) { 307 interfaces = new String[]{samIntf}; 308 } else { 309 // Assure no duplicate interfaces (ClassFormatError) 310 Set<String> itfs = new LinkedHashSet<>(markerInterfaces.length + 1); 311 itfs.add(samIntf); 312 for (Class<?> markerInterface : markerInterfaces) { 313 itfs.add(markerInterface.getName().replace('.', '/')); 314 accidentallySerializable |= !isSerializable && Serializable.class.isAssignableFrom(markerInterface); 315 } 316 interfaces = itfs.toArray(new String[itfs.size()]); 317 } 318 319 cw.visit(CLASSFILE_VERSION, ACC_SUPER + ACC_FINAL + ACC_SYNTHETIC, 320 lambdaClassName, null, 321 JAVA_LANG_OBJECT, interfaces); 322 323 // Generate final fields to be filled in by constructor 324 for (int i = 0; i < argDescs.length; i++) { 325 FieldVisitor fv = cw.visitField(ACC_PRIVATE + ACC_FINAL, 326 argNames[i], 327 argDescs[i], 328 null, null); 329 fv.visitEnd(); 330 } 331 332 generateConstructor(); 333 334 // Forward the SAM method 335 MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, samMethodName, 336 samMethodType.toMethodDescriptorString(), null, null); 337 new ForwardingMethodGenerator(mv).generate(samMethodType); 338 339 // Forward the bridges 340 if (additionalBridges != null) { 341 for (MethodType mt : additionalBridges) { 342 mv = cw.visitMethod(ACC_PUBLIC|ACC_BRIDGE, samMethodName, 343 mt.toMethodDescriptorString(), null, null); 344 new ForwardingMethodGenerator(mv).generate(mt); 345 } 346 } 347 348 if (useImplMethodHandle) { 349 FieldVisitor fv = cw.visitField(ACC_PRIVATE + ACC_STATIC, 350 NAME_FIELD_IMPL_METHOD, 351 DESCR_METHOD_HANDLE, 352 null, null); 353 fv.visitEnd(); 354 } 355 356 if (isSerializable) 357 generateSerializationFriendlyMethods(); 358 else if (accidentallySerializable) 359 generateSerializationHostileMethods(); 360 361 cw.visitEnd(); 362 363 // Define the generated class in this VM. 364 365 final byte[] classBytes = cw.toByteArray(); 366 // If requested, dump out to a file for debugging purposes 367 if (dumper != null) { 368 AccessController.doPrivileged(new PrivilegedAction<>() { 369 @Override 370 public Void run() { 371 dumper.dumpClass(lambdaClassName, classBytes); 372 return null; 373 } 374 }, null, 375 new FilePermission("<<ALL FILES>>", "read, write"), 376 // createDirectories may need it 377 new PropertyPermission("user.dir", "read")); 378 } 379 try { 380 // this class is linked at the indy callsite; so define a hidden nestmate 381 Lookup lookup = caller.defineHiddenClass(classBytes, !disableEagerInitialization, NESTMATE, STRONG); 382 if (useImplMethodHandle) { 383 // If the target class invokes a method reference this::m which is 384 // resolved to a protected method inherited from a superclass in a different 385 // package, the target class does not have a bridge and this method reference 386 // has been changed from public to protected after the target class was compiled. 387 // This lambda proxy class has no access to the resolved method. 388 // So this workaround by passing the live implMethod method handle 389 // to the proxy class to invoke directly. 390 MethodHandle mh = lookup.findStaticSetter(lookup.lookupClass(), NAME_FIELD_IMPL_METHOD, MethodHandle.class); 391 mh.invokeExact(implMethod); 392 } 393 return lookup.lookupClass(); 394 } catch (IllegalAccessException e) { 395 throw new LambdaConversionException("Exception defining lambda proxy class", e); 396 } catch (Throwable t) { 397 throw new InternalError(t); 398 } 399 } 400 401 /** 402 * Generate the constructor for the class 403 */ 404 private void generateConstructor() { 405 // Generate constructor 406 MethodVisitor ctor = cw.visitMethod(ACC_PRIVATE, NAME_CTOR, 407 constructorType.toMethodDescriptorString(), null, null); 408 ctor.visitCode(); 409 ctor.visitVarInsn(ALOAD, 0); 410 ctor.visitMethodInsn(INVOKESPECIAL, JAVA_LANG_OBJECT, NAME_CTOR, 411 METHOD_DESCRIPTOR_VOID, false); 412 int parameterCount = invokedType.parameterCount(); 413 for (int i = 0, lvIndex = 0; i < parameterCount; i++) { 414 ctor.visitVarInsn(ALOAD, 0); 415 Class<?> argType = invokedType.parameterType(i); 416 ctor.visitVarInsn(getLoadOpcode(argType), lvIndex + 1); 417 lvIndex += getParameterSize(argType); 418 ctor.visitFieldInsn(PUTFIELD, lambdaClassName, argNames[i], argDescs[i]); 419 } 420 ctor.visitInsn(RETURN); 421 // Maxs computed by ClassWriter.COMPUTE_MAXS, these arguments ignored 422 ctor.visitMaxs(-1, -1); 423 ctor.visitEnd(); 424 } 425 426 /** 427 * Generate a writeReplace method that supports serialization 428 */ 429 private void generateSerializationFriendlyMethods() { 430 TypeConvertingMethodAdapter mv 431 = new TypeConvertingMethodAdapter( 432 cw.visitMethod(ACC_PRIVATE + ACC_FINAL, 433 NAME_METHOD_WRITE_REPLACE, DESCR_METHOD_WRITE_REPLACE, 434 null, null)); 435 436 mv.visitCode(); 437 mv.visitTypeInsn(NEW, NAME_SERIALIZED_LAMBDA); 438 mv.visitInsn(DUP); 439 mv.visitLdcInsn(Type.getType(targetClass)); 440 mv.visitLdcInsn(invokedType.returnType().getName().replace('.', '/')); 441 mv.visitLdcInsn(samMethodName); 442 mv.visitLdcInsn(samMethodType.toMethodDescriptorString()); 443 mv.visitLdcInsn(implInfo.getReferenceKind()); 444 mv.visitLdcInsn(implInfo.getDeclaringClass().getName().replace('.', '/')); 445 mv.visitLdcInsn(implInfo.getName()); 446 mv.visitLdcInsn(implInfo.getMethodType().toMethodDescriptorString()); 447 mv.visitLdcInsn(instantiatedMethodType.toMethodDescriptorString()); 448 mv.iconst(argDescs.length); 449 mv.visitTypeInsn(ANEWARRAY, JAVA_LANG_OBJECT); 450 for (int i = 0; i < argDescs.length; i++) { 451 mv.visitInsn(DUP); 452 mv.iconst(i); 453 mv.visitVarInsn(ALOAD, 0); 454 mv.visitFieldInsn(GETFIELD, lambdaClassName, argNames[i], argDescs[i]); 455 mv.boxIfTypePrimitive(Type.getType(argDescs[i])); 456 mv.visitInsn(AASTORE); 457 } 458 mv.visitMethodInsn(INVOKESPECIAL, NAME_SERIALIZED_LAMBDA, NAME_CTOR, 459 DESCR_CTOR_SERIALIZED_LAMBDA, false); 460 mv.visitInsn(ARETURN); 461 // Maxs computed by ClassWriter.COMPUTE_MAXS, these arguments ignored 462 mv.visitMaxs(-1, -1); 463 mv.visitEnd(); 464 } 465 466 /** 467 * Generate a readObject/writeObject method that is hostile to serialization 468 */ 469 private void generateSerializationHostileMethods() { 470 MethodVisitor mv = cw.visitMethod(ACC_PRIVATE + ACC_FINAL, 471 NAME_METHOD_WRITE_OBJECT, DESCR_METHOD_WRITE_OBJECT, 472 null, SER_HOSTILE_EXCEPTIONS); 473 mv.visitCode(); 474 mv.visitTypeInsn(NEW, NAME_NOT_SERIALIZABLE_EXCEPTION); 475 mv.visitInsn(DUP); 476 mv.visitLdcInsn("Non-serializable lambda"); 477 mv.visitMethodInsn(INVOKESPECIAL, NAME_NOT_SERIALIZABLE_EXCEPTION, NAME_CTOR, 478 DESCR_CTOR_NOT_SERIALIZABLE_EXCEPTION, false); 479 mv.visitInsn(ATHROW); 480 mv.visitMaxs(-1, -1); 481 mv.visitEnd(); 482 483 mv = cw.visitMethod(ACC_PRIVATE + ACC_FINAL, 484 NAME_METHOD_READ_OBJECT, DESCR_METHOD_READ_OBJECT, 485 null, SER_HOSTILE_EXCEPTIONS); 486 mv.visitCode(); 487 mv.visitTypeInsn(NEW, NAME_NOT_SERIALIZABLE_EXCEPTION); 488 mv.visitInsn(DUP); 489 mv.visitLdcInsn("Non-serializable lambda"); 490 mv.visitMethodInsn(INVOKESPECIAL, NAME_NOT_SERIALIZABLE_EXCEPTION, NAME_CTOR, 491 DESCR_CTOR_NOT_SERIALIZABLE_EXCEPTION, false); 492 mv.visitInsn(ATHROW); 493 mv.visitMaxs(-1, -1); 494 mv.visitEnd(); 495 } 496 497 /** 498 * This class generates a method body which calls the lambda implementation 499 * method, converting arguments, as needed. 500 */ 501 private class ForwardingMethodGenerator extends TypeConvertingMethodAdapter { 502 503 ForwardingMethodGenerator(MethodVisitor mv) { 504 super(mv); 505 } 506 507 void generate(MethodType methodType) { 508 visitCode(); 509 510 if (implKind == MethodHandleInfo.REF_newInvokeSpecial) { 511 visitTypeInsn(NEW, implMethodClassName); 512 visitInsn(DUP); 513 } 514 if (useImplMethodHandle) { 515 visitVarInsn(ALOAD, 0); 516 visitFieldInsn(GETSTATIC, lambdaClassName, NAME_FIELD_IMPL_METHOD, DESCR_METHOD_HANDLE); 517 } 518 for (int i = 0; i < argNames.length; i++) { 519 visitVarInsn(ALOAD, 0); 520 visitFieldInsn(GETFIELD, lambdaClassName, argNames[i], argDescs[i]); 521 } 522 523 convertArgumentTypes(methodType); 524 525 if (useImplMethodHandle) { 526 MethodType mtype = implInfo.getMethodType().insertParameterTypes(0, implClass); 527 visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandle", 528 "invokeExact", mtype.descriptorString(), false); 529 } else { 530 // Invoke the method we want to forward to 531 visitMethodInsn(invocationOpcode(), implMethodClassName, 532 implMethodName, implMethodDesc, 533 implClass.isInterface()); 534 } 535 // Convert the return value (if any) and return it 536 // Note: if adapting from non-void to void, the 'return' 537 // instruction will pop the unneeded result 538 Class<?> implReturnClass = implMethodType.returnType(); 539 Class<?> samReturnClass = methodType.returnType(); 540 convertType(implReturnClass, samReturnClass, samReturnClass); 541 visitInsn(getReturnOpcode(samReturnClass)); 542 // Maxs computed by ClassWriter.COMPUTE_MAXS,these arguments ignored 543 visitMaxs(-1, -1); 544 visitEnd(); 545 } 546 547 private void convertArgumentTypes(MethodType samType) { 548 int lvIndex = 0; 549 int samParametersLength = samType.parameterCount(); 550 int captureArity = invokedType.parameterCount(); 551 for (int i = 0; i < samParametersLength; i++) { 552 Class<?> argType = samType.parameterType(i); 553 visitVarInsn(getLoadOpcode(argType), lvIndex + 1); 554 lvIndex += getParameterSize(argType); 555 convertType(argType, implMethodType.parameterType(captureArity + i), instantiatedMethodType.parameterType(i)); 556 } 557 } 558 559 private int invocationOpcode() throws InternalError { 560 switch (implKind) { 561 case MethodHandleInfo.REF_invokeStatic: 562 return INVOKESTATIC; 563 case MethodHandleInfo.REF_newInvokeSpecial: 564 return INVOKESPECIAL; 565 case MethodHandleInfo.REF_invokeVirtual: 566 return INVOKEVIRTUAL; 567 case MethodHandleInfo.REF_invokeInterface: 568 return INVOKEINTERFACE; 569 case MethodHandleInfo.REF_invokeSpecial: 570 return INVOKESPECIAL; 571 default: 572 throw new InternalError("Unexpected invocation kind: " + implKind); 573 } 574 } 575 } 576 577 static int getParameterSize(Class<?> c) { 578 if (c == Void.TYPE) { 579 return 0; 580 } else if (c == Long.TYPE || c == Double.TYPE) { 581 return 2; 582 } 583 return 1; 584 } 585 586 static int getLoadOpcode(Class<?> c) { 587 if(c == Void.TYPE) { 588 throw new InternalError("Unexpected void type of load opcode"); 589 } 590 return ILOAD + getOpcodeOffset(c); 591 } 592 593 static int getReturnOpcode(Class<?> c) { 594 if(c == Void.TYPE) { 595 return RETURN; 596 } 597 return IRETURN + getOpcodeOffset(c); 598 } 599 600 private static int getOpcodeOffset(Class<?> c) { 601 if (c.isPrimitive()) { 602 if (c == Long.TYPE) { 603 return 1; 604 } else if (c == Float.TYPE) { 605 return 2; 606 } else if (c == Double.TYPE) { 607 return 3; 608 } 609 return 0; 610 } else { 611 return 4; 612 } 613 } 614 615 }