blob: a05a33b6d559018086a65c852ff529dc096cfe8d [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.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);
}
}
}