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 }