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 }