You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tapestry.apache.org by ka...@apache.org on 2014/03/25 19:30:00 UTC

[12/23] FIXED - TAP5-2214: Make tapestry5 java8 compatible - update ASM source to 5.0.1, should be jdk 1.5 compatible, see ASM bug "317132 ASM 5.0 do not supported JDK 1.5?"

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/a0ac605d/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/optimizer/ClassConstantsCollector.java
----------------------------------------------------------------------
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/optimizer/ClassConstantsCollector.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/optimizer/ClassConstantsCollector.java
new file mode 100644
index 0000000..b907322
--- /dev/null
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/optimizer/ClassConstantsCollector.java
@@ -0,0 +1,198 @@
+/***
+ * ASM: a very small and fast Java bytecode manipulation framework
+ * Copyright (c) 2000-2011 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.apache.tapestry5.internal.plastic.asm.optimizer;
+
+import org.apache.tapestry5.internal.plastic.asm.AnnotationVisitor;
+import org.apache.tapestry5.internal.plastic.asm.Attribute;
+import org.apache.tapestry5.internal.plastic.asm.ClassVisitor;
+import org.apache.tapestry5.internal.plastic.asm.FieldVisitor;
+import org.apache.tapestry5.internal.plastic.asm.MethodVisitor;
+import org.apache.tapestry5.internal.plastic.asm.Opcodes;
+import org.apache.tapestry5.internal.plastic.asm.TypePath;
+
+/**
+ * A {@link ClassVisitor} that collects the {@link Constant}s of the classes it
+ * visits.
+ * 
+ * @author Eric Bruneton
+ */
+public class ClassConstantsCollector extends ClassVisitor {
+
+    private final ConstantPool cp;
+
+    public ClassConstantsCollector(final ClassVisitor cv, final ConstantPool cp) {
+        super(Opcodes.ASM5, cv);
+        this.cp = cp;
+    }
+
+    @Override
+    public void visit(final int version, final int access, final String name,
+            final String signature, final String superName,
+            final String[] interfaces) {
+        if ((access & Opcodes.ACC_DEPRECATED) != 0) {
+            cp.newUTF8("Deprecated");
+        }
+        if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
+            cp.newUTF8("Synthetic");
+        }
+        cp.newClass(name);
+        if (signature != null) {
+            cp.newUTF8("Signature");
+            cp.newUTF8(signature);
+        }
+        if (superName != null) {
+            cp.newClass(superName);
+        }
+        if (interfaces != null) {
+            for (int i = 0; i < interfaces.length; ++i) {
+                cp.newClass(interfaces[i]);
+            }
+        }
+        cv.visit(version, access, name, signature, superName, interfaces);
+    }
+
+    @Override
+    public void visitSource(final String source, final String debug) {
+        if (source != null) {
+            cp.newUTF8("SourceFile");
+            cp.newUTF8(source);
+        }
+        if (debug != null) {
+            cp.newUTF8("SourceDebugExtension");
+        }
+        cv.visitSource(source, debug);
+    }
+
+    @Override
+    public void visitOuterClass(final String owner, final String name,
+            final String desc) {
+        cp.newUTF8("EnclosingMethod");
+        cp.newClass(owner);
+        if (name != null && desc != null) {
+            cp.newNameType(name, desc);
+        }
+        cv.visitOuterClass(owner, name, desc);
+    }
+
+    @Override
+    public AnnotationVisitor visitAnnotation(final String desc,
+            final boolean visible) {
+        cp.newUTF8(desc);
+        if (visible) {
+            cp.newUTF8("RuntimeVisibleAnnotations");
+        } else {
+            cp.newUTF8("RuntimeInvisibleAnnotations");
+        }
+        return new AnnotationConstantsCollector(cv.visitAnnotation(desc,
+                visible), cp);
+    }
+
+    @Override
+    public AnnotationVisitor visitTypeAnnotation(int typeRef,
+            TypePath typePath, String desc, boolean visible) {
+        cp.newUTF8(desc);
+        if (visible) {
+            cp.newUTF8("RuntimeVisibleTypeAnnotations");
+        } else {
+            cp.newUTF8("RuntimeInvisibleTypeAnnotations");
+        }
+        return new AnnotationConstantsCollector(cv.visitAnnotation(desc,
+                visible), cp);
+    }
+
+    @Override
+    public void visitAttribute(final Attribute attr) {
+        // can do nothing
+        cv.visitAttribute(attr);
+    }
+
+    @Override
+    public void visitInnerClass(final String name, final String outerName,
+            final String innerName, final int access) {
+        cp.newUTF8("InnerClasses");
+        if (name != null) {
+            cp.newClass(name);
+        }
+        if (outerName != null) {
+            cp.newClass(outerName);
+        }
+        if (innerName != null) {
+            cp.newUTF8(innerName);
+        }
+        cv.visitInnerClass(name, outerName, innerName, access);
+    }
+
+    @Override
+    public FieldVisitor visitField(final int access, final String name,
+            final String desc, final String signature, final Object value) {
+        if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
+            cp.newUTF8("Synthetic");
+        }
+        if ((access & Opcodes.ACC_DEPRECATED) != 0) {
+            cp.newUTF8("Deprecated");
+        }
+        cp.newUTF8(name);
+        cp.newUTF8(desc);
+        if (signature != null) {
+            cp.newUTF8("Signature");
+            cp.newUTF8(signature);
+        }
+        if (value != null) {
+            cp.newConst(value);
+        }
+        return new FieldConstantsCollector(cv.visitField(access, name, desc,
+                signature, value), cp);
+    }
+
+    @Override
+    public MethodVisitor visitMethod(final int access, final String name,
+            final String desc, final String signature, final String[] exceptions) {
+        if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
+            cp.newUTF8("Synthetic");
+        }
+        if ((access & Opcodes.ACC_DEPRECATED) != 0) {
+            cp.newUTF8("Deprecated");
+        }
+        cp.newUTF8(name);
+        cp.newUTF8(desc);
+        if (signature != null) {
+            cp.newUTF8("Signature");
+            cp.newUTF8(signature);
+        }
+        if (exceptions != null) {
+            cp.newUTF8("Exceptions");
+            for (int i = 0; i < exceptions.length; ++i) {
+                cp.newClass(exceptions[i]);
+            }
+        }
+        return new MethodConstantsCollector(cv.visitMethod(access, name, desc,
+                signature, exceptions), cp);
+    }
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/a0ac605d/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/optimizer/ClassOptimizer.java
----------------------------------------------------------------------
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/optimizer/ClassOptimizer.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/optimizer/ClassOptimizer.java
new file mode 100644
index 0000000..f4a7a22
--- /dev/null
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/optimizer/ClassOptimizer.java
@@ -0,0 +1,260 @@
+/***
+ * ASM: a very small and fast Java bytecode manipulation framework
+ * Copyright (c) 2000-2011 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.apache.tapestry5.internal.plastic.asm.optimizer;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.tapestry5.internal.plastic.asm.AnnotationVisitor;
+import org.apache.tapestry5.internal.plastic.asm.Attribute;
+import org.apache.tapestry5.internal.plastic.asm.ClassVisitor;
+import org.apache.tapestry5.internal.plastic.asm.FieldVisitor;
+import org.apache.tapestry5.internal.plastic.asm.Label;
+import org.apache.tapestry5.internal.plastic.asm.MethodVisitor;
+import org.apache.tapestry5.internal.plastic.asm.Opcodes;
+import org.apache.tapestry5.internal.plastic.asm.TypePath;
+import org.apache.tapestry5.internal.plastic.asm.commons.Remapper;
+import org.apache.tapestry5.internal.plastic.asm.commons.RemappingClassAdapter;
+
+/**
+ * A {@link ClassVisitor} that renames fields and methods, and removes debug
+ * info.
+ * 
+ * @author Eric Bruneton
+ * @author Eugene Kuleshov
+ */
+public class ClassOptimizer extends RemappingClassAdapter {
+
+    private String pkgName;
+    String clsName;
+
+    boolean isInterface = false;
+    boolean hasClinitMethod = false;
+    List<String> syntheticClassFields = new ArrayList<String>();
+
+    public ClassOptimizer(final ClassVisitor cv, final Remapper remapper) {
+        super(Opcodes.ASM5, cv, remapper);
+    }
+
+    FieldVisitor syntheticFieldVisitor(final int access, final String name,
+            final String desc) {
+        return super.visitField(access, name, desc, null, null);
+    }
+
+    // ------------------------------------------------------------------------
+    // Overridden methods
+    // ------------------------------------------------------------------------
+
+    @Override
+    public void visit(final int version, final int access, final String name,
+            final String signature, final String superName,
+            final String[] interfaces) {
+        super.visit(Opcodes.V1_2, access, name, null, superName, interfaces);
+        int index = name.lastIndexOf('/');
+        if (index > 0) {
+            pkgName = name.substring(0, index);
+        } else {
+            pkgName = "";
+        }
+        clsName = name;
+        isInterface = (access & Opcodes.ACC_INTERFACE) != 0;
+    }
+
+    @Override
+    public void visitSource(final String source, final String debug) {
+        // remove debug info
+    }
+
+    @Override
+    public void visitOuterClass(final String owner, final String name,
+            final String desc) {
+        // remove debug info
+    }
+
+    @Override
+    public AnnotationVisitor visitAnnotation(final String desc,
+            final boolean visible) {
+        // remove annotations
+        return null;
+    }
+
+    @Override
+    public AnnotationVisitor visitTypeAnnotation(int typeRef,
+            TypePath typePath, String desc, boolean visible) {
+        // remove annotations
+        return null;
+    }
+
+    @Override
+    public void visitAttribute(final Attribute attr) {
+        // remove non standard attributes
+    }
+
+    @Override
+    public void visitInnerClass(final String name, final String outerName,
+            final String innerName, final int access) {
+        // remove debug info
+    }
+
+    @Override
+    public FieldVisitor visitField(final int access, final String name,
+            final String desc, final String signature, final Object value) {
+        String s = remapper.mapFieldName(className, name, desc);
+        if ("-".equals(s)) {
+            return null;
+        }
+        if ((access & (Opcodes.ACC_PUBLIC | Opcodes.ACC_PROTECTED)) == 0) {
+            if ((access & Opcodes.ACC_FINAL) != 0
+                    && (access & Opcodes.ACC_STATIC) != 0 && desc.length() == 1) {
+                return null;
+            }
+            if ("org/objectweb/asm".equals(pkgName) && s.equals(name)) {
+                System.out.println("INFO: " + clsName + "." + s
+                        + " could be renamed");
+            }
+            super.visitField(access, name, desc, null, value);
+        } else {
+            if (!s.equals(name)) {
+                throw new RuntimeException("The public or protected field "
+                        + className + '.' + name + " must not be renamed.");
+            }
+            super.visitField(access, name, desc, null, value);
+        }
+        return null; // remove debug info
+    }
+
+    @Override
+    public MethodVisitor visitMethod(final int access, final String name,
+            final String desc, final String signature, final String[] exceptions) {
+        String s = remapper.mapMethodName(className, name, desc);
+        if ("-".equals(s)) {
+            return null;
+        }
+        if (name.equals("<clinit>") && !isInterface) {
+            hasClinitMethod = true;
+            MethodVisitor mv = super.visitMethod(access, name, desc, null,
+                    exceptions);
+            return new MethodVisitor(Opcodes.ASM5, mv) {
+                @Override
+                public void visitCode() {
+                    super.visitCode();
+                    mv.visitMethodInsn(Opcodes.INVOKESTATIC, clsName,
+                            "_clinit_", "()V", false);
+                }
+            };
+        }
+
+        if ((access & (Opcodes.ACC_PUBLIC | Opcodes.ACC_PROTECTED)) == 0) {
+            if ("org/objectweb/asm".equals(pkgName) && !name.startsWith("<")
+                    && s.equals(name)) {
+                System.out.println("INFO: " + clsName + "." + s
+                        + " could be renamed");
+            }
+            return super.visitMethod(access, name, desc, null, exceptions);
+        } else {
+            if (!s.equals(name)) {
+                throw new RuntimeException("The public or protected method "
+                        + className + '.' + name + desc
+                        + " must not be renamed.");
+            }
+            return super.visitMethod(access, name, desc, null, exceptions);
+        }
+    }
+
+    @Override
+    protected MethodVisitor createRemappingMethodAdapter(int access,
+            String newDesc, MethodVisitor mv) {
+        return new MethodOptimizer(this, access, newDesc, mv, remapper);
+    }
+
+    @Override
+    public void visitEnd() {
+        if (syntheticClassFields.isEmpty()) {
+            if (hasClinitMethod) {
+                MethodVisitor mv = cv.visitMethod(Opcodes.ACC_STATIC
+                        | Opcodes.ACC_SYNTHETIC, "_clinit_", "()V", null, null);
+                mv.visitCode();
+                mv.visitInsn(Opcodes.RETURN);
+                mv.visitMaxs(0, 0);
+                mv.visitEnd();
+            }
+        } else {
+            MethodVisitor mv = cv.visitMethod(Opcodes.ACC_STATIC
+                    | Opcodes.ACC_SYNTHETIC, "class$",
+                    "(Ljava/lang/String;)Ljava/lang/Class;", null, null);
+            mv.visitCode();
+            Label l0 = new Label();
+            Label l1 = new Label();
+            Label l2 = new Label();
+            mv.visitTryCatchBlock(l0, l1, l2,
+                    "java/lang/ClassNotFoundException");
+            mv.visitLabel(l0);
+            mv.visitVarInsn(Opcodes.ALOAD, 0);
+            mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Class",
+                    "forName", "(Ljava/lang/String;)Ljava/lang/Class;", false);
+            mv.visitLabel(l1);
+            mv.visitInsn(Opcodes.ARETURN);
+            mv.visitLabel(l2);
+            mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
+                    "java/lang/ClassNotFoundException", "getMessage",
+                    "()Ljava/lang/String;", false);
+            mv.visitVarInsn(Opcodes.ASTORE, 1);
+            mv.visitTypeInsn(Opcodes.NEW, "java/lang/NoClassDefFoundError");
+            mv.visitInsn(Opcodes.DUP);
+            mv.visitVarInsn(Opcodes.ALOAD, 1);
+            mv.visitMethodInsn(Opcodes.INVOKESPECIAL,
+                    "java/lang/NoClassDefFoundError", "<init>",
+                    "(Ljava/lang/String;)V", false);
+            mv.visitInsn(Opcodes.ATHROW);
+            mv.visitMaxs(3, 2);
+            mv.visitEnd();
+
+            if (hasClinitMethod) {
+                mv = cv.visitMethod(Opcodes.ACC_STATIC | Opcodes.ACC_PRIVATE,
+                        "_clinit_", "()V", null, null);
+            } else {
+                mv = cv.visitMethod(Opcodes.ACC_STATIC, "<clinit>", "()V",
+                        null, null);
+            }
+            for (String ldcName : syntheticClassFields) {
+                String fieldName = "class$" + ldcName.replace('/', '$');
+                mv.visitLdcInsn(ldcName.replace('/', '.'));
+                mv.visitMethodInsn(Opcodes.INVOKESTATIC, clsName, "class$",
+                        "(Ljava/lang/String;)Ljava/lang/Class;", false);
+                mv.visitFieldInsn(Opcodes.PUTSTATIC, clsName, fieldName,
+                        "Ljava/lang/Class;");
+            }
+            mv.visitInsn(Opcodes.RETURN);
+            mv.visitMaxs(1, 0);
+            mv.visitEnd();
+        }
+        super.visitEnd();
+    }
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/a0ac605d/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/optimizer/Constant.java
----------------------------------------------------------------------
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/optimizer/Constant.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/optimizer/Constant.java
new file mode 100644
index 0000000..9c1f306
--- /dev/null
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/optimizer/Constant.java
@@ -0,0 +1,323 @@
+/***
+ * ASM: a very small and fast Java bytecode manipulation framework
+ * Copyright (c) 2000-2011 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.apache.tapestry5.internal.plastic.asm.optimizer;
+
+import java.util.Arrays;
+
+import org.apache.tapestry5.internal.plastic.asm.ClassWriter;
+import org.apache.tapestry5.internal.plastic.asm.Handle;
+
+/**
+ * A constant pool item.
+ * 
+ * @author Eric Bruneton
+ */
+class Constant {
+
+    /**
+     * Type of this constant pool item. A single class is used to represent all
+     * constant pool item types, in order to minimize the bytecode size of this
+     * package. The value of this field is I, J, F, D, S, s, C, T, G, M, N, y,
+     * t, [h..p] (for Constant Integer, Long, Float, Double, STR, UTF8, Class,
+     * NameType, Fieldref, Methodref, InterfaceMethodref, InvokeDynamic,
+     * MethodType and MethodHandle constant pool items respectively).
+     * 
+     * The 9 variable of MethodHandle constants are stored between h and p.
+     */
+    char type;
+
+    /**
+     * Value of this item, for an integer item.
+     */
+    int intVal;
+
+    /**
+     * Value of this item, for a long item.
+     */
+    long longVal;
+
+    /**
+     * Value of this item, for a float item.
+     */
+    float floatVal;
+
+    /**
+     * Value of this item, for a double item.
+     */
+    double doubleVal;
+
+    /**
+     * First part of the value of this item, for items that do not hold a
+     * primitive value.
+     */
+    String strVal1;
+
+    /**
+     * Second part of the value of this item, for items that do not hold a
+     * primitive value.
+     */
+    String strVal2;
+
+    /**
+     * Third part of the value of this item, for items that do not hold a
+     * primitive value.
+     */
+    Object objVal3;
+
+    /**
+     * InvokeDynamic's constant values.
+     */
+    Object[] objVals;
+
+    /**
+     * The hash code value of this constant pool item.
+     */
+    int hashCode;
+
+    Constant() {
+    }
+
+    Constant(final Constant i) {
+        type = i.type;
+        intVal = i.intVal;
+        longVal = i.longVal;
+        floatVal = i.floatVal;
+        doubleVal = i.doubleVal;
+        strVal1 = i.strVal1;
+        strVal2 = i.strVal2;
+        objVal3 = i.objVal3;
+        objVals = i.objVals;
+        hashCode = i.hashCode;
+    }
+
+    /**
+     * Sets this item to an integer item.
+     * 
+     * @param intVal
+     *            the value of this item.
+     */
+    void set(final int intVal) {
+        this.type = 'I';
+        this.intVal = intVal;
+        this.hashCode = 0x7FFFFFFF & (type + intVal);
+    }
+
+    /**
+     * Sets this item to a long item.
+     * 
+     * @param longVal
+     *            the value of this item.
+     */
+    void set(final long longVal) {
+        this.type = 'J';
+        this.longVal = longVal;
+        this.hashCode = 0x7FFFFFFF & (type + (int) longVal);
+    }
+
+    /**
+     * Sets this item to a float item.
+     * 
+     * @param floatVal
+     *            the value of this item.
+     */
+    void set(final float floatVal) {
+        this.type = 'F';
+        this.floatVal = floatVal;
+        this.hashCode = 0x7FFFFFFF & (type + (int) floatVal);
+    }
+
+    /**
+     * Sets this item to a double item.
+     * 
+     * @param doubleVal
+     *            the value of this item.
+     */
+    void set(final double doubleVal) {
+        this.type = 'D';
+        this.doubleVal = doubleVal;
+        this.hashCode = 0x7FFFFFFF & (type + (int) doubleVal);
+    }
+
+    /**
+     * Sets this item to an item that do not hold a primitive value.
+     * 
+     * @param type
+     *            the type of this item.
+     * @param strVal1
+     *            first part of the value of this item.
+     * @param strVal2
+     *            second part of the value of this item.
+     * @param strVal3
+     *            third part of the value of this item.
+     */
+    void set(final char type, final String strVal1, final String strVal2,
+            final String strVal3) {
+        this.type = type;
+        this.strVal1 = strVal1;
+        this.strVal2 = strVal2;
+        this.objVal3 = strVal3;
+        switch (type) {
+        case 's':
+        case 'S':
+        case 'C':
+        case 't':
+            hashCode = 0x7FFFFFFF & (type + strVal1.hashCode());
+            return;
+        case 'T':
+            hashCode = 0x7FFFFFFF & (type + strVal1.hashCode()
+                    * strVal2.hashCode());
+            return;
+            // case 'G':
+            // case 'M':
+            // case 'N':
+            // case 'h' ... 'p':
+        default:
+            hashCode = 0x7FFFFFFF & (type + strVal1.hashCode()
+                    * strVal2.hashCode() * strVal3.hashCode());
+        }
+    }
+
+    /**
+     * Set this item to an InvokeDynamic item.
+     * 
+     * @param name
+     *            invokedynamic's name.
+     * @param desc
+     *            invokedynamic's descriptor.
+     * @param bsm
+     *            bootstrap method.
+     * @param bsmArgs
+     *            bootstrap method constant arguments.
+     */
+    void set(final String name, final String desc, final Handle bsm,
+            final Object[] bsmArgs) {
+        this.type = 'y';
+        this.strVal1 = name;
+        this.strVal2 = desc;
+        this.objVal3 = bsm;
+        this.objVals = bsmArgs;
+
+        int hashCode = 'y' + name.hashCode() * desc.hashCode() * bsm.hashCode();
+        for (int i = 0; i < bsmArgs.length; i++) {
+            hashCode *= bsmArgs[i].hashCode();
+        }
+        this.hashCode = 0x7FFFFFFF & hashCode;
+    }
+
+    void write(final ClassWriter cw) {
+        switch (type) {
+        case 'I':
+            cw.newConst(new Integer(intVal));
+            break;
+        case 'J':
+            cw.newConst(new Long(longVal));
+            break;
+        case 'F':
+            cw.newConst(new Float(floatVal));
+            break;
+        case 'D':
+            cw.newConst(new Double(doubleVal));
+            break;
+        case 'S':
+            cw.newConst(strVal1);
+            break;
+        case 's':
+            cw.newUTF8(strVal1);
+            break;
+        case 'C':
+            cw.newClass(strVal1);
+            break;
+        case 'T':
+            cw.newNameType(strVal1, strVal2);
+            break;
+        case 'G':
+            cw.newField(strVal1, strVal2, (String) objVal3);
+            break;
+        case 'M':
+            cw.newMethod(strVal1, strVal2, (String) objVal3, false);
+            break;
+        case 'N':
+            cw.newMethod(strVal1, strVal2, (String) objVal3, true);
+            break;
+        case 'y':
+            cw.newInvokeDynamic(strVal1, strVal2, (Handle) objVal3, objVals);
+            break;
+        case 't':
+            cw.newMethodType(strVal1);
+            break;
+        default: // 'h' ... 'p': handle
+            cw.newHandle(type - 'h' + 1, strVal1, strVal2, (String) objVal3);
+        }
+    }
+
+    @Override
+    public boolean equals(final Object o) {
+        if (!(o instanceof Constant)) {
+            return false;
+        }
+        Constant c = (Constant) o;
+        if (c.type == type) {
+            switch (type) {
+            case 'I':
+                return c.intVal == intVal;
+            case 'J':
+                return c.longVal == longVal;
+            case 'F':
+                return Float.compare(c.floatVal, floatVal) == 0;
+            case 'D':
+                return Double.compare(c.doubleVal, doubleVal) == 0;
+            case 's':
+            case 'S':
+            case 'C':
+            case 't':
+                return c.strVal1.equals(strVal1);
+            case 'T':
+                return c.strVal1.equals(strVal1) && c.strVal2.equals(strVal2);
+            case 'y':
+                return c.strVal1.equals(strVal1) && c.strVal2.equals(strVal2)
+                        && c.objVal3.equals(objVal3)
+                        && Arrays.equals(c.objVals, objVals);
+                // case 'G':
+                // case 'M':
+                // case 'N':
+                // case 'h' ... 'p':
+            default:
+                return c.strVal1.equals(strVal1) && c.strVal2.equals(strVal2)
+                        && c.objVal3.equals(objVal3);
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        return hashCode;
+    }
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/a0ac605d/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/optimizer/ConstantPool.java
----------------------------------------------------------------------
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/optimizer/ConstantPool.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/optimizer/ConstantPool.java
new file mode 100644
index 0000000..1901387
--- /dev/null
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/optimizer/ConstantPool.java
@@ -0,0 +1,249 @@
+/***
+ * ASM: a very small and fast Java bytecode manipulation framework
+ * Copyright (c) 2000-2011 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.apache.tapestry5.internal.plastic.asm.optimizer;
+
+import java.util.HashMap;
+
+import org.apache.tapestry5.internal.plastic.asm.Handle;
+import org.apache.tapestry5.internal.plastic.asm.Opcodes;
+import org.apache.tapestry5.internal.plastic.asm.Type;
+
+/**
+ * A constant pool.
+ * 
+ * @author Eric Bruneton
+ */
+public class ConstantPool extends HashMap<Constant, Constant> {
+
+    private final Constant key1 = new Constant();
+
+    private final Constant key2 = new Constant();
+
+    private final Constant key3 = new Constant();
+
+    private final Constant key4 = new Constant();
+
+    private final Constant key5 = new Constant();
+
+    public Constant newInteger(final int value) {
+        key1.set(value);
+        Constant result = get(key1);
+        if (result == null) {
+            result = new Constant(key1);
+            put(result);
+        }
+        return result;
+    }
+
+    public Constant newFloat(final float value) {
+        key1.set(value);
+        Constant result = get(key1);
+        if (result == null) {
+            result = new Constant(key1);
+            put(result);
+        }
+        return result;
+    }
+
+    public Constant newLong(final long value) {
+        key1.set(value);
+        Constant result = get(key1);
+        if (result == null) {
+            result = new Constant(key1);
+            put(result);
+        }
+        return result;
+    }
+
+    public Constant newDouble(final double value) {
+        key1.set(value);
+        Constant result = get(key1);
+        if (result == null) {
+            result = new Constant(key1);
+            put(result);
+        }
+        return result;
+    }
+
+    public Constant newUTF8(final String value) {
+        key1.set('s', value, null, null);
+        Constant result = get(key1);
+        if (result == null) {
+            result = new Constant(key1);
+            put(result);
+        }
+        return result;
+    }
+
+    private Constant newString(final String value) {
+        key2.set('S', value, null, null);
+        Constant result = get(key2);
+        if (result == null) {
+            newUTF8(value);
+            result = new Constant(key2);
+            put(result);
+        }
+        return result;
+    }
+
+    public Constant newClass(final String value) {
+        key2.set('C', value, null, null);
+        Constant result = get(key2);
+        if (result == null) {
+            newUTF8(value);
+            result = new Constant(key2);
+            put(result);
+        }
+        return result;
+    }
+
+    public Constant newMethodType(final String methodDescriptor) {
+        key2.set('t', methodDescriptor, null, null);
+        Constant result = get(key2);
+        if (result == null) {
+            newUTF8(methodDescriptor);
+            result = new Constant(key2);
+            put(result);
+        }
+        return result;
+    }
+
+    public Constant newHandle(final int tag, final String owner,
+            final String name, final String desc) {
+        key4.set((char) ('h' - 1 + tag), owner, name, desc);
+        Constant result = get(key4);
+        if (result == null) {
+            if (tag <= Opcodes.H_PUTSTATIC) {
+                newField(owner, name, desc);
+            } else {
+                newMethod(owner, name, desc, tag == Opcodes.H_INVOKEINTERFACE);
+            }
+            result = new Constant(key4);
+            put(result);
+        }
+        return result;
+    }
+
+    public Constant newConst(final Object cst) {
+        if (cst instanceof Integer) {
+            int val = ((Integer) cst).intValue();
+            return newInteger(val);
+        } else if (cst instanceof Float) {
+            float val = ((Float) cst).floatValue();
+            return newFloat(val);
+        } else if (cst instanceof Long) {
+            long val = ((Long) cst).longValue();
+            return newLong(val);
+        } else if (cst instanceof Double) {
+            double val = ((Double) cst).doubleValue();
+            return newDouble(val);
+        } else if (cst instanceof String) {
+            return newString((String) cst);
+        } else if (cst instanceof Type) {
+            Type t = (Type) cst;
+            int s = t.getSort();
+            if (s == Type.OBJECT) {
+                return newClass(t.getInternalName());
+            } else if (s == Type.METHOD) {
+                return newMethodType(t.getDescriptor());
+            } else { // s == primitive type or array
+                return newClass(t.getDescriptor());
+            }
+        } else if (cst instanceof Handle) {
+            Handle h = (Handle) cst;
+            return newHandle(h.getTag(), h.getOwner(), h.getName(), h.getDesc());
+        } else {
+            throw new IllegalArgumentException("value " + cst);
+        }
+    }
+
+    public Constant newField(final String owner, final String name,
+            final String desc) {
+        key3.set('G', owner, name, desc);
+        Constant result = get(key3);
+        if (result == null) {
+            newClass(owner);
+            newNameType(name, desc);
+            result = new Constant(key3);
+            put(result);
+        }
+        return result;
+    }
+
+    public Constant newMethod(final String owner, final String name,
+            final String desc, final boolean itf) {
+        key3.set(itf ? 'N' : 'M', owner, name, desc);
+        Constant result = get(key3);
+        if (result == null) {
+            newClass(owner);
+            newNameType(name, desc);
+            result = new Constant(key3);
+            put(result);
+        }
+        return result;
+    }
+
+    public Constant newInvokeDynamic(String name, String desc, Handle bsm,
+            Object... bsmArgs) {
+        key5.set(name, desc, bsm, bsmArgs);
+        Constant result = get(key5);
+        if (result == null) {
+            newNameType(name, desc);
+            newHandle(bsm.getTag(), bsm.getOwner(), bsm.getName(),
+                    bsm.getDesc());
+            for (int i = 0; i < bsmArgs.length; i++) {
+                newConst(bsmArgs[i]);
+            }
+            result = new Constant(key5);
+            put(result);
+        }
+        return result;
+    }
+
+    public Constant newNameType(final String name, final String desc) {
+        key2.set('T', name, desc, null);
+        Constant result = get(key2);
+        if (result == null) {
+            newUTF8(name);
+            newUTF8(desc);
+            result = new Constant(key2);
+            put(result);
+        }
+        return result;
+    }
+
+    private Constant get(final Constant key) {
+        return get((Object) key);
+    }
+
+    private void put(final Constant cst) {
+        put(cst, cst);
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/a0ac605d/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/optimizer/FieldConstantsCollector.java
----------------------------------------------------------------------
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/optimizer/FieldConstantsCollector.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/optimizer/FieldConstantsCollector.java
new file mode 100644
index 0000000..63ca654
--- /dev/null
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/optimizer/FieldConstantsCollector.java
@@ -0,0 +1,89 @@
+/***
+ * ASM: a very small and fast Java bytecode manipulation framework
+ * Copyright (c) 2000-2011 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.apache.tapestry5.internal.plastic.asm.optimizer;
+
+import org.apache.tapestry5.internal.plastic.asm.AnnotationVisitor;
+import org.apache.tapestry5.internal.plastic.asm.Attribute;
+import org.apache.tapestry5.internal.plastic.asm.FieldVisitor;
+import org.apache.tapestry5.internal.plastic.asm.Opcodes;
+import org.apache.tapestry5.internal.plastic.asm.TypePath;
+
+/**
+ * A {@link FieldVisitor} that collects the {@link Constant}s of the fields it
+ * visits.
+ * 
+ * @author Eric Bruneton
+ */
+public class FieldConstantsCollector extends FieldVisitor {
+
+    private final ConstantPool cp;
+
+    public FieldConstantsCollector(final FieldVisitor fv, final ConstantPool cp) {
+        super(Opcodes.ASM5, fv);
+        this.cp = cp;
+    }
+
+    @Override
+    public AnnotationVisitor visitAnnotation(final String desc,
+            final boolean visible) {
+        cp.newUTF8(desc);
+        if (visible) {
+            cp.newUTF8("RuntimeVisibleAnnotations");
+        } else {
+            cp.newUTF8("RuntimeInvisibleAnnotations");
+        }
+        return new AnnotationConstantsCollector(fv.visitAnnotation(desc,
+                visible), cp);
+    }
+
+    @Override
+    public AnnotationVisitor visitTypeAnnotation(int typeRef,
+            TypePath typePath, String desc, boolean visible) {
+        cp.newUTF8(desc);
+        if (visible) {
+            cp.newUTF8("RuntimeVisibleTypeAnnotations");
+        } else {
+            cp.newUTF8("RuntimeInvisibleTypeAnnotations");
+        }
+        return new AnnotationConstantsCollector(fv.visitAnnotation(desc,
+                visible), cp);
+    }
+
+    @Override
+    public void visitAttribute(final Attribute attr) {
+        // can do nothing
+        fv.visitAttribute(attr);
+    }
+
+    @Override
+    public void visitEnd() {
+        fv.visitEnd();
+    }
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/a0ac605d/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/optimizer/JarOptimizer.java
----------------------------------------------------------------------
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/optimizer/JarOptimizer.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/optimizer/JarOptimizer.java
new file mode 100644
index 0000000..e7d93cf
--- /dev/null
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/optimizer/JarOptimizer.java
@@ -0,0 +1,235 @@
+/***
+ * ASM: a very small and fast Java bytecode manipulation framework
+ * Copyright (c) 2000-2011 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.apache.tapestry5.internal.plastic.asm.optimizer;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.LineNumberReader;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.zip.GZIPInputStream;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+import java.util.zip.ZipOutputStream;
+
+import org.apache.tapestry5.internal.plastic.asm.ClassReader;
+import org.apache.tapestry5.internal.plastic.asm.ClassVisitor;
+import org.apache.tapestry5.internal.plastic.asm.FieldVisitor;
+import org.apache.tapestry5.internal.plastic.asm.MethodVisitor;
+import org.apache.tapestry5.internal.plastic.asm.Opcodes;
+
+/**
+ * A Jar file optimizer.
+ * 
+ * @author Eric Bruneton
+ */
+public class JarOptimizer {
+
+    static final Set<String> API = new HashSet<String>();
+    static final Map<String, String> HIERARCHY = new HashMap<String, String>();
+    static boolean nodebug = false;
+
+    public static void main(final String[] args) throws IOException {
+        File f = new File(args[0]);
+        InputStream is = new GZIPInputStream(new FileInputStream(f));
+        BufferedReader lnr = new LineNumberReader(new InputStreamReader(is));
+        while (true) {
+            String line = lnr.readLine();
+            if (line != null) {
+                if (line.startsWith("class")) {
+                    String c = line.substring(6, line.lastIndexOf(' '));
+                    String sc = line.substring(line.lastIndexOf(' ') + 1);
+                    HIERARCHY.put(c, sc);
+                } else {
+                    API.add(line);
+                }
+            } else {
+                break;
+            }
+        }
+
+        int argIndex = 1;
+        if (args[argIndex].equals("-nodebug")) {
+            nodebug = true;
+            argIndex++;
+        }
+
+        optimize(new File(args[argIndex]));
+    }
+
+    static void optimize(final File f) throws IOException {
+        if (nodebug && f.getName().contains("debug")) {
+            return;
+        }
+
+        if (f.isDirectory()) {
+            File[] files = f.listFiles();
+            for (int i = 0; i < files.length; ++i) {
+                optimize(files[i]);
+            }
+        } else if (f.getName().endsWith(".jar")) {
+            File g = new File(f.getParentFile(), f.getName() + ".new");
+            ZipFile zf = new ZipFile(f);
+            ZipOutputStream out = new ZipOutputStream(new FileOutputStream(g));
+            Enumeration<? extends ZipEntry> e = zf.entries();
+            byte[] buf = new byte[10000];
+            while (e.hasMoreElements()) {
+                ZipEntry ze = e.nextElement();
+                if (ze.isDirectory()) {
+                    out.putNextEntry(ze);
+                    continue;
+                }
+                out.putNextEntry(ze);
+                if (ze.getName().endsWith(".class")) {
+                    ClassReader cr = new ClassReader(zf.getInputStream(ze));
+                    // cr.accept(new ClassDump(), 0);
+                    cr.accept(new ClassVerifier(), 0);
+                }
+                InputStream is = zf.getInputStream(ze);
+                int n;
+                do {
+                    n = is.read(buf, 0, buf.length);
+                    if (n != -1) {
+                        out.write(buf, 0, n);
+                    }
+                } while (n != -1);
+                out.closeEntry();
+            }
+            out.close();
+            zf.close();
+            if (!f.delete()) {
+                throw new IOException("Cannot delete file " + f);
+            }
+            if (!g.renameTo(f)) {
+                throw new IOException("Cannot rename file " + g);
+            }
+        }
+    }
+
+    static class ClassDump extends ClassVisitor {
+
+        String owner;
+
+        public ClassDump() {
+            super(Opcodes.ASM5);
+        }
+
+        @Override
+        public void visit(final int version, final int access,
+                final String name, final String signature,
+                final String superName, final String[] interfaces) {
+            owner = name;
+            if (owner.startsWith("java/")) {
+                System.out.println("class " + name + ' ' + superName);
+            }
+        }
+
+        @Override
+        public FieldVisitor visitField(final int access, final String name,
+                final String desc, final String signature, final Object value) {
+            if (owner.startsWith("java/")) {
+                System.out.println(owner + ' ' + name);
+            }
+            return null;
+        }
+
+        @Override
+        public MethodVisitor visitMethod(final int access, final String name,
+                final String desc, final String signature,
+                final String[] exceptions) {
+            if (owner.startsWith("java/")) {
+                System.out.println(owner + ' ' + name + desc);
+            }
+            return null;
+        }
+    }
+
+    static class ClassVerifier extends ClassVisitor {
+
+        String owner;
+
+        String method;
+
+        public ClassVerifier() {
+            super(Opcodes.ASM5);
+        }
+
+        @Override
+        public void visit(final int version, final int access,
+                final String name, final String signature,
+                final String superName, final String[] interfaces) {
+            owner = name;
+        }
+
+        @Override
+        public MethodVisitor visitMethod(final int access, final String name,
+                final String desc, final String signature,
+                final String[] exceptions) {
+            method = name + desc;
+            return new MethodVisitor(Opcodes.ASM5) {
+                @Override
+                public void visitFieldInsn(final int opcode,
+                        final String owner, final String name, final String desc) {
+                    check(owner, name);
+                }
+
+                @Override
+                public void visitMethodInsn(final int opcode,
+                        final String owner, final String name,
+                        final String desc, final boolean itf) {
+                    check(owner, name + desc);
+                }
+            };
+        }
+
+        void check(String owner, String member) {
+            if (owner.startsWith("java/")) {
+                String o = owner;
+                while (o != null) {
+                    if (API.contains(o + ' ' + member)) {
+                        return;
+                    }
+                    o = HIERARCHY.get(o);
+                }
+                System.out.println("WARNING: " + owner + ' ' + member
+                        + " called in " + this.owner + ' ' + method
+                        + " is not defined in JDK 1.3 API");
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/a0ac605d/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/optimizer/MethodConstantsCollector.java
----------------------------------------------------------------------
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/optimizer/MethodConstantsCollector.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/optimizer/MethodConstantsCollector.java
new file mode 100644
index 0000000..54b3519
--- /dev/null
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/optimizer/MethodConstantsCollector.java
@@ -0,0 +1,224 @@
+/***
+ * ASM: a very small and fast Java bytecode manipulation framework
+ * Copyright (c) 2000-2011 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.apache.tapestry5.internal.plastic.asm.optimizer;
+
+import org.apache.tapestry5.internal.plastic.asm.AnnotationVisitor;
+import org.apache.tapestry5.internal.plastic.asm.Handle;
+import org.apache.tapestry5.internal.plastic.asm.Label;
+import org.apache.tapestry5.internal.plastic.asm.MethodVisitor;
+import org.apache.tapestry5.internal.plastic.asm.Opcodes;
+import org.apache.tapestry5.internal.plastic.asm.TypePath;
+
+/**
+ * An {@link MethodVisitor} that collects the {@link Constant}s of the methods
+ * it visits.
+ * 
+ * @author Eric Bruneton
+ */
+public class MethodConstantsCollector extends MethodVisitor {
+
+    private final ConstantPool cp;
+
+    public MethodConstantsCollector(final MethodVisitor mv,
+            final ConstantPool cp) {
+        super(Opcodes.ASM5, mv);
+        this.cp = cp;
+    }
+
+    @Override
+    public void visitParameter(String name, int access) {
+        cp.newUTF8("MethodParameters");
+        if (name != null) {
+            cp.newUTF8(name);
+        }
+        mv.visitParameter(name, access);
+    }
+
+    @Override
+    public AnnotationVisitor visitAnnotationDefault() {
+        cp.newUTF8("AnnotationDefault");
+        return new AnnotationConstantsCollector(mv.visitAnnotationDefault(), cp);
+    }
+
+    @Override
+    public AnnotationVisitor visitAnnotation(final String desc,
+            final boolean visible) {
+        cp.newUTF8(desc);
+        if (visible) {
+            cp.newUTF8("RuntimeVisibleAnnotations");
+        } else {
+            cp.newUTF8("RuntimeInvisibleAnnotations");
+        }
+        return new AnnotationConstantsCollector(mv.visitAnnotation(desc,
+                visible), cp);
+    }
+
+    @Override
+    public AnnotationVisitor visitTypeAnnotation(int typeRef,
+            TypePath typePath, String desc, boolean visible) {
+        cp.newUTF8(desc);
+        if (visible) {
+            cp.newUTF8("RuntimeVisibleTypeAnnotations");
+        } else {
+            cp.newUTF8("RuntimeInvisibleTypeAnnotations");
+        }
+        return new AnnotationConstantsCollector(mv.visitAnnotation(desc,
+                visible), cp);
+    }
+
+    @Override
+    public AnnotationVisitor visitParameterAnnotation(final int parameter,
+            final String desc, final boolean visible) {
+        cp.newUTF8(desc);
+        if (visible) {
+            cp.newUTF8("RuntimeVisibleParameterAnnotations");
+        } else {
+            cp.newUTF8("RuntimeInvisibleParameterAnnotations");
+        }
+        return new AnnotationConstantsCollector(mv.visitParameterAnnotation(
+                parameter, desc, visible), cp);
+    }
+
+    @Override
+    public void visitTypeInsn(final int opcode, final String type) {
+        cp.newClass(type);
+        mv.visitTypeInsn(opcode, type);
+    }
+
+    @Override
+    public void visitFieldInsn(final int opcode, final String owner,
+            final String name, final String desc) {
+        cp.newField(owner, name, desc);
+        mv.visitFieldInsn(opcode, owner, name, desc);
+    }
+
+    @Override
+    public void visitMethodInsn(final int opcode, final String owner,
+            final String name, final String desc, final boolean itf) {
+        cp.newMethod(owner, name, desc, itf);
+        mv.visitMethodInsn(opcode, owner, name, desc, itf);
+    }
+
+    @Override
+    public void visitInvokeDynamicInsn(String name, String desc, Handle bsm,
+            Object... bsmArgs) {
+        cp.newInvokeDynamic(name, desc, bsm, bsmArgs);
+        mv.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
+    }
+
+    @Override
+    public void visitLdcInsn(final Object cst) {
+        cp.newConst(cst);
+        mv.visitLdcInsn(cst);
+    }
+
+    @Override
+    public void visitMultiANewArrayInsn(final String desc, final int dims) {
+        cp.newClass(desc);
+        mv.visitMultiANewArrayInsn(desc, dims);
+    }
+
+    @Override
+    public AnnotationVisitor visitInsnAnnotation(int typeRef,
+            TypePath typePath, String desc, boolean visible) {
+        cp.newUTF8(desc);
+        if (visible) {
+            cp.newUTF8("RuntimeVisibleTypeAnnotations");
+        } else {
+            cp.newUTF8("RuntimeInvisibleTypeAnnotations");
+        }
+        return new AnnotationConstantsCollector(mv.visitInsnAnnotation(typeRef,
+                typePath, desc, visible), cp);
+    }
+
+    @Override
+    public void visitTryCatchBlock(final Label start, final Label end,
+            final Label handler, final String type) {
+        if (type != null) {
+            cp.newClass(type);
+        }
+        mv.visitTryCatchBlock(start, end, handler, type);
+    }
+
+    @Override
+    public AnnotationVisitor visitTryCatchAnnotation(int typeRef,
+            TypePath typePath, String desc, boolean visible) {
+        cp.newUTF8(desc);
+        if (visible) {
+            cp.newUTF8("RuntimeVisibleTypeAnnotations");
+        } else {
+            cp.newUTF8("RuntimeInvisibleTypeAnnotations");
+        }
+        return new AnnotationConstantsCollector(mv.visitTryCatchAnnotation(
+                typeRef, typePath, desc, visible), cp);
+    }
+
+    @Override
+    public void visitLocalVariable(final String name, final String desc,
+            final String signature, final Label start, final Label end,
+            final int index) {
+        if (signature != null) {
+            cp.newUTF8("LocalVariableTypeTable");
+            cp.newUTF8(name);
+            cp.newUTF8(signature);
+        }
+        cp.newUTF8("LocalVariableTable");
+        cp.newUTF8(name);
+        cp.newUTF8(desc);
+        mv.visitLocalVariable(name, desc, signature, start, end, index);
+    }
+
+    @Override
+    public AnnotationVisitor visitLocalVariableAnnotation(int typeRef,
+            TypePath typePath, Label[] start, Label[] end, int[] index,
+            String desc, boolean visible) {
+        cp.newUTF8(desc);
+        if (visible) {
+            cp.newUTF8("RuntimeVisibleTypeAnnotations");
+        } else {
+            cp.newUTF8("RuntimeInvisibleTypeAnnotations");
+        }
+        return new AnnotationConstantsCollector(
+                mv.visitLocalVariableAnnotation(typeRef, typePath, start, end,
+                        index, desc, visible), cp);
+    }
+
+    @Override
+    public void visitLineNumber(final int line, final Label start) {
+        cp.newUTF8("LineNumberTable");
+        mv.visitLineNumber(line, start);
+    }
+
+    @Override
+    public void visitMaxs(final int maxStack, final int maxLocals) {
+        cp.newUTF8("Code");
+        mv.visitMaxs(maxStack, maxLocals);
+    }
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/a0ac605d/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/optimizer/MethodOptimizer.java
----------------------------------------------------------------------
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/optimizer/MethodOptimizer.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/optimizer/MethodOptimizer.java
new file mode 100644
index 0000000..adad6b4
--- /dev/null
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/optimizer/MethodOptimizer.java
@@ -0,0 +1,136 @@
+/***
+ * ASM: a very small and fast Java bytecode manipulation framework
+ * Copyright (c) 2000-2011 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.apache.tapestry5.internal.plastic.asm.optimizer;
+
+import org.apache.tapestry5.internal.plastic.asm.AnnotationVisitor;
+import org.apache.tapestry5.internal.plastic.asm.Attribute;
+import org.apache.tapestry5.internal.plastic.asm.FieldVisitor;
+import org.apache.tapestry5.internal.plastic.asm.Label;
+import org.apache.tapestry5.internal.plastic.asm.MethodVisitor;
+import org.apache.tapestry5.internal.plastic.asm.Opcodes;
+import org.apache.tapestry5.internal.plastic.asm.Type;
+import org.apache.tapestry5.internal.plastic.asm.TypePath;
+import org.apache.tapestry5.internal.plastic.asm.commons.Remapper;
+import org.apache.tapestry5.internal.plastic.asm.commons.RemappingMethodAdapter;
+
+/**
+ * A {@link MethodVisitor} that renames fields and methods, and removes debug
+ * info.
+ * 
+ * @author Eugene Kuleshov
+ */
+public class MethodOptimizer extends RemappingMethodAdapter implements Opcodes {
+
+    private final ClassOptimizer classOptimizer;
+
+    public MethodOptimizer(ClassOptimizer classOptimizer, int access,
+            String desc, MethodVisitor mv, Remapper remapper) {
+        super(Opcodes.ASM5, access, desc, mv, remapper);
+        this.classOptimizer = classOptimizer;
+    }
+
+    // ------------------------------------------------------------------------
+    // Overridden methods
+    // ------------------------------------------------------------------------
+
+    @Override
+    public void visitParameter(String name, int access) {
+        // remove parameter info
+    }
+
+    @Override
+    public AnnotationVisitor visitAnnotationDefault() {
+        // remove annotations
+        return null;
+    }
+
+    @Override
+    public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
+        // remove annotations
+        return null;
+    }
+
+    @Override
+    public AnnotationVisitor visitTypeAnnotation(int typeRef,
+            TypePath typePath, String desc, boolean visible) {
+        return null;
+    }
+
+    @Override
+    public AnnotationVisitor visitParameterAnnotation(final int parameter,
+            final String desc, final boolean visible) {
+        // remove annotations
+        return null;
+    }
+
+    @Override
+    public void visitLocalVariable(final String name, final String desc,
+            final String signature, final Label start, final Label end,
+            final int index) {
+        // remove debug info
+    }
+
+    @Override
+    public void visitLineNumber(final int line, final Label start) {
+        // remove debug info
+    }
+
+    @Override
+    public void visitFrame(int type, int local, Object[] local2, int stack,
+            Object[] stack2) {
+        // remove frame info
+    }
+
+    @Override
+    public void visitAttribute(Attribute attr) {
+        // remove non standard attributes
+    }
+
+    @Override
+    public void visitLdcInsn(Object cst) {
+        if (!(cst instanceof Type)) {
+            super.visitLdcInsn(cst);
+            return;
+        }
+
+        // transform Foo.class for 1.2 compatibility
+        String ldcName = ((Type) cst).getInternalName();
+        String fieldName = "class$" + ldcName.replace('/', '$');
+        if (!classOptimizer.syntheticClassFields.contains(ldcName)) {
+            classOptimizer.syntheticClassFields.add(ldcName);
+            FieldVisitor fv = classOptimizer.syntheticFieldVisitor(ACC_STATIC
+                    | ACC_SYNTHETIC, fieldName, "Ljava/lang/Class;");
+            fv.visitEnd();
+        }
+
+        String clsName = classOptimizer.clsName;
+        mv.visitFieldInsn(GETSTATIC, clsName, fieldName, "Ljava/lang/Class;");
+    }
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/a0ac605d/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/optimizer/NameMapping.java
----------------------------------------------------------------------
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/optimizer/NameMapping.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/optimizer/NameMapping.java
new file mode 100644
index 0000000..70d74f7
--- /dev/null
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/optimizer/NameMapping.java
@@ -0,0 +1,114 @@
+/***
+ * ASM: a very small and fast Java bytecode manipulation framework
+ * Copyright (c) 2000-2011 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.apache.tapestry5.internal.plastic.asm.optimizer;
+
+import java.io.BufferedInputStream;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashSet;
+import java.util.Properties;
+import java.util.Set;
+
+import org.apache.tapestry5.internal.plastic.asm.Type;
+
+/**
+ * A MAPPING from names to names, used to rename classes, fields and methods.
+ * 
+ * @author Eric Bruneton
+ */
+public class NameMapping {
+
+    public final Properties mapping;
+
+    public final Set<Object> unused;
+
+    public NameMapping(final String file) throws IOException {
+        mapping = new Properties();
+        InputStream is = null;
+        try {
+            is = new BufferedInputStream(new FileInputStream(file));
+            mapping.load(is);
+            unused = new HashSet<Object>(mapping.keySet());
+        } finally {
+            if (is != null) {
+                is.close();
+            }
+        }
+    }
+
+    public String map(final String name) {
+        String s = (String) mapping.get(name);
+        if (s == null) {
+            int p = name.indexOf('.');
+            if (p == -1) {
+                s = name;
+            } else {
+                int q = name.indexOf('(');
+                if (q == -1) {
+                    s = name.substring(p + 1);
+                } else {
+                    s = name.substring(p + 1, q);
+                }
+            }
+        } else {
+            unused.remove(name);
+        }
+        return s;
+    }
+
+    public String fix(final String desc) {
+        if (desc.startsWith("(")) {
+            Type[] arguments = Type.getArgumentTypes(desc);
+            Type result = Type.getReturnType(desc);
+            for (int i = 0; i < arguments.length; ++i) {
+                arguments[i] = fix(arguments[i]);
+            }
+            result = fix(result);
+            return Type.getMethodDescriptor(result, arguments);
+        } else {
+            return fix(Type.getType(desc)).getDescriptor();
+        }
+    }
+
+    private Type fix(final Type t) {
+        if (t.getSort() == Type.OBJECT) {
+            return Type.getObjectType(map(t.getInternalName()));
+        } else if (t.getSort() == Type.ARRAY) {
+            String s = fix(t.getElementType()).getDescriptor();
+            for (int i = 0; i < t.getDimensions(); ++i) {
+                s = '[' + s;
+            }
+            return Type.getType(s);
+        } else {
+            return t;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/a0ac605d/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/optimizer/Shrinker.java
----------------------------------------------------------------------
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/optimizer/Shrinker.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/optimizer/Shrinker.java
new file mode 100644
index 0000000..e20cf5c
--- /dev/null
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/optimizer/Shrinker.java
@@ -0,0 +1,283 @@
+/***
+ * ASM: a very small and fast Java bytecode manipulation framework
+ * Copyright (c) 2000-2011 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.apache.tapestry5.internal.plastic.asm.optimizer;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import java.util.TreeSet;
+
+import org.apache.tapestry5.internal.plastic.asm.ClassReader;
+import org.apache.tapestry5.internal.plastic.asm.ClassWriter;
+import org.apache.tapestry5.internal.plastic.asm.Handle;
+import org.apache.tapestry5.internal.plastic.asm.Type;
+import org.apache.tapestry5.internal.plastic.asm.commons.Remapper;
+import org.apache.tapestry5.internal.plastic.asm.commons.SimpleRemapper;
+
+/**
+ * A class file shrinker utility.
+ * 
+ * @author Eric Bruneton
+ * @author Eugene Kuleshov
+ */
+public class Shrinker {
+
+    static final HashMap<String, String> MAPPING = new HashMap<String, String>();
+
+    public static void main(final String[] args) throws IOException {
+        Properties properties = new Properties();
+        int n = args.length - 1;
+        for (int i = 0; i < n - 1; ++i) {
+            properties.load(new FileInputStream(args[i]));
+        }
+
+        for (Map.Entry<Object, Object> entry : properties.entrySet()) {
+            MAPPING.put((String) entry.getKey(), (String) entry.getValue());
+        }
+
+        final Set<String> unused = new HashSet<String>(MAPPING.keySet());
+
+        File f = new File(args[n - 1]);
+        File d = new File(args[n]);
+
+        optimize(f, d, new SimpleRemapper(MAPPING) {
+            @Override
+            public String map(String key) {
+                String s = super.map(key);
+                if (s != null) {
+                    unused.remove(key);
+                }
+                return s;
+            }
+        });
+
+        Iterator<String> i = unused.iterator();
+        while (i.hasNext()) {
+            String s = i.next();
+            if (!s.endsWith("/remove")) {
+                System.out.println("INFO: unused mapping " + s);
+            }
+        }
+    }
+
+    static void optimize(final File f, final File d, final Remapper remapper)
+            throws IOException {
+        if (f.isDirectory()) {
+            File[] files = f.listFiles();
+            for (int i = 0; i < files.length; ++i) {
+                optimize(files[i], d, remapper);
+            }
+        } else if (f.getName().endsWith(".class")) {
+            ConstantPool cp = new ConstantPool();
+            ClassReader cr = new ClassReader(new FileInputStream(f));
+            ClassWriter cw = new ClassWriter(0);
+            ClassConstantsCollector ccc = new ClassConstantsCollector(cw, cp);
+            ClassOptimizer co = new ClassOptimizer(ccc, remapper);
+            cr.accept(co, ClassReader.SKIP_DEBUG);
+
+            Set<Constant> constants = new TreeSet<Constant>(
+                    new ConstantComparator());
+            constants.addAll(cp.values());
+
+            cr = new ClassReader(cw.toByteArray());
+            cw = new ClassWriter(0);
+            Iterator<Constant> i = constants.iterator();
+            while (i.hasNext()) {
+                Constant c = i.next();
+                c.write(cw);
+            }
+            cr.accept(cw, ClassReader.SKIP_DEBUG);
+
+            if (MAPPING.get(cr.getClassName() + "/remove") != null) {
+                return;
+            }
+            String n = remapper.mapType(cr.getClassName());
+            File g = new File(d, n + ".class");
+            if (!g.exists() || g.lastModified() < f.lastModified()) {
+                if (!g.getParentFile().exists() && !g.getParentFile().mkdirs()) {
+                    throw new IOException("Cannot create directory "
+                            + g.getParentFile());
+                }
+                OutputStream os = new FileOutputStream(g);
+                try {
+                    os.write(cw.toByteArray());
+                } finally {
+                    os.close();
+                }
+            }
+        }
+    }
+
+    static class ConstantComparator implements Comparator<Constant> {
+
+        public int compare(final Constant c1, final Constant c2) {
+            int d = getSort(c1) - getSort(c2);
+            if (d == 0) {
+                switch (c1.type) {
+                case 'I':
+                    return new Integer(c1.intVal).compareTo(new Integer(
+                            c2.intVal));
+                case 'J':
+                    return new Long(c1.longVal).compareTo(new Long(c2.longVal));
+                case 'F':
+                    return new Float(c1.floatVal).compareTo(new Float(
+                            c2.floatVal));
+                case 'D':
+                    return new Double(c1.doubleVal).compareTo(new Double(
+                            c2.doubleVal));
+                case 's':
+                case 'S':
+                case 'C':
+                case 't':
+                    return c1.strVal1.compareTo(c2.strVal1);
+                case 'T':
+                    d = c1.strVal1.compareTo(c2.strVal1);
+                    if (d == 0) {
+                        d = c1.strVal2.compareTo(c2.strVal2);
+                    }
+                    break;
+                case 'y':
+                    d = c1.strVal1.compareTo(c2.strVal1);
+                    if (d == 0) {
+                        d = c1.strVal2.compareTo(c2.strVal2);
+                        if (d == 0) {
+                            Handle bsm1 = (Handle) c1.objVal3;
+                            Handle bsm2 = (Handle) c2.objVal3;
+                            d = compareHandle(bsm1, bsm2);
+                            if (d == 0) {
+                                d = compareObjects(c1.objVals, c2.objVals);
+                            }
+                        }
+                    }
+                    break;
+
+                default:
+                    d = c1.strVal1.compareTo(c2.strVal1);
+                    if (d == 0) {
+                        d = c1.strVal2.compareTo(c2.strVal2);
+                        if (d == 0) {
+                            d = ((String) c1.objVal3)
+                                    .compareTo((String) c2.objVal3);
+                        }
+                    }
+                }
+            }
+            return d;
+        }
+
+        private static int compareHandle(Handle h1, Handle h2) {
+            int d = h1.getTag() - h2.getTag();
+            if (d == 0) {
+                d = h1.getOwner().compareTo(h2.getOwner());
+                if (d == 0) {
+                    d = h1.getName().compareTo(h2.getName());
+                    if (d == 0) {
+                        d = h1.getDesc().compareTo(h2.getDesc());
+                    }
+                }
+            }
+            return d;
+        }
+
+        private static int compareType(Type mtype1, Type mtype2) {
+            return mtype1.getDescriptor().compareTo(mtype2.getDescriptor());
+        }
+
+        private static int compareObjects(Object[] objVals1, Object[] objVals2) {
+            int length = objVals1.length;
+            int d = length - objVals2.length;
+            if (d == 0) {
+                for (int i = 0; i < length; i++) {
+                    Object objVal1 = objVals1[i];
+                    Object objVal2 = objVals2[i];
+                    d = objVal1.getClass().getName()
+                            .compareTo(objVal2.getClass().getName());
+                    if (d == 0) {
+                        if (objVal1 instanceof Type) {
+                            d = compareType((Type) objVal1, (Type) objVal2);
+                        } else if (objVal1 instanceof Handle) {
+                            d = compareHandle((Handle) objVal1,
+                                    (Handle) objVal2);
+                        } else {
+                            d = ((Comparable) objVal1).compareTo(objVal2);
+                        }
+                    }
+
+                    if (d != 0) {
+                        return d;
+                    }
+                }
+            }
+            return 0;
+        }
+
+        private static int getSort(final Constant c) {
+            switch (c.type) {
+            case 'I':
+                return 0;
+            case 'J':
+                return 1;
+            case 'F':
+                return 2;
+            case 'D':
+                return 3;
+            case 's':
+                return 4;
+            case 'S':
+                return 5;
+            case 'C':
+                return 6;
+            case 'T':
+                return 7;
+            case 'G':
+                return 8;
+            case 'M':
+                return 9;
+            case 'N':
+                return 10;
+            case 'y':
+                return 11;
+            case 't':
+                return 12;
+            default:
+                return 100 + c.type - 'h';
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/a0ac605d/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/optimizer/jdk1.2.2_017.txt.gz
----------------------------------------------------------------------
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/optimizer/jdk1.2.2_017.txt.gz b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/optimizer/jdk1.2.2_017.txt.gz
new file mode 100644
index 0000000..39cdf9d
Binary files /dev/null and b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/optimizer/jdk1.2.2_017.txt.gz differ

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/a0ac605d/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/optimizer/jdk1.3.1_19.txt.gz
----------------------------------------------------------------------
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/optimizer/jdk1.3.1_19.txt.gz b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/optimizer/jdk1.3.1_19.txt.gz
new file mode 100644
index 0000000..a3c7aa6
Binary files /dev/null and b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/optimizer/jdk1.3.1_19.txt.gz differ

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/a0ac605d/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/optimizer/shrink-annotations.properties
----------------------------------------------------------------------
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/optimizer/shrink-annotations.properties b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/optimizer/shrink-annotations.properties
new file mode 100644
index 0000000..03fec2e
--- /dev/null
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/optimizer/shrink-annotations.properties
@@ -0,0 +1,53 @@
+###############################################################################
+#ASM: a very small and fast Java bytecode manipulation framework
+#Copyright (c) 2000-2011 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.
+###############################################################################
+
+# class mappings
+
+org/objectweb/asm/AnnotationWriter/remove=true
+
+# field mappings
+
+org/objectweb/asm/ClassWriter.anns=-
+org/objectweb/asm/ClassWriter.ianns=-
+
+org/objectweb/asm/FieldWriter.anns=-
+org/objectweb/asm/FieldWriter.ianns=-
+
+org/objectweb/asm/MethodWriter.annd=-
+org/objectweb/asm/MethodWriter.anns=-
+org/objectweb/asm/MethodWriter.ianns=-
+org/objectweb/asm/MethodWriter.panns=-
+org/objectweb/asm/MethodWriter.ipanns=-
+
+# method mappings
+
+org/objectweb/asm/ClassReader.readAnnotationValue(I[CLjava/lang/String;Lorg/objectweb/asm/AnnotationVisitor;)I=-
+org/objectweb/asm/ClassReader.readAnnotationValues(I[CZLorg/objectweb/asm/AnnotationVisitor;)I=-
+org/objectweb/asm/ClassReader.readParameterAnnotations(I[CZLorg/objectweb/asm/MethodVisitor;)V=-