blob: 7005e066b1b973f719e34af4c79d1ef2c7d9c499 [file] [log] [blame]
// 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.DataResourceProvider;
import com.android.tools.r8.dex.ApplicationReader.ProgramClassConflictResolver;
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.Timing;
import com.google.common.collect.ImmutableList;
import java.util.Collections;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
public class LazyLoadedDexApplication extends DexApplication {
private final ProgramClassCollection programClasses;
private final ClasspathClassCollection classpathClasses;
private final LibraryClassCollection libraryClasses;
/** Constructor should only be invoked by the DexApplication.Builder. */
private LazyLoadedDexApplication(
ClassNameMapper proguardMap,
ProgramClassCollection programClasses,
ImmutableList<DataResourceProvider> dataResourceProviders,
ClasspathClassCollection classpathClasses,
LibraryClassCollection libraryClasses,
InternalOptions options,
DexString highestSortingString,
Timing timing) {
super(
proguardMap,
dataResourceProviders,
options,
highestSortingString,
timing);
this.programClasses = programClasses;
this.classpathClasses = classpathClasses;
this.libraryClasses = libraryClasses;
}
@Override
List<DexProgramClass> programClasses() {
programClasses.forceLoad(t -> true);
return programClasses.getAllClasses();
}
@Override
public DexClass definitionFor(DexType type) {
assert type.isClassType() : "Cannot lookup definition for type: " + type;
DexClass clazz = null;
if (options.lookupLibraryBeforeProgram) {
if (libraryClasses != null) {
clazz = libraryClasses.get(type);
}
if (clazz == null) {
clazz = programClasses.get(type);
}
if (clazz == null && classpathClasses != null) {
clazz = classpathClasses.get(type);
}
} else {
clazz = programClasses.get(type);
if (clazz == null && classpathClasses != null) {
clazz = classpathClasses.get(type);
}
if (clazz == null && libraryClasses != null) {
clazz = libraryClasses.get(type);
}
}
return clazz;
}
@Override
public DexProgramClass programDefinitionFor(DexType type) {
assert type.isClassType() : "Cannot lookup definition for type: " + type;
return programClasses.get(type);
}
public DexLibraryClass libraryDefinitionFor(DexType type) {
assert type.isClassType() : "Cannot lookup library definition for type: " + type;
return libraryClasses.get(type);
}
static class AllClasses {
// Mapping of all types to their definitions.
private final Map<DexType, DexClass> allClasses;
// Collections of the three different types for iteration.
private final ImmutableList<DexProgramClass> programClasses;
private final ImmutableList<DexClasspathClass> classpathClasses;
private final ImmutableList<DexLibraryClass> libraryClasses;
AllClasses(
LibraryClassCollection libraryClassesLoader,
ClasspathClassCollection classpathClassesLoader,
ProgramClassCollection programClassesLoader,
InternalOptions options) {
int expectedMaxSize = 0;
// Force-load library classes.
Map<DexType, DexLibraryClass> allLibraryClasses = null;
if (libraryClassesLoader != null) {
libraryClassesLoader.forceLoad(type -> true);
allLibraryClasses = libraryClassesLoader.getAllClassesInMap();
expectedMaxSize += allLibraryClasses.size();
}
// Program classes should be fully loaded.
assert programClassesLoader != null;
assert programClassesLoader.isFullyLoaded();
programClassesLoader.forceLoad(type -> true);
Map<DexType, DexProgramClass> allProgramClasses = programClassesLoader.getAllClassesInMap();
expectedMaxSize += allProgramClasses.size();
// Force-load classpath classes.
Map<DexType, DexClasspathClass> allClasspathClasses = null;
if (classpathClassesLoader != null) {
classpathClassesLoader.forceLoad(type -> true);
allClasspathClasses = classpathClassesLoader.getAllClassesInMap();
expectedMaxSize += allClasspathClasses.size();
}
// Collect loaded classes in the precedence order library classes, program classes and
// class path classes or program classes, classpath classes and library classes depending
// on the configured lookup order.
Map<DexType, DexClass> prioritizedClasses = new IdentityHashMap<>(expectedMaxSize);
if (options.lookupLibraryBeforeProgram) {
libraryClasses = fillPrioritizedClasses(allLibraryClasses, prioritizedClasses);
programClasses = fillPrioritizedClasses(allProgramClasses, prioritizedClasses);
classpathClasses = fillPrioritizedClasses(allClasspathClasses, prioritizedClasses);
} else {
programClasses = fillPrioritizedClasses(allProgramClasses, prioritizedClasses);
classpathClasses = fillPrioritizedClasses(allClasspathClasses, prioritizedClasses);
libraryClasses = fillPrioritizedClasses(allLibraryClasses, prioritizedClasses);
}
allClasses = Collections.unmodifiableMap(prioritizedClasses);
assert prioritizedClasses.size()
== libraryClasses.size() + classpathClasses.size() + programClasses.size();
}
public Map<DexType, DexClass> getAllClasses() {
return allClasses;
}
public ImmutableList<DexProgramClass> getProgramClasses() {
return programClasses;
}
public ImmutableList<DexClasspathClass> getClasspathClasses() {
return classpathClasses;
}
public ImmutableList<DexLibraryClass> getLibraryClasses() {
return libraryClasses;
}
}
private static <T extends DexClass> ImmutableList<T> fillPrioritizedClasses(
Map<DexType, T> classCollection, Map<DexType, DexClass> prioritizedClasses) {
if (classCollection != null) {
ImmutableList.Builder<T> builder = ImmutableList.builder();
classCollection.forEach(
(type, clazz) -> {
if (!prioritizedClasses.containsKey(type)) {
prioritizedClasses.put(type, clazz);
builder.add(clazz);
}
});
return builder.build();
} else {
return ImmutableList.of();
}
}
/**
* Force load all classes and return type -> class map containing all the classes.
*/
public AllClasses loadAllClasses() {
return new AllClasses(libraryClasses, classpathClasses, programClasses, options);
}
public static class Builder extends DexApplication.Builder<Builder> {
private ClasspathClassCollection classpathClasses;
private LibraryClassCollection libraryClasses;
private final ProgramClassConflictResolver resolver;
Builder(ProgramClassConflictResolver resolver, InternalOptions options, Timing timing) {
super(options, timing);
this.resolver = resolver;
this.classpathClasses = ClasspathClassCollection.empty();
this.libraryClasses = null;
}
private Builder(LazyLoadedDexApplication application) {
super(application);
this.resolver = ProgramClassCollection.defaultConflictResolver(application.options.reporter);
this.classpathClasses = application.classpathClasses;
this.libraryClasses = application.libraryClasses;
}
@Override
Builder self() {
return this;
}
public Builder setClasspathClassCollection(ClasspathClassCollection classes) {
this.classpathClasses = classes;
return this;
}
public Builder setLibraryClassCollection(LibraryClassCollection classes) {
this.libraryClasses = classes;
return this;
}
@Override
public LazyLoadedDexApplication build() {
return new LazyLoadedDexApplication(
proguardMap,
ProgramClassCollection.create(getProgramClasses(), resolver),
ImmutableList.copyOf(dataResourceProviders),
classpathClasses,
libraryClasses,
options,
highestSortingString,
timing);
}
}
@Override
public Builder builder() {
return new Builder(this);
}
@Override
public DirectMappedDexApplication toDirect() {
return new DirectMappedDexApplication.Builder(this).build().asDirect();
}
@Override
public boolean isDirect() {
return false;
}
@Override
public String toString() {
return "Application (" + programClasses + "; " + classpathClasses + "; " + libraryClasses
+ ")";
}
}