23 import com.sun.org.apache.bcel.internal.Const; |
23 import com.sun.org.apache.bcel.internal.Const; |
24 import com.sun.org.apache.bcel.internal.classfile.LocalVariable; |
24 import com.sun.org.apache.bcel.internal.classfile.LocalVariable; |
25 |
25 |
26 /** |
26 /** |
27 * This class represents a local variable within a method. It contains its |
27 * This class represents a local variable within a method. It contains its |
28 * scope, name and type. The generated LocalVariable object can be obtained with |
28 * scope, name and type. The generated LocalVariable object can be obtained |
29 * getLocalVariable which needs the instruction list and the constant pool as |
29 * with getLocalVariable which needs the instruction list and the constant |
30 * parameters. |
30 * pool as parameters. |
31 * |
31 * |
32 * @version $Id: LocalVariableGen.java 1749603 2016-06-21 20:50:19Z ggregory $ |
32 * @version $Id$ |
33 * @see LocalVariable |
33 * @see LocalVariable |
34 * @see MethodGen |
34 * @see MethodGen |
35 */ |
35 */ |
36 public class LocalVariableGen implements InstructionTargeter, NamedAndTyped, Cloneable { |
36 public class LocalVariableGen implements InstructionTargeter, NamedAndTyped, Cloneable { |
37 |
37 |
38 private int index; |
38 private int index; |
39 private String name; |
39 private String name; |
40 private Type type; |
40 private Type type; |
41 private InstructionHandle start; |
41 private InstructionHandle start; |
42 private InstructionHandle end; |
42 private InstructionHandle end; |
43 |
43 private int orig_index; // never changes; used to match up with LocalVariableTypeTable entries |
44 /** |
44 private boolean live_to_end; |
45 * Generate a local variable that with index `index'. Note that double and |
45 |
46 * long variables need two indexs. Index indices have to be provided by the |
46 |
47 * user. |
47 /** |
|
48 * Generate a local variable that with index `index'. Note that double and long |
|
49 * variables need two indexs. Index indices have to be provided by the user. |
48 * |
50 * |
49 * @param index index of local variable |
51 * @param index index of local variable |
50 * @param name its name |
52 * @param name its name |
51 * @param type its type |
53 * @param type its type |
52 * @param start from where the instruction is valid (null means from the |
54 * @param start from where the instruction is valid (null means from the start) |
53 * start) |
|
54 * @param end until where the instruction is valid (null means to the end) |
55 * @param end until where the instruction is valid (null means to the end) |
55 */ |
56 */ |
56 public LocalVariableGen(final int index, final String name, final Type type, |
57 public LocalVariableGen(final int index, final String name, final Type type, final InstructionHandle start, |
57 final InstructionHandle start, final InstructionHandle end) { |
58 final InstructionHandle end) { |
58 if ((index < 0) || (index > Const.MAX_SHORT)) { |
59 if ((index < 0) || (index > Const.MAX_SHORT)) { |
59 throw new ClassGenException("Invalid index index: " + index); |
60 throw new ClassGenException("Invalid index index: " + index); |
60 } |
61 } |
61 this.name = name; |
62 this.name = name; |
62 this.type = type; |
63 this.type = type; |
63 this.index = index; |
64 this.index = index; |
64 setStart(start); |
65 setStart(start); |
65 setEnd(end); |
66 setEnd(end); |
66 } |
67 this.orig_index = index; |
|
68 this.live_to_end = end == null; |
|
69 } |
|
70 |
|
71 |
|
72 /** |
|
73 * Generate a local variable that with index `index'. Note that double and long |
|
74 * variables need two indexs. Index indices have to be provided by the user. |
|
75 * |
|
76 * @param index index of local variable |
|
77 * @param name its name |
|
78 * @param type its type |
|
79 * @param start from where the instruction is valid (null means from the start) |
|
80 * @param end until where the instruction is valid (null means to the end) |
|
81 * @param orig_index index of local variable prior to any changes to index |
|
82 */ |
|
83 public LocalVariableGen(final int index, final String name, final Type type, final InstructionHandle start, |
|
84 final InstructionHandle end, final int orig_index) { |
|
85 this(index, name, type, start, end); |
|
86 this.orig_index = orig_index; |
|
87 } |
|
88 |
67 |
89 |
68 /** |
90 /** |
69 * Get LocalVariable object. |
91 * Get LocalVariable object. |
70 * |
92 * |
71 * This relies on that the instruction list has already been dumped to byte |
93 * This relies on that the instruction list has already been dumped to byte code or |
72 * code or or that the `setPositions' methods has been called for the |
94 * or that the `setPositions' methods has been called for the instruction list. |
73 * instruction list. |
95 * |
74 * |
96 * Note that due to the conversion from byte code offset to InstructionHandle, |
75 * Note that for local variables whose scope end at the last instruction of |
97 * it is impossible to tell the difference between a live range that ends BEFORE |
76 * the method's code, the JVM specification is ambiguous: both a |
98 * the last insturction of the method or a live range that ends AFTER the last |
77 * start_pc+length ending at the last instruction and start_pc+length ending |
99 * instruction of the method. Hence the live_to_end flag to differentiate |
78 * at first index beyond the end of the code are valid. |
100 * between these two cases. |
79 * |
101 * |
80 * @param cp constant pool |
102 * @param cp constant pool |
81 */ |
103 */ |
82 public LocalVariable getLocalVariable(final ConstantPoolGen cp) { |
104 public LocalVariable getLocalVariable( final ConstantPoolGen cp ) { |
83 int start_pc = 0; |
105 int start_pc = 0; |
84 int length = 0; |
106 int length = 0; |
85 if ((start != null) && (end != null)) { |
107 if ((start != null) && (end != null)) { |
86 start_pc = start.getPosition(); |
108 start_pc = start.getPosition(); |
87 length = end.getPosition() - start_pc; |
109 length = end.getPosition() - start_pc; |
88 if (end.getNext() == null) { |
110 if ((end.getNext() == null) && live_to_end) { |
89 length += end.getInstruction().getLength(); |
111 length += end.getInstruction().getLength(); |
90 } |
112 } |
91 } |
113 } |
92 final int name_index = cp.addUtf8(name); |
114 final int name_index = cp.addUtf8(name); |
93 final int signature_index = cp.addUtf8(type.getSignature()); |
115 final int signature_index = cp.addUtf8(type.getSignature()); |
94 return new LocalVariable(start_pc, length, name_index, signature_index, index, cp |
116 return new LocalVariable(start_pc, length, name_index, signature_index, index, cp |
95 .getConstantPool()); |
117 .getConstantPool(), orig_index); |
96 } |
118 } |
97 |
119 |
98 public void setIndex(final int index) { |
120 |
|
121 public void setIndex( final int index ) { |
99 this.index = index; |
122 this.index = index; |
100 } |
123 } |
|
124 |
101 |
125 |
102 public int getIndex() { |
126 public int getIndex() { |
103 return index; |
127 return index; |
104 } |
128 } |
105 |
129 |
106 @Override |
130 |
107 public void setName(final String name) { |
131 public int getOrigIndex() { |
|
132 return orig_index; |
|
133 } |
|
134 |
|
135 |
|
136 public void setLiveToEnd( final boolean live_to_end) { |
|
137 this.live_to_end = live_to_end; |
|
138 } |
|
139 |
|
140 |
|
141 public boolean getLiveToEnd() { |
|
142 return live_to_end; |
|
143 } |
|
144 |
|
145 |
|
146 @Override |
|
147 public void setName( final String name ) { |
108 this.name = name; |
148 this.name = name; |
109 } |
149 } |
|
150 |
110 |
151 |
111 @Override |
152 @Override |
112 public String getName() { |
153 public String getName() { |
113 return name; |
154 return name; |
114 } |
155 } |
115 |
156 |
116 @Override |
157 |
117 public void setType(final Type type) { |
158 @Override |
|
159 public void setType( final Type type ) { |
118 this.type = type; |
160 this.type = type; |
119 } |
161 } |
|
162 |
120 |
163 |
121 @Override |
164 @Override |
122 public Type getType() { |
165 public Type getType() { |
123 return type; |
166 return type; |
124 } |
167 } |
125 |
168 |
|
169 |
126 public InstructionHandle getStart() { |
170 public InstructionHandle getStart() { |
127 return start; |
171 return start; |
128 } |
172 } |
129 |
173 |
|
174 |
130 public InstructionHandle getEnd() { |
175 public InstructionHandle getEnd() { |
131 return end; |
176 return end; |
132 } |
177 } |
133 |
178 |
134 public void setStart(final InstructionHandle start) { // TODO could be package-protected? |
179 |
|
180 public void setStart( final InstructionHandle start ) { // TODO could be package-protected? |
135 BranchInstruction.notifyTarget(this.start, start, this); |
181 BranchInstruction.notifyTarget(this.start, start, this); |
136 this.start = start; |
182 this.start = start; |
137 } |
183 } |
138 |
184 |
139 public void setEnd(final InstructionHandle end) { // TODO could be package-protected? |
185 |
|
186 public void setEnd( final InstructionHandle end ) { // TODO could be package-protected? |
140 BranchInstruction.notifyTarget(this.end, end, this); |
187 BranchInstruction.notifyTarget(this.end, end, this); |
141 this.end = end; |
188 this.end = end; |
142 } |
189 } |
143 |
190 |
|
191 |
144 /** |
192 /** |
145 * @param old_ih old target, either start or end |
193 * @param old_ih old target, either start or end |
146 * @param new_ih new target |
194 * @param new_ih new target |
147 */ |
195 */ |
148 @Override |
196 @Override |
149 public void updateTarget(final InstructionHandle old_ih, final InstructionHandle new_ih) { |
197 public void updateTarget( final InstructionHandle old_ih, final InstructionHandle new_ih ) { |
150 boolean targeted = false; |
198 boolean targeted = false; |
151 if (start == old_ih) { |
199 if (start == old_ih) { |
152 targeted = true; |
200 targeted = true; |
153 setStart(new_ih); |
201 setStart(new_ih); |
154 } |
202 } |
172 |
220 |
173 /** |
221 /** |
174 * @return true, if ih is target of this variable |
222 * @return true, if ih is target of this variable |
175 */ |
223 */ |
176 @Override |
224 @Override |
177 public boolean containsTarget(final InstructionHandle ih) { |
225 public boolean containsTarget( final InstructionHandle ih ) { |
178 return (start == ih) || (end == ih); |
226 return (start == ih) || (end == ih); |
179 } |
227 } |
|
228 |
180 |
229 |
181 @Override |
230 @Override |
182 public int hashCode() { |
231 public int hashCode() { |
183 // If the user changes the name or type, problems with the targeter hashmap will occur. |
232 // If the user changes the name or type, problems with the targeter hashmap will occur. |
184 // Note: index cannot be part of hash as it may be changed by the user. |
233 // Note: index cannot be part of hash as it may be changed by the user. |
185 return name.hashCode() ^ type.hashCode(); |
234 return name.hashCode() ^ type.hashCode(); |
186 } |
235 } |
187 |
236 |
|
237 |
188 /** |
238 /** |
189 * We consider to local variables to be equal, if the use the same index and |
239 * We consider to local variables to be equal, if the use the same index and |
190 * are valid in the same range. |
240 * are valid in the same range. |
191 */ |
241 */ |
192 @Override |
242 @Override |
193 public boolean equals(final Object o) { |
243 public boolean equals( final Object o ) { |
194 if (!(o instanceof LocalVariableGen)) { |
244 if (!(o instanceof LocalVariableGen)) { |
195 return false; |
245 return false; |
196 } |
246 } |
197 final LocalVariableGen l = (LocalVariableGen) o; |
247 final LocalVariableGen l = (LocalVariableGen) o; |
198 return (l.index == index) && (l.start == start) && (l.end == end); |
248 return (l.index == index) && (l.start == start) && (l.end == end); |
199 } |
249 } |
200 |
250 |
|
251 |
201 @Override |
252 @Override |
202 public String toString() { |
253 public String toString() { |
203 return "LocalVariableGen(" + name + ", " + type + ", " + start + ", " + end + ")"; |
254 return "LocalVariableGen(" + name + ", " + type + ", " + start + ", " + end + ")"; |
204 } |
255 } |
|
256 |
205 |
257 |
206 @Override |
258 @Override |
207 public Object clone() { |
259 public Object clone() { |
208 try { |
260 try { |
209 return super.clone(); |
261 return super.clone(); |