blob: 7d85b8df845ce8d2f572fcd9ba5e7f83c44ab960 [file] [log] [blame]
// Copyright (c) 2020, 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.ir.optimize.enums;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.utils.collections.ProgramMethodSet;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
public class EnumUnboxingCandidateInfoCollection {
private final Map<DexType, EnumUnboxingCandidateInfo> enumTypeToInfo = new ConcurrentHashMap<>();
public void addCandidate(DexProgramClass enumClass) {
assert !enumTypeToInfo.containsKey(enumClass.type);
enumTypeToInfo.put(enumClass.type, new EnumUnboxingCandidateInfo(enumClass));
}
public void removeCandidate(DexProgramClass enumClass) {
removeCandidate(enumClass.getType());
}
public void removeCandidate(DexType enumType) {
enumTypeToInfo.remove(enumType);
}
public boolean isCandidate(DexType enumType) {
return enumTypeToInfo.containsKey(enumType);
}
public boolean isEmpty() {
return enumTypeToInfo.isEmpty();
}
public ImmutableSet<DexType> candidates() {
return ImmutableSet.copyOf(enumTypeToInfo.keySet());
}
public ImmutableSet<DexProgramClass> candidateClasses() {
ImmutableSet.Builder<DexProgramClass> builder = ImmutableSet.builder();
for (EnumUnboxingCandidateInfo info : enumTypeToInfo.values()) {
builder.add(info.getEnumClass());
}
return builder.build();
}
public DexProgramClass getCandidateClassOrNull(DexType enumType) {
EnumUnboxingCandidateInfo info = enumTypeToInfo.get(enumType);
if (info == null) {
return null;
}
return info.enumClass;
}
public ProgramMethodSet allMethodDependencies() {
ProgramMethodSet allMethodDependencies = ProgramMethodSet.create();
for (EnumUnboxingCandidateInfo info : enumTypeToInfo.values()) {
allMethodDependencies.addAll(info.methodDependencies);
}
return allMethodDependencies;
}
public void addMethodDependency(DexType enumType, ProgramMethod programMethod) {
// The enumType may be removed concurrently map from enumTypeToInfo. It means in that
// case the enum is no longer a candidate, and dependencies don't need to be recorded
// anymore.
EnumUnboxingCandidateInfo info = enumTypeToInfo.get(enumType);
if (info == null) {
return;
}
info.addMethodDependency(programMethod);
}
public void addRequiredEnumInstanceFieldData(DexProgramClass enumClass, DexField field) {
// The enumType may be removed concurrently map from enumTypeToInfo. It means in that
// case the enum is no longer a candidate, and dependencies don't need to be recorded
// anymore.
EnumUnboxingCandidateInfo info = enumTypeToInfo.get(enumClass.getType());
if (info == null) {
return;
}
info.addRequiredInstanceFieldData(field);
}
public void forEachCandidate(Consumer<DexProgramClass> enumClassConsumer) {
enumTypeToInfo.values().forEach(info -> enumClassConsumer.accept(info.enumClass));
}
public void forEachCandidateAndRequiredInstanceFieldData(
BiConsumer<DexProgramClass, Set<DexField>> biConsumer) {
enumTypeToInfo
.values()
.forEach(
info -> biConsumer.accept(info.getEnumClass(), info.getRequiredInstanceFieldData()));
}
public void clear() {
enumTypeToInfo.clear();
}
private static class EnumUnboxingCandidateInfo {
private final DexProgramClass enumClass;
private final ProgramMethodSet methodDependencies = ProgramMethodSet.createConcurrent();
private final Set<DexField> requiredInstanceFieldData = Sets.newConcurrentHashSet();
public EnumUnboxingCandidateInfo(DexProgramClass enumClass) {
assert enumClass != null;
this.enumClass = enumClass;
}
public DexProgramClass getEnumClass() {
return enumClass;
}
public void addMethodDependency(ProgramMethod programMethod) {
methodDependencies.add(programMethod);
}
public void addRequiredInstanceFieldData(DexField field) {
requiredInstanceFieldData.add(field);
}
public Set<DexField> getRequiredInstanceFieldData() {
return requiredInstanceFieldData;
}
}
}