Merge "Retrieve single call target without liveness if possible."
diff --git a/src/main/java/com/android/tools/r8/GenerateMainDexList.java b/src/main/java/com/android/tools/r8/GenerateMainDexList.java
index f222908..02d6475 100644
--- a/src/main/java/com/android/tools/r8/GenerateMainDexList.java
+++ b/src/main/java/com/android/tools/r8/GenerateMainDexList.java
@@ -10,9 +10,9 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.graph.DexReference;
+import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.shaking.DiscardedChecker;
import com.android.tools.r8.shaking.Enqueuer;
-import com.android.tools.r8.shaking.Enqueuer.AppInfoWithLiveness;
import com.android.tools.r8.shaking.MainDexClasses;
import com.android.tools.r8.shaking.MainDexListBuilder;
import com.android.tools.r8.shaking.RootSetBuilder;
@@ -24,8 +24,8 @@
import com.android.tools.r8.utils.ThreadUtils;
import com.android.tools.r8.utils.Timing;
import java.io.IOException;
-import java.util.HashSet;
import java.util.List;
+import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.stream.Collectors;
@@ -49,7 +49,7 @@
appView.setAppServices(AppServices.builder(appView).build());
RootSet mainDexRootSet =
- new RootSetBuilder(appView, application, options.mainDexKeepRules, options).run(executor);
+ new RootSetBuilder(appView, application, options.mainDexKeepRules).run(executor);
GraphConsumer graphConsumer = options.mainDexKeptGraphConsumer;
WhyAreYouKeepingConsumer whyAreYouKeepingConsumer = null;
@@ -59,10 +59,9 @@
}
Enqueuer enqueuer = new Enqueuer(appView, options, graphConsumer);
- AppInfoWithLiveness mainDexAppInfo = enqueuer.traceMainDex(mainDexRootSet, executor, timing);
+ Set<DexType> liveTypes = enqueuer.traceMainDex(mainDexRootSet, executor, timing);
// LiveTypes is the result.
- MainDexClasses mainDexClasses =
- new MainDexListBuilder(new HashSet<>(mainDexAppInfo.liveTypes), application).run();
+ MainDexClasses mainDexClasses = new MainDexListBuilder(liveTypes, application).run();
List<String> result =
mainDexClasses.getClasses().stream()
@@ -75,9 +74,7 @@
}
if (!mainDexRootSet.checkDiscarded.isEmpty()) {
- new DiscardedChecker(
- mainDexRootSet, mainDexClasses.getClasses(), appView.appInfo(), options)
- .run();
+ new DiscardedChecker(mainDexRootSet, mainDexClasses.getClasses(), appView).run();
}
// Print -whyareyoukeeping results if any.
if (whyAreYouKeepingConsumer != null) {
diff --git a/src/main/java/com/android/tools/r8/PrintSeeds.java b/src/main/java/com/android/tools/r8/PrintSeeds.java
index c787f02..7402eab 100644
--- a/src/main/java/com/android/tools/r8/PrintSeeds.java
+++ b/src/main/java/com/android/tools/r8/PrintSeeds.java
@@ -87,8 +87,7 @@
AppView.createForR8(new AppInfoWithSubtyping(application), options);
appView.setAppServices(AppServices.builder(appView).build());
RootSet rootSet =
- new RootSetBuilder(
- appView, application, options.getProguardConfiguration().getRules(), options)
+ new RootSetBuilder(appView, application, options.getProguardConfiguration().getRules())
.run(executor);
Enqueuer enqueuer = new Enqueuer(appView, options, null);
AppInfoWithLiveness appInfo =
diff --git a/src/main/java/com/android/tools/r8/PrintUses.java b/src/main/java/com/android/tools/r8/PrintUses.java
index f2d2143..654c144 100644
--- a/src/main/java/com/android/tools/r8/PrintUses.java
+++ b/src/main/java/com/android/tools/r8/PrintUses.java
@@ -212,7 +212,7 @@
registerTypeReference(type);
}
for (DexAnnotation annotation : method.annotations.annotations) {
- if (annotation.annotation.type == appInfo.dexItemFactory.annotationThrows) {
+ if (annotation.annotation.type == appInfo.dexItemFactory().annotationThrows) {
DexValueArray dexValues = (DexValueArray) annotation.annotation.elements[0].value;
for (DexValue dexValType : dexValues.getValues()) {
registerTypeReference(((DexValueType) dexValType).value);
@@ -302,7 +302,7 @@
}
private void analyze() {
- UseCollector useCollector = new UseCollector(appInfo.dexItemFactory);
+ UseCollector useCollector = new UseCollector(appInfo.dexItemFactory());
for (DexProgramClass dexProgramClass : application.classes()) {
useCollector.registerSuperType(dexProgramClass, dexProgramClass.superType);
for (DexType implementsType : dexProgramClass.interfaces.values) {
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index 535eb25..889b1b5 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -294,7 +294,7 @@
// Compute kotlin info before setting the roots and before
// kotlin metadata annotation is removed.
- computeKotlinInfoForProgramClasses(application, appView.appInfo());
+ computeKotlinInfoForProgramClasses(application, appView);
ProguardConfiguration.Builder compatibility =
ProguardConfiguration.builder(application.dexItemFactory, options.reporter);
@@ -313,12 +313,11 @@
rootSet =
new RootSetBuilder(
- appView,
- application,
- Iterables.concat(
- options.getProguardConfiguration().getRules(), synthesizedProguardRules),
- options
- ).run(executorService);
+ appView,
+ application,
+ Iterables.concat(
+ options.getProguardConfiguration().getRules(), synthesizedProguardRules))
+ .run(executorService);
Enqueuer enqueuer = new Enqueuer(appView, options, null, compatibility);
appView.setAppInfo(
@@ -401,15 +400,14 @@
if (!options.mainDexKeepRules.isEmpty()) {
// Find classes which may have code executed before secondary dex files installation.
mainDexRootSet =
- new RootSetBuilder(appView, application, options.mainDexKeepRules, options)
- .run(executorService);
+ new RootSetBuilder(appView, application, options.mainDexKeepRules).run(executorService);
Enqueuer enqueuer = new Enqueuer(appView, options, null);
- AppInfoWithLiveness mainDexAppInfo =
+ // Live types is the tracing result.
+ Set<DexType> mainDexBaseClasses =
enqueuer.traceMainDex(mainDexRootSet, executorService, timing);
- // LiveTypes is the tracing result.
- Set<DexType> mainDexBaseClasses = new HashSet<>(mainDexAppInfo.liveTypes);
// Calculate the automatic main dex list according to legacy multidex constraints.
mainDexClasses = new MainDexListBuilder(mainDexBaseClasses, application).run();
+ appView.appInfo().unsetObsolete();
}
if (appView.appInfo().hasLiveness()) {
@@ -508,7 +506,7 @@
// Overwrite SourceFile if specified. This step should be done after IR conversion.
timing.begin("Rename SourceFile");
- new SourceFileRewriter(appView.appInfo(), options).run();
+ new SourceFileRewriter(appView).run();
timing.end();
// Collect the already pruned types before creating a new app info without liveness.
@@ -527,16 +525,13 @@
Enqueuer enqueuer = new Enqueuer(appView, options, mainDexKeptGraphConsumer);
// Find classes which may have code executed before secondary dex files installation.
- AppInfoWithLiveness mainDexAppInfo =
+ // Live types is the tracing result.
+ Set<DexType> mainDexBaseClasses =
enqueuer.traceMainDex(mainDexRootSet, executorService, timing);
- // LiveTypes is the tracing result.
- Set<DexType> mainDexBaseClasses = new HashSet<>(mainDexAppInfo.liveTypes);
// Calculate the automatic main dex list according to legacy multidex constraints.
mainDexClasses = new MainDexListBuilder(mainDexBaseClasses, application).run();
if (!mainDexRootSet.checkDiscarded.isEmpty()) {
- new DiscardedChecker(
- mainDexRootSet, mainDexClasses.getClasses(), appView.appInfo(), options)
- .run();
+ new DiscardedChecker(mainDexRootSet, mainDexClasses.getClasses(), appView).run();
}
if (whyAreYouKeepingConsumer != null) {
for (DexReference reference : mainDexRootSet.reasonAsked) {
@@ -696,8 +691,8 @@
}
private void computeKotlinInfoForProgramClasses(
- DexApplication application, AppInfoWithSubtyping appInfo) {
- Kotlin kotlin = appInfo.dexItemFactory.kotlin;
+ DexApplication application, AppView<? extends AppInfo> appView) {
+ Kotlin kotlin = appView.dexItemFactory().kotlin;
Reporter reporter = options.reporter;
for (DexProgramClass programClass : application.classes()) {
programClass.setKotlinInfo(kotlin.getKotlinInfo(programClass, reporter));
diff --git a/src/main/java/com/android/tools/r8/cf/CfRegisterAllocator.java b/src/main/java/com/android/tools/r8/cf/CfRegisterAllocator.java
index 5f198c0..5c2b363 100644
--- a/src/main/java/com/android/tools/r8/cf/CfRegisterAllocator.java
+++ b/src/main/java/com/android/tools/r8/cf/CfRegisterAllocator.java
@@ -144,7 +144,7 @@
}
@Override
- public InternalOptions getOptions() {
+ public InternalOptions options() {
return appView.options();
}
diff --git a/src/main/java/com/android/tools/r8/cf/TypeVerificationHelper.java b/src/main/java/com/android/tools/r8/cf/TypeVerificationHelper.java
index d84f551..69517f9 100644
--- a/src/main/java/com/android/tools/r8/cf/TypeVerificationHelper.java
+++ b/src/main/java/com/android/tools/r8/cf/TypeVerificationHelper.java
@@ -217,7 +217,7 @@
}
private TypeLatticeElement getLatticeElement(DexType type) {
- return TypeLatticeElement.fromDexType(type, Nullability.maybeNull(), appView.appInfo());
+ return TypeLatticeElement.fromDexType(type, Nullability.maybeNull(), appView);
}
public Map<Value, TypeInfo> computeVerificationTypes() {
diff --git a/src/main/java/com/android/tools/r8/graph/AppInfo.java b/src/main/java/com/android/tools/r8/graph/AppInfo.java
index 1754ad9..fa2947b 100644
--- a/src/main/java/com/android/tools/r8/graph/AppInfo.java
+++ b/src/main/java/com/android/tools/r8/graph/AppInfo.java
@@ -9,7 +9,6 @@
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMap.Builder;
import com.google.common.collect.ImmutableSet;
-import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
@@ -19,8 +18,8 @@
public class AppInfo implements DexDefinitionSupplier {
- public final DexApplication app;
- public final DexItemFactory dexItemFactory;
+ private final DexApplication app;
+ private final DexItemFactory dexItemFactory;
private final ConcurrentHashMap<DexType, Map<Descriptor<?,?>, KeyedDexItem<?>>> definitions =
new ConcurrentHashMap<>();
// For some optimizations, e.g. optimizing synthetic classes, we may need to resolve the current
@@ -28,38 +27,60 @@
private final ConcurrentHashMap<DexType, DexProgramClass> synthesizedClasses =
new ConcurrentHashMap<>();
+ // Set when a new AppInfo replaces a previous one. All public methods should verify that the
+ // current instance is not obsolete, to ensure that we almost use the most recent AppInfo.
+ private boolean obsolete;
+
public AppInfo(DexApplication application) {
this.app = application;
this.dexItemFactory = app.dexItemFactory;
}
protected AppInfo(AppInfo previous) {
+ assert !previous.isObsolete();
this.app = previous.app;
this.dexItemFactory = app.dexItemFactory;
this.definitions.putAll(previous.definitions);
this.synthesizedClasses.putAll(previous.synthesizedClasses);
}
- protected AppInfo(DirectMappedDexApplication application, GraphLense lense) {
- // Rebuild information from scratch, as the application object has changed. We do not
- // use the lense here, as it is about applied occurrences and not definitions.
- // In particular, we have to invalidate the definitions cache, as its keys are no longer
- // valid.
- this(application);
+ public boolean isObsolete() {
+ return obsolete;
+ }
+
+ public void markObsolete() {
+ obsolete = true;
+ }
+
+ public void unsetObsolete() {
+ obsolete = false;
+ }
+
+ public boolean checkIfObsolete() {
+ assert !isObsolete();
+ return true;
+ }
+
+ public DexApplication app() {
+ assert checkIfObsolete();
+ return app;
}
@Override
public DexItemFactory dexItemFactory() {
+ assert checkIfObsolete();
return dexItemFactory;
}
public void addSynthesizedClass(DexProgramClass clazz) {
+ assert checkIfObsolete();
assert clazz.type.isD8R8SynthesizedClassType();
DexProgramClass previous = synthesizedClasses.put(clazz.type, clazz);
assert previous == null || previous == clazz;
}
public Collection<DexProgramClass> getSynthesizedClassesForSanityCheck() {
+ assert checkIfObsolete();
return Collections.unmodifiableCollection(synthesizedClasses.values());
}
@@ -74,15 +95,18 @@
}
public Iterable<DexProgramClass> classes() {
+ assert checkIfObsolete();
return app.classes();
}
public Iterable<DexProgramClass> classesWithDeterministicOrder() {
+ assert checkIfObsolete();
return app.classesWithDeterministicOrder();
}
@Override
public DexDefinition definitionFor(DexReference reference) {
+ assert checkIfObsolete();
if (reference.isDexType()) {
return definitionFor(reference.asDexType());
}
@@ -95,6 +119,7 @@
@Override
public DexClass definitionFor(DexType type) {
+ assert checkIfObsolete();
DexProgramClass cached = synthesizedClasses.get(type);
if (cached != null) {
assert app.definitionFor(type) == null;
@@ -104,12 +129,14 @@
}
public Origin originFor(DexType type) {
+ assert checkIfObsolete();
DexClass definition = app.definitionFor(type);
return definition == null ? Origin.unknown() : definition.origin;
}
@Override
public DexEncodedMethod definitionFor(DexMethod method) {
+ assert checkIfObsolete();
DexType holderType = method.holder;
DexEncodedMethod cached = (DexEncodedMethod) getDefinitions(holderType).get(method);
if (cached != null && cached.isObsolete()) {
@@ -121,6 +148,7 @@
@Override
public DexEncodedField definitionFor(DexField field) {
+ assert checkIfObsolete();
return (DexEncodedField) getDefinitions(field.holder).get(field);
}
@@ -145,6 +173,7 @@
* @return The actual target for {@code method} or {@code null} if none found.
*/
public DexEncodedMethod lookupStaticTarget(DexMethod method) {
+ assert checkIfObsolete();
ResolutionResult resolutionResult = resolveMethod(method.holder, method);
DexEncodedMethod target = resolutionResult.asSingleTarget();
return target == null || target.isStatic() ? target : null;
@@ -152,16 +181,16 @@
/**
* Lookup super method following the super chain from the holder of {@code method}.
- * <p>
- * This method will resolve the method on the holder of {@code method} and only return a non-null
- * value if the result of resolution was an instance (i.e. non-static) method.
+ *
+ * <p>This method will resolve the method on the holder of {@code method} and only return a
+ * non-null value if the result of resolution was an instance (i.e. non-static) method.
*
* @param method the method to lookup
* @param invocationContext the class the invoke is contained in, i.e., the holder of the caller.
* @return The actual target for {@code method} or {@code null} if none found.
*/
- public DexEncodedMethod lookupSuperTarget(DexMethod method,
- DexType invocationContext) {
+ public DexEncodedMethod lookupSuperTarget(DexMethod method, DexType invocationContext) {
+ assert checkIfObsolete();
// Make sure we are not chasing NotFoundError.
ResolutionResult resolutionResult = resolveMethod(method.holder, method);
if (resolutionResult.asListOfTargets().isEmpty()) {
@@ -192,6 +221,7 @@
* @return The actual target for {@code method} or {@code null} if none found.
*/
public DexEncodedMethod lookupDirectTarget(DexMethod method) {
+ assert checkIfObsolete();
ResolutionResult resolutionResult = resolveMethod(method.holder, method);
DexEncodedMethod target = resolutionResult.asSingleTarget();
return target == null || target.isDirectMethod() ? target : null;
@@ -204,6 +234,7 @@
* non-null value if the result of resolution was a non-static, non-private method.
*/
public DexEncodedMethod lookupVirtualTarget(DexType type, DexMethod method) {
+ assert checkIfObsolete();
assert type.isClassType() || type.isArrayType();
ResolutionResult resolutionResult = resolveMethod(type, method);
DexEncodedMethod target = resolutionResult.asSingleTarget();
@@ -221,6 +252,7 @@
* kind of a method reference.
*/
public ResolutionResult resolveMethod(DexType holder, DexMethod method) {
+ assert checkIfObsolete();
if (holder.isArrayType()) {
return resolveMethodOnArray(holder, method);
}
@@ -241,6 +273,7 @@
* All invokations will have target java.lang.Object except clone which has no target.
*/
public ResolutionResult resolveMethodOnArray(DexType holder, DexMethod method) {
+ assert checkIfObsolete();
assert holder.isArrayType();
if (method.name == dexItemFactory.cloneMethodName) {
return EmptyResult.get();
@@ -261,6 +294,7 @@
* resolved method is used as basis for dispatch.
*/
public ResolutionResult resolveMethodOnClass(DexType holder, DexMethod method) {
+ assert checkIfObsolete();
DexClass clazz = definitionFor(holder);
// Step 1: If holder is an interface, resolution fails with an ICCE. We return null.
if (clazz == null || clazz.isInterface()) {
@@ -385,6 +419,7 @@
* resolved method is used as basis for dispatch.
*/
public ResolutionResult resolveMethodOnInterface(DexType holder, DexMethod desc) {
+ assert checkIfObsolete();
// Step 1: Lookup interface.
DexClass definition = definitionFor(holder);
// If the definition is not an interface, resolution fails with an ICCE. We just return the
@@ -419,6 +454,7 @@
* of null indicates that the field is either undefined or not an instance field.
*/
public DexEncodedField lookupInstanceTarget(DexType type, DexField field) {
+ assert checkIfObsolete();
assert type.isClassType();
DexEncodedField result = resolveFieldOn(type, field);
return result == null || result.accessFlags.isStatic() ? null : result;
@@ -431,6 +467,7 @@
* of null indicates that the field is either undefined or not a static field.
*/
public DexEncodedField lookupStaticTarget(DexType type, DexField field) {
+ assert checkIfObsolete();
assert type.isClassType();
DexEncodedField result = resolveFieldOn(type, field);
return result == null || !result.accessFlags.isStatic() ? null : result;
@@ -441,6 +478,7 @@
* #resolveFieldOn}.
*/
public DexEncodedField resolveField(DexField field) {
+ assert checkIfObsolete();
return resolveFieldOn(field.holder, field);
}
@@ -451,6 +489,7 @@
* Section 5.4.3.2 of the JVM Spec</a>.
*/
public DexEncodedField resolveFieldOn(DexType type, DexField desc) {
+ assert checkIfObsolete();
DexClass holder = definitionFor(type);
if (holder == null) {
return null;
@@ -483,6 +522,7 @@
* The only requirement is that the method is indeed static.
*/
public DexEncodedMethod dispatchStaticInvoke(ResolutionResult resolvedMethod) {
+ assert checkIfObsolete();
DexEncodedMethod target = resolvedMethod.asSingleTarget();
if (target != null && target.accessFlags.isStatic()) {
return target;
@@ -496,6 +536,7 @@
* The only requirement is that the method is not static.
*/
public DexEncodedMethod dispatchDirectInvoke(ResolutionResult resolvedMethod) {
+ assert checkIfObsolete();
DexEncodedMethod target = resolvedMethod.asSingleTarget();
if (target != null && !target.accessFlags.isStatic()) {
return target;
@@ -520,42 +561,35 @@
}
public boolean hasSubtyping() {
+ assert checkIfObsolete();
return false;
}
public AppInfoWithSubtyping withSubtyping() {
+ assert checkIfObsolete();
return null;
}
public boolean hasLiveness() {
+ assert checkIfObsolete();
return false;
}
public AppInfoWithLiveness withLiveness() {
+ assert checkIfObsolete();
return null;
}
public void registerNewType(DexType newType, DexType superType) {
// We do not track subtyping relationships in the basic AppInfo. So do nothing.
+ assert checkIfObsolete();
}
public boolean isInMainDexList(DexType type) {
+ assert checkIfObsolete();
return app.mainDexList.contains(type);
}
- public List<DexClass> getSuperTypeClasses(DexType type) {
- List<DexClass> result = new ArrayList<>();
- do {
- DexClass clazz = definitionFor(type);
- if (clazz == null) {
- break;
- }
- result.add(clazz);
- type = clazz.superType;
- } while (type != null);
- return result;
- }
-
public interface ResolutionResult {
DexEncodedMethod asResultOfResolve();
@@ -630,7 +664,6 @@
public void forEachTarget(Consumer<DexEncodedMethod> consumer) {
methods.forEach(consumer);
}
-
}
private static class EmptyResult implements ResolutionResult {
@@ -669,6 +702,5 @@
public void forEachTarget(Consumer<DexEncodedMethod> consumer) {
// Intentionally left empty.
}
-
}
}
diff --git a/src/main/java/com/android/tools/r8/graph/AppInfoWithSubtyping.java b/src/main/java/com/android/tools/r8/graph/AppInfoWithSubtyping.java
index c62df9d..293f6f1 100644
--- a/src/main/java/com/android/tools/r8/graph/AppInfoWithSubtyping.java
+++ b/src/main/java/com/android/tools/r8/graph/AppInfoWithSubtyping.java
@@ -28,6 +28,7 @@
public AppInfoWithSubtyping(DexApplication application) {
super(application);
+ // Recompute subtype map if we have modified the graph.
populateSubtypeMap(application.asDirect(), application.dexItemFactory);
}
@@ -35,29 +36,26 @@
super(previous);
missingClasses.addAll(previous.missingClasses);
subtypeMap.putAll(previous.subtypeMap);
- assert app instanceof DirectMappedDexApplication;
- }
-
- protected AppInfoWithSubtyping(DirectMappedDexApplication application, GraphLense lense) {
- super(application, lense);
- // Recompute subtype map if we have modified the graph.
- populateSubtypeMap(application, dexItemFactory);
+ assert app() instanceof DirectMappedDexApplication;
}
private DirectMappedDexApplication getDirectApplication() {
// TODO(herhut): Remove need for cast.
- return (DirectMappedDexApplication) app;
+ return (DirectMappedDexApplication) app();
}
public Iterable<DexLibraryClass> libraryClasses() {
+ assert checkIfObsolete();
return getDirectApplication().libraryClasses();
}
public Set<DexType> getMissingClasses() {
+ assert checkIfObsolete();
return Collections.unmodifiableSet(missingClasses);
}
public Set<DexType> subtypes(DexType type) {
+ assert checkIfObsolete();
assert type.isClassType();
ImmutableSet<DexType> subtypes = subtypeMap.get(type);
return subtypes == null ? ImmutableSet.of() : subtypes;
@@ -84,7 +82,7 @@
holderClass.superType.addDirectSubtype(holder);
} else {
// We found java.lang.Object
- assert dexItemFactory.objectType == holder;
+ assert dexItemFactory().objectType == holder;
}
for (DexType inter : holderClass.interfaces.values) {
populateSuperType(map, inter, baseClass, definitions);
@@ -98,8 +96,8 @@
missingClasses.add(holder);
}
// The subtype chain is broken, at least make this type a subtype of Object.
- if (holder != dexItemFactory.objectType) {
- dexItemFactory.objectType.addDirectSubtype(holder);
+ if (holder != dexItemFactory().objectType) {
+ dexItemFactory().objectType.addDirectSubtype(holder);
}
}
}
@@ -119,6 +117,7 @@
// For mapping invoke virtual instruction to target methods.
public Set<DexEncodedMethod> lookupVirtualTargets(DexMethod method) {
+ assert checkIfObsolete();
if (method.holder.isArrayType()) {
// For javac output this will only be clone(), but in general the methods from Object can
// be invoked with an array type holder.
@@ -169,6 +168,7 @@
*/
@Override
public DexEncodedMethod lookupSuperTarget(DexMethod method, DexType invocationContext) {
+ assert checkIfObsolete();
if (!invocationContext.isSubtypeOf(method.holder, this)) {
DexClass contextClass = definitionFor(invocationContext);
throw new CompilationError(
@@ -179,11 +179,13 @@
}
protected boolean hasAnyInstantiatedLambdas(DexType type) {
+ assert checkIfObsolete();
return true; // Don't know, there might be.
}
// For mapping invoke interface instruction to target methods.
public Set<DexEncodedMethod> lookupInterfaceTargets(DexMethod method) {
+ assert checkIfObsolete();
// First check that there is a target for this invoke-interface to hit. If there is none,
// this will fail at runtime.
ResolutionResult topTarget = resolveMethodOnInterface(method.holder, method);
@@ -250,6 +252,7 @@
* @return Methods implemented by the lambda expression that created the {@code callSite}.
*/
public Set<DexEncodedMethod> lookupLambdaImplementedMethods(DexCallSite callSite) {
+ assert checkIfObsolete();
List<DexType> callSiteInterfaces = LambdaDescriptor.getInterfaces(callSite, this);
if (callSiteInterfaces == null || callSiteInterfaces.isEmpty()) {
return Collections.emptySet();
@@ -290,24 +293,28 @@
}
public boolean isStringConcat(DexMethodHandle bootstrapMethod) {
+ assert checkIfObsolete();
return bootstrapMethod.type.isInvokeStatic()
- && (bootstrapMethod.asMethod() == dexItemFactory.stringConcatWithConstantsMethod
- || bootstrapMethod.asMethod() == dexItemFactory.stringConcatMethod);
+ && (bootstrapMethod.asMethod() == dexItemFactory().stringConcatWithConstantsMethod
+ || bootstrapMethod.asMethod() == dexItemFactory().stringConcatMethod);
}
@Override
public void registerNewType(DexType newType, DexType superType) {
+ assert checkIfObsolete();
// Register the relationship between this type and its superType.
superType.addDirectSubtype(newType);
}
@Override
public boolean hasSubtyping() {
+ assert checkIfObsolete();
return true;
}
@Override
public AppInfoWithSubtyping withSubtyping() {
+ assert checkIfObsolete();
return this;
}
}
diff --git a/src/main/java/com/android/tools/r8/graph/AppServices.java b/src/main/java/com/android/tools/r8/graph/AppServices.java
index ec22d85..474704a 100644
--- a/src/main/java/com/android/tools/r8/graph/AppServices.java
+++ b/src/main/java/com/android/tools/r8/graph/AppServices.java
@@ -98,7 +98,7 @@
public AppServices build() {
Iterable<ProgramResourceProvider> programResourceProviders =
- appView.appInfo().app.programResourceProviders;
+ appView.appInfo().app().programResourceProviders;
for (ProgramResourceProvider programResourceProvider : programResourceProviders) {
DataResourceProvider dataResourceProvider =
programResourceProvider.getDataResourceProvider();
diff --git a/src/main/java/com/android/tools/r8/graph/AppView.java b/src/main/java/com/android/tools/r8/graph/AppView.java
index 6448896..8d20b1c 100644
--- a/src/main/java/com/android/tools/r8/graph/AppView.java
+++ b/src/main/java/com/android/tools/r8/graph/AppView.java
@@ -26,7 +26,7 @@
private AppView(
T appInfo, WholeProgramOptimizations wholeProgramOptimizations, InternalOptions options) {
this.appInfo = appInfo;
- this.dexItemFactory = appInfo != null ? appInfo.dexItemFactory : null;
+ this.dexItemFactory = appInfo != null ? appInfo.dexItemFactory() : null;
this.wholeProgramOptimizations = wholeProgramOptimizations;
this.graphLense = GraphLense.getIdentityLense();
this.options = options;
@@ -45,7 +45,12 @@
}
public void setAppInfo(T appInfo) {
+ assert !appInfo.isObsolete();
+ AppInfo previous = this.appInfo;
this.appInfo = appInfo;
+ if (appInfo != previous) {
+ previous.markObsolete();
+ }
}
public AppServices appServices() {
diff --git a/src/main/java/com/android/tools/r8/graph/DexClass.java b/src/main/java/com/android/tools/r8/graph/DexClass.java
index 0b104f5..c6b5348 100644
--- a/src/main/java/com/android/tools/r8/graph/DexClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexClass.java
@@ -666,21 +666,22 @@
return false;
}
- public boolean isSerializable(AppInfo appInfo) {
- return type.isSerializable(appInfo);
+ public boolean isSerializable(DexDefinitionSupplier definitions) {
+ return type.isSerializable(definitions);
}
- public boolean isExternalizable(AppInfo appInfo) {
- return type.isExternalizable(appInfo);
+ public boolean isExternalizable(DexDefinitionSupplier definitions) {
+ return type.isExternalizable(definitions);
}
- public boolean classInitializationMayHaveSideEffects(AppInfo appInfo) {
- return classInitializationMayHaveSideEffects(appInfo, Predicates.alwaysFalse());
+ public boolean classInitializationMayHaveSideEffects(DexDefinitionSupplier definitions) {
+ return classInitializationMayHaveSideEffects(definitions, Predicates.alwaysFalse());
}
- public boolean classInitializationMayHaveSideEffects(AppInfo appInfo, Predicate<DexType> ignore) {
+ public boolean classInitializationMayHaveSideEffects(
+ DexDefinitionSupplier definitions, Predicate<DexType> ignore) {
if (ignore.test(type)
- || appInfo.dexItemFactory.libraryTypesWithoutStaticInitialization.contains(type)) {
+ || definitions.dexItemFactory().libraryTypesWithoutStaticInitialization.contains(type)) {
return false;
}
if (hasNonTrivialClassInitializer()) {
@@ -689,21 +690,21 @@
if (defaultValuesForStaticFieldsMayTriggerAllocation()) {
return true;
}
- return initializationOfParentTypesMayHaveSideEffects(appInfo, ignore);
+ return initializationOfParentTypesMayHaveSideEffects(definitions, ignore);
}
- public boolean initializationOfParentTypesMayHaveSideEffects(AppInfo appInfo) {
- return initializationOfParentTypesMayHaveSideEffects(appInfo, Predicates.alwaysFalse());
+ public boolean initializationOfParentTypesMayHaveSideEffects(DexDefinitionSupplier definitions) {
+ return initializationOfParentTypesMayHaveSideEffects(definitions, Predicates.alwaysFalse());
}
public boolean initializationOfParentTypesMayHaveSideEffects(
- AppInfo appInfo, Predicate<DexType> ignore) {
+ DexDefinitionSupplier definitions, Predicate<DexType> ignore) {
for (DexType iface : interfaces.values) {
- if (iface.classInitializationMayHaveSideEffects(appInfo, ignore)) {
+ if (iface.classInitializationMayHaveSideEffects(definitions, ignore)) {
return true;
}
}
- if (superType != null && superType.classInitializationMayHaveSideEffects(appInfo, ignore)) {
+ if (superType != null && superType.classInitializationMayHaveSideEffects(definitions, ignore)) {
return true;
}
return false;
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedField.java b/src/main/java/com/android/tools/r8/graph/DexEncodedField.java
index 9c7b10a..ec1506a 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedField.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedField.java
@@ -30,17 +30,17 @@
this.staticValue = staticValue;
}
- public boolean isProgramField(AppInfo appInfo) {
+ public boolean isProgramField(DexDefinitionSupplier definitions) {
if (field.holder.isClassType()) {
- DexClass clazz = appInfo.definitionFor(field.holder);
+ DexClass clazz = definitions.definitionFor(field.holder);
return clazz != null && clazz.isProgramClass();
}
return false;
}
@Override
- public void collectIndexedItems(IndexedItemCollection indexedItems,
- DexMethod method, int instructionOffset) {
+ public void collectIndexedItems(
+ IndexedItemCollection indexedItems, DexMethod method, int instructionOffset) {
field.collectIndexedItems(indexedItems, method, instructionOffset);
annotations.collectIndexedItems(indexedItems, method, instructionOffset);
if (accessFlags.isStatic()) {
diff --git a/src/main/java/com/android/tools/r8/graph/DexType.java b/src/main/java/com/android/tools/r8/graph/DexType.java
index efd4a2b..83ab503 100644
--- a/src/main/java/com/android/tools/r8/graph/DexType.java
+++ b/src/main/java/com/android/tools/r8/graph/DexType.java
@@ -116,21 +116,24 @@
return hierarchyLevel == INTERFACE_LEVEL;
}
- public boolean isExternalizable(AppInfo appInfo) {
- return implementedInterfaces(appInfo).contains(appInfo.dexItemFactory.externalizableType);
+ public boolean isExternalizable(DexDefinitionSupplier definitions) {
+ return implementedInterfaces(definitions)
+ .contains(definitions.dexItemFactory().externalizableType);
}
- public boolean isSerializable(AppInfo appInfo) {
- return implementedInterfaces(appInfo).contains(appInfo.dexItemFactory.serializableType);
+ public boolean isSerializable(DexDefinitionSupplier definitions) {
+ return implementedInterfaces(definitions)
+ .contains(definitions.dexItemFactory().serializableType);
}
- public boolean classInitializationMayHaveSideEffects(AppInfo appInfo) {
- return classInitializationMayHaveSideEffects(appInfo, Predicates.alwaysFalse());
+ public boolean classInitializationMayHaveSideEffects(DexDefinitionSupplier definitions) {
+ return classInitializationMayHaveSideEffects(definitions, Predicates.alwaysFalse());
}
- public boolean classInitializationMayHaveSideEffects(AppInfo appInfo, Predicate<DexType> ignore) {
- DexClass clazz = appInfo.definitionFor(this);
- return clazz == null || clazz.classInitializationMayHaveSideEffects(appInfo, ignore);
+ public boolean classInitializationMayHaveSideEffects(
+ DexDefinitionSupplier definitions, Predicate<DexType> ignore) {
+ DexClass clazz = definitions.definitionFor(this);
+ return clazz == null || clazz.classInitializationMayHaveSideEffects(definitions, ignore);
}
public boolean initializationOfParentTypesMayHaveSideEffects(AppInfo appInfo) {
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/TypeChecker.java b/src/main/java/com/android/tools/r8/ir/analysis/TypeChecker.java
index 75a9726..b8a8f04 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/TypeChecker.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/TypeChecker.java
@@ -30,10 +30,10 @@
*/
public class TypeChecker {
- private final AppInfo appInfo;
+ private final AppView<? extends AppInfo> appView;
public TypeChecker(AppView<? extends AppInfo> appView) {
- this.appInfo = appView.appInfo();
+ this.appView = appView;
}
public boolean check(IRCode code) {
@@ -72,8 +72,9 @@
? instruction.asInstancePut().value()
: instruction.asStaticPut().inValue();
TypeLatticeElement valueType = value.getTypeLattice();
- TypeLatticeElement fieldType = TypeLatticeElement.fromDexType(
- instruction.getField().type, valueType.nullability(), appInfo);
+ TypeLatticeElement fieldType =
+ TypeLatticeElement.fromDexType(
+ instruction.getField().type, valueType.nullability(), appView);
if (isSubtypeOf(valueType, fieldType)) {
return true;
}
@@ -81,7 +82,7 @@
if (fieldType.isClassType() && valueType.isReference()) {
// Interface types are treated like Object according to the JVM spec.
// https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.10.1.2-100
- DexClass clazz = appInfo.definitionFor(instruction.getField().type);
+ DexClass clazz = appView.definitionFor(instruction.getField().type);
return clazz != null && clazz.isInterface();
}
@@ -90,15 +91,16 @@
public boolean check(Throw instruction) {
TypeLatticeElement valueType = instruction.exception().getTypeLattice();
- TypeLatticeElement throwableType = TypeLatticeElement.fromDexType(
- appInfo.dexItemFactory.throwableType, valueType.nullability(), appInfo);
+ TypeLatticeElement throwableType =
+ TypeLatticeElement.fromDexType(
+ appView.dexItemFactory().throwableType, valueType.nullability(), appView);
return isSubtypeOf(valueType, throwableType);
}
private boolean isSubtypeOf(
TypeLatticeElement expectedSubtype, TypeLatticeElement expectedSupertype) {
return (expectedSubtype.isNullType() && expectedSupertype.isReference())
- || expectedSubtype.lessThanOrEqual(expectedSupertype, appInfo)
- || expectedSubtype.isBasedOnMissingClass(appInfo);
+ || expectedSubtype.lessThanOrEqual(expectedSupertype, appView)
+ || expectedSubtype.isBasedOnMissingClass(appView);
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/BasicBlock.java b/src/main/java/com/android/tools/r8/ir/code/BasicBlock.java
index a3a230d..b5bbf89 100644
--- a/src/main/java/com/android/tools/r8/ir/code/BasicBlock.java
+++ b/src/main/java/com/android/tools/r8/ir/code/BasicBlock.java
@@ -1307,7 +1307,7 @@
public static BasicBlock createRethrowBlock(
IRCode code, Position position, DexType guard, AppView<? extends AppInfo> appView) {
TypeLatticeElement guardTypeLattice =
- TypeLatticeElement.fromDexType(guard, Nullability.definitelyNotNull(), appView.appInfo());
+ TypeLatticeElement.fromDexType(guard, Nullability.definitelyNotNull(), appView);
BasicBlock block = new BasicBlock();
MoveException moveException =
new MoveException(
diff --git a/src/main/java/com/android/tools/r8/ir/code/Binop.java b/src/main/java/com/android/tools/r8/ir/code/Binop.java
index 78827cd..40ce694 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Binop.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Binop.java
@@ -53,11 +53,10 @@
int leftRegister = allocator.getRegisterForValue(leftValue(), getNumber());
int rightRegister = allocator.getRegisterForValue(rightValue(), getNumber());
int destRegister = allocator.getRegisterForValue(outValue, getNumber());
- return ((leftRegister == destRegister) ||
- (isCommutative() && rightRegister == destRegister)) &&
- leftRegister <= U4BIT_MAX &&
- rightRegister <= U4BIT_MAX &&
- !(allocator.getOptions().canHaveMul2AddrBug() && isMul());
+ return ((leftRegister == destRegister) || (isCommutative() && rightRegister == destRegister))
+ && leftRegister <= U4BIT_MAX
+ && rightRegister <= U4BIT_MAX
+ && !(allocator.options().canHaveMul2AddrBug() && isMul());
}
return false;
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/Instruction.java b/src/main/java/com/android/tools/r8/ir/code/Instruction.java
index 9c28e92..4714251 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Instruction.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Instruction.java
@@ -436,7 +436,7 @@
}
// In debug mode or if the instruction can throw we must account for positions, in release mode
// we do want to share non-throwing instructions even if their positions differ.
- if (instructionTypeCanThrow() || allocator.getOptions().debug) {
+ if (instructionTypeCanThrow() || allocator.options().debug) {
if (!identicalNonValueParts(other)) {
return false;
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/StackValue.java b/src/main/java/com/android/tools/r8/ir/code/StackValue.java
index 18019dc..40407db 100644
--- a/src/main/java/com/android/tools/r8/ir/code/StackValue.java
+++ b/src/main/java/com/android/tools/r8/ir/code/StackValue.java
@@ -25,8 +25,7 @@
TypeInfo typeInfo, int height, AppView<? extends AppInfo> appView) {
return new StackValue(
typeInfo,
- TypeLatticeElement.fromDexType(
- typeInfo.getDexType(), Nullability.maybeNull(), appView.appInfo()),
+ TypeLatticeElement.fromDexType(typeInfo.getDexType(), Nullability.maybeNull(), appView),
height);
}
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
index 37102ef..6a6cd08 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
@@ -148,8 +148,10 @@
private List<Action> onWaveDoneActions = null;
- // The argument `appView` is only available when full program optimizations are allowed
- // (i.e., when running R8).
+ /**
+ * The argument `appView` is used to determine if whole program optimizations are allowed or not
+ * (i.e., whether we are running R8). See {@link AppView#enableWholeProgramOptimizations()}.
+ */
public IRConverter(
AppView<? extends AppInfo> appView,
Timing timing,
@@ -727,14 +729,13 @@
private DexType computeOutlineClassType() {
DexType result;
int count = 0;
- AppInfo appInfo = appView.appInfo();
do {
String name = OutlineOptions.CLASS_NAME + (count == 0 ? "" : Integer.toString(count));
count++;
- result = appInfo.dexItemFactory.createType(DescriptorUtils.javaTypeToDescriptor(name));
- } while (appInfo.definitionFor(result) != null);
+ result = appView.dexItemFactory().createType(DescriptorUtils.javaTypeToDescriptor(name));
+ } while (appView.definitionFor(result) != null);
// Register the newly generated type in the subtyping hierarchy, if we have one.
- appInfo.registerNewType(result, appInfo.dexItemFactory.objectType);
+ appView.appInfo().registerNewType(result, appView.dexItemFactory().objectType);
return result;
}
@@ -1270,8 +1271,7 @@
deadCodeRemover.run(code);
materializeInstructionBeforeLongOperationsWorkaround(code);
workaroundForwardingInitializerBug(code);
- LinearScanRegisterAllocator registerAllocator =
- new LinearScanRegisterAllocator(appView.appInfo(), code, options);
+ LinearScanRegisterAllocator registerAllocator = new LinearScanRegisterAllocator(appView, code);
registerAllocator.allocateRegisters();
if (options.canHaveExceptionTargetingLoopHeaderBug()) {
codeRewriter.workaroundExceptionTargetingLoopHeaderBug(code);
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java b/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java
index 7b58034..2a35299 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java
@@ -91,7 +91,6 @@
* Replace type appearances, invoke targets and field accesses with actual definitions.
*/
public void rewrite(IRCode code, DexEncodedMethod method) {
- AppInfo appInfo = appView.appInfo();
GraphLense graphLense = appView.graphLense();
Set<Value> newSSAValues = Sets.newIdentityHashSet();
@@ -112,12 +111,16 @@
InvokeCustom invokeCustom = current.asInvokeCustom();
DexCallSite callSite = invokeCustom.getCallSite();
DexProto newMethodProto =
- appInfo.dexItemFactory.applyClassMappingToProto(
- callSite.methodProto, graphLense::lookupType, protoFixupCache);
+ appView
+ .dexItemFactory()
+ .applyClassMappingToProto(
+ callSite.methodProto, graphLense::lookupType, protoFixupCache);
DexMethodHandle newBootstrapMethod = rewriteDexMethodHandle(
callSite.bootstrapMethod, method, NOT_ARGUMENT_TO_LAMBDA_METAFACTORY);
boolean isLambdaMetaFactory =
- appInfo.dexItemFactory.isLambdaMetafactoryMethod(callSite.bootstrapMethod.asMethod());
+ appView
+ .dexItemFactory()
+ .isLambdaMetafactoryMethod(callSite.bootstrapMethod.asMethod());
MethodHandleUse methodHandleUse = isLambdaMetaFactory
? ARGUMENT_TO_LAMBDA_METAFACTORY
: NOT_ARGUMENT_TO_LAMBDA_METAFACTORY;
@@ -127,8 +130,10 @@
|| newBootstrapMethod != callSite.bootstrapMethod
|| !newArgs.equals(callSite.bootstrapArgs)) {
DexCallSite newCallSite =
- appInfo.dexItemFactory.createCallSite(
- callSite.methodName, newMethodProto, newBootstrapMethod, newArgs);
+ appView
+ .dexItemFactory()
+ .createCallSite(
+ callSite.methodName, newMethodProto, newBootstrapMethod, newArgs);
InvokeCustom newInvokeCustom = new InvokeCustom(newCallSite, invokeCustom.outValue(),
invokeCustom.inValues());
iterator.replaceCurrentInstruction(newInvokeCustom);
@@ -147,16 +152,17 @@
DexMethod invokedMethod = invoke.getInvokedMethod();
DexType invokedHolder = invokedMethod.holder;
if (invokedHolder.isArrayType()) {
- DexType baseType = invokedHolder.toBaseType(appInfo.dexItemFactory);
+ DexType baseType = invokedHolder.toBaseType(appView.dexItemFactory());
DexType mappedBaseType = graphLense.lookupType(baseType);
if (baseType != mappedBaseType) {
DexType mappedHolder =
- invokedHolder.replaceBaseType(mappedBaseType, appInfo.dexItemFactory);
+ invokedHolder.replaceBaseType(mappedBaseType, appView.dexItemFactory());
// Just reuse proto and name, as no methods on array types can be renamed nor
// change signature.
DexMethod actualTarget =
- appInfo.dexItemFactory.createMethod(
- mappedHolder, invokedMethod.proto, invokedMethod.name);
+ appView
+ .dexItemFactory()
+ .createMethod(mappedHolder, invokedMethod.proto, invokedMethod.name);
Invoke newInvoke =
Invoke.create(
VIRTUAL,
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java b/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java
index 1bb56ea..857de34 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java
@@ -470,11 +470,11 @@
abstract boolean ensureAccessibility();
DexClass definitionFor(DexType type) {
- return rewriter.converter.appView.appInfo().app.definitionFor(type);
+ return rewriter.converter.appView.appInfo().app().definitionFor(type);
}
DexProgramClass programDefinitionFor(DexType type) {
- return rewriter.converter.appView.appInfo().app.programDefinitionFor(type);
+ return rewriter.converter.appView.appInfo().app().programDefinitionFor(type);
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/LambdaDescriptor.java b/src/main/java/com/android/tools/r8/ir/desugar/LambdaDescriptor.java
index 235c96d..20becfb 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/LambdaDescriptor.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/LambdaDescriptor.java
@@ -237,7 +237,7 @@
return LambdaDescriptor.MATCH_FAILED;
}
- DexItemFactory factory = appInfo.dexItemFactory;
+ DexItemFactory factory = appInfo.dexItemFactory();
DexMethod bootstrapMethod = callSite.bootstrapMethod.asMethod();
if (!factory.isLambdaMetafactoryMethod(bootstrapMethod)) {
// It is not a lambda, thus no need to manage this call site.
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/LambdaRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/LambdaRewriter.java
index 92d7a9d..064f105 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/LambdaRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/LambdaRewriter.java
@@ -273,8 +273,7 @@
// The out value might be empty in case it was optimized out.
lambdaInstanceValue =
code.createValue(
- TypeLatticeElement.fromDexType(
- lambdaClass.type, Nullability.maybeNull(), appView.appInfo()));
+ TypeLatticeElement.fromDexType(lambdaClass.type, Nullability.maybeNull(), appView));
}
// For stateless lambdas we replace InvokeCustom instruction with StaticGet
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/StringConcatRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/StringConcatRewriter.java
index 4e7636c..e31924e 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/StringConcatRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/StringConcatRewriter.java
@@ -340,8 +340,7 @@
// new-instance v0, StringBuilder
TypeLatticeElement stringBuilderTypeLattice =
- TypeLatticeElement.fromDexType(
- factory.stringBuilderType, definitelyNotNull(), appView.appInfo());
+ TypeLatticeElement.fromDexType(factory.stringBuilderType, definitelyNotNull(), appView);
Value sbInstance = code.createValue(stringBuilderTypeLattice);
appendInstruction(new NewInstance(factory.stringBuilderType, sbInstance));
@@ -364,8 +363,7 @@
if (concatValue == null) {
// The out value might be empty in case it was optimized out.
concatValue =
- code.createValue(
- TypeLatticeElement.stringClassType(appView.appInfo(), definitelyNotNull()));
+ code.createValue(TypeLatticeElement.stringClassType(appView, definitelyNotNull()));
}
// Replace the instruction.
@@ -444,8 +442,7 @@
@Override
Value getOrCreateValue() {
Value value =
- code.createValue(
- TypeLatticeElement.stringClassType(appView.appInfo(), definitelyNotNull()));
+ code.createValue(TypeLatticeElement.stringClassType(appView, definitelyNotNull()));
appendInstruction(
new ConstString(
value,
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/TwrCloseResourceRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/TwrCloseResourceRewriter.java
index f8ebb06..566caf1 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/TwrCloseResourceRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/TwrCloseResourceRewriter.java
@@ -49,12 +49,12 @@
// tree shaking to remove them since now they should not be referenced.
//
public final class TwrCloseResourceRewriter {
+
public static final String UTILITY_CLASS_NAME = "$r8$twr$utility";
public static final String UTILITY_CLASS_DESCRIPTOR = "L$r8$twr$utility;";
private final AppView<? extends AppInfo> appView;
private final IRConverter converter;
- private final DexItemFactory factory;
private final DexMethod twrCloseResourceMethod;
@@ -63,13 +63,15 @@
public TwrCloseResourceRewriter(AppView<? extends AppInfo> appView, IRConverter converter) {
this.appView = appView;
this.converter = converter;
- this.factory = appView.dexItemFactory();
- DexType twrUtilityClass = factory.createType(UTILITY_CLASS_DESCRIPTOR);
- DexProto twrCloseResourceProto = factory.createProto(
- factory.voidType, factory.throwableType, factory.objectType);
- this.twrCloseResourceMethod = factory.createMethod(
- twrUtilityClass, twrCloseResourceProto, factory.twrCloseResourceMethodName);
+ DexItemFactory dexItemFactory = appView.dexItemFactory();
+ DexType twrUtilityClass = dexItemFactory.createType(UTILITY_CLASS_DESCRIPTOR);
+ DexProto twrCloseResourceProto =
+ dexItemFactory.createProto(
+ dexItemFactory.voidType, dexItemFactory.throwableType, dexItemFactory.objectType);
+ this.twrCloseResourceMethod =
+ dexItemFactory.createMethod(
+ twrUtilityClass, twrCloseResourceProto, dexItemFactory.twrCloseResourceMethodName);
}
// Rewrites calls to $closeResource() method. Can be invoked concurrently.
@@ -111,7 +113,7 @@
// right attributes, but it still does not guarantee much since we also
// need to look into code and doing this seems an overkill
//
- DexItemFactory dexItemFactory = appView.appInfo().dexItemFactory;
+ DexItemFactory dexItemFactory = appView.dexItemFactory();
return original.name == dexItemFactory.twrCloseResourceMethodName
&& original.proto == dexItemFactory.twrCloseResourceMethodProto;
}
@@ -137,7 +139,7 @@
null,
new SynthesizedOrigin("twr utility class", getClass()),
ClassAccessFlags.fromSharedAccessFlags(Constants.ACC_PUBLIC | Constants.ACC_SYNTHETIC),
- factory.objectType,
+ appView.dexItemFactory().objectType,
DexTypeList.empty(),
null,
null,
@@ -145,9 +147,9 @@
DexAnnotationSet.empty(),
DexEncodedField.EMPTY_ARRAY,
DexEncodedField.EMPTY_ARRAY,
- new DexEncodedMethod[]{method},
+ new DexEncodedMethod[] {method},
DexEncodedMethod.EMPTY_ARRAY,
- factory.getSkipNameValidationForTesting(),
+ appView.dexItemFactory().getSkipNameValidationForTesting(),
referencingClasses);
code.setUpContext(utilityClass);
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java b/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
index 240ad73..d0bd538 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
@@ -1575,15 +1575,14 @@
private boolean checkArgumentType(InvokeMethod invoke, int argumentIndex) {
// TODO(sgjesse): Insert cast if required.
- AppInfo appInfo = appView.appInfo();
TypeLatticeElement returnType =
TypeLatticeElement.fromDexType(
- invoke.getInvokedMethod().proto.returnType, maybeNull(), appInfo);
+ invoke.getInvokedMethod().proto.returnType, maybeNull(), appView);
TypeLatticeElement argumentType =
TypeLatticeElement.fromDexType(
- getArgumentType(invoke, argumentIndex), maybeNull(), appInfo);
+ getArgumentType(invoke, argumentIndex), maybeNull(), appView);
return appView.enableWholeProgramOptimizations()
- ? argumentType.lessThanOrEqual(returnType, appInfo)
+ ? argumentType.lessThanOrEqual(returnType, appView)
: argumentType.equals(returnType);
}
@@ -1879,7 +1878,6 @@
// Returns true if the given check-cast instruction was removed.
private boolean removeCheckCastInstructionIfTrivial(
CheckCast checkCast, InstructionIterator it, IRCode code) {
- AppInfo appInfo = appView.appInfo();
Value inValue = checkCast.object();
Value outValue = checkCast.outValue();
DexType castType = checkCast.getType();
@@ -1916,11 +1914,11 @@
TypeLatticeElement inTypeLattice = inValue.getTypeLattice();
TypeLatticeElement outTypeLattice = outValue.getTypeLattice();
TypeLatticeElement castTypeLattice =
- TypeLatticeElement.fromDexType(castType, inTypeLattice.nullability(), appInfo);
+ TypeLatticeElement.fromDexType(castType, inTypeLattice.nullability(), appView);
assert inTypeLattice.nullability().lessThanOrEqual(outTypeLattice.nullability());
- if (inTypeLattice.lessThanOrEqual(castTypeLattice, appInfo)) {
+ if (inTypeLattice.lessThanOrEqual(castTypeLattice, appView)) {
// 1) Trivial cast.
// A a = ...
// A a' = (A) a;
@@ -1928,7 +1926,7 @@
// A < B
// A a = ...
// B b = (B) a;
- assert inTypeLattice.lessThanOrEqual(outTypeLattice, appInfo);
+ assert inTypeLattice.lessThanOrEqual(outTypeLattice, appView);
removeOrReplaceByDebugLocalWrite(checkCast, it, inValue, outValue);
return true;
}
@@ -1944,19 +1942,18 @@
}
private boolean isTypeInaccessibleInCurrentContext(DexType type, DexEncodedMethod context) {
- AppInfo appInfo = appView.appInfo();
- DexType baseType = type.toBaseType(appInfo.dexItemFactory);
+ DexType baseType = type.toBaseType(appView.dexItemFactory());
if (baseType.isPrimitiveType()) {
return false;
}
- DexClass clazz = appInfo.definitionFor(baseType);
+ DexClass clazz = appView.definitionFor(baseType);
if (clazz == null) {
// Conservatively say yes.
return true;
}
ConstraintWithTarget classVisibility =
ConstraintWithTarget.deriveConstraint(
- context.method.holder, baseType, clazz.accessFlags, appInfo);
+ context.method.holder, baseType, clazz.accessFlags, appView);
return classVisibility == ConstraintWithTarget.NEVER;
}
@@ -1969,22 +1966,21 @@
return false;
}
- AppInfo appInfo = appView.appInfo();
Value inValue = instanceOf.value();
TypeLatticeElement inType = inValue.getTypeLattice();
TypeLatticeElement instanceOfType =
- TypeLatticeElement.fromDexType(instanceOf.type(), inType.nullability(), appInfo);
+ TypeLatticeElement.fromDexType(instanceOf.type(), inType.nullability(), appView);
InstanceOfResult result = InstanceOfResult.UNKNOWN;
if (inType.isDefinitelyNull()) {
result = InstanceOfResult.FALSE;
- } else if (inType.lessThanOrEqual(instanceOfType, appInfo) && !inType.isNullable()) {
+ } else if (inType.lessThanOrEqual(instanceOfType, appView) && !inType.isNullable()) {
result = InstanceOfResult.TRUE;
} else if (!inValue.isPhi()
&& inValue.definition.isCreatingInstanceOrArray()
- && instanceOfType.strictlyLessThan(inType, appInfo)) {
+ && instanceOfType.strictlyLessThan(inType, appView)) {
result = InstanceOfResult.FALSE;
- } else if (appInfo.hasLiveness()) {
+ } else if (appView.appInfo().hasLiveness()) {
if (instanceOf.type().isClassType()
&& isNeverInstantiatedDirectlyOrIndirectly(instanceOf.type())) {
// The type of the instance-of instruction is a program class, and is never instantiated
@@ -2018,13 +2014,12 @@
}
private boolean isNeverInstantiatedDirectlyOrIndirectly(DexType type) {
- AppInfo appInfo = appView.appInfo();
- assert appInfo.hasLiveness();
+ assert appView.appInfo().hasLiveness();
assert type.isClassType();
- DexClass clazz = appInfo.definitionFor(type);
+ DexClass clazz = appView.definitionFor(type);
return clazz != null
&& clazz.isProgramClass()
- && !appInfo.withLiveness().isInstantiatedDirectlyOrIndirectly(type);
+ && !appView.appInfo().withLiveness().isInstantiatedDirectlyOrIndirectly(type);
}
public static void removeOrReplaceByDebugLocalWrite(
@@ -3641,7 +3636,7 @@
private Value addConstString(IRCode code, InstructionListIterator iterator, String s) {
TypeLatticeElement typeLattice =
- TypeLatticeElement.stringClassType(appView.appInfo(), definitelyNotNull());
+ TypeLatticeElement.stringClassType(appView, definitelyNotNull());
Value value = code.createValue(typeLattice);
ThrowingInfo throwingInfo =
options.isGeneratingClassFiles() ? ThrowingInfo.NO_THROW : ThrowingInfo.CAN_THROW;
@@ -3675,8 +3670,7 @@
DexType javaIoPrintStreamType = dexItemFactory.createType("Ljava/io/PrintStream;");
Value out =
code.createValue(
- TypeLatticeElement.fromDexType(
- javaIoPrintStreamType, definitelyNotNull(), appView.appInfo()));
+ TypeLatticeElement.fromDexType(javaIoPrintStreamType, definitelyNotNull(), appView));
DexProto proto = dexItemFactory.createProto(dexItemFactory.voidType, dexItemFactory.objectType);
DexMethod print = dexItemFactory.createMethod(javaIoPrintStreamType, proto, "print");
@@ -3741,9 +3735,7 @@
iterator.add(new InvokeVirtual(print, null, ImmutableList.of(out, nul)));
iterator = isNotNullBlock.listIterator();
iterator.setInsertionPosition(position);
- value =
- code.createValue(
- TypeLatticeElement.classClassType(appView.appInfo(), definitelyNotNull()));
+ value = code.createValue(TypeLatticeElement.classClassType(appView, definitelyNotNull()));
iterator.add(new InvokeVirtual(dexItemFactory.objectMethods.getClass, value,
ImmutableList.of(arguments.get(i))));
iterator.add(new InvokeVirtual(print, null, ImmutableList.of(out, value)));
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/Devirtualizer.java b/src/main/java/com/android/tools/r8/ir/optimize/Devirtualizer.java
index 8fc16fe..a62c4a1 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/Devirtualizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/Devirtualizer.java
@@ -145,11 +145,11 @@
TypeLatticeElement receiverTypeLattice = receiver.getTypeLattice();
TypeLatticeElement castTypeLattice =
TypeLatticeElement.fromDexType(
- holderType, receiverTypeLattice.nullability(), appView.appInfo());
+ holderType, receiverTypeLattice.nullability(), appView);
// Avoid adding trivial cast and up-cast.
// We should not use strictlyLessThan(castType, receiverType), which detects downcast,
// due to side-casts, e.g., A (unused) < I, B < I, and cast from A to B.
- if (!receiverTypeLattice.lessThanOrEqual(castTypeLattice, appView.appInfo())) {
+ if (!receiverTypeLattice.lessThanOrEqual(castTypeLattice, appView)) {
Value newReceiver = null;
// If this value is ever downcast'ed to the same holder type before, and that casted
// value is safely accessible, i.e., the current line is dominated by that cast, use it.
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java b/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
index 55876af..bf92dfa 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
@@ -63,12 +63,12 @@
public Inliner(AppView<AppInfoWithLiveness> appView, MainDexClasses mainDexClasses) {
this.appView = appView;
this.mainDexClasses = mainDexClasses;
- fillInBlackList(appView.appInfo());
+ fillInBlackList();
}
- private void fillInBlackList(AppInfoWithLiveness appInfo) {
- blackList.add(appInfo.dexItemFactory.kotlin.intrinsics.throwParameterIsNullException);
- blackList.add(appInfo.dexItemFactory.kotlin.intrinsics.throwNpe);
+ private void fillInBlackList() {
+ blackList.add(appView.dexItemFactory().kotlin.intrinsics.throwParameterIsNullException);
+ blackList.add(appView.dexItemFactory().kotlin.intrinsics.throwNpe);
}
public boolean isBlackListed(DexMethod method) {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java b/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java
index 36e9f25..166ce52 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java
@@ -94,7 +94,7 @@
&& rule.hasReturnValue() && rule.getReturnValue().isField()) {
DexField field = rule.getReturnValue().getField();
assert typeLattice
- == TypeLatticeElement.fromDexType(field.type, Nullability.maybeNull(), appView.appInfo());
+ == TypeLatticeElement.fromDexType(field.type, Nullability.maybeNull(), appView);
DexEncodedField staticField = appView.appInfo().lookupStaticTarget(field.holder, field);
if (staticField != null) {
Value value = code.createValue(typeLattice, instruction.getLocalInfo());
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/PeepholeOptimizer.java b/src/main/java/com/android/tools/r8/ir/optimize/PeepholeOptimizer.java
index 5e32629..66a1106 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/PeepholeOptimizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/PeepholeOptimizer.java
@@ -413,7 +413,7 @@
changed = true;
int otherPredIndex = blockToIndex.get(wrapper);
BasicBlock otherPred = block.getPredecessors().get(otherPredIndex);
- assert !allocator.getOptions().debug
+ assert !allocator.options().debug
|| Objects.equals(pred.getPosition(), otherPred.getPosition());
allocator.mergeBlocks(otherPred, pred);
pred.clearCatchHandlers();
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/SwitchUtils.java b/src/main/java/com/android/tools/r8/ir/optimize/SwitchUtils.java
index 8313b09..dbe3f71 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/SwitchUtils.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/SwitchUtils.java
@@ -72,7 +72,7 @@
InvokeVirtual ordinalInvoke = index.asInvokeVirtual();
DexMethod ordinalMethod = ordinalInvoke.getInvokedMethod();
DexClass enumClass = appInfo.definitionFor(ordinalMethod.holder);
- DexItemFactory dexItemFactory = appInfo.dexItemFactory;
+ DexItemFactory dexItemFactory = appInfo.dexItemFactory();
// After member rebinding, enumClass will be the actual java.lang.Enum class.
if (enumClass == null
|| (!enumClass.accessFlags.isEnum() && enumClass.type != dexItemFactory.enumType)
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/UnusedArgumentsCollector.java b/src/main/java/com/android/tools/r8/ir/optimize/UnusedArgumentsCollector.java
index ad5f3be..1a71b05 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/UnusedArgumentsCollector.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/UnusedArgumentsCollector.java
@@ -134,7 +134,7 @@
}
assert newIndex == parameters.length;
}
- return appView.appInfo().dexItemFactory.createProto(method.proto.returnType, parameters);
+ return appView.dexItemFactory().createProto(method.proto.returnType, parameters);
}
private boolean isMethodSignatureAvailable(DexMethod method) {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KotlinLambdaGroupCodeStrategy.java b/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KotlinLambdaGroupCodeStrategy.java
index 48967c3..a5d8c39 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KotlinLambdaGroupCodeStrategy.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KotlinLambdaGroupCodeStrategy.java
@@ -120,7 +120,7 @@
group.getGroupClassType(),
context.code.createValue(
TypeLatticeElement.fromDexType(
- newInstance.clazz, definitelyNotNull(), context.appView.appInfo())));
+ newInstance.clazz, definitelyNotNull(), context.appView)));
context.instructions().replaceCurrentInstruction(patchedNewInstance);
}
@@ -167,7 +167,7 @@
// Since all captured values of non-primitive types are stored in fields of type
// java.lang.Object, we need to cast them to appropriate type to satisfy the verifier.
TypeLatticeElement castTypeLattice =
- TypeLatticeElement.fromDexType(fieldType, definitelyNotNull(), context.appView.appInfo());
+ TypeLatticeElement.fromDexType(fieldType, definitelyNotNull(), context.appView);
Value newValue = context.code.createValue(castTypeLattice, newInstanceGet.getLocalInfo());
newInstanceGet.outValue().replaceUsers(newValue);
CheckCast cast = new CheckCast(newValue, newInstanceGet.outValue(), fieldType);
@@ -232,7 +232,7 @@
return returnType == context.factory.voidType
? null
: context.code.createValue(
- TypeLatticeElement.fromDexType(returnType, maybeNull(), context.appView.appInfo()));
+ TypeLatticeElement.fromDexType(returnType, maybeNull(), context.appView));
}
private List<Value> mapInitializerArgs(
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/staticizer/StaticizingProcessor.java b/src/main/java/com/android/tools/r8/ir/optimize/staticizer/StaticizingProcessor.java
index ec23f05..7791af1 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/staticizer/StaticizingProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/staticizer/StaticizingProcessor.java
@@ -444,10 +444,9 @@
? null
: code.createValue(
TypeLatticeElement.fromDexType(
- method.proto.returnType, maybeNull(), classStaticizer.appView.appInfo()),
+ method.proto.returnType, maybeNull(), classStaticizer.appView),
outValue == null ? null : outValue.getLocalInfo());
- it.replaceCurrentInstruction(
- new InvokeStatic(newMethod, newOutValue, invoke.inValues()));
+ it.replaceCurrentInstruction(new InvokeStatic(newMethod, newOutValue, invoke.inValues()));
}
continue;
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/string/StringOptimizer.java b/src/main/java/com/android/tools/r8/ir/optimize/string/StringOptimizer.java
index 35ddb6f..b305be4 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/string/StringOptimizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/string/StringOptimizer.java
@@ -120,7 +120,7 @@
String sub = rcvString.substring(beginIndexValue, endIndexValue);
Value stringValue =
code.createValue(
- TypeLatticeElement.stringClassType(appView.appInfo(), definitelyNotNull()),
+ TypeLatticeElement.stringClassType(appView, definitelyNotNull()),
invoke.getLocalInfo());
it.replaceCurrentInstruction(
new ConstString(stringValue, factory.createString(sub), throwingInfo));
@@ -335,7 +335,7 @@
if (name != null) {
Value stringValue =
code.createValue(
- TypeLatticeElement.stringClassType(appView.appInfo(), definitelyNotNull()),
+ TypeLatticeElement.stringClassType(appView, definitelyNotNull()),
invoke.getLocalInfo());
ConstString constString = new ConstString(stringValue, name, throwingInfo);
it.replaceCurrentInstruction(constString);
@@ -401,7 +401,7 @@
if (inType.isNullType()) {
Value nullStringValue =
code.createValue(
- TypeLatticeElement.stringClassType(appView.appInfo(), definitelyNotNull()),
+ TypeLatticeElement.stringClassType(appView, definitelyNotNull()),
invoke.getLocalInfo());
ConstString nullString =
new ConstString(nullStringValue, factory.createString("null"), throwingInfo);
diff --git a/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java b/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java
index c0008dc..98ca2a2 100644
--- a/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java
+++ b/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java
@@ -11,6 +11,7 @@
import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.errors.CompilationError;
import com.android.tools.r8.graph.AppInfo;
+import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DebugLocalInfo;
import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
import com.android.tools.r8.ir.code.Add;
@@ -122,14 +123,12 @@
}
}
- // App info to be able to create types.
- private final AppInfo appInfo;
+ // App view to be able to create types and access the options.
+ private final AppView<? extends AppInfo> appView;
// The code for which to allocate registers.
private final IRCode code;
// Number of registers used for arguments.
protected final int numberOfArgumentRegisters;
- // Compiler options.
- private final InternalOptions options;
// Mapping from basic blocks to the set of values live at entry to that basic block.
private Map<BasicBlock, LiveAtEntrySets> liveAtEntrySets;
@@ -185,10 +184,9 @@
return numberOfArgumentRegisters;
}
- public LinearScanRegisterAllocator(AppInfo appInfo, IRCode code, InternalOptions options) {
- this.appInfo = appInfo;
+ public LinearScanRegisterAllocator(AppView<? extends AppInfo> appView, IRCode code) {
+ this.appView = appView;
this.code = code;
- this.options = options;
int argumentRegisters = 0;
for (Instruction instruction : code.entryBlock().getInstructions()) {
if (instruction.isArgument()) {
@@ -223,7 +221,7 @@
// register allocation. We just treat the method as being in debug mode in order to keep
// locals alive for their entire live range. In release mode the liveness is all that matters
// and we do not actually want locals information in the output.
- if (options.debug) {
+ if (options().debug) {
computeDebugInfo(blocks);
} else if (code.method.getOptimizationInfo().isReachabilitySensitive()) {
InstructionIterator it = code.instructionIterator();
@@ -641,8 +639,8 @@
}
@Override
- public InternalOptions getOptions() {
- return options;
+ public InternalOptions options() {
+ return appView.options();
}
private ImmutableList<BasicBlock> computeLivenessInformation() {
@@ -676,8 +674,9 @@
switch (mode) {
case ALLOW_ARGUMENT_REUSE_U4BIT:
- if (!succeeded || highestUsedRegister() > Constants.U4BIT_MAX
- || options.testing.alwaysUsePessimisticRegisterAllocation) {
+ if (!succeeded
+ || highestUsedRegister() > Constants.U4BIT_MAX
+ || options().testing.alwaysUsePessimisticRegisterAllocation) {
// Redo allocation in mode ALLOW_ARGUMENT_REUSE_U8BIT. This may in principle also fail.
// It is extremely rare that a method will use more than 256 registers, though.
result = performAllocation(ArgumentReuseMode.ALLOW_ARGUMENT_REUSE_U8BIT, true);
@@ -699,7 +698,7 @@
computeUnusedRegisters();
if (highestUsedRegister() > Constants.U8BIT_MAX
- || options.testing.alwaysUsePessimisticRegisterAllocation) {
+ || options().testing.alwaysUsePessimisticRegisterAllocation) {
// Redo allocation in mode ALLOW_ARGUMENT_REUSE_U16BIT. This always succeed.
unusedRegisters = null;
result = performAllocation(ArgumentReuseMode.ALLOW_ARGUMENT_REUSE_U16BIT, true);
@@ -1423,7 +1422,7 @@
// We work around that bug by disallowing aget-wide with the same array
// and result register.
private boolean needsArrayGetWideWorkaround(LiveIntervals intervals) {
- if (options.canUseSameArrayAndResultRegisterInArrayGetWide()) {
+ if (options().canUseSameArrayAndResultRegisterInArrayGetWide()) {
return false;
}
if (intervals.requiredRegisters() == 1) {
@@ -1455,7 +1454,7 @@
}
private boolean needsSingleResultOverlappingLongOperandsWorkaround(LiveIntervals intervals) {
- if (!options.canHaveCmpLongBug() && !options.canHaveLongToIntBug()) {
+ if (!options().canHaveCmpLongBug() && !options().canHaveLongToIntBug()) {
return false;
}
if (intervals.requiredRegisters() == 2) {
@@ -1516,7 +1515,7 @@
// Dalvik would add v0 and v2 and write that to v3. It would then read v1 and v3 and produce
// the wrong result.
private boolean needsLongResultOverlappingLongOperandsWorkaround(LiveIntervals intervals) {
- if (!options.canHaveOverlappingLongRegisterBug()) {
+ if (!options().canHaveOverlappingLongRegisterBug()) {
return false;
}
if (intervals.requiredRegisters() == 1) {
@@ -1651,7 +1650,7 @@
// Set all free positions for possible registers to max integer.
RegisterPositions freePositions = new RegisterPositions(registerConstraint + 1);
- if ((options.debug || code.method.getOptimizationInfo().isReachabilitySensitive())
+ if ((options().debug || code.method.getOptimizationInfo().isReachabilitySensitive())
&& !code.method.accessFlags.isStatic()) {
// If we are generating debug information or if the method is reachability sensitive,
// we pin the this value register. The debugger expects to always be able to find it in
@@ -2365,7 +2364,7 @@
private void insertMoves() {
computeRematerializableBits();
- SpillMoveSet spillMoves = new SpillMoveSet(this, code, appInfo);
+ SpillMoveSet spillMoves = new SpillMoveSet(this, code, appView);
for (LiveIntervals intervals : liveIntervals) {
if (intervals.hasSplits()) {
LiveIntervals current = intervals;
@@ -2507,12 +2506,12 @@
}
private void computeLiveRanges() {
- computeLiveRanges(options, code, liveAtEntrySets, liveIntervals);
+ computeLiveRanges(options(), code, liveAtEntrySets, liveIntervals);
// Art VMs before Android M assume that the register for the receiver never changes its value.
// This assumption is used during verification. Allowing the receiver register to be
// overwritten can therefore lead to verification errors. If we could be targeting one of these
// VMs we block the receiver register throughout the method.
- if ((options.canHaveThisTypeVerifierBug() || options.canHaveThisJitCodeDebuggingBug())
+ if ((options().canHaveThisTypeVerifierBug() || options().canHaveThisJitCodeDebuggingBug())
&& !code.method.accessFlags.isStatic()) {
for (Instruction instruction : code.entryBlock().getInstructions()) {
if (instruction.isArgument() && instruction.outValue().isThis()) {
diff --git a/src/main/java/com/android/tools/r8/ir/regalloc/RegisterAllocator.java b/src/main/java/com/android/tools/r8/ir/regalloc/RegisterAllocator.java
index 43b41e5..9cdc715 100644
--- a/src/main/java/com/android/tools/r8/ir/regalloc/RegisterAllocator.java
+++ b/src/main/java/com/android/tools/r8/ir/regalloc/RegisterAllocator.java
@@ -13,7 +13,8 @@
int registersUsed();
int getRegisterForValue(Value value, int instructionNumber);
int getArgumentOrAllocateRegisterForValue(Value value, int instructionNumber);
- InternalOptions getOptions();
+
+ InternalOptions options();
void mergeBlocks(BasicBlock kept, BasicBlock removed);
diff --git a/src/main/java/com/android/tools/r8/ir/regalloc/SpillMoveSet.java b/src/main/java/com/android/tools/r8/ir/regalloc/SpillMoveSet.java
index aad705f..c7dd142 100644
--- a/src/main/java/com/android/tools/r8/ir/regalloc/SpillMoveSet.java
+++ b/src/main/java/com/android/tools/r8/ir/regalloc/SpillMoveSet.java
@@ -5,6 +5,7 @@
package com.android.tools.r8.ir.regalloc;
import com.android.tools.r8.graph.AppInfo;
+import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.ir.analysis.type.Nullability;
import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
import com.android.tools.r8.ir.code.BasicBlock;
@@ -42,10 +43,11 @@
// The number of temporary registers used for parallel moves when scheduling the moves.
private int usedTempRegisters = 0;
- public SpillMoveSet(LinearScanRegisterAllocator allocator, IRCode code, AppInfo appInfo) {
+ public SpillMoveSet(
+ LinearScanRegisterAllocator allocator, IRCode code, AppView<? extends AppInfo> appView) {
this.allocator = allocator;
this.code = code;
- this.objectType = TypeLatticeElement.objectClassType(appInfo, Nullability.maybeNull());
+ this.objectType = TypeLatticeElement.objectClassType(appView, Nullability.maybeNull());
for (BasicBlock block : code.blocks) {
blockStartMap.put(block.entry().getNumber(), block);
}
diff --git a/src/main/java/com/android/tools/r8/naming/SourceFileRewriter.java b/src/main/java/com/android/tools/r8/naming/SourceFileRewriter.java
index 0f9b571..c080a09 100644
--- a/src/main/java/com/android/tools/r8/naming/SourceFileRewriter.java
+++ b/src/main/java/com/android/tools/r8/naming/SourceFileRewriter.java
@@ -4,13 +4,14 @@
package com.android.tools.r8.naming;
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.DexClass;
import com.android.tools.r8.graph.DexDebugEvent;
import com.android.tools.r8.graph.DexDebugEvent.SetFile;
import com.android.tools.r8.graph.DexDebugInfo;
import com.android.tools.r8.graph.DexString;
-import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.shaking.ProguardConfiguration;
import java.util.Arrays;
/**
@@ -20,27 +21,25 @@
*/
public class SourceFileRewriter {
- private final AppInfo appInfo;
- private final InternalOptions options;
+ private final AppView<? extends AppInfo> appView;
- public SourceFileRewriter(AppInfo appInfo, InternalOptions options) {
- this.appInfo = appInfo;
- this.options = options;
+ public SourceFileRewriter(AppView<? extends AppInfo> appView) {
+ this.appView = appView;
}
public void run() {
- String renameSourceFile = options.getProguardConfiguration().getRenameSourceFileAttribute();
+ ProguardConfiguration proguardConfiguration = appView.options().getProguardConfiguration();
+ String renameSourceFile = proguardConfiguration.getRenameSourceFileAttribute();
// Return early if a user wants to keep the current source file attribute as-is.
- if (renameSourceFile == null
- && options.getProguardConfiguration().getKeepAttributes().sourceFile) {
+ if (renameSourceFile == null && proguardConfiguration.getKeepAttributes().sourceFile) {
return;
}
// Now, the user wants either to remove source file attribute or to rename it.
DexString dexRenameSourceFile =
renameSourceFile == null
- ? appInfo.dexItemFactory.createString("")
- : appInfo.dexItemFactory.createString(renameSourceFile);
- for (DexClass clazz : appInfo.classes()) {
+ ? appView.dexItemFactory().createString("")
+ : appView.dexItemFactory().createString(renameSourceFile);
+ for (DexClass clazz : appView.appInfo().classes()) {
clazz.sourceFile = dexRenameSourceFile;
clazz.forEachMethod(encodedMethod -> {
// Abstract methods do not have code_item.
diff --git a/src/main/java/com/android/tools/r8/naming/signature/GenericSignatureRewriter.java b/src/main/java/com/android/tools/r8/naming/signature/GenericSignatureRewriter.java
index 20f4bc2..4187099 100644
--- a/src/main/java/com/android/tools/r8/naming/signature/GenericSignatureRewriter.java
+++ b/src/main/java/com/android/tools/r8/naming/signature/GenericSignatureRewriter.java
@@ -29,7 +29,6 @@
public class GenericSignatureRewriter {
private final AppView<AppInfoWithLiveness> appView;
- private final AppInfoWithLiveness appInfo;
private final Map<DexType, DexString> renaming;
private final Reporter reporter;
@@ -40,7 +39,6 @@
public GenericSignatureRewriter(
AppView<AppInfoWithLiveness> appView, Map<DexType, DexString> renaming) {
this.appView = appView;
- this.appInfo = appView.appInfo();
this.renaming = renaming;
this.reporter = appView.options().reporter;
}
@@ -50,7 +48,7 @@
final GenericSignatureParser<DexType> genericSignatureParser =
new GenericSignatureParser<>(genericSignatureCollector);
- for (DexClass clazz : appInfo.classes()) {
+ for (DexClass clazz : appView.appInfo().classes()) {
clazz.annotations =
rewriteGenericSignatures(
clazz.annotations,
@@ -86,13 +84,12 @@
int invalid = VALID;
for (int i = 0; i < annotations.annotations.length && invalid == VALID; i++) {
DexAnnotation annotation = annotations.annotations[i];
- if (DexAnnotation.isSignatureAnnotation(annotation, appInfo.dexItemFactory)) {
+ if (DexAnnotation.isSignatureAnnotation(annotation, appView.dexItemFactory())) {
String signature = DexAnnotation.getSignature(annotation);
try {
parser.accept(signature);
- annotations.annotations[i] = DexAnnotation.createSignatureAnnotation(
- collector.get(),
- appInfo.dexItemFactory);
+ annotations.annotations[i] =
+ DexAnnotation.createSignatureAnnotation(collector.get(), appView.dexItemFactory());
} catch (GenericSignatureFormatError e) {
parseError.accept(signature, e);
invalid = i;
@@ -159,10 +156,10 @@
@Override
public DexType parsedTypeName(String name) {
- DexType type = appInfo.dexItemFactory.createType(getDescriptorFromClassBinaryName(name));
+ DexType type = appView.dexItemFactory().createType(getDescriptorFromClassBinaryName(name));
type = appView.graphLense().lookupType(type);
- if (appInfo.wasPruned(type)) {
- type = appInfo.dexItemFactory.objectType;
+ if (appView.appInfo().wasPruned(type)) {
+ type = appView.dexItemFactory().objectType;
}
DexString renamedDescriptor = renaming.getOrDefault(type, type.descriptor);
renamedSignature.append(getClassBinaryNameFromDescriptor(renamedDescriptor.toString()));
@@ -174,11 +171,13 @@
assert enclosingType.isClassType();
String enclosingDescriptor = enclosingType.toDescriptorString();
DexType type =
- appInfo.dexItemFactory.createType(
- getDescriptorFromClassBinaryName(
- getClassBinaryNameFromDescriptor(enclosingDescriptor)
- + DescriptorUtils.INNER_CLASS_SEPARATOR
- + name));
+ appView
+ .dexItemFactory()
+ .createType(
+ getDescriptorFromClassBinaryName(
+ getClassBinaryNameFromDescriptor(enclosingDescriptor)
+ + DescriptorUtils.INNER_CLASS_SEPARATOR
+ + name));
String enclosingRenamedBinaryName =
getClassBinaryNameFromDescriptor(
renaming.getOrDefault(enclosingType, enclosingType.descriptor).toString());
diff --git a/src/main/java/com/android/tools/r8/shaking/AbstractMethodRemover.java b/src/main/java/com/android/tools/r8/shaking/AbstractMethodRemover.java
index 0bdbcee..f5250d8 100644
--- a/src/main/java/com/android/tools/r8/shaking/AbstractMethodRemover.java
+++ b/src/main/java/com/android/tools/r8/shaking/AbstractMethodRemover.java
@@ -31,7 +31,7 @@
public void run() {
assert scope.getParent() == null;
- processClass(appInfo.dexItemFactory.objectType);
+ processClass(appInfo.dexItemFactory().objectType);
}
private void processClass(DexType type) {
diff --git a/src/main/java/com/android/tools/r8/shaking/DiscardedChecker.java b/src/main/java/com/android/tools/r8/shaking/DiscardedChecker.java
index 07a62a8..3d8afb2 100644
--- a/src/main/java/com/android/tools/r8/shaking/DiscardedChecker.java
+++ b/src/main/java/com/android/tools/r8/shaking/DiscardedChecker.java
@@ -5,6 +5,7 @@
import com.android.tools.r8.errors.CompilationError;
import com.android.tools.r8.graph.AppInfo;
+import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexDefinition;
@@ -31,17 +32,16 @@
this.options = options;
}
- public DiscardedChecker(
- RootSet rootSet, Set<DexType> types, AppInfo appInfo, InternalOptions options) {
+ public DiscardedChecker(RootSet rootSet, Set<DexType> types, AppView<? extends AppInfo> appView) {
this.checkDiscarded = rootSet.checkDiscarded;
this.classes = new ArrayList<>();
types.forEach(
type -> {
- DexClass clazz = appInfo.definitionFor(type);
+ DexClass clazz = appView.definitionFor(type);
assert clazz.isProgramClass();
this.classes.add(clazz.asProgramClass());
});
- this.options = options;
+ this.options = appView.options();
}
public void run() {
diff --git a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
index d164d91..64624d3 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -336,7 +336,7 @@
}
private void enqueueRootItem(Entry<DexReference, Set<ProguardKeepRule>> root) {
- DexDefinition item = appInfo.definitionFor(root.getKey());
+ DexDefinition item = appView.definitionFor(root.getKey());
if (item != null) {
enqueueRootItem(item, root.getValue());
} else {
@@ -377,7 +377,7 @@
clazz.getDefaultInitializer(),
KeepReason.dueToProguardCompatibilityKeepRule(compatRule)));
}
- if (clazz.isExternalizable(appInfo)) {
+ if (clazz.isExternalizable(appView)) {
workList.add(Action.markMethodLive(clazz.getDefaultInitializer(), reason));
}
}
@@ -392,11 +392,11 @@
}
private void enqueueFirstNonSerializableClassInitializer(DexClass clazz, KeepReason reason) {
- assert clazz.isProgramClass() && clazz.isSerializable(appInfo);
+ assert clazz.isProgramClass() && clazz.isSerializable(appView);
// Climb up the class hierarchy. Break out if the definition is not found, or hit the library
// classes which are kept by definition, or encounter the first non-serializable class.
- while (clazz != null && clazz.isProgramClass() && clazz.isSerializable(appInfo)) {
- clazz = appInfo.definitionFor(clazz.superType);
+ while (clazz != null && clazz.isProgramClass() && clazz.isSerializable(appView)) {
+ clazz = appView.definitionFor(clazz.superType);
}
if (clazz != null && clazz.isProgramClass() && clazz.hasDefaultInitializer()) {
workList.add(Action.markMethodLive(clazz.getDefaultInitializer(), reason));
@@ -413,7 +413,11 @@
if (dependentItem.isDexType()) {
continue;
}
- DexDefinition dependentDefinition = appInfo.definitionFor(dependentItem);
+ DexDefinition dependentDefinition = appView.definitionFor(dependentItem);
+ if (dependentDefinition == null) {
+ assert false;
+ continue;
+ }
if (!dependentDefinition.isStaticMember()) {
enqueueRootItem(holder, entry.getValue());
// Enough to enqueue the known holder once.
@@ -434,7 +438,7 @@
item.isDexField()
? item.asDexField().holder
: item.asDexMethod().holder;
- DexType holder = itemHolder.toBaseType(appInfo.dexItemFactory);
+ DexType holder = itemHolder.toBaseType(appView.dexItemFactory());
if (!holder.isClassType()) {
return false;
}
@@ -449,7 +453,7 @@
item.isDexField()
? item.asDexField().holder
: item.asDexMethod().holder;
- DexType holder = itemHolder.toBaseType(appInfo.dexItemFactory);
+ DexType holder = itemHolder.toBaseType(appView.dexItemFactory());
if (!holder.isClassType()) {
return false;
}
@@ -474,7 +478,7 @@
}
boolean registerInvokeVirtual(DexMethod method, KeepReason keepReason) {
- if (appInfo.dexItemFactory.classMethods.isReflectiveMemberLookup(method)) {
+ if (appView.dexItemFactory().classMethods.isReflectiveMemberLookup(method)) {
// Implicitly add -identifiernamestring rule for the Java reflection in use.
identifierNameStrings.add(method);
// Revisit the current method to implicitly add -keep rule for items with reflective access.
@@ -512,19 +516,19 @@
}
boolean registerInvokeStatic(DexMethod method, KeepReason keepReason) {
- if (method == appInfo.dexItemFactory.classMethods.forName
- || appInfo.dexItemFactory.atomicFieldUpdaterMethods.isFieldUpdater(method)) {
+ if (method == appView.dexItemFactory().classMethods.forName
+ || appView.dexItemFactory().atomicFieldUpdaterMethods.isFieldUpdater(method)) {
// Implicitly add -identifiernamestring rule for the Java reflection in use.
identifierNameStrings.add(method);
// Revisit the current method to implicitly add -keep rule for items with reflective access.
pendingReflectiveUses.add(currentMethod);
}
// See comment in handleJavaLangEnumValueOf.
- if (method == appInfo.dexItemFactory.enumMethods.valueOf) {
+ if (method == appView.dexItemFactory().enumMethods.valueOf) {
pendingReflectiveUses.add(currentMethod);
}
// Handling of application services.
- if (appInfo.dexItemFactory.serviceLoaderMethods.isLoadMethod(method)) {
+ if (appView.dexItemFactory().serviceLoaderMethods.isLoadMethod(method)) {
pendingReflectiveUses.add(currentMethod);
}
if (!registerItemWithTargetAndContext(staticInvokes, method, currentMethod)) {
@@ -625,7 +629,7 @@
}
DexEncodedField encodedField = appInfo.resolveField(field);
- if (encodedField != null && encodedField.isProgramField(appInfo)) {
+ if (encodedField != null && encodedField.isProgramField(appView)) {
boolean isWrittenOutsideEnclosingStaticInitializer =
currentMethod.method.holder != encodedField.field.holder
|| !currentMethod.isClassInitializer();
@@ -666,7 +670,7 @@
// stays in the output (and is not class merged). To ensure that we treat the receiver
// as instantiated.
if (methodHandle.isMethodHandle() && use != MethodHandleUse.ARGUMENT_TO_LAMBDA_METAFACTORY) {
- DexClass holder = appInfo.definitionFor(methodHandle.asMethod().holder);
+ DexClass holder = appView.definitionFor(methodHandle.asMethod().holder);
if (holder != null) {
markInstantiated(holder.type, KeepReason.methodHandleReferencedIn(currentMethod));
}
@@ -695,7 +699,7 @@
}
}
- DexClass bootstrapClass = appInfo.definitionFor(callSite.bootstrapMethod.asMethod().holder);
+ DexClass bootstrapClass = appView.definitionFor(callSite.bootstrapMethod.asMethod().holder);
if (bootstrapClass != null && bootstrapClass.isProgramClass()) {
bootstrapMethods.add(callSite.bootstrapMethod.asMethod());
}
@@ -751,8 +755,8 @@
}
Set<DexType> allInterfaces = Sets.newHashSet(directInterfaces);
- DexType instantiatedType = appInfo.dexItemFactory.objectType;
- DexClass clazz = appInfo.definitionFor(instantiatedType);
+ DexType instantiatedType = appView.dexItemFactory().objectType;
+ DexClass clazz = appView.definitionFor(instantiatedType);
if (clazz == null) {
reportMissingClass(instantiatedType);
return;
@@ -778,7 +782,7 @@
// the shadowing of other interface chains into account.
// See https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-5.html#jvms-5.4.3.3
for (DexType iface : allInterfaces) {
- DexClass ifaceClazz = appInfo.definitionFor(iface);
+ DexClass ifaceClazz = appView.definitionFor(iface);
if (ifaceClazz == null) {
reportMissingClass(iface);
return;
@@ -789,9 +793,9 @@
private boolean registerConstClassOrCheckCast(DexType type) {
if (forceProguardCompatibility) {
- DexType baseType = type.toBaseType(appInfo.dexItemFactory);
+ DexType baseType = type.toBaseType(appView.dexItemFactory());
if (baseType.isClassType()) {
- DexClass baseClass = appInfo.definitionFor(baseType);
+ DexClass baseClass = appView.definitionFor(baseType);
if (baseClass != null && baseClass.isProgramClass()) {
// Don't require any constructor, see b/112386012.
markClassAsInstantiatedWithCompatRule(baseClass);
@@ -809,17 +813,17 @@
}
private DexMethod getInvokeSuperTarget(DexMethod method, DexEncodedMethod currentMethod) {
- DexClass methodHolderClass = appInfo.definitionFor(method.holder);
+ DexClass methodHolderClass = appView.definitionFor(method.holder);
if (methodHolderClass != null && methodHolderClass.isInterface()) {
return method;
}
- DexClass holderClass = appInfo.definitionFor(currentMethod.method.holder);
+ DexClass holderClass = appView.definitionFor(currentMethod.method.holder);
if (holderClass == null || holderClass.superType == null || holderClass.isInterface()) {
// We do not know better or this call is made from an interface.
return method;
}
// Return the invoked method on the supertype.
- return appInfo.dexItemFactory.createMethod(holderClass.superType, method.proto, method.name);
+ return appView.dexItemFactory().createMethod(holderClass.superType, method.proto, method.name);
}
//
@@ -827,7 +831,7 @@
//
private void markTypeAsLive(DexType type) {
- type = type.toBaseType(appInfo.dexItemFactory);
+ type = type.toBaseType(appView.dexItemFactory());
if (!type.isClassType()) {
// Ignore primitive types.
return;
@@ -836,7 +840,7 @@
if (Log.ENABLED) {
Log.verbose(getClass(), "Type `%s` has become live.", type);
}
- DexClass holder = appInfo.definitionFor(type);
+ DexClass holder = appView.definitionFor(type);
if (holder == null) {
reportMissingClass(type);
return;
@@ -865,7 +869,7 @@
}
}
- if (holder.isProgramClass() && holder.isSerializable(appInfo)) {
+ if (holder.isProgramClass() && holder.isSerializable(appView)) {
enqueueFirstNonSerializableClassInitializer(holder, reason);
}
@@ -905,9 +909,9 @@
assert !holder.isDexClass() || !holder.asDexClass().isLibraryClass();
DexType type = annotation.annotation.type;
boolean annotationTypeIsLibraryClass =
- appInfo.definitionFor(type) == null || appInfo.definitionFor(type).isLibraryClass();
+ appView.definitionFor(type) == null || appView.definitionFor(type).isLibraryClass();
boolean isLive = annotationTypeIsLibraryClass || liveTypes.contains(type);
- if (!shouldKeepAnnotation(annotation, isLive, appInfo.dexItemFactory, options)) {
+ if (!shouldKeepAnnotation(annotation, isLive, appView.dexItemFactory(), options)) {
// Remember this annotation for later.
if (!annotationTypeIsLibraryClass) {
deferredAnnotations.computeIfAbsent(type, ignore -> new HashSet<>()).add(annotation);
@@ -916,7 +920,7 @@
}
liveAnnotations.add(annotation, KeepReason.annotatedOn(holder));
AnnotationReferenceMarker referenceMarker =
- new AnnotationReferenceMarker(annotation.annotation.type, appInfo.dexItemFactory);
+ new AnnotationReferenceMarker(annotation.annotation.type, appView.dexItemFactory());
annotation.annotation.collectIndexedItems(referenceMarker);
}
@@ -967,7 +971,7 @@
return;
}
- DexClass holder = appInfo.definitionFor(type);
+ DexClass holder = appView.definitionFor(type);
if (holder != null && !holder.isLibraryClass()) {
if (!dontWarnPatterns.matches(context)) {
Diagnostic message =
@@ -1010,7 +1014,7 @@
}
markTypeAsLive(method.method.holder);
markParameterAndReturnTypesAsLive(method);
- if (!appInfo.definitionFor(method.method.holder).isLibraryClass()) {
+ if (!appView.definitionFor(method.method.holder).isLibraryClass()) {
processAnnotations(method, method.annotations.annotations);
method.parameterAnnotationsList.forEachAnnotation(
annotation -> processAnnotation(method, annotation));
@@ -1021,7 +1025,7 @@
if (forceProguardCompatibility) {
// Keep targeted default methods in compatibility mode. The tree pruner will otherwise make
// these methods abstract, whereas Proguard does not (seem to) touch their code.
- DexClass clazz = appInfo.definitionFor(method.method.holder);
+ DexClass clazz = appView.definitionFor(method.method.holder);
if (!method.accessFlags.isAbstract()
&& clazz.isInterface() && !clazz.isLibraryClass()) {
markMethodAsKeptWithCompatRule(method);
@@ -1069,7 +1073,7 @@
Set<DexType> interfaces = Sets.newIdentityHashSet();
DexType type = instantiatedType;
do {
- DexClass clazz = appInfo.definitionFor(type);
+ DexClass clazz = appView.definitionFor(type);
if (clazz == null) {
reportMissingClass(type);
// TODO(herhut): In essence, our subtyping chain is broken here. Handle that case better.
@@ -1095,7 +1099,7 @@
// the shadowing of other interface chains into account.
// See https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-5.html#jvms-5.4.3.3
for (DexType iface : interfaces) {
- DexClass clazz = appInfo.definitionFor(iface);
+ DexClass clazz = appView.definitionFor(iface);
if (clazz == null) {
reportMissingClass(iface);
// TODO(herhut): In essence, our subtyping chain is broken here. Handle that case better.
@@ -1107,7 +1111,7 @@
private void transitionDefaultMethodsForInstantiatedClass(DexType iface, DexType instantiatedType,
ScopedDexMethodSet seen) {
- DexClass clazz = appInfo.definitionFor(iface);
+ DexClass clazz = appView.definitionFor(iface);
if (clazz == null) {
reportMissingClass(iface);
return;
@@ -1143,7 +1147,7 @@
*/
private void transitionFieldsForInstantiatedClass(DexType type) {
do {
- DexClass clazz = appInfo.definitionFor(type);
+ DexClass clazz = appView.definitionFor(type);
if (clazz == null) {
// TODO(herhut) The subtype chain is broken. We need a way to deal with this better.
reportMissingClass(type);
@@ -1215,7 +1219,7 @@
if (instantiatedTypes.contains(type)) {
return;
}
- DexClass clazz = appInfo.definitionFor(type);
+ DexClass clazz = appView.definitionFor(type);
if (clazz == null) {
reportMissingClass(type);
return;
@@ -1227,7 +1231,7 @@
}
private void markLambdaInstantiated(DexType itf, DexEncodedMethod method) {
- DexClass clazz = appInfo.definitionFor(itf);
+ DexClass clazz = appView.definitionFor(itf);
if (clazz == null) {
if (options.reporter != null) {
StringDiagnostic message =
@@ -1331,7 +1335,7 @@
markTypeAsLive(method.holder);
return;
}
- DexClass holder = appInfo.definitionFor(method.holder);
+ DexClass holder = appView.definitionFor(method.holder);
if (holder == null) {
reportMissingClass(method.holder);
return;
@@ -1371,7 +1375,7 @@
fillWorkList(worklist, encodedMethod.method.holder);
while (!worklist.isEmpty()) {
DexType current = worklist.pollFirst();
- DexClass currentHolder = appInfo.definitionFor(current);
+ DexClass currentHolder = appView.definitionFor(current);
// If this class overrides the virtual, abort the search. Note that, according to
// the JVM spec, private methods cannot override a virtual method.
if (currentHolder == null
@@ -1393,11 +1397,14 @@
private DexMethod generatedEnumValuesMethod(DexClass enumClass) {
DexType arrayOfEnumClass =
- appInfo.dexItemFactory.createType(
- appInfo.dexItemFactory.createString("[" + enumClass.type.toDescriptorString()));
- DexProto proto = appInfo.dexItemFactory.createProto(arrayOfEnumClass);
- return appInfo.dexItemFactory.createMethod(
- enumClass.type, proto, appInfo.dexItemFactory.createString("values"));
+ appView
+ .dexItemFactory()
+ .createType(
+ appView.dexItemFactory().createString("[" + enumClass.type.toDescriptorString()));
+ DexProto proto = appView.dexItemFactory().createProto(arrayOfEnumClass);
+ return appView
+ .dexItemFactory()
+ .createMethod(enumClass.type, proto, appView.dexItemFactory().createString("values"));
}
private void markEnumValuesAsReachable(DexClass clazz, KeepReason reason) {
@@ -1464,15 +1471,16 @@
}
}
- public AppInfoWithLiveness traceMainDex(
+ // Returns the set of live types.
+ public SortedSet<DexType> traceMainDex(
RootSet rootSet, ExecutorService executorService, Timing timing) throws ExecutionException {
this.tracingMainDex = true;
this.rootSet = rootSet;
// Translate the result of root-set computation into enqueuer actions.
enqueueRootItems(rootSet.noShrinking);
- AppInfoWithLiveness appInfo = trace(executorService, timing);
+ trace(executorService, timing);
options.reporter.failIfPendingErrors();
- return appInfo;
+ return ImmutableSortedSet.copyOf(PresortedComparable::slowCompareTo, liveTypes);
}
public AppInfoWithLiveness traceApplication(
@@ -1486,13 +1494,12 @@
// Translate the result of root-set computation into enqueuer actions.
enqueueRootItems(rootSet.noShrinking);
appInfo.libraryClasses().forEach(this::markAllLibraryVirtualMethodsReachable);
- AppInfoWithLiveness result = trace(executorService, timing);
+ trace(executorService, timing);
options.reporter.failIfPendingErrors();
- return result;
+ return new AppInfoWithLiveness(appInfo, this);
}
- private AppInfoWithLiveness trace(
- ExecutorService executorService, Timing timing) throws ExecutionException {
+ private void trace(ExecutorService executorService, Timing timing) throws ExecutionException {
timing.begin("Grow the tree.");
try {
while (true) {
@@ -1537,8 +1544,7 @@
numOfLiveItemsAfterProcessing += (long) liveMethods.items.size();
numOfLiveItemsAfterProcessing += (long) liveFields.items.size();
if (numOfLiveItemsAfterProcessing > numOfLiveItems) {
- RootSetBuilder consequentSetBuilder =
- new RootSetBuilder(appView, rootSet.ifRules, options);
+ RootSetBuilder consequentSetBuilder = new RootSetBuilder(appView, rootSet.ifRules);
IfRuleEvaluator ifRuleEvaluator =
consequentSetBuilder.getIfRuleEvaluator(
liveFields.getItems(),
@@ -1550,14 +1556,15 @@
enqueueRootItems(consequentRootSet.noShrinking);
// Check if any newly dependent members are not static, and in that case find the holder
// and enqueue it as well. This is -if version of workaround for b/115867670.
- consequentRootSet.dependentNoShrinking.forEach((precondition, dependentItems) -> {
- if (precondition.isDexType()) {
- DexClass preconditionHolder = appInfo.definitionFor(precondition.asDexType());
- enqueueHolderIfDependentNonStaticMember(preconditionHolder, dependentItems);
- }
- // Add all dependent members to the workqueue.
- enqueueRootItems(dependentItems);
- });
+ consequentRootSet.dependentNoShrinking.forEach(
+ (precondition, dependentItems) -> {
+ if (precondition.isDexType()) {
+ DexClass preconditionHolder = appView.definitionFor(precondition.asDexType());
+ enqueueHolderIfDependentNonStaticMember(preconditionHolder, dependentItems);
+ }
+ // Add all dependent members to the workqueue.
+ enqueueRootItems(dependentItems);
+ });
if (!workList.isEmpty()) {
continue;
}
@@ -1599,7 +1606,6 @@
timing.end();
}
unpinLambdaMethods();
- return new AppInfoWithLiveness(appInfo, this);
}
private void unpinLambdaMethods() {
@@ -1611,7 +1617,7 @@
}
private void markMethodAsKept(DexEncodedMethod target, KeepReason reason) {
- DexClass holder = appInfo.definitionFor(target.method.holder);
+ DexClass holder = appView.definitionFor(target.method.holder);
// If this method no longer has a corresponding class then we have shaken it away before.
if (holder == null) {
return;
@@ -1634,7 +1640,7 @@
private void markFieldAsKept(DexEncodedField target, KeepReason reason) {
// If this field no longer has a corresponding class, then we have shaken it away before.
- if (appInfo.definitionFor(target.field.holder) == null) {
+ if (appView.definitionFor(target.field.holder) == null) {
return;
}
if (target.accessFlags.isStatic()) {
@@ -1660,7 +1666,7 @@
private void processNewlyLiveMethod(DexEncodedMethod method, KeepReason reason) {
if (liveMethods.add(method, reason)) {
collectProguardCompatibilityRule(reason);
- DexClass holder = appInfo.definitionFor(method.method.holder);
+ DexClass holder = appView.definitionFor(method.method.holder);
assert holder != null;
if (holder.isLibraryClass()) {
// We do not process library classes.
@@ -1678,7 +1684,7 @@
}
}
markParameterAndReturnTypesAsLive(method);
- if (!appInfo.definitionFor(method.method.holder).isLibraryClass()) {
+ if (!appView.definitionFor(method.method.holder).isLibraryClass()) {
processAnnotations(method, method.annotations.annotations);
method.parameterAnnotationsList.forEachAnnotation(
annotation -> processAnnotation(method, annotation));
@@ -1716,7 +1722,7 @@
return Collections.unmodifiableSortedMap(result);
}
- private Set<DexField> collectReachedFields(
+ private static Set<DexField> collectReachedFields(
Set<DexField> set, Function<DexField, DexField> lookup) {
return set.stream()
.map(lookup)
@@ -1734,8 +1740,10 @@
return target == null ? null : target.field;
}
- SortedSet<DexField> mergeFieldAccesses(Set<DexField> instanceFields, Set<DexField> staticFields) {
- return ImmutableSortedSet.copyOf(PresortedComparable<DexField>::slowCompareTo,
+ private SortedSet<DexField> mergeFieldAccesses(
+ Set<DexField> instanceFields, Set<DexField> staticFields) {
+ return ImmutableSortedSet.copyOf(
+ PresortedComparable<DexField>::slowCompareTo,
Sets.union(
collectReachedFields(instanceFields, this::tryLookupInstanceField),
collectReachedFields(staticFields, this::tryLookupStaticField)));
@@ -1760,7 +1768,7 @@
}
private void markMethodAsKeptWithCompatRule(DexEncodedMethod method) {
- DexClass holderClass = appInfo.definitionFor(method.method.holder);
+ DexClass holderClass = appView.definitionFor(method.method.holder);
ProguardKeepRule rule =
ProguardConfigurationUtils.buildMethodKeepRule(holderClass, method);
proguardCompatibilityWorkList.add(
@@ -1784,15 +1792,15 @@
}
InvokeMethod invoke = instruction.asInvokeMethod();
DexMethod invokedMethod = invoke.getInvokedMethod();
- if (invokedMethod == appInfo.dexItemFactory.enumMethods.valueOf) {
+ if (invokedMethod == appView.dexItemFactory().enumMethods.valueOf) {
handleJavaLangEnumValueOf(method, invoke);
return;
}
- if (appInfo.dexItemFactory.serviceLoaderMethods.isLoadMethod(invokedMethod)) {
+ if (appView.dexItemFactory().serviceLoaderMethods.isLoadMethod(invokedMethod)) {
handleServiceLoaderInvocation(method, invoke);
return;
}
- if (!isReflectionMethod(appInfo.dexItemFactory, invokedMethod)) {
+ if (!isReflectionMethod(appView.dexItemFactory(), invokedMethod)) {
return;
}
DexReference identifierItem = identifyIdentifier(appInfo, invoke);
@@ -1800,7 +1808,7 @@
return;
}
if (identifierItem.isDexType()) {
- DexClass clazz = appInfo.definitionFor(identifierItem.asDexType());
+ DexClass clazz = appView.definitionFor(identifierItem.asDexType());
if (clazz != null) {
markInstantiated(clazz.type, KeepReason.reflectiveUseIn(method));
if (clazz.hasDefaultInitializer()) {
@@ -1809,7 +1817,7 @@
}
}
} else if (identifierItem.isDexField()) {
- DexEncodedField encodedField = appInfo.definitionFor(identifierItem.asDexField());
+ DexEncodedField encodedField = appView.definitionFor(identifierItem.asDexField());
if (encodedField != null) {
// Normally, we generate a -keepclassmembers rule for the field, such that the field is only
// kept if it is a static field, or if the holder or one of its subtypes are instantiated.
@@ -1818,9 +1826,9 @@
// is not present.
boolean keepClass =
!encodedField.accessFlags.isStatic()
- && appInfo.dexItemFactory.atomicFieldUpdaterMethods.isFieldUpdater(invokedMethod);
+ && appView.dexItemFactory().atomicFieldUpdaterMethods.isFieldUpdater(invokedMethod);
if (keepClass) {
- DexClass holderClass = appInfo.definitionFor(encodedField.field.holder);
+ DexClass holderClass = appView.definitionFor(encodedField.field.holder);
markInstantiated(holderClass.type, KeepReason.reflectiveUseIn(method));
}
markFieldAsKept(encodedField, KeepReason.reflectiveUseIn(method));
@@ -1835,7 +1843,7 @@
}
} else {
assert identifierItem.isDexMethod();
- DexEncodedMethod encodedMethod = appInfo.definitionFor(identifierItem.asDexMethod());
+ DexEncodedMethod encodedMethod = appView.definitionFor(identifierItem.asDexMethod());
if (encodedMethod != null) {
if (encodedMethod.accessFlags.isStatic() || encodedMethod.accessFlags.isConstructor()) {
markDirectStaticOrConstructorMethodAsLive(
@@ -1854,8 +1862,8 @@
// call this method.
if (invoke.inValues().get(0).isConstClass()) {
DexClass clazz =
- appInfo.definitionFor(invoke.inValues().get(0).definition.asConstClass().getValue());
- if (clazz.accessFlags.isEnum() && clazz.superType == appInfo.dexItemFactory.enumType) {
+ appView.definitionFor(invoke.inValues().get(0).definition.asConstClass().getValue());
+ if (clazz.accessFlags.isEnum() && clazz.superType == appView.dexItemFactory().enumType) {
markEnumValuesAsReachable(clazz, KeepReason.invokedFrom(method));
}
}
@@ -1905,7 +1913,7 @@
continue;
}
- DexClass serviceImplementationClass = appInfo.definitionFor(serviceImplementationType);
+ DexClass serviceImplementationClass = appView.definitionFor(serviceImplementationType);
if (serviceImplementationClass != null && serviceImplementationClass.isProgramClass()) {
markClassAsInstantiatedWithReason(serviceImplementationClass, reason);
}
@@ -2186,10 +2194,10 @@
this.instanceFieldWrites = enqueuer.collectDescriptors(enqueuer.instanceFieldsWritten);
this.staticFieldReads = enqueuer.collectDescriptors(enqueuer.staticFieldsRead);
this.staticFieldWrites = enqueuer.collectDescriptors(enqueuer.staticFieldsWritten);
- this.fieldsRead = enqueuer.mergeFieldAccesses(
- instanceFieldReads.keySet(), staticFieldReads.keySet());
- this.fieldsWritten = enqueuer.mergeFieldAccesses(
- instanceFieldWrites.keySet(), staticFieldWrites.keySet());
+ this.fieldsRead =
+ enqueuer.mergeFieldAccesses(instanceFieldReads.keySet(), staticFieldReads.keySet());
+ this.fieldsWritten =
+ enqueuer.mergeFieldAccesses(instanceFieldWrites.keySet(), staticFieldWrites.keySet());
this.staticFieldsWrittenOnlyInEnclosingStaticInitializer =
ImmutableSortedSet.copyOf(
DexField::slowCompareTo,
@@ -2221,6 +2229,7 @@
this.ordinalsMaps = Collections.emptyMap();
assert Sets.intersection(instanceFieldReads.keySet(), staticFieldReads.keySet()).isEmpty();
assert Sets.intersection(instanceFieldWrites.keySet(), staticFieldWrites.keySet()).isEmpty();
+ appInfo.markObsolete();
}
private AppInfoWithLiveness(AppInfoWithLiveness previous, DexApplication application) {
@@ -2287,7 +2296,7 @@
AppInfoWithLiveness previous,
DirectMappedDexApplication application,
GraphLense lense) {
- super(application, lense);
+ super(application);
this.liveTypes = rewriteItems(previous.liveTypes, lense::lookupType);
this.instantiatedAnnotationTypes =
rewriteItems(previous.instantiatedAnnotationTypes, lense::lookupType);
@@ -2419,13 +2428,15 @@
this.prunedTypes = previous.prunedTypes;
this.switchMaps = switchMaps;
this.ordinalsMaps = ordinalsMaps;
+ previous.markObsolete();
}
public AppInfoWithLiveness withoutStaticFieldsWrites(Set<DexField> noLongerWrittenFields) {
+ assert checkIfObsolete();
if (noLongerWrittenFields.isEmpty()) {
return this;
}
- AppInfoWithLiveness result = new AppInfoWithLiveness(this, app);
+ AppInfoWithLiveness result = new AppInfoWithLiveness(this, app());
Predicate<DexField> isFieldWritten = field -> !noLongerWrittenFields.contains(field);
result.fieldsWritten = filter(fieldsWritten, isFieldWritten);
result.staticFieldsWrittenOnlyInEnclosingStaticInitializer =
@@ -2441,10 +2452,12 @@
}
public Reference2IntMap<DexField> getOrdinalsMapFor(DexType enumClass) {
+ assert checkIfObsolete();
return ordinalsMaps.get(enumClass);
}
public Int2ReferenceMap<DexField> getSwitchMapFor(DexField field) {
+ assert checkIfObsolete();
return switchMaps.get(field);
}
@@ -2466,6 +2479,7 @@
}
public boolean isInstantiatedDirectly(DexType type) {
+ assert checkIfObsolete();
assert type.isClassType();
return type.isD8R8SynthesizedClassType()
|| instantiatedTypes.contains(type)
@@ -2474,6 +2488,7 @@
}
public boolean isInstantiatedIndirectly(DexType type) {
+ assert checkIfObsolete();
assert type.isClassType();
synchronized (indirectlyInstantiatedTypes) {
if (indirectlyInstantiatedTypes.containsKey(type)) {
@@ -2491,11 +2506,13 @@
}
public boolean isInstantiatedDirectlyOrIndirectly(DexType type) {
+ assert checkIfObsolete();
assert type.isClassType();
return isInstantiatedDirectly(type) || isInstantiatedIndirectly(type);
}
public boolean isFieldRead(DexField field) {
+ assert checkIfObsolete();
return fieldsRead.contains(field)
// TODO(b/121354886): Pinned fields should be in `fieldsRead`.
|| isPinned(field)
@@ -2506,6 +2523,7 @@
}
public boolean isFieldWritten(DexField field) {
+ assert checkIfObsolete();
return fieldsWritten.contains(field)
// TODO(b/121354886): Pinned fields should be in `fieldsWritten`.
|| isPinned(field)
@@ -2516,6 +2534,7 @@
}
public boolean isStaticFieldWrittenOnlyInEnclosingStaticInitializer(DexField field) {
+ assert checkIfObsolete();
assert isFieldWritten(field);
return staticFieldsWrittenOnlyInEnclosingStaticInitializer.contains(field);
}
@@ -2585,24 +2604,29 @@
@Override
protected boolean hasAnyInstantiatedLambdas(DexType type) {
+ assert checkIfObsolete();
return instantiatedLambdas.contains(type);
}
@Override
public boolean hasLiveness() {
+ assert checkIfObsolete();
return true;
}
@Override
public AppInfoWithLiveness withLiveness() {
+ assert checkIfObsolete();
return this;
}
public boolean isPinned(DexReference reference) {
+ assert checkIfObsolete();
return pinnedItems.contains(reference);
}
public Iterable<DexReference> getPinnedItems() {
+ assert checkIfObsolete();
return pinnedItems;
}
@@ -2610,13 +2634,15 @@
* Returns a copy of this AppInfoWithLiveness where the set of classes is pruned using the given
* DexApplication object.
*/
- public AppInfoWithLiveness prunedCopyFrom(DexApplication application,
- Collection<DexType> removedClasses) {
+ public AppInfoWithLiveness prunedCopyFrom(
+ DexApplication application, Collection<DexType> removedClasses) {
+ assert checkIfObsolete();
return new AppInfoWithLiveness(this, application, removedClasses);
}
- public AppInfoWithLiveness rewrittenWithLense(DirectMappedDexApplication application,
- GraphLense lense) {
+ public AppInfoWithLiveness rewrittenWithLense(
+ DirectMappedDexApplication application, GraphLense lense) {
+ assert checkIfObsolete();
return new AppInfoWithLiveness(this, application, lense);
}
@@ -2625,14 +2651,17 @@
* tree shaking.
*/
public boolean wasPruned(DexType type) {
+ assert checkIfObsolete();
return prunedTypes.contains(type);
}
public Set<DexType> getPrunedTypes() {
+ assert checkIfObsolete();
return prunedTypes;
}
public DexEncodedMethod lookup(Type type, DexMethod target, DexType invocationContext) {
+ assert checkIfObsolete();
DexType holder = target.holder;
if (!holder.isClassType()) {
return null;
@@ -2657,11 +2686,13 @@
* For mapping invoke virtual instruction to single target method.
*/
public DexEncodedMethod lookupSingleVirtualTarget(DexMethod method) {
+ assert checkIfObsolete();
return lookupSingleVirtualTarget(method, method.holder);
}
public DexEncodedMethod lookupSingleVirtualTarget(
DexMethod method, DexType refinedReceiverType) {
+ assert checkIfObsolete();
// This implements the logic from
// https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-6.html#jvms-6.5.invokevirtual
assert method != null;
@@ -2801,11 +2832,13 @@
}
public DexEncodedMethod lookupSingleInterfaceTarget(DexMethod method) {
+ assert checkIfObsolete();
return lookupSingleInterfaceTarget(method, method.holder);
}
public DexEncodedMethod lookupSingleInterfaceTarget(
DexMethod method, DexType refinedReceiverType) {
+ assert checkIfObsolete();
if (instantiatedLambdas.contains(method.holder)) {
return null;
}
@@ -2862,12 +2895,14 @@
}
public AppInfoWithLiveness addSwitchMaps(Map<DexField, Int2ReferenceMap<DexField>> switchMaps) {
+ assert checkIfObsolete();
assert this.switchMaps.isEmpty();
return new AppInfoWithLiveness(this, switchMaps, ordinalsMaps);
}
public AppInfoWithLiveness addEnumOrdinalMaps(
Map<DexType, Reference2IntMap<DexField>> ordinalsMaps) {
+ assert checkIfObsolete();
assert this.ordinalsMaps.isEmpty();
return new AppInfoWithLiveness(this, switchMaps, ordinalsMaps);
}
@@ -2947,7 +2982,7 @@
@Override
public boolean addField(DexField field) {
- DexClass holder = appInfo.definitionFor(field.holder);
+ DexClass holder = appView.definitionFor(field.holder);
if (holder == null) {
return false;
}
@@ -2969,7 +3004,7 @@
@Override
public boolean addMethod(DexMethod method) {
- DexClass holder = appInfo.definitionFor(method.holder);
+ DexClass holder = appView.definitionFor(method.holder);
if (holder == null) {
return false;
}
@@ -3100,7 +3135,7 @@
return classNodes.computeIfAbsent(
type,
t -> {
- DexClass definition = appInfo.definitionFor(t);
+ DexClass definition = appView.definitionFor(t);
return new ClassGraphNode(
definition != null && definition.isLibraryClass(),
Reference.classFromDescriptor(t.toDescriptorString()));
@@ -3111,7 +3146,7 @@
return methodNodes.computeIfAbsent(
context,
m -> {
- DexClass holderDefinition = appInfo.definitionFor(context.holder);
+ DexClass holderDefinition = appView.definitionFor(context.holder);
Builder<TypeReference> builder = ImmutableList.builder();
for (DexType param : m.proto.parameters.values) {
builder.add(Reference.typeFromDescriptor(param.toDescriptorString()));
@@ -3132,7 +3167,7 @@
return fieldNodes.computeIfAbsent(
context,
f -> {
- DexClass holderDefinition = appInfo.definitionFor(context.holder);
+ DexClass holderDefinition = appView.definitionFor(context.holder);
return new FieldGraphNode(
holderDefinition != null && holderDefinition.isLibraryClass(),
Reference.field(
diff --git a/src/main/java/com/android/tools/r8/shaking/MainDexDirectReferenceTracer.java b/src/main/java/com/android/tools/r8/shaking/MainDexDirectReferenceTracer.java
index 07aaecd..3307f8d 100644
--- a/src/main/java/com/android/tools/r8/shaking/MainDexDirectReferenceTracer.java
+++ b/src/main/java/com/android/tools/r8/shaking/MainDexDirectReferenceTracer.java
@@ -31,7 +31,7 @@
private final Consumer<DexType> consumer;
public MainDexDirectReferenceTracer(AppInfoWithSubtyping appInfo, Consumer<DexType> consumer) {
- this.codeDirectReferenceCollector = new DirectReferencesCollector(appInfo.dexItemFactory);
+ this.codeDirectReferenceCollector = new DirectReferencesCollector(appInfo.dexItemFactory());
this.appInfo = appInfo;
this.consumer = consumer;
}
@@ -68,7 +68,7 @@
new MainDexDirectReferenceTracer(
appInfo,
type -> {
- DexType baseType = type.toBaseType(appInfo.dexItemFactory);
+ DexType baseType = type.toBaseType(appInfo.dexItemFactory());
if (baseType.isClassType() && !classes.contains(baseType)) {
DexClass cls = appInfo.definitionFor(baseType);
if (cls != null && !cls.isLibraryClass()) {
diff --git a/src/main/java/com/android/tools/r8/shaking/MainDexListBuilder.java b/src/main/java/com/android/tools/r8/shaking/MainDexListBuilder.java
index 9d129d6..e14ab9b 100644
--- a/src/main/java/com/android/tools/r8/shaking/MainDexListBuilder.java
+++ b/src/main/java/com/android/tools/r8/shaking/MainDexListBuilder.java
@@ -25,6 +25,7 @@
* <li> Annotation classes with a possible enum value and all classes annotated by them.
*/
public class MainDexListBuilder {
+
private final Set<DexType> roots;
private final AppInfoWithSubtyping appInfo;
private final Map<DexType, Boolean> annotationTypeContainEnum;
@@ -41,19 +42,19 @@
// Only consider program classes for the root set.
this.roots = roots.stream().filter(this::isProgramClass).collect(Collectors.toSet());
mainDexClassesBuilder = MainDexClasses.builder(appInfo).addRoots(this.roots);
- DexClass enumType = appInfo.definitionFor(appInfo.dexItemFactory.enumType);
+ DexClass enumType = appInfo.definitionFor(appInfo.dexItemFactory().enumType);
if (enumType == null) {
throw new CompilationError("Tracing for legacy multi dex is not possible without all"
+ " classpath libraries (java.lang.Enum is missing)");
}
- DexClass annotationType = appInfo.definitionFor(appInfo.dexItemFactory.annotationType);
+ DexClass annotationType = appInfo.definitionFor(appInfo.dexItemFactory().annotationType);
if (annotationType == null) {
throw new CompilationError("Tracing for legacy multi dex is not possible without all"
+ " classpath libraries (java.lang.annotation.Annotation is missing)");
}
annotationTypeContainEnum =
Maps.newHashMapWithExpectedSize(
- appInfo.subtypes(appInfo.dexItemFactory.annotationType).size());
+ appInfo.subtypes(appInfo.dexItemFactory().annotationType).size());
}
public MainDexClasses run() {
@@ -99,7 +100,7 @@
for (DexEncodedMethod method : clazz.virtualMethods()) {
DexProto proto = method.method.proto;
if (proto.parameters.isEmpty()) {
- DexType valueType = proto.returnType.toBaseType(appInfo.dexItemFactory);
+ DexType valueType = proto.returnType.toBaseType(appInfo.dexItemFactory());
if (isEnum(valueType)) {
value = true;
break;
@@ -116,11 +117,11 @@
}
private boolean isEnum(DexType valueType) {
- return valueType.isSubtypeOf(appInfo.dexItemFactory.enumType, appInfo);
+ return valueType.isSubtypeOf(appInfo.dexItemFactory().enumType, appInfo);
}
private boolean isAnnotation(DexType valueType) {
- return valueType.isSubtypeOf(appInfo.dexItemFactory.annotationType, appInfo);
+ return valueType.isSubtypeOf(appInfo.dexItemFactory().annotationType, appInfo);
}
private boolean isProgramClass(DexType dexType) {
@@ -140,7 +141,7 @@
for (DexEncodedMethod method : clazz.virtualMethods()) {
DexProto proto = method.method.proto;
if (proto.parameters.isEmpty()) {
- DexType valueType = proto.returnType.toBaseType(appInfo.dexItemFactory);
+ DexType valueType = proto.returnType.toBaseType(appInfo.dexItemFactory());
if (isEnum(valueType)) {
addDirectDependency(valueType);
}
@@ -155,7 +156,7 @@
private void addDirectDependency(DexType type) {
// Consider only component type of arrays
- type = type.toBaseType(appInfo.dexItemFactory);
+ type = type.toBaseType(appInfo.dexItemFactory());
if (!type.isClassType() || mainDexClassesBuilder.contains(type)) {
return;
diff --git a/src/main/java/com/android/tools/r8/shaking/RootSetBuilder.java b/src/main/java/com/android/tools/r8/shaking/RootSetBuilder.java
index e1dd681..cac448d 100644
--- a/src/main/java/com/android/tools/r8/shaking/RootSetBuilder.java
+++ b/src/main/java/com/android/tools/r8/shaking/RootSetBuilder.java
@@ -94,19 +94,15 @@
public RootSetBuilder(
AppView<? extends AppInfo> appView,
DexApplication application,
- Iterable<? extends ProguardConfigurationRule> rules,
- InternalOptions options) {
+ Iterable<? extends ProguardConfigurationRule> rules) {
this.appView = appView;
this.application = application.asDirect();
this.rules = rules;
- this.options = options;
+ this.options = appView.options();
}
- RootSetBuilder(
- AppView<? extends AppInfo> appView,
- Collection<ProguardIfRule> ifRules,
- InternalOptions options) {
- this(appView, appView.appInfo().app, ifRules, options);
+ RootSetBuilder(AppView<? extends AppInfo> appView, Collection<ProguardIfRule> ifRules) {
+ this(appView, appView.appInfo().app(), ifRules);
}
// Process a class with the keep rule.
@@ -864,7 +860,7 @@
return;
}
if (type.isArrayType()) {
- type = type.toBaseType(application.dexItemFactory);
+ type = type.toBaseType(appView.dexItemFactory());
}
if (type.isPrimitiveType()) {
return;
diff --git a/src/main/java/com/android/tools/r8/shaking/StaticClassMerger.java b/src/main/java/com/android/tools/r8/shaking/StaticClassMerger.java
index 1895a07..f244b6d 100644
--- a/src/main/java/com/android/tools/r8/shaking/StaticClassMerger.java
+++ b/src/main/java/com/android/tools/r8/shaking/StaticClassMerger.java
@@ -222,7 +222,7 @@
}
public GraphLense run() {
- for (DexProgramClass clazz : appView.appInfo().app.classesWithDeterministicOrder()) {
+ for (DexProgramClass clazz : appView.appInfo().app().classesWithDeterministicOrder()) {
MergeGroup group = satisfiesMergeCriteria(clazz);
if (group != MergeGroup.DONT_MERGE) {
merge(clazz, group);
diff --git a/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java b/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
index 6aa1136..b8fd5f6 100644
--- a/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
+++ b/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
@@ -201,7 +201,6 @@
private final AppInfoWithLiveness appInfo;
private final AppView<AppInfoWithLiveness> appView;
private final ExecutorService executorService;
- private final GraphLense graphLense;
private final MethodPoolCollection methodPoolCollection;
private final Timing timing;
private Collection<DexMethod> invokes;
@@ -236,7 +235,6 @@
this.appInfo = appView.appInfo();
this.appView = appView;
this.executorService = executorService;
- this.graphLense = appView.graphLense();
this.methodPoolCollection = new MethodPoolCollection(application);
this.renamedMembersLense = new VerticalClassMergerGraphLense.Builder();
this.timing = timing;
@@ -331,7 +329,7 @@
}
private void markTypeAsPinned(DexType type, AbortReason reason) {
- DexType baseType = type.toBaseType(appInfo.dexItemFactory);
+ DexType baseType = type.toBaseType(appView.dexItemFactory());
if (!baseType.isClassType() || appInfo.isPinned(baseType)) {
// We check for the case where the type is pinned according to appInfo.isPinned,
// so we only need to add it here if it is not the case.
@@ -584,7 +582,7 @@
}
private boolean typeMayReferenceMergedSourceOrTarget(DexType type) {
- type = type.toBaseType(appInfo.dexItemFactory);
+ type = type.toBaseType(appView.dexItemFactory());
if (type.isClassType()) {
if (mergeeCandidates.contains(type)) {
return true;
@@ -600,7 +598,7 @@
public GraphLense run() {
timing.begin("merge");
- GraphLense mergingGraphLense = mergeClasses(graphLense);
+ GraphLense mergingGraphLense = mergeClasses();
timing.end();
timing.begin("fixup");
GraphLense result = new TreeFixer().fixupTypeReferences(mergingGraphLense);
@@ -676,13 +674,13 @@
return true;
}
- private GraphLense mergeClasses(GraphLense graphLense) {
+ private GraphLense mergeClasses() {
// Visit the program classes in a top-down order according to the class hierarchy.
TopDownClassHierarchyTraversal.visit(appView, mergeCandidates, this::mergeClassIfPossible);
if (Log.ENABLED) {
Log.debug(getClass(), "Merged %d classes.", mergedClasses.size());
}
- return renamedMembersLense.build(graphLense, mergedClasses, appInfo);
+ return renamedMembersLense.build(appView.graphLense(), mergedClasses, appView);
}
private boolean methodResolutionMayChange(DexClass source, DexClass target) {
@@ -1182,7 +1180,7 @@
SynthesizedBridgeCode code =
new SynthesizedBridgeCode(
newMethod,
- graphLense.getOriginalMethodSignature(method.method),
+ appView.graphLense().getOriginalMethodSignature(method.method),
invocationTarget.method,
invocationTarget.isPrivateMethod() ? DIRECT : STATIC,
target.isInterface());
@@ -1406,7 +1404,7 @@
DexType[] parameterTypes = new DexType[proto.parameters.size() + 1];
parameterTypes[0] = receiverType;
System.arraycopy(proto.parameters.values, 0, parameterTypes, 1, proto.parameters.size());
- return appInfo.dexItemFactory.createProto(proto.returnType, parameterTypes);
+ return appView.dexItemFactory().createProto(proto.returnType, parameterTypes);
}
private class TreeFixer {
@@ -1588,7 +1586,7 @@
int bitsUsed = 0;
int accumulator = 0;
for (DexType parameterType : proto.parameters.values) {
- DexType parameterBaseType = parameterType.toBaseType(appInfo.dexItemFactory);
+ DexType parameterBaseType = parameterType.toBaseType(appView.dexItemFactory());
// Substitute the type with the already merged class to estimate what it will look like.
DexType mappedType = mergedClasses.getOrDefault(parameterBaseType, parameterBaseType);
accumulator <<= 1;
@@ -1604,7 +1602,7 @@
}
}
// We also take the return type into account for potential conflicts.
- DexType returnBaseType = proto.returnType.toBaseType(appInfo.dexItemFactory);
+ DexType returnBaseType = proto.returnType.toBaseType(appView.dexItemFactory());
DexType mappedReturnType = mergedClasses.getOrDefault(returnBaseType, returnBaseType);
accumulator <<= 1;
if (mappedReturnType == type) {
@@ -1678,7 +1676,7 @@
public GraphLenseLookupResult lookupMethod(DexMethod method, DexMethod context, Type type) {
// First look up the method using the existing graph lense (for example, the type will have
// changed if the method was publicized by ClassAndMemberPublicizer).
- GraphLenseLookupResult lookup = graphLense.lookupMethod(method, context, type);
+ GraphLenseLookupResult lookup = appView.graphLense().lookupMethod(method, context, type);
DexMethod previousMethod = lookup.getMethod();
Type previousType = lookup.getType();
// Then check if there is a renaming due to the vertical class merger.
diff --git a/src/main/java/com/android/tools/r8/shaking/VerticalClassMergerGraphLense.java b/src/main/java/com/android/tools/r8/shaking/VerticalClassMergerGraphLense.java
index 6576433..dd90a66 100644
--- a/src/main/java/com/android/tools/r8/shaking/VerticalClassMergerGraphLense.java
+++ b/src/main/java/com/android/tools/r8/shaking/VerticalClassMergerGraphLense.java
@@ -5,6 +5,7 @@
package com.android.tools.r8.shaking;
import com.android.tools.r8.graph.AppInfo;
+import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethod;
@@ -47,7 +48,8 @@
//
// For the invocation "invoke-virtual A.m()" in B.m2, this graph lense will return the method B.m.
public class VerticalClassMergerGraphLense extends NestedGraphLense {
- private final AppInfo appInfo;
+
+ private final AppView<? extends AppInfo> appView;
private final Map<DexType, Map<DexMethod, GraphLenseLookupResult>>
contextualVirtualToDirectMethodMaps;
@@ -55,7 +57,7 @@
private final Map<DexMethod, DexMethod> originalMethodSignaturesForBridges;
public VerticalClassMergerGraphLense(
- AppInfo appInfo,
+ AppView<? extends AppInfo> appView,
Map<DexField, DexField> fieldMap,
Map<DexMethod, DexMethod> methodMap,
Set<DexMethod> mergedMethods,
@@ -71,8 +73,8 @@
originalFieldSignatures,
originalMethodSignatures,
previousLense,
- appInfo.dexItemFactory);
- this.appInfo = appInfo;
+ appView.dexItemFactory());
+ this.appView = appView;
this.contextualVirtualToDirectMethodMaps = contextualVirtualToDirectMethodMaps;
this.mergedMethods = mergedMethods;
this.originalMethodSignaturesForBridges = originalMethodSignaturesForBridges;
@@ -120,7 +122,7 @@
@Override
protected Type mapInvocationType(DexMethod newMethod, DexMethod originalMethod, Type type) {
- return super.mapVirtualInterfaceInvocationTypes(appInfo, newMethod, originalMethod, type);
+ return super.mapVirtualInterfaceInvocationTypes(appView, newMethod, originalMethod, type);
}
@Override
@@ -174,7 +176,7 @@
public GraphLense build(
GraphLense previousLense,
Map<DexType, DexType> mergedClasses,
- AppInfo appInfo) {
+ AppView<? extends AppInfo> appView) {
if (fieldMap.isEmpty()
&& methodMap.isEmpty()
&& contextualVirtualToDirectMethodMaps.isEmpty()) {
@@ -184,11 +186,11 @@
BiMap<DexField, DexField> originalFieldSignatures = fieldMap.inverse();
// Build new graph lense.
return new VerticalClassMergerGraphLense(
- appInfo,
+ appView,
fieldMap,
methodMap,
getMergedMethodSignaturesAfterClassMerging(
- mergedMethodsBuilder.build(), mergedClasses, appInfo.dexItemFactory, cache),
+ mergedMethodsBuilder.build(), mergedClasses, appView.dexItemFactory(), cache),
contextualVirtualToDirectMethodMaps,
originalFieldSignatures,
originalMethodSignatures,
diff --git a/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java b/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java
index 5a71add..52952a5 100644
--- a/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java
+++ b/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java
@@ -1848,9 +1848,54 @@
}
}
+ private static class VmErrors {
+ private final Set<TestRuntime> failedVms = new HashSet<>();
+ private StringBuilder message;
+
+ private void addShouldHaveFailedError(CompilerUnderTest compilerUnderTest, TestRuntime vm) {
+ addFailure(vm);
+ message.append(
+ "FAILURE: Test should have failed on "
+ + vm
+ + " after compiling with "
+ + compilerUnderTest
+ + ".\n");
+ }
+
+ private void addFailedOnRunError(
+ CompilerUnderTest compilerUnderTest, TestRuntime vm, AssertionError error) {
+ addFailure(vm);
+ message.append(
+ "FAILURE: Test failed on "
+ + vm
+ + " after compiling with "
+ + compilerUnderTest
+ + ", error:\n"
+ + error.getMessage()
+ + "\n");
+ }
+
+ private void addFailure(TestRuntime vm) {
+ if (message == null) {
+ message = new StringBuilder();
+ }
+ failedVms.add(vm);
+ }
+ }
+
protected void runJctfTest(
CompilerUnderTest compilerUnderTest, String classFilePath, String fullClassName)
throws IOException, CompilationFailedException {
+ VmErrors vmErrors = runJctfTestCore(compilerUnderTest, classFilePath, fullClassName);
+ if (vmErrors.message != null) {
+ throw new RuntimeException(vmErrors.message.toString());
+ }
+ }
+
+ private VmErrors runJctfTestCore(
+ CompilerUnderTest compilerUnderTest, String classFilePath, String fullClassName)
+ throws IOException, CompilationFailedException {
+ VmErrors vmErrors = new VmErrors();
List<TestRuntime> vms = new ArrayList<>();
if (compilerUnderTest == CompilerUnderTest.R8CF) {
for (CfVm vm : TestParametersBuilder.getAvailableCfVms()) {
@@ -1890,7 +1935,7 @@
}
if (vmSpecs.isEmpty()) {
- return;
+ return vmErrors;
}
File classFile = new File(JCTF_TESTS_PREFIX + "/" + classFilePath);
@@ -1959,7 +2004,7 @@
runJctfTestDoRunOnJava(
fileNames, vmSpec.spec, fullClassName, compilationMode, vmSpec.vm.asCf().getVm());
}
- return;
+ return vmErrors;
}
CompilationOptions compilationOptions = null;
@@ -1981,17 +2026,31 @@
Files.copy(
compiledDir.toPath().resolve("classes.dex"),
vmSpec.spec.directory.toPath().resolve("classes.dex"));
- runJctfTestDoRunOnArt(fileNames, vmSpec.spec, fullClassName, vmSpec.vm.asDex().getVm());
+
+ AssertionError vmError = null;
+ try {
+ runJctfTestDoRunOnArt(fileNames, vmSpec.spec, fullClassName, vmSpec.vm.asDex().getVm());
+ } catch (AssertionError e) {
+ vmError = e;
+ }
+ if (vmSpec.spec.failsOnRun && vmError == null) {
+ vmErrors.addShouldHaveFailedError(firstCompilerUnderTest, vmSpec.vm);
+ } else if (!vmSpec.spec.failsOnRun && vmError != null) {
+ vmErrors.addFailedOnRunError(firstCompilerUnderTest, vmSpec.vm, vmError);
+ }
}
if (compilerUnderTest != CompilerUnderTest.R8_AFTER_D8) {
- return;
+ return vmErrors;
}
// Second pass (R8), if R8_AFTER_D8.
CompilationOptions r8CompilationOptions = null;
File r8CompiledDir = temp.newFolder();
for (VmSpec vmSpec : vmSpecs) {
+ if (vmSpec.spec.failsOnRun || vmErrors.failedVms.contains(vmSpec.vm)) {
+ continue;
+ }
File r8ResultDir = temp.newFolder("r8-output-" + vmSpec.vm.toString());
TestSpecification specification =
JctfTestSpecifications.getExpectedOutcome(
@@ -2019,8 +2078,13 @@
Files.copy(
r8CompiledDir.toPath().resolve("classes.dex"),
specification.directory.toPath().resolve("classes.dex"));
- runJctfTestDoRunOnArt(fileNames, specification, fullClassName, vmSpec.vm.asDex().getVm());
+ try {
+ runJctfTestDoRunOnArt(fileNames, specification, fullClassName, vmSpec.vm.asDex().getVm());
+ } catch (AssertionError e) {
+ vmErrors.addFailedOnRunError(CompilerUnderTest.R8, vmSpec.vm, e);
+ }
}
+ return vmErrors;
}
private void runJctfTestDoRunOnArt(
@@ -2061,10 +2125,6 @@
builder.setMainClass(JUNIT_TEST_RUNNER);
builder.appendProgramArgument(fullClassName);
- if (specification.failsOnRun) {
- expectException(AssertionError.class);
- }
-
try {
ToolHelper.runArt(builder);
} catch (AssertionError e) {
@@ -2072,9 +2132,6 @@
specification.resolveFile("classes.dex"), e);
throw e;
}
- if (specification.failsOnRun) {
- System.err.println("Should have failed run with art.");
- }
}
private void runJctfTestDoRunOnJava(
diff --git a/src/test/java/com/android/tools/r8/cf/BootstrapCurrentEqualityTest.java b/src/test/java/com/android/tools/r8/cf/BootstrapCurrentEqualityTest.java
index fc00afb..d96d999 100644
--- a/src/test/java/com/android/tools/r8/cf/BootstrapCurrentEqualityTest.java
+++ b/src/test/java/com/android/tools/r8/cf/BootstrapCurrentEqualityTest.java
@@ -13,6 +13,8 @@
import com.android.tools.r8.CompilationMode;
import com.android.tools.r8.ExternalR8TestCompileResult;
import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.ProcessResult;
import com.android.tools.r8.utils.FileUtils;
@@ -25,17 +27,22 @@
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collection;
import java.util.Collections;
import java.util.List;
import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
/**
* This test relies on a freshly built build/libs/r8lib_with_deps.jar. If this test fails remove
* build directory and rebuild r8lib_with_deps by calling test.py or gradle r8libWithdeps.
*/
+@RunWith(Parameterized.class)
public class BootstrapCurrentEqualityTest extends TestBase {
private static final Path MAIN_KEEP = Paths.get("src/main/keep.txt");
@@ -54,8 +61,19 @@
@BeforeClass
public static void beforeAll() throws Exception {
- r8R8Debug = compileR8(CompilationMode.DEBUG);
- r8R8Release = compileR8(CompilationMode.RELEASE);
+ if (data().stream().count() > 0) {
+ r8R8Debug = compileR8(CompilationMode.DEBUG);
+ r8R8Release = compileR8(CompilationMode.RELEASE);
+ }
+ }
+
+ @Parameters
+ public static TestParametersCollection data() {
+ return getTestParameters().withCfRuntimes().build();
+ }
+
+ public BootstrapCurrentEqualityTest(TestParameters parameters) {
+ // TODO: use parameters to run on the right java.
}
private static Pair<Path, Path> compileR8(CompilationMode mode) throws Exception {
diff --git a/src/test/java/com/android/tools/r8/cf/BootstrapTest.java b/src/test/java/com/android/tools/r8/cf/BootstrapTest.java
index fc24ed3..883c2c6 100644
--- a/src/test/java/com/android/tools/r8/cf/BootstrapTest.java
+++ b/src/test/java/com/android/tools/r8/cf/BootstrapTest.java
@@ -13,6 +13,8 @@
import com.android.tools.r8.CompilationMode;
import com.android.tools.r8.R8Command;
import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.ProcessResult;
import com.android.tools.r8.utils.FileUtils;
@@ -23,7 +25,11 @@
import java.util.Collections;
import java.util.List;
import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+@RunWith(Parameterized.class)
public class BootstrapTest extends TestBase {
private static final Path R8_STABLE_JAR = Paths.get("third_party/r8/r8.jar");
@@ -56,6 +62,15 @@
}
}
+ @Parameters
+ public static TestParametersCollection data() {
+ return getTestParameters().withCfRuntimes().build();
+ }
+
+ public BootstrapTest(TestParameters parameters) {
+ // TODO: use parameters to fork the right Java.
+ }
+
@Test
public void test() throws Exception {
// Run hello.jar to ensure it exists and is valid.
diff --git a/src/test/java/com/android/tools/r8/graph/TargetLookupTest.java b/src/test/java/com/android/tools/r8/graph/TargetLookupTest.java
index 263a4c0..db68c25 100644
--- a/src/test/java/com/android/tools/r8/graph/TargetLookupTest.java
+++ b/src/test/java/com/android/tools/r8/graph/TargetLookupTest.java
@@ -78,7 +78,7 @@
AndroidApp application = buildApplication(builder);
AppInfo appInfo = getAppInfo(application);
- CodeInspector inspector = new CodeInspector(appInfo.app);
+ CodeInspector inspector = new CodeInspector(appInfo.app());
DexEncodedMethod method = getMethod(inspector, DEFAULT_CLASS_NAME, "int", "x",
ImmutableList.of());
assertNull(appInfo.lookupVirtualTarget(method.method.holder, method.method));
@@ -99,7 +99,7 @@
}
@Test
- public void lookupDirectSuper() throws Exception {
+ public void lookupDirectSuper() {
SmaliBuilder builder = new SmaliBuilder("TestSuper");
builder.addDefaultConstructor();
@@ -148,7 +148,7 @@
AndroidApp application = buildApplication(builder);
AppInfo appInfo = getAppInfo(application);
- CodeInspector inspector = new CodeInspector(appInfo.app);
+ CodeInspector inspector = new CodeInspector(appInfo.app());
DexMethod methodXOnTestSuper =
getMethod(inspector, "TestSuper", "int", "x", ImmutableList.of()).method;
@@ -160,7 +160,7 @@
DexProto methodXProto = methodXOnTestSuper.proto;
DexString methodXName = methodXOnTestSuper.name;
DexMethod methodXOnTest =
- appInfo.dexItemFactory.createMethod(classTest, methodXProto, methodXName);
+ appInfo.dexItemFactory().createMethod(classTest, methodXProto, methodXName);
assertNull(appInfo.lookupVirtualTarget(classTestSuper, methodXOnTestSuper));
assertNull(appInfo.lookupVirtualTarget(classTest, methodXOnTestSuper));
@@ -197,7 +197,7 @@
AndroidApp application = buildApplication(builder);
AppInfo appInfo = getAppInfo(application);
- DexItemFactory factory = appInfo.dexItemFactory;
+ DexItemFactory factory = appInfo.dexItemFactory();
DexField aFieldOnSubClass = factory
.createField(factory.createType("LSubClass;"), factory.intType, "aField");
@@ -229,7 +229,7 @@
}
AndroidApp application = builder.build();
AppInfo appInfo = getAppInfo(application);
- DexItemFactory factory = appInfo.dexItemFactory;
+ DexItemFactory factory = appInfo.dexItemFactory();
DexType i0 = factory.createType("L" + pkg + "/I0;");
DexType i1 = factory.createType("L" + pkg + "/I1;");
diff --git a/src/test/java/com/android/tools/r8/ir/InlineTest.java b/src/test/java/com/android/tools/r8/ir/InlineTest.java
index d7b2762..8e99382 100644
--- a/src/test/java/com/android/tools/r8/ir/InlineTest.java
+++ b/src/test/java/com/android/tools/r8/ir/InlineTest.java
@@ -50,8 +50,7 @@
new RootSetBuilder(
appView,
application,
- ImmutableList.of(ProguardKeepRule.defaultKeepAllRule(unused -> {})),
- options)
+ ImmutableList.of(ProguardKeepRule.defaultKeepAllRule(unused -> {})))
.run(executorService);
Timing timing = new Timing(getClass().getSimpleName());
Enqueuer enqueuer = new Enqueuer(appView, options, null);
diff --git a/src/test/java/com/android/tools/r8/ir/IrInjectionTestBase.java b/src/test/java/com/android/tools/r8/ir/IrInjectionTestBase.java
index 083f478..1ba8700 100644
--- a/src/test/java/com/android/tools/r8/ir/IrInjectionTestBase.java
+++ b/src/test/java/com/android/tools/r8/ir/IrInjectionTestBase.java
@@ -95,7 +95,7 @@
RootSet rootSet,
MethodSubject method,
List<IRCode> additionalCode) {
- this.application = appView.appInfo().app;
+ this.application = appView.appInfo().app();
this.appView = appView;
this.rootSet = rootSet;
this.method = method.getMethod();
diff --git a/src/test/java/com/android/tools/r8/ir/analysis/type/NullabilityTest.java b/src/test/java/com/android/tools/r8/ir/analysis/type/NullabilityTest.java
index 54399f9..66fa712 100644
--- a/src/test/java/com/android/tools/r8/ir/analysis/type/NullabilityTest.java
+++ b/src/test/java/com/android/tools/r8/ir/analysis/type/NullabilityTest.java
@@ -50,7 +50,7 @@
BiConsumer<AppInfo, IRCode> inspector)
throws Exception {
AppView<? extends AppInfo> appView = build(mainClass);
- CodeInspector codeInspector = new CodeInspector(appView.appInfo().app);
+ CodeInspector codeInspector = new CodeInspector(appView.appInfo().app());
MethodSubject fooSubject = codeInspector.clazz(mainClass.getName()).method(signature);
DexEncodedMethod foo = codeInspector.clazz(mainClass.getName()).method(signature).getMethod();
IRCode irCode = fooSubject.buildIR();
@@ -119,129 +119,209 @@
public void nonNullAfterSafeInvokes() throws Exception {
MethodSignature signature =
new MethodSignature("foo", "int", new String[]{"java.lang.String"});
- buildAndTest(NonNullAfterInvoke.class, signature, false, (appInfo, irCode) -> {
- DexType assertionErrorType = appInfo.dexItemFactory.createType("Ljava/lang/AssertionError;");
- DexType mainClass = appInfo.dexItemFactory.createType(
- DescriptorUtils.javaTypeToDescriptor(NonNullAfterInvoke.class.getCanonicalName()));
- Map<Class<? extends Instruction>, TypeLatticeElement> expectedLattices = ImmutableMap.of(
- InvokeVirtual.class, stringClassType(appInfo, maybeNull()),
- NonNull.class, stringClassType(appInfo, definitelyNotNull()),
- NewInstance.class, fromDexType(assertionErrorType, definitelyNotNull(), appInfo));
- forEachOutValue(irCode, (v, l) -> verifyClassTypeLattice(expectedLattices, mainClass, v, l));
- });
+ buildAndTest(
+ NonNullAfterInvoke.class,
+ signature,
+ false,
+ (appInfo, irCode) -> {
+ DexType assertionErrorType =
+ appInfo.dexItemFactory().createType("Ljava/lang/AssertionError;");
+ DexType mainClass =
+ appInfo
+ .dexItemFactory()
+ .createType(
+ DescriptorUtils.javaTypeToDescriptor(
+ NonNullAfterInvoke.class.getCanonicalName()));
+ Map<Class<? extends Instruction>, TypeLatticeElement> expectedLattices =
+ ImmutableMap.of(
+ InvokeVirtual.class, stringClassType(appInfo, maybeNull()),
+ NonNull.class, stringClassType(appInfo, definitelyNotNull()),
+ NewInstance.class, fromDexType(assertionErrorType, definitelyNotNull(), appInfo));
+ forEachOutValue(
+ irCode, (v, l) -> verifyClassTypeLattice(expectedLattices, mainClass, v, l));
+ });
}
@Test
public void stillNullAfterExceptionCatch_invoke() throws Exception {
MethodSignature signature =
new MethodSignature("bar", "int", new String[]{"java.lang.String"});
- buildAndTest(NonNullAfterInvoke.class, signature, true, (appInfo, irCode) -> {
- DexType assertionErrorType = appInfo.dexItemFactory.createType("Ljava/lang/AssertionError;");
- DexType mainClass = appInfo.dexItemFactory.createType(
- DescriptorUtils.javaTypeToDescriptor(NonNullAfterInvoke.class.getCanonicalName()));
- Map<Class<? extends Instruction>, TypeLatticeElement> expectedLattices = ImmutableMap.of(
- InvokeVirtual.class, stringClassType(appInfo, maybeNull()),
- NonNull.class, stringClassType(appInfo, definitelyNotNull()),
- NewInstance.class, fromDexType(assertionErrorType, definitelyNotNull(), appInfo));
- forEachOutValue(irCode, (v, l) -> verifyClassTypeLattice(expectedLattices, mainClass, v, l));
- });
+ buildAndTest(
+ NonNullAfterInvoke.class,
+ signature,
+ true,
+ (appInfo, irCode) -> {
+ DexType assertionErrorType =
+ appInfo.dexItemFactory().createType("Ljava/lang/AssertionError;");
+ DexType mainClass =
+ appInfo
+ .dexItemFactory()
+ .createType(
+ DescriptorUtils.javaTypeToDescriptor(
+ NonNullAfterInvoke.class.getCanonicalName()));
+ Map<Class<? extends Instruction>, TypeLatticeElement> expectedLattices =
+ ImmutableMap.of(
+ InvokeVirtual.class, stringClassType(appInfo, maybeNull()),
+ NonNull.class, stringClassType(appInfo, definitelyNotNull()),
+ NewInstance.class, fromDexType(assertionErrorType, definitelyNotNull(), appInfo));
+ forEachOutValue(
+ irCode, (v, l) -> verifyClassTypeLattice(expectedLattices, mainClass, v, l));
+ });
}
@Test
public void nonNullAfterSafeArrayAccess() throws Exception {
MethodSignature signature =
new MethodSignature("foo", "int", new String[]{"java.lang.String[]"});
- buildAndTest(NonNullAfterArrayAccess.class, signature, false, (appInfo, irCode) -> {
- DexType assertionErrorType = appInfo.dexItemFactory.createType("Ljava/lang/AssertionError;");
- DexType mainClass = appInfo.dexItemFactory.createType(
- DescriptorUtils.javaTypeToDescriptor(NonNullAfterArrayAccess.class.getCanonicalName()));
- Map<Class<? extends Instruction>, TypeLatticeElement> expectedLattices = ImmutableMap.of(
- // An element inside a non-null array could be null.
- ArrayGet.class, fromDexType(appInfo.dexItemFactory.stringType, maybeNull(), appInfo),
- NewInstance.class, fromDexType(assertionErrorType, definitelyNotNull(), appInfo));
- forEachOutValue(irCode, (v, l) -> {
- if (l.isArrayType()) {
- ArrayTypeLatticeElement lattice = l.asArrayTypeLatticeElement();
- assertEquals(1, lattice.getNesting());
- TypeLatticeElement elementTypeLattice = lattice.getArrayMemberTypeAsMemberType();
- assertTrue(elementTypeLattice.isClassType());
- assertEquals(
- appInfo.dexItemFactory.stringType,
- elementTypeLattice.asClassTypeLatticeElement().getClassType());
- assertEquals(v.definition.isArgument(), l.isNullable());
- } else if (l.isClassType()) {
- verifyClassTypeLattice(expectedLattices, mainClass, v, l);
- }
- });
- });
+ buildAndTest(
+ NonNullAfterArrayAccess.class,
+ signature,
+ false,
+ (appInfo, irCode) -> {
+ DexType assertionErrorType =
+ appInfo.dexItemFactory().createType("Ljava/lang/AssertionError;");
+ DexType mainClass =
+ appInfo
+ .dexItemFactory()
+ .createType(
+ DescriptorUtils.javaTypeToDescriptor(
+ NonNullAfterArrayAccess.class.getCanonicalName()));
+ Map<Class<? extends Instruction>, TypeLatticeElement> expectedLattices =
+ ImmutableMap.of(
+ // An element inside a non-null array could be null.
+ ArrayGet.class,
+ fromDexType(appInfo.dexItemFactory().stringType, maybeNull(), appInfo),
+ NewInstance.class, fromDexType(assertionErrorType, definitelyNotNull(), appInfo));
+ forEachOutValue(
+ irCode,
+ (v, l) -> {
+ if (l.isArrayType()) {
+ ArrayTypeLatticeElement lattice = l.asArrayTypeLatticeElement();
+ assertEquals(1, lattice.getNesting());
+ TypeLatticeElement elementTypeLattice = lattice.getArrayMemberTypeAsMemberType();
+ assertTrue(elementTypeLattice.isClassType());
+ assertEquals(
+ appInfo.dexItemFactory().stringType,
+ elementTypeLattice.asClassTypeLatticeElement().getClassType());
+ assertEquals(v.definition.isArgument(), l.isNullable());
+ } else if (l.isClassType()) {
+ verifyClassTypeLattice(expectedLattices, mainClass, v, l);
+ }
+ });
+ });
}
@Test
public void stillNullAfterExceptionCatch_aget() throws Exception {
MethodSignature signature =
new MethodSignature("bar", "int", new String[]{"java.lang.String[]"});
- buildAndTest(NonNullAfterArrayAccess.class, signature, true, (appInfo, irCode) -> {
- DexType assertionErrorType = appInfo.dexItemFactory.createType("Ljava/lang/AssertionError;");
- DexType mainClass = appInfo.dexItemFactory.createType(
- DescriptorUtils.javaTypeToDescriptor(NonNullAfterArrayAccess.class.getCanonicalName()));
- Map<Class<? extends Instruction>, TypeLatticeElement> expectedLattices = ImmutableMap.of(
- // An element inside a non-null array could be null.
- ArrayGet.class, fromDexType(appInfo.dexItemFactory.stringType, maybeNull(), appInfo),
- NewInstance.class, fromDexType(assertionErrorType, definitelyNotNull(), appInfo));
- forEachOutValue(irCode, (v, l) -> {
- if (l.isArrayType()) {
- ArrayTypeLatticeElement lattice = l.asArrayTypeLatticeElement();
- assertEquals(1, lattice.getNesting());
- TypeLatticeElement elementTypeLattice = lattice.getArrayMemberTypeAsMemberType();
- assertTrue(elementTypeLattice.isClassType());
- assertEquals(
- appInfo.dexItemFactory.stringType,
- elementTypeLattice.asClassTypeLatticeElement().getClassType());
- assertEquals(v.definition.isArgument(), l.isNullable());
- } else if (l.isClassType()) {
- verifyClassTypeLattice(expectedLattices, mainClass, v, l);
- }
- });
- });
+ buildAndTest(
+ NonNullAfterArrayAccess.class,
+ signature,
+ true,
+ (appInfo, irCode) -> {
+ DexType assertionErrorType =
+ appInfo.dexItemFactory().createType("Ljava/lang/AssertionError;");
+ DexType mainClass =
+ appInfo
+ .dexItemFactory()
+ .createType(
+ DescriptorUtils.javaTypeToDescriptor(
+ NonNullAfterArrayAccess.class.getCanonicalName()));
+ Map<Class<? extends Instruction>, TypeLatticeElement> expectedLattices =
+ ImmutableMap.of(
+ // An element inside a non-null array could be null.
+ ArrayGet.class,
+ fromDexType(appInfo.dexItemFactory().stringType, maybeNull(), appInfo),
+ NewInstance.class, fromDexType(assertionErrorType, definitelyNotNull(), appInfo));
+ forEachOutValue(
+ irCode,
+ (v, l) -> {
+ if (l.isArrayType()) {
+ ArrayTypeLatticeElement lattice = l.asArrayTypeLatticeElement();
+ assertEquals(1, lattice.getNesting());
+ TypeLatticeElement elementTypeLattice = lattice.getArrayMemberTypeAsMemberType();
+ assertTrue(elementTypeLattice.isClassType());
+ assertEquals(
+ appInfo.dexItemFactory().stringType,
+ elementTypeLattice.asClassTypeLatticeElement().getClassType());
+ assertEquals(v.definition.isArgument(), l.isNullable());
+ } else if (l.isClassType()) {
+ verifyClassTypeLattice(expectedLattices, mainClass, v, l);
+ }
+ });
+ });
}
@Test
public void nonNullAfterSafeFieldAccess() throws Exception {
MethodSignature signature = new MethodSignature("foo", "int",
new String[]{FieldAccessTest.class.getCanonicalName()});
- buildAndTest(NonNullAfterFieldAccess.class, signature, false, (appInfo, irCode) -> {
- DexType assertionErrorType = appInfo.dexItemFactory.createType("Ljava/lang/AssertionError;");
- DexType mainClass = appInfo.dexItemFactory.createType(
- DescriptorUtils.javaTypeToDescriptor(NonNullAfterFieldAccess.class.getCanonicalName()));
- DexType testClass = appInfo.dexItemFactory.createType(
- DescriptorUtils.javaTypeToDescriptor(FieldAccessTest.class.getCanonicalName()));
- Map<Class<? extends Instruction>, TypeLatticeElement> expectedLattices = ImmutableMap.of(
- Argument.class, fromDexType(testClass, maybeNull(), appInfo),
- NonNull.class, fromDexType(testClass, definitelyNotNull(), appInfo),
- // instance may not be initialized.
- InstanceGet.class, fromDexType(appInfo.dexItemFactory.stringType, maybeNull(), appInfo),
- NewInstance.class, fromDexType(assertionErrorType, definitelyNotNull(), appInfo));
- forEachOutValue(irCode, (v, l) -> verifyClassTypeLattice(expectedLattices, mainClass, v, l));
- });
+ buildAndTest(
+ NonNullAfterFieldAccess.class,
+ signature,
+ false,
+ (appInfo, irCode) -> {
+ DexType assertionErrorType =
+ appInfo.dexItemFactory().createType("Ljava/lang/AssertionError;");
+ DexType mainClass =
+ appInfo
+ .dexItemFactory()
+ .createType(
+ DescriptorUtils.javaTypeToDescriptor(
+ NonNullAfterFieldAccess.class.getCanonicalName()));
+ DexType testClass =
+ appInfo
+ .dexItemFactory()
+ .createType(
+ DescriptorUtils.javaTypeToDescriptor(
+ FieldAccessTest.class.getCanonicalName()));
+ Map<Class<? extends Instruction>, TypeLatticeElement> expectedLattices =
+ ImmutableMap.of(
+ Argument.class, fromDexType(testClass, maybeNull(), appInfo),
+ NonNull.class, fromDexType(testClass, definitelyNotNull(), appInfo),
+ // instance may not be initialized.
+ InstanceGet.class,
+ fromDexType(appInfo.dexItemFactory().stringType, maybeNull(), appInfo),
+ NewInstance.class, fromDexType(assertionErrorType, definitelyNotNull(), appInfo));
+ forEachOutValue(
+ irCode, (v, l) -> verifyClassTypeLattice(expectedLattices, mainClass, v, l));
+ });
}
@Test
public void stillNullAfterExceptionCatch_iget() throws Exception {
MethodSignature signature = new MethodSignature("bar", "int",
new String[]{FieldAccessTest.class.getCanonicalName()});
- buildAndTest(NonNullAfterFieldAccess.class, signature, true, (appInfo, irCode) -> {
- DexType assertionErrorType = appInfo.dexItemFactory.createType("Ljava/lang/AssertionError;");
- DexType mainClass = appInfo.dexItemFactory.createType(
- DescriptorUtils.javaTypeToDescriptor(NonNullAfterFieldAccess.class.getCanonicalName()));
- DexType testClass = appInfo.dexItemFactory.createType(
- DescriptorUtils.javaTypeToDescriptor(FieldAccessTest.class.getCanonicalName()));
- Map<Class<? extends Instruction>, TypeLatticeElement> expectedLattices = ImmutableMap.of(
- Argument.class, fromDexType(testClass, maybeNull(), appInfo),
- NonNull.class, fromDexType(testClass, definitelyNotNull(), appInfo),
- // instance may not be initialized.
- InstanceGet.class, fromDexType(appInfo.dexItemFactory.stringType, maybeNull(), appInfo),
- NewInstance.class, fromDexType(assertionErrorType, definitelyNotNull(), appInfo));
- forEachOutValue(irCode, (v, l) -> verifyClassTypeLattice(expectedLattices, mainClass, v, l));
- });
+ buildAndTest(
+ NonNullAfterFieldAccess.class,
+ signature,
+ true,
+ (appInfo, irCode) -> {
+ DexType assertionErrorType =
+ appInfo.dexItemFactory().createType("Ljava/lang/AssertionError;");
+ DexType mainClass =
+ appInfo
+ .dexItemFactory()
+ .createType(
+ DescriptorUtils.javaTypeToDescriptor(
+ NonNullAfterFieldAccess.class.getCanonicalName()));
+ DexType testClass =
+ appInfo
+ .dexItemFactory()
+ .createType(
+ DescriptorUtils.javaTypeToDescriptor(
+ FieldAccessTest.class.getCanonicalName()));
+ Map<Class<? extends Instruction>, TypeLatticeElement> expectedLattices =
+ ImmutableMap.of(
+ Argument.class, fromDexType(testClass, maybeNull(), appInfo),
+ NonNull.class, fromDexType(testClass, definitelyNotNull(), appInfo),
+ // instance may not be initialized.
+ InstanceGet.class,
+ fromDexType(appInfo.dexItemFactory().stringType, maybeNull(), appInfo),
+ NewInstance.class, fromDexType(assertionErrorType, definitelyNotNull(), appInfo));
+ forEachOutValue(
+ irCode, (v, l) -> verifyClassTypeLattice(expectedLattices, mainClass, v, l));
+ });
}
}
diff --git a/src/test/java/com/android/tools/r8/ir/analysis/type/TypeLatticeTest.java b/src/test/java/com/android/tools/r8/ir/analysis/type/TypeLatticeTest.java
index 3aa4394..880d428 100644
--- a/src/test/java/com/android/tools/r8/ir/analysis/type/TypeLatticeTest.java
+++ b/src/test/java/com/android/tools/r8/ir/analysis/type/TypeLatticeTest.java
@@ -30,6 +30,7 @@
import org.junit.Test;
public class TypeLatticeTest extends TestBase {
+
private static final String IO_EXCEPTION = "Ljava/io/IOException;";
private static final String NOT_FOUND = "Ljava/io/FileNotFoundException;";
private static final String INTERRUPT = "Ljava/io/InterruptedIOException;";
@@ -505,7 +506,7 @@
@Test
public void testSelfOrderWithoutSubtypingInfo() {
- DexType type = appInfo.dexItemFactory.createType("Lmy/Type;");
+ DexType type = factory.createType("Lmy/Type;");
TypeLatticeElement nonNullType =
fromDexType(type, Nullability.definitelyNotNull(), appInfo);
TypeLatticeElement nullableType = nonNullType.asNullable();
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/ConstantRemovalTest.java b/src/test/java/com/android/tools/r8/ir/optimize/ConstantRemovalTest.java
index 0df0f97..3c003ab 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/ConstantRemovalTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/ConstantRemovalTest.java
@@ -6,6 +6,7 @@
import static org.junit.Assert.assertEquals;
import com.android.tools.r8.graph.AppInfo;
+import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
import com.android.tools.r8.ir.code.BasicBlock;
@@ -29,8 +30,8 @@
public class ConstantRemovalTest {
private static class MockLinearScanRegisterAllocator extends LinearScanRegisterAllocator {
- public MockLinearScanRegisterAllocator(AppInfo appInfo, IRCode code, InternalOptions options) {
- super(appInfo, code, options);
+ public MockLinearScanRegisterAllocator(AppView<? extends AppInfo> appView, IRCode code) {
+ super(appView, code);
}
@Override
@@ -130,6 +131,7 @@
InternalOptions options = new InternalOptions();
options.debug = true;
AppInfo appInfo = new AppInfo(DexApplication.builder(options.itemFactory, null).build());
+ AppView<? extends AppInfo> appView = AppView.createForD8(appInfo, options);
IRCode code =
new IRCode(
options,
@@ -140,7 +142,7 @@
false,
false,
Origin.unknown());
- PeepholeOptimizer.optimize(code, new MockLinearScanRegisterAllocator(appInfo, code, options));
+ PeepholeOptimizer.optimize(code, new MockLinearScanRegisterAllocator(appView, code));
// Check that all four constant number instructions remain.
assertEquals(
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/NonNullTrackerTest.java b/src/test/java/com/android/tools/r8/ir/optimize/NonNullTrackerTest.java
index 155a1ba..69e16ba 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/NonNullTrackerTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/NonNullTrackerTest.java
@@ -35,7 +35,7 @@
Consumer<IRCode> testAugmentedIRCode)
throws Exception {
AppView<? extends AppInfo> appView = build(testClass);
- CodeInspector codeInspector = new CodeInspector(appView.appInfo().app);
+ CodeInspector codeInspector = new CodeInspector(appView.appInfo().app());
MethodSubject fooSubject = codeInspector.clazz(testClass.getName()).method(signature);
IRCode irCode = fooSubject.buildIR();
checkCountOfNonNull(irCode, 0);
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/string/StringConcatenationTest.java b/src/test/java/com/android/tools/r8/ir/optimize/string/StringConcatenationTest.java
new file mode 100644
index 0000000..7acb30d
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/ir/optimize/string/StringConcatenationTest.java
@@ -0,0 +1,147 @@
+// Copyright (c) 2019, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8.ir.optimize.string;
+
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assume.assumeTrue;
+
+import com.android.tools.r8.D8TestRunResult;
+import com.android.tools.r8.R8TestRunResult;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestRunResult;
+import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.android.tools.r8.utils.codeinspector.InstructionSubject.JumboStringMode;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
+import com.google.common.collect.Streams;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class StringConcatenationTest extends TestBase {
+ private static final Class<?> MAIN = StringConcatenationTestClass.class;
+ private static final String JAVA_OUTPUT = StringUtils.lines(
+ "xyz",
+ "42",
+ "0.14 0 false null",
+ "Hello,R8",
+ "Hello,R8",
+ "Hello,",
+ "Hello,D8",
+ "na;na;na;na;na;na;na;na;Batman!",
+ "na;na;na;na;na;na;na;na;Batman!"
+ );
+
+ @Parameterized.Parameters(name = "Backend: {0}")
+ public static Backend[] data() {
+ return Backend.values();
+ }
+
+ private final Backend backend;
+
+ public StringConcatenationTest(Backend backend) {
+ this.backend = backend;
+ }
+
+ @Test
+ public void testJVMoutput() throws Exception {
+ assumeTrue("Only run JVM reference once (for CF backend)", backend == Backend.CF);
+ testForJvm().addTestClasspath().run(MAIN).assertSuccessWithOutput(JAVA_OUTPUT);
+ }
+
+ private void test(
+ TestRunResult result, int expectedStringCount1, int expectedStringCount2)
+ throws Exception {
+ CodeInspector codeInspector = result.inspector();
+ ClassSubject mainClass = codeInspector.clazz(MAIN);
+
+ MethodSubject method = mainClass.uniqueMethodWithName("trivialSequence");
+ assertThat(method, isPresent());
+ long count = Streams.stream(method.iterateInstructions(
+ i -> i.isConstString(JumboStringMode.ALLOW))).count();
+ assertEquals(expectedStringCount1, count);
+
+ method = mainClass.uniqueMethodWithName("nonStringArgs");
+ assertThat(method, isPresent());
+ count = Streams.stream(method.iterateInstructions(
+ i -> i.isConstString(JumboStringMode.ALLOW))).count();
+ assertEquals(0, count);
+
+ method = mainClass.uniqueMethodWithName("typeConversion");
+ assertThat(method, isPresent());
+ count = Streams.stream(method.iterateInstructions(
+ i -> i.isConstString(JumboStringMode.ALLOW))).count();
+ assertEquals(0, count);
+
+ method = mainClass.uniqueMethodWithName("nestedBuilders_appendBuilderItself");
+ assertThat(method, isPresent());
+ count = Streams.stream(method.iterateInstructions(
+ i -> i.isConstString(JumboStringMode.ALLOW))).count();
+ assertEquals(expectedStringCount2, count);
+
+ method = mainClass.uniqueMethodWithName("nestedBuilders_appendBuilderResult");
+ assertThat(method, isPresent());
+ count = Streams.stream(method.iterateInstructions(
+ i -> i.isConstString(JumboStringMode.ALLOW))).count();
+ assertEquals(expectedStringCount2, count);
+
+ method = mainClass.uniqueMethodWithName("simplePhi");
+ assertThat(method, isPresent());
+ count = Streams.stream(method.iterateInstructions(
+ i -> i.isConstString(JumboStringMode.ALLOW))).count();
+ assertEquals(5, count);
+
+ method = mainClass.uniqueMethodWithName("loop");
+ assertThat(method, isPresent());
+ count = Streams.stream(method.iterateInstructions(
+ i -> i.isConstString(JumboStringMode.ALLOW))).count();
+ assertEquals(3, count);
+
+ method = mainClass.uniqueMethodWithName("loopWithBuilder");
+ assertThat(method, isPresent());
+ count = Streams.stream(method.iterateInstructions(
+ i -> i.isConstString(JumboStringMode.ALLOW))).count();
+ assertEquals(2, count);
+ }
+
+ @Test
+ public void testD8() throws Exception {
+ assumeTrue("Only run D8 for Dex backend", backend == Backend.DEX);
+
+ D8TestRunResult result = testForD8()
+ .debug()
+ .addProgramClasses(MAIN)
+ .run(MAIN)
+ .assertSuccessWithOutput(JAVA_OUTPUT);
+ test(result, 3, 4);
+
+ result = testForD8()
+ .release()
+ .addProgramClasses(MAIN)
+ .run(MAIN)
+ .assertSuccessWithOutput(JAVA_OUTPUT);
+ // TODO(b/114002137): could be 1 and 3.
+ test(result, 3, 4);
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ // CF should not canonicalize strings or lower them. See (r8g/30163) and (r8g/30320).
+ assumeTrue(backend == Backend.DEX);
+ R8TestRunResult result = testForR8(backend)
+ .addProgramClasses(MAIN)
+ .enableInliningAnnotations()
+ .addKeepMainRule(MAIN)
+ .noMinification()
+ .run(MAIN)
+ .assertSuccessWithOutput(JAVA_OUTPUT);
+ // TODO(b/114002137): could be 1 and 3.
+ test(result, 3, 4);
+ }
+
+}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/string/StringConcatenationTestClass.java b/src/test/java/com/android/tools/r8/ir/optimize/string/StringConcatenationTestClass.java
new file mode 100644
index 0000000..3cfb5de
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/ir/optimize/string/StringConcatenationTestClass.java
@@ -0,0 +1,115 @@
+// Copyright (c) 2019, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8.ir.optimize.string;
+
+import com.android.tools.r8.NeverInline;
+
+class StringConcatenationTestClass {
+ @NeverInline
+ public static void trivialSequence() {
+ String x = "x";
+ String y = "y";
+ String z = "z";
+ System.out.println(x + y + z);
+ }
+
+ @NeverInline
+ public static void nonStringArgs() {
+ StringBuilder builder = new StringBuilder();
+ builder.append(4);
+ builder.append(2);
+ System.out.println(builder.toString());
+ }
+
+ @NeverInline
+ public static void typeConversion() {
+ StringBuilder builder = new StringBuilder();
+ float f = 0.14f;
+ builder.append(f);
+ builder.append(' ');
+ int i = (int) f;
+ builder.append(i);
+ builder.append(' ');
+
+ boolean b = false;
+ builder.append(b);
+ builder.append(' ');
+ Object n = null;
+ builder.append(n);
+ System.out.println(builder.toString());
+ }
+
+ @NeverInline
+ public static void nestedBuilders_appendBuilderItself() {
+ StringBuilder b1 = new StringBuilder();
+ b1.append("Hello");
+ b1.append(",");
+ StringBuilder b2 = new StringBuilder();
+ b2.append("R");
+ // TODO(b/114002137): switch to use the integer.
+ b2.append("8");
+ b1.append(b2);
+ System.out.println(b1.toString());
+ }
+
+ @NeverInline
+ public static void nestedBuilders_appendBuilderResult() {
+ StringBuilder b1 = new StringBuilder();
+ b1.append("Hello");
+ b1.append(",");
+ StringBuilder b2 = new StringBuilder();
+ b2.append("R");
+ // TODO(b/114002137): switch to use the integer.
+ b2.append("8");
+ b1.append(b2.toString());
+ System.out.println(b1.toString());
+ }
+
+ @NeverInline
+ public static void simplePhi() {
+ StringBuilder builder = new StringBuilder();
+ builder.append("Hello");
+ builder.append(",");
+ System.out.println(builder.toString());
+
+ if (System.currentTimeMillis() > 0) {
+ builder.append("D");
+ } else {
+ builder.append("R");
+ }
+ // TODO(b/114002137): switch to use the integer.
+ builder.append("8");
+ System.out.println(builder.toString());
+ }
+
+ @NeverInline
+ public static void loop() {
+ String r = "";
+ for (int i = 0; i < 8; i++) {
+ r = r + "na;";
+ }
+ System.out.println(r + "Batman!");
+ }
+
+ @NeverInline
+ public static void loopWithBuilder() {
+ StringBuilder builder = new StringBuilder();
+ for (int i = 0; i < 8; i++) {
+ builder.append("na;");
+ }
+ builder.append("Batman!");
+ System.out.println(builder.toString());
+ }
+
+ public static void main(String[] args) {
+ trivialSequence();
+ nonStringArgs();
+ typeConversion();
+ nestedBuilders_appendBuilderItself();
+ nestedBuilders_appendBuilderResult();
+ simplePhi();
+ loop();
+ loopWithBuilder();
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/ir/regalloc/IdenticalAfterRegisterAllocationTest.java b/src/test/java/com/android/tools/r8/ir/regalloc/IdenticalAfterRegisterAllocationTest.java
index 12d0a78..d5a89c8 100644
--- a/src/test/java/com/android/tools/r8/ir/regalloc/IdenticalAfterRegisterAllocationTest.java
+++ b/src/test/java/com/android/tools/r8/ir/regalloc/IdenticalAfterRegisterAllocationTest.java
@@ -41,7 +41,7 @@
}
@Override
- public InternalOptions getOptions() {
+ public InternalOptions options() {
return new InternalOptions();
}
diff --git a/src/test/java/com/android/tools/r8/ir/regalloc/Regress68656641.java b/src/test/java/com/android/tools/r8/ir/regalloc/Regress68656641.java
index a0e937d..e9836ae 100644
--- a/src/test/java/com/android/tools/r8/ir/regalloc/Regress68656641.java
+++ b/src/test/java/com/android/tools/r8/ir/regalloc/Regress68656641.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.ir.regalloc;
import com.android.tools.r8.graph.AppInfo;
+import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
import com.android.tools.r8.ir.code.IRCode;
@@ -21,8 +22,8 @@
public class Regress68656641 extends SmaliTestBase {
private static class MyRegisterAllocator extends LinearScanRegisterAllocator {
- public MyRegisterAllocator(AppInfo appInfo, IRCode code, InternalOptions options) {
- super(appInfo, code, options);
+ public MyRegisterAllocator(AppView<? extends AppInfo> appView, IRCode code) {
+ super(appView, code);
}
public void addInactiveIntervals(LiveIntervals intervals) {
@@ -56,8 +57,9 @@
public void splitOverlappingInactiveIntervalWithNoNextUse() {
InternalOptions options = new InternalOptions();
AppInfo appInfo = new AppInfo(DexApplication.builder(options.itemFactory, null).build());
+ AppView<? extends AppInfo> appView = AppView.createForD8(appInfo, options);
IRCode code = simpleCode();
- MyRegisterAllocator allocator = new MyRegisterAllocator(appInfo, code, options);
+ MyRegisterAllocator allocator = new MyRegisterAllocator(appView, code);
// Setup live an inactive live interval with ranges [0, 10[ and [20, 30[ with only
// uses in the first interval and which is linked to another interval.
LiveIntervals inactiveIntervals =
diff --git a/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java b/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
index 483b02e..5d4f802 100644
--- a/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
+++ b/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
@@ -752,8 +752,9 @@
DexAnnotationSet.empty(),
ParameterAnnotationsList.empty(),
code);
- IRCode ir = code.buildIR(method, AppView.createForR8(null, options), Origin.unknown());
- RegisterAllocator allocator = new LinearScanRegisterAllocator(appInfo, ir, options);
+ AppView<? extends AppInfo> appView = AppView.createForR8(null, options);
+ IRCode ir = code.buildIR(method, appView, Origin.unknown());
+ RegisterAllocator allocator = new LinearScanRegisterAllocator(appView, ir);
method.setCode(ir, allocator, options);
directMethods[i] = method;
}
diff --git a/src/test/java/com/android/tools/r8/naming/FieldMinificationCollisionTest.java b/src/test/java/com/android/tools/r8/naming/FieldMinificationCollisionTest.java
new file mode 100644
index 0000000..1727bd6
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/naming/FieldMinificationCollisionTest.java
@@ -0,0 +1,92 @@
+// Copyright (c) 2019, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.naming;
+
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+
+import com.android.tools.r8.NeverClassInline;
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.android.tools.r8.utils.codeinspector.FieldSubject;
+import org.junit.Test;
+
+/** Regression test for b/127932803. */
+public class FieldMinificationCollisionTest extends TestBase {
+
+ @Test
+ public void test() throws Exception {
+ String expectedOutput = StringUtils.lines("ABC");
+ CodeInspector inspector =
+ testForR8(Backend.DEX)
+ .addInnerClasses(FieldMinificationCollisionTest.class)
+ .addKeepMainRule(TestClass.class)
+ .addKeepRules(
+ "-keep class " + B.class.getTypeName() + " { public java.lang.String f2; }")
+ .enableClassInliningAnnotations()
+ .enableInliningAnnotations()
+ .enableMergeAnnotations()
+ .run(TestClass.class)
+ .assertSuccessWithOutput(expectedOutput)
+ .inspector();
+
+ FieldSubject f1Subject = inspector.clazz(A.class).uniqueFieldWithName("f1");
+ assertThat(f1Subject, isPresent());
+
+ FieldSubject f3Subject = inspector.clazz(C.class).uniqueFieldWithName("f3");
+ assertThat(f3Subject, isPresent());
+
+ // TODO(b/127932803): f1 and f3 should not be given the same name.
+ assertEquals(f1Subject.getFinalName(), f3Subject.getFinalName());
+ }
+
+ static class TestClass {
+
+ public static void main(String[] args) {
+ new C("A", "B", "C").print();
+ }
+ }
+
+ @NeverMerge
+ static class A {
+
+ public String f1;
+
+ public A(String f1) {
+ this.f1 = f1;
+ }
+ }
+
+ @NeverMerge
+ static class B extends A {
+
+ public String f2;
+
+ public B(String f1, String f2) {
+ super(f1);
+ this.f2 = f2;
+ }
+ }
+
+ @NeverClassInline
+ static class C extends B {
+
+ public String f3;
+
+ public C(String f1, String f2, String f3) {
+ super(f1, f2);
+ this.f3 = f3;
+ }
+
+ @NeverInline
+ public void print() {
+ System.out.println(f1 + f2 + f3);
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/naming/NamingTestBase.java b/src/test/java/com/android/tools/r8/naming/NamingTestBase.java
index 93e4a4f..6b7005c 100644
--- a/src/test/java/com/android/tools/r8/naming/NamingTestBase.java
+++ b/src/test/java/com/android/tools/r8/naming/NamingTestBase.java
@@ -74,8 +74,7 @@
AppView.createForR8(new AppInfoWithSubtyping(program), options);
appView.setAppServices(AppServices.builder(appView).build());
- RootSet rootSet =
- new RootSetBuilder(appView, program, configuration.getRules(), options).run(executor);
+ RootSet rootSet = new RootSetBuilder(appView, program, configuration.getRules()).run(executor);
Enqueuer enqueuer = new Enqueuer(appView, options, null);
appView.setAppInfo(
diff --git a/src/test/java/com/android/tools/r8/resolution/SingleTargetLookupTest.java b/src/test/java/com/android/tools/r8/resolution/SingleTargetLookupTest.java
index 766d8de..6d71487 100644
--- a/src/test/java/com/android/tools/r8/resolution/SingleTargetLookupTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/SingleTargetLookupTest.java
@@ -111,10 +111,7 @@
ExecutorService executor = Executors.newSingleThreadExecutor();
RootSet rootSet =
new RootSetBuilder(
- appView,
- application,
- buildKeepRuleForClass(Main.class, application.dexItemFactory),
- options)
+ appView, application, buildKeepRuleForClass(Main.class, application.dexItemFactory))
.run(executor);
appInfo =
new Enqueuer(appView, options, null)
@@ -203,15 +200,17 @@
}
private static DexMethod buildMethod(Class clazz, String name) {
- return appInfo.dexItemFactory.createMethod(
- toType(clazz),
- appInfo.dexItemFactory.createProto(appInfo.dexItemFactory.voidType),
- name
- );
+ return appInfo
+ .dexItemFactory()
+ .createMethod(
+ toType(clazz),
+ appInfo.dexItemFactory().createProto(appInfo.dexItemFactory().voidType),
+ name);
}
private static DexType toType(Class clazz) {
- return appInfo.dexItemFactory
+ return appInfo
+ .dexItemFactory()
.createType(DescriptorUtils.javaTypeToDescriptor(clazz.getCanonicalName()));
}
diff --git a/tools/archive.py b/tools/archive.py
index 25e6a4f..9213cc2 100755
--- a/tools/archive.py
+++ b/tools/archive.py
@@ -138,7 +138,7 @@
version = GetGitHash()
destination = GetVersionDestination('gs://', version, is_master)
- if utils.cloud_storage_exists(destination):
+ if utils.cloud_storage_exists(destination) and not options.dry_run:
raise Exception('Target archive directory %s already exists' % destination)
with utils.TempDir() as temp:
version_file = os.path.join(temp, 'r8-version.properties')
diff --git a/tools/as_utils.py b/tools/as_utils.py
index a5bfffe..83d0d15 100644
--- a/tools/as_utils.py
+++ b/tools/as_utils.py
@@ -171,12 +171,13 @@
def MoveProfileReportTo(dest_dir, build_stdout, quiet=False):
html_file = None
profile_message = 'See the profiling report at: '
+ # We are not interested in the profiling report for buildSrc.
for line in build_stdout:
- if profile_message in line:
+ if (profile_message in line) and ('buildSrc' not in line):
+ assert not html_file, "Only one report should be created"
html_file = line[len(profile_message):]
if html_file.startswith('file://'):
html_file = html_file[len('file://'):]
- break
if not html_file:
return
diff --git a/tools/run_on_as_app.py b/tools/run_on_as_app.py
index 425b84a..5596cd5 100755
--- a/tools/run_on_as_app.py
+++ b/tools/run_on_as_app.py
@@ -250,7 +250,6 @@
'module': '',
'flavor': 'play',
'main_dex_rules': 'multidex-config.pro',
- 'releaseTarget': 'assemblePlayRelease',
'signed_apk_name': 'Signal-play-release-4.32.7.apk'
})
]
@@ -287,8 +286,7 @@
'apps': [
App({
'id': 'eu.kanade.tachiyomi',
- 'flavor': 'standard',
- 'releaseTarget': 'app:assembleRelease',
+ 'flavor': 'dev',
'min_sdk': 16
})
]
@@ -680,8 +678,7 @@
app, repo, options, checkout_dir, temp_dir, shrinker, proguard_config_file):
recompilation_results = []
- # Build app with gradle using -D...keepRuleSynthesisForRecompilation=
- # true.
+ # Build app with gradle using -D...keepRuleSynthesisForRecompilation=true.
out_dir = os.path.join(checkout_dir, 'out', shrinker + '-1')
(apk_dest, profile_dest_dir, ext_proguard_config_file) = \
BuildAppWithShrinker(
@@ -1072,10 +1069,10 @@
else:
# Make a copy of r8.jar and r8lib.jar such that they stay the same for
# the entire execution of this script.
- if 'r8-nolib' in options.shrinker:
+ if 'r8-nolib' in options.shrinker or 'r8-nolib-full' in options.shrinker:
assert os.path.isfile(utils.R8_JAR), 'Cannot build without r8.jar'
shutil.copyfile(utils.R8_JAR, os.path.join(temp_dir, 'r8.jar'))
- if 'r8' in options.shrinker:
+ if 'r8' in options.shrinker or 'r8-full' in options.shrinker:
assert os.path.isfile(utils.R8LIB_JAR), 'Cannot build without r8lib.jar'
shutil.copyfile(utils.R8LIB_JAR, os.path.join(temp_dir, 'r8lib.jar'))