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 }