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 }