serp.bytecode.LocalTable Maven / Gradle / Ivy
package serp.bytecode;
import java.io.*;
import java.util.*;
import serp.bytecode.visitor.*;
/**
* Code blocks compiled from source have local tables mapping
* locals used in opcodes to their names and descriptions.
*
* @author Abe White
*/
public abstract class LocalTable extends Attribute implements InstructionPtr {
private List _locals = new ArrayList();
LocalTable(int nameIndex, Attributes owner) {
super(nameIndex, owner);
}
/**
* Return all the locals of this method.
*/
public Local[] getLocals() {
return (Local[]) _locals.toArray(newLocalArray(_locals.size()));
}
/**
* Return the local with the given locals index, or null if none.
*/
public Local getLocal(int local) {
for (int i = 0; i < _locals.size(); i++)
if (((Local) _locals.get(i)).getLocal() == local)
return (Local) _locals.get(i);
return null;
}
/**
* Return the local with the given name, or null if none. If multiple
* locals have the given name, which is returned is undefined.
*/
public Local getLocal(String name) {
String loc;
for (int i = 0; i < _locals.size(); i++) {
loc = ((Local) _locals.get(i)).getName();
if ((loc == null && name == null)
|| (loc != null && loc.equals(name)))
return (Local) _locals.get(i);
}
return null;
}
/**
* Return all locals with the given name, or empty array if none.
*/
public Local[] getLocals(String name) {
List matches = new LinkedList();
String loc;
for (int i = 0; i < _locals.size(); i++) {
loc = ((Local) _locals.get(i)).getName();
if ((loc == null && name == null)
|| (loc != null && loc.equals(name)))
matches.add(_locals.get(i));
}
return (Local[]) matches.toArray(newLocalArray(matches.size()));
}
/**
* Set the locals of this table. This method is useful when
* importing locals from another method.
*/
public void setLocals(Local[] locals) {
clear();
if (locals != null)
for (int i = 0; i < locals.length; i++)
addLocal(locals[i]);
}
/**
* Import a local from another method/class. Note that
* the program counter and length from the given local is copied
* directly, and thus will be incorrect unless this method is the same
* as the one the local is copied from, or the pc and length are reset.
*/
public Local addLocal(Local local) {
Local newLocal = addLocal(local.getName(), local.getTypeName());
newLocal.setStartPc(local.getStartPc());
newLocal.setLength(local.getLength());
return newLocal;
}
/**
* Add a local to this table.
*/
public Local addLocal() {
Local local = newLocal();
_locals.add(local);
return local;
}
/**
* Create a new element of this table.
*/
protected abstract Local newLocal();
/**
* Create a new array.
*/
protected abstract Local[] newLocalArray(int size);
/**
* Add a local to this table.
*/
public Local addLocal(String name, String type) {
Local local = addLocal();
local.setName(name);
local.setType(type);
return local;
}
/**
* Clear all locals from this table.
*/
public void clear() {
for (int i = 0; i < _locals.size(); i++)
((Local) _locals.get(i)).invalidate();
_locals.clear();
}
/**
* Removes the local with the given locals index from the table.
*
* @return true if a local was removed, false otherwise
*/
public boolean removeLocal(int local) {
return removeLocal(getLocal(local));
}
/**
* Removes the local with the given name from this method.
*
* @return true if a local was removed, false otherwise
*/
public boolean removeLocal(String name) {
return removeLocal(getLocal(name));
}
/**
* Removes a local from this method. After this method, the local
* will be invalid, and the result of any operations on it is undefined.
*
* @return true if a local was removed, false otherwise
*/
public boolean removeLocal(Local local) {
if (local == null || !_locals.remove(local))
return false;
local.invalidate();
return true;
}
public void updateTargets() {
for (int i = 0; i < _locals.size(); i++)
((Local) _locals.get(i)).updateTargets();
}
public void replaceTarget(Instruction oldTarget, Instruction newTarget) {
for (int i = 0; i < _locals.size(); i++)
((Local) _locals.get(i)).replaceTarget(oldTarget, newTarget);
}
public Code getCode() {
return (Code) getOwner();
}
int getLength() {
return 2 + (10 * _locals.size());
}
void read(Attribute other) {
setLocals(((LocalTable) other).getLocals());
}
void read(DataInput in, int length) throws IOException {
clear();
int numLocals = in.readUnsignedShort();
Local Local;
for (int i = 0; i < numLocals; i++) {
Local = addLocal();
Local.read(in);
}
}
void write(DataOutput out, int length) throws IOException {
out.writeShort(_locals.size());
for (int i = 0; i < _locals.size(); i++)
((Local) _locals.get(i)).write(out);
}
}