8064516: BCEL still corrupts generic methods if bytecode offsets are modified

Added comprehensive support for LocalVariableTypeTable to MethodGen.

Reviewed-by: joehw
This commit is contained in:
David Buck 2014-11-10 16:09:38 -08:00
parent 23a78f8c2f
commit a02a2a54b6
2 changed files with 105 additions and 15 deletions

View File

@ -213,6 +213,10 @@ public class DescendingVisitor implements Visitor {
public void visitLocalVariableTypeTable(LocalVariableTypeTable obj) {
stack.push(obj);
obj.accept(visitor);
LocalVariable[] vars = obj.getLocalVariableTypeTable();
for(int i=0; i < vars.length; i++)
vars[i].accept(this);
stack.pop();
}

View File

@ -87,6 +87,7 @@ public class MethodGen extends FieldGenOrMethodGen {
private boolean strip_attributes;
private ArrayList variable_vec = new ArrayList();
private ArrayList type_vec = new ArrayList();
private ArrayList line_number_vec = new ArrayList();
private ArrayList exception_vec = new ArrayList();
private ArrayList throws_vec = new ArrayList();
@ -259,11 +260,10 @@ public class MethodGen extends FieldGenOrMethodGen {
l.getIndex(), start, end);
}
} else if (a instanceof LocalVariableTypeTable) {
LocalVariable[] oldLV = ((LocalVariableTypeTable) a).getLocalVariableTypeTable();
int lvLength = oldLV.length;
LocalVariable[] newLV = new LocalVariable[lvLength];
for (int k = 0; k < lvLength; k++) {
LocalVariable l = oldLV[k];
LocalVariable[] lv = ((LocalVariableTypeTable) a).getLocalVariableTypeTable();
removeLocalVariableTypes();
for (int k = 0; k < lv.length; k++) {
LocalVariable l = lv[k];
InstructionHandle start = il.findHandle(l.getStartPC());
InstructionHandle end = il.findHandle(l.getStartPC() + l.getLength());
// Repair malformed handles
@ -273,16 +273,9 @@ public class MethodGen extends FieldGenOrMethodGen {
if (null == end) {
end = il.getEnd();
}
LocalVariable newVar = new LocalVariable(l);
int startPosition = start.getPosition();
newVar.setStartPC(startPosition);
newVar.setLength(end.getPosition() - startPosition);
newLV[k] = newVar;
addLocalVariableType(l.getName(), Type.getType(l.getSignature()), l
.getIndex(), start, end);
}
LocalVariableTypeTable newLVTT = new LocalVariableTypeTable(
(LocalVariableTypeTable)a);
newLVTT.setLocalVariableTable(newLV);
addCodeAttribute(newLVTT);
} else
addCodeAttribute(a);
}
@ -414,6 +407,31 @@ public class MethodGen extends FieldGenOrMethodGen {
return lg;
}
/*
* If the range of the variable has not been set yet, it will be set to be
* val id from the start to the end of the instruction list.
*
* @return array of declared local variable types sorted by index
*/
private LocalVariableGen[] getLocalVariableTypes() {
int size = type_vec.size();
LocalVariableGen[] lg = new LocalVariableGen[size];
type_vec.toArray(lg);
for(int i=0; i < size; i++) {
if(lg[i].getStart() == null)
lg[i].setStart(il.getStart());
if(lg[i].getEnd() == null)
lg[i].setEnd(il.getEnd());
}
if(size > 1)
sort(lg, 0, size - 1);
return lg;
}
/**
* @return `LocalVariableTable' attribute of all the local variables of this method.
*/
@ -429,6 +447,68 @@ public class MethodGen extends FieldGenOrMethodGen {
2 + lv.length * 10, lv, cp.getConstantPool());
}
/**
* @return `LocalVariableTypeTable' attribute of all the local variable
* types of this method.
*/
public LocalVariableTypeTable getLocalVariableTypeTable(ConstantPoolGen cp) {
LocalVariableGen[] lg = getLocalVariableTypes();
int size = lg.length;
LocalVariable[] lv = new LocalVariable[size];
for(int i=0; i < size; i++)
lv[i] = lg[i].getLocalVariable(cp);
return new LocalVariableTypeTable(cp.addUtf8("LocalVariableTypeTable"),
2 + lv.length * 10, lv, cp.getConstantPool());
}
/**
* Adds a local variable type to this method.
*
* @param name variable name
* @param type variable type
* @param slot the index of the local variable, if type is long or double, the next available
* index is slot+2
* @param start from where the variable is valid
* @param end until where the variable is valid
* @return new local variable object
* @see LocalVariable
*/
private LocalVariableGen addLocalVariableType(String name, Type type, int slot,
InstructionHandle start,
InstructionHandle end) {
byte t = type.getType();
if(t != Constants.T_ADDRESS) {
int add = type.getSize();
if(slot + add > max_locals)
max_locals = slot + add;
LocalVariableGen l = new LocalVariableGen(slot, name, type, start, end);
int i;
if((i = type_vec.indexOf(l)) >= 0) // Overwrite if necessary
type_vec.set(i, l);
else
type_vec.add(l);
return l;
} else {
throw new IllegalArgumentException("Can not use " + type +
" as type for local variable");
}
}
/**
* Remove all local variable types.
*/
private void removeLocalVariableTypes() {
type_vec.clear();
}
/**
* Give an instruction a line number corresponding to the source code line.
*
@ -645,12 +725,17 @@ public class MethodGen extends FieldGenOrMethodGen {
LineNumberTable lnt = null;
LocalVariableTable lvt = null;
LocalVariableTypeTable lvtt = null;
/* Create LocalVariableTable and LineNumberTable attributes (for debuggers, e.g.)
/* Create LocalVariableTable, LocalvariableTypeTable, and LineNumberTable
* attributes (for debuggers, e.g.)
*/
if((variable_vec.size() > 0) && !strip_attributes)
addCodeAttribute(lvt = getLocalVariableTable(cp));
if((type_vec.size() > 0) && !strip_attributes)
addCodeAttribute(lvtt = getLocalVariableTypeTable(cp));
if((line_number_vec.size() > 0) && !strip_attributes)
addCodeAttribute(lnt = getLineNumberTable(cp));
@ -699,6 +784,7 @@ public class MethodGen extends FieldGenOrMethodGen {
// Undo effects of adding attributes
if(lvt != null) removeCodeAttribute(lvt);
if(lvtt != null) removeCodeAttribute(lvtt);
if(lnt != null) removeCodeAttribute(lnt);
if(code != null) removeAttribute(code);
if(et != null) removeAttribute(et);