8007297: [pack200] allow opcodes with InterfaceMethodRefs
authorksrini
Sun, 03 Mar 2013 20:52:04 -0800
changeset 16050 1eee624cddb3
parent 16049 92a3a919d4dc
child 16051 649a03329639
8007297: [pack200] allow opcodes with InterfaceMethodRefs Reviewed-by: jrose
jdk/src/share/classes/com/sun/java/util/jar/pack/ClassReader.java
jdk/src/share/classes/com/sun/java/util/jar/pack/ConstantPool.java
jdk/src/share/classes/com/sun/java/util/jar/pack/Constants.java
jdk/src/share/classes/com/sun/java/util/jar/pack/Instruction.java
jdk/src/share/classes/com/sun/java/util/jar/pack/PackageReader.java
jdk/src/share/classes/com/sun/java/util/jar/pack/PackageWriter.java
jdk/src/share/native/com/sun/java/util/jar/pack/constants.h
jdk/src/share/native/com/sun/java/util/jar/pack/unpack.cpp
jdk/test/tools/pack200/AttributeTests.java
jdk/test/tools/pack200/InstructionTests.java
jdk/test/tools/pack200/Utils.java
--- a/jdk/src/share/classes/com/sun/java/util/jar/pack/ClassReader.java	Sat Mar 02 08:54:37 2013 +0000
+++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/ClassReader.java	Sun Mar 03 20:52:04 2013 -0800
@@ -564,7 +564,7 @@
         code.bytes = new byte[readInt()];
         in.readFully(code.bytes);
         Entry[] cpMap = cls.getCPMap();
-        Instruction.opcodeChecker(code.bytes, cpMap);
+        Instruction.opcodeChecker(code.bytes, cpMap, this.cls.version);
         int nh = readUnsignedShort();
         code.setHandlerCount(nh);
         for (int i = 0; i < nh; i++) {
--- a/jdk/src/share/classes/com/sun/java/util/jar/pack/ConstantPool.java	Sat Mar 02 08:54:37 2013 +0000
+++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/ConstantPool.java	Sun Mar 03 20:52:04 2013 -0800
@@ -207,6 +207,10 @@
             return tag;
         }
 
+        public final boolean tagEquals(int tag) {
+            return getTag() == tag;
+        }
+
         public Entry getRef(int i) {
             return null;
         }
--- a/jdk/src/share/classes/com/sun/java/util/jar/pack/Constants.java	Sat Mar 02 08:54:37 2013 +0000
+++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/Constants.java	Sun Mar 03 20:52:04 2013 -0800
@@ -479,4 +479,10 @@
     public final static int _qldc   = _xldc_op+7;
     public final static int _qldc_w = _xldc_op+8;
     public final static int _xldc_limit = _xldc_op+9;
+
+    // handling of InterfaceMethodRef
+    public final static int _invoke_int_op = _xldc_limit;
+    public final static int _invokespecial_int = _invoke_int_op+0;
+    public final static int _invokestatic_int = _invoke_int_op+1;
+    public final static int _invoke_int_limit = _invoke_int_op+2;
 }
--- a/jdk/src/share/classes/com/sun/java/util/jar/pack/Instruction.java	Sat Mar 02 08:54:37 2013 +0000
+++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/Instruction.java	Sun Mar 03 20:52:04 2013 -0800
@@ -446,12 +446,14 @@
     public static boolean isCPRefOp(int bc) {
         if (bc < BC_INDEX[0].length && BC_INDEX[0][bc] > 0)  return true;
         if (bc >= _xldc_op && bc < _xldc_limit)  return true;
+        if (bc == _invokespecial_int || bc == _invokestatic_int) return true;
         return false;
     }
 
     public static byte getCPRefOpTag(int bc) {
         if (bc < BC_INDEX[0].length && BC_INDEX[0][bc] > 0)  return BC_TAG[0][bc];
         if (bc >= _xldc_op && bc < _xldc_limit)  return CONSTANT_LoadableValue;
+        if (bc == _invokestatic_int || bc == _invokespecial_int) return CONSTANT_InterfaceMethodref;
         return CONSTANT_None;
     }
 
@@ -647,7 +649,8 @@
         }
     }
 
