# HG changeset patch # User coffeys # Date 1516022253 0 # Node ID ffa10f8080d04879fca2676655ad0f713708d967 # Parent 299f966882e1122d8e0b81b4541dab4a8cf5151b 8189969: Manifest better manifest entries 8197030: Perf regression on all platforms with 8u171-b03 - early lambda use Reviewed-by: weijun, igerasim diff -r 299f966882e1 -r ffa10f8080d0 src/share/classes/sun/security/util/ManifestDigester.java --- a/src/share/classes/sun/security/util/ManifestDigester.java Fri Jan 05 20:11:29 2018 -0800 +++ b/src/share/classes/sun/security/util/ManifestDigester.java Mon Jan 15 13:17:33 2018 +0000 @@ -26,8 +26,10 @@ package sun.security.util; import java.security.*; +import java.util.ArrayList; import java.util.HashMap; import java.io.ByteArrayOutputStream; +import java.util.List; /** * This class is used to compute digests on sections of the Manifest. @@ -39,7 +41,7 @@ /** the raw bytes of the manifest */ private byte rawBytes[]; - /** the offset/length pair for a section */ + /** the entries grouped by names */ private HashMap entries; // key is a UTF-8 string /** state returned by findSection */ @@ -120,8 +122,8 @@ return; // XXX: exception? // create an entry for main attributes - entries.put(MF_MAIN_ATTRS, - new Entry(0, pos.endOfSection + 1, pos.startOfNext, rawBytes)); + entries.put(MF_MAIN_ATTRS, new Entry().addSection( + new Section(0, pos.endOfSection + 1, pos.startOfNext, rawBytes))); int start = pos.startOfNext; while(findSection(start, pos)) { @@ -167,9 +169,15 @@ } } - entries.put(nameBuf.toString(), - new Entry(start, sectionLen, sectionLenWithBlank, - rawBytes)); + Entry e = entries.get(nameBuf.toString()); + if (e == null) { + entries.put(nameBuf.toString(), new Entry() + .addSection(new Section(start, sectionLen, + sectionLenWithBlank, rawBytes))); + } else { + e.addSection(new Section(start, sectionLen, + sectionLenWithBlank, rawBytes)); + } } catch (java.io.UnsupportedEncodingException uee) { throw new IllegalStateException( @@ -192,13 +200,52 @@ } public static class Entry { + + // One Entry for one name, and one name can have multiple sections. + // According to the JAR File Specification: "If there are multiple + // individual sections for the same file entry, the attributes in + // these sections are merged." + private List
sections = new ArrayList
(); + boolean oldStyle; + + private Entry addSection(Section sec) + { + sections.add(sec); + return this; + } + + public byte[] digest(MessageDigest md) + { + md.reset(); + for (Section sec : sections) { + if (oldStyle) { + Section.doOldStyle(md, sec.rawBytes, sec.offset, sec.lengthWithBlankLine); + } else { + md.update(sec.rawBytes, sec.offset, sec.lengthWithBlankLine); + } + } + return md.digest(); + } + + /** Netscape doesn't include the new line. Intel and JavaSoft do */ + + public byte[] digestWorkaround(MessageDigest md) + { + md.reset(); + for (Section sec : sections) { + md.update(sec.rawBytes, sec.offset, sec.length); + } + return md.digest(); + } + } + + private static class Section { int offset; int length; int lengthWithBlankLine; byte[] rawBytes; - boolean oldStyle; - public Entry(int offset, int length, + public Section(int offset, int length, int lengthWithBlankLine, byte[] rawBytes) { this.offset = offset; @@ -207,18 +254,7 @@ this.rawBytes = rawBytes; } - public byte[] digest(MessageDigest md) - { - md.reset(); - if (oldStyle) { - doOldStyle(md,rawBytes, offset, lengthWithBlankLine); - } else { - md.update(rawBytes, offset, lengthWithBlankLine); - } - return md.digest(); - } - - private void doOldStyle(MessageDigest md, + private static void doOldStyle(MessageDigest md, byte[] bytes, int offset, int length) @@ -242,16 +278,6 @@ } md.update(bytes, start, i-start); } - - - /** Netscape doesn't include the new line. Intel and JavaSoft do */ - - public byte[] digestWorkaround(MessageDigest md) - { - md.reset(); - md.update(rawBytes, offset, length); - return md.digest(); - } } public Entry get(String name, boolean oldStyle) { diff -r 299f966882e1 -r ffa10f8080d0 test/javax/security/auth/Subject/doAs/NestedActions.java --- a/test/javax/security/auth/Subject/doAs/NestedActions.java Fri Jan 05 20:11:29 2018 -0800 +++ b/test/javax/security/auth/Subject/doAs/NestedActions.java Mon Jan 15 13:17:33 2018 +0000 @@ -23,7 +23,6 @@ */ import jdk.testlibrary.ProcessTools; -import jdk.testlibrary.JarUtils; import javax.security.auth.Subject; import javax.security.auth.x500.X500Principal; @@ -101,7 +100,7 @@ public static void main(String[] args) throws IOException { if (args.length > 0) { if ("jar".equals(args[0]) && args.length > 2) { - JarUtils.createJar(args[1], Paths.get(TEST_CLASSES + FS), + createJar(args[1], Arrays.copyOfRange(args, 2, args.length)); } else { runJava(args); @@ -111,6 +110,21 @@ } } + static void createJar(String dest, String... files) throws IOException { + System.out.println("Create " + dest + " with the following content:"); + try (JarOutputStream jos = new JarOutputStream( + new FileOutputStream(dest), new Manifest())) { + for (String file : files) { + System.out.println(" " + file); + jos.putNextEntry(new JarEntry(file)); + try (FileInputStream fis = new FileInputStream( + TEST_CLASSES + FS + file)) { + jdk.testlibrary.Utils.transferTo(fis, jos); + } + } + } + } + static void runJava(String[] args) { if (args == null || args.length < 3) { throw new IllegalArgumentException("wrong parameters"); diff -r 299f966882e1 -r ffa10f8080d0 test/lib/testlibrary/jdk/testlibrary/OutputAnalyzer.java --- a/test/lib/testlibrary/jdk/testlibrary/OutputAnalyzer.java Fri Jan 05 20:11:29 2018 -0800 +++ b/test/lib/testlibrary/jdk/testlibrary/OutputAnalyzer.java Mon Jan 15 13:17:33 2018 +0000 @@ -362,6 +362,21 @@ } /** + * Verify the exit value of the process + * + * @param notExpectedExitValue Unexpected exit value from process + * @throws RuntimeException If the exit value from the process did match the expected value + */ + public OutputAnalyzer shouldNotHaveExitValue(int notExpectedExitValue) { + if (getExitValue() == notExpectedExitValue) { + reportDiagnosticSummary(); + throw new RuntimeException("Unexpected to get exit value of [" + + notExpectedExitValue + "]\n"); + } + return this; + } + + /** * Report summary that will help to diagnose the problem Currently includes: * - standard input produced by the process under test - standard output - * exit code Note: the command line is printed by the ProcessTools diff -r 299f966882e1 -r ffa10f8080d0 test/lib/testlibrary/jdk/testlibrary/Utils.java --- a/test/lib/testlibrary/jdk/testlibrary/Utils.java Fri Jan 05 20:11:29 2018 -0800 +++ b/test/lib/testlibrary/jdk/testlibrary/Utils.java Mon Jan 15 13:17:33 2018 +0000 @@ -56,6 +56,9 @@ public static final String JAVA_OPTIONS = System.getProperty("test.java.opts", "").trim(); + private static final int MAX_BUFFER_SIZE = Integer.MAX_VALUE - 8; + private static final int DEFAULT_BUFFER_SIZE = 8192; + private Utils() { // Private constructor to prevent class instantiation } @@ -232,6 +235,40 @@ private static final int BUFFER_SIZE = 1024; /** + * Helper method to read all bytes from InputStream + * + * @param is InputStream to read from + * @return array of bytes + * @throws IOException + */ + public static byte[] readAllBytes(InputStream is) throws IOException { + byte[] buf = new byte[DEFAULT_BUFFER_SIZE]; + int capacity = buf.length; + int nread = 0; + int n; + for (;;) { + // read to EOF which may read more or less than initial buffer size + while ((n = is.read(buf, nread, capacity - nread)) > 0) + nread += n; + + // if the last call to read returned -1, then we're done + if (n < 0) + break; + + // need to allocate a larger buffer + if (capacity <= MAX_BUFFER_SIZE - capacity) { + capacity = capacity << 1; + } else { + if (capacity == MAX_BUFFER_SIZE) + throw new OutOfMemoryError("Required array size too large"); + capacity = MAX_BUFFER_SIZE; + } + buf = Arrays.copyOf(buf, capacity); + } + return (capacity == nread) ? buf : Arrays.copyOf(buf, nread); + } + + /** * Reads all bytes from the input stream and writes the bytes to the * given output stream in the order that they are read. On return, the * input stream will be at end of stream. This method does not close either @@ -256,7 +293,7 @@ * @throws NullPointerException if {@code in} or {@code out} is {@code null} * */ - public static long transferBetweenStreams(InputStream in, OutputStream out) + public static long transferTo(InputStream in, OutputStream out) throws IOException { long transferred = 0; byte[] buffer = new byte[BUFFER_SIZE];