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    }