Merge "CSE must not remove instructions related to debug info"
diff --git a/build.gradle b/build.gradle
index f13fa61..5cdfd45 100644
--- a/build.gradle
+++ b/build.gradle
@@ -7,7 +7,6 @@
apply plugin: 'java'
apply plugin: 'idea'
apply plugin: 'com.google.protobuf'
-apply plugin: 'com.github.johnrengelman.shadow'
apply plugin: 'com.cookpad.android.licensetools'
apply from: 'copyAdditionalJctfCommonFiles.gradle'
@@ -29,8 +28,12 @@
}
dependencies {
classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.1'
- classpath 'com.github.jengelman.gradle.plugins:shadow:2.0.1'
classpath 'com.cookpad.android.licensetools:license-tools-plugin:0.23.0'
+ // TODO(ager): shadow does not support java9 class files yet. Once it does,
+ // we should use the offial version instead of our fork using ASM 6.0 to
+ // support java9.
+ // classpath 'com.github.jengelman.gradle.plugins:shadow:2.0.1'
+ classpath files("third_party/shadow/shadow-2.0.1.jar")
}
}
@@ -128,10 +131,10 @@
})
compile group: 'it.unimi.dsi', name: 'fastutil', version: '7.2.0'
compile group: 'org.apache.commons', name: 'commons-compress', version: '1.12'
- compile group: 'org.ow2.asm', name: 'asm', version: '5.1'
- compile group: 'org.ow2.asm', name: 'asm-commons', version: '5.1'
- compile group: 'org.ow2.asm', name: 'asm-tree', version: '5.1'
- compile group: 'org.ow2.asm', name: 'asm-util', version: '5.1'
+ compile group: 'org.ow2.asm', name: 'asm', version: '6.0_BETA'
+ compile group: 'org.ow2.asm', name: 'asm-commons', version: '6.0_BETA'
+ compile group: 'org.ow2.asm', name: 'asm-tree', version: '6.0_BETA'
+ compile group: 'org.ow2.asm', name: 'asm-util', version: '6.0_BETA'
testCompile sourceSets.examples.output
testCompile 'junit:junit:4.12'
testCompile group: 'org.smali', name: 'smali', version: '2.2b4'
@@ -140,7 +143,7 @@
jctfCommonCompile 'junit:junit:4.12'
jctfTestsCompile 'junit:junit:4.12'
jctfTestsCompile sourceSets.jctfCommon.output
- examplesAndroidOCompile group: 'org.ow2.asm', name: 'asm', version: '5.1'
+ examplesAndroidOCompile group: 'org.ow2.asm', name: 'asm', version: '6.0_BETA'
examplesCompile 'com.google.protobuf:protobuf-lite:3.0.0'
examplesRuntime 'com.google.protobuf:protobuf-lite:3.0.0'
supportLibs 'com.android.support:support-v4:25.4.0'
@@ -198,6 +201,7 @@
"jctf.tar.gz",
"kotlin.tar.gz",
"android_cts_baseline.tar.gz",
+ "shadow.tar.gz",
],
// All dex-vms have a fixed OS of Linux, as they are only supported on Linux, and will be run in a Docker
// container on other platforms where supported.
diff --git a/src/main/java/com/android/tools/r8/GenerateMainDexList.java b/src/main/java/com/android/tools/r8/GenerateMainDexList.java
index 5a18b41..6190cbd 100644
--- a/src/main/java/com/android/tools/r8/GenerateMainDexList.java
+++ b/src/main/java/com/android/tools/r8/GenerateMainDexList.java
@@ -37,7 +37,8 @@
private List<String> run(AndroidApp app) throws IOException, ExecutionException {
ExecutorService executor = ThreadUtils.getExecutorService(options);
- DexApplication application = new ApplicationReader(app, options, timing).read(executor);
+ DexApplication application =
+ new ApplicationReader(app, options, timing).read(executor).toDirect();
AppInfoWithSubtyping appInfo = new AppInfoWithSubtyping(application);
RootSet mainDexRootSet =
new RootSetBuilder(application, appInfo, options.mainDexKeepRules).run(executor);
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index 0b16963..d0badf2 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -222,7 +222,7 @@
+ oLevel.getName() + " and later (--min-api " + oLevel.getLevel() + ")");
}
DexApplication application =
- new ApplicationReader(inputApp, options, timing).read(executorService);
+ new ApplicationReader(inputApp, options, timing).read(executorService).toDirect();
AppInfoWithSubtyping appInfo = new AppInfoWithSubtyping(application);
RootSet rootSet;
@@ -309,7 +309,7 @@
// Calculate the automatic main dex list according to legacy multidex constraints.
// Add those classes to an eventual manual list of classes.
- application = new DexApplication.Builder(application)
+ application = application.builder()
.addToMainDexList(new MainDexListBuilder(mainDexBaseClasses, application).run())
.build();
}
diff --git a/src/main/java/com/android/tools/r8/bisect/BisectState.java b/src/main/java/com/android/tools/r8/bisect/BisectState.java
index 8c0626a..2e7d731 100644
--- a/src/main/java/com/android/tools/r8/bisect/BisectState.java
+++ b/src/main/java/com/android/tools/r8/bisect/BisectState.java
@@ -270,7 +270,7 @@
}
}
System.out.println("Class split is good: " + goodClasses + ", bad: " + badClasses);
- return new Builder(badApp).replaceProgramClasses(programClasses).build();
+ return badApp.builder().replaceProgramClasses(programClasses).build();
}
private DexProgramClass getGoodClass(DexProgramClass clazz) {
@@ -326,6 +326,7 @@
return classes;
}
+ @SuppressWarnings("deprecation")
private static String makeSignature(DexApplication app) {
List<DexProgramClass> classes = getSortedClasses(app);
StringBuilder builder = new StringBuilder();
diff --git a/src/main/java/com/android/tools/r8/dex/ApplicationReader.java b/src/main/java/com/android/tools/r8/dex/ApplicationReader.java
index 3e2aba5..9aa712a 100644
--- a/src/main/java/com/android/tools/r8/dex/ApplicationReader.java
+++ b/src/main/java/com/android/tools/r8/dex/ApplicationReader.java
@@ -25,6 +25,7 @@
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.JarApplicationReader;
import com.android.tools.r8.graph.JarClassFileReader;
+import com.android.tools.r8.graph.LazyLoadedDexApplication;
import com.android.tools.r8.naming.ProguardMapReader;
import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.ClassProvider;
@@ -73,7 +74,7 @@
public final DexApplication read(ExecutorService executorService)
throws IOException, ExecutionException {
timing.begin("DexApplication.read");
- final DexApplication.Builder builder = new DexApplication.Builder(itemFactory, timing);
+ final LazyLoadedDexApplication.Builder builder = DexApplication.builder(itemFactory, timing);
try {
List<Future<?>> futures = new ArrayList<>();
// Still preload some of the classes, primarily for two reasons:
@@ -142,7 +143,7 @@
}
}
- private void readMainDexList(DexApplication.Builder builder, ExecutorService executorService,
+ private void readMainDexList(DexApplication.Builder<?> builder, ExecutorService executorService,
List<Future<?>> futures) {
if (inputApp.hasMainDexList()) {
futures.add(executorService.submit(() -> {
@@ -254,7 +255,7 @@
: ClassProvider.combine(classKind, providers);
}
- void initializeLazyClassCollection(DexApplication.Builder builder) {
+ void initializeLazyClassCollection(LazyLoadedDexApplication.Builder builder) {
// Add all program classes to the builder.
for (DexProgramClass clazz : programClasses) {
builder.addProgramClass(clazz.asProgramClass());
diff --git a/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java b/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
index 6f92740..972c988 100644
--- a/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
+++ b/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
@@ -20,6 +20,7 @@
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.DexTypeList;
import com.android.tools.r8.graph.DexValue;
+import com.android.tools.r8.graph.ObjectToOffsetMapping;
import com.android.tools.r8.naming.MinifiedNameMapPrinter;
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.utils.AndroidApp;
@@ -32,6 +33,7 @@
import java.io.PrintWriter;
import java.io.Writer;
import java.util.LinkedHashMap;
+import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
@@ -148,18 +150,33 @@
}
Map<Integer, VirtualFile> newFiles = distributor.run();
- // Write the dex files and the Proguard mapping file in parallel. Use a linked hash map
- // as the order matters when addDexProgramData is called below.
- LinkedHashMap<VirtualFile, Future<byte[]>> dexDataFutures = new LinkedHashMap<>();
+ // Collect the indexed items sets for all files and perform JumboString processing.
+ // This is required to ensure that shared code blocks have a single and consistent code
+ // item that is valid for all dex files.
+ // Use a linked hash map as the order matters when addDexProgramData is called below.
+ Map<VirtualFile, Future<ObjectToOffsetMapping>> offsetMappingFutures = new LinkedHashMap<>();
for (int i = 0; i < newFiles.size(); i++) {
VirtualFile newFile = newFiles.get(i);
assert newFile.getId() == i;
assert !newFile.isEmpty();
if (!newFile.isEmpty()) {
- dexDataFutures.put(newFile, executorService.submit(() -> writeDexFile(newFile)));
+ offsetMappingFutures
+ .put(newFile, executorService.submit(() -> {
+ ObjectToOffsetMapping mapping = newFile.computeMapping(application);
+ rewriteCodeWithJumboStrings(mapping, newFile.classes(), application);
+ return mapping;
+ }));
}
}
+ // Generate the dex file contents.
+ LinkedHashMap<VirtualFile, Future<byte[]>> dexDataFutures = new LinkedHashMap<>();
+ for (VirtualFile newFile : offsetMappingFutures.keySet()) {
+ assert !newFile.isEmpty();
+ dexDataFutures.put(newFile,
+ executorService.submit(() -> writeDexFile(offsetMappingFutures.get(newFile).get())));
+ }
+
// Wait for all the spawned futures to terminate.
AndroidApp.Builder builder = AndroidApp.builder();
try {
@@ -199,12 +216,34 @@
}
}
- private byte[] writeDexFile(VirtualFile vfile) throws ApiLevelException {
- FileWriter fileWriter =
- new FileWriter(
- vfile.computeMapping(application), application, appInfo, options, namingLens);
- // The file writer now knows the indexes of the fixed sections including strings.
- fileWriter.rewriteCodeWithJumboStrings(vfile.classes());
+
+ /**
+ * Rewrites the code for all methods in the given file so that they use JumboString for at
+ * least the strings that require it in mapping.
+ * <p>
+ * If run multiple times on a class, the lowest index that is required to be a JumboString will
+ * be used.
+ */
+ private static void rewriteCodeWithJumboStrings(ObjectToOffsetMapping mapping,
+ List<DexProgramClass> classes, DexApplication application) {
+ // If there are no strings with jumbo indices at all this is a no-op.
+ if (!mapping.hasJumboStrings()) {
+ return;
+ }
+ // If the globally highest sorting string is not a jumbo string this is also a no-op.
+ if (application.highestSortingString != null &&
+ application.highestSortingString.slowCompareTo(mapping.getFirstJumboString()) < 0) {
+ return;
+ }
+ // At least one method needs a jumbo string.
+ for (DexProgramClass clazz : classes) {
+ clazz.forEachMethod(method -> method.rewriteCodeWithJumboStrings(mapping, application));
+ }
+ }
+
+ private byte[] writeDexFile(ObjectToOffsetMapping mapping)
+ throws ApiLevelException {
+ FileWriter fileWriter = new FileWriter(mapping, application, appInfo, options, namingLens);
// Collect the non-fixed sections.
fileWriter.collect();
// Generate and write the bytes.
diff --git a/src/main/java/com/android/tools/r8/dex/FileWriter.java b/src/main/java/com/android/tools/r8/dex/FileWriter.java
index eba5613..826aaba 100644
--- a/src/main/java/com/android/tools/r8/dex/FileWriter.java
+++ b/src/main/java/com/android/tools/r8/dex/FileWriter.java
@@ -155,37 +155,6 @@
return this;
}
- private void rewriteCodeWithJumboStrings(DexEncodedMethod method) {
- if (method.getCode() == null) {
- return;
- }
- DexCode code = method.getCode().asDexCode();
- if (code.highestSortingString != null) {
- if (mapping.getOffsetFor(code.highestSortingString) > Constants.MAX_NON_JUMBO_INDEX) {
- JumboStringRewriter rewriter =
- new JumboStringRewriter(method, mapping.getFirstJumboString(), options.itemFactory);
- rewriter.rewrite();
- }
- }
- }
-
- public FileWriter rewriteCodeWithJumboStrings(List<DexProgramClass> classes) {
- // If there are no strings with jumbo indices at all this is a no-op.
- if (!mapping.hasJumboStrings()) {
- return this;
- }
- // If the globally highest sorting string is not a jumbo string this is also a no-op.
- if (application.highestSortingString != null &&
- application.highestSortingString.slowCompareTo(mapping.getFirstJumboString()) < 0) {
- return this;
- }
- // At least one method needs a jumbo string.
- for (DexProgramClass clazz : classes) {
- clazz.forEachMethod(method -> rewriteCodeWithJumboStrings(method));
- }
- return this;
- }
-
public byte[] generate() throws ApiLevelException {
// Check restrictions on interface methods.
checkInterfaceMethods();
diff --git a/src/main/java/com/android/tools/r8/dex/JumboStringRewriter.java b/src/main/java/com/android/tools/r8/dex/JumboStringRewriter.java
index 4b97c51..2d0be98 100644
--- a/src/main/java/com/android/tools/r8/dex/JumboStringRewriter.java
+++ b/src/main/java/com/android/tools/r8/dex/JumboStringRewriter.java
@@ -120,6 +120,8 @@
DexDebugInfo newDebugInfo = rewriteDebugInfoOffsets();
// Set the new code on the method.
DexCode code = method.getCode().asDexCode();
+ // As we have rewritten the code, we now know that its highest string index that is not
+ // a jumbo-string is firstJumboString (actually the previous string, but we do not have that).
method.setDexCode(new DexCode(
code.registerSize,
code.incomingRegisterSize,
@@ -128,7 +130,7 @@
newTries,
newHandlers,
newDebugInfo,
- code.highestSortingString));
+ firstJumboString));
}
private void rewriteInstructionOffsets(List<Instruction> instructions) {
diff --git a/src/main/java/com/android/tools/r8/graph/AppInfo.java b/src/main/java/com/android/tools/r8/graph/AppInfo.java
index afd923c..2d111f0 100644
--- a/src/main/java/com/android/tools/r8/graph/AppInfo.java
+++ b/src/main/java/com/android/tools/r8/graph/AppInfo.java
@@ -52,10 +52,6 @@
return app.classes();
}
- public Iterable<DexLibraryClass> libraryClasses() {
- return app.libraryClasses();
- }
-
public DexClass definitionFor(DexType type) {
return app.definitionFor(type);
}
diff --git a/src/main/java/com/android/tools/r8/graph/AppInfoWithSubtyping.java b/src/main/java/com/android/tools/r8/graph/AppInfoWithSubtyping.java
index 9c87b61..54b2a51 100644
--- a/src/main/java/com/android/tools/r8/graph/AppInfoWithSubtyping.java
+++ b/src/main/java/com/android/tools/r8/graph/AppInfoWithSubtyping.java
@@ -4,7 +4,9 @@
package com.android.tools.r8.graph;
import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;
+
import java.util.Collections;
import java.util.HashSet;
import java.util.Hashtable;
@@ -21,19 +23,29 @@
public AppInfoWithSubtyping(DexApplication application) {
super(application);
- populateSubtypeMap(application.getFullClassMap(), application.dexItemFactory);
+ populateSubtypeMap(application.asDirect(), application.dexItemFactory);
}
protected AppInfoWithSubtyping(AppInfoWithSubtyping previous) {
super(previous);
missingClasses.addAll(previous.missingClasses);
subtypeMap.putAll(previous.subtypeMap);
+ assert app instanceof DirectMappedDexApplication;
}
protected AppInfoWithSubtyping(AppInfoWithSubtyping previous, GraphLense lense) {
super(previous, lense);
// Recompute subtype map if we have modified the graph.
- populateSubtypeMap(previous.app.getFullClassMap(), dexItemFactory);
+ populateSubtypeMap(previous.getDirectApplication(), dexItemFactory);
+ }
+
+ private DirectMappedDexApplication getDirectApplication() {
+ // TODO(herhut): Remove need for cast.
+ return (DirectMappedDexApplication) app;
+ }
+
+ public Iterable<DexLibraryClass> libraryClasses() {
+ return getDirectApplication().libraryClasses();
}
public Set<DexType> getMissingClasses() {
@@ -84,17 +96,17 @@
}
}
- private void populateSubtypeMap(Map<DexType, DexClass> classes, DexItemFactory dexItemFactory) {
+ private void populateSubtypeMap(DirectMappedDexApplication app, DexItemFactory dexItemFactory) {
dexItemFactory.clearSubtypeInformation();
dexItemFactory.objectType.tagAsSubtypeRoot();
Hashtable<DexType, Set<DexType>> map = new Hashtable<>();
- for (Map.Entry<DexType, DexClass> entry : classes.entrySet()) {
- populateAllSuperTypes(map, entry.getKey(), entry.getValue(), classes::get);
+ for (DexClass clazz : Iterables.<DexClass>concat(app.classes(), app.libraryClasses())) {
+ populateAllSuperTypes(map, clazz.type, clazz, app::definitionFor);
}
for (Map.Entry<DexType, Set<DexType>> entry : map.entrySet()) {
subtypeMap.put(entry.getKey(), ImmutableSet.copyOf(entry.getValue()));
}
- assert DexType.validateLevelsAreCorrect(classes::get, dexItemFactory);
+ assert DexType.validateLevelsAreCorrect(app::definitionFor, dexItemFactory);
}
// For mapping invoke virtual instruction to target methods.
diff --git a/src/main/java/com/android/tools/r8/graph/DexAnnotation.java b/src/main/java/com/android/tools/r8/graph/DexAnnotation.java
index 3a8d56b..232a86c 100644
--- a/src/main/java/com/android/tools/r8/graph/DexAnnotation.java
+++ b/src/main/java/com/android/tools/r8/graph/DexAnnotation.java
@@ -5,6 +5,7 @@
import com.android.tools.r8.dex.IndexedItemCollection;
import com.android.tools.r8.dex.MixedSectionCollection;
+import com.android.tools.r8.errors.CompilationError;
import com.android.tools.r8.graph.DexValue.DexValueAnnotation;
import com.android.tools.r8.graph.DexValue.DexValueArray;
import com.android.tools.r8.graph.DexValue.DexValueInt;
@@ -15,7 +16,6 @@
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
-import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -239,11 +239,26 @@
DexAnnotation foundAnnotation = programClass.annotations.getFirstMatching(
dexItemFactory.annotationSynthesizedClassMap);
if (foundAnnotation != null) {
+ if (foundAnnotation.annotation.elements.length != 1) {
+ throw new CompilationError(
+ getInvalidSynthesizedClassMapMessage(programClass, foundAnnotation));
+ }
DexAnnotationElement value = foundAnnotation.annotation.elements[0];
- assert value.name.toSourceString().equals("value");
+ if (!value.name.toSourceString().equals("value")) {
+ throw new CompilationError(
+ getInvalidSynthesizedClassMapMessage(programClass, foundAnnotation));
+ }
+ if (!(value.value instanceof DexValueArray)) {
+ throw new CompilationError(
+ getInvalidSynthesizedClassMapMessage(programClass, foundAnnotation));
+ }
DexValueArray existingList = (DexValueArray) value.value;
Collection<DexType> synthesized = new ArrayList<>(existingList.values.length);
for (DexValue element : existingList.getValues()) {
+ if (!(element instanceof DexValueType)) {
+ throw new CompilationError(
+ getInvalidSynthesizedClassMapMessage(programClass, foundAnnotation));
+ }
synthesized.add(((DexValueType) element).value);
}
return synthesized;
@@ -251,6 +266,15 @@
return Collections.emptyList();
}
+ private static String getInvalidSynthesizedClassMapMessage(
+ DexProgramClass annotatedClass,
+ DexAnnotation invalidAnnotation) {
+ return annotatedClass.toSourceString()
+ + " is annotated with invalid "
+ + invalidAnnotation.annotation.type.toString()
+ + ": " + invalidAnnotation.toString();
+ }
+
public static DexAnnotation createAnnotationSynthesizedClassMap(
Set<DexType> synthesized,
DexItemFactory dexItemFactory) {
diff --git a/src/main/java/com/android/tools/r8/graph/DexApplication.java b/src/main/java/com/android/tools/r8/graph/DexApplication.java
index 294b031..b79f30e 100644
--- a/src/main/java/com/android/tools/r8/graph/DexApplication.java
+++ b/src/main/java/com/android/tools/r8/graph/DexApplication.java
@@ -6,10 +6,9 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.graph;
+import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.naming.ClassNameMapper;
-import com.android.tools.r8.utils.ClasspathClassCollection;
import com.android.tools.r8.utils.InternalOptions;
-import com.android.tools.r8.utils.LibraryClassCollection;
import com.android.tools.r8.utils.ProgramClassCollection;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.Timing;
@@ -26,17 +25,13 @@
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
-import java.util.IdentityHashMap;
import java.util.List;
-import java.util.Map;
import java.util.Set;
-public class DexApplication {
+public abstract class DexApplication {
// Maps type into class, may be used concurrently.
- private ProgramClassCollection programClasses;
- private ClasspathClassCollection classpathClasses;
- private LibraryClassCollection libraryClasses;
+ ProgramClassCollection programClasses;
public final ImmutableSet<DexType> mainDexList;
public final byte[] deadCode;
@@ -50,12 +45,12 @@
// Information on the lexicographically largest string referenced from code.
public final DexString highestSortingString;
- /** Constructor should only be invoked by the DexApplication.Builder. */
- private DexApplication(
+ /**
+ * Constructor should only be invoked by the DexApplication.Builder.
+ */
+ DexApplication(
ClassNameMapper proguardMap,
ProgramClassCollection programClasses,
- ClasspathClassCollection classpathClasses,
- LibraryClassCollection libraryClasses,
ImmutableSet<DexType> mainDexList,
byte[] deadCode,
DexItemFactory dexItemFactory,
@@ -64,8 +59,6 @@
assert programClasses != null;
this.proguardMap = proguardMap;
this.programClasses = programClasses;
- this.classpathClasses = classpathClasses;
- this.libraryClasses = libraryClasses;
this.mainDexList = mainDexList;
this.deadCode = deadCode;
this.dexItemFactory = dexItemFactory;
@@ -73,10 +66,7 @@
this.timing = timing;
}
- /** Force load all classes and return type -> class map containing all the classes */
- public Map<DexType, DexClass> getFullClassMap() {
- return forceLoadAllClasses();
- }
+ public abstract Builder<?> builder();
// Reorder classes randomly. Note that the order of classes in program or library
// class collections should not matter for compilation of valid code and when running
@@ -96,61 +86,14 @@
return classes;
}
- public List<DexLibraryClass> libraryClasses() {
- assert classpathClasses == null : "Operation is not supported.";
- Map<DexType, DexClass> classMap = forceLoadAllClasses();
- List<DexLibraryClass> classes = new ArrayList<>();
- for (DexClass clazz : classMap.values()) {
- if (clazz.isLibraryClass()) {
- classes.add(clazz.asLibraryClass());
- }
- }
- assert reorderClasses(classes);
- return classes;
- }
-
- private Map<DexType, DexClass> forceLoadAllClasses() {
- Map<DexType, DexClass> loaded = new IdentityHashMap<>();
-
- // program classes are supposed to be loaded, but force-loading them is no-op.
- programClasses.forceLoad(type -> true);
- programClasses.getAllClasses().forEach(clazz -> loaded.put(clazz.type, clazz));
-
- if (classpathClasses != null) {
- classpathClasses.forceLoad(type -> !loaded.containsKey(type));
- classpathClasses.getAllClasses().forEach(clazz -> loaded.putIfAbsent(clazz.type, clazz));
- }
-
- if (libraryClasses != null) {
- libraryClasses.forceLoad(type -> !loaded.containsKey(type));
- libraryClasses.getAllClasses().forEach(clazz -> loaded.putIfAbsent(clazz.type, clazz));
- }
-
- return loaded;
- }
-
- public DexClass definitionFor(DexType type) {
- if (type == null) {
- return null;
- }
- DexClass clazz = programClasses.get(type);
- if (clazz == null && classpathClasses != null) {
- clazz = classpathClasses.get(type);
- }
- if (clazz == null && libraryClasses != null) {
- clazz = libraryClasses.get(type);
- }
- return clazz;
- }
+ public abstract DexClass definitionFor(DexType type);
public DexProgramClass programDefinitionFor(DexType type) {
DexClass clazz = programClasses.get(type);
return clazz == null ? null : clazz.asProgramClass();
}
- public String toString() {
- return "Application (" + programClasses + "; " + classpathClasses + "; " + libraryClasses + ")";
- }
+ public abstract String toString();
public ClassNameMapper getProguardMap() {
return proguardMap;
@@ -208,7 +151,9 @@
}
}
- /** Return smali source for the application code. */
+ /**
+ * Return smali source for the application code.
+ */
public String smali(InternalOptions options) {
ByteArrayOutputStream os = new ByteArrayOutputStream();
PrintStream ps = new PrintStream(os);
@@ -296,7 +241,7 @@
}
}
- public static class Builder {
+ public abstract static class Builder<T extends Builder> {
// We handle program class collection separately from classpath
// and library class collections. Since while we assume program
// class collection should always be fully loaded and thus fully
@@ -304,17 +249,15 @@
// new or removing existing classes), classpath and library
// collections will be considered monolithic collections.
- private final List<DexProgramClass> programClasses;
- private ClasspathClassCollection classpathClasses;
- private LibraryClassCollection libraryClasses;
+ final List<DexProgramClass> programClasses;
public final DexItemFactory dexItemFactory;
ClassNameMapper proguardMap;
- private final Timing timing;
+ final Timing timing;
DexString highestSortingString;
- private byte[] deadCode;
- private final Set<DexType> mainDexList = Sets.newIdentityHashSet();
+ byte[] deadCode;
+ final Set<DexType> mainDexList = Sets.newIdentityHashSet();
private final Collection<DexProgramClass> synthesizedClasses;
public Builder(DexItemFactory dexItemFactory, Timing timing) {
@@ -322,16 +265,14 @@
this.dexItemFactory = dexItemFactory;
this.timing = timing;
this.deadCode = null;
- this.classpathClasses = null;
- this.libraryClasses = null;
this.synthesizedClasses = new ArrayList<>();
}
+ abstract T self();
+
public Builder(DexApplication application) {
programClasses = application.programClasses.getAllClasses();
- classpathClasses = application.classpathClasses;
- libraryClasses = application.libraryClasses;
- proguardMap = application.proguardMap;
+ proguardMap = application.getProguardMap();
timing = application.timing;
highestSortingString = application.highestSortingString;
dexItemFactory = application.dexItemFactory;
@@ -340,53 +281,43 @@
synthesizedClasses = new ArrayList<>();
}
- public synchronized Builder setProguardMap(ClassNameMapper proguardMap) {
+ public synchronized T setProguardMap(ClassNameMapper proguardMap) {
assert this.proguardMap == null;
this.proguardMap = proguardMap;
- return this;
+ return self();
}
- public synchronized Builder replaceProgramClasses(List<DexProgramClass> newProgramClasses) {
+ public synchronized T replaceProgramClasses(List<DexProgramClass> newProgramClasses) {
assert newProgramClasses != null;
this.programClasses.clear();
this.programClasses.addAll(newProgramClasses);
- return this;
+ return self();
}
- public Builder appendDeadCode(byte[] deadCodeAtAnotherRound) {
+ public T appendDeadCode(byte[] deadCodeAtAnotherRound) {
if (deadCodeAtAnotherRound == null) {
- return this;
+ return self();
}
if (this.deadCode == null) {
this.deadCode = deadCodeAtAnotherRound;
- return this;
+ return self();
}
// Concatenate existing byte[] and the given byte[].
this.deadCode = Bytes.concat(this.deadCode, deadCodeAtAnotherRound);
- return this;
+ return self();
}
- public synchronized Builder setHighestSortingString(DexString value) {
+ public synchronized T setHighestSortingString(DexString value) {
highestSortingString = value;
- return this;
+ return self();
}
- public synchronized Builder addProgramClass(DexProgramClass clazz) {
+ public synchronized T addProgramClass(DexProgramClass clazz) {
programClasses.add(clazz);
- return this;
+ return self();
}
- public Builder setClasspathClassCollection(ClasspathClassCollection classes) {
- this.classpathClasses = classes;
- return this;
- }
-
- public Builder setLibraryClassCollection(LibraryClassCollection classes) {
- this.libraryClasses = classes;
- return this;
- }
-
- public synchronized Builder addSynthesizedClass(
+ public synchronized T addSynthesizedClass(
DexProgramClass synthesizedClass, boolean addToMainDexList) {
assert synthesizedClass.isProgramClass() : "All synthesized classes must be program classes";
addProgramClass(synthesizedClass);
@@ -394,7 +325,7 @@
if (addToMainDexList && !mainDexList.isEmpty()) {
mainDexList.add(synthesizedClass.type);
}
- return this;
+ return self();
}
public Collection<DexProgramClass> getProgramClasses() {
@@ -414,17 +345,17 @@
return this;
}
- public DexApplication build() {
- return new DexApplication(
- proguardMap,
- ProgramClassCollection.create(programClasses),
- classpathClasses,
- libraryClasses,
- ImmutableSet.copyOf(mainDexList),
- deadCode,
- dexItemFactory,
- highestSortingString,
- timing);
- }
+ public abstract DexApplication build();
}
+
+ public static LazyLoadedDexApplication.Builder builder(DexItemFactory factory, Timing timing) {
+ return new LazyLoadedDexApplication.Builder(factory, timing);
+ }
+
+ public DirectMappedDexApplication asDirect() {
+ throw new Unreachable("Cannot use a LazyDexApplication where a DirectDexApplication is"
+ + " expected.");
+ }
+
+ public abstract DirectMappedDexApplication toDirect();
}
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 b76177b..11d9a23 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -18,7 +18,9 @@
import com.android.tools.r8.code.InvokeStatic;
import com.android.tools.r8.code.NewInstance;
import com.android.tools.r8.code.Throw;
+import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.dex.IndexedItemCollection;
+import com.android.tools.r8.dex.JumboStringRewriter;
import com.android.tools.r8.dex.MixedSectionCollection;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.Invoke;
@@ -392,6 +394,30 @@
return builder.build();
}
+ /**
+ * Rewrites the code in this method to have JumboString bytecode if required by mapping.
+ * <p>
+ * Synchronized such that it can be called concurrently for different mappings. As a side-effect,
+ * this will also update the highestSortingString to the index of the strings up to which the
+ * code was rewritten to avoid rewriting again unless needed.
+ */
+ public synchronized void rewriteCodeWithJumboStrings(ObjectToOffsetMapping mapping,
+ DexApplication application) {
+ assert code == null || code.isDexCode();
+ if (code == null) {
+ return;
+ }
+ DexCode code = this.code.asDexCode();
+ if (code.highestSortingString != null) {
+ if (mapping.getOffsetFor(code.highestSortingString) > Constants.MAX_NON_JUMBO_INDEX) {
+ JumboStringRewriter rewriter =
+ new JumboStringRewriter(this, mapping.getFirstJumboString(),
+ application.dexItemFactory);
+ rewriter.rewrite();
+ }
+ }
+ }
+
public String codeToString() {
return code == null ? "<no code>" : code.toString(this, null);
}
diff --git a/src/main/java/com/android/tools/r8/graph/DirectMappedDexApplication.java b/src/main/java/com/android/tools/r8/graph/DirectMappedDexApplication.java
new file mode 100644
index 0000000..e2583c3
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/graph/DirectMappedDexApplication.java
@@ -0,0 +1,99 @@
+// Copyright (c) 2017, 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.
+// Copyright (c) 2016, 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.graph;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+
+import com.android.tools.r8.naming.ClassNameMapper;
+import com.android.tools.r8.utils.ProgramClassCollection;
+import com.android.tools.r8.utils.Timing;
+
+import java.util.Collection;
+import java.util.IdentityHashMap;
+import java.util.Map;
+
+public class DirectMappedDexApplication extends DexApplication {
+
+ private final ImmutableMap<DexType, DexLibraryClass> libraryClasses;
+
+ private DirectMappedDexApplication(ClassNameMapper proguardMap,
+ ProgramClassCollection programClasses,
+ ImmutableMap<DexType, DexLibraryClass> libraryClasses,
+ ImmutableSet<DexType> mainDexList, byte[] deadCode,
+ DexItemFactory dexItemFactory, DexString highestSortingString,
+ Timing timing) {
+ super(proguardMap, programClasses, mainDexList, deadCode,
+ dexItemFactory, highestSortingString, timing);
+ this.libraryClasses = libraryClasses;
+ }
+
+ public Collection<DexLibraryClass> libraryClasses() {
+ return libraryClasses.values();
+ }
+
+ @Override
+ public DexClass definitionFor(DexType type) {
+ DexClass result = programClasses.get(type);
+ if (result == null) {
+ result = libraryClasses.get(type);
+ }
+ return result;
+ }
+
+ @Override
+ public Builder builder() {
+ return new Builder(this);
+ }
+
+ @Override
+ public DirectMappedDexApplication toDirect() {
+ return this;
+ }
+
+ @Override
+ public DirectMappedDexApplication asDirect() {
+ return this;
+ }
+
+ public String toString() {
+ return "DexApplication (direct)";
+ }
+
+ public static class Builder extends DexApplication.Builder<Builder> {
+
+ private Map<DexType, DexLibraryClass> libraryClasses = new IdentityHashMap<>();
+
+ Builder(LazyLoadedDexApplication application) {
+ super(application);
+ // As a side-effect, this will force-load all classes.
+ Map<DexType, DexClass> allClasses = application.getFullClassMap();
+ Iterables.filter(allClasses.values(), DexLibraryClass.class)
+ .forEach(k -> libraryClasses.put(k.type, k));
+
+ }
+
+ private Builder(DirectMappedDexApplication application) {
+ super(application);
+ this.libraryClasses.putAll(application.libraryClasses);
+ }
+
+ @Override
+ Builder self() {
+ return this;
+ }
+
+ @Override
+ public DexApplication build() {
+ return new DirectMappedDexApplication(proguardMap,
+ ProgramClassCollection.create(programClasses),
+ ImmutableMap.copyOf(libraryClasses), ImmutableSet.copyOf(mainDexList), deadCode,
+ dexItemFactory, highestSortingString, timing);
+ }
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java b/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java
index 5718ec2..a90373e 100644
--- a/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java
+++ b/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java
@@ -5,7 +5,7 @@
import static org.objectweb.asm.ClassReader.SKIP_FRAMES;
import static org.objectweb.asm.Opcodes.ACC_DEPRECATED;
-import static org.objectweb.asm.Opcodes.ASM5;
+import static org.objectweb.asm.Opcodes.ASM6;
import com.android.tools.r8.Resource;
import com.android.tools.r8.dex.Constants;
@@ -121,7 +121,7 @@
byte[] classCache,
JarApplicationReader application,
Consumer<DexClass> classConsumer) {
- super(ASM5);
+ super(ASM6);
this.file = file;
this.classKind = classKind;
this.classConsumer = classConsumer;
@@ -299,7 +299,7 @@
public CreateFieldVisitor(CreateDexClassVisitor parent,
int access, String name, String desc, String signature, Object value) {
- super(ASM5);
+ super(ASM6);
this.parent = parent;
this.access = access;
this.name = name;
@@ -401,7 +401,7 @@
public CreateMethodVisitor(int access, String name, String desc, String signature,
String[] exceptions, CreateDexClassVisitor parent) {
- super(ASM5);
+ super(ASM6);
this.access = access;
this.name = name;
this.desc = desc;
@@ -588,7 +588,7 @@
public CreateAnnotationVisitor(
JarApplicationReader application, BiConsumer<List<DexString>, List<DexValue>> onVisitEnd) {
- super(ASM5);
+ super(ASM6);
this.application = application;
this.onVisitEnd = onVisitEnd;
}
diff --git a/src/main/java/com/android/tools/r8/graph/JarCode.java b/src/main/java/com/android/tools/r8/graph/JarCode.java
index 1dc5964..39c580e 100644
--- a/src/main/java/com/android/tools/r8/graph/JarCode.java
+++ b/src/main/java/com/android/tools/r8/graph/JarCode.java
@@ -165,7 +165,7 @@
private final JarApplicationReader application;
public SecondVisitor(ReparseContext context, JarApplicationReader application) {
- super(Opcodes.ASM5);
+ super(Opcodes.ASM6);
this.context = context;
this.application = application;
}
diff --git a/src/main/java/com/android/tools/r8/graph/LazyLoadedDexApplication.java b/src/main/java/com/android/tools/r8/graph/LazyLoadedDexApplication.java
new file mode 100644
index 0000000..bd7b266
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/graph/LazyLoadedDexApplication.java
@@ -0,0 +1,134 @@
+// Copyright (c) 2017, 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.
+// Copyright (c) 2016, 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.graph;
+
+import com.android.tools.r8.naming.ClassNameMapper;
+import com.android.tools.r8.utils.ClasspathClassCollection;
+import com.android.tools.r8.utils.LibraryClassCollection;
+import com.android.tools.r8.utils.ProgramClassCollection;
+import com.android.tools.r8.utils.Timing;
+import com.google.common.collect.ImmutableSet;
+import java.util.IdentityHashMap;
+import java.util.Map;
+
+public class LazyLoadedDexApplication extends DexApplication {
+
+ private ClasspathClassCollection classpathClasses;
+ private LibraryClassCollection libraryClasses;
+
+ /**
+ * Constructor should only be invoked by the DexApplication.Builder.
+ */
+ private LazyLoadedDexApplication(ClassNameMapper proguardMap,
+ ProgramClassCollection programClasses,
+ ClasspathClassCollection classpathClasses,
+ LibraryClassCollection libraryClasses,
+ ImmutableSet<DexType> mainDexList, byte[] deadCode,
+ DexItemFactory dexItemFactory, DexString highestSortingString,
+ Timing timing) {
+ super(proguardMap, programClasses, mainDexList, deadCode,
+ dexItemFactory, highestSortingString, timing);
+ this.classpathClasses = classpathClasses;
+ this.libraryClasses = libraryClasses;
+ }
+
+ @Override
+ public DexClass definitionFor(DexType type) {
+ if (type == null) {
+ return null;
+ }
+ DexClass clazz = programClasses.get(type);
+ if (clazz == null && classpathClasses != null) {
+ clazz = classpathClasses.get(type);
+ }
+ if (clazz == null && libraryClasses != null) {
+ clazz = libraryClasses.get(type);
+ }
+ return clazz;
+ }
+
+ private Map<DexType, DexClass> forceLoadAllClasses() {
+ Map<DexType, DexClass> loaded = new IdentityHashMap<>();
+
+ // Program classes are supposed to be loaded, but force-loading them is no-op.
+ programClasses.forceLoad(type -> true);
+ programClasses.getAllClasses().forEach(clazz -> loaded.put(clazz.type, clazz));
+
+ if (classpathClasses != null) {
+ classpathClasses.forceLoad(type -> !loaded.containsKey(type));
+ classpathClasses.getAllClasses().forEach(clazz -> loaded.putIfAbsent(clazz.type, clazz));
+ }
+
+ if (libraryClasses != null) {
+ libraryClasses.forceLoad(type -> !loaded.containsKey(type));
+ libraryClasses.getAllClasses().forEach(clazz -> loaded.putIfAbsent(clazz.type, clazz));
+ }
+
+ return loaded;
+ }
+
+ /**
+ * Force load all classes and return type -> class map containing all the classes.
+ */
+ public Map<DexType, DexClass> getFullClassMap() {
+ return forceLoadAllClasses();
+ }
+
+ public static class Builder extends DexApplication.Builder<Builder> {
+
+ private ClasspathClassCollection classpathClasses;
+ private LibraryClassCollection libraryClasses;
+
+ Builder(DexItemFactory dexItemFactory, Timing timing) {
+ super(dexItemFactory, timing);
+ this.classpathClasses = null;
+ this.libraryClasses = null;
+ }
+
+ private Builder(LazyLoadedDexApplication application) {
+ super(application);
+ this.classpathClasses = application.classpathClasses;
+ this.libraryClasses = application.libraryClasses;
+ }
+
+ Builder self() {
+ return this;
+ }
+
+ public Builder setClasspathClassCollection(ClasspathClassCollection classes) {
+ this.classpathClasses = classes;
+ return this;
+ }
+
+ public Builder setLibraryClassCollection(LibraryClassCollection classes) {
+ this.libraryClasses = classes;
+ return this;
+ }
+
+ public LazyLoadedDexApplication build() {
+ return new LazyLoadedDexApplication(proguardMap,
+ ProgramClassCollection.create(programClasses),
+ classpathClasses, libraryClasses, ImmutableSet.copyOf(mainDexList), deadCode,
+ dexItemFactory, highestSortingString, timing);
+ }
+ }
+
+ @Override
+ public Builder builder() {
+ return new Builder(this);
+ }
+
+ @Override
+ public DirectMappedDexApplication toDirect() {
+ return new DirectMappedDexApplication.Builder(this).build().asDirect();
+ }
+
+ public String toString() {
+ return "Application (" + programClasses + "; " + classpathClasses + "; " + libraryClasses
+ + ")";
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
index 716db5e..2ba4421 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
@@ -226,7 +226,7 @@
convertClassesToDex(application.classes(), executor);
// Build a new application with jumbo string info,
- Builder builder = new Builder(application);
+ Builder builder = application.builder();
builder.setHighestSortingString(highestSortingString);
synthesizeLambdaClasses(builder);
@@ -245,7 +245,7 @@
return builder.build();
}
- private void updateMainDexListWithSynthesizedClassMap(Builder builder) {
+ private void updateMainDexListWithSynthesizedClassMap(Builder<?> builder) {
Set<DexType> inputMainDexList = builder.getMainDexList();
if (!inputMainDexList.isEmpty()) {
Map<DexType, DexProgramClass> programClasses = builder.getProgramClasses().stream()
@@ -264,14 +264,14 @@
}
}
- private void clearSynthesizedClassMapping(Builder builder) {
+ private void clearSynthesizedClassMapping(Builder<?> builder) {
for (DexProgramClass programClass : builder.getProgramClasses()) {
programClass.annotations =
programClass.annotations.getWithout(builder.dexItemFactory.annotationSynthesizedClassMap);
}
}
- private void updateSynthesizedClassMapping(Builder builder) {
+ private void updateSynthesizedClassMapping(Builder<?> builder) {
ListMultimap<DexProgramClass, DexProgramClass> originalToSynthesized =
ArrayListMultimap.create();
for (DexProgramClass synthesized : builder.getSynthesizedClasses()) {
@@ -361,7 +361,7 @@
}
// Build a new application with jumbo string info.
- Builder builder = new Builder(application);
+ Builder builder = application.builder();
builder.setHighestSortingString(highestSortingString);
// Second inlining pass for dealing with double inline callers.
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java
index edf8b60..99417c3 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java
@@ -254,7 +254,7 @@
}
private Map<DexProgramClass, DexProgramClass> processInterfaces(
- Builder builder, Flavor flavour) {
+ Builder<?> builder, Flavor flavour) {
InterfaceProcessor processor = new InterfaceProcessor(this);
for (DexProgramClass clazz : builder.getProgramClasses()) {
if (shouldProcess(clazz, flavour, true)) {
@@ -264,7 +264,7 @@
return processor.companionClasses;
}
- private Set<DexEncodedMethod> processClasses(Builder builder, Flavor flavour) {
+ private Set<DexEncodedMethod> processClasses(Builder<?> builder, Flavor flavour) {
ClassProcessor processor = new ClassProcessor(this);
for (DexProgramClass clazz : builder.getProgramClasses()) {
if (shouldProcess(clazz, flavour, false)) {
diff --git a/src/main/java/com/android/tools/r8/jar/JarRegisterEffectsVisitor.java b/src/main/java/com/android/tools/r8/jar/JarRegisterEffectsVisitor.java
index b8cbaa9..2d38bf0 100644
--- a/src/main/java/com/android/tools/r8/jar/JarRegisterEffectsVisitor.java
+++ b/src/main/java/com/android/tools/r8/jar/JarRegisterEffectsVisitor.java
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.jar;
-import static org.objectweb.asm.Opcodes.ASM5;
+import static org.objectweb.asm.Opcodes.ASM6;
import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.errors.Unreachable;
@@ -24,7 +24,7 @@
public JarRegisterEffectsVisitor(DexType clazz, UseRegistry registry,
JarApplicationReader application) {
- super(ASM5);
+ super(ASM6);
this.clazz = clazz;
this.registry = registry;
this.application = application;
diff --git a/src/main/java/com/android/tools/r8/shaking/RootSetBuilder.java b/src/main/java/com/android/tools/r8/shaking/RootSetBuilder.java
index 74cec83..d4ff512 100644
--- a/src/main/java/com/android/tools/r8/shaking/RootSetBuilder.java
+++ b/src/main/java/com/android/tools/r8/shaking/RootSetBuilder.java
@@ -7,6 +7,7 @@
import com.android.tools.r8.graph.DexAnnotation;
import com.android.tools.r8.graph.DexAnnotationSet;
import com.android.tools.r8.graph.DexApplication;
+import com.android.tools.r8.graph.DirectMappedDexApplication;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexEncodedField;
import com.android.tools.r8.graph.DexEncodedMethod;
@@ -18,7 +19,6 @@
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.logging.Log;
-import com.android.tools.r8.shaking.ProguardTypeMatcher.MatchSpecificType;
import com.android.tools.r8.utils.MethodSignatureEquivalence;
import com.android.tools.r8.utils.ThreadUtils;
import com.google.common.base.Equivalence.Wrapper;
@@ -40,7 +40,7 @@
public class RootSetBuilder {
- private DexApplication application;
+ private DirectMappedDexApplication application;
private final AppInfo appInfo;
private final List<ProguardConfigurationRule> rules;
private final Map<DexItem, ProguardKeepRule> noShrinking = new IdentityHashMap<>();
@@ -59,7 +59,7 @@
public RootSetBuilder(DexApplication application, AppInfo appInfo,
List<ProguardConfigurationRule> rules) {
- this.application = application;
+ this.application = application.asDirect();
this.appInfo = appInfo;
this.rules = rules;
}
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 3decec1..f3b712f 100644
--- a/src/main/java/com/android/tools/r8/shaking/TreePruner.java
+++ b/src/main/java/com/android/tools/r8/shaking/TreePruner.java
@@ -56,7 +56,7 @@
}
private DexApplication.Builder removeUnused(DexApplication application) {
- return new DexApplication.Builder(application)
+ return application.builder()
.replaceProgramClasses(getNewProgramClasses(application.classes()));
}
diff --git a/src/test/examplesAndroidO/invokecustom/TestGenerator.java b/src/test/examplesAndroidO/invokecustom/TestGenerator.java
index 5c550e9..574fe14 100644
--- a/src/test/examplesAndroidO/invokecustom/TestGenerator.java
+++ b/src/test/examplesAndroidO/invokecustom/TestGenerator.java
@@ -39,7 +39,7 @@
ClassReader cr = new ClassReader(new FileInputStream(classNamePath.toFile()));
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
cr.accept(
- new ClassVisitor(Opcodes.ASM5, cw) {
+ new ClassVisitor(Opcodes.ASM6, cw) {
@Override
public void visitEnd() {
generateMethodTest1(cw);
diff --git a/src/test/examplesAndroidO/invokecustom2/TestGenerator.java b/src/test/examplesAndroidO/invokecustom2/TestGenerator.java
index 48cfedb..ab77d32 100644
--- a/src/test/examplesAndroidO/invokecustom2/TestGenerator.java
+++ b/src/test/examplesAndroidO/invokecustom2/TestGenerator.java
@@ -40,7 +40,7 @@
ClassReader cr = new ClassReader(new FileInputStream(classNamePath.toFile()));
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
cr.accept(
- new ClassVisitor(Opcodes.ASM5, cw) {
+ new ClassVisitor(Opcodes.ASM6, cw) {
@Override
public void visitEnd() {
generateMethodTest1(cw);
diff --git a/src/test/java/com/android/tools/r8/R8UnreachableCodeTest.java b/src/test/java/com/android/tools/r8/R8UnreachableCodeTest.java
index 61a049e..082b5ee 100644
--- a/src/test/java/com/android/tools/r8/R8UnreachableCodeTest.java
+++ b/src/test/java/com/android/tools/r8/R8UnreachableCodeTest.java
@@ -8,9 +8,9 @@
import com.android.tools.r8.dex.ApplicationReader;
import com.android.tools.r8.graph.AppInfoWithSubtyping;
-import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.DirectMappedDexApplication;
import com.android.tools.r8.ir.conversion.IRConverter;
import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.InternalOptions;
@@ -33,8 +33,10 @@
AndroidApp input = AndroidApp.fromProgramFiles(SMALI_DIR.resolve(name).resolve(name + ".dex"));
ExecutorService executorService = Executors.newSingleThreadExecutor();
Timing timing = new Timing("R8UnreachableCodeTest");
- DexApplication application =
- new ApplicationReader(input, new InternalOptions(), timing).read(executorService);
+ DirectMappedDexApplication application =
+ new ApplicationReader(input, new InternalOptions(), timing)
+ .read(executorService)
+ .toDirect();
IRConverter converter =
new IRConverter(application, new AppInfoWithSubtyping(application), new InternalOptions());
converter.optimize();
diff --git a/src/test/java/com/android/tools/r8/ToolHelper.java b/src/test/java/com/android/tools/r8/ToolHelper.java
index 94d52f0..09f2594 100644
--- a/src/test/java/com/android/tools/r8/ToolHelper.java
+++ b/src/test/java/com/android/tools/r8/ToolHelper.java
@@ -459,7 +459,8 @@
AndroidApp.fromProgramFiles(ListUtils.map(fileNames, Paths::get)),
new InternalOptions(),
new Timing("ToolHelper buildApplication"))
- .read();
+ .read()
+ .toDirect();
}
public static ProguardConfiguration loadProguardConfiguration(
@@ -545,10 +546,10 @@
public static DexApplication optimizeWithR8(
DexApplication application,
- AppInfoWithSubtyping appInfo,
InternalOptions options)
throws CompilationException, ExecutionException, IOException {
- return R8.optimize(application, appInfo, options);
+ application = application.toDirect();
+ return R8.optimize(application, new AppInfoWithSubtyping(application), options);
}
public static AndroidApp runD8(AndroidApp app) throws CompilationException, IOException {
diff --git a/src/test/java/com/android/tools/r8/dex/DebugByteCodeWriterTest.java b/src/test/java/com/android/tools/r8/dex/DebugByteCodeWriterTest.java
index e5581a4..a08f274 100644
--- a/src/test/java/com/android/tools/r8/dex/DebugByteCodeWriterTest.java
+++ b/src/test/java/com/android/tools/r8/dex/DebugByteCodeWriterTest.java
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.dex;
+import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.graph.DexApplication.Builder;
import com.android.tools.r8.graph.DexCallSite;
import com.android.tools.r8.graph.DexDebugEvent;
@@ -24,7 +25,7 @@
ObjectToOffsetMapping emptyObjectTObjectMapping() {
return new ObjectToOffsetMapping(
0,
- new Builder(new DexItemFactory(), null).build(),
+ DexApplication.builder(new DexItemFactory(), null).build(),
new DexProgramClass[] {},
new DexProto[] {},
new DexType[] {},
diff --git a/src/test/java/com/android/tools/r8/internal/R8GMSCoreLookupTest.java b/src/test/java/com/android/tools/r8/internal/R8GMSCoreLookupTest.java
index 74e4e9b..30e02b5 100644
--- a/src/test/java/com/android/tools/r8/internal/R8GMSCoreLookupTest.java
+++ b/src/test/java/com/android/tools/r8/internal/R8GMSCoreLookupTest.java
@@ -9,10 +9,10 @@
import com.android.tools.r8.dex.ApplicationReader;
import com.android.tools.r8.graph.AppInfoWithSubtyping;
-import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.DirectMappedDexApplication;
import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.Timing;
@@ -29,7 +29,7 @@
static final String APP_DIR = "third_party/gmscore/v5/";
private AndroidApp app;
- private DexApplication program;
+ private DirectMappedDexApplication program;
private AppInfoWithSubtyping appInfo;
@Before
@@ -37,7 +37,8 @@
app = AndroidApp.fromProgramDirectory(Paths.get(APP_DIR));
ExecutorService executorService = Executors.newSingleThreadExecutor();
Timing timing = new Timing("ReadGMSCore");
- program = new ApplicationReader(app, new InternalOptions(), timing).read(executorService);
+ program = new ApplicationReader(app, new InternalOptions(), timing)
+ .read(executorService).toDirect();
appInfo = new AppInfoWithSubtyping(program);
}
diff --git a/src/test/java/com/android/tools/r8/jasmin/JasminTestBase.java b/src/test/java/com/android/tools/r8/jasmin/JasminTestBase.java
index 9da8e0e..8cf6e9b 100644
--- a/src/test/java/com/android/tools/r8/jasmin/JasminTestBase.java
+++ b/src/test/java/com/android/tools/r8/jasmin/JasminTestBase.java
@@ -13,7 +13,6 @@
import com.android.tools.r8.dex.ApplicationReader;
import com.android.tools.r8.errors.DexOverflowException;
import com.android.tools.r8.graph.AppInfo;
-import com.android.tools.r8.graph.AppInfoWithSubtyping;
import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.jasmin.JasminBuilder.ClassBuilder;
@@ -141,7 +140,7 @@
protected static DexApplication process(DexApplication app, InternalOptions options)
throws IOException, CompilationException, ExecutionException {
- return ToolHelper.optimizeWithR8(app, new AppInfoWithSubtyping(app), options);
+ return ToolHelper.optimizeWithR8(app, options);
}
protected DexApplication buildApplication(JasminBuilder builder, InternalOptions options) {
diff --git a/src/test/java/com/android/tools/r8/jsr45/JSR45Tests.java b/src/test/java/com/android/tools/r8/jsr45/JSR45Tests.java
index 601ca23..ab88a99 100644
--- a/src/test/java/com/android/tools/r8/jsr45/JSR45Tests.java
+++ b/src/test/java/com/android/tools/r8/jsr45/JSR45Tests.java
@@ -17,7 +17,6 @@
import com.android.tools.r8.utils.DexInspector;
import com.android.tools.r8.utils.DexInspector.AnnotationSubject;
import com.android.tools.r8.utils.DexInspector.ClassSubject;
-import com.google.common.io.Closer;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
@@ -158,7 +157,7 @@
throws IOException, ExecutionException {
ClassReader classReader = new ClassReader(new FileInputStream(inputPath.toFile()));
ReadSourceDebugExtensionAttribute sourceDebugExtensionReader =
- new ReadSourceDebugExtensionAttribute(Opcodes.ASM5, null);
+ new ReadSourceDebugExtensionAttribute(Opcodes.ASM6, null);
classReader.accept(sourceDebugExtensionReader, 0);
DexInspector dexInspector =
diff --git a/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java b/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
index 0acd445..b0a683a 100644
--- a/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
+++ b/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
@@ -35,6 +35,7 @@
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.DexTypeList;
+import com.android.tools.r8.graph.DirectMappedDexApplication;
import com.android.tools.r8.ir.code.CatchHandlers;
import com.android.tools.r8.ir.code.DebugPosition;
import com.android.tools.r8.ir.code.IRCode;
@@ -440,7 +441,7 @@
}
builder.append("]");
fail("Class " + clazz + " found in main dex, " +
- "only expected explicit main dex classes " + builder +" in main dex file");
+ "only expected explicit main dex classes " + builder + " in main dex file");
}
}
@@ -551,7 +552,7 @@
options.minApiLevel = minApi;
options.intermediate = intermediate;
DexItemFactory factory = options.itemFactory;
- DexApplication.Builder builder = new DexApplication.Builder(factory, timing);
+ DexApplication.Builder builder = DexApplication.builder(factory, timing);
for (String clazz : classes) {
DexString desc = factory.createString(DescriptorUtils.javaTypeToDescriptor(clazz));
DexType type = factory.createType(desc);
@@ -591,7 +592,7 @@
directMethods,
DexEncodedMethod.EMPTY_ARRAY));
}
- DexApplication application = builder.build();
+ DirectMappedDexApplication application = builder.build().toDirect();
AppInfoWithSubtyping appInfo = new AppInfoWithSubtyping(application);
ApplicationWriter writer = new ApplicationWriter(
application, appInfo, options, null, null, NamingLens.getIdentityLens(), null);
diff --git a/src/test/java/com/android/tools/r8/smali/OutlineTest.java b/src/test/java/com/android/tools/r8/smali/OutlineTest.java
index c64e39c..1aa9be7 100644
--- a/src/test/java/com/android/tools/r8/smali/OutlineTest.java
+++ b/src/test/java/com/android/tools/r8/smali/OutlineTest.java
@@ -901,8 +901,7 @@
// Process the application several times. Each time will outline the previous outline.
for (int i = 0; i < count; i++) {
// Build a new application with the Outliner class.
- DexApplication.Builder appBuilder =
- new DexApplication.Builder(processedApplication);
+ DexApplication.Builder appBuilder = processedApplication.builder();
originalApplication = appBuilder.build();
processedApplication = processApplication(originalApplication, options);
assertEquals(i + 3, Iterables.size(processedApplication.classes()));
@@ -912,8 +911,7 @@
options.outline.threshold = 2;
for (int i = 0; i < count; i++) {
// Build a new application with the Outliner class.
- DexApplication.Builder appBuilder =
- new DexApplication.Builder(processedApplication);
+ DexApplication.Builder appBuilder = processedApplication.builder();
originalApplication = appBuilder.build();
processedApplication = processApplication(originalApplication, options);
assertEquals(count - 1 + 3, Iterables.size(processedApplication.classes()));
diff --git a/src/test/java/com/android/tools/r8/smali/SmaliTestBase.java b/src/test/java/com/android/tools/r8/smali/SmaliTestBase.java
index 42e289a..c580f74 100644
--- a/src/test/java/com/android/tools/r8/smali/SmaliTestBase.java
+++ b/src/test/java/com/android/tools/r8/smali/SmaliTestBase.java
@@ -13,7 +13,6 @@
import com.android.tools.r8.dex.ApplicationReader;
import com.android.tools.r8.errors.DexOverflowException;
import com.android.tools.r8.graph.AppInfo;
-import com.android.tools.r8.graph.AppInfoWithSubtyping;
import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexEncodedMethod;
@@ -463,7 +462,7 @@
protected DexApplication processApplication(DexApplication application, InternalOptions options) {
try {
- return ToolHelper.optimizeWithR8(application, new AppInfoWithSubtyping(application), options);
+ return ToolHelper.optimizeWithR8(application, options);
} catch (IOException | CompilationException | ExecutionException e) {
throw new RuntimeException(e);
}
diff --git a/src/test/java/com/android/tools/r8/smali/SwitchRewritingTest.java b/src/test/java/com/android/tools/r8/smali/SwitchRewritingTest.java
index 77366fb..3fc329c 100644
--- a/src/test/java/com/android/tools/r8/smali/SwitchRewritingTest.java
+++ b/src/test/java/com/android/tools/r8/smali/SwitchRewritingTest.java
@@ -16,7 +16,6 @@
import com.android.tools.r8.code.Instruction;
import com.android.tools.r8.code.PackedSwitch;
import com.android.tools.r8.code.SparseSwitch;
-import com.android.tools.r8.graph.AppInfoWithSubtyping;
import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.graph.DexCode;
import com.android.tools.r8.graph.DexEncodedMethod;
@@ -296,7 +295,7 @@
" return");
DexApplication app = builder.read();
- app = ToolHelper.optimizeWithR8(app, new AppInfoWithSubtyping(app), new InternalOptions());
+ app = ToolHelper.optimizeWithR8(app, new InternalOptions());
MethodSignature signature = new MethodSignature("Test", "test", "int", ImmutableList.of("int"));
DexEncodedMethod method = getMethod(app, signature);
@@ -354,7 +353,7 @@
" return");
DexApplication app = builder.read();
- app = ToolHelper.optimizeWithR8(app, new AppInfoWithSubtyping(app), new InternalOptions());
+ app = ToolHelper.optimizeWithR8(app, new InternalOptions());
MethodSignature signature = new MethodSignature("Test", "test", "int", ImmutableList.of("int"));
DexEncodedMethod method = getMethod(app, signature);
@@ -432,7 +431,7 @@
" return");
DexApplication app = builder.read();
- app = ToolHelper.optimizeWithR8(app, new AppInfoWithSubtyping(app), new InternalOptions());
+ app = ToolHelper.optimizeWithR8(app, new InternalOptions());
MethodSignature signature = new MethodSignature("Test", "test", "int", ImmutableList.of("int"));
DexEncodedMethod method = getMethod(app, signature);
diff --git a/third_party/shadow.tar.gz.sha1 b/third_party/shadow.tar.gz.sha1
new file mode 100644
index 0000000..2dfb69e
--- /dev/null
+++ b/third_party/shadow.tar.gz.sha1
@@ -0,0 +1 @@
+2e350b99a72aba5d45b018b0f5391130c8751371
\ No newline at end of file
diff --git a/tools/gradle.py b/tools/gradle.py
index 14b5f34..275c270 100755
--- a/tools/gradle.py
+++ b/tools/gradle.py
@@ -15,11 +15,18 @@
GRADLE_DIR = os.path.join(utils.REPO_ROOT, 'third_party', 'gradle')
GRADLE_SHA1 = os.path.join(GRADLE_DIR, 'gradle.tar.gz.sha1')
GRADLE_TGZ = os.path.join(GRADLE_DIR, 'gradle.tar.gz')
+
+SHADOW_DIR = os.path.join(utils.REPO_ROOT, 'third_party')
+SHADOW_SHA1 = os.path.join(SHADOW_DIR, 'shadow.tar.gz.sha1')
+SHADOW_TGZ = os.path.join(SHADOW_DIR, 'shadow.tar.gz')
+
if utils.IsWindows():
GRADLE = os.path.join(GRADLE_DIR, 'gradle', 'bin', 'gradle.bat')
else:
GRADLE = os.path.join(GRADLE_DIR, 'gradle', 'bin', 'gradle')
+SHADOW = os.path.join(SHADOW_DIR, 'shadow', 'shadow-2.0.1.jar')
+
def PrintCmd(s):
if type(s) is list:
s = ' '.join(s)
@@ -37,8 +44,19 @@
else:
print 'gradle.py: Gradle binary present'
+def EnsureShadow():
+ if not os.path.exists(SHADOW) or os.path.getmtime(SHADOW_TGZ) < os.path.getmtime(SHADOW_SHA1):
+ # Bootstrap or update gradle, everything else is controlled using gradle.
+ utils.DownloadFromGoogleCloudStorage(SHADOW_SHA1)
+ # Update the mtime of the tar file to make sure we do not run again unless
+ # there is an update.
+ os.utime(SHADOW_TGZ, None)
+ else:
+ print 'gradle.py: Shadow library present'
+
def RunGradle(args, throw_on_failure=True):
EnsureGradle()
+ EnsureShadow()
cmd = [GRADLE]
cmd.extend(args)
utils.PrintCmd(cmd)