886 lines
20 KiB
Java
886 lines
20 KiB
Java
/*******************************************************************************
|
|
* Copyright (c) 2002,2006 IBM Corporation.
|
|
* All rights reserved. This program and the accompanying materials
|
|
* are made available under the terms of the Eclipse Public License v1.0
|
|
* which accompanies this distribution, and is available at
|
|
* http://www.eclipse.org/legal/epl-v10.html
|
|
*
|
|
* Contributors:
|
|
* IBM Corporation - initial API and implementation
|
|
*******************************************************************************/
|
|
package com.ibm.wala.shrikeBT;
|
|
|
|
import com.ibm.wala.shrikeCT.BootstrapMethodsReader.BootstrapMethod;
|
|
import com.ibm.wala.shrikeCT.ConstantPoolParser;
|
|
|
|
/**
|
|
* A ConstantInstruction pushes some constant value onto the stack.
|
|
*/
|
|
public abstract class ConstantInstruction extends Instruction {
|
|
|
|
public static class InvokeDynamicToken {
|
|
private final BootstrapMethod bootstrapMethod;
|
|
private final String name;
|
|
private final String type;
|
|
|
|
public InvokeDynamicToken(BootstrapMethod bootstrapMethod, String name, String type) {
|
|
this.bootstrapMethod = bootstrapMethod;
|
|
this.name = name;
|
|
this.type = type;
|
|
}
|
|
|
|
@Override
|
|
public int hashCode() {
|
|
final int prime = 31;
|
|
int result = 1;
|
|
result = prime * result + ((bootstrapMethod == null) ? 0 : bootstrapMethod.hashCode());
|
|
result = prime * result + ((name == null) ? 0 : name.hashCode());
|
|
result = prime * result + ((type == null) ? 0 : type.hashCode());
|
|
return result;
|
|
}
|
|
|
|
@Override
|
|
public boolean equals(Object obj) {
|
|
if (this == obj)
|
|
return true;
|
|
if (obj == null)
|
|
return false;
|
|
if (getClass() != obj.getClass())
|
|
return false;
|
|
InvokeDynamicToken other = (InvokeDynamicToken) obj;
|
|
if (bootstrapMethod == null) {
|
|
if (other.bootstrapMethod != null)
|
|
return false;
|
|
} else if (!bootstrapMethod.equals(other.bootstrapMethod))
|
|
return false;
|
|
if (name == null) {
|
|
if (other.name != null)
|
|
return false;
|
|
} else if (!name.equals(other.name))
|
|
return false;
|
|
if (type == null) {
|
|
if (other.type != null)
|
|
return false;
|
|
} else if (!type.equals(other.type))
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
|
|
}
|
|
|
|
public static class ClassToken {
|
|
private final String typeName;
|
|
|
|
ClassToken(String typeName) {
|
|
this.typeName = typeName;
|
|
}
|
|
|
|
@Override
|
|
public int hashCode() {
|
|
final int prime = 31;
|
|
int result = 1;
|
|
result = prime * result + ((typeName == null) ? 0 : typeName.hashCode());
|
|
return result;
|
|
}
|
|
|
|
@Override
|
|
public boolean equals(Object obj) {
|
|
if (this == obj)
|
|
return true;
|
|
if (obj == null)
|
|
return false;
|
|
if (getClass() != obj.getClass())
|
|
return false;
|
|
ClassToken other = (ClassToken) obj;
|
|
if (typeName == null) {
|
|
if (other.typeName != null)
|
|
return false;
|
|
} else if (!typeName.equals(other.typeName))
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
public String getTypeName() {
|
|
return typeName;
|
|
}
|
|
|
|
}
|
|
|
|
public ConstantInstruction(short opcode) {
|
|
super(opcode);
|
|
}
|
|
|
|
ConstantPoolReader getLazyConstantPool() {
|
|
return null;
|
|
}
|
|
|
|
int getCPIndex() {
|
|
return 0;
|
|
}
|
|
|
|
final static class ConstNull extends ConstantInstruction {
|
|
protected ConstNull() {
|
|
super(OP_aconst_null);
|
|
}
|
|
|
|
private final static ConstNull preallocated = new ConstNull();
|
|
|
|
static ConstNull makeInternal() {
|
|
return preallocated;
|
|
}
|
|
|
|
@Override
|
|
public Object getValue() {
|
|
return null;
|
|
}
|
|
|
|
@Override
|
|
public String getType() {
|
|
return TYPE_null;
|
|
}
|
|
}
|
|
|
|
static class ConstInt extends ConstantInstruction {
|
|
protected int value;
|
|
|
|
private final static ConstInt[] preallocated = preallocate();
|
|
|
|
protected ConstInt(short opcode, int value) {
|
|
super(opcode);
|
|
this.value = value;
|
|
}
|
|
|
|
private static ConstInt[] preallocate() {
|
|
ConstInt[] r = new ConstInt[256];
|
|
for (int i = 0; i < r.length; i++) {
|
|
r[i] = new ConstInt(OP_bipush, i - 128);
|
|
}
|
|
for (int i = -1; i <= 5; i++) {
|
|
r[i + 128] = new ConstInt((short) (i - (-1) + OP_iconst_m1), i);
|
|
}
|
|
return r;
|
|
}
|
|
|
|
static ConstInt makeInternal(int i) {
|
|
if (((byte) i) == i) {
|
|
return preallocated[i + 128];
|
|
} else if (((short) i) == i) {
|
|
return new ConstInt(OP_sipush, i);
|
|
} else {
|
|
return new ConstInt(OP_ldc_w, i);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
final public Object getValue() {
|
|
return Integer.valueOf(getIntValue());
|
|
}
|
|
|
|
@Override
|
|
final public String getType() {
|
|
return TYPE_int;
|
|
}
|
|
|
|
public int getIntValue() {
|
|
return value;
|
|
}
|
|
}
|
|
|
|
final static class LazyInt extends ConstInt {
|
|
final private ConstantPoolReader cp;
|
|
|
|
final private int index;
|
|
|
|
private boolean isSet;
|
|
|
|
protected LazyInt(short opcode, ConstantPoolReader cp, int index) {
|
|
super(opcode, 0);
|
|
this.cp = cp;
|
|
this.index = index;
|
|
this.isSet = false;
|
|
}
|
|
|
|
@Override
|
|
public int getIntValue() {
|
|
if (!isSet) {
|
|
value = cp.getConstantPoolInteger(index);
|
|
isSet = true;
|
|
}
|
|
return value;
|
|
}
|
|
|
|
@Override
|
|
public ConstantPoolReader getLazyConstantPool() {
|
|
return cp;
|
|
}
|
|
|
|
@Override
|
|
public int getCPIndex() {
|
|
return index;
|
|
}
|
|
}
|
|
|
|
static class ConstLong extends ConstantInstruction {
|
|
protected long value;
|
|
|
|
private final static ConstLong[] preallocated = preallocate();
|
|
|
|
protected ConstLong(short opcode, long value) {
|
|
super(opcode);
|
|
this.value = value;
|
|
}
|
|
|
|
private static ConstLong[] preallocate() {
|
|
ConstLong[] r = { new ConstLong(OP_lconst_0, 0), new ConstLong(OP_lconst_1, 1) };
|
|
return r;
|
|
}
|
|
|
|
static ConstLong makeInternal(long v) {
|
|
if (v == 0 || v == 1) {
|
|
return preallocated[(int) v];
|
|
} else {
|
|
return new ConstLong(OP_ldc2_w, v);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
final public Object getValue() {
|
|
return Long.valueOf(getLongValue());
|
|
}
|
|
|
|
@Override
|
|
final public String getType() {
|
|
return TYPE_long;
|
|
}
|
|
|
|
public long getLongValue() {
|
|
return value;
|
|
}
|
|
}
|
|
|
|
final static class LazyLong extends ConstLong {
|
|
final private ConstantPoolReader cp;
|
|
|
|
final private int index;
|
|
|
|
private boolean isSet;
|
|
|
|
protected LazyLong(short opcode, ConstantPoolReader cp, int index) {
|
|
super(opcode, 0);
|
|
this.cp = cp;
|
|
this.index = index;
|
|
this.isSet = false;
|
|
}
|
|
|
|
@Override
|
|
public long getLongValue() {
|
|
if (!isSet) {
|
|
value = cp.getConstantPoolLong(index);
|
|
isSet = true;
|
|
}
|
|
return value;
|
|
}
|
|
|
|
@Override
|
|
public ConstantPoolReader getLazyConstantPool() {
|
|
return cp;
|
|
}
|
|
|
|
@Override
|
|
public int getCPIndex() {
|
|
return index;
|
|
}
|
|
}
|
|
|
|
static class ConstFloat extends ConstantInstruction {
|
|
protected float value;
|
|
|
|
private final static ConstFloat[] preallocated = preallocate();
|
|
|
|
protected ConstFloat(short opcode, float value) {
|
|
super(opcode);
|
|
this.value = value;
|
|
}
|
|
|
|
private static ConstFloat[] preallocate() {
|
|
ConstFloat[] r = { new ConstFloat(OP_fconst_0, 0), new ConstFloat(OP_fconst_1, 1), new ConstFloat(OP_fconst_2, 2) };
|
|
return r;
|
|
}
|
|
|
|
static ConstFloat makeInternal(float v) {
|
|
if (v == 0.0 || v == 1.0 || v == 2.0) {
|
|
return preallocated[(int) v];
|
|
} else {
|
|
return new ConstFloat(OP_ldc_w, v);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
final public Object getValue() {
|
|
return Float.valueOf(getFloatValue());
|
|
}
|
|
|
|
@Override
|
|
final public String getType() {
|
|
return TYPE_float;
|
|
}
|
|
|
|
public float getFloatValue() {
|
|
return value;
|
|
}
|
|
}
|
|
|
|
final static class LazyFloat extends ConstFloat {
|
|
final private ConstantPoolReader cp;
|
|
|
|
final private int index;
|
|
|
|
private boolean isSet;
|
|
|
|
protected LazyFloat(short opcode, ConstantPoolReader cp, int index) {
|
|
super(opcode, 0.0f);
|
|
this.cp = cp;
|
|
this.index = index;
|
|
this.isSet = false;
|
|
}
|
|
|
|
@Override
|
|
public float getFloatValue() {
|
|
if (!isSet) {
|
|
value = cp.getConstantPoolFloat(index);
|
|
isSet = true;
|
|
}
|
|
return value;
|
|
}
|
|
|
|
@Override
|
|
public ConstantPoolReader getLazyConstantPool() {
|
|
return cp;
|
|
}
|
|
|
|
@Override
|
|
public int getCPIndex() {
|
|
return index;
|
|
}
|
|
}
|
|
|
|
static class ConstDouble extends ConstantInstruction {
|
|
protected double value;
|
|
|
|
private final static ConstDouble[] preallocated = preallocate();
|
|
|
|
protected ConstDouble(short opcode, double value) {
|
|
super(opcode);
|
|
this.value = value;
|
|
}
|
|
|
|
private static ConstDouble[] preallocate() {
|
|
ConstDouble[] r = { new ConstDouble(OP_dconst_0, 0), new ConstDouble(OP_dconst_1, 1) };
|
|
return r;
|
|
}
|
|
|
|
static ConstDouble makeInternal(double v) {
|
|
if (v == 0.0 || v == 1.0) {
|
|
return preallocated[(int) v];
|
|
} else {
|
|
return new ConstDouble(OP_ldc2_w, v);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
final public Object getValue() {
|
|
return Double.valueOf(getDoubleValue());
|
|
}
|
|
|
|
@Override
|
|
final public String getType() {
|
|
return TYPE_double;
|
|
}
|
|
|
|
public double getDoubleValue() {
|
|
return value;
|
|
}
|
|
}
|
|
|
|
final static class LazyDouble extends ConstDouble {
|
|
final private ConstantPoolReader cp;
|
|
|
|
final private int index;
|
|
|
|
private boolean isSet;
|
|
|
|
protected LazyDouble(short opcode, ConstantPoolReader cp, int index) {
|
|
super(opcode, 0.0);
|
|
this.cp = cp;
|
|
this.index = index;
|
|
this.isSet = false;
|
|
}
|
|
|
|
@Override
|
|
public double getDoubleValue() {
|
|
if (!isSet) {
|
|
value = cp.getConstantPoolDouble(index);
|
|
isSet = true;
|
|
}
|
|
return value;
|
|
}
|
|
|
|
@Override
|
|
public ConstantPoolReader getLazyConstantPool() {
|
|
return cp;
|
|
}
|
|
|
|
@Override
|
|
public int getCPIndex() {
|
|
return index;
|
|
}
|
|
}
|
|
|
|
static class ConstString extends ConstantInstruction {
|
|
protected String value;
|
|
|
|
protected ConstString(short opcode, String value) {
|
|
super(opcode);
|
|
this.value = value;
|
|
}
|
|
|
|
static ConstString makeInternal(String v) {
|
|
return new ConstString(OP_ldc_w, v);
|
|
}
|
|
|
|
@Override
|
|
public Object getValue() {
|
|
return value;
|
|
}
|
|
|
|
@Override
|
|
final public String getType() {
|
|
return TYPE_String;
|
|
}
|
|
}
|
|
|
|
final static class LazyString extends ConstString {
|
|
final private ConstantPoolReader cp;
|
|
|
|
final private int index;
|
|
|
|
protected LazyString(short opcode, ConstantPoolReader cp, int index) {
|
|
super(opcode, null);
|
|
this.cp = cp;
|
|
this.index = index;
|
|
}
|
|
|
|
@Override
|
|
public Object getValue() {
|
|
if (value == null) {
|
|
value = cp.getConstantPoolString(index);
|
|
}
|
|
return value;
|
|
}
|
|
|
|
@Override
|
|
public ConstantPoolReader getLazyConstantPool() {
|
|
return cp;
|
|
}
|
|
|
|
@Override
|
|
public int getCPIndex() {
|
|
return index;
|
|
}
|
|
}
|
|
|
|
static class ConstClass extends ConstantInstruction {
|
|
protected String typeName;
|
|
|
|
protected ConstClass(short opcode, String typeName) {
|
|
super(opcode);
|
|
this.typeName = typeName;
|
|
}
|
|
|
|
static ConstClass makeInternal(String v) {
|
|
return new ConstClass(OP_ldc_w, v);
|
|
}
|
|
|
|
@Override
|
|
public Object getValue() {
|
|
return new ClassToken(typeName);
|
|
}
|
|
|
|
@Override
|
|
final public String getType() {
|
|
return TYPE_Class;
|
|
}
|
|
|
|
@Override
|
|
public boolean isPEI() {
|
|
// load of a class constant may trigger a ClassNotFoundException
|
|
return true;
|
|
}
|
|
|
|
}
|
|
|
|
final static class LazyClass extends ConstClass {
|
|
final private ConstantPoolReader cp;
|
|
|
|
final private int index;
|
|
|
|
protected LazyClass(short opcode, ConstantPoolReader cp, int index) {
|
|
super(opcode, null);
|
|
this.cp = cp;
|
|
this.index = index;
|
|
}
|
|
|
|
@Override
|
|
public Object getValue() {
|
|
if (typeName == null) {
|
|
typeName = cp.getConstantPoolClassType(index);
|
|
}
|
|
return new ClassToken(typeName);
|
|
}
|
|
|
|
@Override
|
|
public ConstantPoolReader getLazyConstantPool() {
|
|
return cp;
|
|
}
|
|
|
|
@Override
|
|
public int getCPIndex() {
|
|
return index;
|
|
}
|
|
}
|
|
|
|
static class ConstMethodType extends ConstantInstruction {
|
|
protected String descriptor;
|
|
|
|
ConstMethodType(short opcode, String descriptor) {
|
|
super(opcode);
|
|
this.descriptor = descriptor;
|
|
}
|
|
|
|
@Override
|
|
public Object getValue() {
|
|
return descriptor;
|
|
}
|
|
|
|
@Override
|
|
public String getType() {
|
|
return TYPE_MethodType;
|
|
}
|
|
}
|
|
|
|
static class LazyMethodType extends ConstMethodType {
|
|
final private ConstantPoolReader cp;
|
|
|
|
final private int index;
|
|
|
|
LazyMethodType(short opcode, ConstantPoolReader cp, int index) {
|
|
super(opcode, null);
|
|
this.cp = cp;
|
|
this.index = index;
|
|
}
|
|
|
|
@Override
|
|
public Object getValue() {
|
|
if (descriptor == null) {
|
|
descriptor = cp.getConstantPoolMethodType(index);
|
|
}
|
|
return descriptor;
|
|
}
|
|
|
|
@Override
|
|
public ConstantPoolReader getLazyConstantPool() {
|
|
return cp;
|
|
}
|
|
|
|
@Override
|
|
public int getCPIndex() {
|
|
return index;
|
|
}
|
|
}
|
|
|
|
static class ConstMethodHandle extends ConstantInstruction {
|
|
protected Object value;
|
|
|
|
public ConstMethodHandle(short opcode, Object value) {
|
|
super(opcode);
|
|
this.value = value;
|
|
}
|
|
|
|
@Override
|
|
public Object getValue() {
|
|
return value;
|
|
}
|
|
|
|
@Override
|
|
public String getType() {
|
|
return TYPE_MethodHandle;
|
|
}
|
|
|
|
}
|
|
|
|
static class LazyMethodHandle extends ConstMethodHandle {
|
|
final private ConstantPoolReader cp;
|
|
|
|
final private int index;
|
|
|
|
LazyMethodHandle(short opcode, ConstantPoolReader cp, int index) {
|
|
super(opcode, null);
|
|
this.cp = cp;
|
|
this.index = index;
|
|
}
|
|
|
|
@Override
|
|
public Object getValue() {
|
|
if (value == null) {
|
|
String className = cp.getConstantPoolHandleClassType(getCPIndex());
|
|
String eltName = cp.getConstantPoolHandleName(getCPIndex());
|
|
String eltDesc = cp.getConstantPoolHandleType(getCPIndex());
|
|
byte kind = cp.getConstantPoolHandleKind(getCPIndex());
|
|
value = new ConstantPoolParser.ReferenceToken(kind, className, eltName, eltDesc);
|
|
}
|
|
return value;
|
|
}
|
|
|
|
@Override
|
|
public ConstantPoolReader getLazyConstantPool() {
|
|
return cp;
|
|
}
|
|
|
|
@Override
|
|
public int getCPIndex() {
|
|
return index;
|
|
}
|
|
}
|
|
|
|
static class ConstInvokeDynamic extends ConstantInstruction {
|
|
protected Object value;
|
|
|
|
public ConstInvokeDynamic(short opcode, Object value) {
|
|
super(opcode);
|
|
this.value = value;
|
|
}
|
|
|
|
@Override
|
|
public Object getValue() {
|
|
return value;
|
|
}
|
|
|
|
@Override
|
|
public String getType() {
|
|
return null;
|
|
}
|
|
|
|
}
|
|
|
|
static class LazyInvokeDynamic extends ConstMethodHandle {
|
|
final private ConstantPoolReader cp;
|
|
|
|
final private int index;
|
|
|
|
LazyInvokeDynamic(short opcode, ConstantPoolReader cp, int index) {
|
|
super(opcode, null);
|
|
this.cp = cp;
|
|
this.index = index;
|
|
}
|
|
|
|
@Override
|
|
public Object getValue() {
|
|
if (value == null) {
|
|
BootstrapMethod bootstrap = cp.getConstantPoolDynamicBootstrap(index);
|
|
String name = cp.getConstantPoolDynamicName(index);
|
|
String type = cp.getConstantPoolDynamicType(index);
|
|
value = new InvokeDynamicToken(bootstrap, name, type);
|
|
}
|
|
|
|
return value;
|
|
}
|
|
|
|
@Override
|
|
public ConstantPoolReader getLazyConstantPool() {
|
|
return cp;
|
|
}
|
|
|
|
@Override
|
|
public int getCPIndex() {
|
|
return index;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @return the constant value pushed: an Integer, a Long, a Float, a Double, a String, or null
|
|
*/
|
|
public abstract Object getValue();
|
|
|
|
/**
|
|
* @return the type of the value pushed
|
|
*/
|
|
public abstract String getType();
|
|
|
|
public static ConstantInstruction make(String type, Object constant) throws IllegalArgumentException {
|
|
if (type == null && constant != null) {
|
|
throw new IllegalArgumentException("(type == null) and (constant != null)");
|
|
}
|
|
if (constant == null) {
|
|
return ConstNull.makeInternal();
|
|
} else if (type.equals(TYPE_String)) {
|
|
return makeString((String) constant);
|
|
} else if (type.equals(TYPE_Class)) {
|
|
return makeClass((String) constant);
|
|
} else {
|
|
try {
|
|
switch (Util.getTypeIndex(type)) {
|
|
case TYPE_int_index:
|
|
return make(((Number) constant).intValue());
|
|
case TYPE_long_index:
|
|
return make(((Number) constant).longValue());
|
|
case TYPE_float_index:
|
|
return make(((Number) constant).floatValue());
|
|
case TYPE_double_index:
|
|
return make(((Number) constant).doubleValue());
|
|
default:
|
|
throw new IllegalArgumentException("Invalid type for constant: " + type);
|
|
}
|
|
} catch (ClassCastException e) {
|
|
throw new IllegalArgumentException(e);
|
|
}
|
|
}
|
|
}
|
|
|
|
public static ConstantInstruction make(int i) {
|
|
return ConstInt.makeInternal(i);
|
|
}
|
|
|
|
public static ConstantInstruction make(long l) {
|
|
return ConstLong.makeInternal(l);
|
|
}
|
|
|
|
public static ConstantInstruction make(float f) {
|
|
return ConstFloat.makeInternal(f);
|
|
}
|
|
|
|
public static ConstantInstruction make(double d) {
|
|
return ConstDouble.makeInternal(d);
|
|
}
|
|
|
|
public static ConstantInstruction makeString(String s) {
|
|
return s == null ? (ConstantInstruction) ConstNull.makeInternal() : (ConstantInstruction) ConstString.makeInternal(s);
|
|
}
|
|
|
|
public static ConstantInstruction makeClass(String s) {
|
|
return ConstClass.makeInternal(s);
|
|
}
|
|
|
|
public static ConstantInstruction make(ConstantPoolReader cp, int index) {
|
|
switch (cp.getConstantPoolItemType(index)) {
|
|
case CONSTANT_Integer:
|
|
return new LazyInt(OP_ldc_w, cp, index);
|
|
case CONSTANT_Long:
|
|
return new LazyLong(OP_ldc2_w, cp, index);
|
|
case CONSTANT_Float:
|
|
return new LazyFloat(OP_ldc_w, cp, index);
|
|
case CONSTANT_Double:
|
|
return new LazyDouble(OP_ldc2_w, cp, index);
|
|
case CONSTANT_String:
|
|
return new LazyString(OP_ldc_w, cp, index);
|
|
case CONSTANT_Class:
|
|
return new LazyClass(OP_ldc_w, cp, index);
|
|
case CONSTANT_MethodHandle:
|
|
return new LazyMethodHandle(OP_ldc_w, cp, index);
|
|
case CONSTANT_MethodType:
|
|
return new LazyMethodType(OP_ldc_w, cp, index);
|
|
case CONSTANT_InvokeDynamic:
|
|
return new LazyInvokeDynamic(OP_ldc_w, cp, index);
|
|
default:
|
|
return null;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
final public boolean equals(Object o) {
|
|
if (o instanceof ConstantInstruction) {
|
|
ConstantInstruction i = (ConstantInstruction) o;
|
|
if (!i.getType().equals(getType())) {
|
|
return false;
|
|
}
|
|
if (i.getValue() == null) {
|
|
if (getValue() == null) {
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
} else {
|
|
if (getValue() == null) {
|
|
return false;
|
|
} else {
|
|
return i.getValue().equals(getValue());
|
|
}
|
|
}
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
final public String getPushedType(String[] types) {
|
|
return getType();
|
|
}
|
|
|
|
@Override
|
|
final public byte getPushedWordSize() {
|
|
return Util.getWordSize(getType());
|
|
}
|
|
|
|
@Override
|
|
final public int hashCode() {
|
|
int v = getValue() == null ? 0 : getValue().hashCode();
|
|
return getType().hashCode() + 14411 * v;
|
|
}
|
|
|
|
@Override
|
|
final public void visit(IInstruction.Visitor v) throws NullPointerException {
|
|
v.visitConstant(this);
|
|
}
|
|
|
|
private static String quote(Object o) {
|
|
if (o instanceof String) {
|
|
String s = (String) o;
|
|
StringBuffer buf = new StringBuffer("\"");
|
|
int len = s.length();
|
|
for (int i = 0; i < len; i++) {
|
|
char ch = s.charAt(i);
|
|
switch (ch) {
|
|
case '"':
|
|
buf.append('\\');
|
|
buf.append(ch);
|
|
break;
|
|
case '\n':
|
|
buf.append("\\\n");
|
|
break;
|
|
case '\t':
|
|
buf.append("\\\t");
|
|
break;
|
|
default:
|
|
buf.append(ch);
|
|
}
|
|
}
|
|
buf.append("\"");
|
|
return buf.toString();
|
|
} else if (o == null) {
|
|
return "null";
|
|
} else {
|
|
return o.toString();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
final public String toString() {
|
|
return "Constant(" + getType() + "," + quote(getValue()) + ")";
|
|
}
|
|
|
|
@Override
|
|
public boolean isPEI() {
|
|
return false;
|
|
}
|
|
}
|