View Javadoc

1   package serp.bytecode;
2   
3   import java.io.*;
4   import java.util.*;
5   
6   import serp.bytecode.visitor.*;
7   
8   /***
9    * Code blocks compiled from source have local tables mapping
10   * locals used in opcodes to their names and descriptions.
11   *
12   * @author Abe White
13   */
14  public abstract class LocalTable extends Attribute implements InstructionPtr {
15      private List _locals = new ArrayList();
16  
17      LocalTable(int nameIndex, Attributes owner) {
18          super(nameIndex, owner);
19      }
20  
21      /***
22       * Return all the locals of this method.
23       */
24      public Local[] getLocals() {
25          return (Local[]) _locals.toArray(newLocalArray(_locals.size()));
26      }
27  
28      /***
29       * Return the local with the given locals index, or null if none.
30       */
31      public Local getLocal(int local) {
32          for (int i = 0; i < _locals.size(); i++)
33              if (((Local) _locals.get(i)).getLocal() == local)
34                  return (Local) _locals.get(i);
35          return null;
36      }
37  
38      /***
39       * Return the local with the given name, or null if none. If multiple
40       * locals have the given name, which is returned is undefined.
41       */
42      public Local getLocal(String name) {
43          String loc;
44          for (int i = 0; i < _locals.size(); i++) {
45              loc = ((Local) _locals.get(i)).getName();
46              if ((loc == null && name == null) 
47                  || (loc != null && loc.equals(name)))
48                  return (Local) _locals.get(i);
49          }
50          return null;
51      }
52  
53      /***
54       * Return all locals with the given name, or empty array if none.
55       */
56      public Local[] getLocals(String name) {
57          List matches = new LinkedList();
58          String loc;
59          for (int i = 0; i < _locals.size(); i++) {
60              loc = ((Local) _locals.get(i)).getName();
61              if ((loc == null && name == null) 
62                  || (loc != null && loc.equals(name)))
63                  matches.add(_locals.get(i));
64          }
65          return (Local[]) matches.toArray(newLocalArray(matches.size()));
66      }
67  
68      /***
69       * Set the locals of this table. This method is useful when
70       * importing locals from another method.
71       */
72      public void setLocals(Local[] locals) {
73          clear();
74          if (locals != null)
75              for (int i = 0; i < locals.length; i++)
76                  addLocal(locals[i]);
77      }
78  
79      /***
80       * Import a local from another method/class. Note that
81       * the program counter and length from the given local is copied
82       * directly, and thus will be incorrect unless this method is the same
83       * as the one the local is copied from, or the pc and length are reset.
84       */
85      public Local addLocal(Local local) {
86          Local newLocal = addLocal(local.getName(), local.getTypeName());
87          newLocal.setStartPc(local.getStartPc());
88          newLocal.setLength(local.getLength());
89          return newLocal;
90      }
91  
92      /***
93       * Add a local to this table.
94       */
95      public Local addLocal() {
96          Local local = newLocal();
97          _locals.add(local);
98          return local;
99      }
100 
101     /***
102      * Create a new element of this table.
103      */
104     protected abstract Local newLocal();
105 
106     /***
107      * Create a new array.
108      */
109     protected abstract Local[] newLocalArray(int size);
110 
111     /***
112      * Add a local to this table.
113      */
114     public Local addLocal(String name, String type) {
115         Local local = addLocal();
116         local.setName(name);
117         local.setType(type);
118         return local;
119     }
120 
121     /***
122      * Clear all locals from this table.
123      */
124     public void clear() {
125         for (int i = 0; i < _locals.size(); i++)
126             ((Local) _locals.get(i)).invalidate();
127         _locals.clear();
128     }
129 
130     /***
131      * Removes the local with the given locals index from the table.
132      *
133      * @return true if a local was removed, false otherwise
134      */
135     public boolean removeLocal(int local) {
136         return removeLocal(getLocal(local));
137     }
138 
139     /***
140      * Removes the local with the given name from this method.
141      *
142      * @return true if a local was removed, false otherwise
143      */
144     public boolean removeLocal(String name) {
145         return removeLocal(getLocal(name));
146     }
147 
148     /***
149      * Removes a local from this method. After this method, the local
150      * will be invalid, and the result of any operations on it is undefined.
151      *
152      * @return true if a local was removed, false otherwise
153      */
154     public boolean removeLocal(Local local) {
155         if (local == null || !_locals.remove(local))
156             return false;
157         local.invalidate();
158         return true;
159     }
160 
161     public void updateTargets() {
162         for (int i = 0; i < _locals.size(); i++)
163             ((Local) _locals.get(i)).updateTargets();
164     }
165 
166     public void replaceTarget(Instruction oldTarget, Instruction newTarget) {
167         for (int i = 0; i < _locals.size(); i++)
168             ((Local) _locals.get(i)).replaceTarget(oldTarget, newTarget);
169     }
170 
171     public Code getCode() {
172         return (Code) getOwner();
173     }
174 
175     int getLength() {
176         return 2 + (10 * _locals.size());
177     }
178 
179     void read(Attribute other) {
180         setLocals(((LocalTable) other).getLocals());
181     }
182 
183     void read(DataInput in, int length) throws IOException {
184         clear();
185         int numLocals = in.readUnsignedShort();
186         Local Local;
187         for (int i = 0; i < numLocals; i++) {
188             Local = addLocal();
189             Local.read(in);
190         }
191     }
192 
193     void write(DataOutput out, int length) throws IOException {
194         out.writeShort(_locals.size());
195         for (int i = 0; i < _locals.size(); i++)
196             ((Local) _locals.get(i)).write(out);
197     }
198 }