package js.tinyvm; import java.io.IOException; import java.util.logging.Logger; import js.tinyvm.io.IByteWriter; import org.apache.bcel.classfile.Constant; import org.apache.bcel.classfile.ConstantDouble; import org.apache.bcel.classfile.ConstantFloat; import org.apache.bcel.classfile.ConstantInteger; import org.apache.bcel.classfile.ConstantLong; import org.apache.bcel.classfile.ConstantPool; import org.apache.bcel.classfile.ConstantString; import org.apache.bcel.classfile.ConstantClass; /** * This class represents a constant value of a basic type. */ public class ConstantValue extends WritableDataWithOffset { Binary iBinary; /** * The dereferenced value. */ Object _value; /** * Constructor. * * @param pool constant pool * @param constant constant * @param aBinary */ public ConstantValue (ConstantPool pool, Constant constant, Binary aBinary) { iBinary = aBinary; _value = value(pool, constant); assert _value != null: "Postconditon: result != null"; } public ConstantValue(ClassRecord crec, Binary aBinary) { iBinary = aBinary; _value = crec; } // use Object.equals() for equality // use Object.hashCode() for hash code /** * Dereferenced value. */ public Object value () { assert _value != null: "Postconditon: result != null"; return _value; } /** * Get type of this value. */ public TinyVMType getType () { if (_value instanceof Double) { return TinyVMType.T_DOUBLE; } else if (_value instanceof Float) { return TinyVMType.T_FLOAT; } else if (_value instanceof Integer) { return TinyVMType.T_INT; } else if (_value instanceof Long) { return TinyVMType.T_LONG; } else if (_value instanceof String) { return TinyVMType.T_OBJECT; } else if (_value instanceof ClassRecord) { return TinyVMType.T_CLASS; } else { assert false: "Check: known type"; return null; } } /** * Get length in bytes of value. */ public int getLength () { if (_value instanceof Double) { return 8; } else if (_value instanceof Float) { return 4; } else if (_value instanceof Integer) { return 4; } else if (_value instanceof Long) { return 8; } else if (_value instanceof String) { return ((String) _value).getBytes().length; } else if (_value instanceof ClassRecord) { return 1; } else { assert false: "Check: known type"; return -1; } } /** * Returns the ideal data alignment for this data type. * @return the alignment in bytes. */ public int getAlignment() { // alignment is the same as length, except for strings which are byte // aligned. if (_value instanceof String) return 1; else return getLength(); } /** * Dump. * * @param writer byte writer */ public void dump (IByteWriter writer) throws TinyVMException { assert writer != null: "Precondition: writer != null"; try { // Constant values are dumped in system byte order. if (_value instanceof Double) { double doubleValue = ((Double) _value).doubleValue(); long longValue = Double.doubleToLongBits(doubleValue); writer.writeU4((int)(longValue >> 32)); writer.writeU4((int)(longValue & 0xffffffff)); } else if (_value instanceof Float) { writer .writeU4(Float.floatToIntBits(((Float) _value).floatValue())); } else if (_value instanceof Integer) { writer.writeU4(((Integer) _value).intValue()); } else if (_value instanceof Long) { long longValue = ((Long) _value).longValue(); writer.writeU4((int)(longValue >> 32)); writer.writeU4((int)(longValue & 0xffffffff)); } else if (_value instanceof String) { byte[] bytes = ((String) _value).getBytes(); writer.write(bytes); } else if (_value instanceof ClassRecord) { int pIdx = iBinary.getClassIndex(((ClassRecord) _value)); writer.writeU1(pIdx); } else { assert false: "Check: known entry type"; } } catch (IOException e) { throw new TinyVMException(e.getMessage(), e); } } // // protected interface // /** * Get value from constant. * * @param pool constant pool * @param constant constant to get value from * @return Double, Float, Integer, Long or String */ private Object value (ConstantPool pool, Constant constant) { assert pool != null: "Precondition: pool != null"; assert constant != null: "Precondition: constant != null"; Object result = null; if (constant instanceof ConstantDouble) { result = new Double(((ConstantDouble) constant).getBytes()); } else if (constant instanceof ConstantFloat) { result = new Float(((ConstantFloat) constant).getBytes()); } else if (constant instanceof ConstantInteger) { result = new Integer(((ConstantInteger) constant).getBytes()); } else if (constant instanceof ConstantLong) { result = new Long(((ConstantLong) constant).getBytes()); } else if (constant instanceof ConstantString) { result = new String(((ConstantString) constant).getBytes(pool)); } else if (constant instanceof ConstantClass) { result = iBinary.getClassRecord(((ConstantClass)constant).getBytes(pool)); } else { assert false: "Check: known type"; } assert result != null: "Postconditon: result != null"; return result; } public void markUsed() { if (_value instanceof ClassRecord) { ((ClassRecord)_value).markUsed(); } } private static final Logger _logger = Logger.getLogger("TinyVM"); }