package org.jf.dexlib2.analysis;
import org.jf.util.ExceptionWithContext;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.IOException;
import java.io.Writer;
public class RegisterType {
public final byte category;
@Nullable public final TypeProto type;
private RegisterType(byte category, @Nullable TypeProto type) {
assert ((category == REFERENCE || category == UNINIT_REF || category == UNINIT_THIS) && type != null) ||
((category != REFERENCE && category != UNINIT_REF && category != UNINIT_THIS) && type == null);
this.category = category;
this.type = type;
}
@Override
public String toString() {
return "(" + CATEGORY_NAMES[category] + (type==null?"":("," + type)) + ")";
}
public void writeTo(Writer writer) throws IOException {
writer.write('(');
writer.write(CATEGORY_NAMES[category]);
if (type != null) {
writer.write(',');
writer.write(type.getType());
}
writer.write(')');
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
RegisterType that = (RegisterType) o;
if (category != that.category) {
return false;
}
if (category == UNINIT_REF || category == UNINIT_THIS) {
return false;
}
return (type != null ? type.equals(that.type) : that.type == null);
}
@Override
public int hashCode() {
int result = category;
result = 31 * result + (type != null ? type.hashCode() : 0);
return result;
}
public static final byte UNKNOWN = 0;
public static final byte UNINIT = 1;
public static final byte NULL = 2;
public static final byte ONE = 3;
public static final byte BOOLEAN = 4;
public static final byte BYTE = 5;
public static final byte POS_BYTE = 6;
public static final byte SHORT = 7;
public static final byte POS_SHORT = 8;
public static final byte CHAR = 9;
public static final byte INTEGER = 10;
public static final byte FLOAT = 11;
public static final byte LONG_LO = 12;
public static final byte LONG_HI = 13;
public static final byte DOUBLE_LO = 14;
public static final byte DOUBLE_HI = 15;
public static final byte UNINIT_REF = 16;
public static final byte UNINIT_THIS = 17;
public static final byte REFERENCE = 18;
public static final byte CONFLICTED = 19;
public static final String[] CATEGORY_NAMES = new String[] {
"Unknown",
"Uninit",
"Null",
"One",
"Boolean",
"Byte",
"PosByte",
"Short",
"PosShort",
"Char",
"Integer",
"Float",
"LongLo",
"LongHi",
"DoubleLo",
"DoubleHi",
"UninitRef",
"UninitThis",
"Reference",
"Conflicted"
};
protected static byte[][] mergeTable =
{
{UNKNOWN, UNINIT, NULL, ONE, BOOLEAN, BYTE, POS_BYTE, SHORT, POS_SHORT, CHAR, INTEGER, FLOAT, LONG_LO, LONG_HI, DOUBLE_LO, DOUBLE_HI, UNINIT_REF, UNINIT_THIS,REFERENCE, CONFLICTED},
{UNINIT, UNINIT, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED},
{NULL, CONFLICTED, NULL, BOOLEAN, BOOLEAN, BYTE, POS_BYTE, SHORT, POS_SHORT, CHAR, INTEGER, FLOAT, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, REFERENCE, CONFLICTED},
{ONE, CONFLICTED, BOOLEAN, ONE, BOOLEAN, BYTE, POS_BYTE, SHORT, POS_SHORT, CHAR, INTEGER, FLOAT, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED},
{BOOLEAN, CONFLICTED, BOOLEAN, BOOLEAN, BOOLEAN, BYTE, POS_BYTE, SHORT, POS_SHORT, CHAR, INTEGER, FLOAT, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED},
{BYTE, CONFLICTED, BYTE, BYTE, BYTE, BYTE, BYTE, SHORT, SHORT, INTEGER, INTEGER, FLOAT, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED},
{POS_BYTE, CONFLICTED, POS_BYTE, POS_BYTE, POS_BYTE, BYTE, POS_BYTE, SHORT, POS_SHORT, CHAR, INTEGER, FLOAT, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED},
{SHORT, CONFLICTED, SHORT, SHORT, SHORT, SHORT, SHORT, SHORT, SHORT, INTEGER, INTEGER, FLOAT, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED},
{POS_SHORT, CONFLICTED, POS_SHORT, POS_SHORT, POS_SHORT, SHORT, POS_SHORT, SHORT, POS_SHORT, CHAR, INTEGER, FLOAT, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED},
{CHAR, CONFLICTED, CHAR, CHAR, CHAR, INTEGER, CHAR, INTEGER, CHAR, CHAR, INTEGER, FLOAT, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED},
{INTEGER, CONFLICTED, INTEGER, INTEGER, INTEGER, INTEGER, INTEGER, INTEGER, INTEGER, INTEGER, INTEGER, INTEGER, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED},
{FLOAT, CONFLICTED, FLOAT, FLOAT, FLOAT, FLOAT, FLOAT, FLOAT, FLOAT, FLOAT, INTEGER, FLOAT, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED},
{LONG_LO, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, LONG_LO, CONFLICTED, LONG_LO, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED},
{LONG_HI, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, LONG_HI, CONFLICTED, LONG_HI, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED},
{DOUBLE_LO, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, LONG_LO, CONFLICTED, DOUBLE_LO, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED},
{DOUBLE_HI, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, LONG_HI, CONFLICTED, DOUBLE_HI, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED},
{UNINIT_REF, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED},
{UNINIT_THIS, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, UNINIT_THIS,CONFLICTED, CONFLICTED},
{REFERENCE, CONFLICTED, REFERENCE, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, REFERENCE, CONFLICTED},
{CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED, CONFLICTED}
};
public static final RegisterType UNKNOWN_TYPE = new RegisterType(UNKNOWN, null);
public static final RegisterType UNINIT_TYPE = new RegisterType(UNINIT, null);
public static final RegisterType NULL_TYPE = new RegisterType(NULL, null);
public static final RegisterType ONE_TYPE = new RegisterType(ONE, null);
public static final RegisterType BOOLEAN_TYPE = new RegisterType(BOOLEAN, null);
public static final RegisterType BYTE_TYPE = new RegisterType(BYTE, null);
public static final RegisterType POS_BYTE_TYPE = new RegisterType(POS_BYTE, null);
public static final RegisterType SHORT_TYPE = new RegisterType(SHORT, null);
public static final RegisterType POS_SHORT_TYPE = new RegisterType(POS_SHORT, null);
public static final RegisterType CHAR_TYPE = new RegisterType(CHAR, null);
public static final RegisterType INTEGER_TYPE = new RegisterType(INTEGER, null);
public static final RegisterType FLOAT_TYPE = new RegisterType(FLOAT, null);
public static final RegisterType LONG_LO_TYPE = new RegisterType(LONG_LO, null);
public static final RegisterType LONG_HI_TYPE = new RegisterType(LONG_HI, null);
public static final RegisterType DOUBLE_LO_TYPE = new RegisterType(DOUBLE_LO, null);
public static final RegisterType DOUBLE_HI_TYPE = new RegisterType(DOUBLE_HI, null);
public static final RegisterType CONFLICTED_TYPE = new RegisterType(CONFLICTED, null);
@Nonnull
public static RegisterType getWideRegisterType(@Nonnull CharSequence type, boolean firstRegister) {
switch (type.charAt(0)) {
case 'J':
if (firstRegister) {
return getRegisterType(LONG_LO, null);
} else {
return getRegisterType(LONG_HI, null);
}
case 'D':
if (firstRegister) {
return getRegisterType(DOUBLE_LO, null);
} else {
return getRegisterType(DOUBLE_HI, null);
}
default:
throw new ExceptionWithContext("Cannot use this method for narrow register type: %s", type);
}
}
@Nonnull
public static RegisterType getRegisterType(@Nonnull ClassPath classPath, @Nonnull CharSequence type) {
switch (type.charAt(0)) {
case 'Z':
return BOOLEAN_TYPE;
case 'B':
return BYTE_TYPE;
case 'S':
return SHORT_TYPE;
case 'C':
return CHAR_TYPE;
case 'I':
return INTEGER_TYPE;
case 'F':
return FLOAT_TYPE;
case 'J':
return LONG_LO_TYPE;
case 'D':
return DOUBLE_LO_TYPE;
case 'L':
case '[':
return getRegisterType(REFERENCE, classPath.getClass(type));
default:
throw new AnalysisException("Invalid type: " + type);
}
}
@Nonnull
public static RegisterType getRegisterTypeForLiteral(int literalValue) {
if (literalValue < -32768) {
return INTEGER_TYPE;
}
if (literalValue < -128) {
return SHORT_TYPE;
}
if (literalValue < 0) {
return BYTE_TYPE;
}
if (literalValue == 0) {
return NULL_TYPE;
}
if (literalValue == 1) {
return ONE_TYPE;
}
if (literalValue < 128) {
return POS_BYTE_TYPE;
}
if (literalValue < 32768) {
return POS_SHORT_TYPE;
}
if (literalValue < 65536) {
return CHAR_TYPE;
}
return INTEGER_TYPE;
}
@Nonnull
public RegisterType merge(@Nonnull RegisterType other) {
if (other.equals(this)) {
return this;
}
byte mergedCategory = mergeTable[this.category][other.category];
TypeProto mergedType = null;
if (mergedCategory == REFERENCE) {
TypeProto type = this.type;
if (type != null) {
if (other.type != null) {
mergedType = type.getCommonSuperclass(other.type);
} else {
mergedType = type;
}
} else {
mergedType = other.type;
}
} else if (mergedCategory == UNINIT_REF || mergedCategory == UNINIT_THIS) {
if (this.category == UNKNOWN) {
return other;
}
assert other.category == UNKNOWN;
return this;
}
if (mergedType != null) {
if (mergedType.equals(this.type)) {
return this;
}
if (mergedType.equals(other.type)) {
return other;
}
}
return RegisterType.getRegisterType(mergedCategory, mergedType);
}
@Nonnull
public static RegisterType getRegisterType(byte category, @Nullable TypeProto typeProto) {
switch (category) {
case UNKNOWN:
return UNKNOWN_TYPE;
case UNINIT:
return UNINIT_TYPE;
case NULL:
return NULL_TYPE;
case ONE:
return ONE_TYPE;
case BOOLEAN:
return BOOLEAN_TYPE;
case BYTE:
return BYTE_TYPE;
case POS_BYTE:
return POS_BYTE_TYPE;
case SHORT:
return SHORT_TYPE;
case POS_SHORT:
return POS_SHORT_TYPE;
case CHAR:
return CHAR_TYPE;
case INTEGER:
return INTEGER_TYPE;
case FLOAT:
return FLOAT_TYPE;
case LONG_LO:
return LONG_LO_TYPE;
case LONG_HI:
return LONG_HI_TYPE;
case DOUBLE_LO:
return DOUBLE_LO_TYPE;
case DOUBLE_HI:
return DOUBLE_HI_TYPE;
case CONFLICTED:
return CONFLICTED_TYPE;
}
return new RegisterType(category, typeProto);
}
}