diff options
Diffstat (limited to 'java/com/google/devtools/build/android/desugar/LambdaClassFixer.java')
-rw-r--r-- | java/com/google/devtools/build/android/desugar/LambdaClassFixer.java | 98 |
1 files changed, 42 insertions, 56 deletions
diff --git a/java/com/google/devtools/build/android/desugar/LambdaClassFixer.java b/java/com/google/devtools/build/android/desugar/LambdaClassFixer.java index e942c95..97c0249 100644 --- a/java/com/google/devtools/build/android/desugar/LambdaClassFixer.java +++ b/java/com/google/devtools/build/android/desugar/LambdaClassFixer.java @@ -27,6 +27,7 @@ import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.FieldVisitor; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; +import org.objectweb.asm.Type; import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.MethodNode; import org.objectweb.asm.tree.TypeInsnNode; @@ -40,10 +41,8 @@ import org.objectweb.asm.tree.TypeInsnNode; */ class LambdaClassFixer extends ClassVisitor { - /** Magic method name used by {@link java.lang.invoke.LambdaMetafactory}. */ + /** Magic method name used by {@link java.lang.invoke.LambdaMetafactory} */ public static final String FACTORY_METHOD_NAME = "get$Lambda"; - /** Field name we'll use to hold singleton instances where possible. */ - public static final String SINGLETON_FIELD_NAME = "$instance"; private final LambdaInfo lambdaInfo; private final ClassReaderFactory factory; @@ -52,7 +51,7 @@ class LambdaClassFixer extends ClassVisitor { private final HashSet<String> implementedMethods = new HashSet<>(); private final LinkedHashSet<String> methodsToMoveIn = new LinkedHashSet<>(); - private String originalInternalName; + private String internalName; private ImmutableList<String> interfaces; private boolean hasState; @@ -60,6 +59,7 @@ class LambdaClassFixer extends ClassVisitor { private String desc; private String signature; + private String[] exceptions; public LambdaClassFixer(ClassVisitor dest, LambdaInfo lambdaInfo, ClassReaderFactory factory, @@ -71,6 +71,10 @@ class LambdaClassFixer extends ClassVisitor { this.allowDefaultMethods = allowDefaultMethods; } + public String getInternalName() { + return internalName; + } + @Override public void visit( int version, @@ -80,15 +84,15 @@ class LambdaClassFixer extends ClassVisitor { String superName, String[] interfaces) { checkArgument(BitFlags.noneSet(access, Opcodes.ACC_INTERFACE), "Not a class: %s", name); - checkState(this.originalInternalName == null, "not intended for reuse but reused for %s", name); - originalInternalName = name; + checkState(internalName == null, "Already visited %s, can't reuse for %s", internalName, name); + internalName = name; hasState = false; hasFactory = false; desc = null; this.signature = null; + exceptions = null; this.interfaces = ImmutableList.copyOf(interfaces); - // Rename to desired name - super.visit(version, access, getInternalName(), signature, superName, interfaces); + super.visit(version, access, name, signature, superName, interfaces); } @Override @@ -121,6 +125,7 @@ class LambdaClassFixer extends ClassVisitor { } else if ("<init>".equals(name)) { this.desc = desc; this.signature = signature; + this.exceptions = exceptions; } MethodVisitor methodVisitor = new LambdaClassMethodRewriter(super.visitMethod(access, name, desc, signature, exceptions)); @@ -138,19 +143,17 @@ class LambdaClassFixer extends ClassVisitor { @Override public void visitEnd() { checkState(!hasState || hasFactory, - "Expected factory method for capturing lambda %s", getInternalName()); - if (!hasState) { + "Expected factory method for capturing lambda %s", internalName); + if (!hasFactory) { + // Fake factory method if LambdaMetafactory didn't generate it checkState(signature == null, - "Didn't expect generic constructor signature %s %s", getInternalName(), signature); - checkState(lambdaInfo.factoryMethodDesc().startsWith("()"), - "Expected 0-arg factory method for %s but found %s", getInternalName(), - lambdaInfo.factoryMethodDesc()); - // Since this is a stateless class we populate and use a static singleton field "$instance". - // Field is package-private so we can read it from the class that had the invokedynamic. - String singletonFieldDesc = lambdaInfo.factoryMethodDesc().substring("()".length()); + "Didn't expect generic constructor signature %s %s", internalName, signature); + + // Since this is a stateless class we populate and use a static singleton field "$instance" + String singletonFieldDesc = Type.getObjectType(internalName).getDescriptor(); super.visitField( - Opcodes.ACC_STATIC | Opcodes.ACC_FINAL, - SINGLETON_FIELD_NAME, + Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC | Opcodes.ACC_FINAL, + "$instance", singletonFieldDesc, (String) null, (Object) null) @@ -163,28 +166,35 @@ class LambdaClassFixer extends ClassVisitor { "()V", (String) null, new String[0]); - codeBuilder.visitTypeInsn(Opcodes.NEW, getInternalName()); + codeBuilder.visitTypeInsn(Opcodes.NEW, internalName); codeBuilder.visitInsn(Opcodes.DUP); - codeBuilder.visitMethodInsn(Opcodes.INVOKESPECIAL, getInternalName(), "<init>", - checkNotNull(desc, "didn't see a constructor for %s", getInternalName()), /*itf*/ false); - codeBuilder.visitFieldInsn( - Opcodes.PUTSTATIC, getInternalName(), SINGLETON_FIELD_NAME, singletonFieldDesc); + codeBuilder.visitMethodInsn(Opcodes.INVOKESPECIAL, internalName, "<init>", + checkNotNull(desc, "didn't see a constructor for %s", internalName), /*itf*/ false); + codeBuilder.visitFieldInsn(Opcodes.PUTSTATIC, internalName, "$instance", singletonFieldDesc); codeBuilder.visitInsn(Opcodes.RETURN); codeBuilder.visitMaxs(2, 0); // two values are pushed onto the stack codeBuilder.visitEnd(); + + codeBuilder = // reuse codeBuilder variable to avoid accidental additions to previous method + super.visitMethod( + Opcodes.ACC_STATIC, + FACTORY_METHOD_NAME, + lambdaInfo.factoryMethodDesc(), + (String) null, + exceptions); + codeBuilder.visitFieldInsn(Opcodes.GETSTATIC, internalName, "$instance", singletonFieldDesc); + codeBuilder.visitInsn(Opcodes.ARETURN); + codeBuilder.visitMaxs(1, 0); // one value on the stack } copyRewrittenLambdaMethods(); + if (!allowDefaultMethods) { copyBridgeMethods(interfaces); } super.visitEnd(); } - private String getInternalName() { - return lambdaInfo.desiredInternalName(); - } - private void copyRewrittenLambdaMethods() { for (String rewritten : methodsToMoveIn) { String interfaceInternalName = rewritten.substring(0, rewritten.indexOf('#')); @@ -223,41 +233,17 @@ class LambdaClassFixer extends ClassVisitor { // Rewrite invocations of lambda methods in interfaces to anticipate the lambda method being // moved into the lambda class (i.e., the class being visited here). checkArgument(opcode == Opcodes.INVOKESTATIC, "Cannot move instance method %s", method); - owner = getInternalName(); + owner = internalName; itf = false; // owner was interface but is now a class methodsToMoveIn.add(method); - } else { - if (originalInternalName.equals(owner)) { - // Reflect renaming of lambda classes - owner = getInternalName(); - } - if (name.startsWith("lambda$")) { - // Reflect renaming of lambda$ instance methods to avoid accidental overrides - name = LambdaDesugaring.uniqueInPackage(owner, name); - } + } else if (name.startsWith("lambda$")) { + // Reflect renaming of lambda$ instance methods to avoid accidental overrides + name = LambdaDesugaring.uniqueInPackage(owner, name); } super.visitMethodInsn(opcode, owner, name, desc, itf); } @Override - public void visitTypeInsn(int opcode, String type) { - if (originalInternalName.equals(type)) { - // Reflect renaming of lambda classes - type = getInternalName(); - } - super.visitTypeInsn(opcode, type); - } - - @Override - public void visitFieldInsn(int opcode, String owner, String name, String desc) { - if (originalInternalName.equals(owner)) { - // Reflect renaming of lambda classes - owner = getInternalName(); - } - super.visitFieldInsn(opcode, owner, name, desc); - } - - @Override public AnnotationVisitor visitAnnotation(String desc, boolean visible) { // Drop annotation that's part of the generated lambda class that's not available on Android. // Proguard complains about this otherwise. |