001 package serp.bytecode;
002
003 import java.io.*;
004 import java.util.*;
005
006 import serp.bytecode.visitor.*;
007
008 /**
009 * Code blocks compiled from source have local tables mapping
010 * locals used in opcodes to their names and descriptions.
011 *
012 * @author Abe White
013 */
014 public abstract class LocalTable extends Attribute implements InstructionPtr {
015 private List _locals = new ArrayList();
016
017 LocalTable(int nameIndex, Attributes owner) {
018 super(nameIndex, owner);
019 }
020
021 /**
022 * Return all the locals of this method.
023 */
024 public Local[] getLocals() {
025 return (Local[]) _locals.toArray(newLocalArray(_locals.size()));
026 }
027
028 /**
029 * Return the local with the given locals index, or null if none.
030 */
031 public Local getLocal(int local) {
032 for (int i = 0; i < _locals.size(); i++)
033 if (((Local) _locals.get(i)).getLocal() == local)
034 return (Local) _locals.get(i);
035 return null;
036 }
037
038 /**
039 * Return the local with the given name, or null if none. If multiple
040 * locals have the given name, which is returned is undefined.
041 */
042 public Local getLocal(String name) {
043 String loc;
044 for (int i = 0; i < _locals.size(); i++) {
045 loc = ((Local) _locals.get(i)).getName();
046 if ((loc == null && name == null)
047 || (loc != null && loc.equals(name)))
048 return (Local) _locals.get(i);
049 }
050 return null;
051 }
052
053 /**
054 * Return all locals with the given name, or empty array if none.
055 */
056 public Local[] getLocals(String name) {
057 List matches = new LinkedList();
058 String loc;
059 for (int i = 0; i < _locals.size(); i++) {
060 loc = ((Local) _locals.get(i)).getName();
061 if ((loc == null && name == null)
062 || (loc != null && loc.equals(name)))
063 matches.add(_locals.get(i));
064 }
065 return (Local[]) matches.toArray(newLocalArray(matches.size()));
066 }
067
068 /**
069 * Set the locals of this table. This method is useful when
070 * importing locals from another method.
071 */
072 public void setLocals(Local[] locals) {
073 clear();
074 if (locals != null)
075 for (int i = 0; i < locals.length; i++)
076 addLocal(locals[i]);
077 }
078
079 /**
080 * Import a local from another method/class. Note that
081 * the program counter and length from the given local is copied
082 * directly, and thus will be incorrect unless this method is the same
083 * as the one the local is copied from, or the pc and length are reset.
084 */
085 public Local addLocal(Local local) {
086 Local newLocal = addLocal(local.getName(), local.getTypeName());
087 newLocal.setStartPc(local.getStartPc());
088 newLocal.setLength(local.getLength());
089 return newLocal;
090 }
091
092 /**
093 * Add a local to this table.
094 */
095 public Local addLocal() {
096 Local local = newLocal();
097 _locals.add(local);
098 return local;
099 }
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 }