|  | // 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); | 
|  | } | 
|  |  | 
|  | @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; | 
|  | } | 
|  | } |