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;
+        }
+    }
 }