diff --git a/src/share/classes/com/sun/java/util/jar/pack/ClassReader.java b/src/share/classes/com/sun/java/util/jar/pack/ClassReader.java index 3df8706da37d4925734c4bc18ea21b41db0c5052..3da159f6e29033716cd7a5a48ecbfcb2a64b818c 100644 --- a/src/share/classes/com/sun/java/util/jar/pack/ClassReader.java +++ b/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/src/share/classes/com/sun/java/util/jar/pack/ConstantPool.java b/src/share/classes/com/sun/java/util/jar/pack/ConstantPool.java index ad2175f9993708df08acf34b85bfeb10da08191e..c23dcb9d4a7db75f410ce5c0d05e5f8341226d9d 100644 --- a/src/share/classes/com/sun/java/util/jar/pack/ConstantPool.java +++ b/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/src/share/classes/com/sun/java/util/jar/pack/Constants.java b/src/share/classes/com/sun/java/util/jar/pack/Constants.java index 158826243811918e489f3ca2062399e053f581f6..5059bc07967273f811e893c750df10d8d39a4736 100644 --- a/src/share/classes/com/sun/java/util/jar/pack/Constants.java +++ b/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/src/share/classes/com/sun/java/util/jar/pack/Instruction.java b/src/share/classes/com/sun/java/util/jar/pack/Instruction.java index 31ee22b059d50df5ed1cbd840de04672093b96c5..93175fe8ecf76a37e465561cc7a8e5153466b2ca 100644 --- a/src/share/classes/com/sun/java/util/jar/pack/Instruction.java +++ b/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/src/share/classes/com/sun/java/util/jar/pack/PackageReader.java b/src/share/classes/com/sun/java/util/jar/pack/PackageReader.java index df4687b4aff74694666f68696cf7051e20eb8788..b42dda30eb45983a570b894a3de3dd9cddefd818 100644 --- a/src/share/classes/com/sun/java/util/jar/pack/PackageReader.java +++ b/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/src/share/classes/com/sun/java/util/jar/pack/PackageWriter.java b/src/share/classes/com/sun/java/util/jar/pack/PackageWriter.java index 47959294fd2be727d95bd5d3e5ed85392fad0e38..a78c9ae9969aa806c804f0de90cd04a15e910444 100644 --- a/src/share/classes/com/sun/java/util/jar/pack/PackageWriter.java +++ b/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/src/share/native/com/sun/java/util/jar/pack/constants.h b/src/share/native/com/sun/java/util/jar/pack/constants.h index 040d8edd55b190e120ee72d4bd5e8d36fb411f8f..2f125e0d8005556c4254a38720ac3ecd58aec8fb 100644 --- a/src/share/native/com/sun/java/util/jar/pack/constants.h +++ b/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/src/share/native/com/sun/java/util/jar/pack/unpack.cpp b/src/share/native/com/sun/java/util/jar/pack/unpack.cpp index 9ce0308089f4b3de7d1ad8d6ee77f2177847c176..aae7921ae43289af996e4550379429b83cd94433 100644 --- a/src/share/native/com/sun/java/util/jar/pack/unpack.cpp +++ b/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/test/tools/pack200/AttributeTests.java b/test/tools/pack200/AttributeTests.java index 6526737b732c930725054fafc918fb740538aced..c12891829e7ccb2d19ec5ca512b14c98aa837c3d 100644 --- a/test/tools/pack200/AttributeTests.java +++ b/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/test/tools/pack200/InstructionTests.java b/test/tools/pack200/InstructionTests.java index ce92c0ed55818807790571103d70533a78674cc6..7015ae9a11fd29e0ac821c86198e7174d1b342da 100644 --- a/test/tools/pack200/InstructionTests.java +++ b/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/test/tools/pack200/Utils.java b/test/tools/pack200/Utils.java index 07a64595e9f7d79fe4775a93369c259ebc00a3cc..f3d1d4666b898447edf14995517e95f4d9b18cf3 100644 --- a/test/tools/pack200/Utils.java +++ b/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<>();