diff --git a/jdk/src/share/classes/com/sun/java/util/jar/pack/ClassReader.java b/jdk/src/share/classes/com/sun/java/util/jar/pack/ClassReader.java index 3df8706da37..3da159f6e29 100644 --- a/jdk/src/share/classes/com/sun/java/util/jar/pack/ClassReader.java +++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/ClassReader.java @@ -564,7 +564,7 @@ class ClassReader { 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++) { diff --git a/jdk/src/share/classes/com/sun/java/util/jar/pack/ConstantPool.java b/jdk/src/share/classes/com/sun/java/util/jar/pack/ConstantPool.java index ad2175f9993..c23dcb9d4a7 100644 --- a/jdk/src/share/classes/com/sun/java/util/jar/pack/ConstantPool.java +++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/ConstantPool.java @@ -207,6 +207,10 @@ class ConstantPool { return tag; } + public final boolean tagEquals(int tag) { + return getTag() == tag; + } + public Entry getRef(int i) { return null; } diff --git a/jdk/src/share/classes/com/sun/java/util/jar/pack/Constants.java b/jdk/src/share/classes/com/sun/java/util/jar/pack/Constants.java index 15882624381..5059bc07967 100644 --- a/jdk/src/share/classes/com/sun/java/util/jar/pack/Constants.java +++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/Constants.java @@ -479,4 +479,10 @@ class Constants { 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; } diff --git a/jdk/src/share/classes/com/sun/java/util/jar/pack/Instruction.java b/jdk/src/share/classes/com/sun/java/util/jar/pack/Instruction.java index 31ee22b059d..93175fe8ecf 100644 --- a/jdk/src/share/classes/com/sun/java/util/jar/pack/Instruction.java +++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/Instruction.java @@ -446,12 +446,14 @@ class Instruction { 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 @@ class Instruction { } } - 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 @@ class Instruction { 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); } } diff --git a/jdk/src/share/classes/com/sun/java/util/jar/pack/PackageReader.java b/jdk/src/share/classes/com/sun/java/util/jar/pack/PackageReader.java index df4687b4aff..b42dda30eb4 100644 --- a/jdk/src/share/classes/com/sun/java/util/jar/pack/PackageReader.java +++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/PackageReader.java @@ -2256,6 +2256,12 @@ class PackageReader extends BandStructure { 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: diff --git a/jdk/src/share/classes/com/sun/java/util/jar/pack/PackageWriter.java b/jdk/src/share/classes/com/sun/java/util/jar/pack/PackageWriter.java index 47959294fd2..a78c9ae9969 100644 --- a/jdk/src/share/classes/com/sun/java/util/jar/pack/PackageWriter.java +++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/PackageWriter.java @@ -1409,6 +1409,10 @@ class PackageWriter extends BandStructure { 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 @@ class PackageWriter extends BandStructure { 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: diff --git a/jdk/src/share/native/com/sun/java/util/jar/pack/constants.h b/jdk/src/share/native/com/sun/java/util/jar/pack/constants.h index 040d8edd55b..2f125e0d800 100644 --- a/jdk/src/share/native/com/sun/java/util/jar/pack/constants.h +++ b/jdk/src/share/native/com/sun/java/util/jar/pack/constants.h @@ -505,5 +505,9 @@ enum { 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 }; diff --git a/jdk/src/share/native/com/sun/java/util/jar/pack/unpack.cpp b/jdk/src/share/native/com/sun/java/util/jar/pack/unpack.cpp index 9ce0308089f..aae7921ae43 100644 --- a/jdk/src/share/native/com/sun/java/util/jar/pack/unpack.cpp +++ b/jdk/src/share/native/com/sun/java/util/jar/pack/unpack.cpp @@ -2942,6 +2942,9 @@ band* unpacker::ref_band_for_op(int bc) { 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 @@ void unpacker::write_bc_ops() { } 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: diff --git a/jdk/test/tools/pack200/AttributeTests.java b/jdk/test/tools/pack200/AttributeTests.java index 6526737b732..c12891829e7 100644 --- a/jdk/test/tools/pack200/AttributeTests.java +++ b/jdk/test/tools/pack200/AttributeTests.java @@ -67,17 +67,7 @@ public class AttributeTests { 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 diff --git a/jdk/test/tools/pack200/InstructionTests.java b/jdk/test/tools/pack200/InstructionTests.java index ce92c0ed558..7015ae9a11f 100644 --- a/jdk/test/tools/pack200/InstructionTests.java +++ b/jdk/test/tools/pack200/InstructionTests.java @@ -26,11 +26,10 @@ import java.nio.file.Files; 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 @@ public class InstructionTests { List 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 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 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()); } } diff --git a/jdk/test/tools/pack200/Utils.java b/jdk/test/tools/pack200/Utils.java index 07a64595e9f..f3d1d4666b8 100644 --- a/jdk/test/tools/pack200/Utils.java +++ b/jdk/test/tools/pack200/Utils.java @@ -314,6 +314,20 @@ class Utils { 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 repack(File inFile, File outFile, boolean disableNative, String... extraOpts) { List cmdList = new ArrayList<>();