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 18:57:57 UTC

git commit: FIXED - TAP5-2214: Make tapestry5 java8 compatible - update ASM source to 5.0.1

Repository: tapestry-5
Updated Branches:
  refs/heads/master cb2ef6a24 -> b6ea90f11


FIXED - TAP5-2214: Make tapestry5 java8 compatible 
- update ASM source to 5.0.1


Project: http://git-wip-us.apache.org/repos/asf/tapestry-5/repo
Commit: http://git-wip-us.apache.org/repos/asf/tapestry-5/commit/b6ea90f1
Tree: http://git-wip-us.apache.org/repos/asf/tapestry-5/tree/b6ea90f1
Diff: http://git-wip-us.apache.org/repos/asf/tapestry-5/diff/b6ea90f1

Branch: refs/heads/master
Commit: b6ea90f114176f54814483e03c55f943c0fa5595
Parents: cb2ef6a
Author: kaosko <ka...@apache.org>
Authored: Tue Mar 25 10:57:53 2014 -0700
Committer: kaosko <ka...@apache.org>
Committed: Tue Mar 25 10:57:53 2014 -0700

----------------------------------------------------------------------
 plastic/NOTICE.txt                              |  2 +-
 .../internal/plastic/asm/ClassWriter.java       | 28 +++++-
 .../internal/plastic/asm/MethodWriter.java      | 99 ++++++++++----------
 .../plastic/asm/commons/InstructionAdapter.java |  2 +-
 .../asm/commons/SerialVersionUIDAdder.java      |  4 +-
 .../plastic/asm/optimizer/ClassOptimizer.java   | 89 +++++++++++++++++-
 .../plastic/asm/optimizer/MethodOptimizer.java  | 63 ++-----------
 7 files changed, 171 insertions(+), 116 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/b6ea90f1/plastic/NOTICE.txt
