| // 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.graph; |
| |
| import com.android.tools.r8.utils.ObjectUtils; |
| import com.android.tools.r8.utils.SetUtils; |
| import java.util.IdentityHashMap; |
| import java.util.Map; |
| import java.util.function.BiPredicate; |
| import java.util.function.Consumer; |
| import java.util.function.Function; |
| |
| public class FieldAccessInfoCollectionImpl |
| implements FieldAccessInfoCollection<FieldAccessInfoImpl> { |
| |
| private final Map<DexField, FieldAccessInfoImpl> infos; |
| |
| public FieldAccessInfoCollectionImpl() { |
| this(new IdentityHashMap<>()); |
| } |
| |
| public FieldAccessInfoCollectionImpl(Map<DexField, FieldAccessInfoImpl> infos) { |
| this.infos = infos; |
| } |
| |
| @Override |
| public void destroyAccessContexts() { |
| infos.values().forEach(FieldAccessInfoImpl::destroyAccessContexts); |
| } |
| |
| @Override |
| public void flattenAccessContexts() { |
| infos.values().forEach(FieldAccessInfoImpl::flattenAccessContexts); |
| } |
| |
| public FieldAccessInfoImpl computeIfAbsent( |
| DexField field, Function<DexField, FieldAccessInfoImpl> fn) { |
| return infos.computeIfAbsent(field, fn); |
| } |
| |
| @Override |
| public boolean contains(DexField field) { |
| return infos.containsKey(field); |
| } |
| |
| @Override |
| public FieldAccessInfoImpl get(DexField field) { |
| return infos.get(field); |
| } |
| |
| public FieldAccessInfoImpl extend(DexField field, FieldAccessInfoImpl info) { |
| assert !infos.containsKey(field); |
| infos.put(field, info); |
| return info; |
| } |
| |
| @Override |
| public void forEach(Consumer<FieldAccessInfoImpl> consumer) { |
| // Verify that the mapping os one-to-one, otherwise the caller could receive duplicates. |
| assert verifyMappingIsOneToOne(); |
| infos.values().forEach(consumer); |
| } |
| |
| public void remove(DexField field) { |
| infos.remove(field); |
| } |
| |
| @Override |
| public void removeIf(BiPredicate<DexField, FieldAccessInfoImpl> predicate) { |
| infos.entrySet().removeIf(entry -> predicate.test(entry.getKey(), entry.getValue())); |
| } |
| |
| @Override |
| public void restrictToProgram(DexDefinitionSupplier definitions) { |
| removeIf((field, info) -> !definitions.definitionForHolder(field).isProgramClass()); |
| } |
| |
| public FieldAccessInfoCollectionImpl rewrittenWithLens( |
| DexDefinitionSupplier definitions, GraphLens lens) { |
| FieldAccessInfoCollectionImpl collection = new FieldAccessInfoCollectionImpl(); |
| Consumer<FieldAccessInfoImpl> rewriteAndMergeFieldInfo = |
| info -> { |
| FieldAccessInfoImpl rewrittenInfo = info.rewrittenWithLens(definitions, lens); |
| DexField newField = rewrittenInfo.getField(); |
| collection.infos.compute( |
| newField, |
| (ignore, oldInfo) -> |
| ObjectUtils.mapNotNullOrDefault(oldInfo, rewrittenInfo, rewrittenInfo::join)); |
| }; |
| infos.values().forEach(rewriteAndMergeFieldInfo); |
| return collection; |
| } |
| |
| // This is used to verify that the temporary mappings inserted into `infos` by the Enqueuer are |
| // removed. |
| public boolean verifyMappingIsOneToOne() { |
| assert infos.values().size() == SetUtils.newIdentityHashSet(infos.values()).size(); |
| return true; |
| } |
| } |