blob: 8e5e7a30d6c5f7ffaf9b97c4516a16fd64dce05b [file] [log] [blame]
// Copyright (c) 2019, 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.shaking;
import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.ir.desugar.PrefixRewritingMapper;
import com.android.tools.r8.utils.InternalOptions;
import com.google.common.collect.Sets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.IdentityHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
// In L8, all classes not rewritten or emulated interfaces are pruned away.
// This avoids having non rewritten classes in the output when compiled with D8.
// This also avoids having non rewritten classes in the output.
public class L8TreePruner {
private final InternalOptions options;
private final Set<DexType> emulatedInterfaces = Sets.newIdentityHashSet();
private final Set<DexType> backports = Sets.newIdentityHashSet();
private final List<DexType> pruned = new ArrayList<>();
public L8TreePruner(InternalOptions options) {
this.options = options;
backports.addAll(options.desugaredLibraryConfiguration.getBackportCoreLibraryMember().keySet());
emulatedInterfaces.addAll(
options.desugaredLibraryConfiguration.getEmulateLibraryInterface().keySet());
}
public DexApplication prune(DexApplication app, PrefixRewritingMapper rewritePrefix) {
Map<DexType, DexProgramClass> typeMap = new IdentityHashMap<>();
for (DexProgramClass aClass : app.classes()) {
typeMap.put(aClass.type, aClass);
}
List<DexProgramClass> toKeep = new ArrayList<>();
for (DexProgramClass aClass : app.classes()) {
if (rewritePrefix.hasRewrittenType(aClass.type, null)
|| emulatedInterfaces.contains(aClass.type)
|| interfaceImplementsEmulatedInterface(aClass, typeMap)) {
toKeep.add(aClass);
} else {
pruned.add(aClass.type);
}
}
typeMap.clear();
// TODO(b/134732760): Would be nice to add pruned type to the appView removedClasses instead
// of just doing nothing with it.
return app.builder().replaceProgramClasses(toKeep).build();
}
private boolean interfaceImplementsEmulatedInterface(
DexClass itf, Map<DexType, DexProgramClass> typeMap) {
if (!itf.isInterface()) {
return false;
}
LinkedList<DexType> workList = new LinkedList<>();
Collections.addAll(workList, itf.interfaces.values);
while (!workList.isEmpty()) {
DexType dexType = workList.removeFirst();
if (emulatedInterfaces.contains(dexType)) {
return true;
}
if (typeMap.containsKey(dexType)) {
DexProgramClass dexProgramClass = typeMap.get(dexType);
Collections.addAll(workList, dexProgramClass.interfaces.values);
}
}
return false;
}
}