Commits

Anonymous committed 5ca383d

Added support for version 51 class files in dx

If an invokedynamic is present, an exception is thrown.

(cherry picked from commit 94629f2a31206637fc79535ffef1b223e9f02e30)

Change-Id: I1922d4cf78465dfd2ac53f8694b7317a1d98016d

Comments (0)

Files changed (19)

dx/src/com/android/dx/cf/code/ByteOps.java

     public static final int INVOKESPECIAL = 0xb7;
     public static final int INVOKESTATIC = 0xb8;
     public static final int INVOKEINTERFACE = 0xb9;
+    public static final int INVOKEDYNAMIC = 0xba;
     public static final int NEW = 0xbb;
     public static final int NEWARRAY = 0xbc;
     public static final int ANEWARRAY = 0xbd;

dx/src/com/android/dx/cf/code/BytecodeArray.java

 
 package com.android.dx.cf.code;
 
+import com.android.dx.cf.iface.ParseException;
 import com.android.dx.rop.cst.Constant;
 import com.android.dx.rop.cst.ConstantPool;
 import com.android.dx.rop.cst.CstDouble;
                                           count | (expectZero << 8));
                     return 5;
                 }
+                case ByteOps.INVOKEDYNAMIC: {
+                  throw new ParseException("invokedynamic not supported");
+                }
                 case ByteOps.NEWARRAY: {
                     return parseNewarray(offset, visitor);
                 }

dx/src/com/android/dx/cf/cst/ConstantPoolParser.java

 import static com.android.dx.cf.cst.ConstantTags.CONSTANT_NameAndType;
 import static com.android.dx.cf.cst.ConstantTags.CONSTANT_String;
 import static com.android.dx.cf.cst.ConstantTags.CONSTANT_Utf8;
