Added: tapestry/tapestry5/trunk/plastic/src/external/java/org/objectweb/asm/util/TraceClassVisitor.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/plastic/src/external/java/org/objectweb/asm/util/TraceClassVisitor.java?rev=1089584&view=auto ============================================================================== --- tapestry/tapestry5/trunk/plastic/src/external/java/org/objectweb/asm/util/TraceClassVisitor.java (added) +++ tapestry/tapestry5/trunk/plastic/src/external/java/org/objectweb/asm/util/TraceClassVisitor.java Wed Apr 6 19:11:34 2011 @@ -0,0 +1,523 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2007 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.util; + +import java.io.FileInputStream; +import java.io.PrintWriter; + +import org.objectweb.asm.AnnotationVisitor; +import org.objectweb.asm.Attribute; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.FieldVisitor; +import org.objectweb.asm.signature.SignatureReader; + +/** + * A {@link ClassVisitor} 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: <p> <blockquote> + * + * <pre> + * // class version 49.0 (49) + * // access flags 0x21 + * public class Hello { + * + * // compiled from: Hello.java + * + * // access flags 0x1 + * public <init> ()V + * ALOAD 0 + * INVOKESPECIAL java/lang/Object <init> ()V + * RETURN + * MAXSTACK = 1 + * MAXLOCALS = 1 + * + * // access flags 0x9 + * 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 + * } + * </pre> + * + * </blockquote> where <tt>Hello</tt> is defined by: <p> <blockquote> + * + * <pre> + * public class Hello { + * + * public static void main(String[] args) { + * System.out.println("hello"); + * } + * } + * </pre> + * + * </blockquote> + * + * @author Eric Bruneton + * @author Eugene Kuleshov + */ +public class TraceClassVisitor extends TraceAbstractVisitor implements + ClassVisitor +{ + + /** + * The {@link ClassVisitor} to which this visitor delegates calls. May be + * <tt>null</tt>. + */ + protected final ClassVisitor cv; + + /** + * The print writer to be used to print the class. + */ + protected final PrintWriter pw; + + /** + * Prints a disassembled view of the given class to the standard output. <p> + * Usage: TraceClassVisitor [-debug] <fully qualified class name or class + * file name > + * + * @param args the command line arguments. + * + * @throws Exception if the class cannot be found, or if an IO exception + * occurs. + */ + public static void main(final String[] args) throws Exception { + int i = 0; + int flags = ClassReader.SKIP_DEBUG; + + boolean ok = true; + if (args.length < 1 || args.length > 2) { + ok = false; + } + if (ok && "-debug".equals(args[0])) { + i = 1; + flags = 0; + if (args.length != 2) { + ok = false; + } + } + if (!ok) { + System.err.println("Prints a disassembled view of the given class."); + System.err.println("Usage: TraceClassVisitor [-debug] " + + "<fully qualified class name or class file name>"); + return; + } + ClassReader cr; + if (args[i].endsWith(".class") || args[i].indexOf('\\') > -1 + || args[i].indexOf('/') > -1) + { + cr = new ClassReader(new FileInputStream(args[i])); + } else { + cr = new ClassReader(args[i]); + } + cr.accept(new TraceClassVisitor(new PrintWriter(System.out)), + getDefaultAttributes(), + flags); + } + + /** + * Constructs a new {@link TraceClassVisitor}. + * + * @param pw the print writer to be used to print the class. + */ + public TraceClassVisitor(final PrintWriter pw) { + this(null, pw); + } + + /** + * Constructs a new {@link TraceClassVisitor}. + * + * @param cv the {@link ClassVisitor} to which this visitor delegates calls. + * May be <tt>null</tt>. + * @param pw the print writer to be used to print the class. + */ + public TraceClassVisitor(final ClassVisitor cv, final PrintWriter pw) { + this.cv = cv; + this.pw = pw; + } + + // ------------------------------------------------------------------------ + // Implementation of the ClassVisitor interface + // ------------------------------------------------------------------------ + + public void visit( + final int version, + final int access, + final String name, + final String signature, + final String superName, + final String[] interfaces) + { + int major = version & 0xFFFF; + int minor = version >>> 16; + buf.setLength(0); + buf.append("// class version ") + .append(major) + .append('.') + .append(minor) + .append(" (") + .append(version) + .append(")\n"); + if ((access & Opcodes.ACC_DEPRECATED) != 0) { + buf.append("// DEPRECATED\n"); + } + buf.append("// access flags 0x").append(Integer.toHexString(access).toUpperCase()).append('\n'); + + appendDescriptor(CLASS_SIGNATURE, signature); + if (signature != null) { + TraceSignatureVisitor sv = new TraceSignatureVisitor(access); + SignatureReader r = new SignatureReader(signature); + r.accept(sv); + buf.append("// declaration: ") + .append(name) + .append(sv.getDeclaration()) + .append('\n'); + } + + appendAccess(access & ~Opcodes.ACC_SUPER); + if ((access & Opcodes.ACC_ANNOTATION) != 0) { + buf.append("@interface "); + } else if ((access & Opcodes.ACC_INTERFACE) != 0) { + buf.append("interface "); + } else if ((access & Opcodes.ACC_ENUM) == 0) { + buf.append("class "); + } + appendDescriptor(INTERNAL_NAME, name); + + if (superName != null && !"java/lang/Object".equals(superName)) { + buf.append(" extends "); + appendDescriptor(INTERNAL_NAME, superName); + buf.append(' '); + } + if (interfaces != null && interfaces.length > 0) { + buf.append(" implements "); + for (int i = 0; i < interfaces.length; ++i) { + appendDescriptor(INTERNAL_NAME, interfaces[i]); + buf.append(' '); + } + } + buf.append(" {\n\n"); + + text.add(buf.toString()); + + if (cv != null) { + cv.visit(version, access, name, signature, superName, interfaces); + } + } + + public void visitSource(final String file, final String debug) { + buf.setLength(0); + if (file != null) { + buf.append(tab) + .append("// compiled from: ") + .append(file) + .append('\n'); + } + if (debug != null) { + buf.append(tab) + .append("// debug info: ") + .append(debug) + .append('\n'); + } + if (buf.length() > 0) { + text.add(buf.toString()); + } + + if (cv != null) { + cv.visitSource(file, debug); + } + } + + public void visitOuterClass( + final String owner, + final String name, + final String desc) + { + buf.setLength(0); + buf.append(tab).append("OUTERCLASS "); + appendDescriptor(INTERNAL_NAME, owner); + buf.append(' '); + if (name != null) { + buf.append(name).append(' '); + } + appendDescriptor(METHOD_DESCRIPTOR, desc); + buf.append('\n'); + text.add(buf.toString()); + + if (cv != null) { + cv.visitOuterClass(owner, name, desc); + } + } + + public AnnotationVisitor visitAnnotation( + final String desc, + final boolean visible) + { + text.add("\n"); + AnnotationVisitor tav = super.visitAnnotation(desc, visible); + if (cv != null) { + ((TraceAnnotationVisitor) tav).av = cv.visitAnnotation(desc, + visible); + } + return tav; + } + + public void visitAttribute(final Attribute attr) { + text.add("\n"); + super.visitAttribute(attr); + + if (cv != null) { + cv.visitAttribute(attr); + } + } + + public void visitInnerClass( + final String name, + final String outerName, + final String innerName, + final int access) + { + buf.setLength(0); + buf.append(tab).append("// access flags 0x"); + buf.append(Integer.toHexString(access & ~Opcodes.ACC_SUPER).toUpperCase()).append('\n'); + buf.append(tab); + appendAccess(access); + buf.append("INNERCLASS "); + appendDescriptor(INTERNAL_NAME, name); + buf.append(' '); + appendDescriptor(INTERNAL_NAME, outerName); + buf.append(' '); + appendDescriptor(INTERNAL_NAME, innerName); + buf.append('\n'); + text.add(buf.toString()); + + if (cv != null) { + cv.visitInnerClass(name, outerName, innerName, access); + } + } + + public FieldVisitor visitField( + final int access, + final String name, + final String desc, + final String signature, + final Object value) + { + buf.setLength(0); + buf.append('\n'); + if ((access & Opcodes.ACC_DEPRECATED) != 0) { + buf.append(tab).append("// DEPRECATED\n"); + } + buf.append(tab).append("// access flags 0x").append(Integer.toHexString(access).toUpperCase()).append('\n'); + if (signature != null) { + buf.append(tab); + appendDescriptor(FIELD_SIGNATURE, signature); + + TraceSignatureVisitor sv = new TraceSignatureVisitor(0); + SignatureReader r = new SignatureReader(signature); + r.acceptType(sv); + buf.append(tab) + .append("// declaration: ") + .append(sv.getDeclaration()) + .append('\n'); + } + + buf.append(tab); + appendAccess(access); + + appendDescriptor(FIELD_DESCRIPTOR, desc); + buf.append(' ').append(name); + if (value != null) { + buf.append(" = "); + if (value instanceof String) { + buf.append('\"').append(value).append('\"'); + } else { + buf.append(value); + } + } + + buf.append('\n'); + text.add(buf.toString()); + + TraceFieldVisitor tav = createTraceFieldVisitor(); + text.add(tav.getText()); + + if (cv != null) { + tav.fv = cv.visitField(access, name, desc, signature, value); + } + + return tav; + } + + public MethodVisitor visitMethod( + final int access, + final String name, + final String desc, + final String signature, + final String[] exceptions) + { + buf.setLength(0); + buf.append('\n'); + if ((access & Opcodes.ACC_DEPRECATED) != 0) { + buf.append(tab).append("// DEPRECATED\n"); + } + buf.append(tab).append("// access flags 0x").append(Integer.toHexString(access).toUpperCase()).append('\n'); + + if (signature != null) { + buf.append(tab); + appendDescriptor(METHOD_SIGNATURE, signature); + + TraceSignatureVisitor v = new TraceSignatureVisitor(0); + SignatureReader r = new SignatureReader(signature); + r.accept(v); + String genericDecl = v.getDeclaration(); + String genericReturn = v.getReturnType(); + String genericExceptions = v.getExceptions(); + + buf.append(tab) + .append("// declaration: ") + .append(genericReturn) + .append(' ') + .append(name) + .append(genericDecl); + if (genericExceptions != null) { + buf.append(" throws ").append(genericExceptions); + } + buf.append('\n'); + } + + buf.append(tab); + appendAccess(access); + if ((access & Opcodes.ACC_NATIVE) != 0) { + buf.append("native "); + } + if ((access & Opcodes.ACC_VARARGS) != 0) { + buf.append("varargs "); + } + if ((access & Opcodes.ACC_BRIDGE) != 0) { + buf.append("bridge "); + } + + buf.append(name); + appendDescriptor(METHOD_DESCRIPTOR, desc); + if (exceptions != null && exceptions.length > 0) { + buf.append(" throws "); + for (int i = 0; i < exceptions.length; ++i) { + appendDescriptor(INTERNAL_NAME, exceptions[i]); + buf.append(' '); + } + } + + buf.append('\n'); + text.add(buf.toString()); + + TraceMethodVisitor tcv = createTraceMethodVisitor(); + text.add(tcv.getText()); + + if (cv != null) { + tcv.mv = cv.visitMethod(access, name, desc, signature, exceptions); + } + + return tcv; + } + + public void visitEnd() { + text.add("}\n"); + + print(pw); + pw.flush(); + + if (cv != null) { + cv.visitEnd(); + } + } + + // ------------------------------------------------------------------------ + // Utility methods + // ------------------------------------------------------------------------ + + protected TraceFieldVisitor createTraceFieldVisitor() { + return new TraceFieldVisitor(); + } + + protected TraceMethodVisitor createTraceMethodVisitor() { + return new TraceMethodVisitor(); + } + + /** + * Appends a string representation of the given access modifiers to {@link + * #buf buf}. + * + * @param access some access modifiers. + */ + private void appendAccess(final int access) { + if ((access & Opcodes.ACC_PUBLIC) != 0) { + buf.append("public "); + } + if ((access & Opcodes.ACC_PRIVATE) != 0) { + buf.append("private "); + } + if ((access & Opcodes.ACC_PROTECTED) != 0) { + buf.append("protected "); + } + if ((access & Opcodes.ACC_FINAL) != 0) { + buf.append("final "); + } + if ((access & Opcodes.ACC_STATIC) != 0) { + buf.append("static "); + } + if ((access & Opcodes.ACC_SYNCHRONIZED) != 0) { + buf.append("synchronized "); + } + if ((access & Opcodes.ACC_VOLATILE) != 0) { + buf.append("volatile "); + } + if ((access & Opcodes.ACC_TRANSIENT) != 0) { + buf.append("transient "); + } + if ((access & Opcodes.ACC_ABSTRACT) != 0) { + buf.append("abstract "); + } + if ((access & Opcodes.ACC_STRICT) != 0) { + buf.append("strictfp "); + } + if ((access & Opcodes.ACC_ENUM) != 0) { + buf.append("enum "); + } + } +}
Added: tapestry/tapestry5/trunk/plastic/src/external/java/org/objectweb/asm/util/TraceFieldVisitor.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/plastic/src/external/java/org/objectweb/asm/util/TraceFieldVisitor.java?rev=1089584&view=auto ============================================================================== --- tapestry/tapestry5/trunk/plastic/src/external/java/org/objectweb/asm/util/TraceFieldVisitor.java (added) +++ tapestry/tapestry5/trunk/plastic/src/external/java/org/objectweb/asm/util/TraceFieldVisitor.java Wed Apr 6 19:11:34 2011 @@ -0,0 +1,78 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2007 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.util; + +import org.objectweb.asm.AnnotationVisitor; +import org.objectweb.asm.Attribute; +import org.objectweb.asm.FieldVisitor; + +/** + * A {@link FieldVisitor} that prints a disassembled view of the fields it + * visits. + * + * @author Eric Bruneton + */ +public class TraceFieldVisitor extends TraceAbstractVisitor implements + FieldVisitor +{ + + /** + * The {@link FieldVisitor} to which this visitor delegates calls. May be + * <tt>null</tt>. + */ + protected FieldVisitor fv; + + public AnnotationVisitor visitAnnotation( + final String desc, + final boolean visible) + { + AnnotationVisitor av = super.visitAnnotation(desc, visible); + if (fv != null) { + ((TraceAnnotationVisitor) av).av = fv.visitAnnotation(desc, visible); + } + return av; + } + + public void visitAttribute(final Attribute attr) { + super.visitAttribute(attr); + + if (fv != null) { + fv.visitAttribute(attr); + } + } + + public void visitEnd() { + super.visitEnd(); + + if (fv != null) { + fv.visitEnd(); + } + } +} Added: tapestry/tapestry5/trunk/plastic/src/external/java/org/objectweb/asm/util/TraceMethodVisitor.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/plastic/src/external/java/org/objectweb/asm/util/TraceMethodVisitor.java?rev=1089584&view=auto ============================================================================== --- tapestry/tapestry5/trunk/plastic/src/external/java/org/objectweb/asm/util/TraceMethodVisitor.java (added) +++ tapestry/tapestry5/trunk/plastic/src/external/java/org/objectweb/asm/util/TraceMethodVisitor.java Wed Apr 6 19:11:34 2011 @@ -0,0 +1,567 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2007 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.util; + +import org.objectweb.asm.AnnotationVisitor; +import org.objectweb.asm.Attribute; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Label; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.Type; +import org.objectweb.asm.signature.SignatureReader; + +import java.util.HashMap; +import java.util.Map; + +/** + * A {@link MethodVisitor} that prints a disassembled view of the methods it + * visits. + * + * @author Eric Bruneton + */ +public class TraceMethodVisitor extends TraceAbstractVisitor implements + MethodVisitor +{ + + /** + * The {@link MethodVisitor} to which this visitor delegates calls. May be + * <tt>null</tt>. + */ + protected MethodVisitor mv; + + /** + * Tab for bytecode instructions. + */ + protected String tab2 = " "; + + /** + * Tab for table and lookup switch instructions. + */ + protected String tab3 = " "; + + /** + * Tab for labels. + */ + protected String ltab = " "; + + /** + * The label names. This map associate String values to Label keys. + */ + protected final Map labelNames; + + /** + * Constructs a new {@link TraceMethodVisitor}. + */ + public TraceMethodVisitor() { + this(null); + } + + /** + * Constructs a new {@link TraceMethodVisitor}. + * + * @param mv the {@link MethodVisitor} to which this visitor delegates + * calls. May be <tt>null</tt>. + */ + public TraceMethodVisitor(final MethodVisitor mv) { + this.labelNames = new HashMap(); + this.mv = mv; + } + + // ------------------------------------------------------------------------ + // Implementation of the MethodVisitor interface + // ------------------------------------------------------------------------ + + public AnnotationVisitor visitAnnotation( + final String desc, + final boolean visible) + { + AnnotationVisitor av = super.visitAnnotation(desc, visible); + if (mv != null) { + ((TraceAnnotationVisitor) av).av = mv.visitAnnotation(desc, visible); + } + return av; + } + + public void visitAttribute(final Attribute attr) { + buf.setLength(0); + buf.append(tab).append("ATTRIBUTE "); + appendDescriptor(-1, attr.type); + + if (attr instanceof Traceable) { + ((Traceable) attr).trace(buf, labelNames); + } else { + buf.append(" : unknown\n"); + } + + text.add(buf.toString()); + if (mv != null) { + mv.visitAttribute(attr); + } + } + + public AnnotationVisitor visitAnnotationDefault() { + text.add(tab2 + "default="); + TraceAnnotationVisitor tav = createTraceAnnotationVisitor(); + text.add(tav.getText()); + text.add("\n"); + if (mv != null) { + tav.av = mv.visitAnnotationDefault(); + } + return tav; + } + + public AnnotationVisitor visitParameterAnnotation( + final int parameter, + final String desc, + final boolean visible) + { + buf.setLength(0); + buf.append(tab2).append('@'); + appendDescriptor(FIELD_DESCRIPTOR, desc); + buf.append('('); + text.add(buf.toString()); + TraceAnnotationVisitor tav = createTraceAnnotationVisitor(); + text.add(tav.getText()); + text.add(visible ? ") // parameter " : ") // invisible, parameter "); + text.add(new Integer(parameter)); + text.add("\n"); + if (mv != null) { + tav.av = mv.visitParameterAnnotation(parameter, desc, visible); + } + return tav; + } + + public void visitCode() { + if (mv != null) { + mv.visitCode(); + } + } + + public void visitFrame( + final int type, + final int nLocal, + final Object[] local, + final int nStack, + final Object[] stack) + { + buf.setLength(0); + buf.append(ltab); + buf.append("FRAME "); + switch (type) { + case Opcodes.F_NEW: + case Opcodes.F_FULL: + buf.append("FULL ["); + appendFrameTypes(nLocal, local); + buf.append("] ["); + appendFrameTypes(nStack, stack); + buf.append(']'); + break; + case Opcodes.F_APPEND: + buf.append("APPEND ["); + appendFrameTypes(nLocal, local); + buf.append(']'); + break; + case Opcodes.F_CHOP: + buf.append("CHOP ").append(nLocal); + break; + case Opcodes.F_SAME: + buf.append("SAME"); + break; + case Opcodes.F_SAME1: + buf.append("SAME1 "); + appendFrameTypes(1, stack); + break; + } + buf.append('\n'); + text.add(buf.toString()); + + if (mv != null) { + mv.visitFrame(type, nLocal, local, nStack, stack); + } + } + + public void visitInsn(final int opcode) { + buf.setLength(0); + buf.append(tab2).append(OPCODES[opcode]).append('\n'); + text.add(buf.toString()); + + if (mv != null) { + mv.visitInsn(opcode); + } + } + + public void visitIntInsn(final int opcode, final int operand) { + buf.setLength(0); + buf.append(tab2) + .append(OPCODES[opcode]) + .append(' ') + .append(opcode == Opcodes.NEWARRAY + ? TYPES[operand] + : Integer.toString(operand)) + .append('\n'); + text.add(buf.toString()); + + if (mv != null) { + mv.visitIntInsn(opcode, operand); + } + } + + public void visitVarInsn(final int opcode, final int var) { + buf.setLength(0); + buf.append(tab2) + .append(OPCODES[opcode]) + .append(' ') + .append(var) + .append('\n'); + text.add(buf.toString()); + + if (mv != null) { + mv.visitVarInsn(opcode, var); + } + } + + public void visitTypeInsn(final int opcode, final String type) { + buf.setLength(0); + buf.append(tab2).append(OPCODES[opcode]).append(' '); + appendDescriptor(INTERNAL_NAME, type); + buf.append('\n'); + text.add(buf.toString()); + + if (mv != null) { + mv.visitTypeInsn(opcode, type); + } + } + + public void visitFieldInsn( + final int opcode, + final String owner, + final String name, + final String desc) + { + buf.setLength(0); + buf.append(tab2).append(OPCODES[opcode]).append(' '); + appendDescriptor(INTERNAL_NAME, owner); + buf.append('.').append(name).append(" : "); + appendDescriptor(FIELD_DESCRIPTOR, desc); + buf.append('\n'); + text.add(buf.toString()); + + if (mv != null) { + mv.visitFieldInsn(opcode, owner, name, desc); + } + } + + public void visitMethodInsn( + final int opcode, + final String owner, + final String name, + final String desc) + { + buf.setLength(0); + buf.append(tab2).append(OPCODES[opcode]).append(' '); + appendDescriptor(INTERNAL_NAME, owner); + buf.append('.').append(name).append(' '); + appendDescriptor(METHOD_DESCRIPTOR, desc); + buf.append('\n'); + text.add(buf.toString()); + + if (mv != null) { + mv.visitMethodInsn(opcode, owner, name, desc); + } + } + + public void visitJumpInsn(final int opcode, final Label label) { + buf.setLength(0); + buf.append(tab2).append(OPCODES[opcode]).append(' '); + appendLabel(label); + buf.append('\n'); + text.add(buf.toString()); + + if (mv != null) { + mv.visitJumpInsn(opcode, label); + } + } + + public void visitLabel(final Label label) { + buf.setLength(0); + buf.append(ltab); + appendLabel(label); + buf.append('\n'); + text.add(buf.toString()); + + if (mv != null) { + mv.visitLabel(label); + } + } + + public void visitLdcInsn(final Object cst) { + buf.setLength(0); + buf.append(tab2).append("LDC "); + if (cst instanceof String) { + AbstractVisitor.appendString(buf, (String) cst); + } else if (cst instanceof Type) { + buf.append(((Type) cst).getDescriptor()).append(".class"); + } else { + buf.append(cst); + } + buf.append('\n'); + text.add(buf.toString()); + + if (mv != null) { + mv.visitLdcInsn(cst); + } + } + + public void visitIincInsn(final int var, final int increment) { + buf.setLength(0); + buf.append(tab2) + .append("IINC ") + .append(var) + .append(' ') + .append(increment) + .append('\n'); + text.add(buf.toString()); + + if (mv != null) { + mv.visitIincInsn(var, increment); + } + } + + public void visitTableSwitchInsn( + final int min, + final int max, + final Label dflt, + final Label[] labels) + { + buf.setLength(0); + buf.append(tab2).append("TABLESWITCH\n"); + for (int i = 0; i < labels.length; ++i) { + buf.append(tab3).append(min + i).append(": "); + appendLabel(labels[i]); + buf.append('\n'); + } + buf.append(tab3).append("default: "); + appendLabel(dflt); + buf.append('\n'); + text.add(buf.toString()); + + if (mv != null) { + mv.visitTableSwitchInsn(min, max, dflt, labels); + } + } + + public void visitLookupSwitchInsn( + final Label dflt, + final int[] keys, + final Label[] labels) + { + buf.setLength(0); + buf.append(tab2).append("LOOKUPSWITCH\n"); + for (int i = 0; i < labels.length; ++i) { + buf.append(tab3).append(keys[i]).append(": "); + appendLabel(labels[i]); + buf.append('\n'); + } + buf.append(tab3).append("default: "); + appendLabel(dflt); + buf.append('\n'); + text.add(buf.toString()); + + if (mv != null) { + mv.visitLookupSwitchInsn(dflt, keys, labels); + } + } + + public void visitMultiANewArrayInsn(final String desc, final int dims) { + buf.setLength(0); + buf.append(tab2).append("MULTIANEWARRAY "); + appendDescriptor(FIELD_DESCRIPTOR, desc); + buf.append(' ').append(dims).append('\n'); + text.add(buf.toString()); + + if (mv != null) { + mv.visitMultiANewArrayInsn(desc, dims); + } + } + + public void visitTryCatchBlock( + final Label start, + final Label end, + final Label handler, + final String type) + { + buf.setLength(0); + buf.append(tab2).append("TRYCATCHBLOCK "); + appendLabel(start); + buf.append(' '); + appendLabel(end); + buf.append(' '); + appendLabel(handler); + buf.append(' '); + appendDescriptor(INTERNAL_NAME, type); + buf.append('\n'); + text.add(buf.toString()); + + if (mv != null) { + mv.visitTryCatchBlock(start, end, handler, type); + } + } + + public void visitLocalVariable( + final String name, + final String desc, + final String signature, + final Label start, + final Label end, + final int index) + { + buf.setLength(0); + buf.append(tab2).append("LOCALVARIABLE ").append(name).append(' '); + appendDescriptor(FIELD_DESCRIPTOR, desc); + buf.append(' '); + appendLabel(start); + buf.append(' '); + appendLabel(end); + buf.append(' ').append(index).append('\n'); + + if (signature != null) { + buf.append(tab2); + appendDescriptor(FIELD_SIGNATURE, signature); + + TraceSignatureVisitor sv = new TraceSignatureVisitor(0); + SignatureReader r = new SignatureReader(signature); + r.acceptType(sv); + buf.append(tab2) + .append("// declaration: ") + .append(sv.getDeclaration()) + .append('\n'); + } + text.add(buf.toString()); + + if (mv != null) { + mv.visitLocalVariable(name, desc, signature, start, end, index); + } + } + + public void visitLineNumber(final int line, final Label start) { + buf.setLength(0); + buf.append(tab2).append("LINENUMBER ").append(line).append(' '); + appendLabel(start); + buf.append('\n'); + text.add(buf.toString()); + + if (mv != null) { + mv.visitLineNumber(line, start); + } + } + + public void visitMaxs(final int maxStack, final int maxLocals) { + buf.setLength(0); + buf.append(tab2).append("MAXSTACK = ").append(maxStack).append('\n'); + text.add(buf.toString()); + + buf.setLength(0); + buf.append(tab2).append("MAXLOCALS = ").append(maxLocals).append('\n'); + text.add(buf.toString()); + + if (mv != null) { + mv.visitMaxs(maxStack, maxLocals); + } + } + + public void visitEnd() { + super.visitEnd(); + + if (mv != null) { + mv.visitEnd(); + } + } + + // ------------------------------------------------------------------------ + // Utility methods + // ------------------------------------------------------------------------ + + private void appendFrameTypes(final int n, final Object[] o) { + for (int i = 0; i < n; ++i) { + if (i > 0) { + buf.append(' '); + } + if (o[i] instanceof String) { + String desc = (String) o[i]; + if (desc.startsWith("[")) { + appendDescriptor(FIELD_DESCRIPTOR, desc); + } else { + appendDescriptor(INTERNAL_NAME, desc); + } + } else if (o[i] instanceof Integer) { + switch (((Integer) o[i]).intValue()) { + case 0: + appendDescriptor(FIELD_DESCRIPTOR, "T"); + break; + case 1: + appendDescriptor(FIELD_DESCRIPTOR, "I"); + break; + case 2: + appendDescriptor(FIELD_DESCRIPTOR, "F"); + break; + case 3: + appendDescriptor(FIELD_DESCRIPTOR, "D"); + break; + case 4: + appendDescriptor(FIELD_DESCRIPTOR, "J"); + break; + case 5: + appendDescriptor(FIELD_DESCRIPTOR, "N"); + break; + case 6: + appendDescriptor(FIELD_DESCRIPTOR, "U"); + break; + } + } else { + appendLabel((Label) o[i]); + } + } + } + + /** + * Appends the name of the given label to {@link #buf buf}. Creates a new + * label name if the given label does not yet have one. + * + * @param l a label. + */ + protected 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); + } +} Added: tapestry/tapestry5/trunk/plastic/src/external/java/org/objectweb/asm/util/TraceSignatureVisitor.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/plastic/src/external/java/org/objectweb/asm/util/TraceSignatureVisitor.java?rev=1089584&view=auto ============================================================================== --- tapestry/tapestry5/trunk/plastic/src/external/java/org/objectweb/asm/util/TraceSignatureVisitor.java (added) +++ tapestry/tapestry5/trunk/plastic/src/external/java/org/objectweb/asm/util/TraceSignatureVisitor.java Wed Apr 6 19:11:34 2011 @@ -0,0 +1,300 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2007 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.util; + +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.signature.SignatureVisitor; + +/** + * A {@link SignatureVisitor} that prints a disassembled view of the signature + * it visits. + * + * @author Eugene Kuleshov + * @author Eric Bruneton + */ +public class TraceSignatureVisitor implements SignatureVisitor { + + private final StringBuffer declaration; + + private boolean isInterface; + + private boolean seenFormalParameter; + + private boolean seenInterfaceBound; + + private boolean seenParameter; + + private boolean seenInterface; + + private StringBuffer returnType; + + private StringBuffer exceptions; + + /** + * Stack used to keep track of class types that have arguments. Each element + * of this stack is a boolean encoded in one bit. The top of the stack is + * the lowest order bit. Pushing false = *2, pushing true = *2+1, popping = + * /2. + */ + private int argumentStack; + + /** + * Stack used to keep track of array class types. Each element of this stack + * is a boolean encoded in one bit. The top of the stack is the lowest order + * bit. Pushing false = *2, pushing true = *2+1, popping = /2. + */ + private int arrayStack; + + private String separator = ""; + + public TraceSignatureVisitor(final int access) { + isInterface = (access & Opcodes.ACC_INTERFACE) != 0; + this.declaration = new StringBuffer(); + } + + private TraceSignatureVisitor(final StringBuffer buf) { + this.declaration = buf; + } + + public void visitFormalTypeParameter(final String name) { + declaration.append(seenFormalParameter ? ", " : "<").append(name); + seenFormalParameter = true; + seenInterfaceBound = false; + } + + public SignatureVisitor visitClassBound() { + separator = " extends "; + startType(); + return this; + } + + public SignatureVisitor visitInterfaceBound() { + separator = seenInterfaceBound ? ", " : " extends "; + seenInterfaceBound = true; + startType(); + return this; + } + + public SignatureVisitor visitSuperclass() { + endFormals(); + separator = " extends "; + startType(); + return this; + } + + public SignatureVisitor visitInterface() { + separator = seenInterface ? ", " : isInterface + ? " extends " + : " implements "; + seenInterface = true; + startType(); + return this; + } + + public SignatureVisitor visitParameterType() { + endFormals(); + if (seenParameter) { + declaration.append(", "); + } else { + seenParameter = true; + declaration.append('('); + } + startType(); + return this; + } + + public SignatureVisitor visitReturnType() { + endFormals(); + if (seenParameter) { + seenParameter = false; + } else { + declaration.append('('); + } + declaration.append(')'); + returnType = new StringBuffer(); + return new TraceSignatureVisitor(returnType); + } + + public SignatureVisitor visitExceptionType() { + if (exceptions == null) { + exceptions = new StringBuffer(); + } else { + exceptions.append(", "); + } + // startType(); + return new TraceSignatureVisitor(exceptions); + } + + public void visitBaseType(final char descriptor) { + switch (descriptor) { + case 'V': + declaration.append("void"); + break; + case 'B': + declaration.append("byte"); + break; + case 'J': + declaration.append("long"); + break; + case 'Z': + declaration.append("boolean"); + break; + case 'I': + declaration.append("int"); + break; + case 'S': + declaration.append("short"); + break; + case 'C': + declaration.append("char"); + break; + case 'F': + declaration.append("float"); + break; + // case 'D': + default: + declaration.append("double"); + break; + } + endType(); + } + + public void visitTypeVariable(final String name) { + declaration.append(name); + endType(); + } + + public SignatureVisitor visitArrayType() { + startType(); + arrayStack |= 1; + return this; + } + + public void visitClassType(final String name) { + if ("java/lang/Object".equals(name)) { + // Map<java.lang.Object,java.util.List> + // or + // abstract public V get(Object key); (seen in Dictionary.class) + // should have Object + // but java.lang.String extends java.lang.Object is unnecessary + boolean needObjectClass = argumentStack % 2 != 0 || seenParameter; + if (needObjectClass) { + declaration.append(separator).append(name.replace('/', '.')); + } + } else { + declaration.append(separator).append(name.replace('/', '.')); + } + separator = ""; + argumentStack *= 2; + } + + public void visitInnerClassType(final String name) { + if (argumentStack % 2 != 0) { + declaration.append('>'); + } + argumentStack /= 2; + declaration.append('.'); + declaration.append(separator).append(name.replace('/', '.')); + separator = ""; + argumentStack *= 2; + } + + public void visitTypeArgument() { + if (argumentStack % 2 == 0) { + ++argumentStack; + declaration.append('<'); + } else { + declaration.append(", "); + } + declaration.append('?'); + } + + public SignatureVisitor visitTypeArgument(final char tag) { + if (argumentStack % 2 == 0) { + ++argumentStack; + declaration.append('<'); + } else { + declaration.append(", "); + } + + if (tag == EXTENDS) { + declaration.append("? extends "); + } else if (tag == SUPER) { + declaration.append("? super "); + } + + startType(); + return this; + } + + public void visitEnd() { + if (argumentStack % 2 != 0) { + declaration.append('>'); + } + argumentStack /= 2; + endType(); + } + + public String getDeclaration() { + return declaration.toString(); + } + + public String getReturnType() { + return returnType == null ? null : returnType.toString(); + } + + public String getExceptions() { + return exceptions == null ? null : exceptions.toString(); + } + + // ----------------------------------------------- + + private void endFormals() { + if (seenFormalParameter) { + declaration.append('>'); + seenFormalParameter = false; + } + } + + private void startType() { + arrayStack *= 2; + } + + private void endType() { + if (arrayStack % 2 == 0) { + arrayStack /= 2; + } else { + while (arrayStack % 2 != 0) { + arrayStack /= 2; + declaration.append("[]"); + } + } + } +} Added: tapestry/tapestry5/trunk/plastic/src/external/java/org/objectweb/asm/util/Traceable.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/plastic/src/external/java/org/objectweb/asm/util/Traceable.java?rev=1089584&view=auto ============================================================================== --- tapestry/tapestry5/trunk/plastic/src/external/java/org/objectweb/asm/util/Traceable.java (added) +++ tapestry/tapestry5/trunk/plastic/src/external/java/org/objectweb/asm/util/Traceable.java Wed Apr 6 19:11:34 2011 @@ -0,0 +1,52 @@ +/** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2007 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.util; + +import java.util.Map; + +/** + * An attribute that can print eadable representation of the attribute. + * + * Implementation should construct readable output from an attribute data + * structures for current attribute state. Such representation could be used in + * unit test assertions. + * + * @author Eugene Kuleshov + */ +public interface Traceable { + + /** + * Build a human readable representation of the attribute. + * + * @param buf A buffer used for printing Java code. + * @param labelNames map of label instances to their names. + */ + void trace(StringBuffer buf, Map labelNames); +} Added: tapestry/tapestry5/trunk/plastic/src/external/java/org/objectweb/asm/util/package.html URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/plastic/src/external/java/org/objectweb/asm/util/package.html?rev=1089584&view=auto ============================================================================== --- tapestry/tapestry5/trunk/plastic/src/external/java/org/objectweb/asm/util/package.html (added) +++ tapestry/tapestry5/trunk/plastic/src/external/java/org/objectweb/asm/util/package.html Wed Apr 6 19:11:34 2011 @@ -0,0 +1,40 @@ +<html> +<!-- + * 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. +--> +<body> +Provides ASM visitors that can be useful for programming and +debugging purposes. These class visitors are normally not used by applications +at runtime. This is why they are bundled in an optional <tt>asm-util.jar</tt> +library that is separated from (but requires) the <tt>asm.jar</tt> library, +which contains the core ASM framework. + +@since ASM 1.3.2 +</body> +</html>