-    public static void opcodeChecker(byte[] code, ConstantPool.Entry[] cpMap) throws FormatException {
+    public static void opcodeChecker(byte[] code, ConstantPool.Entry[] cpMap,
+            Package.Version clsVersion) throws FormatException {
         Instruction i = at(code, 0);
         while (i != null) {
             int opcode = i.getBC();
@@ -658,10 +661,17 @@
             ConstantPool.Entry e = i.getCPRef(cpMap);
             if (e != null) {
                 byte tag = i.getCPTag();
-                if (!e.tagMatches(tag)) {
-                    String message = "illegal reference, expected type=" +
-                                     ConstantPool.tagName(tag) + ": " +
-                                     i.toString(cpMap);
+                boolean match = e.tagMatches(tag);
+                if (!match &&
+                        (i.bc == _invokespecial || i.bc == _invokestatic) &&
+                        e.tagMatches(CONSTANT_InterfaceMethodref) &&
+                        clsVersion.greaterThan(Constants.JAVA7_MAX_CLASS_VERSION)) {
+                    match = true;
+                }
+                if (!match) {
+                    String message = "illegal reference, expected type="
+                            + ConstantPool.tagName(tag) + ": "
+                            + i.toString(cpMap);
                     throw new FormatException(message);
                 }
             }
--- a/jdk/src/share/classes/com/sun/java/util/jar/pack/PackageReader.java	Sat Mar 02 08:54:37 2013 +0000
+++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/PackageReader.java	Sun Mar 03 20:52:04 2013 -0800
@@ -2256,6 +2256,12 @@
                         int origBC = bc;
                         int size = 2;
                         switch (bc) {
+                        case _invokestatic_int:
+                            origBC = _invokestatic;
+                            break;
+                        case _invokespecial_int:
+                            origBC = _invokespecial;
+                            break;
                         case _ildc:
                         case _cldc:
                         case _fldc:
--- a/jdk/src/share/classes/com/sun/java/util/jar/pack/PackageWriter.java	Sat Mar 02 08:54:37 2013 +0000
+++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/PackageWriter.java	Sun Mar 03 20:52:04 2013 -0800
@@ -1409,6 +1409,10 @@
         int bc = i.getBC();
         if (!(bc >= _first_linker_op && bc <= _last_linker_op))  return -1;
         MemberEntry ref = (MemberEntry) i.getCPRef(curCPMap);
+        // do not optimize this case, simply fall back to regular coding
+        if ((bc == _invokespecial || bc == _invokestatic) &&
+                ref.tagEquals(CONSTANT_InterfaceMethodref))
+            return -1;
         ClassEntry refClass = ref.classRef;
         int self_bc = _self_linker_op + (bc - _first_linker_op);
         if (refClass == curClass.thisClass)
@@ -1609,7 +1613,16 @@
                 case CONSTANT_Fieldref:
                     bc_which = bc_fieldref; break;
                 case CONSTANT_Methodref:
-                    bc_which = bc_methodref; break;
+                    if (ref.tagEquals(CONSTANT_InterfaceMethodref)) {
+                        if (bc == _invokespecial)
+                            vbc = _invokespecial_int;
+                        if (bc == _invokestatic)
+                            vbc = _invokestatic_int;
+                        bc_which = bc_imethodref;
+                    } else {
+                        bc_which = bc_methodref;
+                    }
+                    break;
                 case CONSTANT_InterfaceMethodref:
                     bc_which = bc_imethodref; break;
                 case CONSTANT_InvokeDynamic:
--- a/jdk/src/share/native/com/sun/java/util/jar/pack/constants.h	Sat Mar 02 08:54:37 2013 +0000
+++ b/jdk/src/share/native/com/sun/java/util/jar/pack/constants.h	Sun Mar 03 20:52:04 2013 -0800
@@ -505,5 +505,9 @@
   bc_qldc    = _xldc_op+7,
   bc_qldc_w  = _xldc_op+8,
   _xldc_limit = _xldc_op+9,
+  _invoke_int_op = _xldc_limit,
+  _invokespecial_int = _invoke_int_op+0,
+  _invokestatic_int = _invoke_int_op+1,
+  _invoke_int_limit =  _invoke_int_op+2,
   _xxx_3_end
 };
--- a/jdk/src/share/native/com/sun/java/util/jar/pack/unpack.cpp	Sat Mar 02 08:54:37 2013 +0000
+++ b/jdk/src/share/native/com/sun/java/util/jar/pack/unpack.cpp	Sun Mar 03 20:52:04 2013 -0800
@@ -2942,6 +2942,9 @@
   case bc_putfield:
     return &bc_fieldref;
 
+  case _invokespecial_int:
+  case _invokestatic_int:
+    return &bc_imethodref;
   case bc_invokevirtual:
   case bc_invokespecial:
   case bc_invokestatic:
@@ -4177,6 +4180,12 @@
         }
         origBC = bc;
         switch (bc) {
+        case _invokestatic_int:
+          origBC = bc_invokestatic;
+          break;
+        case _invokespecial_int:
+          origBC = bc_invokespecial;
+          break;
         case bc_ildc:
         case bc_cldc:
         case bc_fldc:
--- a/jdk/test/tools/pack200/AttributeTests.java	Sat Mar 02 08:54:37 2013 +0000
+++ b/jdk/test/tools/pack200/AttributeTests.java	Sun Mar 03 20:52:04 2013 -0800
@@ -67,17 +67,7 @@
         File testjarFile = new File(cwd, "test" + Utils.JAR_FILE_EXT);
         Utils.jar("cvf", testjarFile.getName(), javaClassName);
 
-        // pack using native --repack
-        File nativejarFile = new File(cwd, "out-n" + Utils.JAR_FILE_EXT);
-        Utils.repack(testjarFile, nativejarFile, false,
-                     "--unknown-attribute=error");
-        Utils.doCompareVerify(testjarFile, nativejarFile);
-
-        // pack using java --repack
-        File javajarFile = new File(cwd, "out-j" + Utils.JAR_FILE_EXT);
-        Utils.repack(testjarFile, javajarFile, true,
-                     "--unknown-attribute=error");
-        Utils.doCompareBitWise(nativejarFile, javajarFile);
+        Utils.testWithRepack(testjarFile, "--unknown-attribute=error");
     }
     /*
      * this test checks to see if we get the expected strings for output
--- a/jdk/test/tools/pack200/InstructionTests.java	Sat Mar 02 08:54:37 2013 +0000
+++ b/jdk/test/tools/pack200/InstructionTests.java	Sun Mar 03 20:52:04 2013 -0800
@@ -26,11 +26,10 @@
 import java.util.ArrayList;
 import java.util.List;
 import static java.nio.file.StandardOpenOption.*;
-import java.util.regex.Pattern;
 
 /*
  * @test
- * @bug 8003549
+ * @bug 8003549 8007297
  * @summary tests class files instruction formats introduced in JSR-335
  * @compile -XDignore.symbol.file Utils.java InstructionTests.java
  * @run main InstructionTests
@@ -48,52 +47,34 @@
         List<String> scratch = new ArrayList<>();
         final String fname = "A";
         String javaFileName = fname + Utils.JAVA_FILE_EXT;
-        scratch.add("interface IntIterator {");
+        scratch.add("interface I {");
         scratch.add("    default void forEach(){}");
         scratch.add("    static void next() {}");
         scratch.add("}");
-        scratch.add("class A implements IntIterator {");
-        scratch.add("public void forEach(Object o){");
-        scratch.add("IntIterator.super.forEach();");
-        scratch.add("IntIterator.next();");
-        scratch.add("}");
+        scratch.add("class A implements I {");
+        scratch.add("    public void forEach(Object o){");
+        scratch.add("        I.super.forEach();");
+        scratch.add("        I.next();");
+        scratch.add("    }");
         scratch.add("}");
         File cwd = new File(".");
         File javaFile = new File(cwd, javaFileName);
         Files.write(javaFile.toPath(), scratch, Charset.defaultCharset(),
                 CREATE, TRUNCATE_EXISTING);
 
-        // make sure we have -g so that we  compare LVT and LNT entries
+        // -g to compare LVT and LNT entries
         Utils.compiler("-g", javaFile.getName());
 
+        File propsFile = new File("pack.props");
+        scratch.clear();
+        scratch.add("com.sun.java.util.jar.pack.class.format.error=error");
+        scratch.add("pack.unknown.attribute=error");
+        Files.write(propsFile.toPath(), scratch, Charset.defaultCharset(),
+                CREATE, TRUNCATE_EXISTING);
         // jar the file up
         File testjarFile = new File(cwd, "test" + Utils.JAR_FILE_EXT);
         Utils.jar("cvf", testjarFile.getName(), ".");
 
-        // pack using --repack
-        File outjarFile = new File(cwd, "out" + Utils.JAR_FILE_EXT);
-        scratch.clear();
-        scratch.add(Utils.getPack200Cmd());
-        scratch.add("-J-ea");
-        scratch.add("-J-esa");
-        scratch.add("--repack");
-        scratch.add(outjarFile.getName());
-        scratch.add(testjarFile.getName());
-        List<String> output = Utils.runExec(scratch);
-        // TODO remove this when we get bc escapes working correctly
-        // this test anyhow would  fail  at that time
-        findString("WARNING: Passing.*" + fname + Utils.CLASS_FILE_EXT,
-                        output);
-
-        Utils.doCompareVerify(testjarFile, outjarFile);
-    }
-
-    static boolean findString(String str, List<String> list) {
-        Pattern p = Pattern.compile(str);
-        for (String x : list) {
-            if (p.matcher(x).matches())
-                return true;
-        }
-        throw new RuntimeException("Error: " + str + " not found in output");
+        Utils.testWithRepack(testjarFile, "--config-file=" + propsFile.getName());
     }
 }
--- a/jdk/test/tools/pack200/Utils.java	Sat Mar 02 08:54:37 2013 +0000
+++ b/jdk/test/tools/pack200/Utils.java	Sun Mar 03 20:52:04 2013 -0800
@@ -314,6 +314,20 @@
             throw new RuntimeException("jar command failed");
         }
     }
+
+    static void testWithRepack(File inFile, String... repackOpts) throws IOException {
+        File cwd = new File(".");
+        // pack using --repack in native mode
+        File nativejarFile = new File(cwd, "out-n" + Utils.JAR_FILE_EXT);
+        repack(inFile, nativejarFile, false, repackOpts);
+        doCompareVerify(inFile, nativejarFile);
+
+        // ensure bit compatibility between the unpacker variants
+        File javajarFile = new File(cwd, "out-j" + Utils.JAR_FILE_EXT);
+        repack(inFile, javajarFile, true, repackOpts);
+        doCompareBitWise(javajarFile, nativejarFile);
+    }
+
     static List<String> repack(File inFile, File outFile,
             boolean disableNative, String... extraOpts) {
         List<String> cmdList = new ArrayList<>();