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 }