[jboss-cvs] javassist SVN: r669 - in trunk/src: main/javassist/bytecode and 5 other directories.

jboss-cvs-commits at lists.jboss.org jboss-cvs-commits at lists.jboss.org
Thu Oct 4 03:37:39 EDT 2012


Author: chiba
Date: 2012-10-04 03:37:39 -0400 (Thu, 04 Oct 2012)
New Revision: 669

Added:
   trunk/src/main/javassist/bytecode/BootstrapMethodsAttribute.java
   trunk/src/test/test4/InvokeDyn.java
Modified:
   trunk/src/main/javassist/CtBehavior.java
   trunk/src/main/javassist/bytecode/AttributeInfo.java
   trunk/src/main/javassist/bytecode/Bytecode.java
   trunk/src/main/javassist/bytecode/CodeAnalyzer.java
   trunk/src/main/javassist/bytecode/CodeAttribute.java
   trunk/src/main/javassist/bytecode/CodeIterator.java
   trunk/src/main/javassist/bytecode/ConstPool.java
   trunk/src/main/javassist/bytecode/InstructionPrinter.java
   trunk/src/main/javassist/bytecode/MethodInfo.java
   trunk/src/main/javassist/bytecode/Mnemonic.java
   trunk/src/main/javassist/bytecode/Opcode.java
   trunk/src/main/javassist/bytecode/StackMapTable.java
   trunk/src/main/javassist/bytecode/analysis/Executor.java
   trunk/src/main/javassist/bytecode/stackmap/Tracer.java
   trunk/src/test/javassist/JvstTest4.java
   trunk/src/test/javassist/bytecode/BytecodeTest.java
   trunk/src/test/javassist/bytecode/StackMapTest.java
Log:
fixed JASSIST-174

Modified: trunk/src/main/javassist/CtBehavior.java
===================================================================
--- trunk/src/main/javassist/CtBehavior.java	2012-09-29 01:20:28 UTC (rev 668)
+++ trunk/src/main/javassist/CtBehavior.java	2012-10-04 07:37:39 UTC (rev 669)
@@ -26,6 +26,11 @@
  * or a static constructor (class initializer). 
  * It is the abstract super class of
  * <code>CtMethod</code> and <code>CtConstructor</code>.
