001package serp.bytecode;
002
003import java.io.*;
004import java.util.*;
005
006import 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 */
014public 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}