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