001 package serp.bytecode;
002
003 import java.io.*;
004 import java.util.*;
005
006 import serp.bytecode.visitor.*;
007
008 /**
009 * The <code>newarray</code> instruction, which is used to create new
010 * arrays of primitive types.
011 *
012 * @author Abe White
013 */
014 public class NewArrayInstruction extends TypedInstruction {
015 private static final Class[][] _mappings = new Class[][] {
016 { void.class, int.class },
017 { Object.class, int.class },
018 };
019 private int _code = -1;
020
021 NewArrayInstruction(Code owner) {
022 super(owner, Constants.NEWARRAY);
023 }
024
025 int getLength() {
026 return super.getLength() + 1;
027 }
028
029 public String getTypeName() {
030 switch (getTypeCode()) {
031 case Constants.ARRAY_BOOLEAN:
032 return boolean.class.getName();
033 case Constants.ARRAY_CHAR:
034 return char.class.getName();
035 case Constants.ARRAY_FLOAT:
036 return float.class.getName();
037 case Constants.ARRAY_DOUBLE:
038 return double.class.getName();
039 case Constants.ARRAY_BYTE:
040 return byte.class.getName();
041 case Constants.ARRAY_SHORT:
042 return short.class.getName();
043 case Constants.ARRAY_INT:
044 return int.class.getName();
045 case Constants.ARRAY_LONG:
046 return long.class.getName();
047 default:
048 return null;
049 }
050 }
051
052 public TypedInstruction setType(String type) {
053 type = mapType(type, _mappings, true);
054 if (type == null)
055 return setTypeCode(-1);
056
057 switch (type.charAt(0)) {
058 case 'b':
059 if (boolean.class.getName().equals(type))
060 return setTypeCode(Constants.ARRAY_BOOLEAN);
061 return setTypeCode(Constants.ARRAY_BYTE);
062 case 'c':
063 return setTypeCode(Constants.ARRAY_CHAR);
064 case 'f':
065 return setTypeCode(Constants.ARRAY_FLOAT);
066 case 'd':
067 return setTypeCode(Constants.ARRAY_DOUBLE);
068 case 's':
069 return setTypeCode(Constants.ARRAY_SHORT);
070 case 'i':
071 return setTypeCode(Constants.ARRAY_INT);
072 case 'l':
073 return setTypeCode(Constants.ARRAY_LONG);
074 default:
075 throw new IllegalStateException();
076 }
077 }
078
079 /**
080 * Return the array code used in the lowlevel bytecode, or -1 if unset.
081 */
082 public int getTypeCode() {
083 return _code;
084 }
085
086 /**
087 * Set the array code used in the lowlevel bytecode.
088 *
089 * @return this instruction, for method chaining
090 */
091 public NewArrayInstruction setTypeCode(int code) {
092 _code = code;
093 return this;
094 }
095
096 /**
097 * NewArray instructions are equal if the array type is the same,
098 * of if the array type of either is unset.
099 */
100 public boolean equalsInstruction(Instruction other) {
101 if (this == other)
102 return true;
103 if (!(other instanceof NewArrayInstruction))
104 return false;
105
106 NewArrayInstruction ins = (NewArrayInstruction) other;
107 int code = getTypeCode();
108 int otherCode = ins.getTypeCode();
109 return code == -1 || otherCode == -1 || code == otherCode;
110 }
111
112 public void acceptVisit(BCVisitor visit) {
113 visit.enterNewArrayInstruction(this);
114 visit.exitNewArrayInstruction(this);
115 }
116
117 void read(Instruction orig) {
118 super.read(orig);
119 _code = ((NewArrayInstruction) orig).getTypeCode();
120 }
121
122 void read(DataInput in) throws IOException {
123 super.read(in);
124 _code = in.readUnsignedByte();
125 }
126
127 void write(DataOutput out) throws IOException {
128 super.write(out);
129 out.writeByte(_code);
130 }
131 }