+ *
+ * <p>To directly read or modify bytecode, obtain <code>MethodInfo</code>
+ * objects.
+ *
+ * @see #getMethodInfo()
  */
 public abstract class CtBehavior extends CtMember {
     protected MethodInfo methodInfo;

Modified: trunk/src/main/javassist/bytecode/AttributeInfo.java
===================================================================
--- trunk/src/main/javassist/bytecode/AttributeInfo.java	2012-09-29 01:20:28 UTC (rev 668)
+++ trunk/src/main/javassist/bytecode/AttributeInfo.java	2012-10-04 07:37:39 UTC (rev 669)
@@ -77,6 +77,8 @@
         if (nameStr.charAt(0) < 'L') {
             if (nameStr.equals(AnnotationDefaultAttribute.tag))
                 return new AnnotationDefaultAttribute(cp, name, in);
+            else if (nameStr.equals(BootstrapMethodsAttribute.tag))
+                return new BootstrapMethodsAttribute(cp, name, in);
             else if (nameStr.equals(CodeAttribute.tag))
                 return new CodeAttribute(cp, name, in);
             else if (nameStr.equals(ConstantAttribute.tag))

Added: trunk/src/main/javassist/bytecode/BootstrapMethodsAttribute.java
===================================================================
--- trunk/src/main/javassist/bytecode/BootstrapMethodsAttribute.java	                        (rev 0)
+++ trunk/src/main/javassist/bytecode/BootstrapMethodsAttribute.java	2012-10-04 07:37:39 UTC (rev 669)
@@ -0,0 +1,123 @@
+package javassist.bytecode;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.util.Map;
+
+public class BootstrapMethodsAttribute extends AttributeInfo {
+    /**
+     * The name of this attribute <code>"BootstrapMethods"</code>.
+     */
+    public static final String tag = "BootstrapMethods";
+
+    /**
+     * An element of <code>bootstrap_methods</code>.
+     */
+    public static class BootstrapMethod {
+        /**
+         * Constructs an element of <code>bootstrap_methods</code>.
+         *
+         * @param method        <code>bootstrap_method_ref</code>.
+         * @param args          <code>bootstrap_arguments</code>.
+         */
+        public BootstrapMethod(int method, int[] args) {
+            methodRef = method;
+            arguments = args;
+        }
+
+        /**
+         * <code>bootstrap_method_ref</code>.
+         * The value at this index must be a <code>CONSTANT_MethodHandle_info</code>.
+         */
+        public int methodRef;
+
+        /**
+         * <code>bootstrap_arguments</code>.
+         */
+        public int[] arguments;
+    }
+
+    BootstrapMethodsAttribute(ConstPool cp, int n, DataInputStream in)
+        throws IOException
+    {
+        super(cp, n, in);
+    }
+
+    /**
+     * Constructs a BootstrapMethods attribute.
+     *
+     * @param cp                a constant pool table.
+     * @param methods           the contents.
+     */
+    public BootstrapMethodsAttribute(ConstPool cp, BootstrapMethod[] methods) {
+        super(cp, tag);
+        int size = 2;
+        for (int i = 0; i < methods.length; i++)
+            size += 4 + methods[i].arguments.length * 2;
+
+        byte[] data = new byte[size];
+        ByteArray.write16bit(methods.length, data, 0);    // num_bootstrap_methods
+        int pos = 2;
+        for (int i = 0; i < methods.length; i++) {
+            ByteArray.write16bit(methods[i].methodRef, data, pos);
+            ByteArray.write16bit(methods[i].arguments.length, data, pos + 2);
+            int[] args = methods[i].arguments;
+            pos += 4;
+            for (int k = 0; k < args.length; k++) {
+                ByteArray.write16bit(args[k], data, pos);
+                pos += 2;
+            }
+        }
+
+        set(data);
+    }
+
+    /**
+     * Obtains <code>bootstrap_methods</code> in this attribute.
+     *
+     * @return an array of <code>BootstrapMethod</code>.  Since it
+     *          is a fresh copy, modifying the returned array does not
+     *          affect the original contents of this attribute.
+     */
+    public BootstrapMethod[] getMethods() {
+        byte[] data = this.get();
+        int num = ByteArray.readU16bit(data, 0);
+        BootstrapMethod[] methods = new BootstrapMethod[num];
+        int pos = 2;
+        for (int i = 0; i < num; i++) {
+            int ref = ByteArray.readU16bit(data, pos);
+            int len = ByteArray.readU16bit(data, pos + 2);
+            int[] args = new int[len];
+            pos += 4;
+            for (int k = 0; k < len; k++) {
+                args[k] = ByteArray.readU16bit(data, pos);
+                pos += 2;
+            }
+
+            methods[i] = new BootstrapMethod(ref, args);
+        }
+
+        return methods;
+    }
+
+    /**
+     * Makes a copy.  Class names are replaced according to the
+     * given <code>Map</code> object.
+     *
+     * @param newCp     the constant pool table used by the new copy.
+     * @param classnames        pairs of replaced and substituted
+     *                          class names.
+     */
+    public AttributeInfo copy(ConstPool newCp, Map classnames) {
+        BootstrapMethod[] methods = getMethods();
+        ConstPool thisCp = getConstPool();
+        for (int i = 0; i < methods.length; i++) {
+            BootstrapMethod m = methods[i];
+            m.methodRef = thisCp.copy(m.methodRef, newCp, classnames);
+            for (int k = 0; k < m.arguments.length; k++)
+                m.arguments[k] = thisCp.copy(m.arguments[k], newCp, classnames);
+        }
+
+        return new BootstrapMethodsAttribute(newCp, methods);
+    }
+}


Property changes on: trunk/src/main/javassist/bytecode/BootstrapMethodsAttribute.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Modified: trunk/src/main/javassist/bytecode/Bytecode.java
===================================================================
--- trunk/src/main/javassist/bytecode/Bytecode.java	2012-09-29 01:20:28 UTC (rev 668)
+++ trunk/src/main/javassist/bytecode/Bytecode.java	2012-10-04 07:37:39 UTC (rev 669)
@@ -1083,7 +1083,7 @@
     public void addInvokevirtual(int clazz, String name, String desc) {
         add(INVOKEVIRTUAL);
         addIndex(constPool.addMethodrefInfo(clazz, name, desc));
-        growStack(Descriptor.dataSize(desc) - 1);
+        growStack(Descriptor.dataSize(desc));   // assume CosntPool#REF_invokeStatic
     }
 
     /**
@@ -1155,6 +1155,25 @@
     }
 
     /**
+     * Appends INVOKEDYNAMIC.
+     *
+     * @param bootstrap     an index into the <code>bootstrap_methods</code> array
+     *                      of the bootstrap method table.     
+     * @param name          the method name.
+     * @param desc          the method descriptor.
+     * @see Descriptor#ofMethod(CtClass,CtClass[])
+     * @since 3.17
+     */
+    public void addInvokedynamic(int bootstrap, String name, String desc) {
+        int nt = constPool.addNameAndTypeInfo(name, desc);
+        int dyn = constPool.addInvokeDynamicInfo(bootstrap, nt);
+        add(INVOKEDYNAMIC);
+        addIndex(dyn);
+        add(0, 0);
+        growStack(Descriptor.dataSize(desc) - 1);
+    }
+
+    /**
      * Appends LDC or LDC_W.  The pushed item is a <code>String</code>
      * object.
      *

Modified: trunk/src/main/javassist/bytecode/CodeAnalyzer.java
===================================================================
--- trunk/src/main/javassist/bytecode/CodeAnalyzer.java	2012-09-29 01:20:28 UTC (rev 668)
+++ trunk/src/main/javassist/bytecode/CodeAnalyzer.java	2012-10-04 07:37:39 UTC (rev 669)
@@ -240,6 +240,10 @@
                                             ci.u16bitAt(index + 1));
             stack += Descriptor.dataSize(desc) - 1;
             break;
+        case INVOKEDYNAMIC :
+            desc = constPool.getInvokeDynamicType(ci.u16bitAt(index + 1));
+            stack += Descriptor.dataSize(desc);     // assume CosntPool#REF_invokeStatic
+            break;
         case ATHROW :
             stack = 1;      // the stack becomes empty (1 means no values).
             break;

Modified: trunk/src/main/javassist/bytecode/CodeAttribute.java
===================================================================
--- trunk/src/main/javassist/bytecode/CodeAttribute.java	2012-09-29 01:20:28 UTC (rev 668)
+++ trunk/src/main/javassist/bytecode/CodeAttribute.java	2012-10-04 07:37:39 UTC (rev 669)
@@ -32,6 +32,7 @@
  * use <code>CodeIterator</code>.
  *
  * @see CodeIterator
+ * @see #iterator()
  */
 public class CodeAttribute extends AttributeInfo implements Opcode {
     /**
@@ -400,6 +401,12 @@
                 newcode[i + 3] = code[i + 3];
                 newcode[i + 4] = code[i + 4];
                 break;
+            case INVOKEDYNAMIC :
+                copyConstPoolInfo(i + 1, code, srcCp, newcode, destCp,
+                        classnameMap);
+                newcode[i + 3] = 0;
+                newcode[i + 4] = 0;
+                break;
             case MULTIANEWARRAY :
                 copyConstPoolInfo(i + 1, code, srcCp, newcode, destCp,
                                   classnameMap);

Modified: trunk/src/main/javassist/bytecode/CodeIterator.java
===================================================================
--- trunk/src/main/javassist/bytecode/CodeIterator.java	2012-09-29 01:20:28 UTC (rev 668)
+++ trunk/src/main/javassist/bytecode/CodeIterator.java	2012-10-04 07:37:39 UTC (rev 669)
@@ -21,6 +21,16 @@
 /**
  * An iterator for editing a code attribute.
  *
+ * <p>To directly read or edit a bytecode sequence, call {@link #byteAt(int)}, {@link #s16bitAt(int)},
+ * {@link #writeByte(int, int)}, {@link #write16bit(int, int)}, and other methods.
+ * For example, if <code>method</code> refers to a <code>CtMethod</code> object,
+ * the following code substitutes the <code>NOP</code> instruction for the first
+ * instruction of the method:  
+ *
+ * <pre>CodeAttribute ca = method.getMethodInfo().getCodeAttribute();
+ * CodeIterator ci = ca.iterator();
+ * ci.writeByte(Opcode.NOP, 0);</pre>
+ *
  * <p>If there are multiple <code>CodeIterator</code>s referring to the
  * same <code>Code_attribute</code>, then inserting a gap by one
  * <code>CodeIterator</code> will break the other
@@ -725,11 +735,10 @@
         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1,
         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3,
         3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 0, 0, 1, 1, 1, 1, 1, 1, 3, 3,
-     // 3, 3, 3, 3, 3, 5, 5, 3, 2, 3, 1, 1, 3, 3, 1, 1, 0, 4, 3, 3,
-        3, 3, 3, 3, 3, 5, 0, 3, 2, 3, 1, 1, 3, 3, 1, 1, 0, 4, 3, 3,
+        3, 3, 3, 3, 3, 5, 5, 3, 2, 3, 1, 1, 3, 3, 1, 1, 0, 4, 3, 3,
         5, 5
     };
-    // 0 .. UNUSED (186), LOOKUPSWITCH, TABLESWITCH, WIDE
+    // 0 .. LOOKUPSWITCH, TABLESWITCH, WIDE
 
     /**
      * Calculates the index of the next opcode.
@@ -1496,7 +1505,9 @@
             int padding = 3 - (pos & 3);
             int nops = gap - padding;
             int bytecodeSize = 5 + (3 - (orgPos & 3)) + tableSize();
-            adjustOffsets(bytecodeSize, nops);
+            if (nops > 0)
+                adjustOffsets(bytecodeSize, nops);
+
             newcode[dest++] = code[src];
             while (padding-- > 0)
                 newcode[dest++] = 0;

Modified: trunk/src/main/javassist/bytecode/ConstPool.java
===================================================================
--- trunk/src/main/javassist/bytecode/ConstPool.java	2012-09-29 01:20:28 UTC (rev 668)
+++ trunk/src/main/javassist/bytecode/ConstPool.java	2012-10-04 07:37:39 UTC (rev 669)
@@ -94,11 +94,61 @@
     public static final int CONST_Utf8 = Utf8Info.tag;
 
     /**
+     * <code>Cosnt_MethodHandle</code>
+     */
+    public static final int CONST_MethodHandle = MethodHandleInfo.tag;
+
+    /**
      * Represents the class using this constant pool table.
      */
     public static final CtClass THIS = null;
 
     /**
+     * <code>reference_kind</code> of <code>CONSTANT_MethodHandle_info</code>.
+     */
+    public static final int REF_getField = 1;
+
+    /**
+     * <code>reference_kind</code> of <code>CONSTANT_MethodHandle_info</code>.
+     */
+    public static final int REF_getStatic = 2;
+
+    /**
+     * <code>reference_kind</code> of <code>CONSTANT_MethodHandle_info</code>.
+     */
+    public static final int REF_putField = 3;
+
+    /**
+     * <code>reference_kind</code> of <code>CONSTANT_MethodHandle_info</code>.
+     */
+    public static final int REF_putStatic = 4;
+
+    /**
+     * <code>reference_kind</code> of <code>CONSTANT_MethodHandle_info</code>.
+     */
+    public static final int REF_invokeVirtual = 5;
+
+    /**
+     * <code>reference_kind</code> of <code>CONSTANT_MethodHandle_info</code>.
+     */
+    public static final int REF_invokeStatic = 6;
+
+    /**
+     * <code>reference_kind</code> of <code>CONSTANT_MethodHandle_info</code>.
+     */
+    public static final int REF_invokeSpecial = 7;
+
+    /**
+     * <code>reference_kind</code> of <code>CONSTANT_MethodHandle_info</code>.
+     */
+    public static final int REF_newInvokeSpecial = 8;
+
+    /**
+     * <code>reference_kind</code> of <code>CONSTANT_MethodHandle_info</code>.
+     */
+    public static final int REF_invokeInterface = 9;
+
+    /**
      * Constructs a constant pool table.
      *
      * @param thisclass         the name of the class using this constant
@@ -589,6 +639,97 @@
     }
 
     /**
+     * Reads the <code>reference_kind</code> field of the
+     * <code>CONSTANT_MethodHandle_info</code> structure
+     * at the given index.
+     *
+     * @see #REF_getField
+     * @see #REF_getStatic
+     * @see #REF_invokeInterface
+     * @see #REF_invokeSpecial
+     * @see #REF_invokeStatic
+     * @see #REF_invokeVirtual
+     * @see #REF_newInvokeSpecial
+     * @see #REF_putField
+     * @see #REF_putStatic
+     * @since 3.17
+     */
+    public int getMethodHandleKind(int index) {
+        MethodHandleInfo mhinfo = (MethodHandleInfo)getItem(index);
+        return mhinfo.refKind;
+    }
+
+    /**
+     * Reads the <code>reference_index</code> field of the
+     * <code>CONSTANT_MethodHandle_info</code> structure
+     * at the given index.
+     *
+     * @since 3.17
+     */
+    public int getMethodHandleIndex(int index) {
+        MethodHandleInfo mhinfo = (MethodHandleInfo)getItem(index);
+        return mhinfo.refIndex;
+    }
+
+    /**
+     * Reads the <code>descriptor_index</code> field of the
+     * <code>CONSTANT_MethodType_info</code> structure
+     * at the given index.
+     *
+     * @since 3.17
+     */
+    public int getMethodTypeInfo(int index) {
+        MethodTypeInfo mtinfo = (MethodTypeInfo)getItem(index);
+        return mtinfo.descriptor;
+    }
+
+    /**
+     * Reads the <code>bootstrap_method_attr_index</code> field of the
+     * <code>CONSTANT_InvokeDynamic_info</code> structure
+     * at the given index.
+     *
+     * @since 3.17
+     */
+    public int getInvokeDynamicBootstrap(int index) {
+        InvokeDynamicInfo iv = (InvokeDynamicInfo)getItem(index);
+        return iv.bootstrap;
+    }
+
+    /**
+     * Reads the <code>name_and_type_index</code> field of the
+     * <code>CONSTANT_InvokeDynamic_info</code> structure
+     * at the given index.
+     *
+     * @since 3.17
+     */
+    public int getInvokeDynamicNameAndType(int index) {
+        InvokeDynamicInfo iv = (InvokeDynamicInfo)getItem(index);
+        return iv.nameAndType;
+    }
+
+    /**
+     * Reads the <code>descriptor_index</code> field of the
+     * <code>CONSTANT_NameAndType_info</code> structure
+     * indirectly specified by the given index.
+     *
+     * @param index     an index to a <code>CONSTANT_InvokeDynamic_info</code>.
+     * @return  the descriptor of the method.
+     * @since 3.17
+     */
+    public String getInvokeDynamicType(int index) {
+        InvokeDynamicInfo iv = (InvokeDynamicInfo)getItem(index);
+        if (iv == null)
+            return null;
+        else {
+            NameAndTypeInfo n = (NameAndTypeInfo)getItem(iv.nameAndType);
+            if(n == null)
+                return null;
+            else
+                return getUtf8Info(n.typeDescriptor);
+        }
+    }
+
+    /**
      * Determines whether <code>CONSTANT_Methodref_info</code>
      * structure at the given index represents the constructor
      * of the given class.
@@ -927,6 +1068,48 @@
     }
 
     /**
+     * Adds a new <code>CONSTANT_MethodHandle_info</code>
+     * structure.
+     *
+     * @param kind      <code>reference_kind</code>
+     *                  such as {@link #REF_invokeStatic <code>REF_invokeStatic</code>}.
+     * @param index     <code>reference_index</code>.
+     * @return          the index of the added entry.
+     *
+     * @since 3.17
+     */
+    public int addMethodHandleInfo(int kind, int index) {
+        return addItem(new MethodHandleInfo(kind, index, numOfItems));
+    }
+
+    /**
+     * Adds a new <code>CONSTANT_MethodType_info</code>
+     * structure.
+     *
+     * @param desc      <code>descriptor_index</code>.
+     * @return          the index of the added entry.
+     *
+     * @since 3.17
+     */
+    public int addMethodTypeInfo(int desc) {
+        return addItem(new MethodTypeInfo(desc, numOfItems));
+    }
+
+    /**
+     * Adds a new <code>CONSTANT_InvokeDynamic_info</code>
+     * structure.
+     *
+     * @param bootstrap     <code>bootstrap_method_attr_index</code>.
+     * @param nameAndType   <code>name_and_type_index</code>.
+     * @return          the index of the added entry.
+     *
+     * @since 3.17
+     */
+    public int addInvokeDynamicInfo(int bootstrap, int nameAndType) {
+        return addItem(new InvokeDynamicInfo(bootstrap, nameAndType, numOfItems));
+    }
+
+    /**
      * Get all the class names.
      *
      * @return a set of class names (<code>String</code> objects).
@@ -1040,6 +1223,15 @@
         case NameAndTypeInfo.tag :              // 12
             info = new NameAndTypeInfo(in, numOfItems);
             break;
+        case MethodHandleInfo.tag :             // 15
+            info = new MethodHandleInfo(in, numOfItems);
+            break;
+        case MethodTypeInfo.tag :               // 16
+            info = new MethodTypeInfo(in, numOfItems);
+            break;
+        case InvokeDynamicInfo.tag :            // 18
+            info = new InvokeDynamicInfo(in, numOfItems);
+            break;
         default :
             throw new IOException("invalid constant type: " + tag + " at " + numOfItems);
         }
@@ -1632,3 +1824,167 @@
         out.println("\"");
     }
 }
+
+class MethodHandleInfo extends ConstInfo {
+    static final int tag = 15;
+    int refKind, refIndex;
+
+    public MethodHandleInfo(int kind, int referenceIndex, int index) {
+        super(index);
+        refKind = kind;
+        refIndex = referenceIndex;
+    }
+
+    public MethodHandleInfo(DataInputStream in, int index) throws IOException {
+        super(index);
+        refKind = in.readUnsignedByte();
+        refIndex = in.readUnsignedShort();
+    }
+
+    public int hashCode() { return (refKind << 16) ^ refIndex; }
+
+    public boolean equals(Object obj) {
+        if (obj instanceof MethodHandleInfo) {
+            MethodHandleInfo mh = (MethodHandleInfo)obj;
+            return mh.refKind == refKind && mh.refIndex == refIndex; 
+        }
+        else
+            return false;
+    }
+
+    public int getTag() { return tag; }
+
+    public int copy(ConstPool src, ConstPool dest, Map map) {
+       return dest.addMethodHandleInfo(refKind,
+                           src.getItem(refIndex).copy(src, dest, map));
+    }
+
+    public void write(DataOutputStream out) throws IOException {
+        out.writeByte(tag);
+        out.writeByte(refKind);
+        out.writeShort(refIndex);
+    }
+
+    public void print(PrintWriter out) {
+        out.print("MethodHandle #");
+        out.print(refKind);
+        out.print(", index #");
+        out.println(refIndex);
+    }
+}
+
+class MethodTypeInfo extends ConstInfo {
+    static final int tag = 16;
+    int descriptor;
+
+    public MethodTypeInfo(int desc, int index) {
+        super(index);
+        descriptor = desc;
+    }
+
+    public MethodTypeInfo(DataInputStream in, int index) throws IOException {
+        super(index);
+        descriptor = in.readUnsignedShort();
+    }
+
+    public int hashCode() { return descriptor; }
+
+    public boolean equals(Object obj) {
+        if (obj instanceof MethodTypeInfo)
+            return ((MethodTypeInfo)obj).descriptor == descriptor;
+        else
+            return false;
+    }
+
+    public int getTag() { return tag; }
+
+    public void renameClass(ConstPool cp, String oldName, String newName, HashMap cache) {
+        String desc = cp.getUtf8Info(descriptor);
+        String desc2 = Descriptor.rename(desc, oldName, newName);
+        if (desc != desc2)
+            if (cache == null)
+                descriptor = cp.addUtf8Info(desc2);
+            else {
+                cache.remove(this);
+                descriptor = cp.addUtf8Info(desc2);
+                cache.put(this, this);
+            }
+    }
+
+    public void renameClass(ConstPool cp, Map map, HashMap cache) {
+        String desc = cp.getUtf8Info(descriptor);
+        String desc2 = Descriptor.rename(desc, map);
+        if (desc != desc2)
+            if (cache == null)
+                descriptor = cp.addUtf8Info(desc2);
+            else {
+                cache.remove(this);
+                descriptor = cp.addUtf8Info(desc2);
+                cache.put(this, this);
+            }
+    }
+
+    public int copy(ConstPool src, ConstPool dest, Map map) {
+        String desc = src.getUtf8Info(descriptor);
+        desc = Descriptor.rename(desc, map);
+        return dest.addMethodTypeInfo(dest.addUtf8Info(desc));
+    }
+
+    public void write(DataOutputStream out) throws IOException {
+        out.writeByte(tag);
+        out.writeShort(descriptor);
+    }
+
+    public void print(PrintWriter out) {
+        out.print("MethodType #");
+        out.println(descriptor);
+    }
+}
+
+class InvokeDynamicInfo extends ConstInfo {
+    static final int tag = 18;
+    int bootstrap, nameAndType;
+
+    public InvokeDynamicInfo(int bootstrapMethod, int ntIndex, int index) {
+        super(index);
+        bootstrap = bootstrapMethod;
+        nameAndType = ntIndex;
+    }
+
+    public InvokeDynamicInfo(DataInputStream in, int index) throws IOException {
+        super(index);
+        bootstrap = in.readUnsignedShort();
+        nameAndType = in.readUnsignedShort();
+    }
+
+    public int hashCode() { return (bootstrap << 16) ^ nameAndType; }
+
+    public boolean equals(Object obj) {
+        if (obj instanceof InvokeDynamicInfo) {
+            InvokeDynamicInfo iv = (InvokeDynamicInfo)obj;
+            return iv.bootstrap == bootstrap && iv.nameAndType == nameAndType;
+        }
+        else
+            return false;
+    }
+
+    public int getTag() { return tag; }
+
+    public int copy(ConstPool src, ConstPool dest, Map map) {
+       return dest.addInvokeDynamicInfo(bootstrap,
+                           src.getItem(nameAndType).copy(src, dest, map));
+    }
+
+    public void write(DataOutputStream out) throws IOException {
+        out.writeByte(tag);
+        out.writeShort(bootstrap);
+        out.writeShort(nameAndType);
+    }
+
+    public void print(PrintWriter out) {
+        out.print("InvokeDynamic #");
+        out.print(bootstrap);
+        out.print(", name&type #");
+        out.println(nameAndType);
+    }
+}

Modified: trunk/src/main/javassist/bytecode/InstructionPrinter.java
===================================================================
--- trunk/src/main/javassist/bytecode/InstructionPrinter.java	2012-09-29 01:20:28 UTC (rev 668)
+++ trunk/src/main/javassist/bytecode/InstructionPrinter.java	2012-10-04 07:37:39 UTC (rev 669)
@@ -137,8 +137,8 @@
                 return opstring + " " + methodInfo(pool, iter.u16bitAt(pos + 1));
             case INVOKEINTERFACE:
                 return opstring + " " + interfaceMethodInfo(pool, iter.u16bitAt(pos + 1));
-            case 186:
-                throw new RuntimeException("Bad opcode 186");
+            case INVOKEDYNAMIC:
+                return opstring + " " + iter.u16bitAt(pos + 1);
             case NEW:
                 return opstring + " " + classInfo(pool, iter.u16bitAt(pos + 1));
             case NEWARRAY:

Modified: trunk/src/main/javassist/bytecode/MethodInfo.java
===================================================================
--- trunk/src/main/javassist/bytecode/MethodInfo.java	2012-09-29 01:20:28 UTC (rev 668)
+++ trunk/src/main/javassist/bytecode/MethodInfo.java	2012-10-04 07:37:39 UTC (rev 669)
@@ -27,7 +27,12 @@
 
 /**
  * <code>method_info</code> structure.
+ *
+ * <p>The bytecode sequence of the method is represented
+ * by a <code>CodeAttribute</code> object.
  * 
+ * @see #getCodeAttribute()
+ * @see CodeAttribute
  * @see javassist.CtMethod#getMethodInfo()
  * @see javassist.CtConstructor#getMethodInfo()
  */
@@ -390,6 +395,7 @@
      * @param cf            rebuild if this class file is for Java 6 or later.
      * @see #rebuildStackMap(ClassPool)
      * @see #rebuildStackMapForME(ClassPool)
+     * @see #doPreverify
      * @since 3.6
      */
     public void rebuildStackMapIf6(ClassPool pool, ClassFile cf)

Modified: trunk/src/main/javassist/bytecode/Mnemonic.java
===================================================================
--- trunk/src/main/javassist/bytecode/Mnemonic.java	2012-09-29 01:20:28 UTC (rev 668)
+++ trunk/src/main/javassist/bytecode/Mnemonic.java	2012-10-04 07:37:39 UTC (rev 669)
@@ -31,9 +31,6 @@
     /**
      * The instruction names (mnemonics) sorted by the opcode.
      * The length of this array is 202 (jsr_w=201).
-     *
-     * <p>The value at index 186 is null since no instruction is
-     * assigned to 186.
      */
     String[] OPCODE = {
         "nop",  /* 0*/
@@ -222,7 +219,7 @@
         "invokespecial",        /* 183*/
         "invokestatic", /* 184*/
         "invokeinterface",      /* 185*/
-        null,
+        "invokedynamic",        /* 186 */
         "new",  /* 187*/
         "newarray",     /* 188*/
         "anewarray",    /* 189*/

Modified: trunk/src/main/javassist/bytecode/Opcode.java
===================================================================
--- trunk/src/main/javassist/bytecode/Opcode.java	2012-09-29 01:20:28 UTC (rev 668)
+++ trunk/src/main/javassist/bytecode/Opcode.java	2012-10-04 07:37:39 UTC (rev 669)
@@ -156,6 +156,7 @@
     int IMUL = 104;
     int INEG = 116;
     int INSTANCEOF = 193;
+    int INVOKEDYNAMIC = 186;
     int INVOKEINTERFACE = 185;
     int INVOKESPECIAL = 183;
     int INVOKESTATIC = 184;
@@ -428,7 +429,7 @@
         0, // invokespecial, 183        depends on the type
         0, // invokestatic, 184         depends on the type
         0, // invokeinterface, 185      depends on the type
-        0, // undefined, 186
+        0, // invokedynaimc, 186        depends on the type
         1, // new, 187
         0, // newarray, 188
         0, // anewarray, 189

Modified: trunk/src/main/javassist/bytecode/StackMapTable.java
===================================================================
--- trunk/src/main/javassist/bytecode/StackMapTable.java	2012-09-29 01:20:28 UTC (rev 668)
+++ trunk/src/main/javassist/bytecode/StackMapTable.java	2012-10-04 07:37:39 UTC (rev 669)
@@ -909,6 +909,8 @@
                 newDelta = offsetDelta - gap;
             else if (where == oldPos)
                 newDelta = offsetDelta + gap;
+            // else if (gap > 0 && oldPos < where && where < position) // chiba
+            //    throw new RuntimeException("old:" + oldPos + " where:" + where + " pos:" + position);
             else
                 return;
 
@@ -949,6 +951,8 @@
                 newDelta = offsetDelta - gap;
             else if (where == oldPos)
                 newDelta = offsetDelta + gap;
+            // else if (gap > 0 && oldPos < where && where < position)   // chiba
+            //    throw new RuntimeException("old:" + oldPos + " where:" + where + " pos:" + position);
             else
                 return;
 

Modified: trunk/src/main/javassist/bytecode/analysis/Executor.java
===================================================================
--- trunk/src/main/javassist/bytecode/analysis/Executor.java	2012-09-29 01:20:28 UTC (rev 668)
+++ trunk/src/main/javassist/bytecode/analysis/Executor.java	2012-10-04 07:37:39 UTC (rev 669)
@@ -573,8 +573,9 @@
             case INVOKEINTERFACE:
                 evalInvokeIntfMethod(opcode, iter.u16bitAt(pos + 1), frame);
                 break;
-            case 186:
-                throw new RuntimeException("Bad opcode 186");
+            case INVOKEDYNAMIC:
+                evalInvokeDynamic(opcode, iter.u16bitAt(pos + 1), frame);
+                break;
             case NEW:
                 frame.push(resolveClassInfo(constPool.getClassInfo(iter.u16bitAt(pos + 1))));
                 break;
@@ -748,7 +749,21 @@
             simplePush(zeroExtend(returnType), frame);
     }
 
+    private void evalInvokeDynamic(int opcode, int index, Frame frame) throws BadBytecode {
+        String desc = constPool.getInvokeDynamicType(index);
+        Type[] types = paramTypesFromDesc(desc);
+        int i = types.length;
 
+        while (i > 0)
+            verifyAssignable(zeroExtend(types[--i]), simplePop(frame));
+
+        // simplePop(frame);    // assume CosntPool#REF_invokeStatic
+
+        Type returnType = returnTypeFromDesc(desc);
+        if (returnType != Type.VOID)
+            simplePush(zeroExtend(returnType), frame);
+    }
+
     private void evalLDC(int index, Frame frame) throws BadBytecode {
         int tag = constPool.getTag(index);
         Type type;

Modified: trunk/src/main/javassist/bytecode/stackmap/Tracer.java
===================================================================
--- trunk/src/main/javassist/bytecode/stackmap/Tracer.java	2012-09-29 01:20:28 UTC (rev 668)
+++ trunk/src/main/javassist/bytecode/stackmap/Tracer.java	2012-10-04 07:37:39 UTC (rev 669)
@@ -597,8 +597,8 @@
             return doInvokeMethod(pos, code, false);
         case Opcode.INVOKEINTERFACE :
             return doInvokeIntfMethod(pos, code);
-        case 186 :
-            throw new RuntimeException("bad opcode 186");
+        case Opcode.INVOKEDYNAMIC :
+            return doInvokeDynamic(pos, code);
         case Opcode.NEW : {
             int i = ByteArray.readU16bit(code, pos + 1);
             stackTypes[stackTop++]
@@ -835,6 +835,21 @@
         return 5;
     }
 
+    private int doInvokeDynamic(int pos, byte[] code) throws BadBytecode {
+        int i = ByteArray.readU16bit(code, pos + 1);
+        String desc = cpool.getInvokeDynamicType(i);
+        checkParamTypes(desc, 1);
+
+     // assume CosntPool#REF_invokeStatic
+     /* TypeData target = stackTypes[--stackTop];
+        if (target instanceof TypeData.UninitTypeVar && target.isUninit())
+            constructorCalled((TypeData.UninitTypeVar)target);
+      */
+
+        pushMemberType(desc);
+        return 5;
+    }
+
     private void pushMemberType(String descriptor) {
         int top = 0;
         if (descriptor.charAt(0) == '(') {

Modified: trunk/src/test/javassist/JvstTest4.java
===================================================================
--- trunk/src/test/javassist/JvstTest4.java	2012-09-29 01:20:28 UTC (rev 668)
+++ trunk/src/test/javassist/JvstTest4.java	2012-10-04 07:37:39 UTC (rev 669)
@@ -662,6 +662,7 @@
     }
 
     public void testJIRA150b() throws Exception {
+        int origSize = javassist.compiler.MemberResolver.getInvalidMapSize();
         int N = 100;
         for (int k = 0; k < N; k++) {
             ClassPool pool = new ClassPool(true);
@@ -681,12 +682,20 @@
                     "  int n5 = java.lang.Integer#valueOf(5); " +
                     "  return n1+n2+n3+n4+n5; }");
             }
+            pool = null;
         }
+
+        // try to run garbage collection.
+        int[] large;
+        for (int i = 0; i < 100; i++) {
+            large = new int[1000000];
+            large[large.length - 2] = 9;
+        }
         System.gc();
         System.gc();
         int size = javassist.compiler.MemberResolver.getInvalidMapSize();
         System.out.println("JIRA150b " + size);
-        assertTrue("JIRA150b size: " + size, size < N - 10);
+        assertTrue("JIRA150b size: " + origSize + " " + size, size < origSize + N);
     }
 
     public void testJIRA152() throws Exception {

Modified: trunk/src/test/javassist/bytecode/BytecodeTest.java
===================================================================
--- trunk/src/test/javassist/bytecode/BytecodeTest.java	2012-09-29 01:20:28 UTC (rev 668)
+++ trunk/src/test/javassist/bytecode/BytecodeTest.java	2012-10-04 07:37:39 UTC (rev 669)
@@ -779,6 +779,52 @@
         assertEquals("[Ltest.Bar2;", cp.getClassInfo(n8));
     }
 
+    public void testInvokeDynamic() throws Exception {
+        CtClass cc = loader.get("test4.InvokeDyn");
+        ClassFile cf = cc.getClassFile();
+        ConstPool cp = cf.getConstPool();
+
+        Bytecode code = new Bytecode(cp, 0, 1);
+        code.addAload(0);
+        code.addIconst(9);
+        code.addLdc("nine");
+        code.addInvokedynamic(0, "call", "(ILjava/lang/String;)I");
+        code.addOpcode(Opcode.SWAP);
+        code.addOpcode(Opcode.POP);
+        code.addOpcode(Opcode.IRETURN);
+
+        MethodInfo minfo = new MethodInfo(cp, "test", "()I");
+        minfo.setCodeAttribute(code.toCodeAttribute());
+        minfo.setAccessFlags(AccessFlag.PUBLIC);
+        minfo.rebuildStackMapIf6(loader, cf);
+        cf.addMethod(minfo);
+
+        cf.addMethod(new MethodInfo(cp, "test2", minfo, null));
+        int mtIndex = cp.addMethodTypeInfo(cp.addUtf8Info("(I)V"));
+
+        String desc
+            = "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)" +
+              "Ljava/lang/invoke/CallSite;";
+        int mri = cp.addMethodrefInfo(cp.addClassInfo(cc.getName()), "boot", desc);
+        int mhi = cp.addMethodHandleInfo(ConstPool.REF_invokeStatic, mri);
+        int[] args = new int[0];
+        BootstrapMethodsAttribute.BootstrapMethod[] bms
+            = new BootstrapMethodsAttribute.BootstrapMethod[1];
+        bms[0] = new BootstrapMethodsAttribute.BootstrapMethod(mhi, args);
+
+        cf.addAttribute(new BootstrapMethodsAttribute(cp, bms));
+        cc.writeFile();
+        Object obj = make(cc.getName());
+        assertEquals(9, invoke(obj, "test"));
+
+        ClassPool cp2 = new ClassPool();
+        cp2.appendClassPath(".");
+        CtClass cc2 = cp2.get(cc.getName());
+        assertEquals("test4.InvokeDyn", cc2.getClassFile().getName());
+        ConstPool cPool2 = cc2.getClassFile().getConstPool();
+        assertEquals("(I)V", cPool2.getUtf8Info(cPool2.getMethodTypeInfo(mtIndex)));
+    }
+
     public static void main(String[] args) {
         // junit.textui.TestRunner.run(suite());
         junit.awtui.TestRunner.main(new String[] {

Modified: trunk/src/test/javassist/bytecode/StackMapTest.java
===================================================================
--- trunk/src/test/javassist/bytecode/StackMapTest.java	2012-09-29 01:20:28 UTC (rev 668)
+++ trunk/src/test/javassist/bytecode/StackMapTest.java	2012-10-04 07:37:39 UTC (rev 669)
@@ -423,6 +423,171 @@
         }
     }
 
+    public void testSwitchCase3() throws Exception {
+        CtClass cc = loader.get("javassist.bytecode.StackMapTest$T7c");
+        StringBuffer sbuf = new StringBuffer("String s;");
+        for (int i = 0; i < 130; i++)
+            sbuf.append("s =\"" + i + "\";");
+
+        cc.getDeclaredMethod("foo").insertBefore(sbuf.toString());
+        cc.getDeclaredMethod("test2").setBody(loader.get("javassist.bytecode.StackMapTest$T8c").getDeclaredMethod("test2"), null);
+
+        cc.writeFile();
+        Object t1 = make(cc.getName());
+        assertEquals(100, invoke(t1, "test"));
+    }
+
+    public static class T7c {
+        int value = 1;
+        T7b t7;
+        public static T7b make2() { return null; }
+        public static void print(String s) {}
+        public int foo() { return 1; }
+        public int test() { return test2(10); }
+        public int test2(int k) { return 0; }
+    }
+
+    public static class T8c {
+        public int test2(int k) {
+            int jj = 50;
+            if (k > 0)
+                k += "fooo".length();
+
+            int j = 50;
+            loop: for (int i = 0; i < 10; i++) {
+                int jjj = 1;
+                switch (i) {
+                case 0:
+                    k++;
+                    { int poi = 0; }
+                    break;
+                case 9:
+                    break loop;
+                case 7:
+                    k += jjj;
+                    break;
+                }
+            }
+            return j + jj;
+        }
+    }
+
+    public void testSwitchCase4() throws Exception {
+        CtClass cc = loader.get("javassist.bytecode.StackMapTest$T8e");
+        StringBuffer sbuf = new StringBuffer("String s;");
+        for (int i = 0; i < 130; i++)
+            sbuf.append("s =\"" + i + "\";");
+
+        cc.getDeclaredMethod("foo").insertBefore(sbuf.toString());
+        CtClass orig = loader.get("javassist.bytecode.StackMapTest$T8d");
+        CtMethod origM = orig.getDeclaredMethod("test2");
+        writeLdcw(origM);
+        cc.getDeclaredMethod("test2").setBody(origM, null);
+
+        orig.writeFile();
+        cc.writeFile();
+        Object t1 = make(cc.getName());
+        assertEquals(100, invoke(t1, "test"));
+    }
+
+    private void writeLdcw(CtMethod method) {
+        CodeAttribute ca = method.getMethodInfo().getCodeAttribute();
+        int index = ca.getConstPool().addStringInfo("ldcw");
+        CodeIterator ci = ca.iterator();
+        ci.writeByte(Opcode.LDC_W, 14);
+        ci.write16bit(index, 15);
+        ci.writeByte(Opcode.LDC_W, 43);
+        ci.write16bit(index, 44);
+    }
+
+    public static class T8e {
+        static T8dd helper() { return new T8dd(); }
+        int integer() { return 9; }
+        boolean integer2(String s) { return true; }
+        static void print(String s) {}
+        private void print2(String s) {}
+        private Object func(String s) { return null; }
+        I8d func2(String s) { return null; }
+        static String ldcw() { return "k"; }
+        static boolean debug = false;
+        void log(String p1,String p2,String p3,Long p4, Object p5, Object p6) {}
+
+        public int foo() { return 1; }
+        public int test() {
+            try {
+                return test2("", 10) ? 1 : 0;
+            } catch (Exception e) {}
+            return 100;
+        }
+        public boolean test2(String s, int k) throws Exception { return false; }
+    }
+
+    public static interface I8d {
+        String foo(String s, int i);
+    }
+
+    public static class T8dd {
+        java.util.List foo(String s) { return new java.util.ArrayList(); }
+    }
+    public static class T8d {
+        static T8dd helper() { return new T8dd(); }
+        int integer() { return 9; }
+        boolean integer2(String s) { return true; }
+        static void print(String s) {}
+        private void print2(String s) {}
+        private Object func(String s) { return null; }
+        I8d func2(String s) { return null; }
+        static String ldcw() { return "k"; }
+        static boolean debug = false;
+        void log(String p1,String p2,String p3,Long p4, Object p5, Object p6) {}
+
+        public boolean test2(String s, int i) throws Exception {
+            String k = null;
+            Object k2 = null;
+            boolean v5 = true;
+            if (!debug)
+                print(ldcw());
+
+            Object k3 = this.func(s);
+            if (k3 == null)
+                throw new Exception(new StringBuilder().append(ldcw()).append(s).append(",").toString());
+
+            String v7 = k3.toString();
+            k2 = this.func2(v7);
+            if (k2 != null) {   // 82:
+                if (k2 instanceof I8d) {
+                    I8d k5 = (I8d)k2;
+                    k = k5.foo(s, i);
+                }
+            }
+
+            java.util.List list = helper().foo(v7);     // local 8
+            for (int v9 = 0; v9 < list.size(); v9++) {
+                boolean v10 = true;
+                T8d v11 = (T8d)list.get(v9);
+                switch (v11.integer()) {
+                case 1:
+                    break;
+                case 2:
+                    v10 = this.integer2(s);
+                    v5 &= v10;
+                    break;
+                default :
+                    throw new Exception(new StringBuilder().append("ldc 189").append(v11.integer()).append("ldc 169").toString());
+                }
+            }
+
+            if (v5)  // 246:
+                this.print2(s);
+            if (v5)
+                this.log(ldcw(), v7, s, Long.valueOf(new Integer(i).longValue()), k, null);
+            else // 290:
+                this.log(ldcw(), v7, s, Long.valueOf(new Integer(i).longValue()), k, null);
+
+            return v5;
+        }
+    }
+
     public void tstCtClassType() throws Exception {
         ClassPool cp = ClassPool.getDefault();
         CtClass cc = cp.get("javassist.CtClassType");

Added: trunk/src/test/test4/InvokeDyn.java
===================================================================
--- trunk/src/test/test4/InvokeDyn.java	                        (rev 0)
+++ trunk/src/test/test4/InvokeDyn.java	2012-10-04 07:37:39 UTC (rev 669)
@@ -0,0 +1,14 @@
+package test4;
+
+import java.lang.invoke.*;
+
+public class InvokeDyn {
+    public static int test9(int i, String s) { return 9; }
+
+    public static CallSite boot(MethodHandles.Lookup caller, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException {
+        MethodHandles.Lookup lookup = MethodHandles.lookup();
+        Class thisClass = lookup.lookupClass();
+        MethodHandle method = lookup.findStatic(thisClass, "test9", MethodType.methodType(int.class, int.class, String.class));
+        return new ConstantCallSite(method);
+    }
+}


Property changes on: trunk/src/test/test4/InvokeDyn.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain



More information about the jboss-cvs-commits mailing list