removed restriction on visitTryCatch call order and made ClassReader to call it before all method instructions to allow one-pass transformations for try/catch blocks
diff --git a/src/org/objectweb/asm/ClassReader.java b/src/org/objectweb/asm/ClassReader.java
index 45ab14f..f3ca9d9 100644
--- a/src/org/objectweb/asm/ClassReader.java
+++ b/src/org/objectweb/asm/ClassReader.java
@@ -744,6 +744,8 @@
int codeStart = v;
int codeEnd = v + codeLength;
+ mv.visitCode();
+
// 1st phase: finds the labels
int label;
Label[] labels = new Label[codeLength + 1];
@@ -845,16 +847,29 @@
v += 2;
for (; j > 0; --j) {
label = readUnsignedShort(v);
- if (labels[label] == null) {
- labels[label] = new Label();
+ Label start = labels[label];
+ if (start == null) {
+ labels[label] = start = new Label();
}
label = readUnsignedShort(v + 2);
- if (labels[label] == null) {
- labels[label] = new Label();
+ Label end = labels[label];
+ if (end == null) {
+ labels[label] = end = new Label();
}
label = readUnsignedShort(v + 4);
- if (labels[label] == null) {
- labels[label] = new Label();
+ Label handler = labels[label];
+ if (handler == null) {
+ labels[label] = handler = new Label();
+ }
+
+ int type = readUnsignedShort(v + 6);
+ if (type == 0) {
+ mv.visitTryCatchBlock(start, end, handler, null);
+ } else {
+ mv.visitTryCatchBlock(start,
+ end,
+ handler,
+ readUTF8(items[type], c));
}
v += 8;
}
@@ -919,7 +934,6 @@
}
// 2nd phase: visits each instruction
- mv.visitCode();
v = codeStart;
Label l;
while (v < codeEnd) {
@@ -1070,24 +1084,7 @@
if (l != null) {
mv.visitLabel(l);
}
- // visits the try catch entries
- j = readUnsignedShort(v);
- v += 2;
- for (; j > 0; --j) {
- Label start = labels[readUnsignedShort(v)];
- Label end = labels[readUnsignedShort(v + 2)];
- Label handler = labels[readUnsignedShort(v + 4)];
- int type = readUnsignedShort(v + 6);
- if (type == 0) {
- mv.visitTryCatchBlock(start, end, handler, null);
- } else {
- mv.visitTryCatchBlock(start,
- end,
- handler,
- readUTF8(items[type], c));
- }
- v += 8;
- }
+
// visits the local variable tables
if (!skipDebug && varTable != 0) {
int[] typeTable = null;
diff --git a/src/org/objectweb/asm/Handler.java b/src/org/objectweb/asm/Handler.java
new file mode 100644
index 0000000..8bef845
--- /dev/null
+++ b/src/org/objectweb/asm/Handler.java
@@ -0,0 +1,70 @@
+/***
+ * ASM: a very small and fast Java bytecode manipulation framework
+ * Copyright (c) 2000-2005 INRIA, France Telecom
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.objectweb.asm;
+
+/**
+ * Information about an exception handler block.
+ *
+ * @author Eric Bruneton
+ */
+class Handler {
+
+ /**
+ * Beginning of the exception handler's scope (inclusive).
+ */
+ Label start;
+
+ /**
+ * End of the exception handler's scope (exclusive).
+ */
+ Label end;
+
+ /**
+ * Beginning of the exception handler's code.
+ */
+ Label handler;
+
+ /**
+ * Internal name of the type of exceptions handled by this handler, or
+ * <tt>null</tt> to catch any exceptions.
+ */
+ String desc;
+
+ /**
+ * Constant pool index of the internal name of the type of exceptions
+ * handled by this handler, or 0 to catch any exceptions.
+ */
+ int type;
+
+ /**
+ * Next exception handler block info.
+ */
+ Handler next;
+}
diff --git a/src/org/objectweb/asm/MethodVisitor.java b/src/org/objectweb/asm/MethodVisitor.java
index 2d9d1c3..130a3e4 100644
--- a/src/org/objectweb/asm/MethodVisitor.java
+++ b/src/org/objectweb/asm/MethodVisitor.java
@@ -38,9 +38,9 @@
* <tt>visitLineNumber</tt>)* <tt>visitMaxs</tt> ] <tt>visitEnd</tt>. In
* addition, the <tt>visit</tt><i>X</i>Insn</tt> and <tt>visitLabel</tt>
* methods must be called in the sequential order of the bytecode instructions
- * of the visited code, and the <tt>visitTryCatchBlock</tt>, <tt>visitLocalVariable</tt>
- * and <tt>visitLineNumber</tt> methods must be called after the labels passed
- * as arguments have been visited.
+ * of the visited code, and the <tt>visitLocalVariable</tt> and <tt>visitLineNumber</tt>
+ * methods must be called after the labels passed as arguments have been
+ * visited.
*
* @author Eric Bruneton
*/
diff --git a/src/org/objectweb/asm/MethodWriter.java b/src/org/objectweb/asm/MethodWriter.java
index 9a1b177..8acfe35 100644
--- a/src/org/objectweb/asm/MethodWriter.java
+++ b/src/org/objectweb/asm/MethodWriter.java
@@ -158,7 +158,12 @@
/**
* The catch table of this method.
*/
- private ByteVector catchTable;
+ private Handler catchTable;
+
+ /**
+ * The last element in the catchTable handler list.
+ */
+ private Handler lastHandler;
/**
* Number of entries in the LocalVariableTable attribute.
@@ -1008,13 +1013,18 @@
}
}
++catchCount;
- if (catchTable == null) {
- catchTable = new ByteVector();
+ Handler h = new Handler();
+ h.start = start;
+ h.end = end;
+ h.handler = handler;
+ h.desc = type;
+ h.type = type != null ? cw.newClass(type) : 0;
+ if (lastHandler == null) {
+ catchTable = h;
+ } else {
+ lastHandler.next = h;
}
- catchTable.putShort(start.position);
- catchTable.putShort(end.position);
- catchTable.putShort(handler.position);
- catchTable.putShort(type != null ? cw.newClass(type) : 0);
+ lastHandler = h;
}
public void visitLocalVariable(
@@ -1350,7 +1360,14 @@
out.putInt(code.length).putByteArray(code.data, 0, code.length);
out.putShort(catchCount);
if (catchCount > 0) {
- out.putByteArray(catchTable.data, 0, catchTable.length);
+ Handler h = catchTable;
+ while (h != null) {
+ out.putShort(h.start.position)
+ .putShort(h.end.position)
+ .putShort(h.handler.position)
+ .putShort(h.type);
+ h = h.next;
+ }
}
attributeCount = 0;
if (localVar != null) {
@@ -1821,26 +1838,13 @@
}
}
- // updates the instructions addresses in the
- // catch, local var and line number tables
- if (catchTable != null) {
- b = catchTable.data;
- u = 0;
- while (u < catchTable.length) {
- writeShort(b, u, getNewOffset(allIndexes,
- allSizes,
- 0,
- readUnsignedShort(b, u)));
- writeShort(b, u + 2, getNewOffset(allIndexes,
- allSizes,
- 0,
- readUnsignedShort(b, u + 2)));
- writeShort(b, u + 4, getNewOffset(allIndexes,
- allSizes,
- 0,
- readUnsignedShort(b, u + 4)));
- u += 8;
- }
+ // updates the exception handler block labels
+ Handler h = catchTable;
+ while (h != null) {
+ getNewOffset(allIndexes, allSizes, h.start);
+ getNewOffset(allIndexes, allSizes, h.end);
+ getNewOffset(allIndexes, allSizes, h.handler);
+ h = h.next;
}
for (i = 0; i < 2; ++i) {
ByteVector bv = i == 0 ? localVar : localVarType;
@@ -1978,4 +1982,31 @@
}
return offset;
}
+
+ /**
+ * Updates the offset of the given label.
+ *
+ * @param indexes current positions of the instructions to be resized. Each
+ * instruction must be designated by the index of its <i>last</i>
+ * byte, plus one (or, in other words, by the index of the <i>first</i>
+ * byte of the <i>next</i> instruction).
+ * @param sizes the number of bytes to be <i>added</i> to the above
+ * instructions. More precisely, for each i < <tt>len</tt>,
+ * <tt>sizes</tt>[i] bytes will be added at the end of the
+ * instruction designated by <tt>indexes</tt>[i] or, if
+ * <tt>sizes</tt>[i] is negative, the <i>last</i> |<tt>sizes[i]</tt>|
+ * bytes of the instruction will be removed (the instruction size
+ * <i>must not</i> become negative or null).
+ * @param label the label whose offset must be updated.
+ */
+ static void getNewOffset(
+ final int[] indexes,
+ final int[] sizes,
+ final Label label)
+ {
+ if (!label.resized) {
+ label.position = getNewOffset(indexes, sizes, 0, label.position);
+ label.resized = true;
+ }
+ }
}