| // 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.shaking; |
| |
| import com.android.tools.r8.graph.AbstractAccessContexts; |
| import com.android.tools.r8.graph.AbstractAccessContexts.ConcreteAccessContexts; |
| import com.android.tools.r8.graph.AppView; |
| import com.android.tools.r8.graph.DexField; |
| import com.android.tools.r8.graph.FieldAccessInfoCollectionImpl; |
| import com.android.tools.r8.graph.FieldAccessInfoImpl; |
| import com.android.tools.r8.graph.ProgramMethod; |
| import java.util.IdentityHashMap; |
| import java.util.Map; |
| |
| public class FieldAccessInfoCollectionModifier { |
| |
| private static class FieldAccessContexts { |
| |
| private AbstractAccessContexts readsWithContexts = AbstractAccessContexts.empty(); |
| private AbstractAccessContexts writesWithContexts = AbstractAccessContexts.empty(); |
| |
| void addReadContext(DexField field, ProgramMethod context) { |
| if (readsWithContexts.isBottom()) { |
| ConcreteAccessContexts concreteReadContexts = new ConcreteAccessContexts(); |
| concreteReadContexts.recordAccess(field, context); |
| readsWithContexts = concreteReadContexts; |
| } else if (readsWithContexts.isConcrete()) { |
| readsWithContexts.asConcrete().recordAccess(field, context); |
| } else { |
| assert readsWithContexts.isTop(); |
| } |
| } |
| |
| void recordReadInUnknownContext() { |
| readsWithContexts = AbstractAccessContexts.unknown(); |
| } |
| |
| void addWriteContext(DexField field, ProgramMethod context) { |
| if (writesWithContexts.isBottom()) { |
| ConcreteAccessContexts concreteWriteContexts = new ConcreteAccessContexts(); |
| concreteWriteContexts.recordAccess(field, context); |
| writesWithContexts = concreteWriteContexts; |
| } else if (writesWithContexts.isConcrete()) { |
| writesWithContexts.asConcrete().recordAccess(field, context); |
| } else { |
| assert writesWithContexts.isTop(); |
| } |
| } |
| |
| void recordWriteInUnknownContext() { |
| writesWithContexts = AbstractAccessContexts.unknown(); |
| } |
| } |
| |
| private final Map<DexField, FieldAccessContexts> newFieldAccessContexts; |
| |
| private FieldAccessInfoCollectionModifier( |
| Map<DexField, FieldAccessContexts> newFieldAccessContexts) { |
| this.newFieldAccessContexts = newFieldAccessContexts; |
| } |
| |
| public static Builder builder() { |
| return new Builder(); |
| } |
| |
| public void modify(AppView<AppInfoWithLiveness> appView) { |
| FieldAccessInfoCollectionImpl impl = appView.appInfo().getMutableFieldAccessInfoCollection(); |
| newFieldAccessContexts.forEach( |
| (field, accessContexts) -> { |
| FieldAccessInfoImpl fieldAccessInfo = new FieldAccessInfoImpl(field); |
| fieldAccessInfo.setReadsWithContexts(accessContexts.readsWithContexts); |
| fieldAccessInfo.setWritesWithContexts(accessContexts.writesWithContexts); |
| impl.extend(field, fieldAccessInfo); |
| }); |
| } |
| |
| public static class Builder { |
| |
| private final Map<DexField, FieldAccessContexts> newFieldAccessContexts = |
| new IdentityHashMap<>(); |
| |
| public Builder() {} |
| |
| private FieldAccessContexts getFieldAccessContexts(DexField field) { |
| return newFieldAccessContexts.computeIfAbsent(field, ignore -> new FieldAccessContexts()); |
| } |
| |
| public void recordFieldReadInContext(DexField field, ProgramMethod context) { |
| getFieldAccessContexts(field).addReadContext(field, context); |
| } |
| |
| public Builder recordFieldReadInUnknownContext(DexField field) { |
| getFieldAccessContexts(field).recordReadInUnknownContext(); |
| return this; |
| } |
| |
| public void recordFieldWrittenInContext(DexField field, ProgramMethod context) { |
| getFieldAccessContexts(field).addWriteContext(field, context); |
| } |
| |
| public void recordFieldWriteInUnknownContext(DexField field) { |
| getFieldAccessContexts(field).recordWriteInUnknownContext(); |
| } |
| |
| public FieldAccessInfoCollectionModifier build() { |
| return new FieldAccessInfoCollectionModifier(newFieldAccessContexts); |
| } |
| } |
| } |