| // Copyright (c) 2016, 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.graph; |
| |
| import static com.android.tools.r8.ir.analysis.type.Nullability.definitelyNotNull; |
| |
| import com.android.tools.r8.dex.DexOutputBuffer; |
| import com.android.tools.r8.dex.FileWriter; |
| import com.android.tools.r8.dex.IndexedItemCollection; |
| import com.android.tools.r8.dex.MixedSectionCollection; |
| import com.android.tools.r8.errors.Unreachable; |
| import com.android.tools.r8.ir.analysis.type.TypeElement; |
| import com.android.tools.r8.ir.analysis.value.AbstractValue; |
| import com.android.tools.r8.ir.analysis.value.AbstractValueFactory; |
| import com.android.tools.r8.ir.analysis.value.UnknownValue; |
| import com.android.tools.r8.ir.code.ConstInstruction; |
| import com.android.tools.r8.ir.code.ConstString; |
| import com.android.tools.r8.ir.code.DexItemBasedConstString; |
| import com.android.tools.r8.ir.code.IRCode; |
| import com.android.tools.r8.ir.code.Value; |
| import com.android.tools.r8.naming.dexitembasedstring.NameComputationInfo; |
| import com.android.tools.r8.utils.BooleanUtils; |
| import com.android.tools.r8.utils.EncodedValueUtils; |
| import com.android.tools.r8.utils.structural.CompareToVisitor; |
| import com.android.tools.r8.utils.structural.HashingVisitor; |
| import com.android.tools.r8.utils.structural.StructuralItem; |
| import com.android.tools.r8.utils.structural.StructuralMapping; |
| import java.util.Arrays; |
| import java.util.function.Consumer; |
| import org.objectweb.asm.Handle; |
| import org.objectweb.asm.Type; |
| |
| public abstract class DexValue extends DexItem implements StructuralItem<DexValue> { |
| |
| public enum DexValueKind { |
| BYTE(0x00), |
| SHORT(0x02), |
| CHAR(0x03), |
| INT(0x04), |
| LONG(0x06), |
| FLOAT(0x10), |
| DOUBLE(0x11), |
| METHOD_TYPE(0x15), |
| METHOD_HANDLE(0x16), |
| STRING(0x17), |
| TYPE(0x18), |
| FIELD(0x19), |
| METHOD(0x1a), |
| ENUM(0x1b), |
| ARRAY(0x1c), |
| ANNOTATION(0x1d), |
| NULL(0x1e), |
| BOOLEAN(0x1f); |
| |
| public static DexValueKind fromId(int id) { |
| switch (id) { |
| case 0x00: |
| return BYTE; |
| case 0x02: |
| return SHORT; |
| case 0x03: |
| return CHAR; |
| case 0x04: |
| return INT; |
| case 0x06: |
| return LONG; |
| case 0x10: |
| return FLOAT; |
| case 0x11: |
| return DOUBLE; |
| case 0x15: |
| return METHOD_TYPE; |
| case 0x16: |
| return METHOD_HANDLE; |
| case 0x17: |
| return STRING; |
| case 0x18: |
| return TYPE; |
| case 0x19: |
| return FIELD; |
| case 0x1a: |
| return METHOD; |
| case 0x1b: |
| return ENUM; |
| case 0x1c: |
| return ARRAY; |
| case 0x1d: |
| return ANNOTATION; |
| case 0x1e: |
| return NULL; |
| case 0x1f: |
| return BOOLEAN; |
| default: |
| throw new Unreachable(); |
| } |
| } |
| |
| private final byte b; |
| |
| DexValueKind(int b) { |
| this.b = (byte) b; |
| } |
| |
| byte toByte() { |
| return b; |
| } |
| } |
| |
| @Override |
| public DexValue self() { |
| return this; |
| } |
| |
| @Override |
| public final StructuralMapping<DexValue> getStructuralMapping() { |
| // DexValue is not generic at its base type (and can't as we use it as a polymorphic value), |
| // so each concrete value must implement polymorphic accept functions. This base class |
| // implements (most of) the polymorphic checks and concrete types implement the internal |
| // variants for that type. |
| throw new Unreachable(); |
| } |
| |
| @Override |
| public final int acceptCompareTo(DexValue other, CompareToVisitor visitor) { |
| // Order first on 'kind', only equal kinds then forward to the 'kind' specific internal compare. |
| if (getValueKind() != other.getValueKind()) { |
| return visitor.visitInt(getValueKind().toByte(), other.getValueKind().toByte()); |
| } else { |
| return internalAcceptCompareTo(other, visitor); |
| } |
| } |
| |
| @Override |
| public final void acceptHashing(HashingVisitor visitor) { |
| // Always hash the 'kind' which ensures that raw values of different type are distinct. |
| visitor.visitInt(getValueKind().toByte()); |
| internalAcceptHashing(visitor); |
| } |
| |
| abstract int internalAcceptCompareTo(DexValue other, CompareToVisitor visitor); |
| |
| abstract void internalAcceptHashing(HashingVisitor visitor); |
| |
| public static final DexValue[] EMPTY_ARRAY = {}; |
| |
| public abstract DexValueKind getValueKind(); |
| |
| public boolean isDexItemBasedValueString() { |
| return false; |
| } |
| |
| public DexItemBasedValueString asDexItemBasedValueString() { |
| return null; |
| } |
| |
| public boolean isDexValueMethodHandle() { |
| return false; |
| } |
| |
| public DexValueMethodHandle asDexValueMethodHandle() { |
| return null; |
| } |
| |
| public boolean isDexValueMethodType() { |
| return false; |
| } |
| |
| public DexValueMethodType asDexValueMethodType() { |
| return null; |
| } |
| |
| public boolean isDexValueAnnotation() { |
| return false; |
| } |
| |
| public DexValueAnnotation asDexValueAnnotation() { |
| return null; |
| } |
| |
| public boolean isDexValueArray() { |
| return false; |
| } |
| |
| public DexValueArray asDexValueArray() { |
| return null; |
| } |
| |
| public boolean isDexValueBoolean() { |
| return false; |
| } |
| |
| public DexValueBoolean asDexValueBoolean() { |
| return null; |
| } |
| |
| public boolean isDexValueByte() { |
| return false; |
| } |
| |
| public DexValueByte asDexValueByte() { |
| return null; |
| } |
| |
| public boolean isDexValueDouble() { |
| return false; |
| } |
| |
| public DexValueDouble asDexValueDouble() { |
| return null; |
| } |
| |
| public boolean isDexValueChar() { |
| return false; |
| } |
| |
| public DexValueChar asDexValueChar() { |
| return null; |
| } |
| |
| public boolean isDexValueEnum() { |
| return false; |
| } |
| |
| public DexValueEnum asDexValueEnum() { |
| return null; |
| } |
| |
| public boolean isDexValueField() { |
| return false; |
| } |
| |
| public DexValueField asDexValueField() { |
| return null; |
| } |
| |
| public boolean isDexValueFloat() { |
| return false; |
| } |
| |
| public DexValueFloat asDexValueFloat() { |
| return null; |
| } |
| |
| public boolean isDexValueInt() { |
| return false; |
| } |
| |
| public DexValueInt asDexValueInt() { |
| return null; |
| } |
| |
| public boolean isDexValueLong() { |
| return false; |
| } |
| |
| public DexValueLong asDexValueLong() { |
| return null; |
| } |
| |
| public boolean isDexValueMethod() { |
| return false; |
| } |
| |
| public DexValueMethod asDexValueMethod() { |
| return null; |
| } |
| |
| public boolean isDexValueNull() { |
| return false; |
| } |
| |
| public DexValueNull asDexValueNull() { |
| return null; |
| } |
| |
| public boolean isDexValueNumber() { |
| return false; |
| } |
| |
| public DexValueNumber asDexValueNumber() { |
| return null; |
| } |
| |
| public boolean isDexValueShort() { |
| return false; |
| } |
| |
| public DexValueShort asDexValueShort() { |
| return null; |
| } |
| |
| public boolean isDexValueString() { |
| return false; |
| } |
| |
| public DexValueString asDexValueString() { |
| return null; |
| } |
| |
| public boolean isDexValueType() { |
| return false; |
| } |
| |
| public DexValueType asDexValueType() { |
| return null; |
| } |
| |
| public boolean isNestedDexValue() { |
| return false; |
| } |
| |
| public abstract AbstractValue toAbstractValue(AbstractValueFactory factory); |
| |
| public static DexValue fromAsmBootstrapArgument( |
| Object value, JarApplicationReader application, DexType clazz) { |
| if (value instanceof Integer) { |
| return DexValue.DexValueInt.create((Integer) value); |
| } else if (value instanceof Long) { |
| return DexValue.DexValueLong.create((Long) value); |
| } else if (value instanceof Float) { |
| return DexValue.DexValueFloat.create((Float) value); |
| } else if (value instanceof Double) { |
| return DexValue.DexValueDouble.create((Double) value); |
| } else if (value instanceof String) { |
| return new DexValue.DexValueString(application.getString((String) value)); |
| |
| } else if (value instanceof Type) { |
| Type type = (Type) value; |
| switch (type.getSort()) { |
| case Type.OBJECT: |
| return new DexValue.DexValueType( |
| application.getTypeFromDescriptor(((Type) value).getDescriptor())); |
| case Type.METHOD: |
| return new DexValue.DexValueMethodType( |
| application.getProto(((Type) value).getDescriptor())); |
| default: |
| throw new Unreachable("Type sort is not supported: " + type.getSort()); |
| } |
| } else if (value instanceof Handle) { |
| return new DexValue.DexValueMethodHandle( |
| DexMethodHandle.fromAsmHandle((Handle) value, application, clazz)); |
| } else { |
| throw new Unreachable( |
| "Unsupported bootstrap static argument of type " + value.getClass().getSimpleName()); |
| } |
| } |
| |
| private static void writeHeader(DexValueKind kind, int arg, DexOutputBuffer dest) { |
| dest.putByte((byte) ((arg << 5) | kind.toByte())); |
| } |
| |
| public void collectIndexedItems(AppView<?> appView, IndexedItemCollection indexedItems) { |
| // Intentionally left empty |
| } |
| |
| @Override |
| void collectMixedSectionItems(MixedSectionCollection mixedItems) { |
| // Should never be visited. |
| throw new Unreachable(); |
| } |
| |
| public abstract void sort(); |
| |
| public abstract void writeTo(DexOutputBuffer dest, ObjectToOffsetMapping mapping); |
| |
| @Override |
| public abstract int hashCode(); |
| |
| @Override |
| public abstract boolean equals(Object other); |
| |
| @Override |
| public abstract String toString(); |
| |
| public static DexValue defaultForType(DexType type) { |
| switch (type.toShorty()) { |
| case 'Z': |
| return DexValueBoolean.DEFAULT; |
| case 'B': |
| return DexValueByte.DEFAULT; |
| case 'C': |
| return DexValueChar.DEFAULT; |
| case 'S': |
| return DexValueShort.DEFAULT; |
| case 'I': |
| return DexValueInt.DEFAULT; |
| case 'J': |
| return DexValueLong.DEFAULT; |
| case 'F': |
| return DexValueFloat.DEFAULT; |
| case 'D': |
| return DexValueDouble.DEFAULT; |
| case 'L': |
| return DexValueNull.NULL; |
| default: |
| throw new Unreachable("No default value for unexpected type " + type); |
| } |
| } |
| |
| public abstract DexType getType(DexItemFactory factory); |
| |
| public abstract Object getBoxedValue(); |
| |
| /** Returns an instruction that can be used to materialize this {@link DexValue} (or null). */ |
| public ConstInstruction asConstInstruction( |
| AppView<? extends AppInfoWithClassHierarchy> appView, IRCode code, DebugLocalInfo local) { |
| return null; |
| } |
| |
| public boolean isDefault(DexType type) { |
| return this == defaultForType(type); |
| } |
| |
| /** |
| * Whether creating this value as a default value for a field might trigger an allocation. |
| * |
| * <p>This is conservative. It also considers allocations due to class loading when referencing a |
| * field or method. |
| */ |
| public boolean mayHaveSideEffects() { |
| return true; |
| } |
| |
| public abstract Object asAsmEncodedObject(); |
| |
| private abstract static class SimpleDexValue extends DexValue { |
| |
| @Override |
| public void sort() { |
| // Intentionally empty |
| } |
| |
| @Override |
| public boolean mayHaveSideEffects() { |
| return false; |
| } |
| |
| static void writeIntegerTo(DexValueKind kind, long value, int expected, DexOutputBuffer dest) { |
| // Leave space for header. |
| dest.forward(1); |
| int length = dest.putSignedEncodedValue(value, expected); |
| dest.rewind(length + 1); |
| writeHeader(kind, length - 1, dest); |
| dest.forward(length); |
| } |
| } |
| |
| public abstract static class DexValueNumber extends SimpleDexValue { |
| |
| public abstract long getRawValue(); |
| |
| @Override |
| public boolean isDexValueNumber() { |
| return true; |
| } |
| |
| @Override |
| public DexValueNumber asDexValueNumber() { |
| return this; |
| } |
| |
| @Override |
| public AbstractValue toAbstractValue(AbstractValueFactory factory) { |
| return factory.createSingleNumberValue(getRawValue()); |
| } |
| } |
| |
| public static class DexValueByte extends DexValueNumber { |
| |
| public static final DexValueByte DEFAULT = new DexValueByte((byte) 0); |
| |
| final byte value; |
| |
| private DexValueByte(byte value) { |
| this.value = value; |
| } |
| |
| public static DexValueByte create(byte value) { |
| return value == DEFAULT.value ? DEFAULT : new DexValueByte(value); |
| } |
| |
| @Override |
| int internalAcceptCompareTo(DexValue other, CompareToVisitor visitor) { |
| return visitor.visitInt(value, other.asDexValueByte().value); |
| } |
| |
| @Override |
| void internalAcceptHashing(HashingVisitor visitor) { |
| visitor.visitInt(value); |
| } |
| |
| public byte getValue() { |
| return value; |
| } |
| |
| @Override |
| public DexValueKind getValueKind() { |
| return DexValueKind.BYTE; |
| } |
| |
| @Override |
| public DexType getType(DexItemFactory factory) { |
| return factory.byteType; |
| } |
| |
| @Override |
| public long getRawValue() { |
| return value; |
| } |
| |
| @Override |
| public boolean isDexValueByte() { |
| return true; |
| } |
| |
| @Override |
| public DexValueByte asDexValueByte() { |
| return this; |
| } |
| |
| @Override |
| public Object getBoxedValue() { |
| return getValue(); |
| } |
| |
| @Override |
| public void writeTo(DexOutputBuffer dest, ObjectToOffsetMapping mapping) { |
| writeHeader(DexValueKind.BYTE, 0, dest); |
| dest.putSignedEncodedValue(value, 1); |
| } |
| |
| @Override |
| public Object asAsmEncodedObject() { |
| return Integer.valueOf(value); |
| } |
| |
| @Override |
| public int hashCode() { |
| return value * 3; |
| } |
| |
| @Override |
| public boolean equals(Object other) { |
| if (other == this) { |
| return true; |
| } |
| return other instanceof DexValueByte && value == ((DexValueByte) other).value; |
| } |
| |
| @Override |
| public String toString() { |
| return "Byte " + value; |
| } |
| |
| @Override |
| public ConstInstruction asConstInstruction( |
| AppView<? extends AppInfoWithClassHierarchy> appView, IRCode code, DebugLocalInfo local) { |
| return code.createIntConstant(value, local); |
| } |
| } |
| |
| public static class DexValueShort extends DexValueNumber { |
| |
| public static final DexValueShort DEFAULT = new DexValueShort((short) 0); |
| final short value; |
| |
| private DexValueShort(short value) { |
| this.value = value; |
| } |
| |
| public static DexValueShort create(short value) { |
| return value == DEFAULT.value ? DEFAULT : new DexValueShort(value); |
| } |
| |
| @Override |
| void internalAcceptHashing(HashingVisitor visitor) { |
| visitor.visitInt(value); |
| } |
| |
| @Override |
| int internalAcceptCompareTo(DexValue other, CompareToVisitor visitor) { |
| return visitor.visitInt(value, other.asDexValueShort().getValue()); |
| } |
| |
| public short getValue() { |
| return value; |
| } |
| |
| @Override |
| public DexValueKind getValueKind() { |
| return DexValueKind.SHORT; |
| } |
| |
| @Override |
| public DexType getType(DexItemFactory factory) { |
| return factory.shortType; |
| } |
| |
| @Override |
| public long getRawValue() { |
| return value; |
| } |
| |
| @Override |
| public boolean isDexValueShort() { |
| return true; |
| } |
| |
| @Override |
| public DexValueShort asDexValueShort() { |
| return this; |
| } |
| |
| @Override |
| public Object getBoxedValue() { |
| return getValue(); |
| } |
| |
| @Override |
| public void writeTo(DexOutputBuffer dest, ObjectToOffsetMapping mapping) { |
| writeIntegerTo(DexValueKind.SHORT, value, Short.BYTES, dest); |
| } |
| |
| @Override |
| public Object asAsmEncodedObject() { |
| return Integer.valueOf(value); |
| } |
| |
| @Override |
| public int hashCode() { |
| return value * 7; |
| } |
| |
| @Override |
| public boolean equals(Object other) { |
| if (other == this) { |
| return true; |
| } |
| return other instanceof DexValueShort && value == ((DexValueShort) other).value; |
| } |
| |
| @Override |
| public String toString() { |
| return "Short " + value; |
| } |
| |
| @Override |
| public ConstInstruction asConstInstruction( |
| AppView<? extends AppInfoWithClassHierarchy> appView, IRCode code, DebugLocalInfo local) { |
| return code.createIntConstant(value, local); |
| } |
| } |
| |
| public static class DexValueChar extends DexValueNumber { |
| |
| public static final DexValueChar DEFAULT = new DexValueChar((char) 0); |
| final char value; |
| |
| private DexValueChar(char value) { |
| this.value = value; |
| } |
| |
| public static DexValueChar create(char value) { |
| return value == DEFAULT.value ? DEFAULT : new DexValueChar(value); |
| } |
| |
| @Override |
| int internalAcceptCompareTo(DexValue other, CompareToVisitor visitor) { |
| return visitor.visitInt(value, other.asDexValueChar().value); |
| } |
| |
| @Override |
| void internalAcceptHashing(HashingVisitor visitor) { |
| visitor.visitInt(value); |
| } |
| |
| public char getValue() { |
| return value; |
| } |
| |
| @Override |
| public DexValueKind getValueKind() { |
| return DexValueKind.CHAR; |
| } |
| |
| @Override |
| public DexType getType(DexItemFactory factory) { |
| return factory.charType; |
| } |
| |
| @Override |
| public long getRawValue() { |
| return value; |
| } |
| |
| @Override |
| public boolean isDexValueChar() { |
| return true; |
| } |
| |
| @Override |
| public DexValueChar asDexValueChar() { |
| return this; |
| } |
| |
| @Override |
| public Object getBoxedValue() { |
| return getValue(); |
| } |
| |
| @Override |
| public void writeTo(DexOutputBuffer dest, ObjectToOffsetMapping mapping) { |
| dest.forward(1); |
| int length = dest.putUnsignedEncodedValue(value, 2); |
| dest.rewind(length + 1); |
| writeHeader(DexValueKind.CHAR, length - 1, dest); |
| dest.forward(length); |
| } |
| |
| @Override |
| public Object asAsmEncodedObject() { |
| return Integer.valueOf(value); |
| } |
| |
| @Override |
| public int hashCode() { |
| return value * 5; |
| } |
| |
| @Override |
| public boolean equals(Object other) { |
| if (other == this) { |
| return true; |
| } |
| return other instanceof DexValueChar && value == ((DexValueChar) other).value; |
| } |
| |
| @Override |
| public String toString() { |
| return "Char " + value; |
| } |
| |
| @Override |
| public ConstInstruction asConstInstruction( |
| AppView<? extends AppInfoWithClassHierarchy> appView, IRCode code, DebugLocalInfo local) { |
| return code.createIntConstant(value, local); |
| } |
| } |
| |
| public static class DexValueInt extends DexValueNumber { |
| |
| public static final DexValueInt DEFAULT = new DexValueInt(0); |
| public final int value; |
| |
| private DexValueInt(int value) { |
| this.value = value; |
| } |
| |
| public static DexValueInt create(int value) { |
| return value == DEFAULT.value ? DEFAULT : new DexValueInt(value); |
| } |
| |
| @Override |
| void internalAcceptHashing(HashingVisitor visitor) { |
| visitor.visitInt(value); |
| } |
| |
| @Override |
| int internalAcceptCompareTo(DexValue other, CompareToVisitor visitor) { |
| return visitor.visitInt(value, other.asDexValueInt().value); |
| } |
| |
| public int getValue() { |
| return value; |
| } |
| |
| @Override |
| public DexValueKind getValueKind() { |
| return DexValueKind.INT; |
| } |
| |
| @Override |
| public DexType getType(DexItemFactory factory) { |
| return factory.intType; |
| } |
| |
| @Override |
| public long getRawValue() { |
| return value; |
| } |
| |
| @Override |
| public Object getBoxedValue() { |
| return getValue(); |
| } |
| |
| @Override |
| public void writeTo(DexOutputBuffer dest, ObjectToOffsetMapping mapping) { |
| writeIntegerTo(DexValueKind.INT, value, Integer.BYTES, dest); |
| } |
| |
| @Override |
| public boolean isDexValueInt() { |
| return true; |
| } |
| |
| @Override |
| public DexValueInt asDexValueInt() { |
| return this; |
| } |
| |
| @Override |
| public Object asAsmEncodedObject() { |
| return Integer.valueOf(value); |
| } |
| |
| @Override |
| public int hashCode() { |
| return value * 11; |
| } |
| |
| @Override |
| public boolean equals(Object other) { |
| if (other == this) { |
| return true; |
| } |
| return other instanceof DexValueInt && value == ((DexValueInt) other).value; |
| } |
| |
| @Override |
| public String toString() { |
| return "Int " + value; |
| } |
| |
| @Override |
| public ConstInstruction asConstInstruction( |
| AppView<? extends AppInfoWithClassHierarchy> appView, IRCode code, DebugLocalInfo local) { |
| return code.createIntConstant(value, local); |
| } |
| } |
| |
| public static class DexValueLong extends DexValueNumber { |
| |
| public static final DexValueLong DEFAULT = new DexValueLong(0); |
| final long value; |
| |
| private DexValueLong(long value) { |
| this.value = value; |
| } |
| |
| public static DexValueLong create(long value) { |
| return value == DEFAULT.value ? DEFAULT : new DexValueLong(value); |
| } |
| |
| @Override |
| int internalAcceptCompareTo(DexValue other, CompareToVisitor visitor) { |
| return visitor.visitLong(value, other.asDexValueLong().value); |
| } |
| |
| @Override |
| void internalAcceptHashing(HashingVisitor visitor) { |
| visitor.visitLong(value); |
| } |
| |
| public long getValue() { |
| return value; |
| } |
| |
| @Override |
| public DexValueKind getValueKind() { |
| return DexValueKind.LONG; |
| } |
| |
| @Override |
| public DexType getType(DexItemFactory factory) { |
| return factory.longType; |
| } |
| |
| @Override |
| public long getRawValue() { |
| return value; |
| } |
| |
| @Override |
| public boolean isDexValueLong() { |
| return true; |
| } |
| |
| @Override |
| public DexValueLong asDexValueLong() { |
| return this; |
| } |
| |
| @Override |
| public Object getBoxedValue() { |
| return getValue(); |
| } |
| |
| @Override |
| public void writeTo(DexOutputBuffer dest, ObjectToOffsetMapping mapping) { |
| writeIntegerTo(DexValueKind.LONG, value, Long.BYTES, dest); |
| } |
| |
| @Override |
| public Object asAsmEncodedObject() { |
| return Long.valueOf(value); |
| } |
| |
| @Override |
| public int hashCode() { |
| return (int) value * 13; |
| } |
| |
| @Override |
| public boolean equals(Object other) { |
| if (other == this) { |
| return true; |
| } |
| return other instanceof DexValueLong && value == ((DexValueLong) other).value; |
| } |
| |
| @Override |
| public String toString() { |
| return "Long " + value; |
| } |
| |
| @Override |
| public ConstInstruction asConstInstruction( |
| AppView<? extends AppInfoWithClassHierarchy> appView, IRCode code, DebugLocalInfo local) { |
| return code.createLongConstant(value, local); |
| } |
| } |
| |
| public static class DexValueFloat extends DexValueNumber { |
| |
| public static final DexValueFloat DEFAULT = new DexValueFloat(0); |
| final float value; |
| |
| private DexValueFloat(float value) { |
| this.value = value; |
| } |
| |
| public static DexValueFloat create(float value) { |
| return Float.compare(value, DEFAULT.value) == 0 ? DEFAULT : new DexValueFloat(value); |
| } |
| |
| @Override |
| void internalAcceptHashing(HashingVisitor visitor) { |
| visitor.visitFloat(value); |
| } |
| |
| @Override |
| int internalAcceptCompareTo(DexValue other, CompareToVisitor visitor) { |
| return visitor.visitFloat(value, other.asDexValueFloat().value); |
| } |
| |
| public float getValue() { |
| return value; |
| } |
| |
| @Override |
| public DexValueKind getValueKind() { |
| return DexValueKind.FLOAT; |
| } |
| |
| @Override |
| public DexType getType(DexItemFactory factory) { |
| return factory.floatType; |
| } |
| |
| @Override |
| public long getRawValue() { |
| return Float.floatToIntBits(value); |
| } |
| |
| @Override |
| public boolean isDexValueFloat() { |
| return true; |
| } |
| |
| @Override |
| public DexValueFloat asDexValueFloat() { |
| return this; |
| } |
| |
| @Override |
| public Object getBoxedValue() { |
| return getValue(); |
| } |
| |
| @Override |
| public void writeTo(DexOutputBuffer dest, ObjectToOffsetMapping mapping) { |
| dest.forward(1); |
| int length = EncodedValueUtils.putFloat(dest, value); |
| dest.rewind(length + 1); |
| writeHeader(DexValueKind.FLOAT, length - 1, dest); |
| dest.forward(length); |
| } |
| |
| @Override |
| public Object asAsmEncodedObject() { |
| return Float.valueOf(value); |
| } |
| |
| @Override |
| public ConstInstruction asConstInstruction( |
| AppView<? extends AppInfoWithClassHierarchy> appView, IRCode code, DebugLocalInfo local) { |
| return code.createFloatConstant(value, local); |
| } |
| |
| @Override |
| public int hashCode() { |
| return (int) (value * 19); |
| } |
| |
| @Override |
| public boolean equals(Object other) { |
| if (other == this) { |
| return true; |
| } |
| return other instanceof DexValueFloat |
| && Float.compare(value, ((DexValueFloat) other).value) == 0; |
| } |
| |
| @Override |
| public String toString() { |
| return "Float " + value; |
| } |
| } |
| |
| public static class DexValueDouble extends DexValueNumber { |
| |
| public static final DexValueDouble DEFAULT = new DexValueDouble(0); |
| |
| final double value; |
| |
| private DexValueDouble(double value) { |
| this.value = value; |
| } |
| |
| public static DexValueDouble create(double value) { |
| return Double.compare(value, DEFAULT.value) == 0 ? DEFAULT : new DexValueDouble(value); |
| } |
| |
| @Override |
| int internalAcceptCompareTo(DexValue other, CompareToVisitor visitor) { |
| return visitor.visitDouble(value, other.asDexValueDouble().value); |
| } |
| |
| @Override |
| void internalAcceptHashing(HashingVisitor visitor) { |
| visitor.visitDouble(value); |
| } |
| |
| public double getValue() { |
| return value; |
| } |
| |
| @Override |
| public DexValueKind getValueKind() { |
| return DexValueKind.DOUBLE; |
| } |
| |
| @Override |
| public DexType getType(DexItemFactory factory) { |
| return factory.doubleType; |
| } |
| |
| @Override |
| public long getRawValue() { |
| return Double.doubleToRawLongBits(value); |
| } |
| |
| @Override |
| public boolean isDexValueDouble() { |
| return true; |
| } |
| |
| @Override |
| public DexValueDouble asDexValueDouble() { |
| return this; |
| } |
| |
| @Override |
| public Object getBoxedValue() { |
| return getValue(); |
| } |
| |
| @Override |
| public void writeTo(DexOutputBuffer dest, ObjectToOffsetMapping mapping) { |
| dest.forward(1); |
| int length = EncodedValueUtils.putDouble(dest, value); |
| dest.rewind(length + 1); |
| writeHeader(DexValueKind.DOUBLE, length - 1, dest); |
| dest.forward(length); |
| } |
| |
| @Override |
| public Object asAsmEncodedObject() { |
| return Double.valueOf(value); |
| } |
| |
| @Override |
| public ConstInstruction asConstInstruction( |
| AppView<? extends AppInfoWithClassHierarchy> appView, IRCode code, DebugLocalInfo local) { |
| return code.createDoubleConstant(value, local); |
| } |
| |
| @Override |
| public int hashCode() { |
| return (int) (value * 29); |
| } |
| |
| @Override |
| public boolean equals(Object other) { |
| if (other == this) { |
| return true; |
| } |
| return (other instanceof DexValueDouble) && |
| (Double.compare(value, ((DexValueDouble) other).value) == 0); |
| } |
| |
| @Override |
| public String toString() { |
| return "Double " + value; |
| } |
| } |
| |
| static private abstract class NestedDexValue<T extends IndexedDexItem> extends DexValue { |
| |
| public final T value; |
| |
| private NestedDexValue(T value) { |
| this.value = value; |
| } |
| |
| @Override |
| public boolean isNestedDexValue() { |
| return true; |
| } |
| |
| @Override |
| public DexType getType(DexItemFactory factory) { |
| throw new Unreachable(); |
| } |
| |
| public T getValue() { |
| return value; |
| } |
| |
| @Override |
| public void writeTo(DexOutputBuffer dest, ObjectToOffsetMapping mapping) { |
| int offset = value.getOffset(mapping); |
| dest.forward(1); |
| int length = dest.putUnsignedEncodedValue(offset, 4); |
| dest.rewind(length + 1); |
| writeHeader(getValueKind(), length - 1, dest); |
| dest.forward(length); |
| } |
| |
| @Override |
| public Object getBoxedValue() { |
| throw new Unreachable("No boxed value for DexValue " + this.getClass().getSimpleName()); |
| } |
| |
| @Override |
| public Object asAsmEncodedObject() { |
| throw new Unreachable("No ASM conversion for DexValue " + this.getClass().getSimpleName()); |
| } |
| |
| @Override |
| public void sort() { |
| // Intentionally empty. |
| } |
| |
| @Override |
| public int hashCode() { |
| return value.hashCode() * 7 + getValueKind().toByte(); |
| } |
| |
| @Override |
| public boolean equals(Object other) { |
| if (other == this) { |
| return true; |
| } |
| if (other instanceof NestedDexValue) { |
| NestedDexValue<?> that = (NestedDexValue<?>) other; |
| return that.getValueKind() == getValueKind() && that.value.equals(value); |
| } |
| return false; |
| } |
| |
| @Override |
| public String toString() { |
| return "Item " + getValueKind() + " " + value; |
| } |
| } |
| |
| static public class DexValueString extends NestedDexValue<DexString> { |
| |
| public DexValueString(DexString value) { |
| super(value); |
| } |
| |
| @Override |
| void internalAcceptHashing(HashingVisitor visitor) { |
| value.acceptHashing(visitor); |
| } |
| |
| @Override |
| int internalAcceptCompareTo(DexValue other, CompareToVisitor visitor) { |
| int order = DexItemBasedValueString.compareAndCheckValueStrings(this, other, visitor); |
| if (order != 0) { |
| return order; |
| } |
| return value.acceptCompareTo(other.asDexValueString().value, visitor); |
| } |
| |
| @Override |
| public void collectIndexedItems(AppView<?> appView, IndexedItemCollection indexedItems) { |
| value.collectIndexedItems(indexedItems); |
| } |
| |
| @Override |
| public DexValueString asDexValueString() { |
| return this; |
| } |
| |
| @Override |
| public boolean isDexValueString() { |
| return true; |
| } |
| |
| @Override |
| public Object asAsmEncodedObject() { |
| return value.toString(); |
| } |
| |
| @Override |
| public DexValueKind getValueKind() { |
| return DexValueKind.STRING; |
| } |
| |
| @Override |
| public DexType getType(DexItemFactory factory) { |
| return factory.stringType; |
| } |
| |
| @Override |
| public ConstInstruction asConstInstruction( |
| AppView<? extends AppInfoWithClassHierarchy> appView, IRCode code, DebugLocalInfo local) { |
| TypeElement type = TypeElement.stringClassType(appView, definitelyNotNull()); |
| Value outValue = code.createValue(type, local); |
| ConstString instruction = new ConstString(outValue, value); |
| if (!instruction.instructionInstanceCanThrow()) { |
| return instruction; |
| } |
| return null; |
| } |
| |
| @Override |
| public boolean mayHaveSideEffects() { |
| // Assuming that strings do not have side-effects. |
| return false; |
| } |
| |
| @Override |
| public AbstractValue toAbstractValue(AbstractValueFactory factory) { |
| return factory.createSingleStringValue(value); |
| } |
| } |
| |
| public static class DexItemBasedValueString extends NestedDexValue<DexReference> { |
| |
| // Helper to ensure a consistent order on DexValueString and DexItemBasedValueString which are |
| // both defined to have kind 'string'. |
| static int compareAndCheckValueStrings(DexValue v1, DexValue v2, CompareToVisitor visitor) { |
| assert v1.getValueKind() == DexValueKind.STRING; |
| assert v2.getValueKind() == DexValueKind.STRING; |
| int order1 = v1.isDexItemBasedValueString() ? 1 : 0; |
| int order2 = v2.isDexItemBasedValueString() ? 1 : 0; |
| return visitor.visitInt(order1, order2); |
| } |
| |
| private final NameComputationInfo<?> nameComputationInfo; |
| |
| public DexItemBasedValueString(DexReference value, NameComputationInfo<?> nameComputationInfo) { |
| super(value); |
| this.nameComputationInfo = nameComputationInfo; |
| } |
| |
| @Override |
| void internalAcceptHashing(HashingVisitor visitor) { |
| visitor.visitDexReference(value); |
| } |
| |
| @Override |
| int internalAcceptCompareTo(DexValue other, CompareToVisitor visitor) { |
| int order = compareAndCheckValueStrings(this, other, visitor); |
| if (order != 0) { |
| return order; |
| } |
| return visitor.visitDexReference(value, other.asDexItemBasedValueString().value); |
| } |
| |
| @Override |
| public void collectIndexedItems(AppView<?> appView, IndexedItemCollection indexedItems) { |
| value.collectIndexedItems(appView, indexedItems); |
| } |
| |
| public NameComputationInfo<?> getNameComputationInfo() { |
| return nameComputationInfo; |
| } |
| |
| @Override |
| public boolean isDexItemBasedValueString() { |
| return true; |
| } |
| |
| @Override |
| public DexItemBasedValueString asDexItemBasedValueString() { |
| return this; |
| } |
| |
| @Override |
| public Object asAsmEncodedObject() { |
| return value.toString(); |
| } |
| |
| @Override |
| public DexValueKind getValueKind() { |
| return DexValueKind.STRING; |
| } |
| |
| @Override |
| public DexType getType(DexItemFactory factory) { |
| return factory.stringType; |
| } |
| |
| @Override |
| public ConstInstruction asConstInstruction( |
| AppView<? extends AppInfoWithClassHierarchy> appView, IRCode code, DebugLocalInfo local) { |
| TypeElement type = TypeElement.stringClassType(appView, definitelyNotNull()); |
| Value outValue = code.createValue(type, local); |
| DexItemBasedConstString instruction = |
| new DexItemBasedConstString(outValue, value, nameComputationInfo); |
| // DexItemBasedConstString cannot throw. |
| assert !instruction.instructionInstanceCanThrow(); |
| return instruction; |
| } |
| |
| @Override |
| public AbstractValue toAbstractValue(AbstractValueFactory factory) { |
| return factory.createSingleDexItemBasedStringValue(value, nameComputationInfo); |
| } |
| |
| @Override |
| public void writeTo(DexOutputBuffer dest, ObjectToOffsetMapping mapping) { |
| throw new Unreachable( |
| "DexItemBasedValueString values should always be rewritten into DexValueString"); |
| } |
| } |
| |
| static public class DexValueType extends NestedDexValue<DexType> { |
| |
| public DexValueType(DexType value) { |
| super(value); |
| } |
| |
| @Override |
| int internalAcceptCompareTo(DexValue other, CompareToVisitor visitor) { |
| return value.acceptCompareTo(other.asDexValueType().value, visitor); |
| } |
| |
| @Override |
| void internalAcceptHashing(HashingVisitor visitor) { |
| value.acceptHashing(visitor); |
| } |
| |
| @Override |
| public DexValueKind getValueKind() { |
| return DexValueKind.TYPE; |
| } |
| |
| @Override |
| public void collectIndexedItems(AppView<?> appView, IndexedItemCollection indexedItems) { |
| value.collectIndexedItems(appView, indexedItems); |
| } |
| |
| @Override |
| public DexValueType asDexValueType() { |
| return this; |
| } |
| |
| @Override |
| public boolean isDexValueType() { |
| return true; |
| } |
| |
| @Override |
| public AbstractValue toAbstractValue(AbstractValueFactory factory) { |
| return UnknownValue.getInstance(); |
| } |
| } |
| |
| static public class DexValueField extends NestedDexValue<DexField> { |
| |
| public DexValueField(DexField value) { |
| super(value); |
| } |
| |
| @Override |
| int internalAcceptCompareTo(DexValue other, CompareToVisitor visitor) { |
| return value.acceptCompareTo(other.asDexValueField().value, visitor); |
| } |
| |
| @Override |
| void internalAcceptHashing(HashingVisitor visitor) { |
| value.acceptHashing(visitor); |
| } |
| |
| @Override |
| public DexValueKind getValueKind() { |
| return DexValueKind.FIELD; |
| } |
| |
| @Override |
| public void collectIndexedItems(AppView<?> appView, IndexedItemCollection indexedItems) { |
| value.collectIndexedItems(appView, indexedItems); |
| } |
| |
| @Override |
| public boolean isDexValueField() { |
| return true; |
| } |
| |
| @Override |
| public DexValueField asDexValueField() { |
| return this; |
| } |
| |
| @Override |
| public AbstractValue toAbstractValue(AbstractValueFactory factory) { |
| return UnknownValue.getInstance(); |
| } |
| } |
| |
| static public class DexValueMethod extends NestedDexValue<DexMethod> { |
| |
| public DexValueMethod(DexMethod value) { |
| super(value); |
| } |
| |
| @Override |
| int internalAcceptCompareTo(DexValue other, CompareToVisitor visitor) { |
| return value.acceptCompareTo(other.asDexValueMethod().value, visitor); |
| } |
| |
| @Override |
| void internalAcceptHashing(HashingVisitor visitor) { |
| value.acceptHashing(visitor); |
| } |
| |
| @Override |
| public DexValueKind getValueKind() { |
| return DexValueKind.METHOD; |
| } |
| |
| @Override |
| public void collectIndexedItems(AppView<?> appView, IndexedItemCollection indexedItems) { |
| value.collectIndexedItems(appView, indexedItems); |
| } |
| |
| @Override |
| public boolean isDexValueMethod() { |
| return true; |
| } |
| |
| @Override |
| public DexValueMethod asDexValueMethod() { |
| return this; |
| } |
| |
| @Override |
| public AbstractValue toAbstractValue(AbstractValueFactory factory) { |
| return UnknownValue.getInstance(); |
| } |
| } |
| |
| static public class DexValueEnum extends NestedDexValue<DexField> { |
| |
| public DexValueEnum(DexField value) { |
| super(value); |
| } |
| |
| @Override |
| int internalAcceptCompareTo(DexValue other, CompareToVisitor visitor) { |
| return value.acceptCompareTo(other.asDexValueEnum().value, visitor); |
| } |
| |
| @Override |
| void internalAcceptHashing(HashingVisitor visitor) { |
| value.acceptHashing(visitor); |
| } |
| |
| @Override |
| public DexValueKind getValueKind() { |
| return DexValueKind.ENUM; |
| } |
| |
| @Override |
| public void collectIndexedItems(AppView<?> appView, IndexedItemCollection indexedItems) { |
| value.collectIndexedItems(appView, indexedItems); |
| } |
| |
| @Override |
| public boolean isDexValueEnum() { |
| return true; |
| } |
| |
| @Override |
| public DexValueEnum asDexValueEnum() { |
| return this; |
| } |
| |
| @Override |
| public AbstractValue toAbstractValue(AbstractValueFactory factory) { |
| return UnknownValue.getInstance(); |
| } |
| } |
| |
| static public class DexValueMethodType extends NestedDexValue<DexProto> { |
| |
| public DexValueMethodType(DexProto value) { |
| super(value); |
| } |
| |
| @Override |
| int internalAcceptCompareTo(DexValue other, CompareToVisitor visitor) { |
| return value.acceptCompareTo(other.asDexValueMethodType().value, visitor); |
| } |
| |
| @Override |
| void internalAcceptHashing(HashingVisitor visitor) { |
| value.acceptHashing(visitor); |
| } |
| |
| @Override |
| public boolean isDexValueMethodType() { |
| return true; |
| } |
| |
| @Override |
| public DexValueMethodType asDexValueMethodType() { |
| return this; |
| } |
| |
| @Override |
| public DexValueKind getValueKind() { |
| return DexValueKind.METHOD_TYPE; |
| } |
| |
| @Override |
| public void collectIndexedItems(AppView<?> appView, IndexedItemCollection indexedItems) { |
| value.collectIndexedItems(appView, indexedItems); |
| } |
| |
| @Override |
| public AbstractValue toAbstractValue(AbstractValueFactory factory) { |
| return UnknownValue.getInstance(); |
| } |
| } |
| |
| static public class DexValueArray extends DexValue { |
| |
| final DexValue[] values; |
| |
| public DexValueArray(DexValue[] values) { |
| this.values = values; |
| } |
| |
| @Override |
| int internalAcceptCompareTo(DexValue other, CompareToVisitor visitor) { |
| return visitor.visitItemArray(values, other.asDexValueArray().values); |
| } |
| |
| @Override |
| void internalAcceptHashing(HashingVisitor visitor) { |
| visitor.visitItemArray(values); |
| } |
| |
| public void forEachElement(Consumer<DexValue> consumer) { |
| for (DexValue value : values) { |
| consumer.accept(value); |
| } |
| } |
| |
| public DexValue[] getValues() { |
| return values; |
| } |
| |
| @Override |
| public DexValueKind getValueKind() { |
| return DexValueKind.ARRAY; |
| } |
| |
| @Override |
| public void collectIndexedItems(AppView<?> appView, IndexedItemCollection indexedItems) { |
| for (DexValue value : values) { |
| value.collectIndexedItems(appView, indexedItems); |
| } |
| } |
| |
| @Override |
| public void writeTo(DexOutputBuffer dest, ObjectToOffsetMapping mapping) { |
| writeHeader(DexValueKind.ARRAY, 0, dest); |
| dest.putUleb128(values.length); |
| for (DexValue value : values) { |
| value.writeTo(dest, mapping); |
| } |
| } |
| |
| @Override |
| public DexType getType(DexItemFactory factory) { |
| throw new Unreachable(); |
| } |
| |
| @Override |
| public Object getBoxedValue() { |
| throw new Unreachable("No boxed value for DexValueArray"); |
| } |
| |
| @Override |
| public AbstractValue toAbstractValue(AbstractValueFactory factory) { |
| return UnknownValue.getInstance(); |
| } |
| |
| @Override |
| public Object asAsmEncodedObject() { |
| throw new Unreachable("No ASM conversion for DexValueArray"); |
| } |
| |
| @Override |
| public void sort() { |
| for (DexValue value : values) { |
| value.sort(); |
| } |
| } |
| |
| @Override |
| public int hashCode() { |
| return Arrays.hashCode(values); |
| } |
| |
| @Override |
| public boolean equals(Object other) { |
| if (other == this) { |
| return true; |
| } |
| if (other instanceof DexValueArray) { |
| DexValueArray that = (DexValueArray) other; |
| return Arrays.equals(that.values, values); |
| } |
| return false; |
| } |
| |
| @Override |
| public String toString() { |
| return "Array " + Arrays.toString(values); |
| } |
| |
| @Override |
| public boolean isDexValueArray() { |
| return true; |
| } |
| |
| @Override |
| public DexValueArray asDexValueArray() { |
| return this; |
| } |
| } |
| |
| static public class DexValueAnnotation extends DexValue { |
| |
| public final DexEncodedAnnotation value; |
| |
| public DexValueAnnotation(DexEncodedAnnotation value) { |
| this.value = value; |
| } |
| |
| @Override |
| int internalAcceptCompareTo(DexValue other, CompareToVisitor visitor) { |
| return value.acceptCompareTo(other.asDexValueAnnotation().value, visitor); |
| } |
| |
| @Override |
| void internalAcceptHashing(HashingVisitor visitor) { |
| value.acceptHashing(visitor); |
| } |
| |
| public DexEncodedAnnotation getValue() { |
| return value; |
| } |
| |
| @Override |
| public DexValueKind getValueKind() { |
| return DexValueKind.ANNOTATION; |
| } |
| |
| @Override |
| public boolean isDexValueAnnotation() { |
| return true; |
| } |
| |
| @Override |
| public DexValueAnnotation asDexValueAnnotation() { |
| return this; |
| } |
| |
| @Override |
| public void collectIndexedItems(AppView<?> appView, IndexedItemCollection indexedItems) { |
| value.collectIndexedItems(appView, indexedItems); |
| } |
| |
| @Override |
| public AbstractValue toAbstractValue(AbstractValueFactory factory) { |
| return UnknownValue.getInstance(); |
| } |
| |
| @Override |
| public void writeTo(DexOutputBuffer dest, ObjectToOffsetMapping mapping) { |
| writeHeader(DexValueKind.ANNOTATION, 0, dest); |
| FileWriter.writeEncodedAnnotation(value, dest, mapping); |
| } |
| |
| @Override |
| public DexType getType(DexItemFactory factory) { |
| throw new Unreachable(); |
| } |
| |
| @Override |
| public Object getBoxedValue() { |
| throw new Unreachable("No boxed value for DexValueAnnotation"); |
| } |
| |
| @Override |
| public Object asAsmEncodedObject() { |
| throw new Unreachable("No ASM conversion for DexValueAnnotation"); |
| } |
| |
| @Override |
| public void sort() { |
| value.sort(); |
| } |
| |
| @Override |
| public int hashCode() { |
| return value.hashCode() * 7; |
| } |
| |
| @Override |
| public boolean equals(Object other) { |
| if (other == this) { |
| return true; |
| } |
| if (other instanceof DexValueAnnotation) { |
| DexValueAnnotation that = (DexValueAnnotation) other; |
| return that.value.equals(value); |
| } |
| return false; |
| } |
| |
| @Override |
| public String toString() { |
| return "Annotation " + value; |
| } |
| } |
| |
| public static class DexValueNull extends DexValueNumber { |
| |
| public static final DexValue NULL = new DexValueNull(); |
| |
| // See DexValueNull.NULL |
| private DexValueNull() { |
| } |
| |
| @Override |
| void internalAcceptHashing(HashingVisitor visitor) { |
| assert this == NULL; |
| } |
| |
| @Override |
| int internalAcceptCompareTo(DexValue other, CompareToVisitor visitor) { |
| assert this == NULL; |
| assert other == NULL; |
| return 0; |
| } |
| |
| public Object getValue() { |
| return null; |
| } |
| |
| @Override |
| public DexValueKind getValueKind() { |
| return DexValueKind.NULL; |
| } |
| |
| @Override |
| public DexType getType(DexItemFactory factory) { |
| throw new Unreachable(); |
| } |
| |
| @Override |
| public long getRawValue() { |
| return 0; |
| } |
| |
| @Override |
| public void writeTo(DexOutputBuffer dest, ObjectToOffsetMapping mapping) { |
| writeHeader(DexValueKind.NULL, 0, dest); |
| } |
| |
| @Override |
| public boolean isDexValueNull() { |
| return true; |
| } |
| |
| @Override |
| public DexValueNull asDexValueNull() { |
| return this; |
| } |
| |
| @Override |
| public Object getBoxedValue() { |
| return null; |
| } |
| |
| @Override |
| public Object asAsmEncodedObject() { |
| return null; |
| } |
| |
| @Override |
| public int hashCode() { |
| return 42; |
| } |
| |
| @Override |
| public boolean equals(Object other) { |
| if (other == this) { |
| return true; |
| } |
| return other instanceof DexValueNull; |
| } |
| |
| @Override |
| public String toString() { |
| return "Null"; |
| } |
| |
| @Override |
| public ConstInstruction asConstInstruction( |
| AppView<? extends AppInfoWithClassHierarchy> appView, IRCode code, DebugLocalInfo local) { |
| return code.createConstNull(local); |
| } |
| } |
| |
| public static class DexValueBoolean extends DexValueNumber { |
| |
| private static final DexValueBoolean TRUE = new DexValueBoolean(true); |
| private static final DexValueBoolean FALSE = new DexValueBoolean(false); |
| // Use a separate instance for the default value to distinguish it from an explicit false value. |
| private static final DexValueBoolean DEFAULT = new DexValueBoolean(false); |
| |
| final boolean value; |
| |
| private DexValueBoolean(boolean value) { |
| this.value = value; |
| } |
| |
| public static DexValueBoolean create(boolean value) { |
| return value ? TRUE : FALSE; |
| } |
| |
| @Override |
| int internalAcceptCompareTo(DexValue other, CompareToVisitor visitor) { |
| return visitor.visitBool(value, other.asDexValueBoolean().value); |
| } |
| |
| @Override |
| void internalAcceptHashing(HashingVisitor visitor) { |
| visitor.visitBool(value); |
| } |
| |
| public boolean getValue() { |
| return value; |
| } |
| |
| @Override |
| public DexValueKind getValueKind() { |
| return DexValueKind.BOOLEAN; |
| } |
| |
| @Override |
| public DexType getType(DexItemFactory factory) { |
| return factory.booleanType; |
| } |
| |
| @Override |
| public long getRawValue() { |
| return BooleanUtils.longValue(value); |
| } |
| |
| @Override |
| public boolean isDexValueBoolean() { |
| return true; |
| } |
| |
| @Override |
| public DexValueBoolean asDexValueBoolean() { |
| return this; |
| } |
| |
| @Override |
| public Object getBoxedValue() { |
| return getValue(); |
| } |
| |
| @Override |
| public void writeTo(DexOutputBuffer dest, ObjectToOffsetMapping mapping) { |
| writeHeader(DexValueKind.BOOLEAN, value ? 1 : 0, dest); |
| } |
| |
| @Override |
| public Object asAsmEncodedObject() { |
| return Integer.valueOf(value ? 1 : 0); |
| } |
| |
| @Override |
| public int hashCode() { |
| return value ? 1234 : 4321; |
| } |
| |
| @Override |
| public boolean equals(Object other) { |
| if (other == this) { |
| return true; |
| } |
| return other instanceof DexValueBoolean && ((DexValueBoolean) other).value == value; |
| } |
| |
| @Override |
| public String toString() { |
| return value ? "True" : "False"; |
| } |
| |
| @Override |
| public ConstInstruction asConstInstruction( |
| AppView<? extends AppInfoWithClassHierarchy> appView, IRCode code, DebugLocalInfo local) { |
| return code.createIntConstant(BooleanUtils.intValue(value), local); |
| } |
| } |
| |
| static public class DexValueMethodHandle extends NestedDexValue<DexMethodHandle> { |
| |
| public DexValueMethodHandle(DexMethodHandle value) { |
| super(value); |
| } |
| |
| @Override |
| int internalAcceptCompareTo(DexValue other, CompareToVisitor visitor) { |
| return value.acceptCompareTo(other.asDexValueMethodHandle().value, visitor); |
| } |
| |
| @Override |
| void internalAcceptHashing(HashingVisitor visitor) { |
| value.acceptHashing(visitor); |
| } |
| |
| @Override |
| public boolean isDexValueMethodHandle() { |
| return true; |
| } |
| |
| @Override |
| public DexValueMethodHandle asDexValueMethodHandle() { |
| return this; |
| } |
| |
| @Override |
| public DexValueKind getValueKind() { |
| return DexValueKind.METHOD_HANDLE; |
| } |
| |
| @Override |
| public void collectIndexedItems(AppView<?> appView, IndexedItemCollection indexedItems) { |
| value.collectIndexedItems(appView, indexedItems); |
| } |
| |
| @Override |
| public AbstractValue toAbstractValue(AbstractValueFactory factory) { |
| return UnknownValue.getInstance(); |
| } |
| } |
| } |