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
20 import org.apache.bcel.generic.ReferenceType;
21 import org.apache.bcel.generic.Type;
22 import org.apache.bcel.verifier.exc.AssertionViolatedException;
23 import org.apache.bcel.verifier.exc.StructuralCodeConstraintException;
24
25 /***
26 * This class implements an array of local variables used for symbolic JVM
27 * simulation.
28 *
29 * @version $Id: LocalVariables.java 386056 2006-03-15 11:31:56Z tcurdt $
30 * @author Enver Haase
31 */
32 public class LocalVariables{
33 /*** The Type[] containing the local variable slots. */
34 private Type[] locals;
35
36 /***
37 * Creates a new LocalVariables object.
38 */
39 public LocalVariables(int maxLocals){
40 locals = new Type[maxLocals];
41 for (int i=0; i<maxLocals; i++){
42 locals[i] = Type.UNKNOWN;
43 }
44 }
45
46 /***
47 * Returns a deep copy of this object; i.e. the clone
48 * operates on a new local variable array.
49 * However, the Type objects in the array are shared.
50 */
51 protected Object clone(){
52 LocalVariables lvs = new LocalVariables(locals.length);
53 for (int i=0; i<locals.length; i++){
54 lvs.locals[i] = this.locals[i];
55 }
56 return lvs;
57 }
58
59 /***
60 * Returns the type of the local variable slot i.
61 */
62 public Type get(int i){
63 return locals[i];
64 }
65
66 /***
67 * Returns a (correctly typed) clone of this object.
68 * This is equivalent to ((LocalVariables) this.clone()).
69 */
70 public LocalVariables getClone(){
71 return (LocalVariables) this.clone();
72 }
73
74 /***
75 * Returns the number of local variable slots this
76 * LocalVariables instance has.
77 */
78 public int maxLocals(){
79 return locals.length;
80 }
81
82 /***
83 * Sets a new Type for the given local variable slot.
84 */
85 public void set(int i, Type type){
86 if (type == Type.BYTE || type == Type.SHORT || type == Type.BOOLEAN || type == Type.CHAR){
87 throw new AssertionViolatedException("LocalVariables do not know about '"+type+"'. Use Type.INT instead.");
88 }
89 locals[i] = type;
90 }
91
92 /*** @return a hash code value for the object.
93 */
94 public int hashCode() { return locals.length; }
95
96
97
98
99 public boolean equals(Object o){
100 if (!(o instanceof LocalVariables)) {
101 return false;
102 }
103 LocalVariables lv = (LocalVariables) o;
104 if (this.locals.length != lv.locals.length) {
105 return false;
106 }
107 for (int i=0; i<this.locals.length; i++){
108 if (!this.locals[i].equals(lv.locals[i])){
109
110 return false;
111 }
112 }
113 return true;
114 }
115
116 /***
117 * Merges two local variables sets as described in the Java Virtual Machine Specification,
118 * Second Edition, section 4.9.2, page 146.
119 */
120 public void merge(LocalVariables lv){
121
122 if (this.locals.length != lv.locals.length){
123 throw new AssertionViolatedException("Merging LocalVariables of different size?!? From different methods or what?!?");
124 }
125
126 for (int i=0; i<locals.length; i++){
127 merge(lv, i);
128 }
129 }
130
131 /***
132 * Merges a single local variable.
133 *
134 * @see #merge(LocalVariables)
135 */
136 private void merge(LocalVariables lv, int i){
137 try {
138
139
140
141 if ( (!(locals[i] instanceof UninitializedObjectType)) && (lv.locals[i] instanceof UninitializedObjectType) ){
142 throw new StructuralCodeConstraintException("Backwards branch with an uninitialized object in the local variables detected.");
143 }
144
145 if ( (!(locals[i].equals(lv.locals[i]))) && (locals[i] instanceof UninitializedObjectType) && (lv.locals[i] instanceof UninitializedObjectType) ){
146 throw new StructuralCodeConstraintException("Backwards branch with an uninitialized object in the local variables detected.");
147 }
148
149 if (locals[i] instanceof UninitializedObjectType){
150 if (! (lv.locals[i] instanceof UninitializedObjectType)){
151 locals[i] = ((UninitializedObjectType) locals[i]).getInitialized();
152 }
153 }
154 if ((locals[i] instanceof ReferenceType) && (lv.locals[i] instanceof ReferenceType)){
155 if (! locals[i].equals(lv.locals[i])){
156 Type sup = ((ReferenceType) locals[i]).getFirstCommonSuperclass((ReferenceType) (lv.locals[i]));
157
158 if (sup != null){
159 locals[i] = sup;
160 }
161 else{
162
163 throw new AssertionViolatedException("Could not load all the super classes of '"+locals[i]+"' and '"+lv.locals[i]+"'.");
164 }
165 }
166 }
167 else{
168 if (! (locals[i].equals(lv.locals[i])) ){
169
170
171
172
173
174
175 locals[i] = Type.UNKNOWN;
176 }
177 }
178 } catch (ClassNotFoundException e) {
179
180 throw new AssertionViolatedException("Missing class: " + e.toString());
181 }
182 }
183
184 /***
185 * Returns a String representation of this object.
186 */
187 public String toString(){
188 StringBuffer sb = new StringBuffer();
189 for (int i=0; i<locals.length; i++){
190 sb.append(Integer.toString(i));
191 sb.append(": ");
192 sb.append(locals[i]);
193 sb.append("\n");
194 }
195 return sb.toString();
196 }
197
198 /***
199 * Replaces all occurences of u in this local variables set
200 * with an "initialized" ObjectType.
201 */
202 public void initializeObject(UninitializedObjectType u){
203 for (int i=0; i<locals.length; i++){
204 if (locals[i] == u){
205 locals[i] = u.getInitialized();
206 }
207 }
208 }
209 }