----------------------------------------------------------------------
diff --git a/plastic/NOTICE.txt b/plastic/NOTICE.txt
index ec83bda..beec8e0 100644
--- a/plastic/NOTICE.txt
+++ b/plastic/NOTICE.txt
@@ -1,6 +1,6 @@
 This product includes software developed by
 The Apache Software Foundation (http://www.apache.org/).
 
-This product imports and repackages ASM 5.0 code which is
+This product imports and repackages ASM 5.0.1 code which is
 released under a BSD style License
 http://asm.ow2.org/license.html

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/b6ea90f1/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/ClassWriter.java
----------------------------------------------------------------------
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/ClassWriter.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/ClassWriter.java
index 5074b0f..6cd89a5 100644
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/ClassWriter.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/ClassWriter.java
@@ -756,11 +756,29 @@ public class ClassWriter extends ClassVisitor {
         if (innerClasses == null) {
             innerClasses = new ByteVector();
         }
-        ++innerClassesCount;
-        innerClasses.putShort(name == null ? 0 : newClass(name));
-        innerClasses.putShort(outerName == null ? 0 : newClass(outerName));
-        innerClasses.putShort(innerName == null ? 0 : newUTF8(innerName));
-        innerClasses.putShort(access);
+        // �4.7.6 of the JVMS states "Every CONSTANT_Class_info entry in the
+        // constant_pool table which represents a class or interface C that is
+        // not a package member must have exactly one corresponding entry in the
+        // classes array". To avoid duplicates we keep track in the intVal field
+        // of the Item of each CONSTANT_Class_info entry C whether an inner
+        // class entry has already been added for C (this field is unused for
+        // class entries, and changing its value does not change the hashcode
+        // and equality tests). If so we store the index of this inner class
+        // entry (plus one) in intVal. This hack allows duplicate detection in
+        // O(1) time.
+        Item nameItem = newClassItem(name);
+        if (nameItem.intVal == 0) {
+            ++innerClassesCount;
+            innerClasses.putShort(nameItem.index);
+            innerClasses.putShort(outerName == null ? 0 : newClass(outerName));
+            innerClasses.putShort(innerName == null ? 0 : newUTF8(innerName));
+            innerClasses.putShort(access);
+            nameItem.intVal = innerClassesCount;
+        } else {
+            // Compare the inner classes entry nameItem.intVal - 1 with the
+            // arguments of this method and throw an exception if there is a
+            // difference?
+        }
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/b6ea90f1/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/MethodWriter.java
----------------------------------------------------------------------
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/MethodWriter.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/MethodWriter.java
index 9900fbf..3128ff6 100644
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/MethodWriter.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/MethodWriter.java
@@ -43,7 +43,7 @@ class MethodWriter extends MethodVisitor {
      * Pseudo access flag used to denote constructors.
      */
     static final int ACC_CONSTRUCTOR = 0x80000;
-    
+
     /**
      * Frame has exactly the same locals as the previous stack map frame and
      * number of stack items is zero.
@@ -1401,6 +1401,14 @@ class MethodWriter extends MethodVisitor {
 
     @Override
     public void visitMaxs(final int maxStack, final int maxLocals) {
+        if (resize) {
+            // replaces the temporary jump opcodes introduced by Label.resolve.
+            if (ClassReader.RESIZE) {
+                resizeInstructions();
+            } else {
+                throw new RuntimeException("Method code too large!");
+            }
+        }
         if (ClassReader.FRAMES && compute == FRAMES) {
             // completes the control flow graph with exception handler blocks
             Handler handler = firstHandler;
@@ -2022,14 +2030,6 @@ class MethodWriter extends MethodVisitor {
         if (classReaderOffset != 0) {
             return 6 + classReaderLength;
         }
-        if (resize) {
-            // replaces the temporary jump opcodes introduced by Label.resolve.
-            if (ClassReader.RESIZE) {
-                resizeInstructions();
-            } else {
-                throw new RuntimeException("Method code too large!");
-            }
-        }
         int size = 8;
         if (code.length > 0) {
             if (code.length > 65536) {
@@ -2686,49 +2686,50 @@ class MethodWriter extends MethodVisitor {
             }
         }
 
-        // recomputes the stack map frames
-        if (frameCount > 0) {
-            if (compute == FRAMES) {
-                frameCount = 0;
-                stackMap = null;
-                previousFrame = null;
-                frame = null;
-                Frame f = new Frame();
-                f.owner = labels;
-                Type[] args = Type.getArgumentTypes(descriptor);
-                f.initInputFrame(cw, access, args, maxLocals);
-                visitFrame(f);
-                Label l = labels;
-                while (l != null) {
-                    /*
-                     * here we need the original label position. getNewOffset
-                     * must therefore never have been called for this label.
-                     */
-                    u = l.position - 3;
-                    if ((l.status & Label.STORE) != 0 || (u >= 0 && resize[u])) {
-                        getNewOffset(allIndexes, allSizes, l);
-                        // TODO update offsets in UNINITIALIZED values
-                        visitFrame(l.frame);
-                    }
-                    l = l.successor;
-                }
-            } else {
+        // updates the stack map frame labels
+        if (compute == FRAMES) {
+            Label l = labels;
+            while (l != null) {
                 /*
-                 * Resizing an existing stack map frame table is really hard.
-                 * Not only the table must be parsed to update the offets, but
-                 * new frames may be needed for jump instructions that were
-                 * inserted by this method. And updating the offsets or
-                 * inserting frames can change the format of the following
-                 * frames, in case of packed frames. In practice the whole table
-                 * must be recomputed. For this the frames are marked as
-                 * potentially invalid. This will cause the whole class to be
-                 * reread and rewritten with the COMPUTE_FRAMES option (see the
-                 * ClassWriter.toByteArray method). This is not very efficient
-                 * but is much easier and requires much less code than any other
-                 * method I can think of.
+                 * Detects the labels that are just after an IF instruction that
+                 * has been resized with the IFNOT GOTO_W pattern. These labels
+                 * are now the target of a jump instruction (the IFNOT
+                 * instruction). Note that we need the original label position
+                 * here. getNewOffset must therefore never have been called for
+                 * this label.
                  */
-                cw.invalidFrames = true;
+                u = l.position - 3;
+                if (u >= 0 && resize[u]) {
+                    l.status |= Label.TARGET;
+                }
+                getNewOffset(allIndexes, allSizes, l);
+                l = l.successor;
             }
+            // Update the offsets in the uninitialized types
+            for (i = 0; i < cw.typeTable.length; ++i) {
+                Item item = cw.typeTable[i];
+                if (item != null && item.type == ClassWriter.TYPE_UNINIT) {
+                    item.intVal = getNewOffset(allIndexes, allSizes, 0,
+                            item.intVal);
+                }
+            }
+            // The stack map frames are not serialized yet, so we don't need
+            // to update them. They will be serialized in visitMaxs.
+        } else if (frameCount > 0) {
+            /*
+             * Resizing an existing stack map frame table is really hard. Not
+             * only the table must be parsed to update the offets, but new
+             * frames may be needed for jump instructions that were inserted by
+             * this method. And updating the offsets or inserting frames can
+             * change the format of the following frames, in case of packed
+             * frames. In practice the whole table must be recomputed. For this
+             * the frames are marked as potentially invalid. This will cause the
+             * whole class to be reread and rewritten with the COMPUTE_FRAMES
+             * option (see the ClassWriter.toByteArray method). This is not very
+             * efficient but is much easier and requires much less code than any
+             * other method I can think of.
+             */
+            cw.invalidFrames = true;
         }
         // updates the exception handler block labels
         Handler h = firstHandler;

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/b6ea90f1/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/InstructionAdapter.java
----------------------------------------------------------------------
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/InstructionAdapter.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/InstructionAdapter.java
index dd10e0b..fe8400a 100644
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/InstructionAdapter.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/InstructionAdapter.java
@@ -1060,7 +1060,7 @@ public class InstructionAdapter extends MethodVisitor {
     @Deprecated
     public void invokestatic(final String owner, final String name,
             final String desc) {
-        if (api < Opcodes.ASM5) {
+        if (api >= Opcodes.ASM5) {
             invokestatic(owner, name, desc, false);
             return;
         }

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/b6ea90f1/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/SerialVersionUIDAdder.java
----------------------------------------------------------------------
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/SerialVersionUIDAdder.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/SerialVersionUIDAdder.java
index 7ce521c..04dcc9b 100644
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/SerialVersionUIDAdder.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/commons/SerialVersionUIDAdder.java
@@ -210,7 +210,9 @@ public class SerialVersionUIDAdder extends ClassVisitor {
         if (computeSVUID) {
             this.name = name;
             this.access = access;
-            this.interfaces = Arrays.copyOf(interfaces, interfaces.length);
+            this.interfaces = new String[interfaces.length];
+            System.arraycopy(interfaces, 0, this.interfaces, 0,
+                    interfaces.length);
         }
 
         super.visit(version, access, name, signature, superName, interfaces);

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/b6ea90f1/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
index ac34ba7..f4a7a22 100644
--- 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
@@ -29,10 +29,14 @@
  */
 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;
@@ -50,7 +54,10 @@ public class ClassOptimizer extends RemappingClassAdapter {
 
     private String pkgName;
     String clsName;
-    boolean class$;
+
+    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);
@@ -70,13 +77,14 @@ public class ClassOptimizer extends RemappingClassAdapter {
             final String signature, final String superName,
             final String[] interfaces) {
         super.visit(Opcodes.V1_2, access, name, null, superName, interfaces);
-        clsName = name;
         int index = name.lastIndexOf('/');
         if (index > 0) {
             pkgName = name.substring(0, index);
         } else {
             pkgName = "";
         }
+        clsName = name;
+        isInterface = (access & Opcodes.ACC_INTERFACE) != 0;
     }
 
     @Override
@@ -149,6 +157,19 @@ public class ClassOptimizer extends RemappingClassAdapter {
         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("<")
@@ -172,4 +193,68 @@ public class ClassOptimizer extends RemappingClassAdapter {
             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/b6ea90f1/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
index afb4b27..adad6b4 100644
--- 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
@@ -50,8 +50,6 @@ public class MethodOptimizer extends RemappingMethodAdapter implements Opcodes {
 
     private final ClassOptimizer classOptimizer;
 
-    private boolean ldcClass = false;
-
     public MethodOptimizer(ClassOptimizer classOptimizer, int access,
             String desc, MethodVisitor mv, Remapper remapper) {
         super(Opcodes.ASM5, access, desc, mv, remapper);
@@ -122,66 +120,17 @@ public class MethodOptimizer extends RemappingMethodAdapter implements Opcodes {
             return;
         }
 
-        // transform Foo.class to foo$(class) for 1.2 compatibility
+        // transform Foo.class for 1.2 compatibility
         String ldcName = ((Type) cst).getInternalName();
         String fieldName = "class$" + ldcName.replace('/', '$');
-
-        FieldVisitor fv = classOptimizer.syntheticFieldVisitor(ACC_STATIC
-                | ACC_SYNTHETIC, fieldName, "Ljava/lang/Class;");
-        fv.visitEnd();
-
-        if (!classOptimizer.class$) {
-            MethodVisitor mv = classOptimizer.visitMethod(ACC_STATIC
-                    | 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(ALOAD, 0);
-            mv.visitMethodInsn(INVOKESTATIC, "java/lang/Class", "forName",
-                    "(Ljava/lang/String;)Ljava/lang/Class;", false);
-            mv.visitLabel(l1);
-            mv.visitInsn(ARETURN);
-            mv.visitLabel(l2);
-            mv.visitMethodInsn(INVOKEVIRTUAL,
-                    "java/lang/ClassNotFoundException", "getMessage",
-                    "()Ljava/lang/String;", false);
-            mv.visitVarInsn(ASTORE, 1);
-            mv.visitTypeInsn(NEW, "java/lang/NoClassDefFoundError");
-            mv.visitInsn(DUP);
-            mv.visitVarInsn(ALOAD, 1);
-            mv.visitMethodInsn(INVOKESPECIAL, "java/lang/NoClassDefFoundError",
-                    "<init>", "(Ljava/lang/String;)V", false);
-            mv.visitInsn(ATHROW);
-            mv.visitMaxs(3, 2);
-            mv.visitEnd();
-
-            classOptimizer.class$ = true;
+        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;");
-        Label elseLabel = new Label();
-        mv.visitJumpInsn(IFNONNULL, elseLabel);
-        mv.visitLdcInsn(ldcName.replace('/', '.'));
-        mv.visitMethodInsn(INVOKESTATIC, clsName, "class$",
-                "(Ljava/lang/String;)Ljava/lang/Class;", false);
-        mv.visitInsn(DUP);
-        mv.visitFieldInsn(PUTSTATIC, clsName, fieldName, "Ljava/lang/Class;");
-        Label endLabel = new Label();
-        mv.visitJumpInsn(GOTO, endLabel);
-        mv.visitLabel(elseLabel);
-        mv.visitFieldInsn(GETSTATIC, clsName, fieldName, "Ljava/lang/Class;");
-        mv.visitLabel(endLabel);
-        ldcClass = true;
-    }
-
-    @Override
-    public void visitMaxs(int maxStack, int maxLocals) {
-        super.visitMaxs(ldcClass ? maxStack + 1 : maxStack, maxLocals);
     }
 }