+import static com.android.dx.cf.cst.ConstantTags.CONSTANT_MethodHandle;
+import static com.android.dx.cf.cst.ConstantTags.CONSTANT_MethodType;
+import static com.android.dx.cf.cst.ConstantTags.CONSTANT_InvokeDynamic;
 import com.android.dx.cf.iface.ParseException;
 import com.android.dx.cf.iface.ParseObserver;
 import com.android.dx.rop.cst.Constant;
         for (int i = 1; i < offsets.length; i += lastCategory) {
             offsets[i] = at;
             int tag = bytes.getUnsignedByte(at);
-            switch (tag) {
-                case CONSTANT_Integer:
-                case CONSTANT_Float:
-                case CONSTANT_Fieldref:
-                case CONSTANT_Methodref:
-                case CONSTANT_InterfaceMethodref:
-                case CONSTANT_NameAndType: {
-                    lastCategory = 1;
-                    at += 5;
-                    break;
-                }
-                case CONSTANT_Long:
-                case CONSTANT_Double: {
-                    lastCategory = 2;
-                    at += 9;
-                    break;
-                }
-                case CONSTANT_Class:
-                case CONSTANT_String: {
-                    lastCategory = 1;
-                    at += 3;
-                    break;
-                }
-                case CONSTANT_Utf8: {
-                    lastCategory = 1;
-                    at += bytes.getUnsignedShort(at + 1) + 3;
-                    break;
-                }
-                default: {
-                    ParseException ex =
-                        new ParseException("unknown tag byte: " + Hex.u1(tag));
-                    ex.addContext("...while preparsing cst " + Hex.u2(i) +
-                                  " at offset " + Hex.u4(at));
-                    throw ex;
+            try {
+                switch (tag) {
+                    case CONSTANT_Integer:
+                    case CONSTANT_Float:
+                    case CONSTANT_Fieldref:
+                    case CONSTANT_Methodref:
+                    case CONSTANT_InterfaceMethodref:
+                    case CONSTANT_NameAndType: {
+                        lastCategory = 1;
+                        at += 5;
+                        break;
+                    }
+                    case CONSTANT_Long:
+                    case CONSTANT_Double: {
+                        lastCategory = 2;
+                        at += 9;
+                        break;
+                    }
+                    case CONSTANT_Class:
+                    case CONSTANT_String: {
+                        lastCategory = 1;
+                        at += 3;
+                        break;
+                    }
+                    case CONSTANT_Utf8: {
+                        lastCategory = 1;
+                        at += bytes.getUnsignedShort(at + 1) + 3;
+                        break;
+                    }
+                    case CONSTANT_MethodHandle: {
+                        throw new ParseException("MethodHandle not supported");
+                    }
+                    case CONSTANT_MethodType: {
+                        throw new ParseException("MethodType not supported");
+                    }
+                    case CONSTANT_InvokeDynamic: {
+                        throw new ParseException("InvokeDynamic not supported");
+                    }
+                    default: {
+                        throw new ParseException("unknown tag byte: " + Hex.u1(tag));
+                    }
                 }
+            } catch (ParseException ex) {
+                ex.addContext("...while preparsing cst " + Hex.u2(i) + " at offset " + Hex.u4(at));
+                throw ex;
             }
         }
 
                     cst = new CstNat(name, descriptor);
                     break;
                 }
+                case CONSTANT_MethodHandle: {
+                    throw new ParseException("MethodHandle not supported");
+                }
+                case CONSTANT_MethodType: {
+                    throw new ParseException("MethodType not supported");
+                }
+                case CONSTANT_InvokeDynamic: {
+                    throw new ParseException("InvokeDynamic not supported");
+                }
+                default: {
+                    throw new ParseException("unknown tag byte: " + Hex.u1(tag));
+                }
             }
         } catch (ParseException ex) {
             ex.addContext("...while parsing cst " + Hex.u2(idx) +

dx/src/com/android/dx/cf/cst/ConstantTags.java

 
     /** tag for a {@code CONSTANT_NameAndType_info} */
     int CONSTANT_NameAndType = 12;
+
+    /** tag for a {@code CONSTANT_MethodHandle} */
+    int CONSTANT_MethodHandle = 15;
+
+    /** tag for a {@code CONSTANT_MethodType} */
+    int CONSTANT_MethodType = 16;
+
+    /** tag for a {@code CONSTANT_InvokeDynamic} */
+    int CONSTANT_InvokeDynamic = 18;
 }

dx/src/com/android/dx/cf/direct/DirectClassFile.java

      * See http://en.wikipedia.org/wiki/Java_class_file for an up-to-date
      * list of version numbers. Currently known (taken from that table) are:
      *
+     *     J2SE 7.0 = 51 (0x33 hex),
      *     J2SE 6.0 = 50 (0x32 hex),
      *     J2SE 5.0 = 49 (0x31 hex),
      *     JDK 1.4 = 48 (0x30 hex),
      *
      * Note: if you change this, please change "java.class.version" in System.java.
      */
-    private static final int CLASS_FILE_MAX_MAJOR_VERSION = 50;
+    private static final int CLASS_FILE_MAX_MAJOR_VERSION = 51;
 
     /** maximum {@code .class} file minor version */
     private static final int CLASS_FILE_MAX_MINOR_VERSION = 0;

dx/tests/003-magic-version-access/class-version-49.0.txt

 #
-# classfile with the highest valid version, 49.0 (0x31.0x00)
+# classfile with the valid version 49.0 (0x31.0x00)
 #
 
 cafe babe  # magic

dx/tests/003-magic-version-access/class-version-49.1.txt

 #
-# classfile with a minor version 1 higher than the highest valid
-# version.  49.1 (0x31.0x01)
+# classfile with the valid version 49.1 (0x31.0x01)
 #
 
 cafe babe  # magic

dx/tests/003-magic-version-access/class-version-49.65535.txt

 #
-# classfile with an invalid version, with the same major version
-# as the highest valid version.  49.65535 (0x31.0xffff)
+# classfile with the valid version 49.65535 (0x31.0xffff)
 #
 
 cafe babe  # magic

dx/tests/003-magic-version-access/class-version-50.0.txt

 #
-# classfile with an invalid version, with a higher major version
-# than the highest valid version.  50.0 (0x32.0x00)
+# classfile with the valid version 50.0 (0x30.0x00)
 #
 
 cafe babe  # magic

dx/tests/003-magic-version-access/class-version-50.1.txt

 #
-# classfile with an invalid version, with a higher major version
-# than the highest valid version.  50.0 (0x32.0x00)
+# classfile with the valid version 50.1 (0x32.0x01)
 #
 
 cafe babe  # magic

dx/tests/003-magic-version-access/class-version-50.65535.txt

 #
-# classfile with an invalid version, with a higher major version
-# than the highest valid version.  50.0 (0x32.0x00)
+# classfile with the valid version 50.65535 (0x32.0xffff)
 #
 
 cafe babe  # magic

dx/tests/003-magic-version-access/class-version-51.0.txt

 #
-# classfile with an invalid version, with a higher major version
-# than the highest valid version.  50.0 (0x32.0x00)
+# classfile with the highest valid version 51.0 (0x33.0x00)
 #
 
 cafe babe  # magic

dx/tests/003-magic-version-access/class-version-51.1.txt

+#
+# classfile with a minor version 1 higher than the highest valid
+# version.  51.0 (0x33.0x00)
+#
+
+cafe babe  # magic
+0001       # minor_version
+0033       # major_version
+0005       # constant_pool_count
+
+#
+# constant_pool
+#
+01 0005 "Small"            # 0001: utf8["Small"]
+01 0010 "java/lang/Object" # 0002: utf8["java/lang/Object"]
+07 0001                    # 0003: class[Small]
+07 0002                    # 0004: class[java/lang/Object]
+
+ffff  # access_flags
+0003  # this_class
+0004  # super_class
+0000  # interfaces_count
+0000  # fields_count
+0000  # methods_count
+
+0000  # attributes_count

dx/tests/003-magic-version-access/class-version-51.65535.txt

+#
+# classfile with an invalid version, with the same major version
+# as the highest valid version.  51.65535 (0x33.0xffff)
+#
+
+cafe babe  # magic
+ffff       # minor_version
+0033       # major_version
+0005       # constant_pool_count
+
+#
+# constant_pool
+#
+01 0005 "Small"            # 0001: utf8["Small"]
+01 0010 "java/lang/Object" # 0002: utf8["java/lang/Object"]
+07 0001                    # 0003: class[Small]
+07 0002                    # 0004: class[java/lang/Object]
+
+ffff  # access_flags
+0003  # this_class
+0004  # super_class
+0000  # interfaces_count
+0000  # fields_count
+0000  # methods_count
+
+0000  # attributes_count

dx/tests/003-magic-version-access/class-version-52.0.txt

+#
+# classfile with an invalid version, with a higher major version
+# than the highest valid version.  51.0 (0x33.0x00)
+#
+
+cafe babe  # magic
+0000       # minor_version
+0034       # major_version
+0005       # constant_pool_count
+
+#
+# constant_pool
+#
+01 0005 "Small"            # 0001: utf8["Small"]
+01 0010 "java/lang/Object" # 0002: utf8["java/lang/Object"]
+07 0001                    # 0003: class[Small]
+07 0002                    # 0004: class[java/lang/Object]
+
+ffff  # access_flags
+0003  # this_class
+0004  # super_class
+0000  # interfaces_count
+0000  # fields_count
+0000  # methods_count
+
+0000  # attributes_count

dx/tests/003-magic-version-access/expected.txt

 magic: cafebabe
 minor_version: 0001
 major_version: 0032
+constant_pool_count: 0005
 
-trouble parsing:
-bad class file magic (cafebabe) or version (0032.0001)
-...while parsing class-version-50.1.txt
+constant_pool:
+  0001: utf8{"Small"}
+  0002: utf8{"java/lang/Object"}
+  0003: type{Small}
+  0004: type{java.lang.Object}
+end constant_pool
+access_flags: public|final|super|interface|abstract|synthetic|annotation|enum|89ce
+this_class: type{Small}
+super_class: type{java.lang.Object}
+interfaces_count: 0000
+fields_count: 0000
+methods_count: 0000
+attributes_count: 0000
+end classfile
 reading class-version-50.65535.txt...
 begin classfile
 magic: cafebabe
 minor_version: ffff
 major_version: 0032
+constant_pool_count: 0005
 
-trouble parsing:
-bad class file magic (cafebabe) or version (0032.ffff)
-...while parsing class-version-50.65535.txt
+constant_pool:
+  0001: utf8{"Small"}
+  0002: utf8{"java/lang/Object"}
+  0003: type{Small}
+  0004: type{java.lang.Object}
+end constant_pool
+access_flags: public|final|super|interface|abstract|synthetic|annotation|enum|89ce
+this_class: type{Small}
+super_class: type{java.lang.Object}
+interfaces_count: 0000
+fields_count: 0000
+methods_count: 0000
+attributes_count: 0000
+end classfile
 reading class-version-51.0.txt...
 begin classfile
 magic: cafebabe
 minor_version: 0000
 major_version: 0033
+constant_pool_count: 0005
+
+constant_pool:
+  0001: utf8{"Small"}
+  0002: utf8{"java/lang/Object"}
+  0003: type{Small}
+  0004: type{java.lang.Object}
+end constant_pool
+access_flags: public|final|super|interface|abstract|synthetic|annotation|enum|89ce
+this_class: type{Small}
+super_class: type{java.lang.Object}
+interfaces_count: 0000
+fields_count: 0000
+methods_count: 0000
+attributes_count: 0000
+end classfile
+reading class-version-51.1.txt...
+begin classfile
+magic: cafebabe
+minor_version: 0001
+major_version: 0033
+
+trouble parsing:
+bad class file magic (cafebabe) or version (0033.0001)
+...while parsing class-version-51.1.txt
+reading class-version-51.65535.txt...
+begin classfile
+magic: cafebabe
+minor_version: ffff
+major_version: 0033
+
+trouble parsing:
+bad class file magic (cafebabe) or version (0033.ffff)
+...while parsing class-version-51.65535.txt
+reading class-version-52.0.txt...
+begin classfile
+magic: cafebabe
+minor_version: 0000
+major_version: 0034
 
 trouble parsing:
-bad class file magic (cafebabe) or version (0033.0000)
-...while parsing class-version-51.0.txt
+bad class file magic (cafebabe) or version (0034.0000)
+...while parsing class-version-52.0.txt
 reading small-class.txt...
 begin classfile
 magic: cafebabe

dx/tests/003-magic-version-access/run

 dx --debug --dump --width=100 class-version-49.1.txt
 dx --debug --dump --width=100 class-version-49.65535.txt
 dx --debug --dump --width=100 class-version-50.0.txt
+dx --debug --dump --width=100 class-version-50.1.txt
+dx --debug --dump --width=100 class-version-50.65535.txt
+dx --debug --dump --width=100 class-version-51.0.txt
 
 # Too big (throws an exception)
-dx         --dump --strict class-version-50.1.txt
-dx         --dump --strict class-version-50.65535.txt
-dx         --dump --strict class-version-51.0.txt
+dx         --dump --strict class-version-51.1.txt
+dx         --dump --strict class-version-51.65535.txt
+dx         --dump --strict class-version-52.0.txt
 
 # Show that we can dump the access flags even when they
 # don't make any sense.

dx/tests/024-code-bytecode/expected.txt

   
   attributes[0]:
     name: Code
-    length: 000001dc
+    length: 000001db
     max_stack: 0001
     max_locals: 0001
-    code_length: 000001d0
+    code_length: 000001cf
     0000: nop
     0001: aconst_null
     0002: iconst_m1 // #-01
     015d: invokespecial method{Small.blort:()V}
     0160: invokestatic method{Small.blort:()V}
     0163: invokeinterface ifaceMethod{Small.blort:()V}, 0001
-    0168: unused_ba
-    0169: new type{Small}
-    016c: newarray boolean
-    016e: newarray char
-    0170: newarray float
-    0172: newarray double
-    0174: newarray byte
-    0176: newarray short
-    0178: newarray int
-    017a: newarray long
-    017c: anewarray type{Small}
-    017f: arraylength
-    0180: athrow
-    0181: checkcast type{java.lang.Object}
-    0184: instanceof type{java.lang.Object}
-    0187: monitorenter
-    0188: monitorexit
-    0189: wide iload 0123
-    018d: wide lload 0124 // category-2
-    0191: wide fload 0125
-    0195: wide dload 0126 // category-2
-    0199: wide aload 0127
-    019d: wide istore 20f0
-    01a1: wide lstore 20f1 // category-2
-    01a5: wide fstore 20f2
-    01a9: wide dstore 20f3 // category-2
-    01ad: wide astore 20f4
-    01b1: wide ret ffff
-    01b5: wide iinc 0002, #+1000
-    01bb: multianewarray type{java.lang.Object}, 04
-    01bf: ifnull 0000
-    01c2: ifnonnull 01c2
-    01c5: goto_w 700001c5
-    01ca: jsr_w 000001c5
-    01cf: unused_ca
+    0168: new type{Small}
+    016b: newarray boolean
+    016d: newarray char
+    016f: newarray float
+    0171: newarray double
+    0173: newarray byte
+    0175: newarray short
+    0177: newarray int
+    0179: newarray long
+    017b: anewarray type{Small}
+    017e: arraylength
+    017f: athrow
+    0180: checkcast type{java.lang.Object}
+    0183: instanceof type{java.lang.Object}
+    0186: monitorenter
+    0187: monitorexit
+    0188: wide iload 0123
+    018c: wide lload 0124 // category-2
+    0190: wide fload 0125
+    0194: wide dload 0126 // category-2
+    0198: wide aload 0127
+    019c: wide istore 20f0
+    01a0: wide lstore 20f1 // category-2
+    01a4: wide fstore 20f2
+    01a8: wide dstore 20f3 // category-2
+    01ac: wide astore 20f4
+    01b0: wide ret ffff
+    01b4: wide iinc 0002, #+1000
+    01ba: multianewarray type{java.lang.Object}, 04
+    01be: ifnull ffff
+    01c1: ifnonnull 01c1
+    01c4: goto_w 700001c4
+    01c9: jsr_w 000001c4
+    01ce: unused_ca
     exception_table_length: 0000
     attributes_count: 0000
   end attributes[0]

dx/tests/024-code-bytecode/small-class.txt

 0001  # attributes_count
 # attributes[0]
 0007      # name
-000001dc  # length (note: == code_length + 0x0c)
+000001db  # length (note: == code_length + 0x0c)
 0001      # max_stack
 0001      # max_locals
-000001d0  # code_length
+000001cf  # code_length
 
 00        # 0000: nop
 01        # 0001: aconst_null
 b7 0015   # 015d: invokespecial 0015
 b8 0015   # 0160: invokestatic 0015
 b9 0016 01 00  # 0163: invokeinterface 0016
-ba        # 0168: <unused>
 bb 0001   # 0169: new 0001
 bc 04     # 016c: newarray boolean
 bc 05     # 016e: newarray char