added asm utils
diff --git a/archive/asmutil.mf b/archive/asmutil.mf
new file mode 100644
index 0000000..0a7de8f
--- /dev/null
+++ b/archive/asmutil.mf
@@ -0,0 +1,4 @@
+Manifest-Version: 1.0
+Implementation-Title: "ASM Utilities"
+Implementation-Version: "1.3"
+Implementation-Vendor: "France Telecom R&D"
diff --git a/archive/asmutil.xml b/archive/asmutil.xml
new file mode 100644
index 0000000..0a3d6af
--- /dev/null
+++ b/archive/asmutil.xml
@@ -0,0 +1,9 @@
+<project name="asm" default="dist">
+  <target name="dist">
+    <jar jarfile="${dist.lib}/asmutil.jar"
+         basedir="${build}"
+         manifest="${archive}/asmutil.mf">
+      <include name="org/objectweb/asm/util/*.class"/>
+    </jar>
+  </target>
+</project>
diff --git a/src/org/objectweb/asm/util/DumpClassVisitor.java b/src/org/objectweb/asm/util/DumpClassVisitor.java
new file mode 100644
index 0000000..52d502d
--- /dev/null
+++ b/src/org/objectweb/asm/util/DumpClassVisitor.java
@@ -0,0 +1,364 @@
+/***
+ * ASM: a very small and fast Java bytecode manipulation framework
+ * Copyright (C) 2000 INRIA, France Telecom
+ * Copyright (C) 2002 France Telecom
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Contact: Eric.Bruneton@rd.francetelecom.com
+ *
+ * Author: Eric Bruneton
+ */
+
+package org.objectweb.asm.util;
+
+import org.objectweb.asm.Constants;
+import org.objectweb.asm.ClassReader;
+
+import java.io.PrintWriter;
+
+/**
+ * A {@link PrintClassVisitor PrintClassVisitor} that prints the ASM code that
+ * generates the classes it visits. This class visitor can be used to quickly
+ * write ASM code to generate some given bytecode:
+ * <ul>
+ * <li>write the Java source code equivalent to the bytecode you want to
+ * generate;</li>
+ * <li>compile it with <tt>javac</tt>;</li>
+ * <li>make a {@link DumpClassVisitor DumpClassVisitor} visit this compiled
+ * class (see the {@link #main main} method);</li>
+ * <li>edit the generated source code, if necessary.</li>
+ * </ul>
+ * The source code printed when visiting the <tt>Hello</tt> class is the
+ * following:
+ * <pre>
+ * import org.objectweb.asm.*;
+ * import java.io.FileOutputStream;
+ *
+ * public class Dump implements Constants {
+ *
+ * public static void main (String[] args) throws Exception {
+ *
+ * ClassWriter cw = new ClassWriter(false);
+ * CodeVisitor cv;
+ *
+ * cw.visit(ACC_PUBLIC + ACC_SUPER, "Hello", "java/lang/Object", null, "Hello.java");
+ *
+ * {
+ * cv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "main", "([Ljava/lang/String;)V", null);
+ * cv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
+ * cv.visitLdcInsn("hello");
+ * cv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V");
+ * cv.visitInsn(RETURN);
+ * cv.visitMaxs(2, 1);
+ * }
+ * {
+ * cv = cw.visitMethod(ACC_PUBLIC, "&lt;init&gt;", "()V", null);
+ * cv.visitVarInsn(ALOAD, 0);
+ * cv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "&lt;init&gt;", "()V");
+ * cv.visitInsn(RETURN);
+ * cv.visitMaxs(1, 1);
+ * }
+ * cw.visitEnd();
+ *
+ * FileOutputStream os = new FileOutputStream("Dumped.class");
+ * os.write(cw.toByteArray());
+ * os.close();
+ * }
+ * }
+ * </pre>
+ * where <tt>Hello</tt> is defined by:
+ * <pre>
+ * public class Hello {
+ *
+ *   public static void main (String[] args) {
+ *     System.out.println("hello");
+ *   }
+ * }
+ * </pre>
+ */
+
+public class DumpClassVisitor extends PrintClassVisitor {
+
+  private StringBuffer buf;
+
+  /**
+   * Prints the ASM source code to generate the given class to the standard
+   * output.
+   * <p>
+   * Usage: DumpClassVisitor &lt;fully qualified class name&gt;
+   */
+
+  public static void main (final String[] args) throws Exception {
+    if (args.length == 0) {
+      System.err.println("Prints the ASM code to generate the given class.");
+      System.err.println("Usage: DumpClassVisitor <fully qualified class name>");
+    }
+    ClassReader cr = new ClassReader(args[0]);
+    cr.accept(new DumpClassVisitor(new PrintWriter(System.out)), true);
+  }
+
+  /**
+   * Constructs a new {@link DumpClassVisitor DumpClassVisitor} object.
+   *
+   * @param pw the print writer to be used to print the trace.
+   */
+
+  public DumpClassVisitor (final PrintWriter pw) {
+    super(pw);
+    buf = new StringBuffer();
+  }
+
+  public void visit (
+    final int access,
+    final String name,
+    final String superName,
+    final String[] interfaces,
+    final String sourceFile)
+  {
+    dump.add("import org.objectweb.asm.*;\n");
+    dump.add("import java.io.FileOutputStream;\n\n");
+    dump.add("public class Dump implements Constants {\n\n");
+    dump.add("public static void main (String[] args) throws Exception {\n\n");
+    dump.add("ClassWriter cw = new ClassWriter(false);\n");
+    dump.add("CodeVisitor cv;\n\n");
+
+    buf.setLength(0);
+    buf.append("cw.visit(");
+    appendAccess(access | 262144);
+    buf.append(", ");
+    appendConstant(buf, name);
+    buf.append(", ");
+    appendConstant(buf, superName);
+    buf.append(", ");
+    if (interfaces != null && interfaces.length > 0) {
+      buf.append("new String[] {");
+      for (int i = 0; i < interfaces.length; ++i) {
+        buf.append(i == 0 ? " " : ", ");
+        appendConstant(buf, interfaces[i]);
+      }
+      buf.append(" }");
+    } else {
+      buf.append("null");
+    }
+    buf.append(", ");
+    appendConstant(buf, sourceFile);
+    buf.append(");\n\n");
+    dump.add(buf.toString());
+  }
+
+  public void visitInnerClass (
+    final String name,
+    final String outerName,
+    final String innerName,
+    final int access)
+  {
+    buf.setLength(0);
+    buf.append("cw.visitInnerClass(");
+    appendConstant(buf, name);
+    buf.append(", ");
+    appendConstant(buf, outerName);
+    buf.append(", ");
+    appendConstant(buf, innerName);
+    buf.append(", ");
+    appendAccess(access);
+    buf.append(");\n\n");
+    dump.add(buf.toString());
+  }
+
+  public void visitField (
+    final int access,
+    final String name,
+    final String desc,
+    final Object value)
+  {
+    buf.setLength(0);
+    buf.append("cw.visitField(");
+    appendAccess(access);
+    buf.append(", ");
+    appendConstant(buf, name);
+    buf.append(", ");
+    appendConstant(buf, desc);
+    buf.append(", ");
+    appendConstant(buf, value);
+    buf.append(");\n\n");
+    dump.add(buf.toString());
+  }
+
+  public PrintCodeVisitor printMethod (
+    final int access,
+    final String name,
+    final String desc,
+    final String[] exceptions)
+  {
+    buf.setLength(0);
+    buf.append("{\n").append("cv = cw.visitMethod(");
+    appendAccess(access);
+    buf.append(", ");
+    appendConstant(buf, name);
+    buf.append(", ");
+    appendConstant(buf, desc);
+    buf.append(", ");
+    if (exceptions != null && exceptions.length > 0) {
+      buf.append("new String[] {");
+      for (int i = 0; i < exceptions.length; ++i) {
+        buf.append(i == 0 ? " " : ", ");
+        appendConstant(buf, exceptions[i]);
+      }
+      buf.append(" });");
+    } else {
+      buf.append("null);");
+    }
+    buf.append("\n");
+    dump.add(buf.toString());
+    return new DumpCodeVisitor();
+  }
+
+  public void visitEnd () {
+    dump.add("cw.visitEnd();\n\n");
+    dump.add("FileOutputStream os = new FileOutputStream(\"Dumped.class\");\n");
+    dump.add("os.write(cw.toByteArray());\n");
+    dump.add("os.close();\n");
+    dump.add("}\n");
+    dump.add("}\n");
+    super.visitEnd();
+  }
+
+  void appendAccess (final int access) {
+    boolean first = true;
+    if ((access & Constants.ACC_PUBLIC) != 0) {
+      buf.append("ACC_PUBLIC");
+      first = false;
+    }
+    if ((access & Constants.ACC_PRIVATE) != 0) {
+      if (!first) {
+        buf.append(" + ");
+      }
+      buf.append("ACC_PRIVATE");
+      first = false;
+    }
+    if ((access & Constants.ACC_PROTECTED) != 0) {
+      if (!first) {
+        buf.append(" + ");
+      }
+      buf.append("ACC_PROTECTED");
+      first = false;
+    }
+    if ((access & Constants.ACC_FINAL) != 0) {
+      if (!first) {
+        buf.append(" + ");
+      }
+      buf.append("ACC_FINAL");
+      first = false;
+    }
+    if ((access & Constants.ACC_STATIC) != 0) {
+      if (!first) {
+        buf.append(" + ");
+      }
+      buf.append("ACC_STATIC");
+      first = false;
+    }
+    if ((access & Constants.ACC_SYNCHRONIZED) != 0) {
+      if (!first) {
+        buf.append(" + ");
+      }
+      if ((access & 262144) != 0) {
+        buf.append("ACC_SUPER");
+      } else {
+        buf.append("ACC_SYNCHRONIZED");
+      }
+      first = false;
+    }
+    if ((access & Constants.ACC_VOLATILE) != 0) {
+      if (!first) {
+        buf.append(" + ");
+      }
+      buf.append("ACC_VOLATILE");
+      first = false;
+    }
+    if ((access & Constants.ACC_TRANSIENT) != 0) {
+      if (!first) {
+        buf.append(" + ");
+      }
+      buf.append("ACC_TRANSIENT");
+      first = false;
+    }
+    if ((access & Constants.ACC_NATIVE) != 0) {
+      if (!first) {
+        buf.append(" + ");
+      }
+      buf.append("ACC_NATIVE");
+      first = false;
+    }
+    if ((access & Constants.ACC_ABSTRACT) != 0) {
+      if (!first) {
+        buf.append(" + ");
+      }
+      buf.append("ACC_ABSTRACT");
+      first = false;
+    }
+    if ((access & Constants.ACC_SYNTHETIC) != 0) {
+      if (!first) {
+        buf.append(" + ");
+      }
+      buf.append("ACC_SYNTHETIC");
+      first = false;
+    }
+    if ((access & Constants.ACC_DEPRECATED) != 0) {
+      if (!first) {
+        buf.append(" + ");
+      }
+      buf.append("ACC_DEPRECATED");
+    }
+  }
+
+  static void appendConstant (final StringBuffer buf, final Object cst) {
+    if (cst == null) {
+      buf.append("null");
+    } else if (cst instanceof String) {
+      String s = (String)cst;
+      buf.append("\"");
+      for (int i = 0; i < s.length(); ++i) {
+        char c = s.charAt(i);
+        if (c == '\n') {
+          buf.append("\\n");
+        } else if (c == '\\') {
+          buf.append("\\\\");
+        } else if (c == '"') {
+          buf.append("\\\"");
+        } else {
+          buf.append(c);
+        }
+      }
+      buf.append("\"");
+    } else if (cst instanceof Integer) {
+      buf.append("new Integer(")
+        .append(cst)
+        .append(")");
+    } else if (cst instanceof Float) {
+      buf.append("new Float(")
+        .append(cst)
+        .append("F)");
+    } else if (cst instanceof Long) {
+      buf.append("new Long(")
+        .append(cst)
+        .append("L)");
+    } else if (cst instanceof Double) {
+      buf.append("new Double(")
+        .append(cst)
+        .append(")");
+    }
+  }
+}
diff --git a/src/org/objectweb/asm/util/DumpCodeVisitor.java b/src/org/objectweb/asm/util/DumpCodeVisitor.java
new file mode 100644
index 0000000..758fcc4
--- /dev/null
+++ b/src/org/objectweb/asm/util/DumpCodeVisitor.java
@@ -0,0 +1,265 @@
+/***
+ * ASM: a very small and fast Java bytecode manipulation framework
+ * Copyright (C) 2000 INRIA, France Telecom
+ * Copyright (C) 2002 France Telecom
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Contact: Eric.Bruneton@rd.francetelecom.com
+ *
+ * Author: Eric Bruneton
+ */
+
+package org.objectweb.asm.util;
+
+import org.objectweb.asm.Label;
+
+import java.util.HashMap;
+
+/**
+ * A {@link PrintCodeVisitor PrintCodeVisitor} that prints the ASM code that
+ * generates the code it visits.
+ */
+
+public class DumpCodeVisitor extends PrintCodeVisitor {
+
+  private final HashMap labelNames;
+
+  /**
+   * Constructs a new {@link DumpCodeVisitor DumpCodeVisitor} object.
+   */
+
+  public DumpCodeVisitor () {
+    this.labelNames = new HashMap();
+  }
+
+  public void printInsn (final int opcode) {
+    buf.append("cv.visitInsn(").
+      append(OPCODES[opcode]).
+      append(");\n");
+  }
+
+  public void printIntInsn (final int opcode, final int operand) {
+    buf.append("cv.visitIntInsn(").
+      append(OPCODES[opcode]).
+      append(", ").
+      append(operand).
+      append(");\n");
+  }
+
+  public void printVarInsn (final int opcode, final int var) {
+    buf.append("cv.visitVarInsn(").
+      append(OPCODES[opcode]).
+      append(", ").
+      append(var).
+      append(");\n");
+  }
+
+  public void printTypeInsn (final int opcode, final String desc) {
+    buf.append("cv.visitTypeInsn(").
+      append(OPCODES[opcode]).
+      append(", ");
+    DumpClassVisitor.appendConstant(buf, desc);
+    buf.append(");\n");
+  }
+
+  public void printFieldInsn (
+    final int opcode,
+    final String owner,
+    final String name,
+    final String desc)
+  {
+    buf.append("cv.visitFieldInsn(")
+      .append(OPCODES[opcode])
+      .append(", ");
+    DumpClassVisitor.appendConstant(buf, owner);
+    buf.append(", ");
+    DumpClassVisitor.appendConstant(buf, name);
+    buf.append(", ");
+    DumpClassVisitor.appendConstant(buf, desc);
+    buf.append(");\n");
+  }
+
+  public void printMethodInsn (
+    final int opcode,
+    final String owner,
+    final String name,
+    final String desc)
+  {
+    buf.append("cv.visitMethodInsn(")
+      .append(OPCODES[opcode])
+      .append(", ");
+    DumpClassVisitor.appendConstant(buf, owner);
+    buf.append(", ");
+    DumpClassVisitor.appendConstant(buf, name);
+    buf.append(", ");
+    DumpClassVisitor.appendConstant(buf, desc);
+    buf.append(");\n");
+  }
+
+  public void printJumpInsn (final int opcode, final Label label) {
+    declareLabel(label);
+    buf.append("cv.visitJumpInsn(")
+      .append(OPCODES[opcode])
+      .append(", ");
+    appendLabel(label);
+    buf.append(");\n");
+  }
+
+  public void printLabel (final Label label) {
+    declareLabel(label);
+    buf.append("cv.visitLabel(");
+    appendLabel(label);
+    buf.append(");\n");
+  }
+
+  public void printLdcInsn (final Object cst) {
+    buf.append("cv.visitLdcInsn(");
+    DumpClassVisitor.appendConstant(buf, cst);
+    buf.append(");\n");
+  }
+
+  public void printIincInsn (final int var, final int increment) {
+    buf.append("cv.visitIincInsn(")
+      .append(var)
+      .append(", ")
+      .append(increment)
+      .append(");\n");
+  }
+
+  public void printTableSwitchInsn (
+    final int min,
+    final int max,
+    final Label dflt,
+    final Label labels[])
+  {
+    for (int i = 0; i < labels.length; ++i) {
+      declareLabel(labels[i]);
+    }
+    declareLabel(dflt);
+
+    buf.append("cv.visitTableSwitchInsn(")
+      .append(min)
+      .append(", ")
+      .append(max)
+      .append(", ");
+    appendLabel(dflt);
+    buf.append(", new Label[] {");
+    for (int i = 0; i < labels.length; ++i) {
+      buf.append(i == 0 ? " " : ", ");
+      appendLabel(labels[i]);
+    }
+    buf.append(" });\n");
+  }
+
+  public void printLookupSwitchInsn (
+    final Label dflt,
+    final int keys[],
+    final Label labels[])
+  {
+    for (int i = 0; i < labels.length; ++i) {
+      declareLabel(labels[i]);
+    }
+    declareLabel(dflt);
+
+    buf.append("cv.visitLookupSwitch(");
+    appendLabel(dflt);
+    buf.append(", new int[] {");
+    for (int i = 0; i < keys.length; ++i) {
+      buf.append(i == 0 ? " " : ", ").append(keys[i]);
+    }
+    buf.append(" }, new Label[] {");
+    for (int i = 0; i < labels.length; ++i) {
+      buf.append(i == 0 ? " " : ", ");
+      appendLabel(labels[i]);
+    }
+    buf.append(" });\n");
+  }
+
+  public void printMultiANewArrayInsn (final String desc, final int dims) {
+    buf.append("cv.visitMultiANewArrayInsn(");
+    DumpClassVisitor.appendConstant(buf, desc);
+    buf.append(", ")
+      .append(dims)
+      .append(");\n");
+  }
+
+  public void printTryCatchBlock (
+    final Label start,
+    final Label end,
+    final Label handler,
+    final String type)
+  {
+    buf.append("cv.visitTryCatchBlock(");
+    appendLabel(start);
+    buf.append(", ");
+    appendLabel(end);
+    buf.append(", ");
+    appendLabel(handler);
+    buf.append(", ");
+    DumpClassVisitor.appendConstant(buf, type);
+    buf.append(");\n");
+  }
+
+  public void printMaxs (final int maxStack, final int maxLocals) {
+    buf.append("cv.visitMaxs(")
+      .append(maxStack)
+      .append(", ")
+      .append(maxLocals)
+      .append(");\n")
+      .append("}\n");
+  }
+
+  public void printLocalVariable (
+    final String name,
+    final String desc,
+    final Label start,
+    final Label end,
+    final int index)
+  {
+    buf.append("cv.visitLocalVariable(");
+    DumpClassVisitor.appendConstant(buf, name);
+    buf.append(", ");
+    DumpClassVisitor.appendConstant(buf, desc);
+    buf.append(", ");
+    appendLabel(start);
+    buf.append(", ");
+    appendLabel(end);
+    buf.append(", ").append(index).append(");\n");
+  }
+
+  public void printLineNumber (final int line, final Label start) {
+    buf.append("cv.visitLineNumber(")
+      .append(line)
+      .append(", ");
+    appendLabel(start);
+    buf.append(");\n");
+  }
+
+  private void declareLabel (final Label l) {
+    String name = (String)labelNames.get(l);
+    if (name == null) {
+      name = "l" + labelNames.size();
+      labelNames.put(l, name);
+      buf.append("Label ")
+        .append(name)
+        .append(" = new Label();\n");
+    }
+  }
+
+  private void appendLabel (final Label l) {
+    buf.append((String)labelNames.get(l));
+  }
+}
diff --git a/src/org/objectweb/asm/util/PrintClassVisitor.java b/src/org/objectweb/asm/util/PrintClassVisitor.java
new file mode 100644
index 0000000..1777a60
--- /dev/null
+++ b/src/org/objectweb/asm/util/PrintClassVisitor.java
@@ -0,0 +1,87 @@
+/***
+ * ASM: a very small and fast Java bytecode manipulation framework
+ * Copyright (C) 2000 INRIA, France Telecom
+ * Copyright (C) 2002 France Telecom
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Contact: Eric.Bruneton@rd.francetelecom.com
+ *
+ * Author: Eric Bruneton
+ */
+
+package org.objectweb.asm.util;
+
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.CodeVisitor;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * An abstract class visitor that prints the classes it visits.
+ */
+
+public abstract class PrintClassVisitor implements ClassVisitor {
+
+  protected final ArrayList dump;
+
+  protected final PrintWriter pw;
+
+  /**
+   * Constructs a new {@link PrintClassVisitor PrintClassVisitor} object.
+   *
+   * @param pw the print writer to be used to print the trace.
+   */
+
+  public PrintClassVisitor (final PrintWriter pw) {
+    this.dump = new ArrayList();
+    this.pw = pw;
+  }
+
+  public CodeVisitor visitMethod (
+    final int access,
+    final String name,
+    final String desc,
+    final String[] exceptions)
+  {
+    PrintCodeVisitor pcv = printMethod(access, name, desc, exceptions);
+    dump.add(pcv.getText());
+    return pcv;
+  }
+
+  public void visitEnd () {
+    printList(dump);
+    pw.flush();
+  }
+
+  private void printList (final List l) {
+    for (int i = 0; i < l.size(); ++i) {
+      Object o = l.get(i);
+      if (o instanceof List) {
+        printList((List)o);
+      } else {
+        pw.print(o.toString());
+      }
+    }
+  }
+
+  public abstract PrintCodeVisitor printMethod (
+    final int access,
+    final String name,
+    final String desc,
+    final String[] exceptions);
+}
diff --git a/src/org/objectweb/asm/util/PrintCodeVisitor.java b/src/org/objectweb/asm/util/PrintCodeVisitor.java
new file mode 100644
index 0000000..5c64d50
--- /dev/null
+++ b/src/org/objectweb/asm/util/PrintCodeVisitor.java
@@ -0,0 +1,451 @@
+/***
+ * ASM: a very small and fast Java bytecode manipulation framework
+ * Copyright (C) 2000 INRIA, France Telecom
+ * Copyright (C) 2002 France Telecom
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Contact: Eric.Bruneton@rd.francetelecom.com
+ *
+ * Author: Eric Bruneton
+ */
+
+package org.objectweb.asm.util;
+
+import org.objectweb.asm.CodeVisitor;
+import org.objectweb.asm.Label;
+
+import java.util.ArrayList;
+
+/**
+ * An abstract code visitor that prints the code it visits.
+ */
+
+public abstract class PrintCodeVisitor implements CodeVisitor {
+
+  protected final StringBuffer buf;
+
+  protected final ArrayList dump;
+
+  protected final static String[] OPCODES = {
+    "NOP",
+    "ACONST_NULL",
+    "ICONST_M1",
+    "ICONST_0",
+    "ICONST_1",
+    "ICONST_2",
+    "ICONST_3",
+    "ICONST_4",
+    "ICONST_5",
+    "LCONST_0",
+    "LCONST_1",
+    "FCONST_0",
+    "FCONST_1",
+    "FCONST_2",
+    "DCONST_0",
+    "DCONST_1",
+    "BIPUSH",
+    "SIPUSH",
+    "LDC",
+    null,
+    null,
+    "ILOAD",
+    "LLOAD",
+    "FLOAD",
+    "DLOAD",
+    "ALOAD",
+    null,
+    null,
+    null,
+    null,
+    null,
+    null,
+    null,
+    null,
+    null,
+    null,
+    null,
+    null,
+    null,
+    null,
+    null,
+    null,
+    null,
+    null,
+    null,
+    null,
+    "IALOAD",
+    "LALOAD",
+    "FALOAD",
+    "DALOAD",
+    "AALOAD",
+    "BALOAD",
+    "CALOAD",
+    "SALOAD",
+    "ISTORE",
+    "LSTORE",
+    "FSTORE",
+    "DSTORE",
+    "ASTORE",
+    null,
+    null,
+    null,
+    null,
+    null,
+    null,
+    null,
+    null,
+    null,
+    null,
+    null,
+    null,
+    null,
+    null,
+    null,
+    null,
+    null,
+    null,
+    null,
+    null,
+    "IASTORE",
+    "LASTORE",
+    "FASTORE",
+    "DASTORE",
+    "AASTORE",
+    "BASTORE",
+    "CASTORE",
+    "SASTORE",
+    "POP",
+    "POP2",
+    "DUP",
+    "DUP_X1",
+    "DUP_X2",
+    "DUP2",
+    "DUP2_X1",
+    "DUP2_X2",
+    "SWAP",
+    "IADD",
+    "LADD",
+    "FADD",
+    "DADD",
+    "ISUB",
+    "LSUB",
+    "FSUB",
+    "DSUB",
+    "IMUL",
+    "LMUL",
+    "FMUL",
+    "DMUL",
+    "IDIV",
+    "LDIV",
+    "FDIV",
+    "DDIV",
+    "IREM",
+    "LREM",
+    "FREM",
+    "DREM",
+    "INEG",
+    "LNEG",
+    "FNEG",
+    "DNEG",
+    "ISHL",
+    "LSHL",
+    "ISHR",
+    "LSHR",
+    "IUSHR",
+    "LUSHR",
+    "IAND",
+    "LAND",
+    "IOR",
+    "LOR",
+    "IXOR",
+    "LXOR",
+    "IINC",
+    "I2L",
+    "I2F",
+    "I2D",
+    "L2I",
+    "L2F",
+    "L2D",
+    "F2I",
+    "F2L",
+    "F2D",
+    "D2I",
+    "D2L",
+    "D2F",
+    "I2B",
+    "I2C",
+    "I2S",
+    "LCMP",
+    "FCMPL",
+    "FCMPG",
+    "DCMPL",
+    "DCMPG",
+    "IFEQ",
+    "IFNE",
+    "IFLT",
+    "IFGE",
+    "IFGT",
+    "IFLE",
+    "IF_ICMPEQ",
+    "IF_ICMPNE",
+    "IF_ICMPLT",
+    "IF_ICMPGE",
+    "IF_ICMPGT",
+    "IF_ICMPLE",
+    "IF_ACMPEQ",
+    "IF_ACMPNE",
+    "GOTO",
+    "JSR",
+    "RET",
+    "TABLESWITCH",
+    "LOOKUPSWITCH",
+    "IRETURN",
+    "LRETURN",
+    "FRETURN",
+    "DRETURN",
+    "ARETURN",
+    "RETURN",
+    "GETSTATIC",
+    "PUTSTATIC",
+    "GETFIELD",
+    "PUTFIELD",
+    "INVOKEVIRTUAL",
+    "INVOKESPECIAL",
+    "INVOKESTATIC",
+    "INVOKEINTERFACE",
+    null,
+    "NEW",
+    "NEWARRAY",
+    "ANEWARRAY",
+    "ARRAYLENGTH",
+    "ATHROW",
+    "CHECKCAST",
+    "INSTANCEOF",
+    "MONITORENTER",
+    "MONITOREXIT",
+    null,
+    "MULTIANEWARRAY",
+    "IFNULL",
+    "IFNONNULL",
+    null,
+    null
+  };
+
+  /**
+   * Constructs a new {@link PrintCodeVisitor PrintCodeVisitor} object.
+   */
+
+  public PrintCodeVisitor () {
+    this.buf = new StringBuffer();
+    this.dump = new ArrayList();
+  }
+
+  public void visitInsn (final int opcode) {
+    buf.setLength(0);
+    printInsn(opcode);
+    dump.add(buf.toString());
+  }
+
+  public void visitIntInsn (final int opcode, final int operand) {
+    buf.setLength(0);
+    printIntInsn(opcode, operand);
+    dump.add(buf.toString());
+  }
+
+  public void visitVarInsn (final int opcode, final int var) {
+    buf.setLength(0);
+    printVarInsn(opcode, var);
+    dump.add(buf.toString());
+  }
+
+  public void visitTypeInsn (final int opcode, final String desc) {
+    buf.setLength(0);
+    printTypeInsn(opcode, desc);
+    dump.add(buf.toString());
+  }
+
+  public void visitFieldInsn (
+    final int opcode,
+    final String owner,
+    final String name,
+    final String desc)
+  {
+    buf.setLength(0);
+    printFieldInsn(opcode, owner, name, desc);
+    dump.add(buf.toString());
+  }
+
+  public void visitMethodInsn (
+    final int opcode,
+    final String owner,
+    final String name,
+    final String desc)
+  {
+    buf.setLength(0);
+    printMethodInsn(opcode, owner, name, desc);
+    dump.add(buf.toString());
+  }
+
+  public void visitJumpInsn (final int opcode, final Label label) {
+    buf.setLength(0);
+    printJumpInsn(opcode, label);
+    dump.add(buf.toString());
+  }
+
+  public void visitLabel (final Label label) {
+    buf.setLength(0);
+    printLabel(label);
+    dump.add(buf.toString());
+  }
+
+  public void visitLdcInsn (final Object cst) {
+    buf.setLength(0);
+    printLdcInsn(cst);
+    dump.add(buf.toString());
+  }
+
+  public void visitIincInsn (final int var, final int increment) {
+    buf.setLength(0);
+    printIincInsn(var, increment);
+    dump.add(buf.toString());
+  }
+
+  public void visitTableSwitchInsn (
+    final int min,
+    final int max,
+    final Label dflt,
+    final Label labels[])
+  {
+    buf.setLength(0);
+    printTableSwitchInsn(min, max, dflt, labels);
+    dump.add(buf.toString());
+  }
+
+  public void visitLookupSwitchInsn (
+    final Label dflt,
+    final int keys[],
+    final Label labels[])
+  {
+    buf.setLength(0);
+    printLookupSwitchInsn(dflt, keys, labels);
+    dump.add(buf.toString());
+  }
+
+  public void visitMultiANewArrayInsn (final String desc, final int dims) {
+    buf.setLength(0);
+    printMultiANewArrayInsn(desc, dims);
+    dump.add(buf.toString());
+  }
+
+  public void visitTryCatchBlock (
+    final Label start,
+    final Label end,
+    final Label handler,
+    final String type)
+  {
+    buf.setLength(0);
+    printTryCatchBlock(start, end, handler, type);
+    dump.add(buf.toString());
+  }
+
+  public void visitMaxs (final int maxStack, final int maxLocals) {
+    buf.setLength(0);
+    printMaxs(maxStack, maxLocals);
+    dump.add(buf.toString());
+  }
+
+  public void visitLocalVariable (
+    final String name,
+    final String desc,
+    final Label start,
+    final Label end,
+    final int index)
+  {
+    buf.setLength(0);
+    printLocalVariable(name, desc, start, end, index);
+    dump.add(buf.toString());
+  }
+
+  public void visitLineNumber (final int line, final Label start) {
+    buf.setLength(0);
+    printLineNumber(line, start);
+    dump.add(buf.toString());
+  }
+
+  public ArrayList getText () {
+    return dump;
+  }
+
+  public abstract void printInsn (final int opcode);
+
+  public abstract void printIntInsn (final int opcode, final int operand);
+
+  public abstract void printVarInsn (final int opcode, final int var);
+
+  public abstract void printTypeInsn (final int opcode, final String desc);
+
+  public abstract void printFieldInsn (
+    final int opcode,
+    final String owner,
+    final String name,
+    final String desc);
+
+  public abstract void printMethodInsn (
+    final int opcode,
+    final String owner,
+    final String name,
+    final String desc);
+
+  public abstract void printJumpInsn (final int opcode, final Label label);
+
+  public abstract void printLabel (final Label label);
+
+  public abstract void printLdcInsn (final Object cst);
+
+  public abstract void printIincInsn (final int var, final int increment);
+
+  public abstract void printTableSwitchInsn (
+    final int min,
+    final int max,
+    final Label dflt,
+    final Label labels[]);
+
+  public abstract void printLookupSwitchInsn (
+    final Label dflt,
+    final int keys[],
+    final Label labels[]);
+
+  public abstract void printMultiANewArrayInsn (
+    final String desc,
+    final int dims);
+
+  public abstract void printTryCatchBlock (
+    final Label start,
+    final Label end,
+    final Label handler,
+    final String type);
+
+  public abstract void printMaxs (final int maxStack, final int maxLocals);
+
+  public abstract void printLocalVariable (
+    final String name,
+    final String desc,
+    final Label start,
+    final Label end,
+    final int index);
+
+  public abstract void printLineNumber (final int line, final Label start);
+}
diff --git a/src/org/objectweb/asm/util/TraceClassVisitor.java b/src/org/objectweb/asm/util/TraceClassVisitor.java
new file mode 100644
index 0000000..41bfbf0
--- /dev/null
+++ b/src/org/objectweb/asm/util/TraceClassVisitor.java
@@ -0,0 +1,276 @@
+/***
+ * ASM: a very small and fast Java bytecode manipulation framework
+ * Copyright (C) 2000 INRIA, France Telecom
+ * Copyright (C) 2002 France Telecom
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Contact: Eric.Bruneton@rd.francetelecom.com
+ *
+ * Author: Eric Bruneton
+ */
+
+package org.objectweb.asm.util;
+
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.CodeVisitor;
+import org.objectweb.asm.Constants;
+import org.objectweb.asm.ClassReader;
+
+import java.io.PrintWriter;
+
+/**
+ * A {@link PrintClassVisitor PrintClassVisitor} that prints a disassembled
+ * view of the classes it visits. This class visitor can be used alone (see the
+ * {@link #main main} method) to disassemble a class. It can also be used in
+ * the middle of class visitor chain to trace the class that is visited at a
+ * given point in this chain. This may be uselful for debugging purposes.
+ * <p>
+ * The trace printed when visiting the <tt>Hello</tt> class is the following:
+ * <pre>
+ * // compiled from Hello.java
+ * public class Hello {
+ *
+ *   public static main ([Ljava/lang/String;)V
+ *     GETSTATIC java/lang/System out Ljava/io/PrintStream;
+ *     LDC "hello"
+ *     INVOKEVIRTUAL java/io/PrintStream println (Ljava/lang/String;)V
+ *     RETURN
+ *     MAXSTACK = 2
+ *     MAXLOCALS = 1
+ *
+ *   public &lt;init&gt; ()V
+ *     ALOAD 0
+ *     INVOKESPECIAL java/lang/Object &lt;init&gt; ()V
+ *     RETURN
+ *     MAXSTACK = 1
+ *     MAXLOCALS = 1
+ *
+ * }
+ * </pre>
+ * where <tt>Hello</tt> is defined by:
+ * <pre>
+ * public class Hello {
+ *
+ *   public static void main (String[] args) {
+ *     System.out.println("hello");
+ *   }
+ * }
+ * </pre>
+ */
+
+public class TraceClassVisitor extends PrintClassVisitor {
+
+  private final StringBuffer buf;
+
+  private final ClassVisitor cv;
+
+  /**
+   * Prints a disassembled view of the given class to the standard output.
+   * <p>
+   * Usage: TraceClassVisitor &lt;fully qualified class name&gt;
+   */
+
+  public static void main (final String[] args) throws Exception {
+    if (args.length == 0) {
+      System.err.println("Prints a disassembled view of the given class.");
+      System.err.println("Usage: TraceClassVisitor <fully qualified class name>");
+    }
+    ClassReader cr = new ClassReader(args[0]);
+    cr.accept(new TraceClassVisitor(null, new PrintWriter(System.out)), true);
+  }
+
+  /**
+   * Constructs a new {@link TraceClassVisitor TraceClassVisitor} object.
+   *
+   * @param cv the class visitor to which this adapter must delegate calls. May
+   *      be <tt>null</tt>.
+   * @param pw the print writer to be used to print the trace.
+   */
+
+  public TraceClassVisitor (final ClassVisitor cv, final PrintWriter pw) {
+    super(pw);
+    this.buf = new StringBuffer();
+    this.cv = cv;
+  }
+
+  public void visit (
+    final int access,
+    final String name,
+    final String superName,
+    final String[] interfaces,
+    final String sourceFile)
+  {
+    buf.setLength(0);
+    if ((access & Constants.ACC_DEPRECATED) != 0) {
+      buf.append("// DEPRECATED\n");
+    }
+    if (sourceFile != null) {
+      buf.append("// compiled from ").append(sourceFile).append("\n");
+    }
+    appendAccess(access & ~Constants.ACC_SUPER);
+    if ((access & Constants.ACC_INTERFACE) != 0) {
+      buf.append("interface ");
+    } else {
+      buf.append("class ");
+    }
+    buf.append(name).append(" ");
+    if (!superName.equals("java/lang/Object")) {
+      buf.append("extends ").append(superName).append(" ");
+    }
+    if (interfaces != null && interfaces.length > 0) {
+      buf.append("implements ");
+      for (int i = 0; i < interfaces.length; ++i) {
+        buf.append(interfaces[i]).append(" ");
+      }
+    }
+    buf.append("{\n\n");
+    dump.add(buf.toString());
+
+    if (cv != null) {
+      cv.visit(access, name, superName, interfaces, sourceFile);
+    }
+  }
+
+  public void visitInnerClass (
+    final String name,
+    final String outerName,
+    final String innerName,
+    final int access)
+  {
+    buf.setLength(0);
+    buf.append("  INNERCLASS ")
+      .append(name)
+      .append(" ")
+      .append(outerName)
+      .append(" ")
+      .append(innerName)
+      .append(" ")
+      .append(access)
+      .append("\n");
+    dump.add(buf.toString());
+
+    if (cv != null) {
+      cv.visitInnerClass(name, outerName, innerName, access);
+    }
+  }
+
+  public void visitField (
+    final int access,
+    final String name,
+    final String desc,
+    final Object value)
+  {
+    buf.setLength(0);
+    if ((access & Constants.ACC_DEPRECATED) != 0) {
+      buf.append("  // DEPRECATED\n");
+    }
+    buf.append("  ");
+    appendAccess(access);
+    buf.append(desc)
+      .append(" ")
+      .append(name);
+    if (value != null) {
+      buf.append(" = ");
+      if (value instanceof String) {
+        buf.append("\"").append(value).append("\"");
+      } else {
+        buf.append(value);
+      }
+    }
+    buf.append("\n\n");
+    dump.add(buf.toString());
+
+    if (cv != null) {
+      cv.visitField(access, name, desc, value);
+    }
+  }
+
+  public PrintCodeVisitor printMethod (
+    final int access,
+    final String name,
+    final String desc,
+    final String[] exceptions)
+  {
+    buf.setLength(0);
+    if ((access & Constants.ACC_DEPRECATED) != 0) {
+      buf.append("  // DEPRECATED\n");
+    }
+    buf.append("  ");
+    appendAccess(access);
+    buf.append(name).
+      append(" ").
+      append(desc);
+    if (exceptions != null && exceptions.length > 0) {
+      buf.append(" throws ");
+      for (int i = 0; i < exceptions.length; ++i) {
+        buf.append(exceptions[i]).append(" ");
+      }
+    }
+    buf.append("\n");
+    dump.add(buf.toString());
+
+    CodeVisitor cv;
+    if (this.cv != null) {
+      cv = this.cv.visitMethod(access, name, desc, exceptions);
+    } else {
+      cv = null;
+    }
+    return new TraceCodeVisitor(cv);
+  }
+
+  public void visitEnd () {
+    dump.add("}\n");
+
+    if (cv != null) {
+      cv.visitEnd();
+    }
+
+    super.visitEnd();
+  }
+
+  private void appendAccess (final int access) {
+    if ((access & Constants.ACC_PUBLIC) != 0) {
+      buf.append("public ");
+    }
+    if ((access & Constants.ACC_PRIVATE) != 0) {
+      buf.append("private ");
+    }
+    if ((access & Constants.ACC_PROTECTED) != 0) {
+      buf.append("protected ");
+    }
+    if ((access & Constants.ACC_FINAL) != 0) {
+      buf.append("final ");
+    }
+    if ((access & Constants.ACC_STATIC) != 0) {
+      buf.append("static ");
+    }
+    if ((access & Constants.ACC_SYNCHRONIZED) != 0) {
+      buf.append("synchronized ");
+    }
+    if ((access & Constants.ACC_VOLATILE) != 0) {
+      buf.append("volatile ");
+    }
+    if ((access & Constants.ACC_TRANSIENT) != 0) {
+      buf.append("transient ");
+    }
+    if ((access & Constants.ACC_NATIVE) != 0) {
+      buf.append("native ");
+    }
+    if ((access & Constants.ACC_ABSTRACT) != 0) {
+      buf.append("abstract ");
+    }
+  }
+}
diff --git a/src/org/objectweb/asm/util/TraceCodeVisitor.java b/src/org/objectweb/asm/util/TraceCodeVisitor.java
new file mode 100644
index 0000000..223e06d
--- /dev/null
+++ b/src/org/objectweb/asm/util/TraceCodeVisitor.java
@@ -0,0 +1,324 @@
+/***
+ * ASM: a very small and fast Java bytecode manipulation framework
+ * Copyright (C) 2000 INRIA, France Telecom
+ * Copyright (C) 2002 France Telecom
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Contact: Eric.Bruneton@rd.francetelecom.com
+ *
+ * Author: Eric Bruneton
+ */
+
+package org.objectweb.asm.util;
+
+import org.objectweb.asm.CodeVisitor;
+import org.objectweb.asm.Label;
+
+import java.util.HashMap;
+
+/**
+ * A {@link PrintCodeVisitor PrintCodeVisitor} that prints a disassembled view
+ * of the code it visits.
+ */
+
+public class TraceCodeVisitor extends PrintCodeVisitor {
+
+  private final CodeVisitor cv;
+
+  private final HashMap labelNames;
+
+  /**
+   * Constructs a new {@link TraceCodeVisitor TraceCodeVisitor} object.
+   *
+   * @param cv the code visitor to which this adapter must delegate calls. May
+   *      be <tt>null</tt>.
+   */
+
+  public TraceCodeVisitor (final CodeVisitor cv) {
+    this.cv = cv;
+    this.labelNames = new HashMap();
+  }
+
+  public void printInsn (final int opcode) {
+    buf.append("    ")
+      .append(OPCODES[opcode])
+      .append("\n");
+
+    if (cv != null) {
+      cv.visitInsn(opcode);
+    }
+  }
+
+  public void printIntInsn (final int opcode, final int operand) {
+    buf.append("    ")
+      .append(OPCODES[opcode])
+      .append(" ").append(operand)
+      .append("\n");
+
+    if (cv != null) {
+      cv.visitIntInsn(opcode, operand);
+    }
+  }
+
+  public void printVarInsn (final int opcode, final int var) {
+    buf.append("    ")
+      .append(OPCODES[opcode])
+      .append(" ")
+      .append(var)
+      .append("\n");
+
+    if (cv != null) {
+      cv.visitVarInsn(opcode, var);
+    }
+  }
+
+  public void printTypeInsn (final int opcode, final String desc) {
+    buf.append("    ")
+      .append(OPCODES[opcode])
+      .append(" ")
+      .append(desc)
+      .append("\n");
+
+    if (cv != null) {
+      cv.visitTypeInsn(opcode, desc);
+    }
+  }
+
+  public void printFieldInsn (
+    final int opcode,
+    final String owner,
+    final String name,
+    final String desc)
+  {
+    buf.append("    ")
+      .append(OPCODES[opcode])
+      .append(" ")
+      .append(owner)
+      .append(" ")
+      .append(name)
+      .append(" ")
+      .append(desc)
+      .append("\n");
+
+    if (cv != null) {
+      cv.visitFieldInsn(opcode, owner, name, desc);
+    }
+  }
+
+  public void printMethodInsn (
+    final int opcode,
+    final String owner,
+    final String name,
+    final String desc)
+  {
+    buf.append("    ")
+      .append(OPCODES[opcode])
+      .append(" ")
+      .append(owner)
+      .append(" ")
+      .append(name)
+      .append(" ")
+      .append(desc)
+      .append("\n");
+
+    if (cv != null) {
+      cv.visitMethodInsn(opcode, owner, name, desc);
+    }
+  }
+
+  public void printJumpInsn (final int opcode, final Label label) {
+    buf.append("    ")
+      .append(OPCODES[opcode]).
+      append(" ");
+    appendLabel(label);
+    buf.append("\n");
+
+    if (cv != null) {
+      cv.visitJumpInsn(opcode, label);
+    }
+  }
+
+  public void printLabel (final Label label) {
+    buf.append("   ");
+    appendLabel(label);
+    buf.append(":\n");
+
+    if (cv != null) {
+      cv.visitLabel(label);
+    }
+  }
+
+  public void printLdcInsn (final Object cst) {
+    buf.append("    LDC ");
+    if (cst instanceof String) {
+      buf.append("\"").append(cst).append("\"");
+    } else {
+      buf.append(cst);
+    }
+    buf.append("\n");
+
+    if (cv != null) {
+      cv.visitLdcInsn(cst);
+    }
+  }
+
+  public void printIincInsn (final int var, final int increment) {
+    buf.append("    IINC ")
+      .append(var)
+      .append(" ")
+      .append(increment)
+      .append("\n");
+
+    if (cv != null) {
+      cv.visitIincInsn(var, increment);
+    }
+  }
+
+  public void printTableSwitchInsn (
+    final int min,
+    final int max,
+    final Label dflt,
+    final Label labels[])
+  {
+    buf.append("    TABLESWITCH\n");
+    for (int i = 0; i < labels.length; ++i) {
+      buf.append("      ")
+        .append(min + i)
+        .append(": ");
+      appendLabel(labels[i]);
+      buf.append("\n");
+    }
+    buf.append("      default: ");
+    appendLabel(dflt);
+    buf.append("\n");
+
+    if (cv != null) {
+      cv.visitTableSwitchInsn(min, max, dflt, labels);
+    }
+  }
+
+  public void printLookupSwitchInsn (
+    final Label dflt,
+    final int keys[],
+    final Label labels[])
+  {
+    buf.append("    LOOKUPSWITCH\n");
+    for (int i = 0; i < labels.length; ++i) {
+      buf.append("      ")
+        .append(keys[i])
+        .append(": ");
+      appendLabel(labels[i]);
+      buf.append("\n");
+    }
+    buf.append("      default: ");
+    appendLabel(dflt);
+    buf.append("\n");
+
+    if (cv != null) {
+      cv.visitLookupSwitchInsn(dflt, keys, labels);
+    }
+  }
+
+  public void printMultiANewArrayInsn (final String desc, final int dims) {
+    buf.append("    MULTIANEWARRAY ")
+      .append(desc)
+      .append(" ")
+      .append(dims)
+      .append("\n");
+
+    if (cv != null) {
+      cv.visitMultiANewArrayInsn(desc, dims);
+    }
+  }
+
+  public void printTryCatchBlock (
+    final Label start,
+    final Label end,
+    final Label handler,
+    final String type)
+  {
+    buf.append("    TRYCATCHBLOCK ");
+    appendLabel(start);
+    buf.append(" ");
+    appendLabel(end);
+    buf.append(" ");
+    appendLabel(handler);
+    buf.append(" ")
+      .append(type)
+      .append("\n");
+
+    if (cv != null) {
+      cv.visitTryCatchBlock(start, end, handler, type);
+    }
+  }
+
+  public void printMaxs (final int maxStack, final int maxLocals) {
+    buf.append("    MAXSTACK = ")
+      .append(maxStack)
+      .append("\n    MAXLOCALS = ")
+      .append(maxLocals)
+      .append("\n\n");
+
+    if (cv != null) {
+      cv.visitMaxs(maxStack, maxLocals);
+    }
+  }
+
+  public void printLocalVariable (
+    final String name,
+    final String desc,
+    final Label start,
+    final Label end,
+    final int index)
+  {
+    buf.append("    LOCALVARIABLE ")
+      .append(name)
+      .append(" ")
+      .append(desc)
+      .append(" ");
+    appendLabel(start);
+    buf.append(" ");
+    appendLabel(end);
+    buf.append(" ")
+      .append(index)
+      .append("\n");
+
+    if (cv != null) {
+      cv.visitLocalVariable(name, desc, start, end, index);
+    }
+  }
+
+  public void printLineNumber (final int line, final Label start) {
+    buf.append("    LINENUMBER ")
+      .append(line)
+      .append(" ");
+    appendLabel(start);
+    buf.append("\n");
+
+    if (cv != null) {
+      cv.visitLineNumber(line, start);
+    }
+  }
+
+  private void appendLabel (final Label l) {
+    String name = (String)labelNames.get(l);
+    if (name == null) {
+      name = "L" + labelNames.size();
+      labelNames.put(l, name);
+    }
+    buf.append(name);
+  }
+}
diff --git a/src/org/objectweb/asm/util/package.html b/src/org/objectweb/asm/util/package.html
new file mode 100644
index 0000000..93268ce
--- /dev/null
+++ b/src/org/objectweb/asm/util/package.html
@@ -0,0 +1,28 @@
+<html>
+<!--
+ * ASM: a very small and fast Java bytecode manipulation framework
+ * Copyright (C) 2000 INRIA, France Telecom
+ * Copyright (C) 2002 France Telecom
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Contact: Eric.Bruneton@rd.francetelecom.com
+ *
+ * Author: Eric Bruneton
+-->
+<body>
+Provides some useful ASM class visitors.
+</body>
+</html>