blob: b236428fa3006caea68e86260bfb50b54c2bfdde [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.ProgramResourceProvider;
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.LibraryClassCollection;
import com.android.tools.r8.utils.ProgramClassCollection;
import com.android.tools.r8.utils.Timing;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import java.util.IdentityHashMap;
import java.util.Map;
public class LazyLoadedDexApplication extends DexApplication {
private final ClasspathClassCollection classpathClasses;
private final LibraryClassCollection libraryClasses;
/**
* Constructor should only be invoked by the DexApplication.Builder.
*/
private LazyLoadedDexApplication(ClassNameMapper proguardMap,
ProgramClassCollection programClasses,
ImmutableList<ProgramResourceProvider> programResourceProviders,
ClasspathClassCollection classpathClasses,
LibraryClassCollection libraryClasses,
ImmutableSet<DexType> mainDexList, String deadCode,
DexItemFactory dexItemFactory, DexString highestSortingString,
Timing timing) {
super(proguardMap, programClasses, programResourceProviders, mainDexList, deadCode,
dexItemFactory, highestSortingString, timing);
this.classpathClasses = classpathClasses;
this.libraryClasses = libraryClasses;
}
@Override
public DexClass definitionFor(DexType type) {
assert type.isClassType() : "Cannot lookup definition for type: " + type;
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;
}
static class AllClasses {
private Map<DexType, DexClass> libraryClasses;
private Map<DexType, DexClass> classpathClasses;
private Map<DexType, DexClass> programClasses;
private Map<DexType, DexClass> classes;
AllClasses(
LibraryClassCollection libraryClasses,
ClasspathClassCollection classpathClasses,
ProgramClassCollection programClasses) {
load(libraryClasses, classpathClasses, programClasses);
// Collect loaded classes in the precedence order program classes, class path classes and
// library classes.
// TODO(b/120884788): Change this.
classes = new IdentityHashMap<>();
classes.putAll(this.programClasses);
if (classpathClasses != null) {
classpathClasses.getAllClasses().forEach(clazz -> classes.putIfAbsent(clazz.type, clazz));
}
if (libraryClasses != null) {
libraryClasses.getAllClasses().forEach(clazz -> classes.putIfAbsent(clazz.type, clazz));
}
}
public Map<DexType, DexClass> getLibraryClasses() {
return libraryClasses;
}
public Map<DexType, DexClass> getClasspathClasses() {
return classpathClasses;
}
public Map<DexType, DexClass> getClasses() {
return classes;
}
private void load(
LibraryClassCollection libraryClasses,
ClasspathClassCollection classpathClasses,
ProgramClassCollection programClasses) {
if (libraryClasses != null) {
libraryClasses.forceLoad(type -> true);
this.libraryClasses = libraryClasses.getAllClassesInMap();
}
if (classpathClasses != null) {
classpathClasses.forceLoad(type -> true);
this.classpathClasses = classpathClasses.getAllClassesInMap();
}
assert programClasses != null;
// Program classes are supposed to be loaded, but force-loading them is no-op.
programClasses.forceLoad(type -> true);
this.programClasses = programClasses.getAllClassesInMap();
}
}
/**
* Force load all classes and return type -> class map containing all the classes.
*/
public AllClasses loadAllClasses() {
return new AllClasses(libraryClasses, classpathClasses, programClasses);
}
public static class Builder extends DexApplication.Builder<Builder> {
private ClasspathClassCollection classpathClasses;
private LibraryClassCollection libraryClasses;
private final ProgramClassConflictResolver resolver;
Builder(ProgramClassConflictResolver resolver, DexItemFactory dexItemFactory, Timing timing) {
super(dexItemFactory, timing);
this.resolver = resolver;
this.classpathClasses = null;
this.libraryClasses = null;
}
private Builder(LazyLoadedDexApplication application) {
super(application);
this.resolver = ProgramClassCollection::resolveClassConflictImpl;
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(programClasses, resolver),
ImmutableList.copyOf(programResourceProviders),
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();
}
@Override
public String toString() {
return "Application (" + programClasses + "; " + classpathClasses + "; " + libraryClasses
+ ")";
}
}