| // 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) { |
| 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; |
| } |
| |
| 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 |
| + ")"; |
| } |
| } |