184b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael// Copyright 2016 The Bazel Authors. All rights reserved. 284b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael// 384b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael// Licensed under the Apache License, Version 2.0 (the "License"); 484b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael// you may not use this file except in compliance with the License. 584b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael// You may obtain a copy of the License at 684b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael// 784b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael// http://www.apache.org/licenses/LICENSE-2.0 884b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael// 984b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael// Unless required by applicable law or agreed to in writing, software 1084b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael// distributed under the License is distributed on an "AS IS" BASIS, 1184b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1284b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael// See the License for the specific language governing permissions and 1384b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael// limitations under the License. 1484b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michaelpackage com.google.devtools.build.android.desugar; 1584b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael 1684b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michaelimport static com.google.common.base.Preconditions.checkArgument; 1784b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michaelimport static com.google.common.base.Preconditions.checkNotNull; 1884b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michaelimport static com.google.common.base.Preconditions.checkState; 1984b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michaelimport static java.lang.invoke.MethodHandles.publicLookup; 2084b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michaelimport static org.objectweb.asm.Opcodes.ASM5; 2184b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael 2284b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michaelimport com.google.auto.value.AutoValue; 2384b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michaelimport com.google.common.collect.ImmutableSet; 2484b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michaelimport java.io.IOException; 2584b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michaelimport java.lang.invoke.MethodHandle; 2684b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michaelimport java.lang.invoke.MethodHandles.Lookup; 2784b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michaelimport java.lang.invoke.MethodType; 2884b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michaelimport java.lang.reflect.Constructor; 2984b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michaelimport java.lang.reflect.Executable; 3084b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michaelimport java.lang.reflect.Method; 3184b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michaelimport java.lang.reflect.Modifier; 3284b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michaelimport java.util.ArrayList; 3384b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michaelimport java.util.Arrays; 3484b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michaelimport java.util.HashMap; 3584b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michaelimport java.util.Map; 3684b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michaelimport javax.annotation.Nullable; 3784b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michaelimport org.objectweb.asm.ClassVisitor; 3884b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michaelimport org.objectweb.asm.Handle; 3984b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michaelimport org.objectweb.asm.MethodVisitor; 4084b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michaelimport org.objectweb.asm.Opcodes; 4184b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michaelimport org.objectweb.asm.Type; 4284b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael 4384b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael/** 4484b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael * Visitor that desugars classes with uses of lambdas into Java 7-looking code. This includes 4584b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael * rewriting lambda-related invokedynamic instructions as well as fixing accessibility of methods 4684b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael * that javac emits for lambda bodies. 4784b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael */ 4884b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michaelclass LambdaDesugaring extends ClassVisitor { 4984b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael 5084b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael private final ClassLoader targetLoader; 5184b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael private final LambdaClassMaker lambdas; 5284b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael private final ImmutableSet.Builder<String> aggregateInterfaceLambdaMethods; 5384b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael private final Map<Handle, MethodReferenceBridgeInfo> bridgeMethods = new HashMap<>(); 540d1939c7699eea03e166574d0852e91a054ac0daColin Cross private final boolean allowDefaultMethods; 5584b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael 5684b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael private String internalName; 5784b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael private boolean isInterface; 58d3371d01485317d82c584e39838f6cf565076a68Googler private int lambdaCount; 5984b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael 600d1939c7699eea03e166574d0852e91a054ac0daColin Cross public LambdaDesugaring( 610d1939c7699eea03e166574d0852e91a054ac0daColin Cross ClassVisitor dest, 620d1939c7699eea03e166574d0852e91a054ac0daColin Cross ClassLoader targetLoader, 630d1939c7699eea03e166574d0852e91a054ac0daColin Cross LambdaClassMaker lambdas, 640d1939c7699eea03e166574d0852e91a054ac0daColin Cross ImmutableSet.Builder<String> aggregateInterfaceLambdaMethods, 650d1939c7699eea03e166574d0852e91a054ac0daColin Cross boolean allowDefaultMethods) { 6684b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael super(Opcodes.ASM5, dest); 6784b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael this.targetLoader = targetLoader; 6884b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael this.lambdas = lambdas; 6984b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael this.aggregateInterfaceLambdaMethods = aggregateInterfaceLambdaMethods; 700d1939c7699eea03e166574d0852e91a054ac0daColin Cross this.allowDefaultMethods = allowDefaultMethods; 7184b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael } 7284b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael 7384b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael @Override 7484b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael public void visit( 7584b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael int version, 7684b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael int access, 7784b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael String name, 7884b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael String signature, 7984b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael String superName, 8084b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael String[] interfaces) { 81d3371d01485317d82c584e39838f6cf565076a68Googler checkState(internalName == null, "not intended for reuse but reused for %s", name); 8284b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael internalName = name; 8384b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael isInterface = BitFlags.isSet(access, Opcodes.ACC_INTERFACE); 8484b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael super.visit(version, access, name, signature, superName, interfaces); 8584b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael } 8684b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael 8784b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael @Override 8884b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael public void visitEnd() { 8984b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael for (Map.Entry<Handle, MethodReferenceBridgeInfo> bridge : bridgeMethods.entrySet()) { 9084b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael Handle original = bridge.getKey(); 9184b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael Handle neededMethod = bridge.getValue().bridgeMethod(); 9284b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael checkState(neededMethod.getTag() == Opcodes.H_INVOKESTATIC 9384b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael || neededMethod.getTag() == Opcodes.H_INVOKEVIRTUAL, 9484b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael "Cannot generate bridge method %s to reach %s", neededMethod, original); 9584b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael checkState(bridge.getValue().referenced() != null, 9684b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael "Need referenced method %s to generate bridge %s", original, neededMethod); 9784b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael 9884b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael int access = Opcodes.ACC_BRIDGE | Opcodes.ACC_SYNTHETIC | Opcodes.ACC_FINAL; 9984b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael if (neededMethod.getTag() == Opcodes.H_INVOKESTATIC) { 10084b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael access |= Opcodes.ACC_STATIC; 10184b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael } 10284b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael MethodVisitor bridgeMethod = 10384b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael super.visitMethod( 10484b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael access, 10584b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael neededMethod.getName(), 10684b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael neededMethod.getDesc(), 10784b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael (String) null, 10884b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael toInternalNames(bridge.getValue().referenced().getExceptionTypes())); 10984b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael 11084b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael // Bridge is a factory method calling a constructor 11184b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael if (original.getTag() == Opcodes.H_NEWINVOKESPECIAL) { 11284b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael bridgeMethod.visitTypeInsn(Opcodes.NEW, original.getOwner()); 11384b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael bridgeMethod.visitInsn(Opcodes.DUP); 11484b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael } 11584b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael 11684b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael int slot = 0; 11784b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael if (neededMethod.getTag() != Opcodes.H_INVOKESTATIC) { 11884b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael bridgeMethod.visitVarInsn(Opcodes.ALOAD, slot++); 11984b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael } 12084b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael Type neededType = Type.getMethodType(neededMethod.getDesc()); 12184b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael for (Type arg : neededType.getArgumentTypes()) { 12284b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael bridgeMethod.visitVarInsn(arg.getOpcode(Opcodes.ILOAD), slot); 12384b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael slot += arg.getSize(); 12484b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael } 12584b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael bridgeMethod.visitMethodInsn(invokeOpcode(original), original.getOwner(), original.getName(), 12684b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael original.getDesc(), original.isInterface()); 12784b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael bridgeMethod.visitInsn(neededType.getReturnType().getOpcode(Opcodes.IRETURN)); 12884b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael 12984b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael bridgeMethod.visitMaxs(0, 0); // rely on class writer to compute these 13084b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael bridgeMethod.visitEnd(); 13184b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael } 13284b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael super.visitEnd(); 13384b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael } 13484b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael 13584b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael @Override 13684b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael public MethodVisitor visitMethod( 13784b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael int access, String name, String desc, String signature, String[] exceptions) { 13884b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael if (name.equals("$deserializeLambda$") && BitFlags.isSet(access, Opcodes.ACC_SYNTHETIC)) { 13984b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael // Android doesn't do anything special for lambda serialization so drop the special 14084b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael // deserialization hook that javac generates. This also makes sure we don't reference 14184b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael // java/lang/invoke/SerializedLambda, which doesn't exist on Android. 14284b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael return null; 14384b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael } 14484b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael if (name.startsWith("lambda$") && BitFlags.isSet(access, Opcodes.ACC_SYNTHETIC)) { 1450d1939c7699eea03e166574d0852e91a054ac0daColin Cross if (!allowDefaultMethods && isInterface && BitFlags.isSet(access, Opcodes.ACC_STATIC)) { 14684b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael // There must be a lambda in the interface (which in the absence of hand-written default or 14784b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael // static interface methods must mean it's in the <clinit> method or inside another lambda). 14884b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael // We'll move this method out of this class, so just record and drop it here. 14984b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael // (Note lambda body methods have unique names, so we don't need to remember desc here.) 15084b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael aggregateInterfaceLambdaMethods.add(internalName + '#' + name); 15184b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael return null; 15284b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael } 15384b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael if (BitFlags.isSet(access, Opcodes.ACC_PRIVATE)) { 15484b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael // Make lambda body method accessible from lambda class 15584b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael access &= ~Opcodes.ACC_PRIVATE; 1560d1939c7699eea03e166574d0852e91a054ac0daColin Cross if (allowDefaultMethods && isInterface) { 1570d1939c7699eea03e166574d0852e91a054ac0daColin Cross // java 8 requires interface methods to have exactly one of ACC_PUBLIC and ACC_PRIVATE 1580d1939c7699eea03e166574d0852e91a054ac0daColin Cross access |= Opcodes.ACC_PUBLIC; 1590d1939c7699eea03e166574d0852e91a054ac0daColin Cross } else { 1600d1939c7699eea03e166574d0852e91a054ac0daColin Cross // Method was private so it can be final, which should help VMs perform dispatch. 1610d1939c7699eea03e166574d0852e91a054ac0daColin Cross access |= Opcodes.ACC_FINAL; 1620d1939c7699eea03e166574d0852e91a054ac0daColin Cross } 16384b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael } 1640ccdd4c939408a7f4d0adbfbed90031e75021e63Googler // Guarantee unique lambda body method name to avoid accidental overriding. This wouldn't be 1650ccdd4c939408a7f4d0adbfbed90031e75021e63Googler // be necessary for static methods but in visitOuterClass we don't know whether a potential 1660ccdd4c939408a7f4d0adbfbed90031e75021e63Googler // outer lambda$ method is static or not, so we just always do it. 1670ccdd4c939408a7f4d0adbfbed90031e75021e63Googler name = uniqueInPackage(internalName, name); 16884b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael } 16984b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael MethodVisitor dest = super.visitMethod(access, name, desc, signature, exceptions); 17084b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael return new InvokedynamicRewriter(dest); 17184b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael } 17284b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael 1730ccdd4c939408a7f4d0adbfbed90031e75021e63Googler @Override 1740ccdd4c939408a7f4d0adbfbed90031e75021e63Googler public void visitOuterClass(String owner, String name, String desc) { 1750ccdd4c939408a7f4d0adbfbed90031e75021e63Googler if (name != null && name.startsWith("lambda$")) { 1760ccdd4c939408a7f4d0adbfbed90031e75021e63Googler // Reflect renaming of lambda$ methods. Proguard gets grumpy if we leave this inconsistent. 1770ccdd4c939408a7f4d0adbfbed90031e75021e63Googler name = uniqueInPackage(owner, name); 1780ccdd4c939408a7f4d0adbfbed90031e75021e63Googler } 1790ccdd4c939408a7f4d0adbfbed90031e75021e63Googler super.visitOuterClass(owner, name, desc); 1800ccdd4c939408a7f4d0adbfbed90031e75021e63Googler } 1810ccdd4c939408a7f4d0adbfbed90031e75021e63Googler 1820ccdd4c939408a7f4d0adbfbed90031e75021e63Googler static String uniqueInPackage(String owner, String name) { 1830ccdd4c939408a7f4d0adbfbed90031e75021e63Googler String suffix = "$" + owner.substring(owner.lastIndexOf('/') + 1); 1840ccdd4c939408a7f4d0adbfbed90031e75021e63Googler // For idempotency, we only attach the package-unique suffix if it isn't there already. This 1850ccdd4c939408a7f4d0adbfbed90031e75021e63Googler // prevents a cumulative effect when processing a class more than once (which can happen with 1860ccdd4c939408a7f4d0adbfbed90031e75021e63Googler // Bazel, e.g., when re-importing a deploy.jar). During reprocessing, invokedynamics are 1870ccdd4c939408a7f4d0adbfbed90031e75021e63Googler // already removed, so lambda$ methods have regular call sites that we would also have to re- 1880ccdd4c939408a7f4d0adbfbed90031e75021e63Googler // adjust if we just blindly appended something to lambda$ method names every time we see them. 1890ccdd4c939408a7f4d0adbfbed90031e75021e63Googler return name.endsWith(suffix) ? name : name + suffix; 1900ccdd4c939408a7f4d0adbfbed90031e75021e63Googler } 1910ccdd4c939408a7f4d0adbfbed90031e75021e63Googler 19284b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael /** 19384b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael * Makes {@link #visitEnd} generate a bridge method for the given method handle if the 19484b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael * referenced method will be invisible to the generated lambda class. 19584b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael * 19684b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael * @return struct containing either {@code invokedMethod} or {@code invokedMethod} and a handle 19784b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael * representing the bridge method that will be generated for {@code invokedMethod}. 19884b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael */ 19984b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael private MethodReferenceBridgeInfo queueUpBridgeMethodIfNeeded(Handle invokedMethod) 20084b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael throws ClassNotFoundException { 20184b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael if (invokedMethod.getName().startsWith("lambda$")) { 20284b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael // We adjust lambda bodies to be visible 20384b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael return MethodReferenceBridgeInfo.noBridge(invokedMethod); 20484b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael } 20584b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael 20684b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael // invokedMethod is a method reference if we get here 20784b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael Executable invoked = findTargetMethod(invokedMethod); 20884b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael if (isVisibleToLambdaClass(invoked, invokedMethod.getOwner())) { 20984b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael // Referenced method is visible to the generated class, so nothing to do 21084b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael return MethodReferenceBridgeInfo.noBridge(invokedMethod); 21184b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael } 21284b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael 21384b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael // We need a bridge method if we get here 21484b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael checkState(!isInterface, 21584b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael "%s is an interface and shouldn't need bridge to %s", internalName, invokedMethod); 21684b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael checkState(!invokedMethod.isInterface(), 21784b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael "%s's lambda classes can't see interface method: %s", internalName, invokedMethod); 21884b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael MethodReferenceBridgeInfo result = bridgeMethods.get(invokedMethod); 21984b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael if (result != null) { 22084b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael return result; // we're already queued up a bridge method for this method reference 22184b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael } 22284b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael 2238264d43883171b6c0233ec9d2bdd17c614027e91Kevin Bierhoff String name = uniqueInPackage(internalName, "bridge$lambda$" + bridgeMethods.size()); 22484b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael Handle bridgeMethod; 22584b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael switch (invokedMethod.getTag()) { 22684b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael case Opcodes.H_INVOKESTATIC: 22784b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael bridgeMethod = new Handle(invokedMethod.getTag(), internalName, name, 22884b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael invokedMethod.getDesc(), /*itf*/ false); 22984b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael break; 23084b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael case Opcodes.H_INVOKEVIRTUAL: 23184b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael case Opcodes.H_INVOKESPECIAL: // we end up calling these using invokevirtual 23284b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael bridgeMethod = new Handle(Opcodes.H_INVOKEVIRTUAL, internalName, name, 23384b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael invokedMethod.getDesc(), /*itf*/ false); 23484b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael break; 23584b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael case Opcodes.H_NEWINVOKESPECIAL: { 23684b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael // Call invisible constructor through generated bridge "factory" method, so we need to 23784b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael // compute the descriptor for the bridge method from the constructor's descriptor 23884b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael String desc = 23984b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael Type.getMethodDescriptor( 24084b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael Type.getObjectType(invokedMethod.getOwner()), 24184b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael Type.getArgumentTypes(invokedMethod.getDesc())); 24284b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael bridgeMethod = new Handle(Opcodes.H_INVOKESTATIC, internalName, name, desc, /*itf*/ false); 24384b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael break; 24484b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael } 24584b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael case Opcodes.H_INVOKEINTERFACE: 24684b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael // Shouldn't get here 24784b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael default: 24884b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael throw new UnsupportedOperationException("Cannot bridge " + invokedMethod); 24984b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael } 25084b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael result = MethodReferenceBridgeInfo.bridge(invokedMethod, invoked, bridgeMethod); 25184b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael MethodReferenceBridgeInfo old = bridgeMethods.put(invokedMethod, result); 25284b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael checkState(old == null, "Already had bridge %s so we don't also want %s", old, result); 25384b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael return result; 25484b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael } 25584b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael 25684b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael /** 25784b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael * Checks whether the referenced method would be visible by an unrelated class in the same package 25884b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael * as the currently visited class. 25984b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael */ 26084b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael private boolean isVisibleToLambdaClass(Executable invoked, String owner) { 26184b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael int modifiers = invoked.getModifiers(); 26284b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael if (Modifier.isPrivate(modifiers)) { 26384b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael return false; 26484b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael } 26584b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael if (Modifier.isPublic(modifiers)) { 26684b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael return true; 26784b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael } 26884b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael // invoked is protected or package-private, either way we need it to be in the same package 26984b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael // because the additional visibility protected gives doesn't help lambda classes, which are in 27084b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael // a different class hierarchy (and typically just extend Object) 27184b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael return packageName(internalName).equals(packageName(owner)); 27284b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael } 27384b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael 27484b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael private Executable findTargetMethod(Handle invokedMethod) throws ClassNotFoundException { 27584b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael Type descriptor = Type.getMethodType(invokedMethod.getDesc()); 27684b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael Class<?> owner = loadFromInternal(invokedMethod.getOwner()); 27784b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael if (invokedMethod.getTag() == Opcodes.H_NEWINVOKESPECIAL) { 27884b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael for (Constructor<?> c : owner.getDeclaredConstructors()) { 27984b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael if (Type.getType(c).equals(descriptor)) { 28084b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael return c; 28184b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael } 28284b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael } 28384b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael } else { 28484b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael for (Method m : owner.getDeclaredMethods()) { 28584b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael if (m.getName().equals(invokedMethod.getName()) 28684b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael && Type.getType(m).equals(descriptor)) { 28784b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael return m; 28884b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael } 28984b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael } 29084b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael } 29184b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael throw new IllegalArgumentException("Referenced method not found: " + invokedMethod); 29284b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael } 29384b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael 29484b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael private Class<?> loadFromInternal(String internalName) throws ClassNotFoundException { 29584b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael return targetLoader.loadClass(internalName.replace('/', '.')); 29684b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael } 29784b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael 29884b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael static int invokeOpcode(Handle invokedMethod) { 29984b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael switch (invokedMethod.getTag()) { 30084b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael case Opcodes.H_INVOKESTATIC: 30184b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael return Opcodes.INVOKESTATIC; 30284b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael case Opcodes.H_INVOKEVIRTUAL: 30384b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael return Opcodes.INVOKEVIRTUAL; 30484b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael case Opcodes.H_INVOKESPECIAL: 30584b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael case Opcodes.H_NEWINVOKESPECIAL: // Must be preceded by NEW 30684b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael return Opcodes.INVOKESPECIAL; 30784b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael case Opcodes.H_INVOKEINTERFACE: 30884b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael return Opcodes.INVOKEINTERFACE; 30984b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael default: 31084b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael throw new UnsupportedOperationException("Don't know how to call " + invokedMethod); 31184b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael } 31284b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael } 31384b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael 31484b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael private static String[] toInternalNames(Class<?>[] classes) { 31584b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael String[] result = new String[classes.length]; 31684b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael for (int i = 0; i < classes.length; ++i) { 31784b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael result[i] = Type.getInternalName(classes[i]); 31884b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael } 31984b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael return result; 32084b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael } 32184b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael 32284b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael private static String packageName(String internalClassName) { 32384b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael int lastSlash = internalClassName.lastIndexOf('/'); 32484b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael return lastSlash > 0 ? internalClassName.substring(0, lastSlash) : ""; 32584b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael } 32684b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael 32784b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael /** 32884b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael * Desugaring that replaces invokedynamics for {@link java.lang.invoke.LambdaMetafactory} with 32984b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael * static factory method invocations and triggers a class to be generated for each invokedynamic. 33084b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael */ 33184b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael private class InvokedynamicRewriter extends MethodVisitor { 33284b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael 33384b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael public InvokedynamicRewriter(MethodVisitor dest) { 33484b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael super(ASM5, dest); 33584b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael } 33684b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael 33784b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael @Override 33884b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, Object... bsmArgs) { 33984b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael if (!"java/lang/invoke/LambdaMetafactory".equals(bsm.getOwner())) { 34084b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael // Not an invokedynamic for a lambda expression 34184b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael super.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs); 34284b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael return; 34384b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael } 34484b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael 34584b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael try { 34684b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael Lookup lookup = createLookup(internalName); 34784b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael ArrayList<Object> args = new ArrayList<>(bsmArgs.length + 3); 34884b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael args.add(lookup); 34984b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael args.add(name); 35084b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael args.add(MethodType.fromMethodDescriptorString(desc, targetLoader)); 35184b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael for (Object bsmArg : bsmArgs) { 35284b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael args.add(toJvmMetatype(lookup, bsmArg)); 35384b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael } 35484b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael 35584b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael // Both bootstrap methods in LambdaMetafactory expect a MethodHandle as their 5th argument 35684b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael // so we can assume bsmArgs[1] (the 5th arg) to be a Handle. 35784b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael MethodReferenceBridgeInfo bridgeInfo = queueUpBridgeMethodIfNeeded((Handle) bsmArgs[1]); 35884b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael 35984b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael // Resolve the bootstrap method in "host configuration" (this tool's default classloader) 36084b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael // since targetLoader may only contain stubs that we can't actually execute. 36184b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael // generateLambdaClass() below will invoke the bootstrap method, so a stub isn't enough, 36284b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael // and ultimately we don't care if the bootstrap method was even on the bootclasspath 36384b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael // when this class was compiled (although it must've been since javac is unhappy otherwise). 36484b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael MethodHandle bsmMethod = toMethodHandle(publicLookup(), bsm, /*target*/ false); 365d3371d01485317d82c584e39838f6cf565076a68Googler // Give generated classes to have more stable names (b/35643761). Use BSM's naming scheme 366d3371d01485317d82c584e39838f6cf565076a68Googler // but with separate counter for each surrounding class. 367d3371d01485317d82c584e39838f6cf565076a68Googler String lambdaClassName = internalName + "$$Lambda$" + (lambdaCount++); 368d3371d01485317d82c584e39838f6cf565076a68Googler lambdas.generateLambdaClass( 36984b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael internalName, 370d3371d01485317d82c584e39838f6cf565076a68Googler LambdaInfo.create( 371d3371d01485317d82c584e39838f6cf565076a68Googler lambdaClassName, desc, bridgeInfo.methodReference(), bridgeInfo.bridgeMethod()), 37284b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael bsmMethod, 37384b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael args); 3744e1287358e04b9755dfcf19d9c1c15dc86600554Googler if (desc.startsWith("()")) { 3754e1287358e04b9755dfcf19d9c1c15dc86600554Googler // For stateless lambda classes we'll generate a singleton instance that we can just load 3764e1287358e04b9755dfcf19d9c1c15dc86600554Googler super.visitFieldInsn(Opcodes.GETSTATIC, lambdaClassName, 3774e1287358e04b9755dfcf19d9c1c15dc86600554Googler LambdaClassFixer.SINGLETON_FIELD_NAME, desc.substring("()".length())); 3784e1287358e04b9755dfcf19d9c1c15dc86600554Googler } else { 3794e1287358e04b9755dfcf19d9c1c15dc86600554Googler // Emit invokestatic that calls the factory method generated in the lambda class 3804e1287358e04b9755dfcf19d9c1c15dc86600554Googler super.visitMethodInsn( 3814e1287358e04b9755dfcf19d9c1c15dc86600554Googler Opcodes.INVOKESTATIC, 3824e1287358e04b9755dfcf19d9c1c15dc86600554Googler lambdaClassName, 3834e1287358e04b9755dfcf19d9c1c15dc86600554Googler LambdaClassFixer.FACTORY_METHOD_NAME, 3844e1287358e04b9755dfcf19d9c1c15dc86600554Googler desc, 3854e1287358e04b9755dfcf19d9c1c15dc86600554Googler /*itf*/ false); 3864e1287358e04b9755dfcf19d9c1c15dc86600554Googler } 38784b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael } catch (IOException | ReflectiveOperationException e) { 38884b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael throw new IllegalStateException("Couldn't desugar invokedynamic for " + internalName + "." 38984b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael + name + " using " + bsm + " with arguments " + Arrays.toString(bsmArgs), e); 39084b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael } 39184b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael } 39284b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael 39384b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael private Lookup createLookup(String lookupClass) throws ReflectiveOperationException { 39484b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael Class<?> clazz = loadFromInternal(lookupClass); 39584b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael Constructor<Lookup> constructor = Lookup.class.getDeclaredConstructor(Class.class); 39684b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael constructor.setAccessible(true); 39784b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael return constructor.newInstance(clazz); 39884b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael } 39984b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael 40084b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael /** 40184b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael * Produces a {@link MethodHandle} or {@link MethodType} using {@link #targetLoader} for the 40284b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael * given ASM {@link Handle} or {@link Type}. {@code lookup} is only used for resolving 40384b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael * {@link Handle}s. 40484b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael */ 40584b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael private Object toJvmMetatype(Lookup lookup, Object asm) throws ReflectiveOperationException { 40684b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael if (asm instanceof Number) { 40784b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael return asm; 40884b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael } 40984b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael if (asm instanceof Type) { 41084b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael Type type = (Type) asm; 41184b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael switch (type.getSort()) { 41284b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael case Type.OBJECT: 41384b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael return loadFromInternal(type.getInternalName()); 41484b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael case Type.METHOD: 41584b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael return MethodType.fromMethodDescriptorString(type.getDescriptor(), targetLoader); 41684b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael default: 41784b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael throw new IllegalArgumentException("Cannot convert: " + asm); 41884b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael } 41984b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael } 42084b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael if (asm instanceof Handle) { 42184b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael return toMethodHandle(lookup, (Handle) asm, /*target*/ true); 42284b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael } 42384b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael throw new IllegalArgumentException("Cannot convert: " + asm); 42484b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael } 42584b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael 42684b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael /** 42784b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael * Produces a {@link MethodHandle} using either the context or {@link #targetLoader} class 42884b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael * loader, depending on {@code target}. 42984b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael */ 43084b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael private MethodHandle toMethodHandle(Lookup lookup, Handle asmHandle, boolean target) 43184b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael throws ReflectiveOperationException { 43284b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael Class<?> owner = loadFromInternal(asmHandle.getOwner()); 43384b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael MethodType signature = MethodType.fromMethodDescriptorString(asmHandle.getDesc(), 43484b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael target ? targetLoader : Thread.currentThread().getContextClassLoader()); 43584b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael switch (asmHandle.getTag()) { 43684b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael case Opcodes.H_INVOKESTATIC: 43784b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael return lookup.findStatic(owner, asmHandle.getName(), signature); 43884b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael case Opcodes.H_INVOKEVIRTUAL: 43984b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael case Opcodes.H_INVOKEINTERFACE: 44084b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael return lookup.findVirtual(owner, asmHandle.getName(), signature); 4410d1939c7699eea03e166574d0852e91a054ac0daColin Cross case Opcodes.H_INVOKESPECIAL: // we end up calling these using invokevirtual 4420d1939c7699eea03e166574d0852e91a054ac0daColin Cross return lookup.findSpecial(owner, asmHandle.getName(), signature, owner); 44384b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael case Opcodes.H_NEWINVOKESPECIAL: 44484b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael return lookup.findConstructor(owner, signature); 44584b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael default: 44684b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael throw new UnsupportedOperationException("Cannot resolve " + asmHandle); 44784b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael } 44884b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael } 44984b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael } 45084b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael 45184b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael /** 45284b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael * Record of how a lambda class can reach its referenced method through a possibly-different 45384b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael * bridge method. 45484b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael * 45584b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael * <p>In a JVM, lambda classes are allowed to call the referenced methods directly, but we don't 45684b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael * have that luxury when the generated lambda class is evaluated using normal visibility rules. 45784b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael */ 45884b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael @AutoValue 45984b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael abstract static class MethodReferenceBridgeInfo { 46084b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael public static MethodReferenceBridgeInfo noBridge(Handle methodReference) { 46184b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael return new AutoValue_LambdaDesugaring_MethodReferenceBridgeInfo( 46284b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael methodReference, (Executable) null, methodReference); 46384b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael } 46484b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael public static MethodReferenceBridgeInfo bridge( 46584b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael Handle methodReference, Executable referenced, Handle bridgeMethod) { 46684b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael checkArgument(!bridgeMethod.equals(methodReference)); 46784b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael return new AutoValue_LambdaDesugaring_MethodReferenceBridgeInfo( 46884b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael methodReference, checkNotNull(referenced), bridgeMethod); 46984b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael } 47084b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael 47184b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael public abstract Handle methodReference(); 47284b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael 47384b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael /** Returns {@code null} iff {@link #bridgeMethod} equals {@link #methodReference}. */ 47484b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael @Nullable public abstract Executable referenced(); 47584b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael 47684b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael public abstract Handle bridgeMethod(); 47784b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael } 47884b90b3dc637a33f7f6fac59be21b74ba6fc17d6Adam Michael} 479