blob: 8e57e8770c8d3f86557315219b30646680c2b97e [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.horizontalclassmerging.policies;
import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexEncodedField;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.FieldAccessFlags;
import com.android.tools.r8.horizontalclassmerging.HorizontalClassMerger.Mode;
import com.android.tools.r8.horizontalclassmerging.MultiClassSameReferencePolicy;
import com.android.tools.r8.horizontalclassmerging.policies.SameInstanceFields.InstanceFieldInfo;
import com.google.common.collect.HashMultiset;
import com.google.common.collect.Multiset;
import java.util.Objects;
public class SameInstanceFields extends MultiClassSameReferencePolicy<Multiset<InstanceFieldInfo>> {
private final DexItemFactory dexItemFactory;
private final Mode mode;
public SameInstanceFields(AppView<? extends AppInfoWithClassHierarchy> appView, Mode mode) {
this.dexItemFactory = appView.dexItemFactory();
this.mode = mode;
}
@Override
public Multiset<InstanceFieldInfo> getMergeKey(DexProgramClass clazz) {
Multiset<InstanceFieldInfo> fields = HashMultiset.create();
for (DexEncodedField field : clazz.instanceFields()) {
// We do not allow merging fields with different types in the final round of horizontal class
// merging, since that requires inserting check-cast instructions at reads.
InstanceFieldInfo instanceFieldInfo =
mode.isInitial()
? InstanceFieldInfo.createRelaxed(field, dexItemFactory)
: InstanceFieldInfo.createExact(field);
fields.add(instanceFieldInfo);
}
return fields;
}
@Override
public String getName() {
return "SameInstanceFields";
}
public static class InstanceFieldInfo {
private final FieldAccessFlags accessFlags;
private final DexType type;
private InstanceFieldInfo(FieldAccessFlags accessFlags, DexType type) {
this.accessFlags =
FieldAccessFlags.fromSharedAccessFlags(accessFlags.materialize())
.unsetFinal()
.unsetSynthetic();
this.type = type;
}
public static InstanceFieldInfo createExact(DexEncodedField field) {
return new InstanceFieldInfo(field.getAccessFlags(), field.getType());
}
public static InstanceFieldInfo createRelaxed(
DexEncodedField field, DexItemFactory dexItemFactory) {
return new InstanceFieldInfo(
field.getAccessFlags(),
field.getType().isReferenceType() ? dexItemFactory.objectType : field.getType());
}
public FieldAccessFlags getAccessFlags() {
return accessFlags;
}
public InstanceFieldInfo toInfoWithRelaxedType(DexItemFactory dexItemFactory) {
return new InstanceFieldInfo(
accessFlags, type.isReferenceType() ? dexItemFactory.objectType : type);
}
@Override
public boolean equals(Object obj) {
if (obj == null || getClass() != obj.getClass()) {
return false;
}
InstanceFieldInfo info = (InstanceFieldInfo) obj;
return accessFlags.materialize() == info.accessFlags.materialize() && type == info.type;
}
@Override
public int hashCode() {
return Objects.hash(accessFlags, type);
}
}
}