View Javadoc

1   package serp.bytecode;
2   
3   import serp.bytecode.lowlevel.*;
4   import serp.bytecode.visitor.*;
5   
6   /***
7    * Represents an instruction that manipulates the stack of the current
8    * frame. Using the {@link #setType} methods is a hint about the type being
9    * manipulated that might cause this instruction to use the wide version
10   * of the opcode it represents (if manipulating a long or double). This
11   * saves the developer from having to decide at compile time whether to
12   * use <code>pop</code> or <code>pop2</code>, etc.
13   *
14   * @author Abe White
15   */
16  public class StackInstruction extends TypedInstruction {
17      StackInstruction(Code owner, int opcode) {
18          super(owner, opcode);
19      }
20  
21      public int getStackChange() {
22          switch (getOpcode()) {
23          case Constants.POP:
24              return -1;
25          case Constants.POP2:
26              return -2;
27          case Constants.DUP:
28          case Constants.DUPX1:
29          case Constants.DUPX2:
30              return 1;
31          case Constants.DUP2:
32          case Constants.DUP2X1:
33          case Constants.DUP2X2:
34              return 2;
35          default:
36              return 0;
37          }
38      }
39  
40      /***
41       * This method will always return null; use {@link #isWide} to determine
42       * if this is pop2, dup2, etc.
43       */
44      public String getTypeName() {
45          return null;
46      }
47  
48      public TypedInstruction setType(String type) {
49          type = getProject().getNameCache().getExternalForm(type, false);
50          return setWide(long.class.getName().equals(type) 
51              || double.class.getName().equals(type));
52      }
53  
54      /***
55       * Return whether to use the wide form of the current opcode for
56       * operations on longs or doubles.
57       */
58      public boolean isWide() {
59          switch (getOpcode()) {
60          case Constants.POP2:
61          case Constants.DUP2:
62          case Constants.DUP2X1:
63          case Constants.DUP2X2:
64              return true;
65          default:
66              return false;
67          }
68      }
69  
70      /***
71       * Set whether to use the wide form of the current opcode for operations
72       * on longs or doubles.
73       *
74       * @return this instruction, for method chaining
75       */
76      public StackInstruction setWide(boolean wide) {
77          switch (getOpcode()) {
78          case Constants.POP:
79              if (wide)
80                  setOpcode(Constants.POP2);
81              break;
82          case Constants.POP2:
83              if (!wide)
84                  setOpcode(Constants.POP);
85              break;
86          case Constants.DUP:
87              if (wide)
88                  setOpcode(Constants.DUP2);
89              break;
90          case Constants.DUP2:
91              if (!wide)
92                  setOpcode(Constants.DUP);
93              break;
94          case Constants.DUPX1:
95              if (wide)
96                  setOpcode(Constants.DUP2X1);
97              break;
98          case Constants.DUP2X1:
99              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 }