blob: 6bb13a74ef7bba457a151a79bbdbed0e2d863953 [file] [log] [blame]
// Copyright (c) 2017, 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.analysis.type;
import com.android.tools.r8.graph.AppInfo;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexType;
public class ArrayTypeLatticeElement extends ReferenceTypeLatticeElement {
private final TypeLatticeElement memberTypeLattice;
public ArrayTypeLatticeElement(TypeLatticeElement memberTypeLattice, boolean isNullable) {
super(isNullable, null);
this.memberTypeLattice = memberTypeLattice;
}
public DexType getArrayType(DexItemFactory factory) {
TypeLatticeElement baseTypeLattice = getArrayBaseTypeLattice();
DexType baseType;
if (baseTypeLattice.isPrimitive()) {
baseType = baseTypeLattice.asPrimitiveTypeLatticeElement().toDexType(factory);
} else {
assert baseTypeLattice.isClassType();
baseType = baseTypeLattice.asClassTypeLatticeElement().getClassType();
}
return factory.createArrayType(getNesting(), baseType);
}
int getNesting() {
int nesting = 1;
TypeLatticeElement member = getArrayMemberTypeAsMemberType();
while (member.isArrayType()) {
++nesting;
member = member.asArrayTypeLatticeElement().getArrayMemberTypeAsMemberType();
}
return nesting;
}
TypeLatticeElement getArrayMemberTypeAsMemberType() {
return memberTypeLattice;
}
public TypeLatticeElement getArrayMemberTypeAsValueType() {
return memberTypeLattice.isFineGrainedType() ? INT : memberTypeLattice;
}
private TypeLatticeElement getArrayBaseTypeLattice() {
TypeLatticeElement base = getArrayMemberTypeAsMemberType();
while (base.isArrayType()) {
base = base.asArrayTypeLatticeElement().getArrayMemberTypeAsMemberType();
}
return base;
}
@Override
public ReferenceTypeLatticeElement getOrCreateDualLattice() {
if (dual != null) {
return dual;
}
synchronized (this) {
if (dual == null) {
ArrayTypeLatticeElement dual =
new ArrayTypeLatticeElement(memberTypeLattice, !isNullable());
linkDualLattice(this, dual);
}
}
return this.dual;
}
@Override
public TypeLatticeElement asNullable() {
return isNullable() ? this : getOrCreateDualLattice();
}
@Override
public TypeLatticeElement asNonNullable() {
return !isNullable() ? this : getOrCreateDualLattice();
}
@Override
public boolean isBasedOnMissingClass(AppInfo appInfo) {
return memberTypeLattice.isBasedOnMissingClass(appInfo);
}
@Override
public boolean isArrayType() {
return true;
}
@Override
public ArrayTypeLatticeElement asArrayTypeLatticeElement() {
return this;
}
@Override
public String toString() {
return memberTypeLattice.toString() + "[]";
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof ArrayTypeLatticeElement)) {
return false;
}
ArrayTypeLatticeElement other = (ArrayTypeLatticeElement) o;
if (isNullable() != other.isNullable()) {
return false;
}
if (type != null && other.type != null && !type.equals(other.type)) {
return false;
}
return memberTypeLattice.equals(other.memberTypeLattice);
}
@Override
public int hashCode() {
return (isNullable() ? 1 : -1) * memberTypeLattice.hashCode();
}
ReferenceTypeLatticeElement join(ArrayTypeLatticeElement other, AppInfo appInfo) {
TypeLatticeElement aMember = getArrayMemberTypeAsMemberType();
TypeLatticeElement bMember = other.getArrayMemberTypeAsMemberType();
if (aMember.equals(bMember)) {
// Return null indicating the join is the same as the member to avoid object allocation.
return null;
}
boolean isNullable = isNullable() || other.isNullable();
if (aMember.isArrayType() && bMember.isArrayType()) {
ReferenceTypeLatticeElement join =
aMember.asArrayTypeLatticeElement().join(bMember.asArrayTypeLatticeElement(), appInfo);
return join == null ? null : new ArrayTypeLatticeElement(join, isNullable);
}
if (aMember.isClassType() && bMember.isClassType()) {
ClassTypeLatticeElement join =
aMember.asClassTypeLatticeElement().join(bMember.asClassTypeLatticeElement(), appInfo);
return join == null ? null : new ArrayTypeLatticeElement(join, isNullable);
}
if (aMember.isPrimitive() || bMember.isPrimitive()) {
return objectClassType(appInfo, isNullable);
}
return objectArrayType(appInfo, isNullable);
}
}