001    package serp.bytecode;
002    
003    import serp.bytecode.lowlevel.*;
004    import serp.bytecode.visitor.*;
005    
006    /**
007     * Represents an instruction that manipulates the stack of the current
008     * frame. Using the {@link #setType} methods is a hint about the type being
009     * manipulated that might cause this instruction to use the wide version
010     * of the opcode it represents (if manipulating a long or double). This
011     * saves the developer from having to decide at compile time whether to
012     * use <code>pop</code> or <code>pop2</code>, etc.
013     *
014     * @author Abe White
015     */
016    public class StackInstruction extends TypedInstruction {
017        StackInstruction(Code owner, int opcode) {
018            super(owner, opcode);
019        }
020    
021        public int getStackChange() {
022            switch (getOpcode()) {
023            case Constants.POP:
024                return -1;
025            case Constants.POP2:
026                return -2;
027            case Constants.DUP:
028            case Constants.DUPX1:
029            case Constants.DUPX2:
030                return 1;
031            case Constants.DUP2:
032            case Constants.DUP2X1:
033            case Constants.DUP2X2:
034                return 2;
035            default:
036                return 0;
037            }
038        }
039    
040        /**
041         * This method will always return null; use {@link #isWide} to determine
042         * if this is pop2, dup2, etc.
043         */
044        public String getTypeName() {
045            return null;
046        }
047    
048        public TypedInstruction setType(String type) {
049            type = getProject().getNameCache().getExternalForm(type, false);
050            return setWide(long.class.getName().equals(type) 
051                || double.class.getName().equals(type));
052        }
053    
054        /**
055         * Return whether to use the wide form of the current opcode for
056         * operations on longs or doubles.
057         */
058        public boolean isWide() {
059            switch (getOpcode()) {
060            case Constants.POP2:
061            case Constants.DUP2:
062            case Constants.DUP2X1:
063            case Constants.DUP2X2:
064                return true;
065            default:
066                return false;
067            }
068        }
069    
070        /**
071         * Set whether to use the wide form of the current opcode for operations
072         * on longs or doubles.
073         *
074         * @return this instruction, for method chaining
075         */
076        public StackInstruction setWide(boolean wide) {
077            switch (getOpcode()) {
078            case Constants.POP:
079                if (wide)
080                    setOpcode(Constants.POP2);
081                break;
082            case Constants.POP2:
083                if (!wide)
084                    setOpcode(Constants.POP);
085                break;
086            case Constants.DUP:
087                if (wide)
088                    setOpcode(Constants.DUP2);
089                break;
090            case Constants.DUP2:
091                if (!wide)
092                    setOpcode(Constants.DUP);
093                break;
094            case Constants.DUPX1:
095                if (wide)
096                    setOpcode(Constants.DUP2X1);
097                break;
098            case Constants.DUP2X1:
099                if (!wide)
100                    setOpcode(Constants.DUPX1);
101                break;
102            case Constants.DUPX2:
103                if (wide)
104                    setOpcode(Constants.DUP2X2);
105                break;
106            case Constants.DUP2X2:
107                if (!wide)
108                    setOpcode(Constants.DUPX2);
109                break;
110            }
111            return this;
112        }
113    
114        public void acceptVisit(BCVisitor visit) {
115            visit.enterStackInstruction(this);
116            visit.exitStackInstruction(this);
117        }
118    }