001    package serp.bytecode;
002    
003    import java.io.*;
004    
005    import serp.bytecode.lowlevel.*;
006    import serp.bytecode.visitor.*;
007    
008    /**
009     * An instruction that takes as an argument a class to operate
010     * on. Examples include <code>anewarray, checkcast, instance, anew</code>, etc.
011     *
012     * @author Abe White
013     */
014    public class ClassInstruction extends TypedInstruction {
015        private int _index = 0;
016    
017        ClassInstruction(Code owner, int opcode) {
018            super(owner, opcode);
019        }
020    
021        public int getStackChange() {
022            if (getOpcode() == Constants.NEW)
023                return 1;
024            return 0;
025        }
026    
027        int getLength() {
028            return super.getLength() + 2;
029        }
030    
031        /**
032         * Return the {@link ConstantPool} index of the
033         * {@link ClassEntry} describing the class for this instruction.
034         */
035        public int getTypeIndex() {
036            return _index;
037        }
038    
039        /**
040         * Set the {@link ConstantPool} index of the
041         * {@link ClassEntry} describing the class for this instruction.
042         *
043         * @return this instruction, for method chaining
044         */
045        public ClassInstruction setTypeIndex(int index) {
046            _index = index;
047            return this;
048        }
049    
050        public String getTypeName() {
051            if (_index == 0)
052                return null;
053    
054            ClassEntry entry = (ClassEntry) getPool().getEntry(_index);
055            return getProject().getNameCache().getExternalForm(entry.
056                getNameEntry().getValue(), false);
057        }
058    
059        public TypedInstruction setType(String type) {
060            if (type == null)
061                _index = 0;
062            else {
063                type = getProject().getNameCache().getInternalForm(type, false);
064                _index = getPool().findClassEntry(type, true);
065            }
066            return this;
067        }
068    
069        /**
070         * ClassInstructions are equal if the type they reference is the same or
071         * unset and if their opcodes are equal.
072         */
073        public boolean equalsInstruction(Instruction other) {
074            if (other == this)
075                return true;
076            if (!super.equalsInstruction(other))
077                return false;
078    
079            String type = getTypeName();
080            String otherType = ((ClassInstruction) other).getTypeName();
081            return (type == null) || (otherType == null) || type.equals(otherType);
082        }
083    
084        public void acceptVisit(BCVisitor visit) {
085            visit.enterClassInstruction(this);
086            visit.exitClassInstruction(this);
087        }
088    
089        void read(Instruction other) {
090            super.read(other);
091            setType(((ClassInstruction) other).getTypeName());
092        }
093    
094        void read(DataInput in) throws IOException {
095            super.read(in);
096            _index = in.readUnsignedShort();
097        }
098    
099        void write(DataOutput out) throws IOException {
100            super.write(out);
101            out.writeShort(_index);
102        }
103    }