blob: 770b59ce0fddfc1e6b2f536a29f6a337556eade2 [file] [log] [blame]
// 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.ir.optimize.info.initializer;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexEncodedField;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.GraphLense;
import com.android.tools.r8.ir.analysis.fieldvalueanalysis.AbstractFieldSet;
import com.android.tools.r8.ir.analysis.fieldvalueanalysis.ConcreteMutableFieldSet;
import com.android.tools.r8.ir.analysis.fieldvalueanalysis.EmptyFieldSet;
import com.android.tools.r8.ir.analysis.fieldvalueanalysis.UnknownFieldSet;
import com.android.tools.r8.ir.optimize.info.field.InstanceFieldInitializationInfoCollection;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
public final class NonTrivialInstanceInitializerInfo extends InstanceInitializerInfo {
private static final int INSTANCE_FIELD_INITIALIZATION_INDEPENDENT_OF_ENVIRONMENT = 1 << 0;
private static final int NO_OTHER_SIDE_EFFECTS_THAN_INSTANCE_FIELD_ASSIGNMENTS = 1 << 1;
private static final int RECEIVER_NEVER_ESCAPE_OUTSIDE_CONSTRUCTOR_CHAIN = 1 << 2;
private final int data;
private final InstanceFieldInitializationInfoCollection fieldInitializationInfos;
private final AbstractFieldSet readSet;
private final DexMethod parent;
private NonTrivialInstanceInitializerInfo(
int data,
InstanceFieldInitializationInfoCollection fieldInitializationInfos,
AbstractFieldSet readSet,
DexMethod parent) {
assert verifyNoUnknownBits(data);
this.data = data;
this.fieldInitializationInfos = fieldInitializationInfos;
this.readSet = readSet;
this.parent = parent;
}
private static boolean verifyNoUnknownBits(int data) {
int knownBits =
INSTANCE_FIELD_INITIALIZATION_INDEPENDENT_OF_ENVIRONMENT
| NO_OTHER_SIDE_EFFECTS_THAN_INSTANCE_FIELD_ASSIGNMENTS
| RECEIVER_NEVER_ESCAPE_OUTSIDE_CONSTRUCTOR_CHAIN;
assert (data & ~knownBits) == 0;
return true;
}
public static Builder builder(
InstanceFieldInitializationInfoCollection instanceFieldInitializationInfos) {
return new Builder(instanceFieldInitializationInfos);
}
@Override
public DexMethod getParent() {
return parent;
}
@Override
public InstanceFieldInitializationInfoCollection fieldInitializationInfos() {
return fieldInitializationInfos;
}
@Override
public AbstractFieldSet readSet() {
return readSet;
}
@Override
public boolean instanceFieldInitializationMayDependOnEnvironment() {
return (data & INSTANCE_FIELD_INITIALIZATION_INDEPENDENT_OF_ENVIRONMENT) == 0;
}
@Override
public boolean mayHaveOtherSideEffectsThanInstanceFieldAssignments() {
return (data & NO_OTHER_SIDE_EFFECTS_THAN_INSTANCE_FIELD_ASSIGNMENTS) == 0;
}
@Override
public boolean receiverNeverEscapesOutsideConstructorChain() {
return (data & RECEIVER_NEVER_ESCAPE_OUTSIDE_CONSTRUCTOR_CHAIN) != 0;
}
@Override
public NonTrivialInstanceInitializerInfo rewrittenWithLens(
AppView<AppInfoWithLiveness> appView, GraphLense lens) {
return new NonTrivialInstanceInitializerInfo(
data,
fieldInitializationInfos.rewrittenWithLens(appView, lens),
readSet.rewrittenWithLens(appView, lens),
lens.getRenamedMethodSignature(parent));
}
@Override
public String toString() {
return "NonTrivialInstanceInitializerInfo(" + fieldInitializationInfos + ")";
}
public static class Builder {
private final InstanceFieldInitializationInfoCollection instanceFieldInitializationInfos;
private int data =
INSTANCE_FIELD_INITIALIZATION_INDEPENDENT_OF_ENVIRONMENT
| NO_OTHER_SIDE_EFFECTS_THAN_INSTANCE_FIELD_ASSIGNMENTS
| RECEIVER_NEVER_ESCAPE_OUTSIDE_CONSTRUCTOR_CHAIN;
private AbstractFieldSet readSet = EmptyFieldSet.getInstance();
private DexMethod parent;
public Builder(InstanceFieldInitializationInfoCollection instanceFieldInitializationInfos) {
this.instanceFieldInitializationInfos = instanceFieldInitializationInfos;
}
private boolean isTrivial() {
return instanceFieldInitializationInfos.isEmpty()
&& data == 0
&& readSet.isTop()
&& parent == null;
}
public Builder markFieldAsRead(DexEncodedField field) {
if (readSet.isKnownFieldSet()) {
if (readSet.isBottom()) {
readSet = new ConcreteMutableFieldSet(field);
} else {
readSet.asConcreteFieldSet().add(field);
}
}
assert readSet.contains(field);
return this;
}
public Builder markFieldsAsRead(AbstractFieldSet otherReadSet) {
if (readSet.isTop() || otherReadSet.isBottom()) {
return this;
}
if (otherReadSet.isTop()) {
return markAllFieldsAsRead();
}
ConcreteMutableFieldSet otherConcreteReadSet = otherReadSet.asConcreteFieldSet();
if (readSet.isBottom()) {
readSet = new ConcreteMutableFieldSet().addAll(otherConcreteReadSet);
} else {
readSet.asConcreteFieldSet().addAll(otherConcreteReadSet);
}
return this;
}
public Builder markAllFieldsAsRead() {
readSet = UnknownFieldSet.getInstance();
return this;
}
public Builder merge(InstanceInitializerInfo instanceInitializerInfo) {
markFieldsAsRead(instanceInitializerInfo.readSet());
if (instanceInitializerInfo.instanceFieldInitializationMayDependOnEnvironment()) {
setInstanceFieldInitializationMayDependOnEnvironment();
}
if (instanceInitializerInfo.mayHaveOtherSideEffectsThanInstanceFieldAssignments()) {
setMayHaveOtherSideEffectsThanInstanceFieldAssignments();
}
if (instanceInitializerInfo.receiverMayEscapeOutsideConstructorChain()) {
setReceiverMayEscapeOutsideConstructorChain();
}
return this;
}
public Builder setInstanceFieldInitializationMayDependOnEnvironment() {
data &= ~INSTANCE_FIELD_INITIALIZATION_INDEPENDENT_OF_ENVIRONMENT;
return this;
}
public boolean mayHaveOtherSideEffectsThanInstanceFieldAssignments() {
return (data & ~NO_OTHER_SIDE_EFFECTS_THAN_INSTANCE_FIELD_ASSIGNMENTS) == 0;
}
public Builder setMayHaveOtherSideEffectsThanInstanceFieldAssignments() {
data &= ~NO_OTHER_SIDE_EFFECTS_THAN_INSTANCE_FIELD_ASSIGNMENTS;
return this;
}
public Builder setReceiverMayEscapeOutsideConstructorChain() {
data &= ~RECEIVER_NEVER_ESCAPE_OUTSIDE_CONSTRUCTOR_CHAIN;
return this;
}
public boolean hasParent() {
return parent != null;
}
public Builder setParent(DexMethod parent) {
assert !hasParent();
this.parent = parent;
return this;
}
public InstanceInitializerInfo build() {
return isTrivial()
? DefaultInstanceInitializerInfo.getInstance()
: new NonTrivialInstanceInitializerInfo(
data, instanceFieldInitializationInfos, readSet, parent);
}
}
}