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 }