blob: f9b12d397016ca54040e4ead968457f6960e64dd [file] [log] [blame]
// 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 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.code.BasicBlock.ThrowingInfo;
import com.android.tools.r8.ir.code.ConstInstruction;
import com.android.tools.r8.ir.code.ConstNumber;
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.EncodedValueUtils;
import com.android.tools.r8.utils.InternalOptions;
import java.util.Arrays;
import org.objectweb.asm.Handle;
import org.objectweb.asm.Type;
public abstract class DexValue extends DexItem {
public static final DexValue[] EMPTY_ARRAY = {};
public static final UnknownDexValue UNKNOWN = UnknownDexValue.UNKNOWN;
public static final byte VALUE_BYTE = 0x00;
public static final byte VALUE_SHORT = 0x02;
public static final byte VALUE_CHAR = 0x03;
public static final byte VALUE_INT = 0x04;
public static final byte VALUE_LONG = 0x06;
public static final byte VALUE_FLOAT = 0x10;
public static final byte VALUE_DOUBLE = 0x11;
public static final byte VALUE_METHOD_TYPE = 0x15;
public static final byte VALUE_METHOD_HANDLE = 0x16;
public static final byte VALUE_STRING = 0x17;
public static final byte VALUE_TYPE = 0x18;
public static final byte VALUE_FIELD = 0x19;
public static final byte VALUE_METHOD = 0x1a;
public static final byte VALUE_ENUM = 0x1b;
public static final byte VALUE_ARRAY = 0x1c;
public static final byte VALUE_ANNOTATION = 0x1d;
public static final byte VALUE_NULL = 0x1e;
public static final byte VALUE_BOOLEAN = 0x1f;
public DexValueMethodHandle asDexValueMethodHandle() {
return null;
}
public DexValueMethodType asDexValueMethodType() {
return null;
}
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(byte type, int arg, DexOutputBuffer dest) {
dest.putByte((byte) ((arg << 5) | type));
}
@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 Object getBoxedValue();
/** Returns an instruction that can be used to materialize this {@link DexValue} (or null). */
public ConstInstruction asConstInstruction(IRCode code, Value dest, InternalOptions options) {
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();
static public class UnknownDexValue extends DexValue {
// Singleton instance.
public static final UnknownDexValue UNKNOWN = new UnknownDexValue();
private UnknownDexValue() {
}
@Override
public void collectIndexedItems(IndexedItemCollection indexedItems,
DexMethod method, int instructionOffset) {
throw new Unreachable();
}
@Override
public void sort() {
throw new Unreachable();
}
@Override
public boolean mayHaveSideEffects() {
return true;
}
@Override
public void writeTo(DexOutputBuffer dest, ObjectToOffsetMapping mapping) {
throw new Unreachable();
}
@Override
public Object getBoxedValue() {
throw new Unreachable();
}
@Override
public Object asAsmEncodedObject() {
throw new Unreachable();
}
@Override
public int hashCode() {
return System.identityHashCode(this);
}
@Override
public boolean equals(Object other) {
return other == this;
}
@Override
public String toString() {
return "UNKNOWN";
}
@Override
public ConstInstruction asConstInstruction(IRCode code, Value dest, InternalOptions options) {
return null;
}
}
static private abstract class SimpleDexValue extends DexValue {
@Override
public void collectIndexedItems(IndexedItemCollection indexedItems,
DexMethod method, int instructionOffset) {
// Intentionally left empty
}
@Override
public void sort() {
// Intentionally empty
}
@Override
public boolean mayHaveSideEffects() {
return false;
}
protected static void writeIntegerTo(byte type, long value, int expected,
DexOutputBuffer dest) {
// Leave space for header.
dest.forward(1);
int length = dest.putSignedEncodedValue(value, expected);
dest.rewind(length + 1);
writeHeader(type, length - 1, dest);
dest.forward(length);
}
}
static public class DexValueByte extends SimpleDexValue {
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);
}
public byte getValue() {
return value;
}
@Override
public Object getBoxedValue() {
return getValue();
}
@Override
public void writeTo(DexOutputBuffer dest, ObjectToOffsetMapping mapping) {
writeHeader(VALUE_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(IRCode code, Value dest, InternalOptions options) {
return new ConstNumber(dest, value);
}
}
static public class DexValueShort extends SimpleDexValue {
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);
}
public short getValue() {
return value;
}
@Override
public Object getBoxedValue() {
return getValue();
}
@Override
public void writeTo(DexOutputBuffer dest, ObjectToOffsetMapping mapping) {
writeIntegerTo(VALUE_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(IRCode code, Value dest, InternalOptions options) {
return new ConstNumber(dest, value);
}
}
static public class DexValueChar extends SimpleDexValue {
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);
}
public char getValue() {
return value;
}
@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(VALUE_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(IRCode code, Value dest, InternalOptions options) {
return new ConstNumber(dest, value);
}
}
static public class DexValueInt extends SimpleDexValue {
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);
}
public int getValue() {
return value;
}
@Override
public Object getBoxedValue() {
return getValue();
}
@Override
public void writeTo(DexOutputBuffer dest, ObjectToOffsetMapping mapping) {
writeIntegerTo(VALUE_INT, value, Integer.BYTES, dest);
}
@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(IRCode code, Value dest, InternalOptions options) {
return new ConstNumber(dest, value);
}
}
static public class DexValueLong extends SimpleDexValue {
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);
}
public long getValue() {
return value;
}
@Override
public Object getBoxedValue() {
return getValue();
}
@Override
public void writeTo(DexOutputBuffer dest, ObjectToOffsetMapping mapping) {
writeIntegerTo(VALUE_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(IRCode code, Value dest, InternalOptions options) {
return new ConstNumber(dest, value);
}
}
static public class DexValueFloat extends SimpleDexValue {
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);
}
public float getValue() {
return value;
}
@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(VALUE_FLOAT, length - 1, dest);
dest.forward(length);
}
@Override
public Object asAsmEncodedObject() {
return Float.valueOf(value);
}
@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;
}
}
static public class DexValueDouble extends SimpleDexValue {
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);
}
public double getValue() {
return value;
}
@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(VALUE_DOUBLE, length - 1, dest);
dest.forward(length);
}
@Override
public Object asAsmEncodedObject() {
return Double.valueOf(value);
}
@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;
}
protected abstract byte getValueKind();
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 collectIndexedItems(IndexedItemCollection indexedItems,
DexMethod method, int instructionOffset) {
value.collectIndexedItems(indexedItems, method, instructionOffset);
}
@Override
public void sort() {
// Intentionally empty.
}
@Override
public int hashCode() {
return value.hashCode() * 7 + getValueKind();
}
@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
public Object asAsmEncodedObject() {
return value.toString();
}
@Override
protected byte getValueKind() {
return VALUE_STRING;
}
@Override
public ConstInstruction asConstInstruction(IRCode code, Value dest, InternalOptions options) {
ConstString instruction =
new ConstString(dest, value, ThrowingInfo.defaultForConstString(options));
if (!instruction.instructionInstanceCanThrow()) {
return instruction;
}
return null;
}
@Override
public boolean mayHaveSideEffects() {
// Assuming that strings do not have side-effects.
return false;
}
}
public static class DexItemBasedValueString extends NestedDexValue<DexReference> {
private final NameComputationInfo<?> nameComputationInfo;
public DexItemBasedValueString(DexReference value, NameComputationInfo<?> nameComputationInfo) {
super(value);
this.nameComputationInfo = nameComputationInfo;
}
public NameComputationInfo<?> getNameComputationInfo() {
return nameComputationInfo;
}
@Override
public Object asAsmEncodedObject() {
return value.toString();
}
@Override
protected byte getValueKind() {
return VALUE_STRING;
}
@Override
public ConstInstruction asConstInstruction(IRCode code, Value dest, InternalOptions options) {
DexItemBasedConstString instruction =
new DexItemBasedConstString(
dest, value, nameComputationInfo, ThrowingInfo.defaultForConstString(options));
// DexItemBasedConstString cannot throw.
assert !instruction.instructionInstanceCanThrow();
return instruction;
}
@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
protected byte getValueKind() {
return VALUE_TYPE;
}
@Override
public void collectIndexedItems(IndexedItemCollection indexedItems,
DexMethod method, int instructionOffset) {
value.collectIndexedItems(indexedItems, method, instructionOffset);
}
}
static public class DexValueField extends NestedDexValue<DexField> {
public DexValueField(DexField value) {
super(value);
}
@Override
protected byte getValueKind() {
return VALUE_FIELD;
}
@Override
public void collectIndexedItems(IndexedItemCollection indexedItems,
DexMethod method, int instructionOffset) {
value.collectIndexedItems(indexedItems, method, instructionOffset);
}
}
static public class DexValueMethod extends NestedDexValue<DexMethod> {
public DexValueMethod(DexMethod value) {
super(value);
}
@Override
protected byte getValueKind() {
return VALUE_METHOD;
}
@Override
public void collectIndexedItems(IndexedItemCollection indexedItems,
DexMethod method, int instructionOffset) {
value.collectIndexedItems(indexedItems, method, instructionOffset);
}
}
static public class DexValueEnum extends NestedDexValue<DexField> {
public DexValueEnum(DexField value) {
super(value);
}
@Override
protected byte getValueKind() {
return VALUE_ENUM;
}
@Override
public void collectIndexedItems(IndexedItemCollection indexedItems,
DexMethod method, int instructionOffset) {
value.collectIndexedItems(indexedItems, method, instructionOffset);
}
}
static public class DexValueMethodType extends NestedDexValue<DexProto> {
public DexValueMethodType(DexProto value) {
super(value);
}
@Override
public DexValueMethodType asDexValueMethodType() {
return this;
}
@Override
protected byte getValueKind() {
return VALUE_METHOD_TYPE;
}
@Override
public void collectIndexedItems(IndexedItemCollection indexedItems,
DexMethod method, int instructionOffset) {
value.collectIndexedItems(indexedItems, method, instructionOffset);
}
}
static public class DexValueArray extends DexValue {
final DexValue[] values;
public DexValueArray(DexValue[] values) {
this.values = values;
}
public DexValue[] getValues() {
return values;
}
@Override
public void collectIndexedItems(IndexedItemCollection indexedItems,
DexMethod method, int instructionOffset) {
collectAll(indexedItems, values);
}
@Override
public void writeTo(DexOutputBuffer dest, ObjectToOffsetMapping mapping) {
writeHeader(VALUE_ARRAY, 0, dest);
dest.putUleb128(values.length);
for (DexValue value : values) {
value.writeTo(dest, mapping);
}
}
@Override
public Object getBoxedValue() {
throw new Unreachable("No boxed value for DexValueArray");
}
@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);
}
}
static public class DexValueAnnotation extends DexValue {
public final DexEncodedAnnotation value;
public DexValueAnnotation(DexEncodedAnnotation value) {
this.value = value;
}
@Override
public void collectIndexedItems(IndexedItemCollection indexedItems,
DexMethod method, int instructionOffset) {
value.collectIndexedItems(indexedItems, method, instructionOffset);
}
@Override
public void writeTo(DexOutputBuffer dest, ObjectToOffsetMapping mapping) {
writeHeader(VALUE_ANNOTATION, 0, dest);
FileWriter.writeEncodedAnnotation(value, dest, mapping);
}
@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;
}
}
static public class DexValueNull extends SimpleDexValue {
public static final DexValue NULL = new DexValueNull();
// See DexValueNull.NULL
private DexValueNull() {
}
public Object getValue() {
return null;
}
@Override
public void writeTo(DexOutputBuffer dest, ObjectToOffsetMapping mapping) {
writeHeader(VALUE_NULL, 0, dest);
}
@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(IRCode code, Value dest, InternalOptions options) {
if (dest.getTypeLattice().isNullType()) {
return new ConstNumber(dest, 0);
}
return code.createConstNull(dest.getLocalInfo());
}
}
static public class DexValueBoolean extends SimpleDexValue {
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;
}
public boolean getValue() {
return value;
}
@Override
public Object getBoxedValue() {
return getValue();
}
@Override
public void writeTo(DexOutputBuffer dest, ObjectToOffsetMapping mapping) {
writeHeader(VALUE_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(IRCode code, Value dest, InternalOptions options) {
return new ConstNumber(dest, value ? 1 : 0);
}
}
static public class DexValueMethodHandle extends NestedDexValue<DexMethodHandle> {
public DexValueMethodHandle(DexMethodHandle value) {
super(value);
}
@Override
public DexValueMethodHandle asDexValueMethodHandle() {
return this;
}
@Override
protected byte getValueKind() {
return VALUE_METHOD_HANDLE;
}
@Override
public void collectIndexedItems(IndexedItemCollection indexedItems,
DexMethod method, int instructionOffset) {
value.collectIndexedItems(indexedItems, method, instructionOffset);
}
}
}