View Javadoc

1   package serp.bytecode;
2   
3   import java.io.*;
4   import java.util.*;
5   
6   import serp.bytecode.lowlevel.*;
7   import serp.bytecode.visitor.*;
8   import serp.util.*;
9   
10  /***
11   * A local variable or local variable type.
12   *
13   * @author Abe White
14   * @author Sakir Murat Cengiz
15   */
16  public abstract class Local implements BCEntity, InstructionPtr {
17      private LocalTable _owner = null;
18      private InstructionPtrStrategy _target = new InstructionPtrStrategy(this);
19      private Instruction _end = null;
20      private int _length = 0;
21      private int _nameIndex = 0;
22      private int _descriptorIndex = 0;
23      private int _index = 0;
24  
25      Local(LocalTable owner) {
26          _owner = owner;
27      }
28  
29      /***
30       * The owning table.
31       */
32      public LocalTable getTable() {
33          return _owner;
34      }
35  
36      void invalidate() {
37          _owner = null;
38      }
39  
40      //////////////////////////
41      // Local index operations
42      //////////////////////////
43  
44      /***
45       * Get the local variable index of the current frame for this local.
46       */
47      public int getLocal() {
48          return _index;
49      }
50  
51      /***
52       * Set the local variable index of the current frame for this local.
53       */
54      public void setLocal(int index) {
55          _index = index;
56      }
57  
58      /***
59       * Return the parameter that this local corresponds to, or -1 if none.
60       */
61      public int getParam() {
62          return getCode().getParamsIndex(getLocal());
63      }
64  
65      /***
66       * Set the method parameter that this local corresponds to.
67       */
68      public void setParam(int param) {
69          setLocal(_owner.getCode().getLocalsIndex(param));
70      }
71  
72      ////////////////////////////
73      // Start, Length operations
74      ////////////////////////////
75  
76      /***
77       * Return the index into the code byte array at which this local starts.
78       */
79      public int getStartPc() {
80          return _target.getByteIndex();
81      }
82  
83      /***
84       * Return the instruction marking the beginning of this local.
85       */
86      public Instruction getStart() {
87          return _target.getTargetInstruction();
88      }
89  
90      /***
91       * Set the index into the code byte array at which this local starts.
92       */
93      public void setStartPc(int startPc) {
94          _target.setByteIndex(startPc);
95      }
96  
97      /***
98       * Set the {@link Instruction} marking the beginning this local.
99       * The instruction must already be a part of the method.
100      * WARNING: if this instruction is deleted, the results are undefined.
101      */
102     public void setStart(Instruction instruction) {
103         _target.setTargetInstruction(instruction);
104     }
105 
106     /***
107      * The last {@link Instruction} for which this local is in scope.
108      */
109     public Instruction getEnd() {
110         if (_end != null)
111             return _end;
112         int idx = _target.getByteIndex() + _length;
113         Instruction end = getCode().getInstruction(idx);
114         return (end != null) ? (Instruction) end.prev 
115             : getCode().getLastInstruction();
116     }
117 
118     /***
119      * Get the number of bytes for which this local has a value in
120      * the code byte array.
121      */
122     public int getLength() {
123         if (_end != null)
124             return _end.getByteIndex() + _end.getLength() 
125                 - _target.getByteIndex();
126         return _length;
127     }
128 
129     /***
130      * Set the last {@link Instruction} for which this local is in scope.
131      * The instruction must already be a part of the method.
132      * WARNING: if this instruction is deleted, the results are undefined.
133      */
134     public void setEnd(Instruction end) {
135         if (end.getCode() != getCode())
136             throw new IllegalArgumentException("Instruction pointers and " 
137                 + "targets must be part of the same code block.");
138         _end = end;
139         _length = -1;
140     }
141 
142     /***
143      * Set the number of bytes for which this local has a value in
144      * the code byte array.
145      */
146     public void setLength(int length) {
147         if (length < 0)
148             throw new IllegalArgumentException(String.valueOf(length));
149         _length = length;
150         _end = null;
151     }
152 
153     public void updateTargets() {
154         _target.updateTargets();
155         _end = getEnd();
156     }
157 
158     public void replaceTarget(Instruction oldTarget, Instruction newTarget) {
159         _target.replaceTarget(oldTarget, newTarget);
160         if (getEnd() == oldTarget)
161             setEnd(newTarget);
162     }
163 
164     /////////////////////////
165     // Name, Type operations
166     /////////////////////////
167 
168     /***
169      * Return the {@link ConstantPool} index of the {@link UTF8Entry} that
170      * describes the name of this local. Defaults to 0.
171      */
172     public int getNameIndex() {
173         return _nameIndex;
174     }
175 
176     /***
177      * Set the {@link ConstantPool} index of the {@link UTF8Entry} that
178      * describes the name of this local.
179      */
180     public void setNameIndex(int nameIndex) {
181         _nameIndex = nameIndex;
182     }
183 
184     /***
185      * Return the name of this local, or null if unset.
186      */
187     public String getName() {
188         if (getNameIndex() == 0)
189             return null;
190         return ((UTF8Entry) getPool().getEntry(getNameIndex())).getValue();
191     }
192 
193     /***
194      * Set the name of this inner local.
195      */
196     public void setName(String name) {
197         if (name == null)
198             setNameIndex(0);
199         else
200             setNameIndex(getPool().findUTF8Entry(name, true));
201     }
202 
203     /***
204      * Return the {@link ConstantPool} index of the {@link UTF8Entry} that
205      * describes this local. Defaults to 0.
206      */
207     public int getTypeIndex() {
208         return _descriptorIndex;
209     }
210 
211     /***
212      * Set the {@link ConstantPool} index of the {@link UTF8Entry} that
213      * describes this local.
214      */
215     public void setTypeIndex(int index) {
216         _descriptorIndex = index;
217     }
218 
219     /***
220      * Return the full name of the local's type, or null if unset.
221      */
222     public String getTypeName() {
223         if (getTypeIndex() == 0)
224             return null;
225         UTF8Entry entry = (UTF8Entry) getPool().getEntry(getTypeIndex());
226         return getProject().getNameCache().getExternalForm(entry.getValue(), 
227             false);
228     }
229 
230     /***
231      * Set the type of this local.
232      */
233     public void setType(String type) {
234         if (type == null)
235             setTypeIndex(0);
236         else {
237             type = getProject().getNameCache().getInternalForm(type, true);
238             setTypeIndex(getPool().findUTF8Entry(type, true));
239         }
240     }
241 
242     ///////////////////////////
243     // BCEntity implementation
244     ///////////////////////////
245 
246     public Project getProject() {
247         return _owner.getProject();
248     }
249 
250     public ConstantPool getPool() {
251         return _owner.getPool();
252     }
253 
254     public ClassLoader getClassLoader() {
255         return _owner.getClassLoader();
256     }
257 
258     public boolean isValid() {
259         return _owner != null;
260     }
261 
262     //////////////////
263     // I/O operations
264     //////////////////
265 
266     void read(DataInput in) throws IOException {
267         setStartPc(in.readUnsignedShort());
268         setLength(in.readUnsignedShort());
269         setNameIndex(in.readUnsignedShort());
270         setTypeIndex(in.readUnsignedShort());
271         setLocal(in.readUnsignedShort());
272     }
273 
274     void write(DataOutput out) throws IOException {
275         out.writeShort(getStartPc());
276         out.writeShort(getLength());
277         out.writeShort(getNameIndex());
278         out.writeShort(getTypeIndex());
279         out.writeShort(getLocal());
280     }
281 
282     public Code getCode() {
283         return _owner.getCode();
284     }
285 }