8064516: BCEL still corrupts generic methods if bytecode offsets are modified
Summary: Added comprehensive support for LocalVariableTypeTable to MethodGen.
Reviewed-by: joehw
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/DescendingVisitor.java Fri Nov 07 13:18:58 2014 -0800
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/DescendingVisitor.java Mon Nov 10 16:09:38 2014 -0800
@@ -213,6 +213,10 @@
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();
}
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/MethodGen.java Fri Nov 07 13:18:58 2014 -0800
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/MethodGen.java Mon Nov 10 16:09:38 2014 -0800
@@ -87,6 +87,7 @@
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 @@
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 @@
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 @@
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.
*/
@@ -430,6 +448,68 @@
}
/**
+ * @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.
*
* @param ih instruction to tag
@@ -645,12 +725,17 @@
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 @@
// 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);