Extend the use of LIR past horizontal class merging
Change-Id: I251f28dc2e20bd084840bde35d7e3446520a3aa9
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index f9694e5..ecb29de 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -730,7 +730,7 @@
GenericSignatureContextBuilder genericContextBuilderBeforeFinalMerging = null;
if (appView.hasCfByteCodePassThroughMethods()) {
- LirConverter.finalizeLirToOutputFormat(appView, timing, executorService);
+ LirConverter.rewriteLirWithLens(appView, timing, executorService);
} else {
// Perform repackaging.
if (appView.hasLiveness()) {
@@ -743,16 +743,14 @@
// Rewrite LIR with lens to allow building IR from LIR in class mergers.
LirConverter.rewriteLirWithLens(appView, timing, executorService);
appView.clearCodeRewritings(executorService, timing);
+ assert appView.dexItemFactory().verifyNoCachedTypeElements();
if (appView.hasLiveness()) {
VerticalClassMerger.createForFinalClassMerging(appView.withLiveness())
.runIfNecessary(executorService, timing);
+ assert appView.dexItemFactory().verifyNoCachedTypeElements();
}
- // TODO(b/225838009): Move further down.
- LirConverter.finalizeLirToOutputFormat(appView, timing, executorService);
- assert appView.dexItemFactory().verifyNoCachedTypeElements();
-
genericContextBuilderBeforeFinalMerging = GenericSignatureContextBuilder.create(appView);
// Run horizontal class merging. This runs even if shrinking is disabled to ensure
@@ -764,8 +762,13 @@
finalRuntimeTypeCheckInfoBuilder != null
? finalRuntimeTypeCheckInfoBuilder.build(appView.graphLens())
: null);
+ assert appView.dexItemFactory().verifyNoCachedTypeElements();
}
+ // TODO(b/225838009): Move further down.
+ LirConverter.finalizeLirToOutputFormat(appView, timing, executorService);
+ assert appView.dexItemFactory().verifyNoCachedTypeElements();
+
// Perform minification.
if (options.getProguardConfiguration().hasApplyMappingFile()) {
timing.begin("apply-mapping");
diff --git a/src/main/java/com/android/tools/r8/graph/AppInfoWithClassHierarchy.java b/src/main/java/com/android/tools/r8/graph/AppInfoWithClassHierarchy.java
index 1b9b0b0..2ae1e75 100644
--- a/src/main/java/com/android/tools/r8/graph/AppInfoWithClassHierarchy.java
+++ b/src/main/java/com/android/tools/r8/graph/AppInfoWithClassHierarchy.java
@@ -89,6 +89,10 @@
return new AppInfoWithClassHierarchy(WITNESS, appInfo);
}
+ public final AppInfoWithClassHierarchy rebuildWithClassHierarchy(DexApplication application) {
+ return rebuildWithClassHierarchy(getSyntheticItems().commit(application));
+ }
+
public final AppInfoWithClassHierarchy rebuildWithClassHierarchy(CommittedItems commit) {
return new AppInfoWithClassHierarchy(
commit, getClassToFeatureSplitMap(), getMainDexInfo(), getMissingClasses());
diff --git a/src/main/java/com/android/tools/r8/graph/lens/GraphLens.java b/src/main/java/com/android/tools/r8/graph/lens/GraphLens.java
index 05bf1b7..7c01711 100644
--- a/src/main/java/com/android/tools/r8/graph/lens/GraphLens.java
+++ b/src/main/java/com/android/tools/r8/graph/lens/GraphLens.java
@@ -20,6 +20,7 @@
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.proto.RewrittenPrototypeDescription;
+import com.android.tools.r8.horizontalclassmerging.HorizontalClassMergerGraphLens;
import com.android.tools.r8.ir.code.InvokeType;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.ir.optimize.CustomLensCodeRewriter;
@@ -425,6 +426,10 @@
return false;
}
+ public HorizontalClassMergerGraphLens asHorizontalClassMergerGraphLens() {
+ return null;
+ }
+
public abstract boolean isIdentityLens();
public abstract boolean isIdentityLensForFields(GraphLens codeLens);
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassMerger.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassMerger.java
index 7139797..e754435 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassMerger.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassMerger.java
@@ -27,6 +27,7 @@
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.PrunedItems;
import com.android.tools.r8.horizontalclassmerging.code.ClassInitializerMerger;
+import com.android.tools.r8.horizontalclassmerging.code.ClassInitializerMerger.IRProvider;
import com.android.tools.r8.horizontalclassmerging.code.SyntheticInitializerConverter;
import com.android.tools.r8.ir.analysis.value.NumberFromIntervalValue;
import com.android.tools.r8.ir.optimize.info.OptimizationFeedback;
@@ -112,11 +113,10 @@
ClassMergerSharedData classMergerSharedData,
ProfileCollectionAdditions profileCollectionAdditions,
SyntheticInitializerConverter.Builder syntheticInitializerConverterBuilder) {
- mergeInstanceInitializers(
- classMergerSharedData, profileCollectionAdditions, syntheticInitializerConverterBuilder);
+ mergeInstanceInitializers(classMergerSharedData, profileCollectionAdditions);
mergeStaticClassInitializers(syntheticInitializerConverterBuilder);
group.forEach(this::mergeDirectMethods);
- if (!classInitializerMerger.isEmpty() && classInitializerMerger.isTrivialMerge()) {
+ if (classInitializerMerger.size() > 1 && classInitializerMerger.isTrivialMerge()) {
classInitializerMerger.setObsolete();
}
instanceInitializerMergers.setObsolete();
@@ -128,6 +128,13 @@
return;
}
+ if (classInitializerMerger.isSingleton()) {
+ DexEncodedMethod classInitializer =
+ classInitializerMerger.moveSingleton(group, dexItemFactory);
+ classMethodsBuilder.addDirectMethod(classInitializer);
+ return;
+ }
+
// Synthesize a new class initializer with a fresh synthetic original name.
DexMethod newMethodReference =
dexItemFactory.createClassInitializer(group.getTarget().getType());
@@ -144,17 +151,15 @@
.setMethod(newMethodReference)
.setAccessFlags(MethodAccessFlags.createForClassInitializer())
.setCode(classInitializerMerger.getCode(newMethodReference))
- .setClassFileVersion(classInitializerMerger.getCfVersion())
+ .setClassFileVersion(classInitializerMerger.getCfVersion(appView.options()))
.setApiLevelForDefinition(apiReferenceLevel)
.setApiLevelForCode(apiReferenceLevel)
.build();
classMethodsBuilder.addDirectMethod(definition);
- // In case we didn't synthesize CF code, we register the class initializer for conversion to dex
- // after merging.
- if (!definition.getCode().isCfCode()) {
- assert appView.options().isGeneratingDex();
- assert mode.isFinal();
+ // Convert the synthetic code object to LIR before exiting class merging.
+ if (mode.isFinal()) {
+ assert definition.getCode() instanceof IRProvider;
syntheticInitializerConverterBuilder.addClassInitializer(
new ProgramMethod(group.getTarget(), definition));
}
@@ -204,15 +209,10 @@
void mergeInstanceInitializers(
ClassMergerSharedData classMergerSharedData,
- ProfileCollectionAdditions profileCollectionAdditions,
- SyntheticInitializerConverter.Builder syntheticInitializerConverterBuilder) {
+ ProfileCollectionAdditions profileCollectionAdditions) {
instanceInitializerMergers.forEach(
merger ->
- merger.merge(
- classMergerSharedData,
- profileCollectionAdditions,
- classMethodsBuilder,
- syntheticInitializerConverterBuilder));
+ merger.merge(classMergerSharedData, profileCollectionAdditions, classMethodsBuilder));
}
void mergeMethods(
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMerger.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMerger.java
index 91ca758..2c5dee9 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMerger.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMerger.java
@@ -12,13 +12,14 @@
import com.android.tools.r8.graph.AppInfo;
import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.CfCode;
+import com.android.tools.r8.graph.Code;
import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.PrunedItems;
import com.android.tools.r8.horizontalclassmerging.code.SyntheticInitializerConverter;
+import com.android.tools.r8.ir.conversion.LirConverter;
import com.android.tools.r8.ir.conversion.MethodConversionOptions;
import com.android.tools.r8.ir.conversion.MethodConversionOptions.MutableMethodConversionOptions;
import com.android.tools.r8.profile.art.ArtProfileCompletenessChecker;
@@ -102,9 +103,9 @@
}
private MutableMethodConversionOptions getConversionOptions() {
- return mode == ClassMergerMode.INITIAL
+ return mode.isInitial()
? MethodConversionOptions.forPreLirPhase(appView)
- : MethodConversionOptions.forPostLirPhase(appView);
+ : MethodConversionOptions.forLirPhase(appView);
}
private void run(
@@ -135,7 +136,7 @@
ProfileCollectionAdditions profileCollectionAdditions =
ProfileCollectionAdditions.create(appView);
SyntheticInitializerConverter.Builder syntheticInitializerConverterBuilder =
- SyntheticInitializerConverter.builder(appView, codeProvider, mode);
+ SyntheticInitializerConverter.builder(appView, codeProvider);
List<VirtuallyMergedMethodsKeepInfo> virtuallyMergedMethodsKeepInfos = new ArrayList<>();
PrunedItems prunedItems =
applyClassMergers(
@@ -177,7 +178,6 @@
// Finalize synthetic code.
transformIncompleteCode(groups, horizontalClassMergerGraphLens, executorService);
- syntheticInitializerConverter.convertInstanceInitializers(executorService);
// Must rewrite AppInfoWithLiveness before pruning the merged classes, to ensure that allocation
// sites, fields accesses, etc. are correctly transferred to the target classes.
@@ -187,8 +187,23 @@
KeepInfoCollection keepInfo = appView.getKeepInfo();
keepInfo.mutate(mutator -> mutator.removeKeepInfoForMergedClasses(prunedItems));
assert appView.hasClassHierarchy();
- appView.rewriteWithLensAndApplication(
- horizontalClassMergerGraphLens, newApplication.toDirect(), executorService, timing);
+ if (mode.isInitial()) {
+ appView.rewriteWithLensAndApplication(
+ horizontalClassMergerGraphLens, newApplication.toDirect(), executorService, timing);
+ } else {
+ appView.rewriteWithLens(horizontalClassMergerGraphLens, executorService, timing);
+ LirConverter.rewriteLirWithLens(appView.withClassHierarchy(), timing, executorService);
+ if (appView.hasLiveness()) {
+ appView
+ .withLiveness()
+ .setAppInfo(appView.appInfoWithLiveness().rebuildWithLiveness(newApplication));
+ } else {
+ appView
+ .withClassHierarchy()
+ .setAppInfo(
+ appView.appInfoWithClassHierarchy().rebuildWithClassHierarchy(newApplication));
+ }
+ }
} else {
assert mode.isFinal();
SyntheticItems syntheticItems = appView.appInfo().getSyntheticItems();
@@ -297,11 +312,14 @@
// This should be changed to generate non-null LirCode always.
IncompleteHorizontalClassMergerCode code =
(IncompleteHorizontalClassMergerCode) method.getDefinition().getCode();
- CfCode cfCode =
- code.toCfCode(
- appView.withClassHierarchy(), method, horizontalClassMergerGraphLens);
- if (cfCode != null) {
- method.setCode(cfCode, appView);
+ Code newCode =
+ mode.isInitial()
+ ? code.toCfCode(
+ appView.withClassHierarchy(), method, horizontalClassMergerGraphLens)
+ : code.toLirCode(
+ appView.withClassHierarchy(), method, horizontalClassMergerGraphLens);
+ if (newCode != null) {
+ method.setCode(newCode, appView);
}
});
},
@@ -399,6 +417,7 @@
syntheticInitializerConverterBuilder,
virtuallyMergedMethodsKeepInfoConsumer);
}
+ appView.dexItemFactory().clearTypeElementsCache();
return prunedItemsBuilder.build();
}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMergerGraphLens.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMergerGraphLens.java
index 24e3f18..92931c2 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMergerGraphLens.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMergerGraphLens.java
@@ -70,6 +70,11 @@
}
@Override
+ public HorizontalClassMergerGraphLens asHorizontalClassMergerGraphLens() {
+ return this;
+ }
+
+ @Override
protected Iterable<DexType> internalGetOriginalTypes(DexType previous) {
return IterableUtils.prependSingleton(previous, mergedClasses.getSourcesFor(previous));
}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/IncompleteHorizontalClassMergerCode.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/IncompleteHorizontalClassMergerCode.java
index 7ca989f..0d66d8b 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/IncompleteHorizontalClassMergerCode.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/IncompleteHorizontalClassMergerCode.java
@@ -17,6 +17,7 @@
import com.android.tools.r8.graph.UseRegistry;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.conversion.MethodConversionOptions.MutableMethodConversionOptions;
+import com.android.tools.r8.lightir.LirCode;
import com.android.tools.r8.utils.RetracerForCodePrinting;
public abstract class IncompleteHorizontalClassMergerCode extends Code {
@@ -36,6 +37,11 @@
ProgramMethod method,
HorizontalClassMergerGraphLens lens);
+ public abstract LirCode<Integer> toLirCode(
+ AppView<? extends AppInfoWithClassHierarchy> appView,
+ ProgramMethod method,
+ HorizontalClassMergerGraphLens lens);
+
@Override
public final Code getCodeAsInlining(
DexMethod caller,
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/IncompleteMergedInstanceInitializerCode.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/IncompleteMergedInstanceInitializerCode.java
index 95a4920..2ce9bac 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/IncompleteMergedInstanceInitializerCode.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/IncompleteMergedInstanceInitializerCode.java
@@ -4,6 +4,8 @@
package com.android.tools.r8.horizontalclassmerging;
+import static com.android.tools.r8.ir.analysis.type.Nullability.definitelyNotNull;
+
import com.android.tools.r8.cf.code.CfConstClass;
import com.android.tools.r8.cf.code.CfConstNull;
import com.android.tools.r8.cf.code.CfConstNumber;
@@ -23,20 +25,34 @@
import com.android.tools.r8.graph.CfCodeWithLens;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
import com.android.tools.r8.graph.lens.MethodLookupResult;
+import com.android.tools.r8.ir.analysis.type.TypeElement;
import com.android.tools.r8.ir.analysis.value.SingleConstValue;
import com.android.tools.r8.ir.analysis.value.SingleDexItemBasedStringValue;
+import com.android.tools.r8.ir.code.IRMetadata;
import com.android.tools.r8.ir.code.Position;
import com.android.tools.r8.ir.code.Position.SyntheticPosition;
+import com.android.tools.r8.ir.code.Value;
import com.android.tools.r8.ir.code.ValueType;
import com.android.tools.r8.ir.conversion.ExtraParameter;
import com.android.tools.r8.ir.optimize.info.field.InstanceFieldInitializationInfo;
+import com.android.tools.r8.lightir.LirBuilder;
+import com.android.tools.r8.lightir.LirCode;
+import com.android.tools.r8.lightir.LirEncodingStrategy;
+import com.android.tools.r8.lightir.LirStrategy;
+import com.android.tools.r8.utils.Box;
import com.android.tools.r8.utils.IntBox;
+import com.android.tools.r8.utils.ListUtils;
import com.google.common.collect.ImmutableList;
+import java.util.ArrayList;
import java.util.List;
import java.util.Map;
+import java.util.Map.Entry;
+import java.util.function.Consumer;
import org.objectweb.asm.Opcodes;
/**
@@ -174,6 +190,127 @@
instructionBuilder.build());
}
+ @Override
+ public LirCode<Integer> toLirCode(
+ AppView<? extends AppInfoWithClassHierarchy> appView,
+ ProgramMethod method,
+ HorizontalClassMergerGraphLens lens) {
+ LirEncodingStrategy<Value, Integer> strategy =
+ LirStrategy.getDefaultStrategy().getEncodingStrategy();
+ LirBuilder<Value, Integer> lirBuilder =
+ LirCode.builder(
+ method.getReference(),
+ method.getDefinition().isD8R8Synthesized(),
+ strategy,
+ appView.options())
+ .setMetadata(IRMetadata.unknown());
+
+ int instructionIndex = 0;
+ List<Value> argumentValues = new ArrayList<>();
+
+ // Add receiver argument.
+ DexType receiverType = method.getHolderType();
+ TypeElement receiverTypeElement = receiverType.toTypeElement(appView, definitelyNotNull());
+ Value receiverValue = Value.createNoDebugLocal(instructionIndex, receiverTypeElement);
+ argumentValues.add(receiverValue);
+ strategy.defineValue(receiverValue, receiverValue.getNumber());
+ lirBuilder.addArgument(receiverValue.getNumber(), false);
+ instructionIndex++;
+
+ // Add non-receiver arguments.
+ for (; instructionIndex < method.getDefinition().getNumberOfArguments(); instructionIndex++) {
+ DexType argumentType = method.getArgumentType(instructionIndex);
+ TypeElement argumentTypeElement = argumentType.toTypeElement(appView);
+ Value argumentValue = Value.createNoDebugLocal(instructionIndex, argumentTypeElement);
+ argumentValues.add(argumentValue);
+ strategy.defineValue(argumentValue, argumentValue.getNumber());
+ lirBuilder.addArgument(argumentValue.getNumber(), argumentType.isBooleanType());
+ }
+
+ // Assign class id.
+ if (classIdField != null) {
+ Value classIdValue = argumentValues.get(argumentValues.size() - 1 - extraNulls);
+ lirBuilder.addInstancePut(
+ lens.getNextFieldSignature(classIdField), receiverValue, classIdValue);
+ instructionIndex++;
+ }
+
+ // Assign each field.
+ instructionIndex =
+ addLirInstructionsForInstanceFieldAssignments(
+ appView,
+ method,
+ lirBuilder,
+ strategy,
+ argumentValues,
+ instructionIndex,
+ instanceFieldAssignmentsPre,
+ lens);
+
+ // Load constructor arguments.
+ MethodLookupResult parentConstructorLookup =
+ lens.lookupInvokeDirect(parentConstructor, method, appView.codeLens());
+ List<Value> parentConstructorArgumentValues = new ArrayList<>();
+ parentConstructorArgumentValues.add(receiverValue);
+ int parentConstructorArgumentIndex = 0;
+ for (InstanceFieldInitializationInfo initializationInfo : parentConstructorArguments) {
+ instructionIndex =
+ addLirInstructionsForInitializationInfo(
+ appView,
+ lirBuilder,
+ strategy,
+ initializationInfo,
+ argumentValues,
+ instructionIndex,
+ parentConstructorLookup.getReference().getParameter(parentConstructorArgumentIndex),
+ parentConstructorArgumentValues::add);
+ parentConstructorArgumentIndex++;
+ }
+
+ for (ExtraParameter extraParameter :
+ parentConstructorLookup.getPrototypeChanges().getExtraParameters()) {
+ instructionIndex =
+ addLirInstructionsForInitializationInfo(
+ appView,
+ lirBuilder,
+ strategy,
+ extraParameter.getValue(appView),
+ argumentValues,
+ instructionIndex,
+ parentConstructorLookup.getReference().getParameter(parentConstructorArgumentIndex),
+ parentConstructorArgumentValues::add);
+ parentConstructorArgumentIndex++;
+ }
+
+ // Invoke parent constructor.
+ lirBuilder.addInvokeDirect(
+ parentConstructorLookup.getReference(), parentConstructorArgumentValues, false);
+ instructionIndex++;
+
+ // Assign each field.
+ addLirInstructionsForInstanceFieldAssignments(
+ appView,
+ method,
+ lirBuilder,
+ strategy,
+ argumentValues,
+ instructionIndex,
+ instanceFieldAssignmentsPost,
+ lens);
+
+ // Return.
+ lirBuilder.addReturnVoid();
+ instructionIndex++;
+
+ return new LirCode<>(lirBuilder.build()) {
+
+ @Override
+ public GraphLens getCodeLens(AppView<?> appView) {
+ return lens;
+ }
+ };
+ }
+
private static void addCfInstructionsForInstanceFieldAssignments(
AppView<? extends AppInfoWithClassHierarchy> appView,
ProgramMethod method,
@@ -260,6 +397,117 @@
}
}
+ private static int addLirInstructionsForInstanceFieldAssignments(
+ AppView<? extends AppInfoWithClassHierarchy> appView,
+ ProgramMethod method,
+ LirBuilder<Value, Integer> lirBuilder,
+ LirEncodingStrategy<Value, Integer> strategy,
+ List<Value> argumentValues,
+ int instructionIndex,
+ Map<DexField, InstanceFieldInitializationInfo> instanceFieldAssignments,
+ HorizontalClassMergerGraphLens lens) {
+ for (Entry<DexField, InstanceFieldInitializationInfo> entry :
+ instanceFieldAssignments.entrySet()) {
+ DexField field = entry.getKey();
+ InstanceFieldInitializationInfo initializationInfo = entry.getValue();
+
+ // Load the field value and then set the field.
+ Box<Value> fieldValueBox = new Box<>();
+ instructionIndex =
+ addLirInstructionsForInitializationInfo(
+ appView,
+ lirBuilder,
+ strategy,
+ initializationInfo,
+ argumentValues,
+ instructionIndex,
+ field.getType(),
+ fieldValueBox::set);
+ Value fieldValue = fieldValueBox.get();
+
+ // Insert a check to ensure the program continues to type check according to Java type
+ // checking. Otherwise, instance initializer merging may cause open interfaces. If
+ // <init>(A) and <init>(B) both have the behavior `this.i = arg; this.j = arg` where the
+ // type of `i` is I and the type of `j` is J, and both A and B implements I and J, then
+ // the constructors are merged into a single constructor <init>(java.lang.Object), which
+ // is no longer strictly type checking. Note that no choice of parameter type would solve
+ // this.
+ DexField rewrittenField = lens.getNextFieldSignature(field);
+ if (initializationInfo.isArgumentInitializationInfo()) {
+ int argumentIndex = initializationInfo.asArgumentInitializationInfo().getArgumentIndex();
+ if (argumentIndex > 0) {
+ DexType argumentType = method.getArgumentType(argumentIndex);
+ if (argumentType.isClassType()
+ && !appView.appInfo().isSubtype(argumentType, rewrittenField.getType())) {
+ TypeElement newFieldValueTypeElement =
+ rewrittenField.getType().toTypeElement(appView, fieldValue.getType().nullability());
+ Value newFieldValue =
+ Value.createNoDebugLocal(instructionIndex, newFieldValueTypeElement);
+ strategy.defineValue(newFieldValue, newFieldValue.getNumber());
+ lirBuilder.addSafeCheckCast(rewrittenField.getType(), fieldValue);
+ fieldValue = newFieldValue;
+ instructionIndex++;
+ }
+ }
+ }
+
+ lirBuilder.addInstancePut(rewrittenField, ListUtils.first(argumentValues), fieldValue);
+ instructionIndex++;
+ }
+ return instructionIndex;
+ }
+
+ private static int addLirInstructionsForInitializationInfo(
+ AppView<? extends AppInfoWithClassHierarchy> appView,
+ LirBuilder<Value, Integer> lirBuilder,
+ LirEncodingStrategy<Value, Integer> strategy,
+ InstanceFieldInitializationInfo initializationInfo,
+ List<Value> argumentValues,
+ int instructionIndex,
+ DexType type,
+ Consumer<Value> valueConsumer) {
+ Value value;
+ if (initializationInfo.isArgumentInitializationInfo()) {
+ int argumentIndex = initializationInfo.asArgumentInitializationInfo().getArgumentIndex();
+ value = argumentValues.get(argumentIndex);
+ } else {
+ assert initializationInfo.isSingleValue();
+ assert initializationInfo.asSingleValue().isSingleConstValue();
+ SingleConstValue singleConstValue = initializationInfo.asSingleValue().asSingleConstValue();
+ TypeElement valueTypeElement;
+ if (singleConstValue.isSingleConstClassValue()) {
+ DexType classType = singleConstValue.asSingleConstClassValue().getType();
+ lirBuilder.addConstClass(classType, false);
+ valueTypeElement = TypeElement.classClassType(appView, definitelyNotNull());
+ } else if (singleConstValue.isSingleDexItemBasedStringValue()) {
+ SingleDexItemBasedStringValue dexItemBasedStringValue =
+ singleConstValue.asSingleDexItemBasedStringValue();
+ lirBuilder.addDexItemBasedConstString(
+ dexItemBasedStringValue.getItem(), dexItemBasedStringValue.getNameComputationInfo());
+ valueTypeElement = TypeElement.stringClassType(appView, definitelyNotNull());
+ } else if (singleConstValue.isNull()) {
+ assert type.isReferenceType();
+ lirBuilder.addConstNull();
+ valueTypeElement = TypeElement.getNull();
+ } else if (singleConstValue.isSingleNumberValue()) {
+ assert type.isPrimitiveType();
+ long numberValue = singleConstValue.asSingleNumberValue().getValue();
+ lirBuilder.addConstNumber(ValueType.fromDexType(type), numberValue);
+ valueTypeElement = type.toTypeElement(appView);
+ } else {
+ assert singleConstValue.isSingleStringValue();
+ DexString string = singleConstValue.asSingleStringValue().getDexString();
+ lirBuilder.addConstString(string);
+ valueTypeElement = TypeElement.stringClassType(appView, definitelyNotNull());
+ }
+ value = Value.createNoDebugLocal(instructionIndex, valueTypeElement);
+ strategy.defineValue(value, value.getNumber());
+ instructionIndex++;
+ }
+ valueConsumer.accept(value);
+ return instructionIndex;
+ }
+
@Override
public String toString() {
return "IncompleteMergedInstanceInitializerCode";
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/IncompleteVirtuallyMergedMethodCode.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/IncompleteVirtuallyMergedMethodCode.java
index 378b433..05088a9 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/IncompleteVirtuallyMergedMethodCode.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/IncompleteVirtuallyMergedMethodCode.java
@@ -15,6 +15,7 @@
import com.android.tools.r8.cf.code.CfSwitch;
import com.android.tools.r8.cf.code.CfSwitch.Kind;
import com.android.tools.r8.cf.code.frame.FrameType;
+import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.CfCode;
@@ -25,6 +26,7 @@
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.horizontalclassmerging.VirtualMethodMerger.SuperMethodReference;
import com.android.tools.r8.ir.code.ValueType;
+import com.android.tools.r8.lightir.LirCode;
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.IterableUtils;
import it.unimi.dsi.fastutil.ints.Int2ReferenceSortedMap;
@@ -157,6 +159,14 @@
lens, originalMethod.getHolderType(), maxStack, maxLocals, instructions);
}
+ @Override
+ public LirCode<Integer> toLirCode(
+ AppView<? extends AppInfoWithClassHierarchy> appView,
+ ProgramMethod method,
+ HorizontalClassMergerGraphLens lens) {
+ throw new Unreachable();
+ }
+
private static CfFrame createCfFrameForSwitchCase(ProgramMethod representative, int localsSize) {
CfFrame.Builder builder =
CfFrame.builder().allocateStack(representative.getDefinition().getNumberOfArguments());
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/InstanceInitializerMerger.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/InstanceInitializerMerger.java
index 66b8a1e..829d715 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/InstanceInitializerMerger.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/InstanceInitializerMerger.java
@@ -21,7 +21,6 @@
import com.android.tools.r8.graph.MethodAccessFlags;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.horizontalclassmerging.code.ConstructorEntryPointSynthesizedCode;
-import com.android.tools.r8.horizontalclassmerging.code.SyntheticInitializerConverter;
import com.android.tools.r8.ir.conversion.ExtraConstantIntParameter;
import com.android.tools.r8.ir.conversion.ExtraParameter;
import com.android.tools.r8.ir.conversion.ExtraUnusedParameter;
@@ -299,8 +298,7 @@
void merge(
ClassMergerSharedData classMergerSharedData,
ProfileCollectionAdditions profileCollectionAdditions,
- ClassMethodsBuilder classMethodsBuilder,
- SyntheticInitializerConverter.Builder syntheticInitializerConverterBuilder) {
+ ClassMethodsBuilder classMethodsBuilder) {
ProgramMethod representative = ListUtils.first(instanceInitializers);
// Create merged instance initializer reference.
@@ -390,16 +388,10 @@
}
classMethodsBuilder.addDirectMethod(newInstanceInitializer);
- if (mode.isFinal()) {
- if (appView.options().isGeneratingDex() && !newInstanceInitializer.getCode().isDexCode()) {
- syntheticInitializerConverterBuilder.addInstanceInitializer(
- new ProgramMethod(group.getTarget(), newInstanceInitializer));
- } else {
- assert appView.options().isGeneratingDex()
- || newInstanceInitializer.getCode().isCfWritableCode()
- || newInstanceInitializer.getCode().isIncompleteHorizontalClassMergerCode();
- }
- }
+ assert mode.isInitial()
+ || newInstanceInitializer.getCode().isDefaultInstanceInitializerCode()
+ || newInstanceInitializer.getCode().isLirCode()
+ || newInstanceInitializer.getCode().isIncompleteHorizontalClassMergerCode();
}
void setObsolete() {
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/code/ClassInitializerMerger.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/code/ClassInitializerMerger.java
index d54026f..21e4584 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/code/ClassInitializerMerger.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/code/ClassInitializerMerger.java
@@ -19,6 +19,7 @@
import com.android.tools.r8.graph.ClasspathMethod;
import com.android.tools.r8.graph.Code;
import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.ProgramMethod;
@@ -36,6 +37,7 @@
import com.android.tools.r8.ir.code.Return;
import com.android.tools.r8.ir.conversion.MethodConversionOptions.MutableMethodConversionOptions;
import com.android.tools.r8.utils.CfVersionUtils;
+import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.IterableUtils;
import com.android.tools.r8.utils.ListUtils;
import com.android.tools.r8.utils.RetracerForCodePrinting;
@@ -84,18 +86,23 @@
return new IRProvider(classInitializers);
}
- public CfVersion getCfVersion() {
- ProgramMethod classInitializer = ListUtils.first(classInitializers);
- if (classInitializers.size() == 1) {
- DexEncodedMethod method = classInitializer.getDefinition();
- return method.hasClassFileVersion() ? method.getClassFileVersion() : null;
+ public CfVersion getCfVersion(InternalOptions options) {
+ return options.isGeneratingClassFiles() ? CfVersionUtils.max(classInitializers) : null;
+ }
+
+ public boolean isSingleton() {
+ return classInitializers.size() == 1;
+ }
+
+ public DexEncodedMethod moveSingleton(HorizontalMergeGroup group, DexItemFactory dexItemFactory) {
+ assert isSingleton();
+ ProgramMethod method = ListUtils.first(classInitializers);
+ DexEncodedMethod definition = method.getDefinition();
+ if (method.getHolder() == group.getTarget()) {
+ return definition;
}
- if (classInitializer.getDefinition().getCode().isCfCode()) {
- assert IterableUtils.allIdentical(
- classInitializers, method -> method.getDefinition().getCode().isCfCode());
- return CfVersionUtils.max(classInitializers);
- }
- return null;
+ DexMethod newReference = method.getReference().withHolder(group.getTarget(), dexItemFactory);
+ return definition.toTypeSubstitutedMethodAsInlining(newReference, dexItemFactory);
}
public boolean isTrivialMerge() {
@@ -115,6 +122,10 @@
classInitializers.forEach(classInitializer -> classInitializer.getDefinition().setObsolete());
}
+ public int size() {
+ return classInitializers.size();
+ }
+
public static class Builder {
private final ImmutableList.Builder<ProgramMethod> classInitializers = ImmutableList.builder();
@@ -195,7 +206,7 @@
* Provides a piece of {@link IRCode} that is the concatenation of a collection of class
* initializers.
*/
- static class IRProvider extends Code {
+ public static class IRProvider extends Code {
private final ImmutableList<ProgramMethod> classInitializers;
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/code/ConstructorEntryPointSynthesizedCode.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/code/ConstructorEntryPointSynthesizedCode.java
index fda1515..fde81de 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/code/ConstructorEntryPointSynthesizedCode.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/code/ConstructorEntryPointSynthesizedCode.java
@@ -27,6 +27,7 @@
import com.android.tools.r8.ir.conversion.MethodConversionOptions;
import com.android.tools.r8.ir.conversion.MethodConversionOptions.MutableMethodConversionOptions;
import com.android.tools.r8.ir.conversion.SourceCode;
+import com.android.tools.r8.lightir.LirCode;
import com.android.tools.r8.utils.RetracerForCodePrinting;
import it.unimi.dsi.fastutil.ints.Int2ReferenceMap;
import it.unimi.dsi.fastutil.ints.Int2ReferenceSortedMap;
@@ -84,6 +85,14 @@
}
@Override
+ public LirCode<Integer> toLirCode(
+ AppView<? extends AppInfoWithClassHierarchy> appView,
+ ProgramMethod method,
+ HorizontalClassMergerGraphLens lens) {
+ throw new Unreachable();
+ }
+
+ @Override
public final boolean isEmptyVoidMethod() {
return false;
}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/code/SyntheticInitializerConverter.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/code/SyntheticInitializerConverter.java
index 2b7d783..55a073a 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/code/SyntheticInitializerConverter.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/code/SyntheticInitializerConverter.java
@@ -4,13 +4,9 @@
package com.android.tools.r8.horizontalclassmerging.code;
-import com.android.tools.r8.classmerging.ClassMergerMode;
import com.android.tools.r8.graph.AppInfo;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.Code;
-import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.graph.lens.GraphLens;
import com.android.tools.r8.horizontalclassmerging.IRCodeProvider;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.conversion.IRConverter;
@@ -18,10 +14,8 @@
import com.android.tools.r8.synthesis.SyntheticItems.GlobalSyntheticsStrategy;
import com.android.tools.r8.utils.ThreadUtils;
import com.android.tools.r8.utils.Timing;
-import com.google.common.collect.Sets;
import java.util.ArrayList;
import java.util.List;
-import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
@@ -33,73 +27,33 @@
private final AppView<?> appView;
private final IRCodeProvider codeProvider;
- private final ClassMergerMode mode;
private final List<ProgramMethod> classInitializers;
- // Classes with one or more instance initializers that need to have their code processed into dex.
- private final Set<DexProgramClass> instanceInitializers;
-
private SyntheticInitializerConverter(
- AppView<?> appView,
- IRCodeProvider codeProvider,
- ClassMergerMode mode,
- List<ProgramMethod> classInitializers,
- Set<DexProgramClass> instanceInitializers) {
+ AppView<?> appView, IRCodeProvider codeProvider, List<ProgramMethod> classInitializers) {
this.appView = appView;
this.codeProvider = codeProvider;
- this.mode = mode;
this.classInitializers = classInitializers;
- this.instanceInitializers = instanceInitializers;
}
- public static Builder builder(
- AppView<?> appView, IRCodeProvider codeProvider, ClassMergerMode mode) {
- return new Builder(appView, codeProvider, mode);
+ public static Builder builder(AppView<?> appView, IRCodeProvider codeProvider) {
+ return new Builder(appView, codeProvider);
}
public void convertClassInitializers(ExecutorService executorService) throws ExecutionException {
if (!classInitializers.isEmpty()) {
+ assert appView.dexItemFactory().verifyNoCachedTypeElements();
IRConverter converter = new IRConverter(createAppViewForConversion());
ThreadUtils.processItems(
classInitializers,
method -> processMethod(method, converter),
appView.options().getThreadingModule(),
executorService);
+ appView.dexItemFactory().clearTypeElementsCache();
}
}
- public void convertInstanceInitializers(ExecutorService executorService)
- throws ExecutionException {
- if (!instanceInitializers.isEmpty()) {
- IRConverter converter = new IRConverter(createAppViewForConversion());
- ThreadUtils.processItems(
- instanceInitializers,
- clazz -> processInstanceInitializers(clazz, converter),
- appView.options().getThreadingModule(),
- executorService);
- }
- }
-
- private void processInstanceInitializers(DexProgramClass clazz, IRConverter converter) {
- assert appView.options().isGeneratingDex();
- assert mode.isFinal();
- clazz.forEachProgramInstanceInitializerMatching(
- method -> method.getCode().isCfCode(),
- method -> {
- GraphLens codeLens = method.getDefinition().getCode().getCodeLens(appView);
- assert codeLens != appView.codeLens();
-
- // Convert to dex.
- processMethod(method, converter);
-
- // Recover code lens.
- Code code = method.getDefinition().getCode();
- assert code.isDexCode();
- method.setCode(code.asDexCode().withCodeLens(codeLens), appView);
- });
- }
-
private AppView<AppInfo> createAppViewForConversion() {
assert appView.enableWholeProgramOptimizations();
assert appView.hasClassHierarchy();
@@ -129,22 +83,19 @@
}
public boolean isEmpty() {
- return classInitializers.isEmpty() && instanceInitializers.isEmpty();
+ return classInitializers.isEmpty();
}
public static class Builder {
private final AppView<?> appView;
private final IRCodeProvider codeProvider;
- private final ClassMergerMode mode;
private final List<ProgramMethod> classInitializers = new ArrayList<>();
- private final Set<DexProgramClass> instanceInitializers = Sets.newIdentityHashSet();
- private Builder(AppView<?> appView, IRCodeProvider codeProvider, ClassMergerMode mode) {
+ private Builder(AppView<?> appView, IRCodeProvider codeProvider) {
this.appView = appView;
this.codeProvider = codeProvider;
- this.mode = mode;
}
public Builder addClassInitializer(ProgramMethod method) {
@@ -152,17 +103,8 @@
return this;
}
- public Builder addInstanceInitializer(ProgramMethod method) {
- // Record that the holder has an instance initializer that needs processing to dex. We avoid
- // storing the collection of exact initializers that need processing, since that requires lens
- // code rewriting after the fixup has been made.
- this.instanceInitializers.add(method.getHolder());
- return this;
- }
-
public SyntheticInitializerConverter build() {
- return new SyntheticInitializerConverter(
- appView, codeProvider, mode, classInitializers, instanceInitializers);
+ return new SyntheticInitializerConverter(appView, codeProvider, classInitializers);
}
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/LirConverter.java b/src/main/java/com/android/tools/r8/ir/conversion/LirConverter.java
index 5f5a9c9..5eb58db 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/LirConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/LirConverter.java
@@ -149,7 +149,6 @@
assert !appView.getSyntheticItems().hasPendingSyntheticClasses();
assert verifyLirOnly(appView);
appView.testing().exitLirSupportedPhase();
- LensCodeRewriterUtils rewriterUtils = new LensCodeRewriterUtils(appView, true);
DeadCodeRemover deadCodeRemover = new DeadCodeRemover(appView);
String output = appView.options().isGeneratingClassFiles() ? "CF" : "DEX";
timing.begin("LIR->IR->" + output);
@@ -157,7 +156,7 @@
appView.appInfo().classes(),
clazz ->
clazz.forEachProgramMethod(
- m -> finalizeLirMethodToOutputFormat(m, deadCodeRemover, appView, rewriterUtils)),
+ m -> finalizeLirMethodToOutputFormat(m, deadCodeRemover, appView)),
appView.options().getThreadingModule(),
executorService);
timing.end();
@@ -170,18 +169,12 @@
private static void finalizeLirMethodToOutputFormat(
ProgramMethod method,
DeadCodeRemover deadCodeRemover,
- AppView<? extends AppInfoWithClassHierarchy> appView,
- LensCodeRewriterUtils rewriterUtils) {
+ AppView<? extends AppInfoWithClassHierarchy> appView) {
Code code = method.getDefinition().getCode();
if (!(code instanceof LirCode)) {
return;
}
Timing onThreadTiming = Timing.empty();
- LirCode<Integer> lirCode = code.asLirCode();
- LirCode<Integer> rewrittenLirCode = lirCode.rewriteWithLens(method, appView, rewriterUtils);
- if (ObjectUtils.notIdentical(lirCode, rewrittenLirCode)) {
- method.setCode(rewrittenLirCode, appView);
- }
IRCode irCode = method.buildIR(appView, MethodConversionOptions.forPostLirPhase(appView));
assert irCode.verifyInvokeInterface(appView);
ConstResourceNumberRemover constResourceNumberRemover = new ConstResourceNumberRemover(appView);
diff --git a/src/main/java/com/android/tools/r8/lightir/LirCode.java b/src/main/java/com/android/tools/r8/lightir/LirCode.java
index a571e49..91a85d7 100644
--- a/src/main/java/com/android/tools/r8/lightir/LirCode.java
+++ b/src/main/java/com/android/tools/r8/lightir/LirCode.java
@@ -644,20 +644,13 @@
@Override
public int estimatedDexCodeSizeUpperBoundInBytes() {
- throw new Unimplemented();
+ return getEstimatedDexSizeForInlining();
}
@Override
public int getEstimatedSizeForInliningIfLessThanOrEquals(int threshold) {
if (useDexEstimationStrategy) {
- LirSizeEstimation<EV> estimation = new LirSizeEstimation<>(this);
- for (LirInstructionView view : this) {
- estimation.onInstructionView(view);
- if (estimation.getSizeEstimate() > threshold) {
- return -1;
- }
- }
- return estimation.getSizeEstimate();
+ return getEstimatedDexSizeForInliningIfLessThanOrEquals(threshold);
} else {
// TODO(b/225838009): Currently the size estimation for CF has size one for each instruction
// (even switches!) and ignores stack instructions, thus loads to arguments are not included.
@@ -671,6 +664,21 @@
}
}
+ private int getEstimatedDexSizeForInlining() {
+ return getEstimatedDexSizeForInliningIfLessThanOrEquals(Integer.MAX_VALUE);
+ }
+
+ private int getEstimatedDexSizeForInliningIfLessThanOrEquals(int threshold) {
+ LirSizeEstimation<EV> estimation = new LirSizeEstimation<>(this);
+ for (LirInstructionView view : this) {
+ estimation.onInstructionView(view);
+ if (estimation.getSizeEstimate() > threshold) {
+ return -1;
+ }
+ }
+ return estimation.getSizeEstimate();
+ }
+
public Position getPreamblePosition(DexMethod method, boolean isD8R8Synthesized) {
if (positionTable.length > 0 && positionTable[0].fromInstructionIndex == 0) {
return positionTable[0].getPosition(method, isD8R8Synthesized);
diff --git a/src/main/java/com/android/tools/r8/lightir/LirLensCodeRewriter.java b/src/main/java/com/android/tools/r8/lightir/LirLensCodeRewriter.java
index b4a6cb7..2d7dcee 100644
--- a/src/main/java/com/android/tools/r8/lightir/LirLensCodeRewriter.java
+++ b/src/main/java/com/android/tools/r8/lightir/LirLensCodeRewriter.java
@@ -22,6 +22,7 @@
import com.android.tools.r8.graph.lens.GraphLens;
import com.android.tools.r8.graph.lens.MethodLookupResult;
import com.android.tools.r8.graph.proto.RewrittenPrototypeDescription;
+import com.android.tools.r8.horizontalclassmerging.HorizontalClassMergerGraphLens;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.IRMetadata;
import com.android.tools.r8.ir.code.IROpcodeUtils;
@@ -85,8 +86,8 @@
public void onFieldReference(DexField field) {
FieldLookupResult result = graphLens.lookupFieldResult(field, codeLens);
- assert !result.hasReadCastType();
- assert !result.hasWriteCastType();
+ assert !result.hasReadCastType() || graphLens.isHorizontalClassMergerGraphLens();
+ assert !result.hasWriteCastType() || graphLens.isHorizontalClassMergerGraphLens();
addRewrittenMapping(field, result.getReference());
}
@@ -172,6 +173,32 @@
}
@Override
+ public void onInstanceGet(DexField field, EV object) {
+ onFieldGet(field);
+ }
+
+ @Override
+ public void onStaticGet(DexField field) {
+ onFieldGet(field);
+ }
+
+ private void onFieldGet(DexField field) {
+ if (hasPotentialNonTrivialFieldGetRewriting(field)) {
+ hasNonTrivialRewritings = true;
+ }
+ }
+
+ private boolean hasPotentialNonTrivialFieldGetRewriting(DexField field) {
+ HorizontalClassMergerGraphLens horizontalClassMergerLens =
+ graphLens.asHorizontalClassMergerGraphLens();
+ if (horizontalClassMergerLens != null) {
+ FieldLookupResult result = horizontalClassMergerLens.lookupFieldResult(field, codeLens);
+ return result.hasReadCastType();
+ }
+ return false;
+ }
+
+ @Override
public void onInstancePut(DexField field, EV object, EV value) {
onFieldPut(field);
}
@@ -188,6 +215,12 @@
}
private boolean hasPotentialNonTrivialFieldPutRewriting(DexField field) {
+ HorizontalClassMergerGraphLens horizontalClassMergerLens =
+ graphLens.asHorizontalClassMergerGraphLens();
+ if (horizontalClassMergerLens != null) {
+ FieldLookupResult result = horizontalClassMergerLens.lookupFieldResult(field, codeLens);
+ return result.hasWriteCastType();
+ }
VerticalClassMergerGraphLens verticalClassMergerLens = graphLens.asVerticalClassMergerLens();
if (verticalClassMergerLens != null
&& verticalClassMergerLens.hasInterfaceBeenMergedIntoClass(field.getType())) {
@@ -360,9 +393,9 @@
// If there are potential method rewritings then we need to iterate the instructions as the
// rewriting is instruction-sensitive (i.e., may be dependent on the invoke type).
- boolean hasPotentialNonTrivialFieldPutRewriting =
- hasFieldReference && graphLens.isVerticalClassMergerLens();
- if (hasPotentialNonTrivialFieldPutRewriting || hasPotentialRewrittenMethod) {
+ boolean hasPotentialNonTrivialFieldAccessRewriting =
+ hasFieldReference && graphLens.isClassMergerLens();
+ if (hasPotentialNonTrivialFieldAccessRewriting || hasPotentialRewrittenMethod) {
for (LirInstructionView view : code) {
view.accept(this);
if (hasNonTrivialRewritings) {
diff --git a/src/main/java/com/android/tools/r8/verticalclassmerging/VerticalClassMerger.java b/src/main/java/com/android/tools/r8/verticalclassmerging/VerticalClassMerger.java
index 64d6556..5d13246 100644
--- a/src/main/java/com/android/tools/r8/verticalclassmerging/VerticalClassMerger.java
+++ b/src/main/java/com/android/tools/r8/verticalclassmerging/VerticalClassMerger.java
@@ -138,6 +138,7 @@
// Finally update the code lens to signal that the code is fully up to date.
markRewrittenWithLens(executorService, timing);
+ appView.dexItemFactory().clearTypeElementsCache();
appView.notifyOptimizationFinishedForTesting();
}