1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.bcel.verifier.structurals;
20
21 import java.util.ArrayList;
22
23 import org.apache.bcel.generic.ObjectType;
24 import org.apache.bcel.generic.ReferenceType;
25 import org.apache.bcel.generic.Type;
26 import org.apache.bcel.verifier.exc.AssertionViolatedException;
27 import org.apache.bcel.verifier.exc.StructuralCodeConstraintException;
28
29
30
31
32
33 public class OperandStack implements Cloneable {
34
35
36 private ArrayList<Type> stack = new ArrayList<>();
37
38
39 private final int maxStack;
40
41
42
43
44 public OperandStack(final int maxStack) {
45 this.maxStack = maxStack;
46 }
47
48
49
50
51 public OperandStack(final int maxStack, final ObjectType obj) {
52 this.maxStack = maxStack;
53 push(obj);
54 }
55
56
57
58
59 public void clear() {
60 stack = new ArrayList<>();
61 }
62
63
64
65
66
67 @Override
68 public Object clone() {
69 final OperandStack newstack = new OperandStack(this.maxStack);
70 @SuppressWarnings("unchecked")
71 final ArrayList<Type> clone = (ArrayList<Type>) this.stack.clone();
72 newstack.stack = clone;
73 return newstack;
74 }
75
76
77
78
79 @Override
80 public boolean equals(final Object o) {
81 if (!(o instanceof OperandStack)) {
82 return false;
83 }
84 final OperandStack s = (OperandStack) o;
85 return this.stack.equals(s.stack);
86 }
87
88
89
90
91
92
93 public OperandStack getClone() {
94 return (OperandStack) clone();
95 }
96
97
98
99
100 @Override
101 public int hashCode() {
102 return stack.hashCode();
103 }
104
105
106
107
108 public void initializeObject(final UninitializedObjectType u) {
109 for (int i = 0; i < stack.size(); i++) {
110 if (stack.get(i) == u) {
111 stack.set(i, u.getInitialized());
112 }
113 }
114 }
115
116
117
118
119 public boolean isEmpty() {
120 return stack.isEmpty();
121 }
122
123
124
125
126 public int maxStack() {
127 return this.maxStack;
128 }
129
130
131
132
133
134 public void merge(final OperandStack s) {
135 try {
136 if (slotsUsed() != s.slotsUsed() || size() != s.size()) {
137 throw new StructuralCodeConstraintException("Cannot merge stacks of different size:\nOperandStack A:\n" + this + "\nOperandStack B:\n" + s);
138 }
139
140 for (int i = 0; i < size(); i++) {
141
142
143 if (!(stack.get(i) instanceof UninitializedObjectType) && s.stack.get(i) instanceof UninitializedObjectType) {
144 throw new StructuralCodeConstraintException("Backwards branch with an uninitialized object on the stack detected.");
145 }
146
147
148 if (!stack.get(i).equals(s.stack.get(i)) && stack.get(i) instanceof UninitializedObjectType
149 && !(s.stack.get(i) instanceof UninitializedObjectType)) {
150 throw new StructuralCodeConstraintException("Backwards branch with an uninitialized object on the stack detected.");
151 }
152
153 if (stack.get(i) instanceof UninitializedObjectType && !(s.stack.get(i) instanceof UninitializedObjectType)) {
154
155 stack.set(i, ((UninitializedObjectType) stack.get(i)).getInitialized());
156 }
157 if (!stack.get(i).equals(s.stack.get(i))) {
158 if (!(stack.get(i) instanceof ReferenceType) || !(s.stack.get(i) instanceof ReferenceType)) {
159 throw new StructuralCodeConstraintException("Cannot merge stacks of different types:\nStack A:\n" + this + "\nStack B:\n" + s);
160 }
161 stack.set(i, ((ReferenceType) stack.get(i)).getFirstCommonSuperclass((ReferenceType) s.stack.get(i)));
162 }
163 }
164 } catch (final ClassNotFoundException e) {
165
166 throw new AssertionViolatedException("Missing class: " + e, e);
167 }
168 }
169
170
171
172
173 public Type peek() {
174 return peek(0);
175 }
176
177
178
179
180
181 public Type peek(final int i) {
182 return stack.get(size() - i - 1);
183 }
184
185
186
187
188 public Type pop() {
189 return stack.remove(size() - 1);
190 }
191
192
193
194
195
196
197 public Type pop(final int count) {
198 for (int j = 0; j < count; j++) {
199 pop();
200 }
201 return null;
202 }
203
204
205
206
207 public void push(final Type type) {
208 if (type == null) {
209 throw new AssertionViolatedException("Cannot push NULL onto OperandStack.");
210 }
211 if (type == Type.BOOLEAN || type == Type.CHAR || type == Type.BYTE || type == Type.SHORT) {
212 throw new AssertionViolatedException("The OperandStack does not know about '" + type + "'; use Type.INT instead.");
213 }
214 if (slotsUsed() >= maxStack) {
215 throw new AssertionViolatedException("OperandStack too small, should have thrown proper Exception elsewhere. Stack: " + this);
216 }
217 stack.add(type);
218 }
219
220
221
222
223 public int size() {
224 return stack.size();
225 }
226
227
228
229
230
231
232 public int slotsUsed() {
233
234
235
236
237 int slots = 0;
238 for (int i = 0; i < stack.size(); i++) {
239 slots += peek(i).getSize();
240 }
241 return slots;
242 }
243
244
245
246
247 @Override
248 public String toString() {
249 final StringBuilder sb = new StringBuilder();
250 sb.append("Slots used: ");
251 sb.append(slotsUsed());
252 sb.append(" MaxStack: ");
253 sb.append(maxStack);
254 sb.append(".\n");
255 for (int i = 0; i < size(); i++) {
256 sb.append(peek(i));
257 sb.append(" (Size: ");
258 sb.append(String.valueOf(peek(i).getSize()));
259 sb.append(")\n");
260 }
261 return sb.toString();
262 }
263
264 }