| // 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.graph.LazyLoadedDexApplication.AllClasses; |
| import com.android.tools.r8.naming.ClassNameMapper; |
| 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.ImmutableMap; |
| import com.google.common.collect.ImmutableSet; |
| import com.google.common.collect.Iterables; |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.List; |
| import java.util.Map; |
| |
| public class DirectMappedDexApplication extends DexApplication { |
| |
| private final AllClasses allClasses; |
| private final ImmutableMap<DexType, DexLibraryClass> libraryClasses; |
| |
| private DirectMappedDexApplication(ClassNameMapper proguardMap, |
| AllClasses allClasses, |
| ProgramClassCollection programClasses, |
| ImmutableList<ProgramResourceProvider> programResourceProviders, |
| ImmutableMap<DexType, DexLibraryClass> libraryClasses, |
| ImmutableSet<DexType> mainDexList, String deadCode, |
| DexItemFactory dexItemFactory, DexString highestSortingString, |
| Timing timing) { |
| super(proguardMap, programClasses, programResourceProviders, mainDexList, deadCode, |
| dexItemFactory, highestSortingString, timing); |
| this.allClasses = allClasses; |
| this.libraryClasses = libraryClasses; |
| } |
| |
| public Collection<DexLibraryClass> libraryClasses() { |
| return libraryClasses.values(); |
| } |
| |
| @Override |
| public DexClass definitionFor(DexType type) { |
| assert type.isClassType() : "Cannot lookup definition for type: " + 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; |
| } |
| |
| @Override |
| public String toString() { |
| return "DexApplication (direct)"; |
| } |
| |
| public DirectMappedDexApplication rewrittenWithLense(GraphLense graphLense) { |
| // As a side effect, this will rebuild the program classes and library classes maps. |
| DirectMappedDexApplication rewrittenApplication = this.builder().build().asDirect(); |
| assert rewrittenApplication.mappingIsValid(graphLense, programClasses.getAllTypes()); |
| assert rewrittenApplication.mappingIsValid(graphLense, libraryClasses.keySet()); |
| return rewrittenApplication; |
| } |
| |
| private boolean mappingIsValid(GraphLense graphLense, Iterable<DexType> types) { |
| // The lens might either map to a different type that is already present in the application |
| // (e.g. relinking a type) or it might encode a type that was renamed, in which case the |
| // original type will point to a definition that was renamed. |
| for (DexType type : types) { |
| DexType renamed = graphLense.lookupType(type); |
| if (renamed != type) { |
| if (definitionFor(type) == null && definitionFor(renamed) != null) { |
| continue; |
| } |
| assert definitionFor(type).type == renamed || definitionFor(renamed) != null; |
| } |
| } |
| return true; |
| } |
| |
| public static class Builder extends DexApplication.Builder<Builder> { |
| |
| private final AllClasses allClasses; |
| private final List<DexLibraryClass> libraryClasses = new ArrayList<>(); |
| |
| Builder(LazyLoadedDexApplication application) { |
| super(application); |
| // As a side-effect, this will force-load all classes. |
| this.allClasses = application.loadAllClasses(); |
| Map<DexType, DexClass> allClasses = this.allClasses.getClasses(); |
| // TODO(120884788): This filter will only add library classes which are not program classes. |
| Iterables.filter(allClasses.values(), DexLibraryClass.class).forEach(libraryClasses::add); |
| } |
| |
| private Builder(DirectMappedDexApplication application) { |
| super(application); |
| this.allClasses = application.allClasses; |
| this.libraryClasses.addAll(application.libraryClasses.values()); |
| } |
| |
| @Override |
| Builder self() { |
| return this; |
| } |
| |
| @Override |
| public DexApplication build() { |
| // Rebuild the map. This will fail if keys are not unique. |
| return new DirectMappedDexApplication( |
| proguardMap, |
| allClasses, |
| ProgramClassCollection.create( |
| programClasses, ProgramClassCollection::resolveClassConflictImpl), |
| ImmutableList.copyOf(programResourceProviders), |
| libraryClasses.stream().collect(ImmutableMap.toImmutableMap(c -> c.type, c -> c)), |
| ImmutableSet.copyOf(mainDexList), |
| deadCode, |
| dexItemFactory, |
| highestSortingString, |
| timing); |
| } |
| } |
| } |