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