Refactoring resource and class kinds.
Changing resource kind to represent resource's content
rather than what resource is used for. Currently we only
supprt two resource kinds: DEX file and Java class file.
Moving what used to be a resource kind into a separate enum
ClassKind representing if the class is program, classpath
or library class.
With this change, resources only represent their content as
stream and their kinds, and only are mapped into class kinds
based on the API used to introduce them to AndroidApp.
Interface Resource and class InternalResource are also merged
into one class Resource since after we made getClassDescriptors()
part of public API, there is no 'hidden' resource API.
NOTE: Resource class is also used internally to represent other
file kinds (e.g. proguardMap, etc...), we use `null` kind for
such resources.
BUG=
Change-Id: I97df13f28531d1b3086e2929ffd85fdeb2298e81
diff --git a/src/main/java/com/android/tools/r8/Resource.java b/src/main/java/com/android/tools/r8/Resource.java
index c7760bb..eaabc99 100644
--- a/src/main/java/com/android/tools/r8/Resource.java
+++ b/src/main/java/com/android/tools/r8/Resource.java
@@ -1,30 +1,97 @@
// 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.
+
package com.android.tools.r8;
import com.google.common.io.Closer;
+import java.io.ByteArrayInputStream;
+import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.nio.file.Path;
import java.util.Set;
/** Represents application resources. */
-public interface Resource {
-
- /** Application resource kind. */
- enum Kind {
- PROGRAM, CLASSPATH, LIBRARY
+public abstract class Resource {
+ /** Kind of the resource describing the resource content. */
+ public enum Kind {
+ DEX, CLASSFILE
}
- /** Get the kind of the resource. */
- Kind getKind();
+ private Resource(Kind kind) {
+ this.kind = kind;
+ }
+
+ /** Kind of the resource. */
+ public final Kind kind;
+
+ /** Create an application resource for a given file. */
+ public static Resource fromFile(Kind kind, Path file) {
+ return new FileResource(kind, file);
+ }
+
+ /** Create an application resource for a given content. */
+ public static Resource fromBytes(Kind kind, byte[] bytes) {
+ return fromBytes(kind, bytes, null);
+ }
+
+ /** Create an application resource for a given content and type descriptor. */
+ public static Resource fromBytes(Kind kind, byte[] bytes, Set<String> typeDescriptors) {
+ return new ByteResource(kind, bytes, typeDescriptors);
+ }
/**
* Returns the set of class descriptors for classes represented
* by the resource if known, or `null' otherwise.
*/
- Set<String> getClassDescriptors();
+ public abstract Set<String> getClassDescriptors();
/** Get the resource as a stream. */
- InputStream getStream(Closer closer) throws IOException;
+ public abstract InputStream getStream(Closer closer) throws IOException;
+
+ /** File based application resource. */
+ private static class FileResource extends Resource {
+ final Path file;
+
+ FileResource(Kind kind, Path file) {
+ super(kind);
+ assert file != null;
+ this.file = file;
+ }
+
+ @Override
+ public Set<String> getClassDescriptors() {
+ return null;
+ }
+
+ @Override
+ public InputStream getStream(Closer closer) throws IOException {
+ return closer.register(new FileInputStream(file.toFile()));
+ }
+ }
+
+ /** Byte content based application resource. */
+ private static class ByteResource extends Resource {
+ final Set<String> classDescriptors;
+ final byte[] bytes;
+
+ ByteResource(Kind kind, byte[] bytes, Set<String> classDescriptors) {
+ super(kind);
+ assert bytes != null;
+ this.classDescriptors = classDescriptors;
+ this.bytes = bytes;
+ }
+
+ @Override
+ public Set<String> getClassDescriptors() {
+ return classDescriptors;
+ }
+
+ @Override
+ public InputStream getStream(Closer closer) throws IOException {
+ // Note: closing a byte-array input stream is a no-op.
+ return new ByteArrayInputStream(bytes);
+ }
+ }
}
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 35f9bfe..af6bebe 100644
--- a/src/main/java/com/android/tools/r8/dex/ApplicationReader.java
+++ b/src/main/java/com/android/tools/r8/dex/ApplicationReader.java
@@ -13,6 +13,7 @@
import com.android.tools.r8.Resource;
import com.android.tools.r8.ResourceProvider;
import com.android.tools.r8.errors.CompilationError;
+import com.android.tools.r8.graph.ClassKind;
import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexType;
@@ -22,7 +23,6 @@
import com.android.tools.r8.naming.ProguardMapReader;
import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.InternalOptions;
-import com.android.tools.r8.utils.InternalResource;
import com.android.tools.r8.utils.LazyClassCollection;
import com.android.tools.r8.utils.MainDexList;
import com.android.tools.r8.utils.ThreadUtils;
@@ -32,6 +32,7 @@
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
+import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@@ -90,67 +91,68 @@
JarApplicationReader application = new JarApplicationReader(options);
JarClassFileReader reader = new JarClassFileReader(
application, builder::addClassIgnoringLibraryDuplicates);
- for (InternalResource input : inputApp.getClassProgramResources()) {
- reader.read(DEFAULT_DEX_FILENAME, Resource.Kind.PROGRAM, input.getStream(closer));
+ for (Resource input : inputApp.getClassProgramResources()) {
+ reader.read(DEFAULT_DEX_FILENAME, ClassKind.PROGRAM, input.getStream(closer));
}
- for (InternalResource input : inputApp.getClassClasspathResources()) {
- if (options.lazyClasspathLoading && input.getSingleClassDescriptorOrNull() != null) {
- addLazyLoader(application, builder, input);
+ for (Resource input : inputApp.getClassClasspathResources()) {
+ if (options.lazyClasspathLoading && getResourceClassDescriptorOrNull(input) != null) {
+ addLazyLoader(application, ClassKind.CLASSPATH, builder, input);
} else {
- reader.read(DEFAULT_DEX_FILENAME, Resource.Kind.CLASSPATH, input.getStream(closer));
+ reader.read(DEFAULT_DEX_FILENAME, ClassKind.CLASSPATH, input.getStream(closer));
}
}
- for (InternalResource input : inputApp.getClassLibraryResources()) {
- if (options.lazyLibraryLoading && input.getSingleClassDescriptorOrNull() != null) {
- addLazyLoader(application, builder, input);
+ for (Resource input : inputApp.getClassLibraryResources()) {
+ if (options.lazyLibraryLoading && getResourceClassDescriptorOrNull(input) != null) {
+ addLazyLoader(application, ClassKind.LIBRARY, builder, input);
} else {
- reader.read(DEFAULT_DEX_FILENAME, Resource.Kind.LIBRARY, input.getStream(closer));
+ reader.read(DEFAULT_DEX_FILENAME, ClassKind.LIBRARY, input.getStream(closer));
}
}
}
private void initializeLazyClassCollection(DexApplication.Builder builder) {
- List<ResourceProvider> providers = inputApp.getLazyResourceProviders();
- if (!providers.isEmpty()) {
- builder.setLazyClassCollection(
- new LazyClassCollection(new JarApplicationReader(options), providers));
+ List<ResourceProvider> classpathProviders = inputApp.getClasspathResourceProviders();
+ List<ResourceProvider> libraryProviders = inputApp.getLibraryResourceProviders();
+ if (!classpathProviders.isEmpty() || !libraryProviders.isEmpty()) {
+ builder.setLazyClassCollection(new LazyClassCollection(
+ new JarApplicationReader(options), classpathProviders, libraryProviders));
}
}
private void addLazyLoader(JarApplicationReader application,
- DexApplication.Builder builder, InternalResource resource) {
+ ClassKind classKind, DexApplication.Builder builder, Resource resource) {
// Generate expected DEX type.
- String classDescriptor = resource.getSingleClassDescriptorOrNull();
+ String classDescriptor = getResourceClassDescriptorOrNull(resource);
assert classDescriptor != null;
DexType type = options.itemFactory.createType(classDescriptor);
- LazyClassFileLoader newLoader = new LazyClassFileLoader(type, resource, application);
+ LazyClassFileLoader newLoader = new LazyClassFileLoader(type, resource, classKind, application);
builder.addClassPromise(newLoader, true);
}
private void readDexSources(DexApplication.Builder builder, ExecutorService executorService,
List<Future<?>> futures, Closer closer)
throws IOException, ExecutionException {
- List<InternalResource> dexProgramSources = inputApp.getDexProgramResources();
- List<InternalResource> dexClasspathSources = inputApp.getDexClasspathResources();
- List<InternalResource> dexLibrarySources = inputApp.getDexLibraryResources();
+ List<Resource> dexProgramSources = inputApp.getDexProgramResources();
+ List<Resource> dexClasspathSources = inputApp.getDexClasspathResources();
+ List<Resource> dexLibrarySources = inputApp.getDexLibraryResources();
int numberOfFiles = dexProgramSources.size()
+ dexLibrarySources.size() + dexClasspathSources.size();
if (numberOfFiles > 0) {
List<DexFileReader> fileReaders = new ArrayList<>(numberOfFiles);
int computedMinApiLevel = options.minApiLevel;
- for (InternalResource input : dexProgramSources) {
+ for (Resource input : dexProgramSources) {
DexFile file = new DexFile(input.getStream(closer));
computedMinApiLevel = verifyOrComputeMinApiLevel(computedMinApiLevel, file);
- fileReaders.add(new DexFileReader(file, Resource.Kind.PROGRAM, itemFactory));
+ fileReaders.add(new DexFileReader(file, ClassKind.PROGRAM, itemFactory));
}
- for (InternalResource input : dexClasspathSources) {
+ for (Resource input : dexClasspathSources) {
DexFile file = new DexFile(input.getStream(closer));
- fileReaders.add(new DexFileReader(file, Resource.Kind.CLASSPATH, itemFactory));
+ fileReaders.add(new DexFileReader(file, ClassKind.CLASSPATH, itemFactory));
}
- for (InternalResource input : dexLibrarySources) {
+ for (Resource input : dexLibrarySources) {
DexFile file = new DexFile(input.getStream(closer));
computedMinApiLevel = verifyOrComputeMinApiLevel(computedMinApiLevel, file);
- fileReaders.add(new DexFileReader(file, Resource.Kind.LIBRARY, itemFactory));
+ fileReaders.add(new DexFileReader(file, ClassKind.LIBRARY, itemFactory));
}
options.minApiLevel = computedMinApiLevel;
for (DexFileReader reader : fileReaders) {
@@ -230,4 +232,9 @@
}
}
+ private static String getResourceClassDescriptorOrNull(Resource resource) {
+ Set<String> descriptors = resource.getClassDescriptors();
+ return (descriptors == null) || (descriptors.size() != 1)
+ ? null : descriptors.iterator().next();
+ }
}
diff --git a/src/main/java/com/android/tools/r8/dex/DexFileReader.java b/src/main/java/com/android/tools/r8/dex/DexFileReader.java
index 02b0ce8..6aacd55 100644
--- a/src/main/java/com/android/tools/r8/dex/DexFileReader.java
+++ b/src/main/java/com/android/tools/r8/dex/DexFileReader.java
@@ -11,6 +11,7 @@
import com.android.tools.r8.Resource;
import com.android.tools.r8.code.Instruction;
import com.android.tools.r8.code.InstructionFactory;
+import com.android.tools.r8.graph.ClassKind;
import com.android.tools.r8.graph.Descriptor;
import com.android.tools.r8.graph.DexAccessFlags;
import com.android.tools.r8.graph.DexAnnotation;
@@ -68,12 +69,12 @@
private DexFile file;
private final Segment[] segments;
private int[] stringIDs;
- private final Resource.Kind fileKind;
+ private final ClassKind classKind;
public static Segment[] parseMapFrom(Path file) throws IOException {
DexFileReader reader =
new DexFileReader(
- new DexFile(file.toString()), Resource.Kind.PROGRAM, new DexItemFactory());
+ new DexFile(file.toString()), ClassKind.PROGRAM, new DexItemFactory());
return reader.parseMap();
}
@@ -98,14 +99,13 @@
// Factory to canonicalize certain dexitems.
private final DexItemFactory dexItemFactory;
- public DexFileReader(
- DexFile file, Resource.Kind fileKind, DexItemFactory dexItemFactory) {
+ public DexFileReader(DexFile file, ClassKind classKind, DexItemFactory dexItemFactory) {
this.file = file;
this.dexItemFactory = dexItemFactory;
file.setByteOrder();
segments = parseMap();
parseStringIDs();
- this.fileKind = fileKind;
+ this.classKind = classKind;
}
public OffsetToObjectMapping getIndexedItemsMap() {
@@ -113,7 +113,7 @@
}
void addCodeItemsTo() {
- if (fileKind == Resource.Kind.LIBRARY) {
+ if (classKind == ClassKind.LIBRARY) {
// Ignore contents of library files.
return;
}
@@ -644,17 +644,17 @@
directMethodsSize,
annotationsDirectory.methods,
annotationsDirectory.parameters,
- fileKind != Resource.Kind.PROGRAM);
+ classKind != ClassKind.PROGRAM);
virtualMethods =
readMethods(
virtualMethodsSize,
annotationsDirectory.methods,
annotationsDirectory.parameters,
- fileKind != Resource.Kind.PROGRAM);
+ classKind != ClassKind.PROGRAM);
}
- clazz = DexClass.factoryForResourceKind(fileKind).create(
+ clazz = classKind.create(
type,
- DexClass.Origin.Dex,
+ Resource.Kind.DEX,
flags,
superclass,
typeListAt(interfacesOffsets[i]),
diff --git a/src/main/java/com/android/tools/r8/graph/ClassKind.java b/src/main/java/com/android/tools/r8/graph/ClassKind.java
new file mode 100644
index 0000000..6f53a40
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/graph/ClassKind.java
@@ -0,0 +1,33 @@
+package com.android.tools.r8.graph;
+
+import com.android.tools.r8.Resource;
+
+/** Kind of the application class. Can be program, classpath or library. */
+public enum ClassKind {
+ PROGRAM(DexProgramClass::new),
+ CLASSPATH(DexClasspathClass::new),
+ LIBRARY(DexLibraryClass::new);
+
+ private interface Factory {
+ DexClass create(DexType type, Resource.Kind origin, DexAccessFlags accessFlags,
+ DexType superType,
+ DexTypeList interfaces, DexString sourceFile, DexAnnotationSet annotations,
+ DexEncodedField[] staticFields, DexEncodedField[] instanceFields,
+ DexEncodedMethod[] directMethods, DexEncodedMethod[] virtualMethods);
+ }
+
+ private final Factory factory;
+
+ ClassKind(Factory factory) {
+ this.factory = factory;
+ }
+
+ public DexClass create(
+ DexType type, Resource.Kind origin, DexAccessFlags accessFlags, DexType superType,
+ DexTypeList interfaces, DexString sourceFile, DexAnnotationSet annotations,
+ DexEncodedField[] staticFields, DexEncodedField[] instanceFields,
+ DexEncodedMethod[] directMethods, DexEncodedMethod[] virtualMethods) {
+ return factory.create(type, origin, accessFlags, superType, interfaces, sourceFile,
+ annotations, staticFields, instanceFields, directMethods, virtualMethods);
+ }
+}
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 bcc845e..acbc205 100644
--- a/src/main/java/com/android/tools/r8/graph/DexApplication.java
+++ b/src/main/java/com/android/tools/r8/graph/DexApplication.java
@@ -6,6 +6,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.graph;
+import com.android.tools.r8.Resource;
import com.android.tools.r8.errors.CompilationError;
import com.android.tools.r8.ir.desugar.LambdaRewriter;
import com.android.tools.r8.logging.Log;
@@ -387,8 +388,8 @@
private static boolean allowProgramClassConflict(DexClassPromise a, DexClassPromise b) {
// Currently only allow collapsing synthetic lambda classes.
- return a.getOrigin() == DexClass.Origin.Dex
- && b.getOrigin() == DexClass.Origin.Dex
+ return a.getOrigin() == Resource.Kind.DEX
+ && b.getOrigin() == Resource.Kind.DEX
&& a.get().accessFlags.isSynthetic()
&& b.get().accessFlags.isSynthetic()
&& LambdaRewriter.hasLambdaClassPrefix(a.getType())
diff --git a/src/main/java/com/android/tools/r8/graph/DexClass.java b/src/main/java/com/android/tools/r8/graph/DexClass.java
index 90828b7..f684309 100644
--- a/src/main/java/com/android/tools/r8/graph/DexClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexClass.java
@@ -7,27 +7,14 @@
import com.android.tools.r8.dex.MixedSectionCollection;
import com.android.tools.r8.errors.CompilationError;
import com.android.tools.r8.errors.Unreachable;
-import com.android.tools.r8.utils.InternalResource;
import com.google.common.base.MoreObjects;
public abstract class DexClass extends DexItem implements DexClassPromise {
- public interface Factory {
-
- DexClass create(DexType type, Origin origin, DexAccessFlags accessFlags, DexType superType,
- DexTypeList interfaces, DexString sourceFile, DexAnnotationSet annotations,
- DexEncodedField[] staticFields, DexEncodedField[] instanceFields,
- DexEncodedMethod[] directMethods, DexEncodedMethod[] virtualMethods);
- }
-
- public enum Origin {
- Dex, ClassFile, Synthetic
- }
-
private static final DexEncodedMethod[] NO_METHODS = {};
private static final DexEncodedField[] NO_FIELDS = {};
- public final Origin origin;
+ public final Resource.Kind origin;
public final DexType type;
public final DexAccessFlags accessFlags;
public DexType superType;
@@ -43,7 +30,7 @@
DexString sourceFile, DexTypeList interfaces, DexAccessFlags accessFlags, DexType superType,
DexType type, DexEncodedField[] staticFields, DexEncodedField[] instanceFields,
DexEncodedMethod[] directMethods, DexEncodedMethod[] virtualMethods,
- DexAnnotationSet annotations, Origin origin) {
+ DexAnnotationSet annotations, Resource.Kind origin) {
this.origin = origin;
this.sourceFile = sourceFile;
this.interfaces = interfaces;
@@ -168,7 +155,7 @@
}
@Override
- public Origin getOrigin() {
+ public Resource.Kind getOrigin() {
return this.origin;
}
@@ -182,19 +169,6 @@
return type;
}
- /** Get a class factory for a particular resource kind */
- public static Factory factoryForResourceKind(Resource.Kind kind) {
- switch (kind) {
- case PROGRAM:
- return DexProgramClass::new;
- case CLASSPATH:
- return DexClasspathClass::new;
- case LIBRARY:
- return DexLibraryClass::new;
- }
- throw new Unreachable();
- }
-
public boolean hasClassInitializer() {
return getClassInitializer() != null;
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexClassPromise.java b/src/main/java/com/android/tools/r8/graph/DexClassPromise.java
index 243eadf..c0bdf20 100644
--- a/src/main/java/com/android/tools/r8/graph/DexClassPromise.java
+++ b/src/main/java/com/android/tools/r8/graph/DexClassPromise.java
@@ -3,6 +3,8 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.graph;
+import com.android.tools.r8.Resource;
+
/**
* Provides a way for delayed DexClass discovery.
*
@@ -15,7 +17,7 @@
public interface DexClassPromise {
DexType getType();
- DexClass.Origin getOrigin();
+ Resource.Kind getOrigin();
boolean isProgramClass();
diff --git a/src/main/java/com/android/tools/r8/graph/DexClasspathClass.java b/src/main/java/com/android/tools/r8/graph/DexClasspathClass.java
index 0ec8cf7..dd5efbb 100644
--- a/src/main/java/com/android/tools/r8/graph/DexClasspathClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexClasspathClass.java
@@ -3,13 +3,14 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.graph;
+import com.android.tools.r8.Resource;
import com.android.tools.r8.dex.IndexedItemCollection;
import com.android.tools.r8.dex.MixedSectionCollection;
import com.android.tools.r8.errors.Unreachable;
public class DexClasspathClass extends DexClass {
- public DexClasspathClass(DexType type, Origin origin, DexAccessFlags accessFlags,
+ public DexClasspathClass(DexType type, Resource.Kind origin, DexAccessFlags accessFlags,
DexType superType, DexTypeList interfaces, DexString sourceFile, DexAnnotationSet annotations,
DexEncodedField[] staticFields, DexEncodedField[] instanceFields,
DexEncodedMethod[] directMethods, DexEncodedMethod[] virtualMethods) {
diff --git a/src/main/java/com/android/tools/r8/graph/DexLibraryClass.java b/src/main/java/com/android/tools/r8/graph/DexLibraryClass.java
index c4ed702..c1b9205 100644
--- a/src/main/java/com/android/tools/r8/graph/DexLibraryClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexLibraryClass.java
@@ -3,14 +3,15 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.graph;
+import com.android.tools.r8.Resource;
import com.android.tools.r8.dex.IndexedItemCollection;
import com.android.tools.r8.dex.MixedSectionCollection;
import com.android.tools.r8.errors.Unreachable;
public class DexLibraryClass extends DexClass {
- public DexLibraryClass(DexType type, Origin origin, DexAccessFlags accessFlags, DexType superType,
- DexTypeList interfaces, DexString sourceFile, DexAnnotationSet annotations,
+ public DexLibraryClass(DexType type, Resource.Kind origin, DexAccessFlags accessFlags,
+ DexType superType, DexTypeList interfaces, DexString sourceFile, DexAnnotationSet annotations,
DexEncodedField[] staticFields, DexEncodedField[] instanceFields,
DexEncodedMethod[] directMethods, DexEncodedMethod[] virtualMethods) {
super(sourceFile, interfaces, accessFlags, superType, type,
diff --git a/src/main/java/com/android/tools/r8/graph/DexProgramClass.java b/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
index 6713083..094a039 100644
--- a/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.graph;
+import com.android.tools.r8.Resource;
import com.android.tools.r8.dex.IndexedItemCollection;
import com.android.tools.r8.dex.MixedSectionCollection;
import java.util.Arrays;
@@ -12,7 +13,7 @@
private DexEncodedArray staticValues;
public DexProgramClass(DexType type,
- Origin origin,
+ Resource.Kind origin,
DexAccessFlags accessFlags,
DexType superType,
DexTypeList interfaces,
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 bca0d14..c738e17 100644
--- a/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java
+++ b/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java
@@ -58,10 +58,10 @@
this.classConsumer = classConsumer;
}
- public void read(String file, Resource.Kind kind, InputStream input) throws IOException {
+ public void read(String file, ClassKind classKind, InputStream input) throws IOException {
ClassReader reader = new ClassReader(input);
reader.accept(new CreateDexClassVisitor(
- file, kind, reader.b, application, classConsumer), SKIP_FRAMES);
+ file, classKind, reader.b, application, classConsumer), SKIP_FRAMES);
}
private static DexAccessFlags createAccessFlags(int access) {
@@ -92,7 +92,7 @@
private static class CreateDexClassVisitor extends ClassVisitor {
private final String file;
- private final Resource.Kind kind;
+ private final ClassKind classKind;
private final JarApplicationReader application;
private final Consumer<DexClass> classConsumer;
private final ReparseContext context = new ReparseContext();
@@ -115,13 +115,13 @@
public CreateDexClassVisitor(
String file,
- Resource.Kind kind,
+ ClassKind classKind,
byte[] classCache,
JarApplicationReader application,
Consumer<DexClass> classConsumer) {
super(ASM5);
this.file = file;
- this.kind = kind;
+ this.classKind = classKind;
this.classConsumer = classConsumer;
this.context.classCache = classCache;
this.application = application;
@@ -247,9 +247,9 @@
addAnnotation(DexAnnotation.createAnnotationDefaultAnnotation(
type, defaultAnnotations, application.getFactory()));
}
- DexClass clazz = DexClass.factoryForResourceKind(kind).create(
+ DexClass clazz = classKind.create(
type,
- DexClass.Origin.ClassFile,
+ Resource.Kind.CLASSFILE,
accessFlags,
superType,
interfaces,
@@ -259,7 +259,7 @@
instanceFields.toArray(new DexEncodedField[instanceFields.size()]),
directMethods.toArray(new DexEncodedMethod[directMethods.size()]),
virtualMethods.toArray(new DexEncodedMethod[virtualMethods.size()]));
- if (kind == Resource.Kind.PROGRAM) {
+ if (classKind == ClassKind.PROGRAM) {
context.owner = clazz.asProgramClass();
}
classConsumer.accept(clazz);
@@ -512,7 +512,7 @@
Code code = null;
if (!flags.isAbstract()
&& !flags.isNative()
- && parent.kind == Resource.Kind.PROGRAM) {
+ && parent.classKind == ClassKind.PROGRAM) {
code = new JarCode(method, parent.context, parent.application);
}
DexAnnotationSetRefList parameterAnnotationSets;
diff --git a/src/main/java/com/android/tools/r8/graph/LazyClassFileLoader.java b/src/main/java/com/android/tools/r8/graph/LazyClassFileLoader.java
index ce40d19..e5792cd 100644
--- a/src/main/java/com/android/tools/r8/graph/LazyClassFileLoader.java
+++ b/src/main/java/com/android/tools/r8/graph/LazyClassFileLoader.java
@@ -9,14 +9,15 @@
import com.android.tools.r8.Resource;
import com.android.tools.r8.errors.CompilationError;
import com.android.tools.r8.errors.Unreachable;
-import com.android.tools.r8.utils.InternalResource;
import com.google.common.io.Closer;
import java.io.IOException;
// Lazily loads a class file represented by resource.
public final class LazyClassFileLoader implements DexClassPromise {
// Resource representing file definition.
- private final InternalResource resource;
+ private final Resource resource;
+ // Class kind to be created.
+ private final ClassKind classKind;
// Application reader to be used. Note that the reader may be reused in
// many loaders and may be used concurrently, it is considered to be
@@ -32,10 +33,13 @@
// field is only accessed in context synchronized on `this`.
private DexClass loadedClass = null;
- public LazyClassFileLoader(DexType type, InternalResource resource, JarApplicationReader reader) {
+ public LazyClassFileLoader(DexType type,
+ Resource resource, ClassKind classKind, JarApplicationReader reader) {
this.resource = resource;
this.reader = reader;
this.type = type;
+ this.classKind = classKind;
+ assert classKind != ClassKind.PROGRAM;
}
// Callback method for JarClassFileReader, is always called in synchronized context.
@@ -51,23 +55,23 @@
}
@Override
- public DexClass.Origin getOrigin() {
- return DexClass.Origin.ClassFile;
+ public Resource.Kind getOrigin() {
+ return Resource.Kind.CLASSFILE;
}
@Override
public boolean isProgramClass() {
- return resource.getKind() == Resource.Kind.PROGRAM;
+ return false;
}
@Override
public boolean isClasspathClass() {
- return resource.getKind() == Resource.Kind.CLASSPATH;
+ return classKind == ClassKind.CLASSPATH;
}
@Override
public boolean isLibraryClass() {
- return resource.getKind() == Resource.Kind.LIBRARY;
+ return classKind == ClassKind.LIBRARY;
}
// Loads the class from the resource. Synchronized on `this` to avoid
@@ -81,7 +85,7 @@
try (Closer closer = Closer.create()) {
JarClassFileReader reader = new JarClassFileReader(this.reader, this::addClass);
- reader.read(DEFAULT_DEX_FILENAME, resource.getKind(), resource.getStream(closer));
+ reader.read(DEFAULT_DEX_FILENAME, classKind, resource.getStream(closer));
} catch (IOException e) {
throw new CompilationError("Failed to load class: " + type.toSourceString(), e);
}
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 215cfba..01be50d 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
@@ -4,12 +4,12 @@
package com.android.tools.r8.ir.desugar;
+import com.android.tools.r8.Resource;
import com.android.tools.r8.errors.CompilationError;
import com.android.tools.r8.errors.Unimplemented;
import com.android.tools.r8.graph.DexApplication.Builder;
import com.android.tools.r8.graph.DexCallSite;
import com.android.tools.r8.graph.DexClass;
-import com.android.tools.r8.graph.DexClassPromise;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethod;
@@ -217,7 +217,7 @@
private static boolean shouldProcess(
DexProgramClass clazz, Flavor flavour, boolean mustBeInterface) {
- return (clazz.getOrigin() != DexClass.Origin.Dex || flavour == Flavor.IncludeAllResources)
+ return (clazz.getOrigin() != Resource.Kind.DEX || flavour == Flavor.IncludeAllResources)
&& clazz.isInterface() == mustBeInterface;
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/InterfaceProcessor.java
index 66cd7d9..d1b1577 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/InterfaceProcessor.java
@@ -9,7 +9,6 @@
import com.android.tools.r8.graph.Code;
import com.android.tools.r8.graph.DexAccessFlags;
import com.android.tools.r8.graph.DexAnnotationSet;
-import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexCode;
import com.android.tools.r8.graph.DexEncodedField;
import com.android.tools.r8.graph.DexEncodedMethod;
@@ -128,7 +127,7 @@
DexType companionClassType = rewriter.getCompanionClassType(iface.type);
DexProgramClass companionClass = new DexProgramClass(
companionClassType,
- DexClass.Origin.Synthetic,
+ null,
companionClassFlags,
rewriter.factory.objectType,
DexTypeList.empty(),
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java b/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java
index db28115..37bfdaa 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java
@@ -10,7 +10,6 @@
import com.android.tools.r8.graph.DexAccessFlags;
import com.android.tools.r8.graph.DexAnnotationSet;
import com.android.tools.r8.graph.DexAnnotationSetRefList;
-import com.android.tools.r8.graph.DexApplication.Builder;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexClassPromise;
import com.android.tools.r8.graph.DexCode;
@@ -114,7 +113,7 @@
final DexProgramClass synthesizeLambdaClass() {
return new DexProgramClass(
type,
- DexClass.Origin.Synthetic,
+ null,
new DexAccessFlags(Constants.ACC_FINAL | Constants.ACC_SYNTHETIC),
rewriter.factory.objectType,
buildInterfaces(),
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/Outliner.java b/src/main/java/com/android/tools/r8/ir/optimize/Outliner.java
index 80a5975..42b5220 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/Outliner.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/Outliner.java
@@ -1028,7 +1028,7 @@
DexAccessFlags accessFlags = new DexAccessFlags(Constants.ACC_PUBLIC);
DexProgramClass clazz = new DexProgramClass(
type,
- DexClass.Origin.Synthetic,
+ null,
accessFlags,
superType,
interfaces,
diff --git a/src/main/java/com/android/tools/r8/utils/AndroidApp.java b/src/main/java/com/android/tools/r8/utils/AndroidApp.java
index 2b78295..453a250 100644
--- a/src/main/java/com/android/tools/r8/utils/AndroidApp.java
+++ b/src/main/java/com/android/tools/r8/utils/AndroidApp.java
@@ -10,6 +10,8 @@
import com.android.tools.r8.Resource;
import com.android.tools.r8.ResourceProvider;
import com.android.tools.r8.errors.CompilationError;
+import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.ClassKind;
import com.google.common.collect.ImmutableList;
import com.google.common.io.ByteStreams;
import com.google.common.io.Closer;
@@ -50,26 +52,32 @@
public static final String DEFAULT_PROGUARD_SEEDS_FILE = "proguard.seeds";
public static final String DEFAULT_PACKAGE_DISTRIBUTION_FILE = "package.map";
- private final ImmutableList<InternalResource> dexSources;
- private final ImmutableList<InternalResource> classSources;
- private final ImmutableList<ResourceProvider> resourceProviders;
- private final InternalResource proguardMap;
- private final InternalResource proguardSeeds;
- private final InternalResource packageDistribution;
- private final InternalResource mainDexList;
+ private final ImmutableList<Resource> programResources;
+ private final ImmutableList<Resource> classpathResources;
+ private final ImmutableList<Resource> libraryResources;
+ private final ImmutableList<ResourceProvider> classpathResourceProviders;
+ private final ImmutableList<ResourceProvider> libraryResourceProviders;
+ private final Resource proguardMap;
+ private final Resource proguardSeeds;
+ private final Resource packageDistribution;
+ private final Resource mainDexList;
// See factory methods and AndroidApp.Builder below.
private AndroidApp(
- ImmutableList<InternalResource> dexSources,
- ImmutableList<InternalResource> classSources,
- ImmutableList<ResourceProvider> resourceProviders,
- InternalResource proguardMap,
- InternalResource proguardSeeds,
- InternalResource packageDistribution,
- InternalResource mainDexList) {
- this.dexSources = dexSources;
- this.classSources = classSources;
- this.resourceProviders = resourceProviders;
+ ImmutableList<Resource> programResources,
+ ImmutableList<Resource> classpathResources,
+ ImmutableList<Resource> libraryResources,
+ ImmutableList<ResourceProvider> classpathResourceProviders,
+ ImmutableList<ResourceProvider> libraryResourceProviders,
+ Resource proguardMap,
+ Resource proguardSeeds,
+ Resource packageDistribution,
+ Resource mainDexList) {
+ this.programResources = programResources;
+ this.classpathResources = classpathResources;
+ this.libraryResources = libraryResources;
+ this.classpathResourceProviders = classpathResourceProviders;
+ this.libraryResourceProviders = libraryResourceProviders;
this.proguardMap = proguardMap;
this.proguardSeeds = proguardSeeds;
this.packageDistribution = packageDistribution;
@@ -140,45 +148,49 @@
}
/** Get input streams for all dex program resources. */
- public List<InternalResource> getDexProgramResources() {
- return filter(dexSources, Resource.Kind.PROGRAM);
+ public List<Resource> getDexProgramResources() {
+ return filter(programResources, Resource.Kind.DEX);
}
/** Get input streams for all Java-bytecode program resources. */
- public List<InternalResource> getClassProgramResources() {
- return filter(classSources, Resource.Kind.PROGRAM);
+ public List<Resource> getClassProgramResources() {
+ return filter(programResources, Resource.Kind.CLASSFILE);
}
/** Get input streams for all dex program classpath resources. */
- public List<InternalResource> getDexClasspathResources() {
- return filter(dexSources, Resource.Kind.CLASSPATH);
+ public List<Resource> getDexClasspathResources() {
+ return filter(classpathResources, Resource.Kind.DEX);
}
/** Get input streams for all Java-bytecode classpath resources. */
- public List<InternalResource> getClassClasspathResources() {
- return filter(classSources, Resource.Kind.CLASSPATH);
+ public List<Resource> getClassClasspathResources() {
+ return filter(classpathResources, Resource.Kind.CLASSFILE);
}
/** Get input streams for all dex library resources. */
- public List<InternalResource> getDexLibraryResources() {
- return filter(dexSources, Resource.Kind.LIBRARY);
+ public List<Resource> getDexLibraryResources() {
+ return filter(libraryResources, Resource.Kind.DEX);
}
/** Get input streams for all Java-bytecode library resources. */
- public List<InternalResource> getClassLibraryResources() {
- return filter(classSources, Resource.Kind.LIBRARY);
+ public List<Resource> getClassLibraryResources() {
+ return filter(libraryResources, Resource.Kind.CLASSFILE);
}
- /** Get lazy resource providers. */
- public List<ResourceProvider> getLazyResourceProviders() {
- return resourceProviders;
+ /** Get classpath resource providers. */
+ public List<ResourceProvider> getClasspathResourceProviders() {
+ return classpathResourceProviders;
}
- private List<InternalResource> filter(
- List<InternalResource> resources, Resource.Kind kind) {
- List<InternalResource> out = new ArrayList<>(resources.size());
- for (InternalResource resource : resources) {
- if (kind == resource.getKind()) {
+ /** Get library resource providers. */
+ public List<ResourceProvider> getLibraryResourceProviders() {
+ return libraryResourceProviders;
+ }
+
+ private List<Resource> filter(List<Resource> resources, Resource.Kind kind) {
+ List<Resource> out = new ArrayList<>(resources.size());
+ for (Resource resource : resources) {
+ if (kind == resource.kind) {
out.add(resource);
}
}
@@ -273,7 +285,7 @@
Path directory, OutputMode outputMode, boolean overwrite) throws IOException {
CopyOption[] options = copyOptions(overwrite);
try (Closer closer = Closer.create()) {
- List<InternalResource> dexProgramSources = getDexProgramResources();
+ List<Resource> dexProgramSources = getDexProgramResources();
for (int i = 0; i < dexProgramSources.size(); i++) {
Path fileName = directory.resolve(outputMode.getFileName(dexProgramSources.get(i), i));
Files.copy(dexProgramSources.get(i).getStream(closer), fileName, options);
@@ -286,7 +298,7 @@
public List<byte[]> writeToMemory() throws IOException {
List<byte[]> dex = new ArrayList<>();
try (Closer closer = Closer.create()) {
- List<InternalResource> dexProgramSources = getDexProgramResources();
+ List<Resource> dexProgramSources = getDexProgramResources();
for (int i = 0; i < dexProgramSources.size(); i++) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
ByteStreams.copy(dexProgramSources.get(i).getStream(closer), out);
@@ -312,7 +324,7 @@
OpenOption[] options = openOptions(overwrite);
try (Closer closer = Closer.create()) {
try (ZipOutputStream out = new ZipOutputStream(Files.newOutputStream(archive, options))) {
- List<InternalResource> dexProgramSources = getDexProgramResources();
+ List<Resource> dexProgramSources = getDexProgramResources();
for (int i = 0; i < dexProgramSources.size(); i++) {
ZipEntry zipEntry = new ZipEntry(outputMode.getFileName(dexProgramSources.get(i), i));
byte[] bytes = ByteStreams.toByteArray(dexProgramSources.get(i).getStream(closer));
@@ -368,13 +380,15 @@
*/
public static class Builder {
- private final List<InternalResource> dexSources = new ArrayList<>();
- private final List<InternalResource> classSources = new ArrayList<>();
- private final List<ResourceProvider> resourceProviders = new ArrayList<>();
- private InternalResource proguardMap;
- private InternalResource proguardSeeds;
- private InternalResource packageDistribution;
- private InternalResource mainDexList;
+ private final List<Resource> programResources = new ArrayList<>();
+ private final List<Resource> classpathResources = new ArrayList<>();
+ private final List<Resource> libraryResources = new ArrayList<>();
+ private final List<ResourceProvider> classpathResourceProviders = new ArrayList<>();
+ private final List<ResourceProvider> libraryResourceProviders = new ArrayList<>();
+ private Resource proguardMap;
+ private Resource proguardSeeds;
+ private Resource packageDistribution;
+ private Resource mainDexList;
// See AndroidApp::builder().
private Builder() {
@@ -382,9 +396,11 @@
// See AndroidApp::builder(AndroidApp).
private Builder(AndroidApp app) {
- dexSources.addAll(app.dexSources);
- classSources.addAll(app.classSources);
- resourceProviders.addAll(app.resourceProviders);
+ programResources.addAll(app.programResources);
+ classpathResources.addAll(app.classpathResources);
+ libraryResources.addAll(app.libraryResources);
+ classpathResourceProviders.addAll(app.classpathResourceProviders);
+ libraryResourceProviders.addAll(app.libraryResourceProviders);
proguardMap = app.proguardMap;
proguardSeeds = app.proguardSeeds;
packageDistribution = app.packageDistribution;
@@ -405,7 +421,7 @@
public Builder addProgramDirectory(Path directory) throws IOException {
File[] resources = directory.toFile().listFiles(file -> isDexFile(file.toPath()));
for (File source : resources) {
- addFile(source.toPath(), Resource.Kind.PROGRAM);
+ addFile(source.toPath(), ClassKind.PROGRAM);
}
File mapFile = new File(directory.toFile(), DEFAULT_PROGUARD_MAP_FILE);
if (mapFile.exists()) {
@@ -426,7 +442,7 @@
*/
public Builder addProgramFiles(Collection<Path> files) throws IOException {
for (Path file : files) {
- addFile(file, Resource.Kind.PROGRAM);
+ addFile(file, ClassKind.PROGRAM);
}
return this;
}
@@ -443,7 +459,7 @@
*/
public Builder addClasspathFiles(Collection<Path> files) throws IOException {
for (Path file : files) {
- addFile(file, Resource.Kind.CLASSPATH);
+ addFile(file, ClassKind.CLASSPATH);
}
return this;
}
@@ -452,7 +468,7 @@
* Add classpath resource provider.
*/
public Builder addClasspathResourceProvider(ResourceProvider provider) {
- resourceProviders.add(provider);
+ classpathResourceProviders.add(provider);
return this;
}
@@ -468,7 +484,7 @@
*/
public Builder addLibraryFiles(Collection<Path> files) throws IOException {
for (Path file : files) {
- addFile(file, Resource.Kind.LIBRARY);
+ addFile(file, ClassKind.LIBRARY);
}
return this;
}
@@ -477,7 +493,7 @@
* Add library resource provider.
*/
public Builder addLibraryResourceProvider(ResourceProvider provider) {
- resourceProviders.add(provider);
+ libraryResourceProviders.add(provider);
return this;
}
@@ -485,7 +501,8 @@
* Add dex program-data with class descriptor.
*/
public Builder addDexProgramData(byte[] data, Set<String> classDescriptors) {
- dexSources.add(InternalResource.fromBytes(Resource.Kind.PROGRAM, data, classDescriptors));
+ resources(ClassKind.PROGRAM).add(
+ Resource.fromBytes(Resource.Kind.DEX, data, classDescriptors));
return this;
}
@@ -501,7 +518,7 @@
*/
public Builder addDexProgramData(Collection<byte[]> data) {
for (byte[] datum : data) {
- dexSources.add(InternalResource.fromBytes(Resource.Kind.PROGRAM, datum));
+ resources(ClassKind.PROGRAM).add(Resource.fromBytes(Resource.Kind.DEX, datum));
}
return this;
}
@@ -518,7 +535,7 @@
*/
public Builder addClassProgramData(Collection<byte[]> data) {
for (byte[] datum : data) {
- classSources.add(InternalResource.fromBytes(Resource.Kind.PROGRAM, datum));
+ resources(ClassKind.PROGRAM).add(Resource.fromBytes(Resource.Kind.CLASSFILE, datum));
}
return this;
}
@@ -527,7 +544,7 @@
* Set proguard-map file.
*/
public Builder setProguardMapFile(Path file) {
- proguardMap = file == null ? null : InternalResource.fromFile(null, file);
+ proguardMap = file == null ? null : Resource.fromFile(null, file);
return this;
}
@@ -542,7 +559,7 @@
* Set proguard-map data.
*/
public Builder setProguardMapData(byte[] content) {
- proguardMap = content == null ? null : InternalResource.fromBytes(null, content);
+ proguardMap = content == null ? null : Resource.fromBytes(null, content);
return this;
}
@@ -550,7 +567,7 @@
* Set proguard-seeds data.
*/
public Builder setProguardSeedsData(byte[] content) {
- proguardSeeds = content == null ? null : InternalResource.fromBytes(null, content);
+ proguardSeeds = content == null ? null : Resource.fromBytes(null, content);
return this;
}
@@ -558,7 +575,7 @@
* Set the package-distribution file.
*/
public Builder setPackageDistributionFile(Path file) {
- packageDistribution = file == null ? null : InternalResource.fromFile(null, file);
+ packageDistribution = file == null ? null : Resource.fromFile(null, file);
return this;
}
@@ -566,7 +583,7 @@
* Set the main-dex list file.
*/
public Builder setMainDexListFile(Path file) {
- mainDexList = file == null ? null : InternalResource.fromFile(null, file);
+ mainDexList = file == null ? null : Resource.fromFile(null, file);
return this;
}
@@ -575,31 +592,45 @@
*/
public AndroidApp build() {
return new AndroidApp(
- ImmutableList.copyOf(dexSources),
- ImmutableList.copyOf(classSources),
- ImmutableList.copyOf(resourceProviders),
+ ImmutableList.copyOf(programResources),
+ ImmutableList.copyOf(classpathResources),
+ ImmutableList.copyOf(libraryResources),
+ ImmutableList.copyOf(classpathResourceProviders),
+ ImmutableList.copyOf(libraryResourceProviders),
proguardMap,
proguardSeeds,
packageDistribution,
mainDexList);
}
- private void addFile(Path file, Resource.Kind kind) throws IOException {
+ private List<Resource> resources(ClassKind classKind) {
+ switch (classKind) {
+ case PROGRAM:
+ return programResources;
+ case CLASSPATH:
+ return classpathResources;
+ case LIBRARY:
+ return libraryResources;
+ }
+ throw new Unreachable();
+ }
+
+ private void addFile(Path file, ClassKind classKind) throws IOException {
if (!Files.exists(file)) {
throw new FileNotFoundException("Non-existent input file: " + file);
}
if (isDexFile(file)) {
- dexSources.add(InternalResource.fromFile(kind, file));
+ resources(classKind).add(Resource.fromFile(Resource.Kind.DEX, file));
} else if (isClassFile(file)) {
- classSources.add(InternalResource.fromFile(kind, file));
+ resources(classKind).add(Resource.fromFile(Resource.Kind.CLASSFILE, file));
} else if (isArchive(file)) {
- addArchive(file, kind);
+ addArchive(file, classKind);
} else {
throw new CompilationError("Unsupported source file type for file: " + file);
}
}
- private void addArchive(Path archive, Resource.Kind kind) throws IOException {
+ private void addArchive(Path archive, ClassKind classKind) throws IOException {
assert isArchive(archive);
boolean containsDexData = false;
boolean containsClassData = false;
@@ -609,12 +640,13 @@
Path name = Paths.get(entry.getName());
if (isDexFile(name)) {
containsDexData = true;
- dexSources.add(InternalResource.fromBytes(kind, ByteStreams.toByteArray(stream)));
+ resources(classKind).add(Resource.fromBytes(
+ Resource.Kind.DEX, ByteStreams.toByteArray(stream)));
} else if (isClassFile(name)) {
containsClassData = true;
String descriptor = PreloadedResourceProvider.guessTypeDescriptor(name);
- classSources.add(InternalResource.fromBytes(
- kind, ByteStreams.toByteArray(stream), Collections.singleton(descriptor)));
+ resources(classKind).add(Resource.fromBytes(Resource.Kind.CLASSFILE,
+ ByteStreams.toByteArray(stream), Collections.singleton(descriptor)));
}
}
} catch (ZipException e) {
diff --git a/src/main/java/com/android/tools/r8/utils/DirectoryResourceProvider.java b/src/main/java/com/android/tools/r8/utils/DirectoryResourceProvider.java
index 1d2ff81..b003d86 100644
--- a/src/main/java/com/android/tools/r8/utils/DirectoryResourceProvider.java
+++ b/src/main/java/com/android/tools/r8/utils/DirectoryResourceProvider.java
@@ -10,13 +10,15 @@
import java.io.File;
import java.nio.file.Path;
-/** Lazy resource provider based on filesystem directory content. */
+/**
+ * Lazy resource provider based on filesystem directory content.
+ *
+ * NOTE: only handles classfile resources.
+ */
public final class DirectoryResourceProvider implements ResourceProvider {
- private final Resource.Kind kind;
private final Path root;
- private DirectoryResourceProvider(Resource.Kind kind, Path root) {
- this.kind = kind;
+ private DirectoryResourceProvider(Path root) {
this.root = root;
}
@@ -30,11 +32,11 @@
File file = filePath.toFile();
return (file.exists() && !file.isDirectory())
- ? InternalResource.fromFile(kind, filePath) : null;
+ ? Resource.fromFile(Resource.Kind.CLASSFILE, filePath) : null;
}
/** Create resource provider from directory path. */
- public static ResourceProvider fromDirectory(Resource.Kind kind, Path dir) {
- return new DirectoryResourceProvider(kind, dir.toAbsolutePath());
+ public static ResourceProvider fromDirectory(Path dir) {
+ return new DirectoryResourceProvider(dir.toAbsolutePath());
}
}
diff --git a/src/main/java/com/android/tools/r8/utils/InternalResource.java b/src/main/java/com/android/tools/r8/utils/InternalResource.java
deleted file mode 100644
index 9181092..0000000
--- a/src/main/java/com/android/tools/r8/utils/InternalResource.java
+++ /dev/null
@@ -1,105 +0,0 @@
-// 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.
-
-package com.android.tools.r8.utils;
-
-import com.android.tools.r8.Resource;
-import com.google.common.io.Closer;
-import java.io.ByteArrayInputStream;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.nio.file.Path;
-import java.util.Set;
-
-/**
- * Internal resource class that is not intended for use from the outside.
- *
- * <p>This is only here to hide the creation and class descriptor methods
- * from the javadoc for the D8 API. If we decide to expose those methods
- * later the split between Resource and InternalResource can be removed.
- */
-public abstract class InternalResource implements Resource {
-
- private final Kind kind;
-
- private InternalResource(Kind kind) {
- this.kind = kind;
- }
-
- /** Get the kind of the resource. */
- public Kind getKind() {
- return kind;
- }
-
- /** Create an application resource for a given file and kind. */
- public static InternalResource fromFile(Kind kind, Path file) {
- return new FileResource(kind, file);
- }
-
- /** Create an application resource for a given content and kind. */
- public static InternalResource fromBytes(Kind kind, byte[] bytes) {
- return fromBytes(kind, bytes, null);
- }
-
- /** Create an application resource for a given content, kind and type descriptor. */
- public static InternalResource fromBytes(Kind kind, byte[] bytes, Set<String> typeDescriptors) {
- return new ByteResource(kind, bytes, typeDescriptors);
- }
-
- /**
- * If the resource represents a single class returns
- * its descriptor, returns `null` otherwise.
- */
- public String getSingleClassDescriptorOrNull() {
- Set<String> descriptors = getClassDescriptors();
- return (descriptors == null) || (descriptors.size() != 1)
- ? null : descriptors.iterator().next();
- }
-
- /** File based application resource. */
- private static class FileResource extends InternalResource {
- final Path file;
-
- FileResource(Kind kind, Path file) {
- super(kind);
- assert file != null;
- this.file = file;
- }
-
- @Override
- public Set<String> getClassDescriptors() {
- return null;
- }
-
- @Override
- public InputStream getStream(Closer closer) throws IOException {
- return closer.register(new FileInputStream(file.toFile()));
- }
- }
-
- /** Byte content based application resource. */
- private static class ByteResource extends InternalResource {
- final Set<String> classDescriptors;
- final byte[] bytes;
-
- ByteResource(Kind kind, byte[] bytes, Set<String> classDescriptors) {
- super(kind);
- assert bytes != null;
- this.classDescriptors = classDescriptors;
- this.bytes = bytes;
- }
-
- @Override
- public Set<String> getClassDescriptors() {
- return classDescriptors;
- }
-
- @Override
- public InputStream getStream(Closer closer) throws IOException {
- // Note: closing a byte-array input stream is a no-op.
- return new ByteArrayInputStream(bytes);
- }
- }
-}
diff --git a/src/main/java/com/android/tools/r8/utils/LazyClassCollection.java b/src/main/java/com/android/tools/r8/utils/LazyClassCollection.java
index 4f36811..0e71973 100644
--- a/src/main/java/com/android/tools/r8/utils/LazyClassCollection.java
+++ b/src/main/java/com/android/tools/r8/utils/LazyClassCollection.java
@@ -7,6 +7,7 @@
import com.android.tools.r8.ResourceProvider;
import com.android.tools.r8.errors.CompilationError;
import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.ClassKind;
import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexClassPromise;
@@ -39,7 +40,8 @@
private final Map<DexType, DexClassPromise> classes = new IdentityHashMap<>();
// Available lazy resource providers.
- private final List<ResourceProvider> providers;
+ private final List<ResourceProvider> classpathProviders;
+ private final List<ResourceProvider> libraryProviders;
// Application reader to be used. Note that the reader may be reused in
// many loaders and may be used concurrently, it is considered to be
@@ -48,8 +50,10 @@
// which is thread-safe).
private final JarApplicationReader reader;
- public LazyClassCollection(JarApplicationReader reader, List<ResourceProvider> providers) {
- this.providers = ImmutableList.copyOf(providers);
+ public LazyClassCollection(JarApplicationReader reader,
+ List<ResourceProvider> classpathProviders, List<ResourceProvider> libraryProviders) {
+ this.classpathProviders = ImmutableList.copyOf(classpathProviders);
+ this.libraryProviders = ImmutableList.copyOf(libraryProviders);
this.reader = reader;
}
@@ -92,25 +96,30 @@
// provided resource for this type.
private DexClassPromise buildPromiseChain(DexType type) {
String descriptor = type.descriptor.toString();
- DexClassPromise promise = null;
- int size = providers.size();
- for (int i = size - 1; i >= 0; i--) {
- Resource resource = providers.get(i).getResource(descriptor);
+ DexClassPromise promise = buildPromiseChain(
+ type, descriptor, null, classpathProviders, ClassKind.CLASSPATH);
+ promise = buildPromiseChain(
+ type, descriptor, promise, libraryProviders, ClassKind.LIBRARY);
+ return promise == null ? EmptyPromise.INSTANCE : promise;
+ }
+
+ private DexClassPromise buildPromiseChain(DexType type, String descriptor,
+ DexClassPromise promise, List<ResourceProvider> providers, ClassKind classKind) {
+ for (ResourceProvider provider : providers) {
+ Resource resource = provider.getResource(descriptor);
if (resource == null) {
continue;
}
- if (resource.getKind() == Resource.Kind.PROGRAM) {
- throw new CompilationError("Attempt to load program class " +
- type.toSourceString() + " via lazy resource provider");
+ if (resource.kind != Resource.Kind.CLASSFILE) {
+ throw new CompilationError("Resource returned by resource provider for type " +
+ type.toSourceString() + " must be a class file resource.");
}
- assert resource instanceof InternalResource;
- LazyClassFileLoader loader =
- new LazyClassFileLoader(type, (InternalResource) resource, reader);
+ LazyClassFileLoader loader = new LazyClassFileLoader(type, resource, classKind, reader);
promise = (promise == null) ? loader : new DexClassPromiseChain(loader, promise);
}
- return promise == null ? EmptyPromise.INSTANCE : promise;
+ return promise;
}
// Chooses the proper promise. Recursion is not expected to be deep.
@@ -130,7 +139,7 @@
}
@Override
- public DexClass.Origin getOrigin() {
+ public Resource.Kind getOrigin() {
throw new Unreachable();
}
@@ -172,7 +181,7 @@
}
@Override
- public DexClass.Origin getOrigin() {
+ public Resource.Kind getOrigin() {
return promise.getOrigin();
}
diff --git a/src/main/java/com/android/tools/r8/utils/OutputMode.java b/src/main/java/com/android/tools/r8/utils/OutputMode.java
index c27429a..ce743e8 100644
--- a/src/main/java/com/android/tools/r8/utils/OutputMode.java
+++ b/src/main/java/com/android/tools/r8/utils/OutputMode.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.utils;
import com.android.tools.r8.Resource;
+import java.util.Set;
/** Defines way the output is formed. */
public enum OutputMode {
@@ -16,9 +17,10 @@
FilePerClass {
@Override
String getFileName(Resource resource, int index) {
- assert resource instanceof InternalResource;
- String classDescriptor = ((InternalResource) resource).getSingleClassDescriptorOrNull();
- assert classDescriptor != null;
+ Set<String> classDescriptors = resource.getClassDescriptors();
+ assert classDescriptors != null;
+ assert classDescriptors.size() == 1;
+ String classDescriptor = classDescriptors.iterator().next();
assert !classDescriptor.contains(".");
return DescriptorUtils.descriptorToJavaType(classDescriptor) + ".dex";
}
diff --git a/src/main/java/com/android/tools/r8/utils/PreloadedResourceProvider.java b/src/main/java/com/android/tools/r8/utils/PreloadedResourceProvider.java
index e3d5652..fcb89d4 100644
--- a/src/main/java/com/android/tools/r8/utils/PreloadedResourceProvider.java
+++ b/src/main/java/com/android/tools/r8/utils/PreloadedResourceProvider.java
@@ -22,13 +22,15 @@
import java.util.zip.ZipException;
import java.util.zip.ZipInputStream;
-/** Lazy resource provider based on preloaded/prebuilt context. */
+/**
+ * Lazy resource provider based on preloaded/prebuilt context.
+ *
+ * NOTE: only handles classfile resources.
+ */
public final class PreloadedResourceProvider implements ResourceProvider {
- private final Resource.Kind kind;
private final Map<String, byte[]> content;
- private PreloadedResourceProvider(Resource.Kind kind, Map<String, byte[]> content) {
- this.kind = kind;
+ private PreloadedResourceProvider(Map<String, byte[]> content) {
this.content = content;
}
@@ -38,12 +40,11 @@
if (bytes == null) {
return null;
}
- return InternalResource.fromBytes(kind, bytes, Collections.singleton(descriptor));
+ return Resource.fromBytes(Resource.Kind.CLASSFILE, bytes, Collections.singleton(descriptor));
}
/** Create preloaded content resource provider from archive file. */
- public static ResourceProvider fromArchive(
- Resource.Kind kind, Path archive) throws IOException {
+ public static ResourceProvider fromArchive(Path archive) throws IOException {
assert isArchive(archive);
Builder builder = builder();
try (ZipInputStream stream = new ZipInputStream(new FileInputStream(archive.toFile()))) {
@@ -59,7 +60,7 @@
"Zip error while reading '" + archive + "': " + e.getMessage(), e);
}
- return builder.build(kind);
+ return builder.build();
}
// Guess class descriptor from location of the class file.
@@ -99,10 +100,9 @@
return this;
}
- public PreloadedResourceProvider build(Resource.Kind kind) {
+ public PreloadedResourceProvider build() {
assert content != null;
- assert kind != null;
- PreloadedResourceProvider provider = new PreloadedResourceProvider(kind, content);
+ PreloadedResourceProvider provider = new PreloadedResourceProvider(content);
content = null;
return provider;
}
diff --git a/src/test/java/com/android/tools/r8/D8IncrementalRunExamplesAndroidOTest.java b/src/test/java/com/android/tools/r8/D8IncrementalRunExamplesAndroidOTest.java
index e2e88e2..728f769 100644
--- a/src/test/java/com/android/tools/r8/D8IncrementalRunExamplesAndroidOTest.java
+++ b/src/test/java/com/android/tools/r8/D8IncrementalRunExamplesAndroidOTest.java
@@ -10,7 +10,6 @@
import com.android.tools.r8.errors.InternalCompilerError;
import com.android.tools.r8.errors.Unimplemented;
import com.android.tools.r8.utils.AndroidApp;
-import com.android.tools.r8.utils.InternalResource;
import com.android.tools.r8.utils.OffOrAuto;
import com.android.tools.r8.utils.OutputMode;
import com.beust.jcommander.internal.Lists;
@@ -26,6 +25,7 @@
import java.util.Collections;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.function.UnaryOperator;
@@ -74,9 +74,11 @@
List<String> classFiles = collectClassFiles(testJarFile);
AndroidApp app = compileClassFiles(
testJarFile, classFiles, output, OutputMode.FilePerClass);
- for (InternalResource resource : app.getDexProgramResources()) {
- String classDescriptor = resource.getSingleClassDescriptorOrNull();
- Assert.assertNotNull("Add resources are expected to have a descriptor", classDescriptor);
+ for (Resource resource : app.getDexProgramResources()) {
+ Set<String> descriptors = resource.getClassDescriptors();
+ Assert.assertNotNull(descriptors);
+ Assert.assertEquals(1, descriptors.size());
+ String classDescriptor = descriptors.iterator().next();
classDescriptor = classDescriptor.substring(1, classDescriptor.length() - 1);
fileToResource.put(classDescriptor + ".class", resource);
}
diff --git a/src/test/java/com/android/tools/r8/D8ResourceProviderRunExamplesAndroidOTest.java b/src/test/java/com/android/tools/r8/D8ResourceProviderRunExamplesAndroidOTest.java
index b7181b8..7cef1a4 100644
--- a/src/test/java/com/android/tools/r8/D8ResourceProviderRunExamplesAndroidOTest.java
+++ b/src/test/java/com/android/tools/r8/D8ResourceProviderRunExamplesAndroidOTest.java
@@ -25,14 +25,13 @@
private void addClasspathPath(Path location, D8Command.Builder builder) {
builder.addClasspathResourceProvider(
- DirectoryResourceProvider.fromDirectory(
- Resource.Kind.CLASSPATH, location.resolve("..")));
+ DirectoryResourceProvider.fromDirectory(location.resolve("..")));
}
@Override
void addLibraryReference(D8Command.Builder builder, Path location) throws IOException {
builder.addLibraryResourceProvider(
- PreloadedResourceProvider.fromArchive(Resource.Kind.LIBRARY, location));
+ PreloadedResourceProvider.fromArchive(location));
}
}
diff --git a/src/test/java/com/android/tools/r8/internal/R8GMSCoreDeterministicTest.java b/src/test/java/com/android/tools/r8/internal/R8GMSCoreDeterministicTest.java
index d9314d8..2bc8dba 100644
--- a/src/test/java/com/android/tools/r8/internal/R8GMSCoreDeterministicTest.java
+++ b/src/test/java/com/android/tools/r8/internal/R8GMSCoreDeterministicTest.java
@@ -8,10 +8,10 @@
import com.android.tools.r8.CompilationException;
import com.android.tools.r8.R8Command;
+import com.android.tools.r8.Resource;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.shaking.ProguardRuleParserException;
import com.android.tools.r8.utils.AndroidApp;
-import com.android.tools.r8.utils.InternalResource;
import com.android.tools.r8.utils.OutputMode;
import com.google.common.io.ByteStreams;
import com.google.common.io.Closer;
@@ -43,8 +43,8 @@
// Verify that the result of the two compilations was the same.
try (Closer closer = Closer.create()) {
- List<InternalResource> files1 = app1.getDexProgramResources();
- List<InternalResource> files2 = app2.getDexProgramResources();
+ List<Resource> files1 = app1.getDexProgramResources();
+ List<Resource> files2 = app2.getDexProgramResources();
assertEquals(files1.size(), files2.size());
for (int index = 0; index < files1.size(); index++) {
InputStream file1 = files1.get(index).getStream(closer);
diff --git a/src/test/java/com/android/tools/r8/internal/R8GMSCoreTreeShakeJarVerificationTest.java b/src/test/java/com/android/tools/r8/internal/R8GMSCoreTreeShakeJarVerificationTest.java
index fecc360..d28c37d 100644
--- a/src/test/java/com/android/tools/r8/internal/R8GMSCoreTreeShakeJarVerificationTest.java
+++ b/src/test/java/com/android/tools/r8/internal/R8GMSCoreTreeShakeJarVerificationTest.java
@@ -10,7 +10,7 @@
import com.android.tools.r8.R8RunArtTestsTest.CompilerUnderTest;
import com.android.tools.r8.shaking.ProguardRuleParserException;
import com.android.tools.r8.utils.AndroidApp;
-import com.android.tools.r8.utils.InternalResource;
+import com.android.tools.r8.Resource;
import com.google.common.collect.ImmutableList;
import com.google.common.io.ByteStreams;
import com.google.common.io.Closer;
@@ -33,7 +33,7 @@
ImmutableList.of());
int bytes = 0;
try (Closer closer = Closer.create()) {
- for (InternalResource dex : app.getDexProgramResources()) {
+ for (Resource dex : app.getDexProgramResources()) {
bytes += ByteStreams.toByteArray(dex.getStream(closer)).length;
}
}
diff --git a/src/test/java/com/android/tools/r8/internal/YouTubeTreeShakeJarVerificationTest.java b/src/test/java/com/android/tools/r8/internal/YouTubeTreeShakeJarVerificationTest.java
index 8b5b814..b26d1aa 100644
--- a/src/test/java/com/android/tools/r8/internal/YouTubeTreeShakeJarVerificationTest.java
+++ b/src/test/java/com/android/tools/r8/internal/YouTubeTreeShakeJarVerificationTest.java
@@ -10,7 +10,7 @@
import com.android.tools.r8.R8RunArtTestsTest.CompilerUnderTest;
import com.android.tools.r8.shaking.ProguardRuleParserException;
import com.android.tools.r8.utils.AndroidApp;
-import com.android.tools.r8.utils.InternalResource;
+import com.android.tools.r8.Resource;
import com.google.common.collect.ImmutableList;
import com.google.common.io.ByteStreams;
import com.google.common.io.Closer;
@@ -35,7 +35,7 @@
ImmutableList.of());
int bytes = 0;
try (Closer closer = Closer.create()) {
- for (InternalResource dex : app.getDexProgramResources()) {
+ for (Resource dex : app.getDexProgramResources()) {
bytes += ByteStreams.toByteArray(dex.getStream(closer)).length;
}
}
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 29cef19..44c2156 100644
--- a/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
+++ b/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
@@ -24,7 +24,6 @@
import com.android.tools.r8.graph.DexAnnotationSet;
import com.android.tools.r8.graph.DexAnnotationSetRefList;
import com.android.tools.r8.graph.DexApplication;
-import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexEncodedField;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexItemFactory;
@@ -291,7 +290,7 @@
builder.addClassPromise(
new DexProgramClass(
type,
- DexClass.Origin.Synthetic,
+ null,
new DexAccessFlags(),
factory.objectType,
DexTypeList.empty(),