# HG changeset patch # User dbuck # Date 1415683634 28800 # Node ID 572db6f408a27d37d3d0475cacbe9115d67486d1 # Parent 02d2df45bda8a9d5a0c22874a71830c8a6a53ad1 8064516: BCEL still corrupts generic methods if bytecode offsets are modified Summary: Added comprehensive support for LocalVariableTypeTable to MethodGen. Reviewed-by: joehw diff -r 02d2df45bda8 -r 572db6f408a2 src/com/sun/org/apache/bcel/internal/classfile/DescendingVisitor.java --- a/src/com/sun/org/apache/bcel/internal/classfile/DescendingVisitor.java Fri Nov 07 01:18:43 2014 -0800 +++ b/src/com/sun/org/apache/bcel/internal/classfile/DescendingVisitor.java Mon Nov 10 21:27:14 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(); } diff -r 02d2df45bda8 -r 572db6f408a2 src/com/sun/org/apache/bcel/internal/generic/MethodGen.java --- a/src/com/sun/org/apache/bcel/internal/generic/MethodGen.java Fri Nov 07 01:18:43 2014 -0800 +++ b/src/com/sun/org/apache/bcel/internal/generic/MethodGen.java Mon Nov 10 21:27:14 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);