Merge "Make sure all golem-dependent dex-segments are reported"
diff --git a/build.gradle b/build.gradle
index a38fd63..f492319 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1597,18 +1597,17 @@
if (project.hasProperty('tool')) {
if (project.property('tool') == 'r8') {
exclude "com/android/tools/r8/art/*/d8/**"
- exclude "com/android/tools/r8/jctf/d8/**"
- exclude "com/android/tools/r8/jctf/r8cf/**"
+ exclude "com/android/tools/r8/jctf/**"
} else if (project.property('tool') == 'd8') {
- exclude "com/android/tools/r8/art/*/r8/**"
- exclude "com/android/tools/r8/jctf/r8/**"
- exclude "com/android/tools/r8/jctf/r8cf/**"
+ if (project.hasProperty('only_jctf')) {
+ include "com/android/tools/r8/jctf/d8/**"
+ } else {
+ include "com/android/tools/r8/art/*/d8/**"
+ }
} else {
assert(project.property('tool') == 'r8cf')
- exclude "com/android/tools/r8/art/*/d8/**"
- exclude "com/android/tools/r8/art/*/r8/**"
- exclude "com/android/tools/r8/jctf/d8/**"
- exclude "com/android/tools/r8/jctf/r8/**"
+ assert(project.hasProperty('only_jctf'))
+ include "com/android/tools/r8/jctf/r8cf/**"
}
}
if (!project.hasProperty('all_tests')) {
@@ -1617,9 +1616,6 @@
if (!project.hasProperty('jctf') && !project.hasProperty('only_jctf')) {
exclude "com/android/tools/r8/jctf/**"
}
- if (project.hasProperty('only_jctf')) {
- include "com/android/tools/r8/jctf/**"
- }
if (project.hasProperty('shard_count') ) {
assert project.hasProperty('shard_number')
int shard_count = project.getProperty('shard_count') as Integer
diff --git a/infra/config/global/cr-buildbucket.cfg b/infra/config/global/cr-buildbucket.cfg
index 1040635..a38e3bf 100644
--- a/infra/config/global/cr-buildbucket.cfg
+++ b/infra/config/global/cr-buildbucket.cfg
@@ -45,6 +45,11 @@
}
}
+builder_mixins {
+ name: "fast_bot"
+ execution_timeout_secs: 5400 # 1.5 hours
+}
+
acl_sets {
name: "ci"
acls {
@@ -122,6 +127,7 @@
name: "d8-linux"
mixins: "linux"
mixins: "normal"
+ mixins: "fast_bot"
recipe {
properties: "tool:d8"
properties: "aosp_jar:True"
@@ -131,6 +137,7 @@
name: "d8-linux-android-4.0.4"
mixins: "linux"
mixins: "normal"
+ mixins: "fast_bot"
recipe {
properties: "tool:d8"
properties: "dex_vm:4.0.4"
@@ -149,6 +156,7 @@
name: "d8-linux-android-4.4.4"
mixins: "linux"
mixins: "normal"
+ mixins: "fast_bot"
recipe {
properties: "tool:d8"
properties: "dex_vm:4.4.4"
@@ -167,6 +175,7 @@
name: "d8-linux-android-5.1.1"
mixins: "linux"
mixins: "normal"
+ mixins: "fast_bot"
recipe {
properties: "tool:d8"
properties: "dex_vm:5.1.1"
@@ -185,6 +194,7 @@
name: "d8-linux-android-6.0.1"
mixins: "linux"
mixins: "normal"
+ mixins: "fast_bot"
recipe {
properties: "tool:d8"
properties: "dex_vm:6.0.1"
@@ -203,6 +213,7 @@
name: "d8-linux-android-7.0.0"
mixins: "linux"
mixins: "normal"
+ mixins: "fast_bot"
recipe {
properties: "tool:d8"
properties: "dex_vm:7.0.0"
@@ -218,29 +229,6 @@
}
}
builders {
- name: "d8-linux-jctf"
- mixins: "linux"
- mixins: "jctf"
- execution_timeout_secs: 43200 # 12h
- recipe {
- properties: "tool:d8"
- properties: "dex_vm:all"
- properties: "only_jctf:True"
- }
- }
- builders {
- name: "d8-linux-jctf_release"
- mixins: "linux"
- mixins: "jctf"
- dimensions: "jctf:true"
- execution_timeout_secs: 43200 # 12h
- recipe {
- properties: "tool:d8"
- properties: "dex_vm:all"
- properties: "only_jctf:True"
- }
- }
- builders {
name: "d8-linux_release"
mixins: "linux"
mixins: "normal"
@@ -376,7 +364,7 @@
mixins: "jctf"
execution_timeout_secs: 43200 # 12h
recipe {
- properties: "tool:r8"
+ properties: "tool:d8"
properties: "dex_vm:all"
properties: "only_jctf:True"
}
@@ -387,7 +375,7 @@
mixins: "jctf"
execution_timeout_secs: 43200 # 12h
recipe {
- properties: "tool:r8"
+ properties: "tool:d8"
properties: "dex_vm:all"
properties: "only_jctf:True"
}
diff --git a/infra/config/global/luci-milo.cfg b/infra/config/global/luci-milo.cfg
index 8dc59cb..1a3ae77 100644
--- a/infra/config/global/luci-milo.cfg
+++ b/infra/config/global/luci-milo.cfg
@@ -87,11 +87,6 @@
short_name: "7.0.0"
}
builders {
- name: "buildbucket/luci.r8.ci/d8-linux-jctf"
- category: "D8"
- short_name: "jctf"
- }
- builders {
name: "buildbucket/luci.r8.ci/windows"
category: "win"
short_name: "win"
@@ -180,11 +175,6 @@
category: "D8"
short_name: "7.0.0"
}
- builders {
- name: "buildbucket/luci.r8.ci/d8-linux-jctf_release"
- category: "D8"
- short_name: "jctf"
- }
# TODO(ricow): Windows on the release branches currently do not work
# There is no java available.
# builders {
@@ -282,11 +272,6 @@
short_name: "7.0.0"
}
builders {
- name: "buildbucket/luci.r8.ci/d8-linux-jctf"
- category: "D8"
- short_name: "jctf"
- }
- builders {
name: "buildbucket/luci.r8.ci/windows"
category: "win"
short_name: "win"
@@ -366,9 +351,4 @@
category: "D8 release"
short_name: "7.0.0"
}
- builders {
- name: "buildbucket/luci.r8.ci/d8-linux-jctf_release"
- category: "D8 release"
- short_name: "jctf"
- }
}
diff --git a/infra/config/global/luci-notify.cfg b/infra/config/global/luci-notify.cfg
index c7f9ec7..bb27c81 100644
--- a/infra/config/global/luci-notify.cfg
+++ b/infra/config/global/luci-notify.cfg
@@ -83,16 +83,6 @@
repository: "https://r8.googlesource.com/r8"
}
builders {
- name: "d8-linux-jctf"
- bucket: "ci"
- repository: "https://r8.googlesource.com/r8"
- }
- builders {
- name: "d8-linux-jctf_release"
- bucket: "ci"
- repository: "https://r8.googlesource.com/r8"
- }
- builders {
name: "d8-linux_release"
bucket: "ci"
repository: "https://r8.googlesource.com/r8"
diff --git a/infra/config/global/luci-scheduler.cfg b/infra/config/global/luci-scheduler.cfg
index f7e4493..dca0298 100644
--- a/infra/config/global/luci-scheduler.cfg
+++ b/infra/config/global/luci-scheduler.cfg
@@ -31,7 +31,6 @@
triggers: "d8-linux-android-5.1.1"
triggers: "d8-linux-android-6.0.1"
triggers: "d8-linux-android-7.0.0"
- triggers: "d8-linux-jctf"
triggers: "linux"
triggers: "linux"
triggers: "linux-android-4.0.4"
@@ -58,7 +57,6 @@
triggers: "d8-linux-android-5.1.1_release"
triggers: "d8-linux-android-6.0.1_release"
triggers: "d8-linux-android-7.0.0_release"
- triggers: "d8-linux-jctf_release"
triggers: "d8-linux_release"
triggers: "linux-android-4.0.4_release"
triggers: "linux-android-4.4.4_release"
@@ -215,26 +213,6 @@
}
job {
- id: "d8-linux-jctf"
- acl_sets: "default"
- buildbucket {
- server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
- builder: "d8-linux-jctf"
- }
-}
-
-job {
- id: "d8-linux-jctf_release"
- acl_sets: "default"
- buildbucket {
- server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
- builder: "d8-linux-jctf_release"
- }
-}
-
-job {
id: "d8-linux_release"
acl_sets: "default"
buildbucket {
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index af3c140..535eb25 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -339,8 +339,7 @@
proguardSeedsData = bytes.toString();
}
if (options.enableTreeShaking) {
- TreePruner pruner =
- new TreePruner(application, appView.appInfo().withLiveness(), options);
+ TreePruner pruner = new TreePruner(application, appView.withLiveness());
application = pruner.run();
// Recompute the subtyping information.
@@ -355,11 +354,7 @@
classesToRetainInnerClassAttributeFor =
AnnotationRemover.computeClassesToRetainInnerClassAttributeFor(
appView.appInfo().withLiveness(), options);
- new AnnotationRemover(
- appView.appInfo().withLiveness(),
- appView.graphLense(),
- options,
- classesToRetainInnerClassAttributeFor)
+ new AnnotationRemover(appView.withLiveness(), classesToRetainInnerClassAttributeFor)
.ensureValid(compatibility)
.run();
@@ -579,7 +574,7 @@
AppView<AppInfoWithLiveness> appViewWithLiveness = appView.withLiveness();
if (options.enableTreeShaking) {
- TreePruner pruner = new TreePruner(application, appViewWithLiveness.appInfo(), options);
+ TreePruner pruner = new TreePruner(application, appViewWithLiveness);
application = pruner.run();
appViewWithLiveness.setAppInfo(
appViewWithLiveness
@@ -597,11 +592,7 @@
}
// Remove annotations that refer to types that no longer exist.
assert classesToRetainInnerClassAttributeFor != null;
- new AnnotationRemover(
- appView.appInfo().withLiveness(),
- appView.graphLense(),
- options,
- classesToRetainInnerClassAttributeFor)
+ new AnnotationRemover(appView.withLiveness(), classesToRetainInnerClassAttributeFor)
.run();
if (!mainDexClasses.isEmpty()) {
// Remove types that no longer exists from the computed main dex list.
diff --git a/src/main/java/com/android/tools/r8/Version.java b/src/main/java/com/android/tools/r8/Version.java
index 1cda441..45deb7f 100644
--- a/src/main/java/com/android/tools/r8/Version.java
+++ b/src/main/java/com/android/tools/r8/Version.java
@@ -11,7 +11,7 @@
// This field is accessed from release scripts using simple pattern matching.
// Therefore, changing this field could break our release scripts.
- public static final String LABEL = "1.5.11-dev";
+ public static final String LABEL = "1.5.12-dev";
private Version() {
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
index 057090e..9546590 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -628,7 +628,7 @@
return builder.build();
}
- public DexEncodedMethod toForwardingMethod(DexClass holder, AppInfo appInfo) {
+ public DexEncodedMethod toForwardingMethod(DexClass holder, DexDefinitionSupplier definitions) {
checkIfObsolete();
// Clear the final flag, as this method is now overwritten. Do this before creating the builder
// for the forwarding method, as the forwarding method will copy the access flags from this,
@@ -636,7 +636,7 @@
// final.
accessFlags.demoteFromFinal();
DexMethod newMethod =
- appInfo.dexItemFactory.createMethod(holder.type, method.proto, method.name);
+ definitions.dexItemFactory().createMethod(holder.type, method.proto, method.name);
Invoke.Type type = accessFlags.isStatic() ? Invoke.Type.STATIC : Invoke.Type.SUPER;
Builder builder = builder(this);
builder.setMethod(newMethod);
@@ -646,7 +646,7 @@
builder.accessFlags.setAbstract();
} else {
// Create code that forwards the call to the target.
- DexClass target = appInfo.definitionFor(method.holder);
+ DexClass target = definitions.definitionFor(method.holder);
builder.setCode(
new SynthesizedCode(
callerPosition ->
diff --git a/src/main/java/com/android/tools/r8/graph/GraphLense.java b/src/main/java/com/android/tools/r8/graph/GraphLense.java
index 5dd36c6..95ba121 100644
--- a/src/main/java/com/android/tools/r8/graph/GraphLense.java
+++ b/src/main/java/com/android/tools/r8/graph/GraphLense.java
@@ -939,14 +939,17 @@
* <p>Handle methods moved from interface to class or class to interface.
*/
protected final Type mapVirtualInterfaceInvocationTypes(
- AppInfo appInfo, DexMethod newMethod, DexMethod originalMethod, Type type) {
+ DexDefinitionSupplier definitions,
+ DexMethod newMethod,
+ DexMethod originalMethod,
+ Type type) {
if (type == Type.VIRTUAL || type == Type.INTERFACE) {
// Get the invoke type of the actual definition.
- DexClass newTargetClass = appInfo.definitionFor(newMethod.holder);
+ DexClass newTargetClass = definitions.definitionFor(newMethod.holder);
if (newTargetClass == null) {
return type;
}
- DexClass originalTargetClass = appInfo.definitionFor(originalMethod.holder);
+ DexClass originalTargetClass = definitions.definitionFor(originalMethod.holder);
if (originalTargetClass != null
&& (originalTargetClass.isInterface() ^ (type == Type.INTERFACE))) {
// The invoke was wrong to start with, so we keep it wrong. This is to ensure we get
diff --git a/src/main/java/com/android/tools/r8/naming/ClassNameMinifier.java b/src/main/java/com/android/tools/r8/naming/ClassNameMinifier.java
index 92c07d1..f6aaf96 100644
--- a/src/main/java/com/android/tools/r8/naming/ClassNameMinifier.java
+++ b/src/main/java/com/android/tools/r8/naming/ClassNameMinifier.java
@@ -40,7 +40,6 @@
class ClassNameMinifier {
private final AppView<AppInfoWithLiveness> appView;
- private final AppInfoWithLiveness appInfo;
private final ClassNamingStrategy classNamingStrategy;
private final PackageNamingStrategy packageNamingStrategy;
private final Iterable<? extends DexClass> classes;
@@ -68,7 +67,6 @@
PackageNamingStrategy packageNamingStrategy,
Iterable<? extends DexClass> classes) {
this.appView = appView;
- this.appInfo = appView.appInfo();
this.classNamingStrategy = classNamingStrategy;
this.packageNamingStrategy = packageNamingStrategy;
this.classes = classes;
@@ -136,7 +134,7 @@
timing.end();
timing.begin("rename-arrays");
- appInfo.dexItemFactory.forAllTypes(this::renameArrayTypeIfNeeded);
+ appView.dexItemFactory().forAllTypes(this::renameArrayTypeIfNeeded);
timing.end();
return new ClassRenaming(Collections.unmodifiableMap(renaming), getPackageRenaming());
@@ -172,13 +170,13 @@
}
private void renameDanglingType(DexType type) {
- if (appInfo.wasPruned(type)
+ if (appView.appInfo().wasPruned(type)
&& !renaming.containsKey(type)
&& !noObfuscationTypes.contains(type)) {
// We have a type that is defined in the program source but is only used in a proto or
// return type. As we don't need the class, we can rename it to anything as long as it is
// unique.
- assert appInfo.definitionFor(type) == null;
+ assert appView.definitionFor(type) == null;
renaming.put(type, topLevelState.nextTypeName(type));
}
}
@@ -217,7 +215,7 @@
}
private DexType getOutClassForType(DexType type) {
- DexClass clazz = appInfo.definitionFor(type);
+ DexClass clazz = appView.definitionFor(type);
if (clazz == null) {
return null;
}
@@ -333,7 +331,7 @@
private void renameArrayTypeIfNeeded(DexType type) {
if (type.isArrayType()) {
- DexType base = type.toBaseType(appInfo.dexItemFactory);
+ DexType base = type.toBaseType(appView.dexItemFactory());
DexString value = renaming.get(base);
if (value != null) {
int dimensions = type.descriptor.numberOfLeadingSquareBrackets();
@@ -342,7 +340,7 @@
builder.append('[');
}
builder.append(value.toString());
- DexString descriptor = appInfo.dexItemFactory.createString(builder.toString());
+ DexString descriptor = appView.dexItemFactory().createString(builder.toString());
renaming.put(type, descriptor);
}
}
@@ -371,7 +369,7 @@
// R.class in Android, which contains constant IDs to assets, can be bundled at any time.
// Insert `R` immediately so that the class name minifier can skip that name by default.
StringBuilder rBuilder = new StringBuilder().append(packagePrefix).append("R;");
- usedTypeNames.add(appInfo.dexItemFactory.createString(rBuilder.toString()));
+ usedTypeNames.add(appView.dexItemFactory().createString(rBuilder.toString()));
}
public String getPackageName() {
@@ -382,7 +380,7 @@
StringBuilder nextName = new StringBuilder();
if (!classNamingStrategy.bypassDictionary() && classDictionaryIterator.hasNext()) {
nextName.append(packagePrefix).append(classDictionaryIterator.next()).append(';');
- return appInfo.dexItemFactory.createString(nextName.toString());
+ return appView.dexItemFactory().createString(nextName.toString());
} else {
return classNamingStrategy.next(this, type, packagePrefix);
}
@@ -450,6 +448,7 @@
}
private boolean isNotKotlinMetadata(DexAnnotation annotation) {
- return annotation.annotation.type != appInfo.dexItemFactory.kotlin.metadata.kotlinMetadataType;
+ return annotation.annotation.type
+ != appView.dexItemFactory().kotlin.metadata.kotlinMetadataType;
}
}
diff --git a/src/main/java/com/android/tools/r8/naming/FieldNameMinifier.java b/src/main/java/com/android/tools/r8/naming/FieldNameMinifier.java
index 96bba7a..def7262 100644
--- a/src/main/java/com/android/tools/r8/naming/FieldNameMinifier.java
+++ b/src/main/java/com/android/tools/r8/naming/FieldNameMinifier.java
@@ -14,7 +14,9 @@
import com.android.tools.r8.utils.Timing;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Sets;
+import java.io.PrintStream;
import java.util.Map;
+import java.util.Set;
import java.util.function.Function;
class FieldNameMinifier extends MemberNameMinifier<DexField, DexType> {
@@ -41,17 +43,17 @@
// dispatch in Java, field resolution still traverses the super type chain and external
// code might use a subtype to reference the field.
timing.begin("reserve-classes");
- reserveNamesInSubtypes(appInfo.dexItemFactory.objectType, globalState);
+ reserveNamesInSubtypes(appView.dexItemFactory().objectType, globalState);
timing.end();
// Next, reserve field names in interfaces. These should only be static.
timing.begin("reserve-interfaces");
- DexType.forAllInterfaces(appInfo.dexItemFactory,
- iface -> reserveNamesInSubtypes(iface, globalState));
+ DexType.forAllInterfaces(
+ appView.dexItemFactory(), iface -> reserveNamesInSubtypes(iface, globalState));
timing.end();
// Rename the definitions.
timing.begin("rename-definitions");
- renameFieldsInSubtypes(appInfo.dexItemFactory.objectType);
- DexType.forAllInterfaces(appInfo.dexItemFactory, this::renameFieldsInSubtypes);
+ renameFieldsInClasses();
+ renameFieldsInInterfaces();
timing.end();
// Rename the references that are not rebound to definitions for some reasons.
timing.begin("rename-references");
@@ -74,7 +76,7 @@
}
private void reserveNamesInSubtypes(DexType type, NamingState<DexType, ?> state) {
- DexClass holder = appInfo.definitionFor(type);
+ DexClass holder = appView.definitionFor(type);
if (holder == null) {
return;
}
@@ -94,19 +96,57 @@
}
}
- private void renameFieldsInSubtypes(DexType type) {
- DexClass clazz = appInfo.definitionFor(type);
+ private void renameFieldsInClasses() {
+ renameFieldsInSubclasses(appView.dexItemFactory().objectType, null);
+ }
+
+ private void renameFieldsInSubclasses(DexType type, DexType parent) {
+ DexClass clazz = appView.definitionFor(type);
if (clazz == null) {
return;
}
+ assert !clazz.isInterface();
+ assert clazz.superType == parent;
+
NamingState<DexType, ?> state = minifierState.getState(clazz.type);
assert state != null;
- clazz.forEachField(field -> renameField(field, state));
- type.forAllExtendsSubtypes(this::renameFieldsInSubtypes);
+ for (DexEncodedField field : clazz.fields()) {
+ renameField(field, state);
+ }
+ for (DexType subclass : type.allExtendsSubtypes()) {
+ renameFieldsInSubclasses(subclass, type);
+ }
+ }
+
+ private void renameFieldsInInterfaces() {
+ for (DexType interfaceType : DexType.allInterfaces(appView.dexItemFactory())) {
+ renameFieldsInInterface(interfaceType);
+ }
+ }
+
+ private void renameFieldsInInterface(DexType type) {
+ DexClass clazz = appView.definitionFor(type);
+ if (clazz == null) {
+ return;
+ }
+ assert clazz.isInterface();
+ NamingState<DexType, ?> state = minifierState.getState(clazz.type);
+ assert state != null;
+ for (DexEncodedField field : clazz.fields()) {
+ renameField(field, state);
+ }
}
private void renameField(DexEncodedField encodedField, NamingState<DexType, ?> state) {
DexField field = encodedField.field;
+
+ Set<String> loggingFilter = appView.options().extensiveFieldMinifierLoggingFilter;
+ if (!loggingFilter.isEmpty()) {
+ if (loggingFilter.contains(field.toSourceString())) {
+ print(field, state, System.out);
+ }
+ }
+
if (!state.isReserved(field.name, field.type)) {
renaming.put(
field, state.assignNewNameFor(field, field.name, field.type, useUniqueMemberNames));
@@ -115,6 +155,7 @@
private void renameNonReboundReferences() {
// TODO(b/123068484): Collect non-rebound references instead of visiting all references.
+ AppInfoWithLiveness appInfo = appView.appInfo();
Sets.union(
Sets.union(appInfo.staticFieldReads.keySet(), appInfo.staticFieldWrites.keySet()),
Sets.union(appInfo.instanceFieldReads.keySet(), appInfo.instanceFieldWrites.keySet()))
@@ -126,18 +167,18 @@
if (renaming.containsKey(field)) {
return;
}
- DexEncodedField definition = appInfo.definitionFor(field);
+ DexEncodedField definition = appView.definitionFor(field);
if (definition != null) {
assert definition.field == field;
return;
}
// Now, `field` is reference. Find its definition and check if it's renamed.
- DexClass holder = appInfo.definitionFor(field.holder);
+ DexClass holder = appView.definitionFor(field.holder);
// We don't care pruned types or library classes.
if (holder == null || holder.isLibraryClass()) {
return;
}
- definition = appInfo.resolveField(field);
+ definition = appView.appInfo().resolveField(field);
if (definition == null) {
// The program is already broken in the sense that it has an unresolvable field reference.
// Leave it as-is.
@@ -151,4 +192,12 @@
renaming.put(field, renaming.get(definition.field));
}
}
+
+ private void print(DexField field, NamingState<DexType, ?> state, PrintStream out) {
+ out.println("--------------------------------------------------------------------------------");
+ out.println("FieldNameMinifier(`" + field.toSourceString() + "`)");
+ out.println("--------------------------------------------------------------------------------");
+ state.printState(field.type, minifierState::getStateKey, "", out);
+ out.println();
+ }
}
diff --git a/src/main/java/com/android/tools/r8/naming/IdentifierMinifier.java b/src/main/java/com/android/tools/r8/naming/IdentifierMinifier.java
index 35c5147..d6053e3 100644
--- a/src/main/java/com/android/tools/r8/naming/IdentifierMinifier.java
+++ b/src/main/java/com/android/tools/r8/naming/IdentifierMinifier.java
@@ -12,6 +12,7 @@
import com.android.tools.r8.code.ConstString;
import com.android.tools.r8.code.DexItemBasedConstString;
import com.android.tools.r8.code.Instruction;
+import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.Code;
import com.android.tools.r8.graph.DexEncodedField;
import com.android.tools.r8.graph.DexEncodedMethod;
@@ -33,14 +34,13 @@
*/
class IdentifierMinifier {
- private final AppInfoWithLiveness appInfo;
+ private final AppView<AppInfoWithLiveness> appView;
private final ProguardClassFilter adaptClassStrings;
private final NamingLens lens;
- IdentifierMinifier(
- AppInfoWithLiveness appInfo, ProguardClassFilter adaptClassStrings, NamingLens lens) {
- this.appInfo = appInfo;
- this.adaptClassStrings = adaptClassStrings;
+ IdentifierMinifier(AppView<AppInfoWithLiveness> appView, NamingLens lens) {
+ this.appView = appView;
+ this.adaptClassStrings = appView.options().getProguardConfiguration().getAdaptClassStrings();
this.lens = lens;
}
@@ -52,7 +52,7 @@
}
private void adaptClassStrings() {
- for (DexProgramClass clazz : appInfo.classes()) {
+ for (DexProgramClass clazz : appView.appInfo().classes()) {
if (adaptClassStrings.matches(clazz.type)) {
for (DexEncodedField field : clazz.staticFields()) {
adaptClassStringsInStaticField(field);
@@ -110,14 +110,14 @@
DexString renamed = lens.lookupDescriptor(type);
// Create a new DexString only when the corresponding string literal will be replaced.
if (renamed != originalLiteral) {
- return appInfo.dexItemFactory.createString(descriptorToJavaType(renamed.toString()));
+ return appView.dexItemFactory().createString(descriptorToJavaType(renamed.toString()));
}
}
return originalLiteral;
}
private void replaceDexItemBasedConstString() {
- for (DexProgramClass clazz : appInfo.classes()) {
+ for (DexProgramClass clazz : appView.appInfo().classes()) {
// Some const strings could be moved to field's static value (from <clinit>).
for (DexEncodedField field : clazz.staticFields()) {
replaceDexItemBasedConstStringInStaticField(field);
@@ -136,10 +136,10 @@
dexItemBasedValueString.getClassNameComputationInfo().needsToComputeClassName()
? computeClassName(
lens.lookupDescriptor(original.asDexType()),
- appInfo.definitionFor(original.asDexType()),
+ appView.definitionFor(original.asDexType()),
dexItemBasedValueString.getClassNameComputationInfo(),
- appInfo.dexItemFactory)
- : lens.lookupName(original, appInfo.dexItemFactory);
+ appView.dexItemFactory())
+ : lens.lookupName(original, appView.dexItemFactory());
encodedField.setStaticValue(new DexValueString(replacement));
}
}
@@ -166,10 +166,10 @@
cnst.getClassNameComputationInfo().needsToComputeClassName()
? computeClassName(
lens.lookupDescriptor(cnst.getItem().asDexType()),
- appInfo.definitionFor(cnst.getItem().asDexType()),
+ appView.definitionFor(cnst.getItem().asDexType()),
cnst.getClassNameComputationInfo(),
- appInfo.dexItemFactory)
- : lens.lookupName(cnst.getItem(), appInfo.dexItemFactory);
+ appView.dexItemFactory())
+ : lens.lookupName(cnst.getItem(), appView.dexItemFactory());
ConstString constString = new ConstString(cnst.AA, replacement);
constString.setOffset(instruction.getOffset());
instructions[i] = constString;
@@ -186,10 +186,10 @@
cnst.getClassNameComputationInfo().needsToComputeClassName()
? computeClassName(
lens.lookupDescriptor(cnst.getItem().asDexType()),
- appInfo.definitionFor(cnst.getItem().asDexType()),
+ appView.definitionFor(cnst.getItem().asDexType()),
cnst.getClassNameComputationInfo(),
- appInfo.dexItemFactory)
- : lens.lookupName(cnst.getItem(), appInfo.dexItemFactory);
+ appView.dexItemFactory())
+ : lens.lookupName(cnst.getItem(), appView.dexItemFactory());
instructions.set(i, new CfConstString(replacement));
}
}
diff --git a/src/main/java/com/android/tools/r8/naming/InterfaceMethodNameMinifier.java b/src/main/java/com/android/tools/r8/naming/InterfaceMethodNameMinifier.java
index 6c46119..9b55542 100644
--- a/src/main/java/com/android/tools/r8/naming/InterfaceMethodNameMinifier.java
+++ b/src/main/java/com/android/tools/r8/naming/InterfaceMethodNameMinifier.java
@@ -5,6 +5,7 @@
import static com.android.tools.r8.naming.MethodNameMinifier.shuffleMethods;
+import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexCallSite;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexEncodedMethod;
@@ -15,7 +16,6 @@
import com.android.tools.r8.naming.MethodNameMinifier.FrontierState;
import com.android.tools.r8.naming.MethodNameMinifier.MethodNamingState;
import com.android.tools.r8.shaking.Enqueuer.AppInfoWithLiveness;
-import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.Timing;
import com.google.common.base.Equivalence;
import com.google.common.base.Equivalence.Wrapper;
@@ -36,12 +36,11 @@
public class InterfaceMethodNameMinifier {
- private final AppInfoWithLiveness appInfo;
+ private final AppView<AppInfoWithLiveness> appView;
private final Set<DexCallSite> desugaredCallSites;
private final Equivalence<DexMethod> equivalence;
private final FrontierState frontierState;
private final MemberNameMinifier<DexMethod, DexProto>.State minifierState;
- private final InternalOptions options;
private final Map<DexCallSite, DexString> callSiteRenamings = new IdentityHashMap<>();
@@ -58,18 +57,16 @@
private final Map<Wrapper<DexMethod>, Set<DexMethod>> sourceMethodsMap = new HashMap<>();
InterfaceMethodNameMinifier(
- AppInfoWithLiveness appInfo,
+ AppView<AppInfoWithLiveness> appView,
Set<DexCallSite> desugaredCallSites,
Equivalence<DexMethod> equivalence,
FrontierState frontierState,
- MemberNameMinifier<DexMethod, DexProto>.State minifierState,
- InternalOptions options) {
- this.appInfo = appInfo;
+ MemberNameMinifier<DexMethod, DexProto>.State minifierState) {
+ this.appView = appView;
this.desugaredCallSites = desugaredCallSites;
this.equivalence = equivalence;
this.frontierState = frontierState;
this.minifierState = minifierState;
- this.options = options;
}
public Comparator<Wrapper<DexMethod>> createDefaultInterfaceMethodOrdering() {
@@ -81,7 +78,7 @@
}
private void reserveNamesInInterfaces() {
- for (DexType type : DexType.allInterfaces(appInfo.dexItemFactory)) {
+ for (DexType type : DexType.allInterfaces(appView.dexItemFactory())) {
assert type.isInterface();
frontierState.allocateNamingStateAndReserve(type, type, null);
}
@@ -95,13 +92,13 @@
// frontier states of classes that implement them. We add the frontier states so that we can
// reserve the names for later method naming.
timing.begin("Compute map");
- for (DexType type : DexType.allInterfaces(appInfo.dexItemFactory)) {
+ for (DexType type : DexType.allInterfaces(appView.dexItemFactory())) {
assert type.isInterface();
- DexClass clazz = appInfo.definitionFor(type);
+ DexClass clazz = appView.definitionFor(type);
if (clazz != null) {
assert clazz.isInterface();
Set<NamingState<DexProto, ?>> collectedStates = getReachableStates(type);
- for (DexEncodedMethod method : shuffleMethods(clazz.methods(), options)) {
+ for (DexEncodedMethod method : shuffleMethods(clazz.methods(), appView.options())) {
addStatesToGlobalMapForMethod(method.method, collectedStates, type);
}
}
@@ -111,7 +108,7 @@
// desugared lambdas this is a conservative estimate, as we don't track if the generated
// lambda classes survive into the output. As multi-interface lambda expressions are rare
// this is not a big deal.
- Set<DexCallSite> liveCallSites = Sets.union(desugaredCallSites, appInfo.callSites);
+ Set<DexCallSite> liveCallSites = Sets.union(desugaredCallSites, appView.appInfo().callSites);
// If the input program contains a multi-interface lambda expression that implements
// interface methods with different protos, we need to make sure that
// the implemented lambda methods are renamed to the same name.
@@ -128,7 +125,7 @@
// Don't report errors, as the set of call sites is a conservative estimate, and can
// refer to interfaces which has been removed.
Set<DexEncodedMethod> implementedMethods =
- appInfo.lookupLambdaImplementedMethods(callSite);
+ appView.appInfo().lookupLambdaImplementedMethods(callSite);
if (implementedMethods.isEmpty()) {
return;
}
@@ -169,7 +166,7 @@
List<Wrapper<DexMethod>> interfaceMethods =
globalStateMap.keySet().stream()
.filter(wrapper -> unificationParent.getOrDefault(wrapper, wrapper).equals(wrapper))
- .sorted(options.testing.minifier.createInterfaceMethodOrdering(this))
+ .sorted(appView.options().testing.minifier.createInterfaceMethodOrdering(this))
.collect(Collectors.toList());
// Propagate reserved names to all states.
@@ -242,7 +239,7 @@
DexMethod method = key.get();
assert method != null;
- Set<String> loggingFilter = options.extensiveInterfaceMethodMinifierLoggingFilter;
+ Set<String> loggingFilter = appView.options().extensiveInterfaceMethodMinifierLoggingFilter;
if (!loggingFilter.isEmpty()) {
if (sourceMethods.stream().map(DexMethod::toSourceString).anyMatch(loggingFilter::contains)) {
print(method, sourceMethods, collectedStates, System.out);
@@ -361,7 +358,7 @@
}
private void collectSuperInterfaces(DexType iface, Set<DexType> interfaces) {
- DexClass clazz = appInfo.definitionFor(iface);
+ DexClass clazz = appView.definitionFor(iface);
// In cases where we lack the interface's definition, we can at least look at subtypes and
// tie those up to get proper naming.
if (clazz != null) {
diff --git a/src/main/java/com/android/tools/r8/naming/MemberNameMinifier.java b/src/main/java/com/android/tools/r8/naming/MemberNameMinifier.java
index b6b50b9..5804e9c 100644
--- a/src/main/java/com/android/tools/r8/naming/MemberNameMinifier.java
+++ b/src/main/java/com/android/tools/r8/naming/MemberNameMinifier.java
@@ -11,8 +11,8 @@
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.naming.NamingState.InternalState;
import com.android.tools.r8.shaking.Enqueuer.AppInfoWithLiveness;
+import com.android.tools.r8.shaking.ProguardConfiguration;
import com.android.tools.r8.shaking.RootSetBuilder.RootSet;
-import com.android.tools.r8.utils.InternalOptions;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import java.util.IdentityHashMap;
@@ -23,9 +23,7 @@
abstract class MemberNameMinifier<MemberType, StateType extends CachedHashValueDexItem> {
protected final AppView<AppInfoWithLiveness> appView;
- protected final AppInfoWithLiveness appInfo;
protected final RootSet rootSet;
- protected final InternalOptions options;
protected final List<String> dictionary;
protected final Map<MemberType, DexString> renaming = new IdentityHashMap<>();
@@ -42,18 +40,21 @@
MemberNameMinifier(
AppView<AppInfoWithLiveness> appView, RootSet rootSet, MemberNamingStrategy strategy) {
+ ProguardConfiguration proguardConfiguration = appView.options().getProguardConfiguration();
this.appView = appView;
- this.appInfo = appView.appInfo();
this.rootSet = rootSet;
- this.options = appView.options();
- this.dictionary = options.getProguardConfiguration().getObfuscationDictionary();
- this.useUniqueMemberNames = options.getProguardConfiguration().isUseUniqueClassMemberNames();
+ this.dictionary = proguardConfiguration.getObfuscationDictionary();
+ this.useUniqueMemberNames = proguardConfiguration.isUseUniqueClassMemberNames();
this.overloadAggressively =
- options.getProguardConfiguration().isOverloadAggressivelyWithoutUseUniqueClassMemberNames();
+ proguardConfiguration.isOverloadAggressivelyWithoutUseUniqueClassMemberNames();
this.globalState =
NamingState.createRoot(
- appInfo.dexItemFactory, dictionary, getKeyTransform(), strategy, useUniqueMemberNames);
- this.useApplyMapping = options.getProguardConfiguration().hasApplyMappingFile();
+ appView.dexItemFactory(),
+ dictionary,
+ getKeyTransform(),
+ strategy,
+ useUniqueMemberNames);
+ this.useApplyMapping = proguardConfiguration.hasApplyMappingFile();
}
abstract Function<StateType, ?> getKeyTransform();
diff --git a/src/main/java/com/android/tools/r8/naming/MethodNameMinifier.java b/src/main/java/com/android/tools/r8/naming/MethodNameMinifier.java
index e9932e1..a93c815 100644
--- a/src/main/java/com/android/tools/r8/naming/MethodNameMinifier.java
+++ b/src/main/java/com/android/tools/r8/naming/MethodNameMinifier.java
@@ -142,23 +142,23 @@
timing.begin("Phase 2");
InterfaceMethodNameMinifier interfaceMethodNameMinifier =
new InterfaceMethodNameMinifier(
- appInfo, desugaredCallSites, equivalence, frontierState, minifierState, options);
+ appView, desugaredCallSites, equivalence, frontierState, minifierState);
interfaceMethodNameMinifier.assignNamesToInterfaceMethods(timing);
timing.end();
// Phase 3: Assign names top-down by traversing the subtype hierarchy.
timing.begin("Phase 3");
- assignNamesToClassesMethods(appInfo.dexItemFactory.objectType, false);
+ assignNamesToClassesMethods(appView.dexItemFactory().objectType, false);
timing.end();
// Phase 4: Do the same for private methods.
timing.begin("Phase 4");
- assignNamesToClassesMethods(appInfo.dexItemFactory.objectType, true);
+ assignNamesToClassesMethods(appView.dexItemFactory().objectType, true);
timing.end();
return new MethodRenaming(renaming, interfaceMethodNameMinifier.getCallSiteRenamings());
}
private void assignNamesToClassesMethods(DexType type, boolean doPrivates) {
- DexClass holder = appInfo.definitionFor(type);
+ DexClass holder = appView.definitionFor(type);
boolean shouldAssignName = holder != null && !alwaysReserveMemberNames(holder);
if (shouldAssignName) {
Map<Wrapper<DexMethod>, DexString> renamingAtThisLevel = new HashMap<>();
@@ -200,7 +200,7 @@
private void reserveNamesInClasses() {
reserveNamesInClasses(
- appInfo.dexItemFactory.objectType, appInfo.dexItemFactory.objectType, null);
+ appView.dexItemFactory().objectType, appView.dexItemFactory().objectType, null);
}
private void reserveNamesInClasses(
@@ -211,7 +211,7 @@
// If this is a library class (or effectively a library class as it is missing) move the
// frontier forward.
- DexClass holder = appInfo.definitionFor(type);
+ DexClass holder = appView.definitionFor(type);
for (DexType subtype : type.allExtendsSubtypes()) {
assert !subtype.isInterface();
reserveNamesInClasses(
@@ -235,17 +235,17 @@
ignore ->
parent == null
? NamingState.createRoot(
- appInfo.dexItemFactory,
+ appView.dexItemFactory(),
dictionary,
getKeyTransform(),
strategy,
useUniqueMemberNames)
: parent.createChild());
- DexClass holder = appInfo.definitionFor(type);
+ DexClass holder = appView.definitionFor(type);
if (holder != null) {
boolean keepAll = alwaysReserveMemberNames(holder) || holder.accessFlags.isAnnotation();
- for (DexEncodedMethod method : shuffleMethods(holder.methods(), options)) {
+ for (DexEncodedMethod method : shuffleMethods(holder.methods(), appView.options())) {
// TODO(christofferqa): Wouldn't it be sufficient only to reserve names for non-private
// methods?
if (keepAll || rootSet.noObfuscation.contains(method.method)) {
@@ -327,7 +327,7 @@
out.print(".");
out.print(name.toSourceString());
out.println(proto.toSmaliString());
- parent.printState(proto, indentation + " ", out);
+ parent.printState(proto, stateKeyGetter, indentation + " ", out);
}
}
diff --git a/src/main/java/com/android/tools/r8/naming/MinifiedRenaming.java b/src/main/java/com/android/tools/r8/naming/MinifiedRenaming.java
index 18a23ba..a2212b0 100644
--- a/src/main/java/com/android/tools/r8/naming/MinifiedRenaming.java
+++ b/src/main/java/com/android/tools/r8/naming/MinifiedRenaming.java
@@ -5,6 +5,7 @@
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.DexCallSite;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexEncodedMethod;
@@ -30,16 +31,16 @@
class MinifiedRenaming extends NamingLens {
- private final AppInfo appInfo;
+ private final AppView<? extends AppInfo> appView;
private final Map<String, String> packageRenaming;
private final Map<DexItem, DexString> renaming = new IdentityHashMap<>();
MinifiedRenaming(
+ AppView<? extends AppInfo> appView,
ClassRenaming classRenaming,
MethodRenaming methodRenaming,
- FieldRenaming fieldRenaming,
- AppInfo appInfo) {
- this.appInfo = appInfo;
+ FieldRenaming fieldRenaming) {
+ this.appView = appView;
this.packageRenaming = classRenaming.packageRenaming;
renaming.putAll(classRenaming.classRenaming);
renaming.putAll(methodRenaming.renaming);
@@ -140,21 +141,21 @@
// Array methods are never renamed, so do not bother to check.
return true;
}
- DexClass holder = appInfo.definitionFor(item.holder);
+ DexClass holder = appView.definitionFor(item.holder);
if (holder == null || holder.isLibraryClass()) {
return true;
}
// We don't know which invoke type this method is used for, so checks that it has been
// rebound either way.
- DexEncodedMethod staticTarget = appInfo.lookupStaticTarget(item);
- DexEncodedMethod directTarget = appInfo.lookupDirectTarget(item);
- DexEncodedMethod virtualTarget = appInfo.lookupVirtualTarget(item.holder, item);
+ DexEncodedMethod staticTarget = appView.appInfo().lookupStaticTarget(item);
+ DexEncodedMethod directTarget = appView.appInfo().lookupDirectTarget(item);
+ DexEncodedMethod virtualTarget = appView.appInfo().lookupVirtualTarget(item.holder, item);
DexClass staticTargetHolder =
- staticTarget != null ? appInfo.definitionFor(staticTarget.method.holder) : null;
+ staticTarget != null ? appView.definitionFor(staticTarget.method.holder) : null;
DexClass directTargetHolder =
- directTarget != null ? appInfo.definitionFor(directTarget.method.holder) : null;
+ directTarget != null ? appView.definitionFor(directTarget.method.holder) : null;
DexClass virtualTargetHolder =
- virtualTarget != null ? appInfo.definitionFor(virtualTarget.method.holder) : null;
+ virtualTarget != null ? appView.definitionFor(virtualTarget.method.holder) : null;
return (directTarget == null && staticTarget == null && virtualTarget == null)
|| (virtualTarget != null && virtualTarget.method == item)
|| (directTarget != null && directTarget.method == item)
diff --git a/src/main/java/com/android/tools/r8/naming/Minifier.java b/src/main/java/com/android/tools/r8/naming/Minifier.java
index 0b7bf45..ebaf4a4 100644
--- a/src/main/java/com/android/tools/r8/naming/Minifier.java
+++ b/src/main/java/com/android/tools/r8/naming/Minifier.java
@@ -19,7 +19,6 @@
import com.android.tools.r8.naming.NamingState.InternalState;
import com.android.tools.r8.shaking.Enqueuer.AppInfoWithLiveness;
import com.android.tools.r8.shaking.RootSetBuilder.RootSet;
-import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.Timing;
import it.unimi.dsi.fastutil.objects.Object2IntLinkedOpenHashMap;
@@ -29,37 +28,33 @@
public class Minifier {
private final AppView<AppInfoWithLiveness> appView;
- private final AppInfoWithLiveness appInfo;
private final RootSet rootSet;
private final Set<DexCallSite> desugaredCallSites;
- private final InternalOptions options;
public Minifier(
AppView<AppInfoWithLiveness> appView, RootSet rootSet, Set<DexCallSite> desugaredCallSites) {
this.appView = appView;
- this.appInfo = appView.appInfo();
this.rootSet = rootSet;
this.desugaredCallSites = desugaredCallSites;
- this.options = appView.options();
}
public NamingLens run(Timing timing) {
- assert options.enableMinification;
+ assert appView.options().enableMinification;
timing.begin("MinifyClasses");
ClassNameMinifier classNameMinifier =
new ClassNameMinifier(
appView,
rootSet,
- new MinificationClassNamingStrategy(appInfo.dexItemFactory),
+ new MinificationClassNamingStrategy(appView.dexItemFactory()),
new MinificationPackageNamingStrategy(),
// Use deterministic class order to make sure renaming is deterministic.
- appInfo.classesWithDeterministicOrder());
+ appView.appInfo().classesWithDeterministicOrder());
ClassRenaming classRenaming = classNameMinifier.computeRenaming(timing);
timing.end();
assert new MinifiedRenaming(
- classRenaming, MethodRenaming.empty(), FieldRenaming.empty(), appInfo)
- .verifyNoCollisions(appInfo.classes(), appInfo.dexItemFactory);
+ appView, classRenaming, MethodRenaming.empty(), FieldRenaming.empty())
+ .verifyNoCollisions(appView.appInfo().classes(), appView.dexItemFactory());
MemberNamingStrategy minifyMembers = new MinifierMemberNamingStrategy(appView.dexItemFactory());
timing.begin("MinifyMethods");
@@ -68,20 +63,19 @@
.computeRenaming(desugaredCallSites, timing);
timing.end();
- assert new MinifiedRenaming(classRenaming, methodRenaming, FieldRenaming.empty(), appInfo)
- .verifyNoCollisions(appInfo.classes(), appInfo.dexItemFactory);
+ assert new MinifiedRenaming(appView, classRenaming, methodRenaming, FieldRenaming.empty())
+ .verifyNoCollisions(appView.appInfo().classes(), appView.dexItemFactory());
timing.begin("MinifyFields");
FieldRenaming fieldRenaming =
new FieldNameMinifier(appView, rootSet, minifyMembers).computeRenaming(timing);
timing.end();
- NamingLens lens = new MinifiedRenaming(classRenaming, methodRenaming, fieldRenaming, appInfo);
- assert lens.verifyNoCollisions(appInfo.classes(), appInfo.dexItemFactory);
+ NamingLens lens = new MinifiedRenaming(appView, classRenaming, methodRenaming, fieldRenaming);
+ assert lens.verifyNoCollisions(appView.appInfo().classes(), appView.dexItemFactory());
timing.begin("MinifyIdentifiers");
- new IdentifierMinifier(
- appInfo, options.getProguardConfiguration().getAdaptClassStrings(), lens).run();
+ new IdentifierMinifier(appView, lens).run();
timing.end();
return lens;
}
@@ -136,7 +130,7 @@
static class MinifierMemberNamingStrategy implements MemberNamingStrategy {
- char[] EMPTY_CHAR_ARRAY = new char[0];
+ public static char[] EMPTY_CHAR_ARRAY = new char[0];
private final DexItemFactory factory;
diff --git a/src/main/java/com/android/tools/r8/naming/NamingState.java b/src/main/java/com/android/tools/r8/naming/NamingState.java
index c44c70d..502fae2 100644
--- a/src/main/java/com/android/tools/r8/naming/NamingState.java
+++ b/src/main/java/com/android/tools/r8/naming/NamingState.java
@@ -3,11 +3,15 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.naming;
+import static com.android.tools.r8.naming.Minifier.MinifierMemberNamingStrategy.EMPTY_CHAR_ARRAY;
+
import com.android.tools.r8.graph.CachedHashValueDexItem;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexReference;
import com.android.tools.r8.graph.DexString;
+import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.naming.MemberNameMinifier.MemberNamingStrategy;
+import com.android.tools.r8.utils.StringUtils;
import com.google.common.collect.HashBasedTable;
import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;
@@ -73,12 +77,8 @@
// TODO(herhut): Maybe allocate these sparsely and search via state chain.
InternalState result = usedNames.get(key);
if (result == null) {
- if (parent != null) {
- InternalState parentState = parent.getOrCreateInternalStateFor(key);
- result = parentState.createChild();
- } else {
- result = new InternalState(itemFactory, null, dictionary);
- }
+ InternalState parentState = parent != null ? parent.getOrCreateInternalStateFor(key) : null;
+ result = new InternalState(itemFactory, parentState, dictionary);
usedNames.put(key, result);
}
return result;
@@ -139,12 +139,23 @@
state.addRenaming(original, key, newName);
}
- void printState(ProtoType proto, String indentation, PrintStream out) {
+ void printState(
+ ProtoType proto,
+ Function<NamingState<ProtoType, ?>, DexType> stateKeyGetter,
+ String indentation,
+ PrintStream out) {
KeyType key = keyTransform.apply(proto);
- InternalState state = findInternalStateFor(key);
+ InternalState state = getOrCreateInternalStateFor(key);
+ out.print(indentation);
+ out.print("NamingState(node=`");
+ out.print(stateKeyGetter.apply(this).toSourceString());
+ out.print("`, proto=`");
+ out.print(proto.toSourceString());
+ out.print("`, key=`");
+ out.print(key.toString());
+ out.println("`)");
if (state != null) {
- state.printReservedNames(indentation, out);
- state.printRenamings(indentation, out);
+ state.printInternalState(this, stateKeyGetter, indentation + " ", out);
} else {
out.print(indentation);
out.println("<NO STATE>");
@@ -189,10 +200,6 @@
&& (parentInternalState == null || parentInternalState.isAvailable(name));
}
- InternalState createChild() {
- return new InternalState(itemFactory, this, dictionaryIterator);
- }
-
void reserveName(DexString name) {
if (reservedNames == null) {
reservedNames = Sets.newIdentityHashSet();
@@ -256,6 +263,43 @@
}
}
+ void printInternalState(
+ NamingState<ProtoType, ?> expectedNamingState,
+ Function<NamingState<ProtoType, ?>, DexType> stateKeyGetter,
+ String indentation,
+ PrintStream out) {
+ assert expectedNamingState == NamingState.this;
+
+ DexType stateKey = stateKeyGetter.apply(expectedNamingState);
+ out.print(indentation);
+ out.print("InternalState(node=`");
+ out.print(stateKey != null ? stateKey.toSourceString() : "<GLOBAL>");
+ out.println("`)");
+
+ printLastName(indentation + " ", out);
+ printReservedNames(indentation + " ", out);
+ printRenamings(indentation + " ", out);
+
+ if (parentInternalState != null) {
+ parentInternalState.printInternalState(
+ expectedNamingState.parent, stateKeyGetter, indentation + " ", out);
+ }
+ }
+
+ void printLastName(String indentation, PrintStream out) {
+ out.print(indentation);
+ out.print("Last name: ");
+ if (nameCount > 1) {
+ out.print(StringUtils.numberToIdentifier(EMPTY_CHAR_ARRAY, nameCount - 1, false));
+ out.print(" (name count: ");
+ out.print(nameCount);
+ out.print(")");
+ } else {
+ out.print("<NONE>");
+ }
+ out.println();
+ }
+
void printReservedNames(String indentation, PrintStream out) {
out.print(indentation);
out.print("Reserved names:");
@@ -270,9 +314,6 @@
}
}
out.println();
- if (parentInternalState != null) {
- parentInternalState.printReservedNames(indentation + " ", out);
- }
}
void printRenamings(String indentation, PrintStream out) {
@@ -295,9 +336,6 @@
}
}
out.println();
- if (parentInternalState != null) {
- parentInternalState.printRenamings(indentation + " ", out);
- }
}
}
}
diff --git a/src/main/java/com/android/tools/r8/naming/ProguardMapMinifier.java b/src/main/java/com/android/tools/r8/naming/ProguardMapMinifier.java
index 84c21f6..5ca0da3 100644
--- a/src/main/java/com/android/tools/r8/naming/ProguardMapMinifier.java
+++ b/src/main/java/com/android/tools/r8/naming/ProguardMapMinifier.java
@@ -38,11 +38,9 @@
public class ProguardMapMinifier {
private final AppView<AppInfoWithLiveness> appView;
- private final AppInfoWithLiveness appInfo;
private final RootSet rootSet;
private final SeedMapper seedMapper;
private final Set<DexCallSite> desugaredCallSites;
- private final DexItemFactory factory;
public ProguardMapMinifier(
AppView<AppInfoWithLiveness> appView,
@@ -50,8 +48,6 @@
SeedMapper seedMapper,
Set<DexCallSite> desugaredCallSites) {
this.appView = appView;
- this.appInfo = appView.appInfo();
- this.factory = appInfo.dexItemFactory;
this.rootSet = rootSet;
this.seedMapper = seedMapper;
this.desugaredCallSites = desugaredCallSites;
@@ -69,24 +65,25 @@
Map<DexReference, MemberNaming> memberNames = new IdentityHashMap<>();
for (String key : seedMapper.getKeyset()) {
ClassNamingForMapApplier classNaming = seedMapper.getMapping(key);
- DexType type = factory.lookupType(factory.createString(key));
+ DexType type =
+ appView.dexItemFactory().lookupType(appView.dexItemFactory().createString(key));
if (type == null) {
// The map contains additional mapping of classes compared to what we have seen. This should
// have no effect.
continue;
}
- DexClass dexClass = appInfo.definitionFor(type);
+ DexClass dexClass = appView.definitionFor(type);
if (dexClass == null) {
continue;
}
- DexString mappedName = factory.createString(classNaming.renamedName);
- DexType mappedType = factory.lookupType(mappedName);
+ DexString mappedName = appView.dexItemFactory().createString(classNaming.renamedName);
+ DexType mappedType = appView.dexItemFactory().lookupType(mappedName);
// The mappedType has to be available:
// - If it is null we have not seen it.
// - If the mapped type is itself the name is already reserved (by itself).
// - If the there is no definition for the mapped type we will not get a naming clash.
// Otherwise, there will be a naming conflict.
- if (mappedType != null && type != mappedType && appInfo.definitionFor(mappedType) != null) {
+ if (mappedType != null && type != mappedType && appView.definitionFor(mappedType) != null) {
appView
.options()
.reporter
@@ -100,7 +97,8 @@
memberNaming -> {
Signature signature = memberNaming.getOriginalSignature();
assert !signature.isQualified();
- DexMethod originalMethod = ((MethodSignature) signature).toDexMethod(factory, type);
+ DexMethod originalMethod =
+ ((MethodSignature) signature).toDexMethod(appView.dexItemFactory(), type);
assert !memberNames.containsKey(originalMethod);
memberNames.put(originalMethod, memberNaming);
});
@@ -108,7 +106,8 @@
memberNaming -> {
Signature signature = memberNaming.getOriginalSignature();
assert !signature.isQualified();
- DexField originalField = ((FieldSignature) signature).toDexField(factory, type);
+ DexField originalField =
+ ((FieldSignature) signature).toDexField(appView.dexItemFactory(), type);
assert !memberNames.containsKey(originalField);
memberNames.put(originalField, memberNaming);
});
@@ -132,7 +131,7 @@
ApplyMappingMemberNamingStrategy nameStrategy =
new ApplyMappingMemberNamingStrategy(
- memberNames, appInfo.dexItemFactory, appView.options().reporter);
+ memberNames, appView.dexItemFactory(), appView.options().reporter);
timing.begin("MinifyMethods");
MethodRenaming methodRenaming =
new MethodNameMinifier(appView, rootSet, nameStrategy)
@@ -146,13 +145,10 @@
appView.options().reporter.failIfPendingErrors();
- NamingLens lens =
- new MinifiedRenaming(classRenaming, methodRenaming, fieldRenaming, appView.appInfo());
+ NamingLens lens = new MinifiedRenaming(appView, classRenaming, methodRenaming, fieldRenaming);
timing.begin("MinifyIdentifiers");
- new IdentifierMinifier(
- appInfo, appView.options().getProguardConfiguration().getAdaptClassStrings(), lens)
- .run();
+ new IdentifierMinifier(appView, lens).run();
timing.end();
return lens;
diff --git a/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java b/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java
index b398c7d..325140d 100644
--- a/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java
+++ b/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java
@@ -4,9 +4,9 @@
package com.android.tools.r8.optimize;
import com.android.tools.r8.graph.AccessFlags;
-import com.android.tools.r8.graph.AppInfo;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.graph.DexDefinitionSupplier;
import com.android.tools.r8.graph.DexEncodedField;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexField;
@@ -29,7 +29,7 @@
public class MemberRebindingAnalysis {
- private final AppInfoWithLiveness appInfo;
+ private final AppView<AppInfoWithLiveness> appView;
private final GraphLense lense;
private final InternalOptions options;
@@ -37,14 +37,14 @@
public MemberRebindingAnalysis(AppView<AppInfoWithLiveness> appView) {
assert appView.graphLense().isContextFreeForMethods();
- this.appInfo = appView.appInfo();
+ this.appView = appView;
this.lense = appView.graphLense();
this.options = appView.options();
- this.builder = MemberRebindingLense.builder(appInfo);
+ this.builder = MemberRebindingLense.builder(appView);
}
private DexMethod validTargetFor(DexMethod target, DexMethod original) {
- DexClass clazz = appInfo.definitionFor(target.holder);
+ DexClass clazz = appView.definitionFor(target.holder);
assert clazz != null;
if (!clazz.isLibraryClass()) {
return target;
@@ -56,12 +56,12 @@
} else {
newHolder = firstLibraryClass(target.holder, original.holder);
}
- return appInfo.dexItemFactory.createMethod(newHolder, original.proto, original.name);
+ return appView.dexItemFactory().createMethod(newHolder, original.proto, original.name);
}
private DexField validTargetFor(DexField target, DexField original,
BiFunction<DexClass, DexField, DexEncodedField> lookup) {
- DexClass clazz = appInfo.definitionFor(target.holder);
+ DexClass clazz = appView.definitionFor(target.holder);
assert clazz != null;
if (!clazz.isLibraryClass()) {
return target;
@@ -72,12 +72,12 @@
} else {
newHolder = firstLibraryClass(target.holder, original.holder);
}
- return appInfo.dexItemFactory.createField(newHolder, original.type, original.name);
+ return appView.dexItemFactory().createField(newHolder, original.type, original.name);
}
private <T> DexType firstLibraryClassForInterfaceTarget(T target, DexType current,
BiFunction<DexClass, T, ?> lookup) {
- DexClass clazz = appInfo.definitionFor(current);
+ DexClass clazz = appView.definitionFor(current);
Object potential = lookup.apply(clazz, target);
if (potential != null) {
// Found, return type.
@@ -101,24 +101,24 @@
}
private DexType firstLibraryClass(DexType top, DexType bottom) {
- assert appInfo.definitionFor(top).isLibraryClass();
- DexClass searchClass = appInfo.definitionFor(bottom);
+ assert appView.definitionFor(top).isLibraryClass();
+ DexClass searchClass = appView.definitionFor(bottom);
while (!searchClass.isLibraryClass()) {
- searchClass = appInfo.definitionFor(searchClass.superType);
+ searchClass = appView.definitionFor(searchClass.superType);
}
return searchClass.type;
}
private DexEncodedMethod classLookup(DexMethod method) {
- return appInfo.resolveMethodOnClass(method.holder, method).asResultOfResolve();
+ return appView.appInfo().resolveMethodOnClass(method.holder, method).asResultOfResolve();
}
private DexEncodedMethod interfaceLookup(DexMethod method) {
- return appInfo.resolveMethodOnInterface(method.holder, method).asResultOfResolve();
+ return appView.appInfo().resolveMethodOnInterface(method.holder, method).asResultOfResolve();
}
private DexEncodedMethod anyLookup(DexMethod method) {
- return appInfo.resolveMethod(method.holder, method).asResultOfResolve();
+ return appView.appInfo().resolveMethod(method.holder, method).asResultOfResolve();
}
private void computeMethodRebinding(
@@ -130,7 +130,7 @@
if (!method.holder.isClassType()) {
continue;
}
- DexClass originalClass = appInfo.definitionFor(method.holder);
+ DexClass originalClass = appView.definitionFor(method.holder);
if (originalClass == null || originalClass.isLibraryClass()) {
continue;
}
@@ -138,7 +138,7 @@
// TODO(b/128404854) Rebind to the lowest library class or program class. For now we allow
// searching in library for methods, but this should be done on classpath instead.
if (target != null && target.method != method) {
- DexClass targetClass = appInfo.definitionFor(target.method.holder);
+ DexClass targetClass = appView.definitionFor(target.method.holder);
if (!originalClass.isLibraryClass()) {
// In Java bytecode, it is only possible to target interface methods that are in one of
// the immediate super-interfaces via a super-invocation (see IndirectSuperInterfaceTest).
@@ -193,7 +193,7 @@
findHolderForInterfaceMethodBridge(originalClass, targetClass.type);
assert bridgeHolder != null;
assert bridgeHolder != targetClass;
- DexEncodedMethod bridgeMethod = target.toForwardingMethod(bridgeHolder, appInfo);
+ DexEncodedMethod bridgeMethod = target.toForwardingMethod(bridgeHolder, appView);
bridgeHolder.addMethod(bridgeMethod);
assert lookupTarget.apply(method) == bridgeMethod;
return bridgeMethod;
@@ -203,10 +203,10 @@
if (clazz.accessFlags.isInterface()) {
return clazz;
}
- DexClass superClass = appInfo.definitionFor(clazz.superType);
+ DexClass superClass = appView.definitionFor(clazz.superType);
if (superClass == null
|| superClass.isLibraryClass()
- || !superClass.type.isSubtypeOf(iface, appInfo)) {
+ || !superClass.type.isSubtypeOf(iface, appView)) {
return clazz;
}
return findHolderForInterfaceMethodBridge(superClass.asProgramClass(), iface);
@@ -214,14 +214,14 @@
private boolean mayNeedBridgeForVisibility(DexType context, DexEncodedMethod method) {
DexType holderType = method.method.holder;
- DexClass holder = appInfo.definitionFor(holderType);
+ DexClass holder = appView.definitionFor(holderType);
if (holder == null) {
return false;
}
ConstraintWithTarget classVisibility =
- ConstraintWithTarget.deriveConstraint(context, holderType, holder.accessFlags, appInfo);
+ ConstraintWithTarget.deriveConstraint(context, holderType, holder.accessFlags, appView);
ConstraintWithTarget methodVisibility =
- ConstraintWithTarget.deriveConstraint(context, holderType, method.accessFlags, appInfo);
+ ConstraintWithTarget.deriveConstraint(context, holderType, method.accessFlags, appView);
// We may need bridge for visibility if the target class is not visible while the target method
// is visible from the calling context.
return classVisibility == ConstraintWithTarget.NEVER
@@ -244,7 +244,7 @@
DexProgramClass bridgeHolder =
findHolderForVisibilityBridge(originalClass, targetClass, packageDescriptor);
assert bridgeHolder != null;
- DexEncodedMethod bridgeMethod = target.toForwardingMethod(bridgeHolder, appInfo);
+ DexEncodedMethod bridgeMethod = target.toForwardingMethod(bridgeHolder, appView);
bridgeHolder.addMethod(bridgeMethod);
assert lookupTarget.apply(method) == bridgeMethod;
return bridgeMethod;
@@ -259,13 +259,13 @@
}
DexProgramClass newHolder = null;
// Recurse through supertype chain.
- if (originalClass.superType.isSubtypeOf(targetClass.type, appInfo)) {
- DexClass superClass = appInfo.definitionFor(originalClass.superType);
+ if (originalClass.superType.isSubtypeOf(targetClass.type, appView)) {
+ DexClass superClass = appView.definitionFor(originalClass.superType);
newHolder = findHolderForVisibilityBridge(superClass, targetClass, packageDescriptor);
} else {
for (DexType iface : originalClass.interfaces.values) {
- if (iface.isSubtypeOf(targetClass.type, appInfo)) {
- DexClass interfaceClass = appInfo.definitionFor(iface);
+ if (iface.isSubtypeOf(targetClass.type, appView)) {
+ DexClass interfaceClass = appView.definitionFor(iface);
newHolder = findHolderForVisibilityBridge(interfaceClass, targetClass, packageDescriptor);
}
}
@@ -296,7 +296,7 @@
.allMatch(
context ->
isMemberVisibleFromOriginalContext(
- appInfo,
+ appView,
context.method.holder,
target.field.holder,
target.accessFlags))) {
@@ -307,18 +307,21 @@
}
public static boolean isMemberVisibleFromOriginalContext(
- AppInfo appInfo, DexType context, DexType holder, AccessFlags<?> memberAccessFlags) {
- DexClass clazz = appInfo.definitionFor(holder);
+ DexDefinitionSupplier definitions,
+ DexType context,
+ DexType holder,
+ AccessFlags<?> memberAccessFlags) {
+ DexClass clazz = definitions.definitionFor(holder);
if (clazz == null) {
return false;
}
ConstraintWithTarget classVisibility =
- ConstraintWithTarget.deriveConstraint(context, holder, clazz.accessFlags, appInfo);
+ ConstraintWithTarget.deriveConstraint(context, holder, clazz.accessFlags, definitions);
if (classVisibility == ConstraintWithTarget.NEVER) {
return false;
}
ConstraintWithTarget memberVisibility =
- ConstraintWithTarget.deriveConstraint(context, holder, memberAccessFlags, appInfo);
+ ConstraintWithTarget.deriveConstraint(context, holder, memberAccessFlags, definitions);
return memberVisibility != ConstraintWithTarget.NEVER;
}
@@ -337,6 +340,7 @@
}
public GraphLense run() {
+ AppInfoWithLiveness appInfo = appView.appInfo();
// Virtual invokes are on classes, so use class resolution.
computeMethodRebinding(appInfo.virtualInvokes, this::classLookup, Type.VIRTUAL);
// Interface invokes are always on interfaces, so use interface resolution.
diff --git a/src/main/java/com/android/tools/r8/optimize/MemberRebindingLense.java b/src/main/java/com/android/tools/r8/optimize/MemberRebindingLense.java
index 5e19d48..8a7d1aa 100644
--- a/src/main/java/com/android/tools/r8/optimize/MemberRebindingLense.java
+++ b/src/main/java/com/android/tools/r8/optimize/MemberRebindingLense.java
@@ -5,6 +5,7 @@
package com.android.tools.r8.optimize;
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.DexMethod;
import com.android.tools.r8.graph.GraphLense;
@@ -14,11 +15,13 @@
import java.util.Map;
public class MemberRebindingLense extends NestedGraphLense {
- public static class Builder extends NestedGraphLense.Builder {
- private final AppInfo appInfo;
- protected Builder(AppInfo appInfo) {
- this.appInfo = appInfo;
+ public static class Builder extends NestedGraphLense.Builder {
+
+ private final AppView<? extends AppInfo> appView;
+
+ protected Builder(AppView<? extends AppInfo> appView) {
+ this.appView = appView;
}
public GraphLense build(GraphLense previousLense) {
@@ -26,28 +29,34 @@
if (methodMap.isEmpty() && fieldMap.isEmpty()) {
return previousLense;
}
- return new MemberRebindingLense(appInfo, methodMap, fieldMap, previousLense);
+ return new MemberRebindingLense(appView, methodMap, fieldMap, previousLense);
}
}
- private final AppInfo appInfo;
+ private final AppView<? extends AppInfo> appView;
public MemberRebindingLense(
- AppInfo appInfo,
+ AppView<? extends AppInfo> appView,
Map<DexMethod, DexMethod> methodMap,
Map<DexField, DexField> fieldMap,
GraphLense previousLense) {
super(
- ImmutableMap.of(), methodMap, fieldMap, null, null, previousLense, appInfo.dexItemFactory);
- this.appInfo = appInfo;
+ ImmutableMap.of(),
+ methodMap,
+ fieldMap,
+ null,
+ null,
+ previousLense,
+ appView.dexItemFactory());
+ this.appView = appView;
}
- public static Builder builder(AppInfo appInfo) {
- return new Builder(appInfo);
+ public static Builder builder(AppView<? extends AppInfo> appView) {
+ return new Builder(appView);
}
@Override
protected Type mapInvocationType(DexMethod newMethod, DexMethod originalMethod, Type type) {
- return super.mapVirtualInterfaceInvocationTypes(appInfo, newMethod, originalMethod, type);
+ return super.mapVirtualInterfaceInvocationTypes(appView, newMethod, originalMethod, type);
}
}
diff --git a/src/main/java/com/android/tools/r8/shaking/AnnotationRemover.java b/src/main/java/com/android/tools/r8/shaking/AnnotationRemover.java
index 25e0832..02e7442 100644
--- a/src/main/java/com/android/tools/r8/shaking/AnnotationRemover.java
+++ b/src/main/java/com/android/tools/r8/shaking/AnnotationRemover.java
@@ -5,6 +5,7 @@
import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexAnnotation;
import com.android.tools.r8.graph.DexAnnotationElement;
import com.android.tools.r8.graph.DexClass;
@@ -28,21 +29,14 @@
public class AnnotationRemover {
- private final AppInfoWithLiveness appInfo;
- private final GraphLense lense;
+ private final AppView<AppInfoWithLiveness> appView;
private final ProguardKeepAttributes keep;
- private final InternalOptions options;
private final Set<DexType> classesToRetainInnerClassAttributeFor;
public AnnotationRemover(
- AppInfoWithLiveness appInfo,
- GraphLense lense,
- InternalOptions options,
- Set<DexType> classesToRetainInnerClassAttributeFor) {
- this.appInfo = appInfo;
- this.lense = lense;
- this.keep = options.getProguardConfiguration().getKeepAttributes();
- this.options = options;
+ AppView<AppInfoWithLiveness> appView, Set<DexType> classesToRetainInnerClassAttributeFor) {
+ this.appView = appView;
+ this.keep = appView.options().getProguardConfiguration().getKeepAttributes();
this.classesToRetainInnerClassAttributeFor = classesToRetainInnerClassAttributeFor;
}
@@ -51,7 +45,7 @@
*/
private boolean filterAnnotations(DexAnnotation annotation) {
return shouldKeepAnnotation(
- annotation, isAnnotationTypeLive(annotation), appInfo.dexItemFactory, options);
+ annotation, isAnnotationTypeLive(annotation), appView.dexItemFactory(), appView.options());
}
static boolean shouldKeepAnnotation(
@@ -114,14 +108,15 @@
}
private boolean isAnnotationTypeLive(DexAnnotation annotation) {
- DexType annotationType = annotation.annotation.type.toBaseType(appInfo.dexItemFactory);
- DexClass definition = appInfo.definitionFor(annotationType);
+ DexType annotationType = annotation.annotation.type.toBaseType(appView.dexItemFactory());
+ DexClass definition = appView.definitionFor(annotationType);
// TODO(b/73102187): How to handle annotations without definition.
- if (options.enableTreeShaking && definition == null) {
+ if (appView.options().enableTreeShaking && definition == null) {
return false;
}
- return definition == null || definition.isLibraryClass()
- || appInfo.liveTypes.contains(annotationType);
+ return definition == null
+ || definition.isLibraryClass()
+ || appView.appInfo().liveTypes.contains(annotationType);
}
/**
@@ -148,7 +143,7 @@
}
public AnnotationRemover ensureValid(ProguardConfiguration.Builder compatibility) {
- keep.ensureValid(options.forceProguardCompatibility, compatibility);
+ keep.ensureValid(appView.options().forceProguardCompatibility, compatibility);
return this;
}
@@ -226,7 +221,7 @@
}
public void run() {
- for (DexProgramClass clazz : appInfo.classes()) {
+ for (DexProgramClass clazz : appView.appInfo().classes()) {
stripAttributes(clazz);
clazz.annotations = clazz.annotations.rewrite(this::rewriteAnnotation);
clazz.forEachMethod(this::processMethod);
@@ -254,15 +249,16 @@
}
private DexEncodedAnnotation rewriteEncodedAnnotation(DexEncodedAnnotation original) {
- DexType annotationType = original.type.toBaseType(appInfo.dexItemFactory);
+ GraphLense graphLense = appView.graphLense();
+ DexType annotationType = original.type.toBaseType(appView.dexItemFactory());
return original.rewrite(
- lense::lookupType,
- element -> rewriteAnnotationElement(lense.lookupType(annotationType), element));
+ graphLense::lookupType,
+ element -> rewriteAnnotationElement(graphLense.lookupType(annotationType), element));
}
private DexAnnotationElement rewriteAnnotationElement(
DexType annotationType, DexAnnotationElement original) {
- DexClass definition = appInfo.definitionFor(annotationType);
+ DexClass definition = appView.definitionFor(annotationType);
// TODO(b/73102187): How to handle annotations without definition.
if (definition == null) {
return original;
@@ -277,10 +273,11 @@
private boolean enclosingMethodPinned(DexClass clazz) {
return clazz.getEnclosingMethod() != null
&& clazz.getEnclosingMethod().getEnclosingClass() != null
- && appInfo.isPinned(clazz.getEnclosingMethod().getEnclosingClass());
+ && appView.appInfo().isPinned(clazz.getEnclosingMethod().getEnclosingClass());
}
private boolean innerClassPinned(DexClass clazz) {
+ AppInfoWithLiveness appInfo = appView.appInfo();
List<InnerClassAttribute> innerClasses = clazz.getInnerClasses();
for (InnerClassAttribute innerClass : innerClasses) {
if (appInfo.isPinned(innerClass.getInner())) {
@@ -310,10 +307,10 @@
// if only one side is kept - keep the attributes is any class mentioned in these attributes
// is kept.
boolean keptAnyway =
- appInfo.isPinned(clazz.type)
+ appView.appInfo().isPinned(clazz.type)
|| enclosingMethodPinned(clazz)
|| innerClassPinned(clazz)
- || options.forceProguardCompatibility;
+ || appView.options().forceProguardCompatibility;
boolean keepForThisInnerClass = false;
boolean keepForThisEnclosingClass = false;
if (!keptAnyway) {
diff --git a/src/main/java/com/android/tools/r8/shaking/TreePruner.java b/src/main/java/com/android/tools/r8/shaking/TreePruner.java
index 743e48d..823091c 100644
--- a/src/main/java/com/android/tools/r8/shaking/TreePruner.java
+++ b/src/main/java/com/android/tools/r8/shaking/TreePruner.java
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.shaking;
+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.DexEncodedField;
@@ -30,24 +31,24 @@
public class TreePruner {
private final DexApplication application;
- private final AppInfoWithLiveness appInfo;
- private final InternalOptions options;
+ private final AppView<AppInfoWithLiveness> appView;
private final UsagePrinter usagePrinter;
private final Set<DexType> prunedTypes = Sets.newIdentityHashSet();
- public TreePruner(
- DexApplication application, AppInfoWithLiveness appInfo, InternalOptions options) {
+ public TreePruner(DexApplication application, AppView<AppInfoWithLiveness> appView) {
this.application = application;
- this.appInfo = appInfo;
- this.options = options;
+ this.appView = appView;
+
+ ProguardConfiguration proguardConfiguration = appView.options().getProguardConfiguration();
this.usagePrinter =
- options.getProguardConfiguration() != null
- && options.getProguardConfiguration().isPrintUsage()
- ? new UsagePrinter() : UsagePrinter.DONT_PRINT;
+ proguardConfiguration != null && proguardConfiguration.isPrintUsage()
+ ? new UsagePrinter()
+ : UsagePrinter.DONT_PRINT;
}
public DexApplication run() {
application.timing.begin("Pruning application...");
+ InternalOptions options = appView.options();
if (options.debugKeepRules && options.enableMinification) {
options.reporter.info(
new StringDiagnostic(
@@ -70,6 +71,8 @@
}
private List<DexProgramClass> getNewProgramClasses(List<DexProgramClass> classes) {
+ AppInfoWithLiveness appInfo = appView.appInfo();
+ InternalOptions options = appView.options();
List<DexProgramClass> newClasses = new ArrayList<>();
for (DexProgramClass clazz : classes) {
if (!appInfo.liveTypes.contains(clazz.type)) {
@@ -125,6 +128,7 @@
}
private boolean isAttributeReferencingPrunedItem(EnclosingMethodAttribute attr) {
+ AppInfoWithLiveness appInfo = appView.appInfo();
return
(attr.getEnclosingClass() != null
&& !appInfo.liveTypes.contains(attr.getEnclosingClass()))
@@ -133,6 +137,7 @@
}
private boolean isAttributeReferencingPrunedType(InnerClassAttribute attr) {
+ AppInfoWithLiveness appInfo = appView.appInfo();
if (!appInfo.liveTypes.contains(attr.getInner())) {
return true;
}
@@ -173,6 +178,8 @@
}
private DexEncodedMethod[] reachableMethods(List<DexEncodedMethod> methods, DexClass clazz) {
+ AppInfoWithLiveness appInfo = appView.appInfo();
+ InternalOptions options = appView.options();
int firstUnreachable = firstUnreachableIndex(methods, appInfo.liveMethods::contains);
// Return the original array if all methods are used.
if (firstUnreachable == -1) {
@@ -232,6 +239,7 @@
}
private DexEncodedField[] reachableFields(List<DexEncodedField> fields) {
+ AppInfoWithLiveness appInfo = appView.appInfo();
Predicate<DexField> isReachableOrReferencedField =
field ->
appInfo.liveFields.contains(field)
diff --git a/src/main/java/com/android/tools/r8/utils/InternalOptions.java b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
index e595762..29a6036 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -227,6 +227,7 @@
}
public Set<String> extensiveLoggingFilter = getExtensiveLoggingFilter();
+ public Set<String> extensiveFieldMinifierLoggingFilter = getExtensiveFieldMinifierLoggingFilter();
public Set<String> extensiveInterfaceMethodMinifierLoggingFilter =
getExtensiveInterfaceMethodMinifierLoggingFilter();
@@ -304,6 +305,19 @@
return ImmutableSet.of();
}
+ private static Set<String> getExtensiveFieldMinifierLoggingFilter() {
+ String property =
+ System.getProperty("com.android.tools.r8.extensiveFieldMinifierLoggingFilter");
+ if (property != null) {
+ ImmutableSet.Builder<String> builder = ImmutableSet.builder();
+ for (String method : property.split(";")) {
+ builder.add(method);
+ }
+ return builder.build();
+ }
+ return ImmutableSet.of();
+ }
+
private static Set<String> getExtensiveInterfaceMethodMinifierLoggingFilter() {
String property =
System.getProperty("com.android.tools.r8.extensiveInterfaceMethodMinifierLoggingFilter");
diff --git a/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java b/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java
index 60dc9ae..5a71add 100644
--- a/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java
+++ b/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java
@@ -9,13 +9,15 @@
import com.android.tools.r8.JctfTestSpecifications.Outcome;
import com.android.tools.r8.TestCondition.Runtime;
import com.android.tools.r8.TestCondition.RuntimeSet;
+import com.android.tools.r8.TestRuntime.CfVm;
+import com.android.tools.r8.TestRuntime.DexRuntime;
import com.android.tools.r8.ToolHelper.ArtCommandBuilder;
import com.android.tools.r8.ToolHelper.DexVm;
import com.android.tools.r8.ToolHelper.DexVm.Kind;
import com.android.tools.r8.ToolHelper.ProcessResult;
import com.android.tools.r8.errors.CompilationError;
+import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.origin.Origin;
-import com.android.tools.r8.shaking.ProguardRuleParserException;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.ArtErrorParser;
import com.android.tools.r8.utils.ArtErrorParser.ArtErrorInfo;
@@ -46,6 +48,7 @@
import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.function.BiFunction;
@@ -1526,19 +1529,53 @@
runArtTest(ToolHelper.getDexVm(), compilerUnderTest);
}
+ private static class CompilationOptions {
+ private final boolean disableInlining;
+ private final boolean disableClassInlining;
+ private final boolean disableUninstantiatedTypeOptimization;
+ private final boolean hasMissingClasses;
+
+ private CompilationOptions(TestSpecification spec) {
+ this.disableInlining = spec.disableInlining;
+ this.disableClassInlining = spec.disableClassInlining;
+ this.disableUninstantiatedTypeOptimization = spec.disableUninstantiatedTypeOptimization;
+ this.hasMissingClasses = spec.hasMissingClasses;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ CompilationOptions options = (CompilationOptions) o;
+ return disableInlining == options.disableInlining
+ && disableClassInlining == options.disableClassInlining
+ && disableUninstantiatedTypeOptimization == options.disableUninstantiatedTypeOptimization
+ && hasMissingClasses == options.hasMissingClasses;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(
+ disableInlining,
+ disableClassInlining,
+ disableUninstantiatedTypeOptimization,
+ hasMissingClasses);
+ }
+ }
+
private void executeCompilerUnderTest(
CompilerUnderTest compilerUnderTest,
Collection<String> fileNames,
String resultPath,
CompilationMode compilationMode,
- boolean disableInlining,
- boolean disableClassInlining,
- boolean disableUninstantiatedTypeOptimization,
- boolean hasMissingClasses)
+ CompilationOptions compilationOptions)
throws CompilationFailedException {
- executeCompilerUnderTest(compilerUnderTest, fileNames, resultPath, compilationMode, null,
- disableInlining, disableClassInlining, disableUninstantiatedTypeOptimization,
- hasMissingClasses);
+ executeCompilerUnderTest(
+ compilerUnderTest, fileNames, resultPath, compilationMode, null, compilationOptions);
}
private void executeCompilerUnderTest(
@@ -1547,10 +1584,7 @@
String resultPath,
CompilationMode mode,
String keepRulesFile,
- boolean disableInlining,
- boolean disableClassInlining,
- boolean disableUninstantiatedTypeOptimization,
- boolean hasMissingClasses)
+ CompilationOptions compilationOptions)
throws CompilationFailedException {
assert mode != null;
switch (compilerUnderTest) {
@@ -1698,20 +1732,20 @@
ToolHelper.runR8(
builder.build(),
options -> {
- if (disableInlining) {
+ if (compilationOptions.disableInlining) {
options.enableInlining = false;
}
- if (disableClassInlining) {
+ if (compilationOptions.disableClassInlining) {
options.enableClassInlining = false;
}
- if (disableUninstantiatedTypeOptimization) {
+ if (compilationOptions.disableUninstantiatedTypeOptimization) {
options.enableUninstantiatedTypeOptimization = false;
}
// Make sure we don't depend on this settings.
options.classInliningInstructionLimit = 10000;
options.lineNumberOptimization = LineNumberOptimization.OFF;
// Some tests actually rely on missing classes for what they test.
- options.ignoreMissingClasses = hasMissingClasses;
+ options.ignoreMissingClasses = compilationOptions.hasMissingClasses;
});
break;
}
@@ -1794,15 +1828,38 @@
noInlining);
}
- protected void runJctfTest(CompilerUnderTest compilerUnderTest, String classFilePath,
- String fullClassName)
- throws IOException, ProguardRuleParserException, ExecutionException,
- CompilationFailedException {
- Runtime runtime;
- if (compilerUnderTest == CompilerUnderTest.R8CF) {
- runtime = Runtime.JAVA;
+ private static Runtime getRuntime(TestRuntime vm) {
+ if (vm.isCf()) {
+ return Runtime.JAVA;
+ } else if (vm.isDex()) {
+ return Runtime.fromDexVmVersion(vm.asDex().getVm().getVersion());
} else {
- runtime = Runtime.fromDexVmVersion(ToolHelper.getDexVm().getVersion());
+ throw new Unreachable();
+ }
+ }
+
+ private static class VmSpec {
+ final TestRuntime vm;
+ final TestSpecification spec;
+
+ private VmSpec(TestRuntime vm, TestSpecification testSpecification) {
+ this.vm = vm;
+ this.spec = testSpecification;
+ }
+ }
+
+ protected void runJctfTest(
+ CompilerUnderTest compilerUnderTest, String classFilePath, String fullClassName)
+ throws IOException, CompilationFailedException {
+ List<TestRuntime> vms = new ArrayList<>();
+ if (compilerUnderTest == CompilerUnderTest.R8CF) {
+ for (CfVm vm : TestParametersBuilder.getAvailableCfVms()) {
+ vms.add(new TestRuntime.CfRuntime(vm));
+ }
+ } else {
+ for (DexVm vm : TestParametersBuilder.getAvailableDexVms()) {
+ vms.add(new DexRuntime(vm));
+ }
}
CompilerUnderTest firstCompilerUnderTest =
@@ -1811,19 +1868,28 @@
: compilerUnderTest;
CompilationMode compilationMode = defaultCompilationMode(compilerUnderTest);
- File resultDir = temp.newFolder(firstCompilerUnderTest.toString().toLowerCase() + "-output");
+ List<VmSpec> vmSpecs = new ArrayList<>();
+ for (TestRuntime vm : vms) {
+ File resultDir =
+ temp.newFolder(
+ firstCompilerUnderTest.toString().toLowerCase() + "-output-" + vm.toString());
- TestSpecification specification =
- JctfTestSpecifications.getExpectedOutcome(
- name,
- firstCompilerUnderTest,
- runtime,
- compilationMode,
- compilerUnderTest == CompilerUnderTest.R8CF
- ? jctfOutcomeToSpecificationJava(name, resultDir)
- : jctfOutcomeToSpecification(name, DexTool.NONE, resultDir, ToolHelper.getDexVm()));
+ TestSpecification specification =
+ JctfTestSpecifications.getExpectedOutcome(
+ name,
+ firstCompilerUnderTest,
+ getRuntime(vm),
+ compilationMode,
+ compilerUnderTest == CompilerUnderTest.R8CF
+ ? jctfOutcomeToSpecificationJava(name, resultDir)
+ : jctfOutcomeToSpecification(name, DexTool.NONE, resultDir, vm.asDex().getVm()));
- if (specification.skipTest) {
+ if (!specification.skipTest) {
+ vmSpecs.add(new VmSpec(vm, specification));
+ }
+ }
+
+ if (vmSpecs.isEmpty()) {
return;
}
@@ -1887,62 +1953,82 @@
}
if (compilerUnderTest == CompilerUnderTest.R8CF) {
- runJctfTestDoRunOnJava(fileNames, specification, fullClassName, compilationMode, resultDir);
- } else {
-
- runJctfTestDoRunOnArt(
- fileNames,
- specification,
- firstCompilerUnderTest,
- fullClassName,
- compilationMode,
- ToolHelper.getDexVm(),
- resultDir);
+ assert vmSpecs.size() == 1
+ : "Running the same test on multiple JVMs should share the same build.";
+ for (VmSpec vmSpec : vmSpecs) {
+ runJctfTestDoRunOnJava(
+ fileNames, vmSpec.spec, fullClassName, compilationMode, vmSpec.vm.asCf().getVm());
+ }
+ return;
}
- // second pass if D8_R8Debug
- if (compilerUnderTest == CompilerUnderTest.R8_AFTER_D8) {
- List<String> d8OutputFileNames =
- Files.list(resultDir.toPath())
- .filter(FileUtils::isDexFile)
- .map(Path::toString)
- .collect(Collectors.toList());
- File r8ResultDir = temp.newFolder("r8-output");
- compilationMode = CompilationMode.DEBUG;
- specification =
+ CompilationOptions compilationOptions = null;
+ File compiledDir = temp.newFolder();
+ for (VmSpec vmSpec : vmSpecs) {
+ CompilationOptions thisOptions = new CompilationOptions(vmSpec.spec);
+ if (compilationOptions == null) {
+ compilationOptions = thisOptions;
+ executeCompilerUnderTest(
+ firstCompilerUnderTest,
+ fileNames,
+ compiledDir.getAbsolutePath(),
+ compilationMode,
+ compilationOptions);
+ } else {
+ // For now compile options don't change across vms.
+ assert compilationOptions.equals(thisOptions);
+ }
+ Files.copy(
+ compiledDir.toPath().resolve("classes.dex"),
+ vmSpec.spec.directory.toPath().resolve("classes.dex"));
+ runJctfTestDoRunOnArt(fileNames, vmSpec.spec, fullClassName, vmSpec.vm.asDex().getVm());
+ }
+
+ if (compilerUnderTest != CompilerUnderTest.R8_AFTER_D8) {
+ return;
+ }
+
+ // Second pass (R8), if R8_AFTER_D8.
+ CompilationOptions r8CompilationOptions = null;
+ File r8CompiledDir = temp.newFolder();
+ for (VmSpec vmSpec : vmSpecs) {
+ File r8ResultDir = temp.newFolder("r8-output-" + vmSpec.vm.toString());
+ TestSpecification specification =
JctfTestSpecifications.getExpectedOutcome(
name,
CompilerUnderTest.R8_AFTER_D8,
- runtime,
- compilationMode,
- jctfOutcomeToSpecification(name, DexTool.DX, r8ResultDir, ToolHelper.getDexVm()));
+ getRuntime(vmSpec.vm),
+ CompilationMode.RELEASE,
+ jctfOutcomeToSpecification(name, DexTool.DX, r8ResultDir, vmSpec.vm.asDex().getVm()));
if (specification.skipTest) {
- return;
+ continue;
}
- runJctfTestDoRunOnArt(
- d8OutputFileNames,
- specification,
- CompilerUnderTest.R8,
- fullClassName,
- compilationMode,
- ToolHelper.getDexVm(),
- r8ResultDir);
+ CompilationOptions thisOptions = new CompilationOptions(vmSpec.spec);
+ if (r8CompilationOptions == null) {
+ r8CompilationOptions = thisOptions;
+ executeCompilerUnderTest(
+ CompilerUnderTest.R8,
+ Collections.singletonList(compiledDir.toPath().resolve("classes.dex").toString()),
+ r8CompiledDir.getAbsolutePath(),
+ CompilationMode.RELEASE,
+ r8CompilationOptions);
+ } else {
+ // For now compile options don't change across vms.
+ assert r8CompilationOptions.equals(thisOptions);
+ }
+ Files.copy(
+ r8CompiledDir.toPath().resolve("classes.dex"),
+ specification.directory.toPath().resolve("classes.dex"));
+ runJctfTestDoRunOnArt(fileNames, specification, fullClassName, vmSpec.vm.asDex().getVm());
}
}
private void runJctfTestDoRunOnArt(
Collection<String> fileNames,
TestSpecification specification,
- CompilerUnderTest compilerUnderTest,
String fullClassName,
- CompilationMode mode,
- DexVm dexVm,
- File resultDir)
- throws IOException, CompilationFailedException {
- executeCompilerUnderTest(compilerUnderTest, fileNames, resultDir.getAbsolutePath(), mode,
- specification.disableInlining, specification.disableClassInlining,
- specification.disableUninstantiatedTypeOptimization, specification.hasMissingClasses);
-
+ DexVm dexVm)
+ throws IOException {
if (!ToolHelper.artSupported() && !ToolHelper.dealsWithGoldenFiles()) {
return;
}
@@ -1951,16 +2037,9 @@
// Collect the generated dex files.
File[] outputFiles =
- resultDir.listFiles((File file) -> file.getName().endsWith(".dex"));
- if (outputFiles.length == 1) {
- // Just run Art on classes.dex.
- processedFile = outputFiles[0];
- } else {
- // Run Art on JAR file with multiple dex files.
- processedFile
- = temp.getRoot().toPath().resolve(specification.name + ".jar").toFile();
- buildJar(outputFiles, processedFile);
- }
+ specification.directory.listFiles((File file) -> file.getName().endsWith(".dex"));
+ assert outputFiles.length == 1;
+ processedFile = outputFiles[0];
boolean compileOnly = System.getProperty("jctf_compile_only", "0").equals("1");
if (compileOnly || specification.skipRun) {
@@ -1976,7 +2055,7 @@
if (dexVm.isNewerThan(DexVm.ART_4_4_4_HOST)) {
builder.appendArtOption("-Ximage:/system/non/existent/image.art");
}
- for (String s : ToolHelper.getBootLibs()) {
+ for (String s : ToolHelper.getBootLibs(dexVm)) {
builder.appendBootClassPath(new File(s).getCanonicalPath());
}
builder.setMainClass(JUNIT_TEST_RUNNER);
@@ -2003,20 +2082,18 @@
TestSpecification specification,
String fullClassName,
CompilationMode mode,
- File resultDir)
+ CfVm vm)
throws IOException, CompilationFailedException {
+ assert TestParametersBuilder.isSystemJdk(vm);
if (JctfTestSpecifications.compilationFailsWithAsmMethodTooLarge.contains(specification.name)) {
expectException(org.objectweb.asm.MethodTooLargeException.class);
}
executeCompilerUnderTest(
CompilerUnderTest.R8CF,
fileNames,
- resultDir.getAbsolutePath(),
+ specification.directory.getAbsolutePath(),
mode,
- specification.disableInlining,
- specification.disableClassInlining,
- specification.disableUninstantiatedTypeOptimization,
- specification.hasMissingClasses);
+ new CompilationOptions(specification));
boolean compileOnly = System.getProperty("jctf_compile_only", "0").equals("1");
@@ -2033,7 +2110,7 @@
// running the test.
ProcessResult result =
ToolHelper.runJava(
- resultDir.toPath(),
+ specification.directory.toPath(),
"-Xmx" + ToolHelper.BOT_MAX_HEAP_SIZE,
JUNIT_TEST_RUNNER,
fullClassName);
@@ -2168,9 +2245,11 @@
expectException(CompilationError.class);
try {
executeCompilerUnderTest(
- compilerUnderTest, fileNames, resultDir.getCanonicalPath(), compilationMode,
- specification.disableInlining, specification.disableClassInlining,
- specification.disableUninstantiatedTypeOptimization, specification.hasMissingClasses);
+ compilerUnderTest,
+ fileNames,
+ resultDir.getCanonicalPath(),
+ compilationMode,
+ new CompilationOptions(specification));
} catch (CompilationFailedException e) {
throw new CompilationError(e.getMessage(), e);
}
@@ -2179,16 +2258,20 @@
} else if (specification.failsWithX8) {
expectException(Throwable.class);
executeCompilerUnderTest(
- compilerUnderTest, fileNames, resultDir.getCanonicalPath(), compilationMode,
- specification.disableInlining, specification.disableClassInlining,
- specification.disableUninstantiatedTypeOptimization, specification.hasMissingClasses);
+ compilerUnderTest,
+ fileNames,
+ resultDir.getCanonicalPath(),
+ compilationMode,
+ new CompilationOptions(specification));
System.err.println("Should have failed R8/D8 compilation with an exception.");
return;
} else {
executeCompilerUnderTest(
- compilerUnderTest, fileNames, resultDir.getCanonicalPath(), compilationMode,
- specification.disableInlining, specification.disableClassInlining,
- specification.disableUninstantiatedTypeOptimization, specification.hasMissingClasses);
+ compilerUnderTest,
+ fileNames,
+ resultDir.getCanonicalPath(),
+ compilationMode,
+ new CompilationOptions(specification));
}
if (!specification.skipRun
diff --git a/src/test/java/com/android/tools/r8/TestParametersBuilder.java b/src/test/java/com/android/tools/r8/TestParametersBuilder.java
index 8059f21..4cefe0c 100644
--- a/src/test/java/com/android/tools/r8/TestParametersBuilder.java
+++ b/src/test/java/com/android/tools/r8/TestParametersBuilder.java
@@ -158,7 +158,7 @@
return isSystemJdk(vm);
}
- private static List<CfVm> getAvailableCfVms() {
+ public static List<CfVm> getAvailableCfVms() {
String cfVmsProperty = System.getProperty("cf_vms");
if (cfVmsProperty != null) {
return Arrays.stream(cfVmsProperty.split(":"))
@@ -174,7 +174,7 @@
}
}
- private static List<DexVm> getAvailableDexVms() {
+ public static List<DexVm> getAvailableDexVms() {
String dexVmsProperty = System.getProperty("dex_vms");
if (dexVmsProperty != null) {
return Arrays.stream(dexVmsProperty.split(":"))
diff --git a/src/test/java/com/android/tools/r8/ToolHelper.java b/src/test/java/com/android/tools/r8/ToolHelper.java
index 7467bfa..1ab645d 100644
--- a/src/test/java/com/android/tools/r8/ToolHelper.java
+++ b/src/test/java/com/android/tools/r8/ToolHelper.java
@@ -704,10 +704,10 @@
}
}
- public static List<String> getBootLibs() {
- String prefix = getArtDir(getDexVm()) + "/";
+ public static List<String> getBootLibs(DexVm dexVm) {
+ String prefix = getArtDir(dexVm) + "/";
List<String> result = new ArrayList<>();
- BOOT_LIBS.get(getDexVm()).stream().forEach(x -> result.add(prefix + "framework/" + x));
+ BOOT_LIBS.get(dexVm).stream().forEach(x -> result.add(prefix + "framework/" + x));
return result;
}
diff --git a/src/test/java/com/android/tools/r8/naming/b128656974/B128656974.java b/src/test/java/com/android/tools/r8/naming/b128656974/B128656974.java
new file mode 100644
index 0000000..100b359
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/naming/b128656974/B128656974.java
@@ -0,0 +1,129 @@
+// 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.b128656974;
+
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isRenamed;
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.junit.Assert.assertNotEquals;
+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.naming.testclasses.Greeting;
+import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.FieldSubject;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
+import org.junit.Ignore;
+import org.junit.Test;
+
+public class B128656974 extends TestBase {
+
+ @Ignore("b/128656974")
+ @Test
+ public void testField() throws Exception {
+ Class<?> main = TestClassMainForField.class;
+ testForR8(Backend.DEX)
+ .addProgramClasses(
+ Greeting.class, Greeting.getGreetingBase(), TestClassSub.class, main)
+ .enableClassInliningAnnotations()
+ .enableInliningAnnotations()
+ .enableMergeAnnotations()
+ .addKeepMainRule(main)
+ .addKeepRules(
+ "-keepclassmembernames class "
+ + TestClassSub.class.getTypeName()
+ + "{ static java.lang.String a; }")
+ .run(main)
+ .assertSuccessWithOutput(StringUtils.lines("TestClassSub.greeting", "TestClassSub.a"))
+ .inspect(inspector -> {
+ ClassSubject greetingBase = inspector.clazz(Greeting.getGreetingBase());
+ assertThat(greetingBase, isPresent());
+ FieldSubject greeting = greetingBase.uniqueFieldWithName("greeting");
+ assertThat(greeting, isPresent());
+ assertThat(greeting, isRenamed());
+ assertNotEquals("a", greeting.getFinalName());
+ });
+ }
+
+ @NeverClassInline
+ static class TestClassSub extends Greeting {
+ // Since this name is kept, renaming of Greeting.greeting should avoid `a`.
+ // Otherwise, we'll see Out-of-order field_ids due to the duplicate fields.
+ static String a;
+
+ TestClassSub() {
+ greeting = "TestClassSub.greeting";
+ a = "TestClassSub.a";
+ }
+
+ @Override
+ public String toString(){
+ return greeting + System.lineSeparator() + a;
+ }
+ }
+
+ static class TestClassMainForField {
+ public static void main(String[] args) {
+ TestClassSub instance = new TestClassSub();
+ System.out.println(instance.toString());
+ }
+ }
+
+ @Test
+ public void testMethod() throws Exception {
+ Class<?> main = TestClassMainForMethod.class;
+ testForR8(Backend.DEX)
+ .addProgramClasses(
+ TestClassBase.class, TestClassSub2.class, main)
+ .enableMergeAnnotations()
+ .enableClassInliningAnnotations()
+ .enableInliningAnnotations()
+ .addKeepMainRule(main)
+ .addKeepRules(
+ "-keepclassmembernames class "
+ + TestClassSub2.class.getTypeName()
+ + "{ void a(...); }")
+ .run(main)
+ .assertSuccessWithOutput(StringUtils.lines("TestClassSub2::a", "TestClassBase::foo"))
+ .inspect(inspector -> {
+ ClassSubject base = inspector.clazz(TestClassBase.class);
+ assertThat(base, isPresent());
+ MethodSubject foo = base.uniqueMethodWithName("foo");
+ assertThat(foo, isPresent());
+ assertThat(foo, isRenamed());
+ assertNotEquals("a", foo.getFinalName());
+ });
+ }
+
+ @NeverMerge
+ static class TestClassBase {
+ @NeverInline
+ void foo() {
+ System.out.println("TestClassBase::foo");
+ }
+ }
+
+ @NeverClassInline
+ static class TestClassSub2 extends TestClassBase {
+ // Since this name is kept, renaming of TestClassBase#foo should avoid `a`.
+ // Otherwise, we'll see Out-of-order method_ids due to the duplicate methods.
+ @NeverInline
+ void a() {
+ System.out.println("TestClassSub2::a");
+ }
+ }
+
+ static class TestClassMainForMethod {
+ public static void main(String[] args) {
+ TestClassSub2 instance = new TestClassSub2();
+ instance.a();
+ instance.foo();
+ }
+ }
+
+}
diff --git a/src/test/java/com/android/tools/r8/proguard/configuration/InheritanceClauseWithDisjunctionTest.java b/src/test/java/com/android/tools/r8/proguard/configuration/InheritanceClauseWithDisjunctionTest.java
new file mode 100644
index 0000000..6a26c3b
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/proguard/configuration/InheritanceClauseWithDisjunctionTest.java
@@ -0,0 +1,275 @@
+// 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.proguard.configuration;
+
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.fail;
+
+import com.android.tools.r8.CompilationFailedException;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestShrinkerBuilder;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.google.common.collect.ImmutableList;
+import java.util.List;
+import java.util.function.Consumer;
+import org.junit.Ignore;
+import org.junit.Test;
+
+public class InheritanceClauseWithDisjunctionTest extends TestBase {
+
+ @Ignore("b/128503974")
+ @Test
+ public void testExtendsClauseWithR8() throws Exception {
+ runTest(
+ testForR8(Backend.DEX),
+ getKeepRulesForExtendsClauseTests(),
+ InheritanceClauseWithDisjunctionTest::inspectExtendsClauseTests);
+ }
+
+ @Test
+ public void testExtendsClauseWithProguard() throws Exception {
+ runTest(
+ testForProguard(),
+ getKeepRulesForExtendsClauseTests(),
+ InheritanceClauseWithDisjunctionTest::inspectExtendsClauseTests);
+ }
+
+ private static List<String> getKeepRulesForExtendsClauseTests() {
+ return ImmutableList.of(
+ "-keep class * extends "
+ + InheritanceClauseWithDisjunctionTestClassA.class.getTypeName()
+ + ", "
+ + InheritanceClauseWithDisjunctionTestClassB.class.getTypeName()
+ + ", "
+ + InheritanceClauseWithDisjunctionTestClassC.class.getTypeName());
+ }
+
+ private static void inspectExtendsClauseTests(CodeInspector inspector) {
+ // ASub extends A and BSub extends B. A and B are kept because Proguard presumably does not
+ // merge them into ASub and BSub, respectively.
+ assertEquals(4, inspector.allClasses().size());
+ assertThat(inspector.clazz(InheritanceClauseWithDisjunctionTestClassA.class), isPresent());
+ assertThat(inspector.clazz(InheritanceClauseWithDisjunctionTestClassASub.class), isPresent());
+ assertThat(inspector.clazz(InheritanceClauseWithDisjunctionTestClassB.class), isPresent());
+ assertThat(inspector.clazz(InheritanceClauseWithDisjunctionTestClassBSub.class), isPresent());
+ }
+
+ @Ignore("b/128503974")
+ @Test
+ public void testExtendsClauseWithNegation1WithR8() throws Exception {
+ runTest(
+ testForR8(Backend.DEX),
+ getKeepRulesForExtendsClauseWithNegation1Tests(),
+ InheritanceClauseWithDisjunctionTest::inspectExtendsClauseWithNegation1Tests);
+ }
+
+ @Test
+ public void testExtendsClauseWithNegation1WithProguard() throws Exception {
+ runTest(
+ testForProguard(),
+ getKeepRulesForExtendsClauseWithNegation1Tests(),
+ InheritanceClauseWithDisjunctionTest::inspectExtendsClauseWithNegation1Tests);
+ }
+
+ private static List<String> getKeepRulesForExtendsClauseWithNegation1Tests() {
+ return ImmutableList.of(
+ "-keep class * extends "
+ + InheritanceClauseWithDisjunctionTestClassA.class.getTypeName()
+ + ", !"
+ + InheritanceClauseWithDisjunctionTestClassB.class.getTypeName());
+ }
+
+ private static void inspectExtendsClauseWithNegation1Tests(CodeInspector inspector) {
+ // Strangely, BSub is kept, although it does not extend A and it extends B.
+ assertEquals(11, inspector.allClasses().size());
+ }
+
+ @Ignore("b/128503974")
+ @Test
+ public void testExtendsClauseWithNegation2WithR8() throws Exception {
+ runTest(
+ testForR8(Backend.DEX),
+ getKeepRulesForExtendsClauseWithNegation2Tests(),
+ InheritanceClauseWithDisjunctionTest::inspectExtendsClauseWithNegation2Tests);
+ }
+
+ @Test
+ public void testExtendsClauseWithNegation2WithProguard() throws Exception {
+ runTest(
+ testForProguard(),
+ getKeepRulesForExtendsClauseWithNegation2Tests(),
+ InheritanceClauseWithDisjunctionTest::inspectExtendsClauseWithNegation2Tests);
+ }
+
+ private static List<String> getKeepRulesForExtendsClauseWithNegation2Tests() {
+ return ImmutableList.of(
+ "-keep class * extends !"
+ + InheritanceClauseWithDisjunctionTestClassB.class.getTypeName()
+ + ", "
+ + InheritanceClauseWithDisjunctionTestClassA.class.getTypeName());
+ }
+
+ private static void inspectExtendsClauseWithNegation2Tests(CodeInspector inspector) {
+ // Strangely, all the types that do not extend A have not kept.
+ assertEquals(2, inspector.allClasses().size());
+ assertThat(inspector.clazz(InheritanceClauseWithDisjunctionTestClassA.class), isPresent());
+ assertThat(inspector.clazz(InheritanceClauseWithDisjunctionTestClassASub.class), isPresent());
+ }
+
+ @Ignore("b/128503974")
+ @Test
+ public void testExtendsClauseWithMatchAllNegationWithR8() throws Exception {
+ runTest(
+ testForR8(Backend.DEX),
+ getKeepRulesForExtendsClauseWithMatchAllNegationTests(),
+ InheritanceClauseWithDisjunctionTest::inspectExtendsClauseWithMatchAllNegationTests);
+ }
+
+ @Test
+ public void testExtendsClauseWithMatchAllNegationWithProguard() throws Exception {
+ runTest(
+ testForProguard(),
+ getKeepRulesForExtendsClauseWithMatchAllNegationTests(),
+ InheritanceClauseWithDisjunctionTest::inspectExtendsClauseWithMatchAllNegationTests);
+ }
+
+ private static List<String> getKeepRulesForExtendsClauseWithMatchAllNegationTests() {
+ return ImmutableList.of(
+ "-keep class * extends "
+ + InheritanceClauseWithDisjunctionTestClassA.class.getTypeName()
+ + ", !"
+ + InheritanceClauseWithDisjunctionTestClassA.class.getTypeName());
+ }
+
+ private static void inspectExtendsClauseWithMatchAllNegationTests(CodeInspector inspector) {
+ // Every type extends A or does not extend A.
+ assertEquals(11, inspector.allClasses().size());
+ }
+
+ @Ignore("b/128503974")
+ @Test
+ public void testImplementsClauseWithR8() throws Exception {
+ runTest(
+ testForR8(Backend.DEX),
+ getKeepRulesForImplementsClauseTests(),
+ InheritanceClauseWithDisjunctionTest::inspectImplementsClauseTests);
+ }
+
+ @Test
+ public void testImplementsClauseWithProguard() throws Exception {
+ try {
+ runTest(
+ testForProguard(),
+ getKeepRulesForImplementsClauseTests(),
+ InheritanceClauseWithDisjunctionTest::inspectImplementsClauseTests);
+ fail();
+ } catch (CompilationFailedException e) {
+ // Strangely, nothing matches implements I or J (not even InheritanceClauseWithDisjunction-
+ // TestClassIJSub, which implements both I and J!).
+ assertThat(e.getMessage(), containsString("The output jar is empty"));
+ }
+ }
+
+ private static List<String> getKeepRulesForImplementsClauseTests() {
+ return ImmutableList.of(
+ "-keep class * implements "
+ + InheritanceClauseWithDisjunctionTestInterfaceI.class.getTypeName()
+ + ", "
+ + InheritanceClauseWithDisjunctionTestInterfaceJ.class.getTypeName()
+ + ", "
+ + InheritanceClauseWithDisjunctionTestInterfaceK.class.getTypeName());
+ }
+
+ private static void inspectImplementsClauseTests(CodeInspector inspector) {
+ // Strangely, nothing matches implements I or J (not even InheritanceClauseWithDisjunctionTest-
+ // ClassIJSub, which implements both I and J!).
+ assertEquals(0, inspector.allClasses().size());
+ }
+
+ @Ignore("b/128503974")
+ @Test
+ public void testImplementsClauseWithNegationWithR8() throws Exception {
+ runTest(
+ testForR8(Backend.DEX),
+ getKeepRulesForImplementsClauseTests(),
+ InheritanceClauseWithDisjunctionTest::inspectImplementsClauseWithNegationTests);
+ }
+
+ @Test
+ public void testImplementsClauseWithNegationWithProguard() throws Exception {
+ runTest(
+ testForProguard(),
+ getKeepRulesForImplementsClauseWithNegationTests(),
+ InheritanceClauseWithDisjunctionTest::inspectImplementsClauseWithNegationTests);
+ }
+
+ private static List<String> getKeepRulesForImplementsClauseWithNegationTests() {
+ return ImmutableList.of(
+ "-keep class * implements "
+ + InheritanceClauseWithDisjunctionTestInterfaceI.class.getTypeName()
+ + ", !"
+ + InheritanceClauseWithDisjunctionTestInterfaceI.class.getTypeName());
+ }
+
+ private static void inspectImplementsClauseWithNegationTests(CodeInspector inspector) {
+ // Every type implements I or does not implement I.
+ assertEquals(11, inspector.allClasses().size());
+ }
+
+ private static void runTest(
+ TestShrinkerBuilder<?, ?, ?, ?, ?> builder,
+ List<String> keepRules,
+ Consumer<CodeInspector> consumer)
+ throws Exception {
+ builder
+ .addProgramClasses(
+ InheritanceClauseWithDisjunctionTestClassA.class,
+ InheritanceClauseWithDisjunctionTestClassASub.class,
+ InheritanceClauseWithDisjunctionTestClassB.class,
+ InheritanceClauseWithDisjunctionTestClassBSub.class,
+ InheritanceClauseWithDisjunctionTestClassC.class,
+ InheritanceClauseWithDisjunctionTestInterfaceI.class,
+ InheritanceClauseWithDisjunctionTestClassISub.class,
+ InheritanceClauseWithDisjunctionTestInterfaceJ.class,
+ InheritanceClauseWithDisjunctionTestClassJSub.class,
+ InheritanceClauseWithDisjunctionTestInterfaceK.class,
+ InheritanceClauseWithDisjunctionTestClassIJKSub.class)
+ .addKeepRules(keepRules)
+ .compile()
+ .inspect(consumer);
+ }
+}
+
+class InheritanceClauseWithDisjunctionTestClassA {}
+
+class InheritanceClauseWithDisjunctionTestClassASub
+ extends InheritanceClauseWithDisjunctionTestClassA {}
+
+class InheritanceClauseWithDisjunctionTestClassB {}
+
+class InheritanceClauseWithDisjunctionTestClassBSub
+ extends InheritanceClauseWithDisjunctionTestClassB {}
+
+class InheritanceClauseWithDisjunctionTestClassC {}
+
+interface InheritanceClauseWithDisjunctionTestInterfaceI {}
+
+class InheritanceClauseWithDisjunctionTestClassISub
+ implements InheritanceClauseWithDisjunctionTestInterfaceI {}
+
+interface InheritanceClauseWithDisjunctionTestInterfaceJ {}
+
+class InheritanceClauseWithDisjunctionTestClassJSub
+ implements InheritanceClauseWithDisjunctionTestInterfaceJ {}
+
+interface InheritanceClauseWithDisjunctionTestInterfaceK {}
+
+class InheritanceClauseWithDisjunctionTestClassIJKSub
+ implements InheritanceClauseWithDisjunctionTestInterfaceI,
+ InheritanceClauseWithDisjunctionTestInterfaceJ,
+ InheritanceClauseWithDisjunctionTestInterfaceK {}
diff --git a/tools/archive.py b/tools/archive.py
index 687844a..25e6a4f 100755
--- a/tools/archive.py
+++ b/tools/archive.py
@@ -91,6 +91,10 @@
def GetMavenUrl(is_master):
return GetVersionDestination('http://storage.googleapis.com/', '', is_master)
+def SetRLimitToMax():
+ (soft, hard) = resource.getrlimit(resource.RLIMIT_NOFILE)
+ resource.setrlimit(resource.RLIMIT_NOFILE, (hard, hard))
+
def PrintResourceInfo():
(soft, hard) = resource.getrlimit(resource.RLIMIT_NOFILE)
print('INFO: Open files soft limit: %s' % soft)
@@ -101,10 +105,8 @@
if not utils.is_bot() and not options.dry_run:
raise Exception('You are not a bot, don\'t archive builds')
- if utils.is_old_bot():
- print("Archiving is disabled on old bots.")
- return
-
+ if utils.is_bot():
+ SetRLimitToMax()
PrintResourceInfo()
# Create maven release which uses a build that exclude dependencies.
create_maven_release.main(["--out", utils.LIBS])
diff --git a/tools/create_jctf_tests.py b/tools/create_jctf_tests.py
index 28dde99..bc065d9 100755
--- a/tools/create_jctf_tests.py
+++ b/tools/create_jctf_tests.py
@@ -129,7 +129,6 @@
relative_package = package[idx + len(dot_java_dot):]
generate_test(class_name, 'd8', 'R8_AFTER_D8', relative_package)
- generate_test(class_name, 'r8', 'R8', relative_package)
generate_test(class_name, 'r8cf', 'R8CF', relative_package)
diff --git a/tools/internal_test.py b/tools/internal_test.py
index 032f1fe..a9a90eb 100755
--- a/tools/internal_test.py
+++ b/tools/internal_test.py
@@ -193,9 +193,6 @@
print('\n\n%s had value:\n%s' % (to_print, value))
def run_bot():
- if utils.is_old_bot():
- print('Not running on on old bot, please see: https://ci.chromium.org/p/r8')
- return
print_magic_file_state()
# Ensure that there is nothing currently scheduled (broken/stopped run)
for magic in ALL_MAGIC:
diff --git a/tools/run_on_as_app.py b/tools/run_on_as_app.py
index cc21bb3..6ab3546 100755
--- a/tools/run_on_as_app.py
+++ b/tools/run_on_as_app.py
@@ -584,7 +584,8 @@
env_vars = {}
env_vars['ANDROID_HOME'] = utils.getAndroidHome()
- env_vars['JAVA_OPTS'] = '-ea:com.android.tools.r8...'
+ if not options.disable_assertions:
+ env_vars['JAVA_OPTS'] = '-ea:com.android.tools.r8...'
releaseTarget = app.releaseTarget
if not releaseTarget:
@@ -760,9 +761,16 @@
# is 'r8'.
entry_point = 'com.android.tools.r8.R8'
- cmd = [jdk.GetJavaExecutable(), '-ea:com.android.tools.r8...', '-cp', r8_jar,
- entry_point, '--release', '--min-api', str(min_sdk), '--pg-conf',
- proguard_config_file, '--lib', android_jar, '--output', zip_dest, apk]
+ cmd = ([jdk.GetJavaExecutable()] +
+ (['-ea:com.android.tools.r8...']
+ if not options.disable_assertions
+ else []) +
+ ['-cp', r8_jar, entry_point,
+ '--release', '--min-api', str(min_sdk),
+ '--pg-conf', proguard_config_file,
+ '--lib', android_jar,
+ '--output', zip_dest,
+ apk])
for android_optional_jar in utils.get_android_optional_jars(compile_sdk):
cmd.append('--lib')
@@ -925,6 +933,10 @@
result.add_option('--app',
help='What app to run on',
choices=GetAllAppNames())
+ result.add_option('--disable-assertions',
+ help='Disable assertions when compiling',
+ default=False,
+ action='store_true')
result.add_option('--download-only', '--download_only',
help='Whether to download apps without any compilation',
default=False,
diff --git a/tools/test.py b/tools/test.py
index 06aefca..6f664eb 100755
--- a/tools/test.py
+++ b/tools/test.py
@@ -141,9 +141,13 @@
def Main():
(options, args) = ParseOptions()
if utils.is_bot():
- gradle.RunGradle(['clean'])
+ gradle.RunGradle(['--no-daemon', 'clean'])
gradle_args = ['--stacktrace']
+ if utils.is_bot():
+ # Bots don't like dangling processes
+ gradle_args.append('--no-daemon')
+
# Set all necessary Gradle properties and options first.
if options.shard_count:
assert options.shard_number
@@ -253,12 +257,13 @@
# Now run tests on selected runtime(s).
vms_to_test = [options.dex_vm] if options.dex_vm != "all" else ALL_ART_VMS
- # TODO(126683699): remove once we have single run
- if options.dex_vm == 'all' and options.only_jctf:
- vms_to_test = ["default", "5.1.1"]
# The full set of VMs is configured in the first run, then set to empty below.
dex_vms_property = ':'.join(vms_to_test)
+
+ if options.only_jctf:
+ vms_to_test = ['default']
+
for art_vm in vms_to_test:
vm_suffix = "_" + options.dex_vm_kind if art_vm != "default" else ""
return_code = gradle.RunGradle(
diff --git a/tools/utils.py b/tools/utils.py
index ec830f2..27df3b5 100644
--- a/tools/utils.py
+++ b/tools/utils.py
@@ -504,14 +504,8 @@
android_optional_jar for android_optional_jar in android_optional_jars
if os.path.isfile(android_optional_jar)]
-def is_new_bot():
- return 'SWARMING_BOT_ID' in os.environ
-
-def is_old_bot():
- return 'BUILDBOT_SLAVENAME' in os.environ
-
def is_bot():
- return 'USER' in os.environ and os.environ['USER'] == 'chrome-bot'
+ return 'SWARMING_BOT_ID' in os.environ
def uncompressed_size(path):
return sum(z.file_size for z in zipfile.ZipFile(path).infolist())