aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/tools/android/java/com/google/devtools/build
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools/android/java/com/google/devtools/build')
-rw-r--r--src/tools/android/java/com/google/devtools/build/android/desugar/DefaultMethodClassFixer.java209
-rw-r--r--src/tools/android/java/com/google/devtools/build/android/desugar/Desugar.java7
-rw-r--r--src/tools/android/java/com/google/devtools/build/android/desugar/InterfaceDesugaring.java79
3 files changed, 9 insertions, 286 deletions
diff --git a/src/tools/android/java/com/google/devtools/build/android/desugar/DefaultMethodClassFixer.java b/src/tools/android/java/com/google/devtools/build/android/desugar/DefaultMethodClassFixer.java
index 68f9756735..2563c7a9ab 100644
--- a/src/tools/android/java/com/google/devtools/build/android/desugar/DefaultMethodClassFixer.java
+++ b/src/tools/android/java/com/google/devtools/build/android/desugar/DefaultMethodClassFixer.java
@@ -20,7 +20,6 @@ import static com.google.common.base.Preconditions.checkState;
import com.google.common.collect.ImmutableList;
import java.util.Comparator;
import java.util.HashSet;
-import java.util.Iterator;
import java.util.Set;
import java.util.TreeSet;
import org.objectweb.asm.ClassReader;
@@ -28,11 +27,6 @@ import org.objectweb.asm.ClassVisitor;
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.InsnList;
-import org.objectweb.asm.tree.InsnNode;
-import org.objectweb.asm.tree.MethodInsnNode;
-import org.objectweb.asm.tree.MethodNode;
/**
* Fixer of classes that extend interfaces with default methods to declare any missing methods
@@ -49,8 +43,6 @@ public class DefaultMethodClassFixer extends ClassVisitor {
private String internalName;
private ImmutableList<String> directInterfaces;
private String superName;
- /** This method node caches <clinit>, and flushes out in {@code visitEnd()}; */
- private MethodNode clInitMethodNode;
public DefaultMethodClassFixer(
ClassVisitor dest,
@@ -90,88 +82,10 @@ public class DefaultMethodClassFixer extends ClassVisitor {
// figure out what methods they declare before stubbing in any missing default methods.
recordInheritedMethods();
stubMissingDefaultAndBridgeMethods();
- // Check whether there are interfaces with default methods and <clinit>. If yes, the following
- // method call will return a list of interface fields to access in the <clinit> to trigger
- // the initialization of these interfaces.
- ImmutableList<String> companionsToTriggerInterfaceClinit =
- computeOrderedCompanionsToTriggerInterfaceClinit(directInterfaces);
- if (!companionsToTriggerInterfaceClinit.isEmpty()) {
- if (clInitMethodNode == null) {
- clInitMethodNode = new MethodNode(Opcodes.ACC_STATIC, "<clinit>", "()V", null, null);
- }
- desugarClinitToTriggerInterfaceInitializers(companionsToTriggerInterfaceClinit);
- }
- }
- if (clInitMethodNode != null && super.cv != null) { // Write <clinit> to the chained visitor.
- clInitMethodNode.accept(super.cv);
}
super.visitEnd();
}
- private boolean isClinitAlreadyDesugared(
- ImmutableList<String> companionsToAccessToTriggerInterfaceClinit) {
- InsnList instructions = clInitMethodNode.instructions;
- if (instructions.size() <= companionsToAccessToTriggerInterfaceClinit.size()) {
- // The <clinit> must end with RETURN, so if the instruction count is less than or equal to
- // the companion class count, this <clinit> has not been desugared.
- return false;
- }
- Iterator<AbstractInsnNode> iterator = instructions.iterator();
- for (String companion : companionsToAccessToTriggerInterfaceClinit) {
- if (!iterator.hasNext()) {
- return false;
- }
- AbstractInsnNode first = iterator.next();
- if (!(first instanceof MethodInsnNode)) {
- return false;
- }
- MethodInsnNode methodInsnNode = (MethodInsnNode) first;
- if (methodInsnNode.getOpcode() != Opcodes.INVOKESTATIC
- || !methodInsnNode.owner.equals(companion)
- || !methodInsnNode.name.equals(
- InterfaceDesugaring.COMPANION_METHOD_TO_TRIGGER_INTERFACE_CLINIT_NAME)) {
- return false;
- }
- checkState(
- methodInsnNode.desc.equals(
- InterfaceDesugaring.COMPANION_METHOD_TO_TRIGGER_INTERFACE_CLINIT_DESC),
- "Inconsistent method desc: %s vs %s",
- methodInsnNode.desc,
- InterfaceDesugaring.COMPANION_METHOD_TO_TRIGGER_INTERFACE_CLINIT_DESC);
-
- if (!iterator.hasNext()) {
- return false;
- }
- AbstractInsnNode second = iterator.next();
- if (second.getOpcode() != Opcodes.POP) {
- return false;
- }
- }
- return true;
- }
-
- private void desugarClinitToTriggerInterfaceInitializers(
- ImmutableList<String> companionsToTriggerInterfaceClinit) {
- if (isClinitAlreadyDesugared(companionsToTriggerInterfaceClinit)) {
- return;
- }
- InsnList desugarInsts = new InsnList();
- for (String companionClass : companionsToTriggerInterfaceClinit) {
- desugarInsts.add(
- new MethodInsnNode(
- Opcodes.INVOKESTATIC,
- companionClass,
- InterfaceDesugaring.COMPANION_METHOD_TO_TRIGGER_INTERFACE_CLINIT_NAME,
- InterfaceDesugaring.COMPANION_METHOD_TO_TRIGGER_INTERFACE_CLINIT_DESC,
- false));
- }
- if (clInitMethodNode.instructions.size() == 0) {
- clInitMethodNode.instructions.insert(new InsnNode(Opcodes.RETURN));
- }
- clInitMethodNode.instructions.insertBefore(
- clInitMethodNode.instructions.getFirst(), desugarInsts);
- }
-
@Override
public MethodVisitor visitMethod(
int access, String name, String desc, String signature, String[] exceptions) {
@@ -179,11 +93,6 @@ public class DefaultMethodClassFixer extends ClassVisitor {
if (!isInterface) {
recordIfInstanceMethod(access, name, desc);
}
- if ("<clinit>".equals(name)) {
- checkState(clInitMethodNode == null, "This class fixer has been used. ");
- clInitMethodNode = new MethodNode(access, name, desc, signature, exceptions);
- return clInitMethodNode;
- }
return super.visitMethod(access, name, desc, signature, exceptions);
}
@@ -256,55 +165,6 @@ public class DefaultMethodClassFixer extends ClassVisitor {
}
/**
- * Starting from the given interfaces, this method scans the interface hierarchy, finds the
- * interfaces that have default methods and <clinit>, and returns the companion class names of
- * these interfaces.
- *
- * <p>Note that the returned companion classes are ordered in the order of the interface
- * initialization, which is consistent with the JVM behavior. For example, "class A implements I1,
- * I2", the returned list would be [I1$$CC, I2$$CC], not [I2$$CC, I1$$CC].
- */
- private ImmutableList<String> computeOrderedCompanionsToTriggerInterfaceClinit(
- ImmutableList<String> interfaces) {
- ImmutableList.Builder<String> companionCollector = ImmutableList.builder();
- HashSet<String> visitedInterfaces = new HashSet<>();
- for (String anInterface : interfaces) {
- computeOrderedCompanionsToTriggerInterfaceClinit(
- anInterface, visitedInterfaces, companionCollector);
- }
- return companionCollector.build();
- }
-
- private void computeOrderedCompanionsToTriggerInterfaceClinit(
- String anInterface,
- HashSet<String> visitedInterfaces,
- ImmutableList.Builder<String> companionCollector) {
- if (!visitedInterfaces.add(anInterface)) {
- return;
- }
- ClassReader bytecode = classpath.readIfKnown(anInterface);
- if (bytecode == null || bootclasspath.isKnown(anInterface)) {
- return;
- }
- String[] parentInterfaces = bytecode.getInterfaces();
- if (parentInterfaces != null && parentInterfaces.length > 0) {
- for (String parentInterface : parentInterfaces) {
- computeOrderedCompanionsToTriggerInterfaceClinit(
- parentInterface, visitedInterfaces, companionCollector);
- }
- }
- InterfaceInitializationNecessityDetector necessityDetector =
- new InterfaceInitializationNecessityDetector(bytecode.getClassName());
- bytecode.accept(necessityDetector, ClassReader.SKIP_DEBUG);
- if (necessityDetector.needsToInitialize()) {
- // If we need to initialize this interface, we initialize its companion class, and its
- // companion class will initialize the interface then. This desigin decision is made to avoid
- // access issue, e.g., package-private interfaces.
- companionCollector.add(InterfaceDesugaring.getCompanionClassName(anInterface));
- }
- }
-
- /**
* Recursively searches the given interfaces for default methods not implemented by this class
* directly. If this method returns true we need to think about stubbing missing default methods.
*/
@@ -338,13 +198,10 @@ public class DefaultMethodClassFixer extends ClassVisitor {
// Note that an exception is that, if a bridge method is for a default interface method, javac
// will NOT generate the bridge method in the implementing class. So we need extra logic to
// handle these bridge methods.
- return isNonBridgeDefaultMethod(access) && !instanceMethods.contains(name + ":" + desc);
- }
-
- private static boolean isNonBridgeDefaultMethod(int access) {
return BitFlags.noneSet(
- access,
- Opcodes.ACC_ABSTRACT | Opcodes.ACC_STATIC | Opcodes.ACC_BRIDGE | Opcodes.ACC_PRIVATE);
+ access,
+ Opcodes.ACC_ABSTRACT | Opcodes.ACC_STATIC | Opcodes.ACC_BRIDGE | Opcodes.ACC_PRIVATE)
+ && !instanceMethods.contains(name + ":" + desc);
}
/**
@@ -522,66 +379,6 @@ public class DefaultMethodClassFixer extends ClassVisitor {
}
}
- /**
- * Detector to determine whether an interface needs to be initialized when it is loaded.
- *
- * <p>If the interface has a default method, and its <clinit> initializes any of its fields, then
- * this interface needs to be initialized.
- */
- private static class InterfaceInitializationNecessityDetector extends ClassVisitor {
-
- private final String internalName;
- private boolean hasFieldInitializedInClinit;
- private boolean hasDefaultMethods;
-
- public InterfaceInitializationNecessityDetector(String internalName) {
- super(Opcodes.ASM5);
- this.internalName = internalName;
- }
-
- public boolean needsToInitialize() {
- return hasDefaultMethods && hasFieldInitializedInClinit;
- }
-
- @Override
- public void visit(
- int version,
- int access,
- String name,
- String signature,
- String superName,
- String[] interfaces) {
- super.visit(version, access, name, signature, superName, interfaces);
- checkState(
- internalName.equals(name),
- "Inconsistent internal names: expected=%s, real=%s",
- internalName,
- name);
- checkArgument(
- BitFlags.isSet(access, Opcodes.ACC_INTERFACE),
- "This class visitor is only used for interfaces.");
- }
-
- @Override
- public MethodVisitor visitMethod(
- int access, String name, String desc, String signature, String[] exceptions) {
- if (!hasDefaultMethods) {
- hasDefaultMethods = isNonBridgeDefaultMethod(access);
- }
- if ("<clinit>".equals(name)) {
- return new MethodVisitor(Opcodes.ASM5) {
- @Override
- public void visitFieldInsn(int opcode, String owner, String name, String desc) {
- if (opcode == Opcodes.PUTSTATIC && internalName.equals(owner)) {
- hasFieldInitializedInClinit = true;
- }
- }
- };
- }
- return null; // Do not care about the code.
- }
- }
-
/** Comparator for interfaces that compares by whether interfaces extend one another. */
enum InterfaceComparator implements Comparator<Class<?>> {
INSTANCE;
diff --git a/src/tools/android/java/com/google/devtools/build/android/desugar/Desugar.java b/src/tools/android/java/com/google/devtools/build/android/desugar/Desugar.java
index 74dfa176a1..bbba22e149 100644
--- a/src/tools/android/java/com/google/devtools/build/android/desugar/Desugar.java
+++ b/src/tools/android/java/com/google/devtools/build/android/desugar/Desugar.java
@@ -20,7 +20,6 @@ import static com.google.devtools.build.android.desugar.LambdaClassMaker.LAMBDA_
import static java.nio.charset.StandardCharsets.ISO_8859_1;
import com.google.auto.value.AutoValue;
-import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
@@ -626,8 +625,7 @@ class Desugar {
return ioPairListbuilder.build();
}
- @VisibleForTesting
- static class ThrowingClassLoader extends ClassLoader {
+ private static class ThrowingClassLoader extends ClassLoader {
@Override
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
if (name.startsWith("java.")) {
@@ -702,8 +700,7 @@ class Desugar {
* closer.
*/
@SuppressWarnings("MustBeClosedChecker")
- @VisibleForTesting
- static ImmutableList<InputFileProvider> toRegisteredInputFileProvider(
+ private static ImmutableList<InputFileProvider> toRegisteredInputFileProvider(
Closer closer, List<Path> paths) throws IOException {
ImmutableList.Builder<InputFileProvider> builder = new ImmutableList.Builder<>();
for (Path path : paths) {
diff --git a/src/tools/android/java/com/google/devtools/build/android/desugar/InterfaceDesugaring.java b/src/tools/android/java/com/google/devtools/build/android/desugar/InterfaceDesugaring.java
index c32ca9ab98..adcd1e04af 100644
--- a/src/tools/android/java/com/google/devtools/build/android/desugar/InterfaceDesugaring.java
+++ b/src/tools/android/java/com/google/devtools/build/android/desugar/InterfaceDesugaring.java
@@ -14,7 +14,6 @@
package com.google.devtools.build.android.desugar;
import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import javax.annotation.Nullable;
@@ -38,9 +37,6 @@ import org.objectweb.asm.TypePath;
*/
class InterfaceDesugaring extends ClassVisitor {
- static final String COMPANION_METHOD_TO_TRIGGER_INTERFACE_CLINIT_NAME = "$$triggerInterfaceInit";
- static final String COMPANION_METHOD_TO_TRIGGER_INTERFACE_CLINIT_DESC = "()V";
-
static final String COMPANION_SUFFIX = "$$CC";
static final String INTERFACE_STATIC_COMPANION_METHOD_SUFFIX = "$$STATIC$$";
@@ -51,7 +47,6 @@ class InterfaceDesugaring extends ClassVisitor {
private int bytecodeVersion;
private int accessFlags;
@Nullable private ClassVisitor companion;
- @Nullable private FieldInfo interfaceFieldToAccessInCompanionMethodToTriggerInterfaceClinit;
public InterfaceDesugaring(
ClassVisitor dest, ClassReaderFactory bootclasspath, GeneratedClassStore store) {
@@ -78,50 +73,18 @@ class InterfaceDesugaring extends ClassVisitor {
@Override
public void visitEnd() {
if (companion != null) {
- // Emit a method to access the fields of the interfaces that need initialization.
- emitInterfaceFieldAccessInCompanionMethodToTriggerInterfaceClinit();
companion.visitEnd();
}
super.visitEnd();
}
- private void emitInterfaceFieldAccessInCompanionMethodToTriggerInterfaceClinit() {
- if (companion == null
- || interfaceFieldToAccessInCompanionMethodToTriggerInterfaceClinit == null) {
- return;
- }
-
- // Create a method to access the interface fields
- MethodVisitor visitor =
- checkNotNull(
- companion.visitMethod(
- Opcodes.ACC_STATIC | Opcodes.ACC_PUBLIC,
- COMPANION_METHOD_TO_TRIGGER_INTERFACE_CLINIT_NAME,
- COMPANION_METHOD_TO_TRIGGER_INTERFACE_CLINIT_DESC,
- null,
- null),
- "Cannot get a method visitor to write out %s to the companion class.",
- COMPANION_METHOD_TO_TRIGGER_INTERFACE_CLINIT_NAME);
- // Visit the interface field to triger <clinit> of the interface.
- visitor.visitFieldInsn(
- Opcodes.GETSTATIC,
- interfaceFieldToAccessInCompanionMethodToTriggerInterfaceClinit.owner(),
- interfaceFieldToAccessInCompanionMethodToTriggerInterfaceClinit.name(),
- interfaceFieldToAccessInCompanionMethodToTriggerInterfaceClinit.desc());
- visitor.visitInsn(Opcodes.POP);
- visitor.visitInsn(Opcodes.RETURN);
- }
-
@Override
public MethodVisitor visitMethod(
int access, String name, String desc, String signature, String[] exceptions) {
MethodVisitor result;
- if (isStaticInitializer(name)) {
- result =
- new InterfaceFieldWriteCollector(
- super.visitMethod(access, name, desc, signature, exceptions));
- } else if (BitFlags.isSet(accessFlags, Opcodes.ACC_INTERFACE)
- && BitFlags.noneSet(access, Opcodes.ACC_ABSTRACT | Opcodes.ACC_BRIDGE)) {
+ if (BitFlags.isSet(accessFlags, Opcodes.ACC_INTERFACE)
+ && BitFlags.noneSet(access, Opcodes.ACC_ABSTRACT | Opcodes.ACC_BRIDGE)
+ && !"<clinit>".equals(name)) {
checkArgument(BitFlags.noneSet(access, Opcodes.ACC_NATIVE), "Forbidden per JLS ch 9.4");
boolean isLambdaBody =
@@ -177,10 +140,6 @@ class InterfaceDesugaring extends ClassVisitor {
: null;
}
- private static boolean isStaticInitializer(String methodName) {
- return "<clinit>".equals(methodName);
- }
-
private static String normalizeInterfaceMethodName(
String name, boolean isLambda, boolean isStatic) {
String suffix;
@@ -197,10 +156,6 @@ class InterfaceDesugaring extends ClassVisitor {
return name + suffix;
}
- static String getCompanionClassName(String interfaceName) {
- return interfaceName + COMPANION_SUFFIX;
- }
-
/**
* Returns the descriptor of a static method for an instance method with the given receiver and
* description, simply by pre-pending the given descriptor's parameter list with the given
@@ -217,7 +172,7 @@ class InterfaceDesugaring extends ClassVisitor {
private ClassVisitor companion() {
if (companion == null) {
checkState(BitFlags.isSet(accessFlags, Opcodes.ACC_INTERFACE));
- String companionName = getCompanionClassName(internalName);
+ String companionName = internalName + COMPANION_SUFFIX;
companion = store.add(companionName);
companion.visit(
@@ -233,32 +188,6 @@ class InterfaceDesugaring extends ClassVisitor {
}
/**
- * Interface field scanner to get the field of the current interface that is written in the
- * initializer.
- */
- private class InterfaceFieldWriteCollector extends MethodVisitor {
-
- public InterfaceFieldWriteCollector(MethodVisitor mv) {
- super(Opcodes.ASM5, mv);
- }
-
- @Override
- public void visitFieldInsn(int opcode, String owner, String name, String desc) {
- if (interfaceFieldToAccessInCompanionMethodToTriggerInterfaceClinit == null
- && opcode == Opcodes.PUTSTATIC) {
- checkState(
- owner.equals(internalName),
- "Expect only the fields in this interface to be initialized. owner=%s, expected=%s",
- owner,
- internalName);
- interfaceFieldToAccessInCompanionMethodToTriggerInterfaceClinit =
- FieldInfo.create(owner, name, desc);
- }
- super.visitFieldInsn(opcode, owner, name, desc);
- }
- }
-
- /**
* Rewriter for calls to static interface methods and super calls to default methods, unless
* they're part of the bootclasspath, as well as all lambda body methods. Keeps calls to interface
* methods declared in the bootclasspath as-is (but note that these would presumably fail on