Avoid redundant synthesis in var handle desugaring
Bug: b/278817819
Change-Id: I50cf5c2bb239de0e1a4a176b96bcab64c727e7be
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/varhandle/VarHandleDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/varhandle/VarHandleDesugaring.java
index 80f114f4..063286c 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/varhandle/VarHandleDesugaring.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/varhandle/VarHandleDesugaring.java
@@ -35,6 +35,7 @@
import com.android.tools.r8.ir.desugar.DesugarDescription;
import com.android.tools.r8.ir.desugar.FreshLocalProvider;
import com.android.tools.r8.ir.desugar.LocalStackAllocator;
+import com.android.tools.r8.utils.BitUtils;
import com.google.common.collect.ImmutableList;
import java.util.ArrayList;
import java.util.Collection;
@@ -47,6 +48,9 @@
public class VarHandleDesugaring implements CfInstructionDesugaring, CfClassSynthesizerDesugaring {
+ private static final int SYNTHESIZED_METHOD_HANDLES_LOOKUP_CLASS = 1;
+ private static final int SYNTHESIZED_VAR_HANDLE_CLASS_FLAG = 2;
+
private final AppView<?> appView;
private final DexItemFactory factory;
@@ -70,26 +74,33 @@
return;
}
CfCode cfCode = programMethod.getDefinition().getCode().asCfCode();
+ int synthesizedClasses = 0;
for (CfInstruction instruction : cfCode.getInstructions()) {
- scanInstruction(instruction, eventConsumer, programMethod);
+ synthesizedClasses =
+ scanInstruction(instruction, eventConsumer, programMethod, synthesizedClasses);
}
}
- private void scanInstruction(
+ private int scanInstruction(
CfInstruction instruction,
CfInstructionDesugaringEventConsumer eventConsumer,
- ProgramMethod context) {
+ ProgramMethod context,
+ int synthesizedClasses) {
assert !instruction.isInitClass();
if (instruction.isInvoke()) {
CfInvoke cfInvoke = instruction.asInvoke();
- if (refersToVarHandle(cfInvoke.getMethod(), factory)) {
+ if (BitUtils.isBitInMaskUnset(synthesizedClasses, SYNTHESIZED_VAR_HANDLE_CLASS_FLAG)
+ && refersToVarHandle(cfInvoke.getMethod(), factory)) {
ensureVarHandleClass(eventConsumer, context);
+ synthesizedClasses |= SYNTHESIZED_VAR_HANDLE_CLASS_FLAG;
}
- if (refersToMethodHandlesLookup(cfInvoke.getMethod(), factory)) {
+ if (BitUtils.isBitInMaskUnset(synthesizedClasses, SYNTHESIZED_METHOD_HANDLES_LOOKUP_CLASS)
+ && refersToMethodHandlesLookup(cfInvoke.getMethod(), factory)) {
ensureMethodHandlesLookupClass(eventConsumer, context);
+ synthesizedClasses |= SYNTHESIZED_METHOD_HANDLES_LOOKUP_CLASS;
}
- return;
}
+ return synthesizedClasses;
}
private static boolean refersToVarHandle(DexType type, DexItemFactory factory) {
@@ -175,6 +186,7 @@
private void ensureMethodHandlesLookupClass(
VarHandleDesugaringEventConsumer eventConsumer,
Collection<? extends ProgramDefinition> contexts) {
+ assert contexts.stream().allMatch(context -> context.getContextType() != factory.lookupType);
DexProgramClass clazz =
appView
.getSyntheticItems()
@@ -201,6 +213,7 @@
private void ensureVarHandleClass(
VarHandleDesugaringEventConsumer eventConsumer,
Collection<? extends ProgramDefinition> contexts) {
+ assert contexts.stream().allMatch(context -> context.getContextType() != factory.varHandleType);
DexProgramClass clazz =
appView
.getSyntheticItems()
@@ -221,7 +234,9 @@
private void ensureVarHandleClass(
VarHandleDesugaringEventConsumer eventConsumer, ProgramDefinition context) {
- ensureVarHandleClass(eventConsumer, ImmutableList.of(context));
+ if (context.getContextType() != factory.varHandleType) {
+ ensureVarHandleClass(eventConsumer, ImmutableList.of(context));
+ }
}
@Override
diff --git a/src/main/java/com/android/tools/r8/utils/BitUtils.java b/src/main/java/com/android/tools/r8/utils/BitUtils.java
index f951031..732d62a 100644
--- a/src/main/java/com/android/tools/r8/utils/BitUtils.java
+++ b/src/main/java/com/android/tools/r8/utils/BitUtils.java
@@ -7,13 +7,17 @@
public class BitUtils {
public static boolean isBitSet(int value, int which) {
- return (value & (1 << (which - 1))) != 0;
+ return isBitInMaskSet(value, 1 << (which - 1));
}
public static boolean isBitInMaskSet(int value, int mask) {
return (value & mask) != 0;
}
+ public static boolean isBitInMaskUnset(int value, int mask) {
+ return !isBitInMaskSet(value, mask);
+ }
+
public static boolean isAligned(int alignment, int value) {
assert (alignment & (alignment - 1)) == 0; // Check alignment is power of 2.
return (value & (alignment - 1)) == 0;