[JDK-6341887] Patch V2: java.util.zip: Add ByteBuffer methods to Inflater/Deflater
David Lloyd
david.lloyd at redhat.com
Thu Feb 22 20:08:08 UTC 2018
This is the second version of the patch first discussed here [1] to
add the ability to inflate/deflate to/from heap/direct byte buffers.
The patch is attached, as well as benchmark results with the original
and new code, and the benchmark source. The patch is also visible
online at [2].
Some notable features of this version:
• Complete JavaDoc per Alan's reminder
• Misc. small bug fixes
• Removed nearly all JNI field accesses, replaced with simple
bit-fields on input and output parameters to inflate* and deflate*
native methods
• Fixed a problem Alan alluded to where an inflate operation can throw
DataFormatException yet still have consumed some input data; this is
done by way of a single field-based output parameter which is only
used when this exception is thrown
• Cleaned up "finish" handling on the deflate side
• Implemented Sherman's suggestion to support both array-based and
buffer-based input; no ByteBuffer wrapping is used in this version
• Updated FlaterTest to test all combinations of inflate/deflate
array/heap/direct
• Per-call performance seems generally improved overall; from the JMH results:
◦ JDK version completed 95% of 16-byte inflate ops within 1262
ns/op (array in, array out)
◦ New version completes 95% of 16-byte inflate ops within 1124
ns/op (array in, array out)
◦ In addition, the new direct buffer modes show slightly better
results at 1114 ns/op for 16-byte ops for direct buffer in & out - not
accounting for possible secondary improvements resulting from avoiding
Get*Critical JNI functions (as well as the obvious: avoiding the need
to allocate & copy between byte arrays and direct buffers)
The JMH test methods are named based on the type of input and output
done for each test, where "A" signifies "array", "H" signifies "heap
buffer", and "D" signifies "direct buffer".
[1] http://mail.openjdk.java.net/pipermail/core-libs-dev/2018-February/051562.html
[2] https://github.com/dmlloyd/openjdk/commit/zlib-bytebuffer-v6
--
- DML
-------------- next part --------------
commit 04a83977c5b70d1a9d5850b05fc8b585356b6c2a
Author: David M. Lloyd <david.lloyd at redhat.com>
Date: Fri Feb 16 11:00:10 2018 -0600
[JDK-6341887] Update Inflater/Deflater to handle ByteBuffer
diff --git a/make/mapfiles/libzip/mapfile-vers b/make/mapfiles/libzip/mapfile-vers
index d711d8e17f4..11ccc2d6ecb 100644
--- a/make/mapfiles/libzip/mapfile-vers
+++ b/make/mapfiles/libzip/mapfile-vers
@@ -33,20 +33,28 @@ SUNWprivate_1.1 {
Java_java_util_zip_CRC32_update;
Java_java_util_zip_CRC32_updateBytes0;
Java_java_util_zip_CRC32_updateByteBuffer0;
- Java_java_util_zip_Deflater_deflateBytes;
+ Java_java_util_zip_Deflater_deflateBytesBytes;
+ Java_java_util_zip_Deflater_deflateBytesBuffer;
+ Java_java_util_zip_Deflater_deflateBufferBytes;
+ Java_java_util_zip_Deflater_deflateBufferBuffer;
Java_java_util_zip_Deflater_end;
Java_java_util_zip_Deflater_getAdler;
Java_java_util_zip_Deflater_init;
Java_java_util_zip_Deflater_initIDs;
Java_java_util_zip_Deflater_reset;
Java_java_util_zip_Deflater_setDictionary;
+ Java_java_util_zip_Deflater_setDictionaryBuffer;
Java_java_util_zip_Inflater_end;
Java_java_util_zip_Inflater_getAdler;
- Java_java_util_zip_Inflater_inflateBytes;
+ Java_java_util_zip_Inflater_inflateBytesBytes;
+ Java_java_util_zip_Inflater_inflateBytesBuffer;
+ Java_java_util_zip_Inflater_inflateBufferBytes;
+ Java_java_util_zip_Inflater_inflateBufferBuffer;
Java_java_util_zip_Inflater_init;
Java_java_util_zip_Inflater_initIDs;
Java_java_util_zip_Inflater_reset;
Java_java_util_zip_Inflater_setDictionary;
+ Java_java_util_zip_Inflater_setDictionaryBuffer;
ZIP_Close;
ZIP_CRC32;
ZIP_FreeEntry;
diff --git a/src/java.base/share/classes/java/util/zip/Deflater.java b/src/java.base/share/classes/java/util/zip/Deflater.java
index c75dd4a33f0..36e08a1dfc7 100644
--- a/src/java.base/share/classes/java/util/zip/Deflater.java
+++ b/src/java.base/share/classes/java/util/zip/Deflater.java
@@ -26,7 +26,12 @@
package java.util.zip;
import java.lang.ref.Cleaner.Cleanable;
+import java.nio.ByteBuffer;
+import java.nio.ReadOnlyBufferException;
+import java.util.Objects;
+
import jdk.internal.ref.CleanerFactory;
+import sun.nio.ch.DirectBuffer;
/**
* This class provides support for general purpose compression using the
@@ -92,8 +97,9 @@ import jdk.internal.ref.CleanerFactory;
public class Deflater {
private final DeflaterZStreamRef zsRef;
- private byte[] buf = new byte[0];
- private int off, len;
+ private ByteBuffer input = ZipUtils.defaultBuf;
+ private byte[] inputArray;
+ private int inputPos, inputLim;
private int level, strategy;
private boolean setParams;
private boolean finish, finished;
@@ -170,9 +176,14 @@ public class Deflater {
*/
public static final int FULL_FLUSH = 3;
+ /**
+ * Flush mode to use at the end of output. Can only be provided by the
+ * user by way of {@link #finish()}.
+ */
+ private static final int FINISH = 4;
+
static {
ZipUtils.loadLibrary();
- initIDs();
}
/**
@@ -216,16 +227,14 @@ public class Deflater {
* @see Deflater#needsInput
*/
public void setInput(byte[] b, int off, int len) {
- if (b== null) {
- throw new NullPointerException();
- }
if (off < 0 || len < 0 || off > b.length - len) {
throw new ArrayIndexOutOfBoundsException();
}
synchronized (zsRef) {
- this.buf = b;
- this.off = off;
- this.len = len;
+ this.input = null;
+ this.inputArray = b;
+ this.inputPos = off;
+ this.inputLim = off + len;
}
}
@@ -239,6 +248,31 @@ public class Deflater {
setInput(b, 0, b.length);
}
+ /**
+ * Sets input data for compression. This should be called whenever
+ * needsInput() returns true indicating that more input data is required.
+ * <p>
+ * The given buffer's position will be updated as deflate operations are
+ * performed. The input buffer may be modified (refilled) between deflate
+ * operations; doing so is equivalent to creating a new buffer and setting
+ * it with this method.
+ * <p>
+ * Modifying the input buffer's contents, position, or limit concurrently with
+ * a deflate operation will result in undefined behavior, which may include
+ * incorrect operation results or operation failure.
+ *
+ * @param byteBuffer the input data bytes
+ * @see Deflater#needsInput
+ * @since 11
+ */
+ public void setInput(ByteBuffer byteBuffer) {
+ Objects.requireNonNull(byteBuffer);
+ synchronized (zsRef) {
+ this.input = byteBuffer;
+ this.inputArray = null;
+ }
+ }
+
/**
* Sets preset dictionary for compression. A preset dictionary is used
* when the history buffer can be predetermined. When the data is later
@@ -252,9 +286,6 @@ public class Deflater {
* @see Inflater#getAdler
*/
public void setDictionary(byte[] b, int off, int len) {
- if (b == null) {
- throw new NullPointerException();
- }
if (off < 0 || len < 0 || off > b.length - len) {
throw new ArrayIndexOutOfBoundsException();
}
@@ -278,6 +309,37 @@ public class Deflater {
setDictionary(b, 0, b.length);
}
+ /**
+ * Sets preset dictionary for compression. A preset dictionary is used
+ * when the history buffer can be predetermined. When the data is later
+ * uncompressed with Inflater.inflate(), Inflater.getAdler() can be called
+ * in order to get the Adler-32 value of the dictionary required for
+ * decompression.
+ * <p>
+ * The bytes in given byte buffer will be fully consumed by this method. On
+ * return, its position will equal its limit.
+ *
+ * @param byteBuffer the dictionary data bytes
+ * @see Inflater#inflate
+ * @see Inflater#getAdler
+ */
+ public void setDictionary(ByteBuffer byteBuffer) {
+ synchronized (zsRef) {
+ final int position = byteBuffer.position();
+ final int remaining = Math.max(byteBuffer.limit() - position, 0);
+ ensureOpen();
+ if (byteBuffer.isDirect()) {
+ final long address = ((DirectBuffer) byteBuffer).address();
+ setDictionaryBuffer(zsRef.address(), address + position, remaining);
+ } else {
+ final byte[] array = ZipUtils.getBufferArray(byteBuffer);
+ final int offset = ZipUtils.getBufferOffset(byteBuffer);
+ setDictionary(zsRef.address(), array, offset + position, remaining);
+ }
+ byteBuffer.position(position + remaining);
+ }
+ }
+
/**
* Sets the compression strategy to the specified value.
*
@@ -331,14 +393,17 @@ public class Deflater {
}
/**
- * Returns true if the input data buffer is empty and setInput()
- * should be called in order to provide more input.
+ * Returns true if no data remains in the input buffer. This can
+ * be used to determine if one of the {@code setInput()} methods should be
+ * called in order to provide more input.
+ *
* @return true if the input data buffer is empty and setInput()
* should be called in order to provide more input
*/
public boolean needsInput() {
synchronized (zsRef) {
- return len <= 0;
+ final ByteBuffer input = this.input;
+ return input == null ? inputLim == inputPos : ! input.hasRemaining();
}
}
@@ -404,6 +469,26 @@ public class Deflater {
return deflate(b, 0, b.length, NO_FLUSH);
}
+ /**
+ * Compresses the input data and fills specified buffer with compressed
+ * data. Returns actual number of bytes of compressed data. A return value
+ * of 0 indicates that {@link #needsInput() needsInput} should be called
+ * in order to determine if more input data is required.
+ *
+ * <p>This method uses {@link #NO_FLUSH} as its compression flush mode.
+ * An invocation of this method of the form {@code deflater.deflate(b)}
+ * yields the same result as the invocation of
+ * {@code deflater.deflate(b, 0, b.length, Deflater.NO_FLUSH)}.
+ *
+ * @param output the buffer for the compressed data
+ * @return the actual number of bytes of compressed data written to the
+ * output buffer
+ * @since 11
+ */
+ public int deflate(ByteBuffer output) {
+ return deflate(output, NO_FLUSH);
+ }
+
/**
* Compresses the input data and fills the specified buffer with compressed
* data. Returns actual number of bytes of data compressed.
@@ -441,6 +526,10 @@ public class Deflater {
* repeatedly output to the output buffer every time this method is
* invoked.
*
+ * <p>If the {@link #setInput(ByteBuffer)} method was called to provide a buffer
+ * for input, the input buffer's position will be advanced by the number of bytes
+ * consumed by this operation.
+ *
* @param b the buffer for the compressed data
* @param off the start offset of the data
* @param len the maximum number of bytes of compressed data
@@ -452,24 +541,227 @@ public class Deflater {
* @since 1.7
*/
public int deflate(byte[] b, int off, int len, int flush) {
- if (b == null) {
- throw new NullPointerException();
- }
if (off < 0 || len < 0 || off > b.length - len) {
throw new ArrayIndexOutOfBoundsException();
}
+ if (flush != NO_FLUSH && flush != SYNC_FLUSH && flush != FULL_FLUSH) {
+ throw new IllegalArgumentException();
+ }
synchronized (zsRef) {
ensureOpen();
- if (flush == NO_FLUSH || flush == SYNC_FLUSH ||
- flush == FULL_FLUSH) {
- int thisLen = this.len;
- int n = deflateBytes(zsRef.address(), b, off, len, flush);
- bytesWritten += n;
- bytesRead += (thisLen - this.len);
- return n;
+
+ final ByteBuffer input = this.input;
+ if (finish) {
+ // disregard given flush mode in this case
+ flush = FINISH;
+ }
+ final int params;
+ if (setParams) {
+ // bit 0: true to set params
+ // bit 1-2: strategy (0, 1, or 2)
+ // bit 3-31: level (0..9 or -1)
+ params = 1 | strategy << 1 | level << 3;
+ } else {
+ params = 0;
+ }
+ final int inputPos;
+ final long result;
+ if (input == null) {
+ inputPos = this.inputPos;
+ result = deflateBytesBytes(zsRef.address(),
+ inputArray, inputPos, inputLim - inputPos,
+ b, off, len,
+ flush, params);
+ } else {
+ inputPos = input.position();
+ final int inputRem = Math.max(input.limit() - inputPos, 0);
+ if (input.isDirect()) {
+ final long inputAddress = ((DirectBuffer) input).address();
+ result = deflateBufferBytes(zsRef.address(),
+ inputAddress + inputPos, inputRem,
+ b, off, len,
+ flush, params);
+ } else {
+ final byte[] inputArray = ZipUtils.getBufferArray(input);
+ final int inputOffset = ZipUtils.getBufferOffset(input);
+ result = deflateBytesBytes(zsRef.address(),
+ inputArray, inputOffset + inputPos, inputRem,
+ b, off, len,
+ flush, params);
+ }
+ }
+ int read = (int) (result & 0x7fff_ffffL);
+ int written = (int) (result >>> 31 & 0x7fff_ffffL);
+ if ((result >>> 62 & 1) != 0) {
+ finished = true;
+ }
+ if (params != 0 && (result >>> 63 & 1) == 0) {
+ setParams = false;
+ }
+ if (input != null) {
+ input.position(inputPos + read);
+ } else {
+ this.inputPos = inputPos + read;
}
+ bytesWritten += written;
+ bytesRead += read;
+ return written;
+ }
+ }
+
+ /**
+ * Compresses the input data and fills the specified buffer with compressed
+ * data. Returns actual number of bytes of data compressed.
+ *
+ * <p>Compression flush mode is one of the following three modes:
+ *
+ * <ul>
+ * <li>{@link #NO_FLUSH}: allows the deflater to decide how much data
+ * to accumulate, before producing output, in order to achieve the best
+ * compression (should be used in normal use scenario). A return value
+ * of 0 in this flush mode indicates that {@link #needsInput()} should
+ * be called in order to determine if more input data is required.
+ *
+ * <li>{@link #SYNC_FLUSH}: all pending output in the deflater is flushed,
+ * to the specified output buffer, so that an inflater that works on
+ * compressed data can get all input data available so far (In particular
+ * the {@link #needsInput()} returns {@code true} after this invocation
+ * if enough output space is provided). Flushing with {@link #SYNC_FLUSH}
+ * may degrade compression for some compression algorithms and so it
+ * should be used only when necessary.
+ *
+ * <li>{@link #FULL_FLUSH}: all pending output is flushed out as with
+ * {@link #SYNC_FLUSH}. The compression state is reset so that the inflater
+ * that works on the compressed output data can restart from this point
+ * if previous compressed data has been damaged or if random access is
+ * desired. Using {@link #FULL_FLUSH} too often can seriously degrade
+ * compression.
+ * </ul>
+ *
+ * <p>In the case of {@link #FULL_FLUSH} or {@link #SYNC_FLUSH}, if
+ * the return value is {@code len}, the space available in output
+ * buffer {@code output}, this method should be invoked again with the same
+ * {@code flush} parameter and more output space. Make sure that
+ * {@code len} is greater than 6 to avoid flush marker (5 bytes) being
+ * repeatedly output to the output buffer every time this method is
+ * invoked.
+ *
+ * <p>On success, the position of the given {@code output} byte buffer will be
+ * advanced by as many bytes as were produced by the operation, which is equal
+ * to the number returned by this method.
+ *
+ * <p>If the {@link #setInput(ByteBuffer)} method was called to provide a buffer
+ * for input, the input buffer's position will be advanced by the number of bytes
+ * consumed by this operation.
+ *
+ * @param output the buffer for the compressed data
+ * @param flush the compression flush mode
+ * @return the actual number of bytes of compressed data written to
+ * the output buffer
+ *
+ * @throws IllegalArgumentException if the flush mode is invalid
+ * @since 11
+ */
+ public int deflate(ByteBuffer output, int flush) {
+ if (output.isReadOnly()) {
+ throw new ReadOnlyBufferException();
+ }
+ if (flush != NO_FLUSH && flush != SYNC_FLUSH && flush != FULL_FLUSH) {
throw new IllegalArgumentException();
}
+ synchronized (zsRef) {
+ ensureOpen();
+
+ final ByteBuffer input = this.input;
+ if (finish) {
+ // disregard given flush mode in this case
+ flush = FINISH;
+ }
+ final int params;
+ if (setParams) {
+ // bit 0: true to set params
+ // bit 1-2: strategy (0, 1, or 2)
+ // bit 3-31: level (0..9 or -1)
+ params = 1 | strategy << 1 | level << 3;
+ } else {
+ params = 0;
+ }
+ final int outputPos = output.position();
+ final int outputRem = Math.max(output.limit() - outputPos, 0);
+ final int inputPos;
+ final long result;
+ if (input == null) {
+ inputPos = this.inputPos;
+ if (output.isDirect()) {
+ final long outputAddress = ((DirectBuffer) output).address();
+ result = deflateBytesBuffer(zsRef.address(),
+ inputArray, inputPos, inputLim - inputPos,
+ outputAddress + outputPos, outputRem,
+ flush, params);
+ } else {
+ final byte[] outputArray = ZipUtils.getBufferArray(output);
+ final int outputOffset = ZipUtils.getBufferOffset(output);
+ result = deflateBytesBytes(zsRef.address(),
+ inputArray, inputPos, inputLim - inputPos,
+ outputArray, outputOffset + outputPos, outputRem,
+ flush, params);
+ }
+ } else {
+ inputPos = input.position();
+ final int inputRem = Math.max(input.limit() - inputPos, 0);
+ if (input.isDirect()) {
+ final long inputAddress = ((DirectBuffer) input).address();
+ if (output.isDirect()) {
+ final long outputAddress = outputPos + ((DirectBuffer) output).address();
+ result = deflateBufferBuffer(zsRef.address(),
+ inputAddress + inputPos, inputRem,
+ outputAddress, outputRem,
+ flush, params);
+ } else {
+ final byte[] outputArray = ZipUtils.getBufferArray(output);
+ final int outputOffset = ZipUtils.getBufferOffset(output);
+ result = deflateBufferBytes(zsRef.address(),
+ inputAddress + inputPos, inputRem,
+ outputArray, outputOffset + outputPos, outputRem,
+ flush, params);
+ }
+ } else {
+ final byte[] inputArray = ZipUtils.getBufferArray(input);
+ final int inputOffset = ZipUtils.getBufferOffset(input);
+ if (output.isDirect()) {
+ final long outputAddress = ((DirectBuffer) output).address();
+ result = deflateBytesBuffer(zsRef.address(),
+ inputArray, inputOffset + inputPos, inputRem,
+ outputAddress + outputPos, outputRem,
+ flush, params);
+ } else {
+ final byte[] outputArray = ZipUtils.getBufferArray(output);
+ final int outputOffset = ZipUtils.getBufferOffset(output);
+ result = deflateBytesBytes(zsRef.address(),
+ inputArray, inputOffset + inputPos, inputRem,
+ outputArray, outputOffset + outputPos, outputRem,
+ flush, params);
+ }
+ }
+ }
+ int read = (int) (result & 0x7fff_ffffL);
+ int written = (int) (result >>> 31 & 0x7fff_ffffL);
+ if ((result >>> 62 & 1) != 0) {
+ finished = true;
+ }
+ if (params != 0 && (result >>> 63 & 1) == 0) {
+ setParams = false;
+ }
+ if (input != null) {
+ input.position(inputPos + read);
+ } else {
+ this.inputPos = inputPos + read;
+ }
+ output.position(outputPos + written);
+ bytesWritten += written;
+ bytesRead += read;
+ return written;
+ }
}
/**
@@ -545,7 +837,8 @@ public class Deflater {
reset(zsRef.address());
finish = false;
finished = false;
- off = len = 0;
+ input = ZipUtils.defaultBuf;
+ inputArray = null;
bytesRead = bytesWritten = 0;
}
}
@@ -560,7 +853,7 @@ public class Deflater {
public void end() {
synchronized (zsRef) {
zsRef.clean();
- buf = null;
+ input = ZipUtils.defaultBuf;
}
}
@@ -585,11 +878,26 @@ public class Deflater {
throw new NullPointerException("Deflater has been closed");
}
- private static native void initIDs();
private static native long init(int level, int strategy, boolean nowrap);
- private static native void setDictionary(long addr, byte[] b, int off, int len);
- private native int deflateBytes(long addr, byte[] b, int off, int len,
- int flush);
+ private static native void setDictionary(long addr, byte[] b, int off,
+ int len);
+ private static native void setDictionaryBuffer(long addr, long bufAddress, int len);
+ private native long deflateBytesBytes(long addr,
+ byte[] inputArray, int inputOff, int inputLen,
+ byte[] outputArray, int outputOff, int outputLen,
+ int flush, int params);
+ private native long deflateBytesBuffer(long addr,
+ byte[] inputArray, int inputOff, int inputLen,
+ long outputAddress, int outputLen,
+ int flush, int params);
+ private native long deflateBufferBytes(long addr,
+ long inputAddress, int inputLen,
+ byte[] outputArray, int outputOff, int outputLen,
+ int flush, int params);
+ private native long deflateBufferBuffer(long addr,
+ long inputAddress, int inputLen,
+ long outputAddress, int outputLen,
+ int flush, int params);
private static native int getAdler(long addr);
private static native void reset(long addr);
private static native void end(long addr);
diff --git a/src/java.base/share/classes/java/util/zip/Inflater.java b/src/java.base/share/classes/java/util/zip/Inflater.java
index 9c6d8aa3d83..6cb76c4c44f 100644
--- a/src/java.base/share/classes/java/util/zip/Inflater.java
+++ b/src/java.base/share/classes/java/util/zip/Inflater.java
@@ -26,7 +26,12 @@
package java.util.zip;
import java.lang.ref.Cleaner.Cleanable;
+import java.nio.ByteBuffer;
+import java.nio.ReadOnlyBufferException;
+import java.util.Objects;
+
import jdk.internal.ref.CleanerFactory;
+import sun.nio.ch.DirectBuffer;
/**
* This class provides support for general purpose decompression using the
@@ -92,14 +97,19 @@ import jdk.internal.ref.CleanerFactory;
public class Inflater {
private final InflaterZStreamRef zsRef;
- private byte[] buf = defaultBuf;
- private int off, len;
+ private ByteBuffer input = ZipUtils.defaultBuf;
+ private byte[] inputArray;
+ private int inputPos, inputLim;
private boolean finished;
private boolean needDict;
private long bytesRead;
private long bytesWritten;
- private static final byte[] defaultBuf = new byte[0];
+ /**
+ * This field is used as an "out" parameter from JNI when a
+ * {@link DataFormatException} is thrown during the inflate operation.
+ */
+ private int inputConsumed;
static {
ZipUtils.loadLibrary();
@@ -138,16 +148,14 @@ public class Inflater {
* @see Inflater#needsInput
*/
public void setInput(byte[] b, int off, int len) {
- if (b == null) {
- throw new NullPointerException();
- }
if (off < 0 || len < 0 || off > b.length - len) {
throw new ArrayIndexOutOfBoundsException();
}
synchronized (zsRef) {
- this.buf = b;
- this.off = off;
- this.len = len;
+ this.input = null;
+ this.inputArray = b;
+ this.inputPos = off;
+ this.inputLim = off + len;
}
}
@@ -162,6 +170,32 @@ public class Inflater {
setInput(b, 0, b.length);
}
+ /**
+ * Sets input data for decompression. Should be called whenever
+ * needsInput() returns true indicating that more input data is
+ * required.
+ * <p>
+ * The given buffer's position will be updated as inflate operations are
+ * performed. The input buffer may be modified (refilled) between inflate
+ * operations; doing so is equivalent to creating a new buffer and setting
+ * it with this method.
+ * <p>
+ * Modifying the input buffer's contents, position, or limit concurrently with
+ * an inflate operation will result in undefined behavior, which may include
+ * incorrect operation results or operation failure.
+ *
+ * @param byteBuffer the input data bytes
+ * @see Inflater#needsInput
+ * @since 11
+ */
+ public void setInput(ByteBuffer byteBuffer) {
+ Objects.requireNonNull(byteBuffer);
+ synchronized (zsRef) {
+ this.input = byteBuffer;
+ this.inputArray = null;
+ }
+ }
+
/**
* Sets the preset dictionary to the given array of bytes. Should be
* called when inflate() returns 0 and needsDictionary() returns true
@@ -174,9 +208,6 @@ public class Inflater {
* @see Inflater#getAdler
*/
public void setDictionary(byte[] b, int off, int len) {
- if (b == null) {
- throw new NullPointerException();
- }
if (off < 0 || len < 0 || off > b.length - len) {
throw new ArrayIndexOutOfBoundsException();
}
@@ -200,6 +231,38 @@ public class Inflater {
setDictionary(b, 0, b.length);
}
+ /**
+ * Sets the preset dictionary to the given array of bytes. Should be
+ * called when inflate() returns 0 and needsDictionary() returns true
+ * indicating that a preset dictionary is required. The method getAdler()
+ * can be used to get the Adler-32 value of the dictionary needed.
+ * <p>
+ * The bytes in given byte buffer will be fully consumed by this method. On
+ * return, its position will equal its limit.
+ *
+ * @param byteBuffer the dictionary data bytes
+ * @see Inflater#needsDictionary
+ * @see Inflater#getAdler
+ * @since 11
+ */
+ public void setDictionary(ByteBuffer byteBuffer) {
+ synchronized (zsRef) {
+ final int position = byteBuffer.position();
+ final int remaining = Math.max(byteBuffer.limit() - position, 0);
+ ensureOpen();
+ if (byteBuffer.isDirect()) {
+ final long address = ((DirectBuffer) byteBuffer).address();
+ setDictionaryBuffer(zsRef.address(), address + position, remaining);
+ } else {
+ final byte[] array = ZipUtils.getBufferArray(byteBuffer);
+ final int offset = ZipUtils.getBufferOffset(byteBuffer);
+ setDictionary(zsRef.address(), array, offset + position, remaining);
+ }
+ byteBuffer.position(position + remaining);
+ needDict = false;
+ }
+ }
+
/**
* Returns the total number of bytes remaining in the input buffer.
* This can be used to find out what bytes still remain in the input
@@ -208,19 +271,22 @@ public class Inflater {
*/
public int getRemaining() {
synchronized (zsRef) {
- return len;
+ final ByteBuffer input = this.input;
+ return input == null ? inputLim - inputPos : input.remaining();
}
}
/**
* Returns true if no data remains in the input buffer. This can
- * be used to determine if #setInput should be called in order
- * to provide more input.
+ * be used to determine if one of the {@code setInput()} methods should be
+ * called in order to provide more input.
+ *
* @return true if no data remains in the input buffer
*/
public boolean needsInput() {
synchronized (zsRef) {
- return len <= 0;
+ final ByteBuffer input = this.input;
+ return input == null ? inputLim == inputPos : ! input.hasRemaining();
}
}
@@ -254,30 +320,83 @@ public class Inflater {
* determine if more input data or a preset dictionary is required.
* In the latter case, getAdler() can be used to get the Adler-32
* value of the dictionary required.
+ * <p>
+ * If the {@link #setInput(ByteBuffer)} method was called to provide a buffer
+ * for input, the input buffer's position will be advanced by the number of bytes
+ * consumed by this operation, even in the event that an exception is thrown.
+ *
* @param b the buffer for the uncompressed data
* @param off the start offset of the data
* @param len the maximum number of uncompressed bytes
* @return the actual number of uncompressed bytes
- * @exception DataFormatException if the compressed data format is invalid
+ * @throws DataFormatException if the compressed data format is invalid
* @see Inflater#needsInput
* @see Inflater#needsDictionary
*/
public int inflate(byte[] b, int off, int len)
throws DataFormatException
{
- if (b == null) {
- throw new NullPointerException();
- }
if (off < 0 || len < 0 || off > b.length - len) {
throw new ArrayIndexOutOfBoundsException();
}
synchronized (zsRef) {
ensureOpen();
- int thisLen = this.len;
- int n = inflateBytes(zsRef.address(), b, off, len);
- bytesWritten += n;
- bytesRead += (thisLen - this.len);
- return n;
+ final ByteBuffer input = this.input;
+ final long result;
+ final int inputPos;
+ if (input == null) {
+ inputPos = this.inputPos;
+ try {
+ result = inflateBytesBytes(zsRef.address(),
+ inputArray, inputPos, inputLim - inputPos,
+ b, off, len);
+ } catch (DataFormatException e) {
+ int read = inputConsumed;
+ this.inputPos = inputPos + read;
+ bytesRead += read;
+ inputConsumed = 0;
+ throw e;
+ }
+ } else {
+ inputPos = input.position();
+ try {
+ final int inputRem = Math.max(input.limit() - inputPos, 0);
+ if (input.isDirect()) {
+ final long inputAddress = ((DirectBuffer) input).address();
+ result = inflateBufferBytes(zsRef.address(),
+ inputAddress + inputPos, inputRem,
+ b, off, len);
+ } else {
+ final byte[] inputArray = ZipUtils.getBufferArray(input);
+ final int inputOffset = ZipUtils.getBufferOffset(input);
+ result = inflateBytesBytes(zsRef.address(),
+ inputArray, inputOffset + inputPos, inputRem,
+ b, off, len);
+ }
+ } catch (DataFormatException e) {
+ int read = inputConsumed;
+ input.position(inputPos + read);
+ bytesRead += read;
+ inputConsumed = 0;
+ throw e;
+ }
+ }
+ int read = (int) (result & 0x7fff_ffffL);
+ int written = (int) (result >>> 31 & 0x7fff_ffffL);
+ if ((result >>> 62 & 1) != 0) {
+ finished = true;
+ }
+ if ((result >>> 63 & 1) != 0) {
+ needDict = true;
+ }
+ if (input != null) {
+ input.position(inputPos + read);
+ } else {
+ this.inputPos = inputPos + read;
+ }
+ bytesWritten += written;
+ bytesRead += read;
+ return written;
}
}
@@ -288,9 +407,14 @@ public class Inflater {
* determine if more input data or a preset dictionary is required.
* In the latter case, getAdler() can be used to get the Adler-32
* value of the dictionary required.
+ * <p>
+ * If the {@link #setInput(ByteBuffer)} method was called to provide a buffer
+ * for input, the input buffer's position will be advanced by the number of bytes
+ * consumed by this operation, even in the event that an exception is thrown.
+ *
* @param b the buffer for the uncompressed data
* @return the actual number of uncompressed bytes
- * @exception DataFormatException if the compressed data format is invalid
+ * @throws DataFormatException if the compressed data format is invalid
* @see Inflater#needsInput
* @see Inflater#needsDictionary
*/
@@ -298,6 +422,125 @@ public class Inflater {
return inflate(b, 0, b.length);
}
+ /**
+ * Uncompresses bytes into specified buffer. Returns actual number
+ * of bytes uncompressed. A return value of 0 indicates that
+ * needsInput() or needsDictionary() should be called in order to
+ * determine if more input data or a preset dictionary is required.
+ * In the latter case, getAdler() can be used to get the Adler-32
+ * value of the dictionary required.
+ * <p>
+ * On success, the position of the given {@code output} byte buffer will be
+ * advanced by as many bytes as were produced by the operation, which is equal
+ * to the number returned by this method.
+ * <p>
+ * If the {@link #setInput(ByteBuffer)} method was called to provide a buffer
+ * for input, the input buffer's position will be advanced by the number of bytes
+ * consumed by this operation, even in the event that an exception is thrown.
+ *
+ * @param output the buffer for the uncompressed data
+ * @return the actual number of uncompressed bytes
+ * @throws DataFormatException if the compressed data format is invalid
+ * @throws ReadOnlyBufferException if the given output buffer is read-only
+ * @see Inflater#needsInput
+ * @see Inflater#needsDictionary
+ * @since 11
+ */
+ public int inflate(ByteBuffer output) throws DataFormatException {
+ if (output.isReadOnly()) {
+ throw new ReadOnlyBufferException();
+ }
+ synchronized (zsRef) {
+ ensureOpen();
+ final ByteBuffer input = this.input;
+ final long result;
+ final int inputPos;
+ final int outputPos = output.position();
+ final int outputRem = Math.max(output.limit() - outputPos, 0);
+ if (input == null) {
+ inputPos = this.inputPos;
+ try {
+ if (output.isDirect()) {
+ final long outputAddress = ((DirectBuffer) output).address();
+ result = inflateBytesBuffer(zsRef.address(),
+ inputArray, inputPos, inputLim - inputPos,
+ outputAddress + outputPos, outputRem);
+ } else {
+ final byte[] outputArray = ZipUtils.getBufferArray(output);
+ final int outputOffset = ZipUtils.getBufferOffset(output);
+ result = inflateBytesBytes(zsRef.address(),
+ inputArray, inputPos, inputLim - inputPos,
+ outputArray, outputOffset + outputPos, outputRem);
+ }
+ } catch (DataFormatException e) {
+ int read = inputConsumed;
+ this.inputPos = inputPos + read;
+ bytesRead += read;
+ inputConsumed = 0;
+ throw e;
+ }
+ } else {
+ inputPos = input.position();
+ final int inputRem = Math.max(input.limit() - inputPos, 0);
+ try {
+ if (input.isDirect()) {
+ final long inputAddress = ((DirectBuffer) input).address();
+ if (output.isDirect()) {
+ final long outputAddress = ((DirectBuffer) output).address();
+ result = inflateBufferBuffer(zsRef.address(),
+ inputAddress + inputPos, inputRem,
+ outputAddress + outputPos, outputRem);
+ } else {
+ final byte[] outputArray = ZipUtils.getBufferArray(output);
+ final int outputOffset = ZipUtils.getBufferOffset(output);
+ result = inflateBufferBytes(zsRef.address(),
+ inputAddress + inputPos, inputRem,
+ outputArray, outputOffset + outputPos, outputRem);
+ }
+ } else {
+ final byte[] inputArray = ZipUtils.getBufferArray(input);
+ final int inputOffset = ZipUtils.getBufferOffset(input);
+ if (output.isDirect()) {
+ final long outputAddress = ((DirectBuffer) output).address();
+ result = inflateBytesBuffer(zsRef.address(),
+ inputArray, inputOffset + inputPos, inputRem,
+ outputAddress + outputPos, outputRem);
+ } else {
+ final byte[] outputArray = ZipUtils.getBufferArray(output);
+ final int outputOffset = ZipUtils.getBufferOffset(output);
+ result = inflateBytesBytes(zsRef.address(),
+ inputArray, inputOffset + inputPos, inputRem,
+ outputArray, outputOffset + outputPos, outputRem);
+ }
+ }
+ } catch (DataFormatException e) {
+ int read = inputConsumed;
+ input.position(inputPos + read);
+ bytesRead += read;
+ inputConsumed = 0;
+ throw e;
+ }
+ }
+ int read = (int) (result & 0x7fff_ffffL);
+ int written = (int) (result >>> 31 & 0x7fff_ffffL);
+ if ((result >>> 62 & 1) != 0) {
+ finished = true;
+ }
+ if ((result >>> 63 & 1) != 0) {
+ needDict = true;
+ }
+ if (input != null) {
+ input.position(inputPos + read);
+ } else {
+ this.inputPos = inputPos + read;
+ }
+ output.position(outputPos + written);
+ bytesWritten += written;
+ bytesRead += read;
+ return written;
+ }
+ }
+
/**
* Returns the ADLER-32 value of the uncompressed data.
* @return the ADLER-32 value of the uncompressed data
@@ -368,10 +611,10 @@ public class Inflater {
synchronized (zsRef) {
ensureOpen();
reset(zsRef.address());
- buf = defaultBuf;
+ input = ZipUtils.defaultBuf;
+ inputArray = null;
finished = false;
needDict = false;
- off = len = 0;
bytesRead = bytesWritten = 0;
}
}
@@ -386,7 +629,8 @@ public class Inflater {
public void end() {
synchronized (zsRef) {
zsRef.clean();
- buf = null;
+ input = ZipUtils.defaultBuf;
+ inputArray = null;
}
}
@@ -416,18 +660,23 @@ public class Inflater {
throw new NullPointerException("Inflater has been closed");
}
- boolean ended() {
- synchronized (zsRef) {
- return zsRef.address() == 0;
- }
- }
-
private static native void initIDs();
private static native long init(boolean nowrap);
private static native void setDictionary(long addr, byte[] b, int off,
int len);
- private native int inflateBytes(long addr, byte[] b, int off, int len)
- throws DataFormatException;
+ private static native void setDictionaryBuffer(long addr, long bufAddress, int len);
+ private native long inflateBytesBytes(long addr,
+ byte[] inputArray, int inputOff, int inputLen,
+ byte[] outputArray, int outputOff, int outputLen) throws DataFormatException;
+ private native long inflateBytesBuffer(long addr,
+ byte[] inputArray, int inputOff, int inputLen,
+ long outputAddress, int outputLen) throws DataFormatException;
+ private native long inflateBufferBytes(long addr,
+ long inputAddress, int inputLen,
+ byte[] outputArray, int outputOff, int outputLen) throws DataFormatException;
+ private native long inflateBufferBuffer(long addr,
+ long inputAddress, int inputLen,
+ long outputAddress, int outputLen) throws DataFormatException;
private static native int getAdler(long addr);
private static native void reset(long addr);
private static native void end(long addr);
diff --git a/src/java.base/share/classes/java/util/zip/ZipUtils.java b/src/java.base/share/classes/java/util/zip/ZipUtils.java
index 45c5d8dbb67..07e64e4fa92 100644
--- a/src/java.base/share/classes/java/util/zip/ZipUtils.java
+++ b/src/java.base/share/classes/java/util/zip/ZipUtils.java
@@ -25,6 +25,8 @@
package java.util.zip;
+import java.nio.Buffer;
+import java.nio.ByteBuffer;
import java.nio.file.attribute.FileTime;
import java.security.AccessController;
import java.security.PrivilegedAction;
@@ -37,6 +39,9 @@ import java.util.concurrent.TimeUnit;
import static java.util.zip.ZipConstants.ENDHDR;
+import jdk.internal.misc.Unsafe;
+import sun.nio.ch.DirectBuffer;
+
class ZipUtils {
// used to adjust values between Windows and java epoch
@@ -45,6 +50,8 @@ class ZipUtils {
// used to indicate the corresponding windows time is not available
public static final long WINDOWS_TIME_NOT_AVAILABLE = Long.MIN_VALUE;
+ static final ByteBuffer defaultBuf = ByteBuffer.allocateDirect(0);
+
/**
* Converts Windows time (in microseconds, UTC/GMT) time to FileTime.
*/
@@ -281,4 +288,17 @@ class ZipUtils {
AccessController.doPrivileged(pa);
}
}
+
+ private static final Unsafe unsafe = Unsafe.getUnsafe();
+
+ private static final long byteBufferArrayOffset = unsafe.objectFieldOffset(ByteBuffer.class, "hb");
+ private static final long byteBufferOffsetOffset = unsafe.objectFieldOffset(ByteBuffer.class, "offset");
+
+ static byte[] getBufferArray(ByteBuffer byteBuffer) {
+ return (byte[]) unsafe.getObject(byteBuffer, byteBufferArrayOffset);
+ }
+
+ static int getBufferOffset(ByteBuffer byteBuffer) {
+ return unsafe.getInt(byteBuffer, byteBufferOffsetOffset);
+ }
}
diff --git a/src/java.base/share/native/libzip/Deflater.c b/src/java.base/share/native/libzip/Deflater.c
index b666a16145a..b56df5ecc1b 100644
--- a/src/java.base/share/native/libzip/Deflater.c
+++ b/src/java.base/share/native/libzip/Deflater.c
@@ -38,34 +38,6 @@
#define DEF_MEM_LEVEL 8
-static jfieldID levelID;
-static jfieldID strategyID;
-static jfieldID setParamsID;
-static jfieldID finishID;
-static jfieldID finishedID;
-static jfieldID bufID, offID, lenID;
-
-JNIEXPORT void JNICALL
-Java_java_util_zip_Deflater_initIDs(JNIEnv *env, jclass cls)
-{
- levelID = (*env)->GetFieldID(env, cls, "level", "I");
- CHECK_NULL(levelID);
- strategyID = (*env)->GetFieldID(env, cls, "strategy", "I");
- CHECK_NULL(strategyID);
- setParamsID = (*env)->GetFieldID(env, cls, "setParams", "Z");
- CHECK_NULL(setParamsID);
- finishID = (*env)->GetFieldID(env, cls, "finish", "Z");
- CHECK_NULL(finishID);
- finishedID = (*env)->GetFieldID(env, cls, "finished", "Z");
- CHECK_NULL(finishedID);
- bufID = (*env)->GetFieldID(env, cls, "buf", "[B");
- CHECK_NULL(bufID);
- offID = (*env)->GetFieldID(env, cls, "off", "I");
- CHECK_NULL(offID);
- lenID = (*env)->GetFieldID(env, cls, "len", "I");
- CHECK_NULL(lenID);
-}
-
JNIEXPORT jlong JNICALL
Java_java_util_zip_Deflater_init(JNIEnv *env, jclass cls, jint level,
jint strategy, jboolean nowrap)
@@ -104,17 +76,9 @@ Java_java_util_zip_Deflater_init(JNIEnv *env, jclass cls, jint level,
}
}
-JNIEXPORT void JNICALL
-Java_java_util_zip_Deflater_setDictionary(JNIEnv *env, jclass cls, jlong addr,
- jarray b, jint off, jint len)
+static void doSetDictionary(JNIEnv *env, jlong addr, jbyte *buf, jint len)
{
- Bytef *buf = (*env)->GetPrimitiveArrayCritical(env, b, 0);
- int res;
- if (buf == 0) {/* out of memory */
- return;
- }
- res = deflateSetDictionary((z_stream *)jlong_to_ptr(addr), buf + off, len);
- (*env)->ReleasePrimitiveArrayCritical(env, b, buf, 0);
+ int res = deflateSetDictionary(jlong_to_ptr(addr), (Bytef *) buf, len);
switch (res) {
case Z_OK:
break;
@@ -127,94 +91,169 @@ Java_java_util_zip_Deflater_setDictionary(JNIEnv *env, jclass cls, jlong addr,
}
}
-JNIEXPORT jint JNICALL
-Java_java_util_zip_Deflater_deflateBytes(JNIEnv *env, jobject this, jlong addr,
- jarray b, jint off, jint len, jint flush)
+JNIEXPORT void JNICALL
+Java_java_util_zip_Deflater_setDictionary(JNIEnv *env, jclass cls, jlong addr,
+ jbyteArray b, jint off, jint len)
+{
+ jbyte *buf = (*env)->GetPrimitiveArrayCritical(env, b, 0);
+ if (buf == NULL) /* out of memory */
+ return;
+ doSetDictionary(env, addr, buf + off, len);
+ (*env)->ReleasePrimitiveArrayCritical(env, b, buf, 0);
+}
+
+JNIEXPORT void JNICALL
+Java_java_util_zip_Deflater_setDictionaryBuffer(JNIEnv *env, jclass cls, jlong addr,
+ jlong bufferAddr, jint len)
+{
+ jbyte *buf = jlong_to_ptr(bufferAddr);
+ doSetDictionary(env, addr, buf, len);
+}
+
+static jlong doDeflate(JNIEnv *env, jobject this, jlong addr,
+ jbyte *input, jint inputLen,
+ jbyte *output, jint outputLen,
+ jint flush, jint params)
{
z_stream *strm = jlong_to_ptr(addr);
+ jint inputUsed = 0, outputUsed = 0;
- jarray this_buf = (*env)->GetObjectField(env, this, bufID);
- jint this_off = (*env)->GetIntField(env, this, offID);
- jint this_len = (*env)->GetIntField(env, this, lenID);
- jbyte *in_buf;
- jbyte *out_buf;
- int res;
- if ((*env)->GetBooleanField(env, this, setParamsID)) {
- int level = (*env)->GetIntField(env, this, levelID);
- int strategy = (*env)->GetIntField(env, this, strategyID);
- in_buf = (*env)->GetPrimitiveArrayCritical(env, this_buf, 0);
- if (in_buf == NULL) {
- // Throw OOME only when length is not zero
- if (this_len != 0 && (*env)->ExceptionOccurred(env) == NULL)
- JNU_ThrowOutOfMemoryError(env, 0);
- return 0;
- }
- out_buf = (*env)->GetPrimitiveArrayCritical(env, b, 0);
- if (out_buf == NULL) {
- (*env)->ReleasePrimitiveArrayCritical(env, this_buf, in_buf, 0);
- if (len != 0 && (*env)->ExceptionOccurred(env) == NULL)
- JNU_ThrowOutOfMemoryError(env, 0);
- return 0;
- }
+ strm->next_in = (Bytef *) input;
+ strm->next_out = (Bytef *) output;
+ strm->avail_in = inputLen;
+ strm->avail_out = outputLen;
+
+ int finished = 0;
+ int setParams = params & 1;
- strm->next_in = (Bytef *) (in_buf + this_off);
- strm->next_out = (Bytef *) (out_buf + off);
- strm->avail_in = this_len;
- strm->avail_out = len;
- res = deflateParams(strm, level, strategy);
- (*env)->ReleasePrimitiveArrayCritical(env, b, out_buf, 0);
- (*env)->ReleasePrimitiveArrayCritical(env, this_buf, in_buf, 0);
+ if (setParams) {
+ int strategy = (params >> 1) & 3;
+ int level = params >> 3;
+ int res = deflateParams(strm, level, strategy);
switch (res) {
case Z_OK:
- (*env)->SetBooleanField(env, this, setParamsID, JNI_FALSE);
+ setParams = 0;
+ /* fall through */
case Z_BUF_ERROR:
- this_off += this_len - strm->avail_in;
- (*env)->SetIntField(env, this, offID, this_off);
- (*env)->SetIntField(env, this, lenID, strm->avail_in);
- return (jint) (len - strm->avail_out);
+ inputUsed = inputLen - strm->avail_in;
+ outputUsed = outputLen - strm->avail_out;
+ break;
default:
JNU_ThrowInternalError(env, strm->msg);
return 0;
}
} else {
- jboolean finish = (*env)->GetBooleanField(env, this, finishID);
- in_buf = (*env)->GetPrimitiveArrayCritical(env, this_buf, 0);
- if (in_buf == NULL) {
- if (this_len != 0)
- JNU_ThrowOutOfMemoryError(env, 0);
- return 0;
- }
- out_buf = (*env)->GetPrimitiveArrayCritical(env, b, 0);
- if (out_buf == NULL) {
- (*env)->ReleasePrimitiveArrayCritical(env, this_buf, in_buf, 0);
- if (len != 0)
- JNU_ThrowOutOfMemoryError(env, 0);
-
- return 0;
- }
-
- strm->next_in = (Bytef *) (in_buf + this_off);
- strm->next_out = (Bytef *) (out_buf + off);
- strm->avail_in = this_len;
- strm->avail_out = len;
- res = deflate(strm, finish ? Z_FINISH : flush);
- (*env)->ReleasePrimitiveArrayCritical(env, b, out_buf, 0);
- (*env)->ReleasePrimitiveArrayCritical(env, this_buf, in_buf, 0);
+ int res = deflate(strm, flush);
switch (res) {
case Z_STREAM_END:
- (*env)->SetBooleanField(env, this, finishedID, JNI_TRUE);
+ finished = 1;
/* fall through */
case Z_OK:
case Z_BUF_ERROR:
- this_off += this_len - strm->avail_in;
- (*env)->SetIntField(env, this, offID, this_off);
- (*env)->SetIntField(env, this, lenID, strm->avail_in);
- return len - strm->avail_out;
+ inputUsed = inputLen - strm->avail_in;
+ outputUsed = outputLen - strm->avail_out;
+ break;
default:
JNU_ThrowInternalError(env, strm->msg);
return 0;
}
}
+ return ((jlong)inputUsed) | (((jlong)outputUsed) << 31) | (((jlong)finished) << 62) | (((jlong)setParams) << 63);
+}
+
+JNIEXPORT jlong JNICALL
+Java_java_util_zip_Deflater_deflateBytesBytes(JNIEnv *env, jobject this, jlong addr,
+ jbyteArray inputArray, jint inputOff, jint inputLen,
+ jbyteArray outputArray, jint outputOff, jint outputLen,
+ jint flush, jint params)
+{
+ jbyte *input = (*env)->GetPrimitiveArrayCritical(env, inputArray, 0);
+ if (input == NULL) {
+ if (inputLen != 0 && (*env)->ExceptionOccurred(env) == NULL)
+ JNU_ThrowOutOfMemoryError(env, 0);
+ return 0L;
+ }
+ jbyte *output = (*env)->GetPrimitiveArrayCritical(env, outputArray, 0);
+ if (output == NULL) {
+ (*env)->ReleasePrimitiveArrayCritical(env, inputArray, input, 0);
+ if (outputLen != 0 && (*env)->ExceptionOccurred(env) == NULL)
+ JNU_ThrowOutOfMemoryError(env, 0);
+ return 0L;
+ }
+
+ jlong retVal = doDeflate(env, this, addr,
+ input + inputOff, inputLen,
+ output + outputOff, outputLen,
+ flush, params);
+
+ (*env)->ReleasePrimitiveArrayCritical(env, outputArray, output, 0);
+ (*env)->ReleasePrimitiveArrayCritical(env, inputArray, input, 0);
+
+ return retVal;
+}
+
+
+JNIEXPORT jlong JNICALL
+Java_java_util_zip_Deflater_deflateBytesBuffer(JNIEnv *env, jobject this, jlong addr,
+ jbyteArray inputArray, jint inputOff, jint inputLen,
+ jlong outputBuffer, jint outputLen,
+ jint flush, jint params)
+{
+ jbyte *input = (*env)->GetPrimitiveArrayCritical(env, inputArray, 0);
+ if (input == NULL) {
+ if (inputLen != 0 && (*env)->ExceptionOccurred(env) == NULL)
+ JNU_ThrowOutOfMemoryError(env, 0);
+ return 0L;
+ }
+ jbyte *output = jlong_to_ptr(outputBuffer);
+
+ jlong retVal = doDeflate(env, this, addr,
+ input + inputOff, inputLen,
+ output, outputLen,
+ flush, params);
+
+ (*env)->ReleasePrimitiveArrayCritical(env, inputArray, input, 0);
+
+ return retVal;
+}
+
+JNIEXPORT jlong JNICALL
+Java_java_util_zip_Deflater_deflateBufferBytes(JNIEnv *env, jobject this, jlong addr,
+ jlong inputBuffer, jint inputLen,
+ jbyteArray outputArray, jint outputOff, jint outputLen,
+ jint flush, jint params)
+{
+ jbyte *input = jlong_to_ptr(inputBuffer);
+ jbyte *output = (*env)->GetPrimitiveArrayCritical(env, outputArray, 0);
+ if (output == NULL) {
+ if (outputLen != 0 && (*env)->ExceptionOccurred(env) == NULL)
+ JNU_ThrowOutOfMemoryError(env, 0);
+ return 0L;
+ }
+
+ jlong retVal = doDeflate(env, this, addr,
+ input, inputLen,
+ output + outputOff, outputLen,
+ flush, params);
+
+ (*env)->ReleasePrimitiveArrayCritical(env, outputArray, input, 0);
+
+ return retVal;
+}
+
+JNIEXPORT jlong JNICALL
+Java_java_util_zip_Deflater_deflateBufferBuffer(JNIEnv *env, jobject this, jlong addr,
+ jlong inputBuffer, jint inputLen,
+ jlong outputBuffer, jint outputLen,
+ jint flush, jint params)
+{
+ jbyte *input = jlong_to_ptr(inputBuffer);
+ jbyte *output = jlong_to_ptr(outputBuffer);
+
+ return doDeflate(env, this, addr,
+ input, inputLen,
+ output, outputLen,
+ flush, params);
}
JNIEXPORT jint JNICALL
diff --git a/src/java.base/share/native/libzip/Inflater.c b/src/java.base/share/native/libzip/Inflater.c
index 2e21d084b39..4999b5467a0 100644
--- a/src/java.base/share/native/libzip/Inflater.c
+++ b/src/java.base/share/native/libzip/Inflater.c
@@ -42,23 +42,13 @@
#define ThrowDataFormatException(env, msg) \
JNU_ThrowByName(env, "java/util/zip/DataFormatException", msg)
-static jfieldID needDictID;
-static jfieldID finishedID;
-static jfieldID bufID, offID, lenID;
+static jfieldID inputConsumedID;
JNIEXPORT void JNICALL
Java_java_util_zip_Inflater_initIDs(JNIEnv *env, jclass cls)
{
- needDictID = (*env)->GetFieldID(env, cls, "needDict", "Z");
- CHECK_NULL(needDictID);
- finishedID = (*env)->GetFieldID(env, cls, "finished", "Z");
- CHECK_NULL(finishedID);
- bufID = (*env)->GetFieldID(env, cls, "buf", "[B");
- CHECK_NULL(bufID);
- offID = (*env)->GetFieldID(env, cls, "off", "I");
- CHECK_NULL(offID);
- lenID = (*env)->GetFieldID(env, cls, "len", "I");
- CHECK_NULL(lenID);
+ inputConsumedID = (*env)->GetFieldID(env, cls, "inputConsumed", "I");
+ CHECK_NULL(inputConsumedID);
}
JNIEXPORT jlong JNICALL
@@ -94,16 +84,9 @@ Java_java_util_zip_Inflater_init(JNIEnv *env, jclass cls, jboolean nowrap)
}
}
-JNIEXPORT void JNICALL
-Java_java_util_zip_Inflater_setDictionary(JNIEnv *env, jclass cls, jlong addr,
- jarray b, jint off, jint len)
+static void doSetDictionary(JNIEnv *env, jlong addr, jbyte *buf, jint len)
{
- Bytef *buf = (*env)->GetPrimitiveArrayCritical(env, b, 0);
- int res;
- if (buf == 0) /* out of memory */
- return;
- res = inflateSetDictionary(jlong_to_ptr(addr), buf + off, len);
- (*env)->ReleasePrimitiveArrayCritical(env, b, buf, 0);
+ int res = inflateSetDictionary(jlong_to_ptr(addr), (Bytef *) buf, len);
switch (res) {
case Z_OK:
break;
@@ -117,68 +100,155 @@ Java_java_util_zip_Inflater_setDictionary(JNIEnv *env, jclass cls, jlong addr,
}
}
-JNIEXPORT jint JNICALL
-Java_java_util_zip_Inflater_inflateBytes(JNIEnv *env, jobject this, jlong addr,
- jarray b, jint off, jint len)
+JNIEXPORT void JNICALL
+Java_java_util_zip_Inflater_setDictionary(JNIEnv *env, jclass cls, jlong addr,
+ jbyteArray b, jint off, jint len)
+{
+ jbyte *buf = (*env)->GetPrimitiveArrayCritical(env, b, 0);
+ if (buf == NULL) /* out of memory */
+ return;
+ doSetDictionary(env, addr, buf + off, len);
+ (*env)->ReleasePrimitiveArrayCritical(env, b, buf, 0);
+}
+
+JNIEXPORT void JNICALL
+Java_java_util_zip_Inflater_setDictionaryBuffer(JNIEnv *env, jclass cls, jlong addr,
+ jlong bufferAddr, jint len)
+{
+ jbyte *buf = jlong_to_ptr(bufferAddr);
+ doSetDictionary(env, addr, buf, len);
+}
+
+static jlong doInflate(JNIEnv *env, jobject this, jlong addr,
+ jbyte *input, jint inputLen,
+ jbyte *output, jint outputLen)
{
z_stream *strm = jlong_to_ptr(addr);
- jarray this_buf = (jarray)(*env)->GetObjectField(env, this, bufID);
- jint this_off = (*env)->GetIntField(env, this, offID);
- jint this_len = (*env)->GetIntField(env, this, lenID);
+ jint inputUsed = 0, outputUsed = 0;
- jbyte *in_buf;
- jbyte *out_buf;
- int ret;
+ strm->next_in = (Bytef *) input;
+ strm->next_out = (Bytef *) output;
+ strm->avail_in = inputLen;
+ strm->avail_out = outputLen;
- in_buf = (*env)->GetPrimitiveArrayCritical(env, this_buf, 0);
- if (in_buf == NULL) {
- if (this_len != 0 && (*env)->ExceptionOccurred(env) == NULL)
- JNU_ThrowOutOfMemoryError(env, 0);
- return 0;
- }
- out_buf = (*env)->GetPrimitiveArrayCritical(env, b, 0);
- if (out_buf == NULL) {
- (*env)->ReleasePrimitiveArrayCritical(env, this_buf, in_buf, 0);
- if (len != 0 && (*env)->ExceptionOccurred(env) == NULL)
- JNU_ThrowOutOfMemoryError(env, 0);
- return 0;
- }
- strm->next_in = (Bytef *) (in_buf + this_off);
- strm->next_out = (Bytef *) (out_buf + off);
- strm->avail_in = this_len;
- strm->avail_out = len;
- ret = inflate(strm, Z_PARTIAL_FLUSH);
- (*env)->ReleasePrimitiveArrayCritical(env, b, out_buf, 0);
- (*env)->ReleasePrimitiveArrayCritical(env, this_buf, in_buf, 0);
+ int ret = inflate(strm, Z_PARTIAL_FLUSH);
+ int finished = 0;
+ int needDict = 0;
switch (ret) {
case Z_STREAM_END:
- (*env)->SetBooleanField(env, this, finishedID, JNI_TRUE);
+ finished = 1;
/* fall through */
case Z_OK:
- this_off += this_len - strm->avail_in;
- (*env)->SetIntField(env, this, offID, this_off);
- (*env)->SetIntField(env, this, lenID, strm->avail_in);
- return (jint) (len - strm->avail_out);
+ inputUsed = inputLen - strm->avail_in;
+ outputUsed = outputLen - strm->avail_out;
+ break;
case Z_NEED_DICT:
- (*env)->SetBooleanField(env, this, needDictID, JNI_TRUE);
+ needDict = 1;
/* Might have consumed some input here! */
- this_off += this_len - strm->avail_in;
- (*env)->SetIntField(env, this, offID, this_off);
- (*env)->SetIntField(env, this, lenID, strm->avail_in);
- return 0;
+ inputUsed = inputLen - strm->avail_in;
+ break;
case Z_BUF_ERROR:
- return 0;
+ break;
case Z_DATA_ERROR:
+ inputUsed = inputLen - strm->avail_in;
+ (*env)->SetIntField(env, this, inputConsumedID, inputUsed);
ThrowDataFormatException(env, strm->msg);
- return 0;
+ break;
case Z_MEM_ERROR:
JNU_ThrowOutOfMemoryError(env, 0);
- return 0;
+ break;
default:
JNU_ThrowInternalError(env, strm->msg);
- return 0;
+ break;
+ }
+ return ((jlong)inputUsed) | (((jlong)outputUsed) << 31) | (((jlong)finished) << 62) | (((jlong)needDict) << 63);
+}
+
+JNIEXPORT jlong JNICALL
+Java_java_util_zip_Inflater_inflateBytesBytes(JNIEnv *env, jobject this, jlong addr,
+ jbyteArray inputArray, jint inputOff, jint inputLen,
+ jbyteArray outputArray, jint outputOff, jint outputLen)
+{
+ jbyte *input = (*env)->GetPrimitiveArrayCritical(env, inputArray, 0);
+ if (input == NULL) {
+ if (inputLen != 0 && (*env)->ExceptionOccurred(env) == NULL)
+ JNU_ThrowOutOfMemoryError(env, 0);
+ return 0L;
+ }
+ jbyte *output = (*env)->GetPrimitiveArrayCritical(env, outputArray, 0);
+ if (output == NULL) {
+ (*env)->ReleasePrimitiveArrayCritical(env, inputArray, input, 0);
+ if (outputLen != 0 && (*env)->ExceptionOccurred(env) == NULL)
+ JNU_ThrowOutOfMemoryError(env, 0);
+ return 0L;
+ }
+
+ jlong retVal = doInflate(env, this, addr,
+ input + inputOff, inputLen,
+ output + outputOff, outputLen);
+
+ (*env)->ReleasePrimitiveArrayCritical(env, outputArray, output, 0);
+ (*env)->ReleasePrimitiveArrayCritical(env, inputArray, input, 0);
+
+ return retVal;
+}
+
+JNIEXPORT jlong JNICALL
+Java_java_util_zip_Inflater_inflateBytesBuffer(JNIEnv *env, jobject this, jlong addr,
+ jbyteArray inputArray, jint inputOff, jint inputLen,
+ jlong outputBuffer, jint outputLen)
+{
+ jbyte *input = (*env)->GetPrimitiveArrayCritical(env, inputArray, 0);
+ if (input == NULL) {
+ if (inputLen != 0 && (*env)->ExceptionOccurred(env) == NULL)
+ JNU_ThrowOutOfMemoryError(env, 0);
+ return 0L;
+ }
+ jbyte *output = jlong_to_ptr(outputBuffer);
+
+ jlong retVal = doInflate(env, this, addr,
+ input + inputOff, inputLen,
+ output, outputLen);
+
+ (*env)->ReleasePrimitiveArrayCritical(env, inputArray, input, 0);
+
+ return retVal;
+}
+
+JNIEXPORT jlong JNICALL
+Java_java_util_zip_Inflater_inflateBufferBytes(JNIEnv *env, jobject this, jlong addr,
+ jlong inputBuffer, jint inputLen,
+ jbyteArray outputArray, jint outputOff, jint outputLen)
+{
+ jbyte *input = jlong_to_ptr(inputBuffer);
+ jbyte *output = (*env)->GetPrimitiveArrayCritical(env, outputArray, 0);
+ if (output == NULL) {
+ if (outputLen != 0 && (*env)->ExceptionOccurred(env) == NULL)
+ JNU_ThrowOutOfMemoryError(env, 0);
+ return 0L;
}
+
+ jlong retVal = doInflate(env, this, addr,
+ input, inputLen,
+ output + outputOff, outputLen);
+
+ (*env)->ReleasePrimitiveArrayCritical(env, outputArray, input, 0);
+
+ return retVal;
+}
+
+JNIEXPORT jlong JNICALL
+Java_java_util_zip_Inflater_inflateBufferBuffer(JNIEnv *env, jobject this, jlong addr,
+ jlong inputBuffer, jint inputLen,
+ jlong outputBuffer, jint outputLen)
+{
+ jbyte *input = jlong_to_ptr(inputBuffer);
+ jbyte *output = jlong_to_ptr(outputBuffer);
+
+ return doInflate(env, this, addr,
+ input, inputLen,
+ output, outputLen);
}
JNIEXPORT jint JNICALL
diff --git a/test/jdk/java/util/zip/FlaterTest.java b/test/jdk/java/util/zip/FlaterTest.java
index 7245440d033..b5aff0319b3 100644
--- a/test/jdk/java/util/zip/FlaterTest.java
+++ b/test/jdk/java/util/zip/FlaterTest.java
@@ -29,7 +29,6 @@
* @key randomness
*/
-import java.io.*;
import java.nio.*;
import java.util.*;
import java.util.zip.*;
@@ -41,35 +40,37 @@ import java.util.zip.*;
*/
public class FlaterTest extends Thread {
private static final int DATA_LEN = 1024 * 128;
- private static byte[] data;
+
+ private static ByteBuffer dataDirect;
+ private static ByteBuffer dataHeap;
// If true, print extra info.
private static final boolean debug = false;
// Set of Flater threads running.
- private static Set flaters =
- Collections.synchronizedSet(new HashSet());
+ private static Set<Flater> flaters =
+ Collections.synchronizedSet(new HashSet<>());
/** Fill in {@code data} with random values. */
static void createData() {
- ByteBuffer bb = ByteBuffer.allocate(8);
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- for (int i = 0; i < DATA_LEN; i++) {
- bb.putDouble(0, Math.random());
- baos.write(bb.array(), 0, 8);
+ ByteBuffer bb = ByteBuffer.allocateDirect(DATA_LEN * 8);
+ for (int i = 0; i < DATA_LEN * 8; i += 8) {
+ bb.putDouble(i, Math.random());
}
- data = baos.toByteArray();
- if (debug) System.out.println("data length is " + data.length);
+ dataDirect = bb;
+ final ByteBuffer hb = ByteBuffer.allocate(bb.capacity());
+ hb.duplicate().put(bb.duplicate());
+ dataHeap = hb;
+ if (debug) System.out.println("data length is " + bb.capacity());
}
/** @return the length of the deflated {@code data}. */
- private static int getDeflatedLength() throws Throwable {
- int rc = 0;
+ private static int getDeflatedLength() {
Deflater deflater = new Deflater();
- deflater.setInput(data);
+ deflater.setInput(dataDirect.duplicate());
deflater.finish();
- byte[] out = new byte[data.length];
- rc = deflater.deflate(out);
+ byte[] out = new byte[dataDirect.capacity()];
+ int rc = deflater.deflate(out);
deflater.end();
if (debug) System.out.println("deflatedLength is " + rc);
return rc;
@@ -78,70 +79,98 @@ public class FlaterTest extends Thread {
/** Compares given bytes with those in {@code data}.
* @throws Exception if given bytes don't match {@code data}.
*/
- private static void validate(byte[] buf, int offset, int len) throws Exception {
+ private static void validate(ByteBuffer buf, int offset, int len) throws Exception {
for (int i = 0; i < len; i++ ) {
- if (buf[i] != data[offset+i]) {
+ if (buf.get(i) != dataDirect.get(offset+i)) {
throw new Exception("mismatch at " + (offset + i));
}
}
}
- public static void realMain(String[] args) throws Throwable {
- createData();
+ public static void realMain(String[] args) {
int numThreads = args.length > 0 ? Integer.parseInt(args[0]) : 5;
- new FlaterTest().go(numThreads);
+ createData();
+ for (int srcMode = 0; srcMode <= 2; srcMode ++) {
+ for (int dstMode = 0; dstMode <= 2; dstMode ++) {
+ new FlaterTest().go(numThreads, srcMode, dstMode);
+ }
+ }
}
- private synchronized void go(int numThreads) throws Throwable {
+ private synchronized void go(int numThreads, int srcMode, int dstMode) {
int deflatedLength = getDeflatedLength();
long time = System.currentTimeMillis();
for (int i = 0; i < numThreads; i++) {
- Flater f = new Flater(deflatedLength);
+ Flater f = new Flater(deflatedLength, srcMode, dstMode);
flaters.add(f);
f.start();
}
- while (flaters.size() != 0) {
- try {
- Thread.currentThread().sleep(10);
- } catch (InterruptedException ex) {
- unexpected(ex);
+ synchronized (flaters) {
+ while (flaters.size() != 0) {
+ try {
+ flaters.wait();
+ } catch (InterruptedException ex) {
+ unexpected(ex);
+ }
}
}
time = System.currentTimeMillis() - time;
System.out.println("Time needed for " + numThreads
- + " threads to deflate/inflate: " + time + " ms.");
+ + " threads to deflate/inflate: " + time + " ms (srcMode="+srcMode+",dstMode="+dstMode+")");
}
/** Deflates and inflates data. */
static class Flater extends Thread {
private final int deflatedLength;
+ private final int srcMode, dstMode;
- private Flater(int length) {
+ private Flater(int length, int srcMode, int dstMode) {
this.deflatedLength = length;
+ this.srcMode = srcMode;
+ this.dstMode = dstMode;
}
/** Deflates and inflates {@code data}. */
public void run() {
if (debug) System.out.println(getName() + " starting run()");
try {
- byte[] deflated = DeflateData(deflatedLength);
+ ByteBuffer deflated = DeflateData(deflatedLength);
InflateData(deflated);
} catch (Throwable t) {
t.printStackTrace();
fail(getName() + " failed");
} finally {
- flaters.remove(this);
+ synchronized (flaters) {
+ flaters.remove(this);
+ if (flaters.isEmpty()) {
+ flaters.notifyAll();
+ }
+ }
}
}
/** Returns a copy of {@code data} in deflated form. */
- private byte[] DeflateData(int length) throws Throwable {
+ private ByteBuffer DeflateData(int length) {
Deflater deflater = new Deflater();
- deflater.setInput(data);
+ if (srcMode == 0) {
+ deflater.setInput(dataHeap.array());
+ } else if (srcMode == 1) {
+ deflater.setInput(dataHeap.duplicate());
+ } else {
+ assert srcMode == 2;
+ deflater.setInput(dataDirect.duplicate());
+ }
deflater.finish();
- byte[] out = new byte[length];
- deflater.deflate(out);
+ ByteBuffer out = dstMode == 2 ? ByteBuffer.allocateDirect(length) : ByteBuffer.allocate(length);
+ int deflated;
+ if (dstMode == 0) {
+ deflated = deflater.deflate(out.array(), 0, length);
+ out.position(deflated);
+ } else {
+ deflater.deflate(out);
+ }
+ out.flip();
return out;
}
@@ -149,14 +178,30 @@ public class FlaterTest extends Thread {
* inflation.
* @throws Exception if inflated bytes don't match {@code data}.
*/
- private void InflateData(byte[] bytes) throws Throwable {
+ private void InflateData(ByteBuffer bytes) throws Throwable {
Inflater inflater = new Inflater();
- inflater.setInput(bytes, 0, bytes.length);
+ if (dstMode == 0) {
+ inflater.setInput(bytes.array(), 0, bytes.remaining());
+ } else {
+ inflater.setInput(bytes);
+ }
+ if (inflater.getRemaining() == 0) {
+ throw new Exception("Nothing to inflate (bytes=" + bytes + ")");
+ }
int len = 1024 * 8;
int offset = 0;
+ ByteBuffer buf = srcMode == 2 ? ByteBuffer.allocateDirect(len) : ByteBuffer.allocate(len);
while (inflater.getRemaining() > 0) {
- byte[] buf = new byte[len];
- int inflated = inflater.inflate(buf, 0, len);
+ buf.clear();
+ int inflated;
+ if (srcMode == 0) {
+ inflated = inflater.inflate(buf.array(), 0, buf.remaining());
+ } else {
+ inflated = inflater.inflate(buf);
+ }
+ if (inflated == 0) {
+ throw new Exception("Nothing inflated (dst=" + buf + ",offset=" + offset + ",rem=" + inflater.getRemaining() + ",srcMode="+srcMode+",dstMode="+dstMode+")");
+ }
validate(buf, offset, inflated);
offset += inflated;
}
-------------- next part --------------
# Run complete. Total time: 00:01:14
Benchmark (opSize) Mode Cnt Score Error Units
InflateTests.testAIAO 16 sample 297564 997.985 ± 1.602 ns/op
InflateTests.testAIAO:testAIAO·p0.00 16 sample 383.000 ns/op
InflateTests.testAIAO:testAIAO·p0.50 16 sample 978.000 ns/op
InflateTests.testAIAO:testAIAO·p0.90 16 sample 1190.000 ns/op
InflateTests.testAIAO:testAIAO·p0.95 16 sample 1262.000 ns/op
InflateTests.testAIAO:testAIAO·p0.99 16 sample 1626.000 ns/op
InflateTests.testAIAO:testAIAO·p0.999 16 sample 3828.000 ns/op
InflateTests.testAIAO:testAIAO·p0.9999 16 sample 6729.948 ns/op
InflateTests.testAIAO:testAIAO·p1.00 16 sample 29760.000 ns/op
InflateTests.testAIAO 128 sample 286720 4274.280 ± 12.714 ns/op
InflateTests.testAIAO:testAIAO·p0.00 128 sample 3280.000 ns/op
InflateTests.testAIAO:testAIAO·p0.50 128 sample 4224.000 ns/op
InflateTests.testAIAO:testAIAO·p0.90 128 sample 4600.000 ns/op
InflateTests.testAIAO:testAIAO·p0.95 128 sample 4728.000 ns/op
InflateTests.testAIAO:testAIAO·p0.99 128 sample 6176.000 ns/op
InflateTests.testAIAO:testAIAO·p0.999 128 sample 8656.000 ns/op
InflateTests.testAIAO:testAIAO·p0.9999 128 sample 16746.493 ns/op
InflateTests.testAIAO:testAIAO·p1.00 128 sample 1075200.000 ns/op
InflateTests.testAIAO 1024 sample 160496 30884.232 ± 14.240 ns/op
InflateTests.testAIAO:testAIAO·p0.00 1024 sample 28160.000 ns/op
InflateTests.testAIAO:testAIAO·p0.50 1024 sample 30656.000 ns/op
InflateTests.testAIAO:testAIAO·p0.90 1024 sample 31680.000 ns/op
InflateTests.testAIAO:testAIAO·p0.95 1024 sample 32512.000 ns/op
InflateTests.testAIAO:testAIAO·p0.99 1024 sample 39936.000 ns/op
InflateTests.testAIAO:testAIAO·p0.999 1024 sample 48320.000 ns/op
InflateTests.testAIAO:testAIAO·p0.9999 1024 sample 54646.458 ns/op
InflateTests.testAIAO:testAIAO·p1.00 1024 sample 94208.000 ns/op
-------------- next part --------------
# Run complete. Total time: 00:09:20
Benchmark (opSize) Mode Cnt Score Error Units
InflateTests.testAIAO 16 sample 317476 931.285 ± 1.366 ns/op
InflateTests.testAIAO:testAIAO·p0.00 16 sample 322.000 ns/op
InflateTests.testAIAO:testAIAO·p0.50 16 sample 914.000 ns/op
InflateTests.testAIAO:testAIAO·p0.90 16 sample 1124.000 ns/op
InflateTests.testAIAO:testAIAO·p0.95 16 sample 1190.000 ns/op
InflateTests.testAIAO:testAIAO·p0.99 16 sample 1462.000 ns/op
InflateTests.testAIAO:testAIAO·p0.999 16 sample 3666.092 ns/op
InflateTests.testAIAO:testAIAO·p0.9999 16 sample 5920.368 ns/op
InflateTests.testAIAO:testAIAO·p1.00 16 sample 17248.000 ns/op
InflateTests.testAIAO 128 sample 291550 4198.369 ± 2.803 ns/op
InflateTests.testAIAO:testAIAO·p0.00 128 sample 3200.000 ns/op
InflateTests.testAIAO:testAIAO·p0.50 128 sample 4152.000 ns/op
InflateTests.testAIAO:testAIAO·p0.90 128 sample 4520.000 ns/op
InflateTests.testAIAO:testAIAO·p0.95 128 sample 4664.000 ns/op
InflateTests.testAIAO:testAIAO·p0.99 128 sample 6232.000 ns/op
InflateTests.testAIAO:testAIAO·p0.999 128 sample 8128.000 ns/op
InflateTests.testAIAO:testAIAO·p0.9999 128 sample 11853.518 ns/op
InflateTests.testAIAO:testAIAO·p1.00 128 sample 46208.000 ns/op
InflateTests.testAIAO 1024 sample 161199 30768.958 ± 12.730 ns/op
InflateTests.testAIAO:testAIAO·p0.00 1024 sample 28032.000 ns/op
InflateTests.testAIAO:testAIAO·p0.50 1024 sample 30560.000 ns/op
InflateTests.testAIAO:testAIAO·p0.90 1024 sample 31616.000 ns/op
InflateTests.testAIAO:testAIAO·p0.95 1024 sample 32448.000 ns/op
InflateTests.testAIAO:testAIAO·p0.99 1024 sample 37120.000 ns/op
InflateTests.testAIAO:testAIAO·p0.999 1024 sample 47667.200 ns/op
InflateTests.testAIAO:testAIAO·p0.9999 1024 sample 56488.960 ns/op
InflateTests.testAIAO:testAIAO·p1.00 1024 sample 90624.000 ns/op
InflateTests.testAIDO 16 sample 327750 904.254 ± 1.392 ns/op
InflateTests.testAIDO:testAIDO·p0.00 16 sample 274.000 ns/op
InflateTests.testAIDO:testAIDO·p0.50 16 sample 885.000 ns/op
InflateTests.testAIDO:testAIDO·p0.90 16 sample 1098.000 ns/op
InflateTests.testAIDO:testAIDO·p0.95 16 sample 1168.000 ns/op
InflateTests.testAIDO:testAIDO·p0.99 16 sample 1508.000 ns/op
InflateTests.testAIDO:testAIDO·p0.999 16 sample 3728.000 ns/op
InflateTests.testAIDO:testAIDO·p0.9999 16 sample 6113.799 ns/op
InflateTests.testAIDO:testAIDO·p1.00 16 sample 9904.000 ns/op
InflateTests.testAIDO 128 sample 292247 4189.979 ± 8.170 ns/op
InflateTests.testAIDO:testAIDO·p0.00 128 sample 3168.000 ns/op
InflateTests.testAIDO:testAIDO·p0.50 128 sample 4128.000 ns/op
InflateTests.testAIDO:testAIDO·p0.90 128 sample 4536.000 ns/op
InflateTests.testAIDO:testAIDO·p0.95 128 sample 4688.000 ns/op
InflateTests.testAIDO:testAIDO·p0.99 128 sample 6512.000 ns/op
InflateTests.testAIDO:testAIDO·p0.999 128 sample 8432.000 ns/op
InflateTests.testAIDO:testAIDO·p0.9999 128 sample 12944.000 ns/op
InflateTests.testAIDO:testAIDO·p1.00 128 sample 674816.000 ns/op
InflateTests.testAIDO 1024 sample 158182 31271.382 ± 28.774 ns/op
InflateTests.testAIDO:testAIDO·p0.00 1024 sample 28160.000 ns/op
InflateTests.testAIDO:testAIDO·p0.50 1024 sample 30944.000 ns/op
InflateTests.testAIDO:testAIDO·p0.90 1024 sample 32384.000 ns/op
InflateTests.testAIDO:testAIDO·p0.95 1024 sample 33408.000 ns/op
InflateTests.testAIDO:testAIDO·p0.99 1024 sample 41600.000 ns/op
InflateTests.testAIDO:testAIDO·p0.999 1024 sample 50368.000 ns/op
InflateTests.testAIDO:testAIDO·p0.9999 1024 sample 58740.205 ns/op
InflateTests.testAIDO:testAIDO·p1.00 1024 sample 786432.000 ns/op
InflateTests.testAIHO 16 sample 319679 922.777 ± 1.386 ns/op
InflateTests.testAIHO:testAIHO·p0.00 16 sample 314.000 ns/op
InflateTests.testAIHO:testAIHO·p0.50 16 sample 905.000 ns/op
InflateTests.testAIHO:testAIHO·p0.90 16 sample 1114.000 ns/op
InflateTests.testAIHO:testAIHO·p0.95 16 sample 1180.000 ns/op
InflateTests.testAIHO:testAIHO·p0.99 16 sample 1492.000 ns/op
InflateTests.testAIHO:testAIHO·p0.999 16 sample 3713.280 ns/op
InflateTests.testAIHO:testAIHO·p0.9999 16 sample 5747.328 ns/op
InflateTests.testAIHO:testAIHO·p1.00 16 sample 22304.000 ns/op
InflateTests.testAIHO 128 sample 288260 4244.463 ± 3.200 ns/op
InflateTests.testAIHO:testAIHO·p0.00 128 sample 3220.000 ns/op
InflateTests.testAIHO:testAIHO·p0.50 128 sample 4184.000 ns/op
InflateTests.testAIHO:testAIHO·p0.90 128 sample 4600.000 ns/op
InflateTests.testAIHO:testAIHO·p0.95 128 sample 4768.000 ns/op
InflateTests.testAIHO:testAIHO·p0.99 128 sample 6576.000 ns/op
InflateTests.testAIHO:testAIHO·p0.999 128 sample 8544.000 ns/op
InflateTests.testAIHO:testAIHO·p0.9999 128 sample 12267.819 ns/op
InflateTests.testAIHO:testAIHO·p1.00 128 sample 48128.000 ns/op
InflateTests.testAIHO 1024 sample 158861 31168.797 ± 24.568 ns/op
InflateTests.testAIHO:testAIHO·p0.00 1024 sample 28160.000 ns/op
InflateTests.testAIHO:testAIHO·p0.50 1024 sample 30880.000 ns/op
InflateTests.testAIHO:testAIHO·p0.90 1024 sample 32128.000 ns/op
InflateTests.testAIHO:testAIHO·p0.95 1024 sample 33088.000 ns/op
InflateTests.testAIHO:testAIHO·p0.99 1024 sample 40832.000 ns/op
InflateTests.testAIHO:testAIHO·p0.999 1024 sample 51712.000 ns/op
InflateTests.testAIHO:testAIHO·p0.9999 1024 sample 61326.566 ns/op
InflateTests.testAIHO:testAIHO·p1.00 1024 sample 873472.000 ns/op
InflateTests.testDIAO 16 sample 333837 879.467 ± 1.301 ns/op
InflateTests.testDIAO:testDIAO·p0.00 16 sample 260.000 ns/op
InflateTests.testDIAO:testDIAO·p0.50 16 sample 863.000 ns/op
InflateTests.testDIAO:testDIAO·p0.90 16 sample 1070.000 ns/op
InflateTests.testDIAO:testDIAO·p0.95 16 sample 1136.000 ns/op
InflateTests.testDIAO:testDIAO·p0.99 16 sample 1402.000 ns/op
InflateTests.testDIAO:testDIAO·p0.999 16 sample 3596.648 ns/op
InflateTests.testDIAO:testDIAO·p0.9999 16 sample 5737.859 ns/op
InflateTests.testDIAO:testDIAO·p1.00 16 sample 15312.000 ns/op
InflateTests.testDIAO 128 sample 293782 4160.117 ± 2.942 ns/op
InflateTests.testDIAO:testDIAO·p0.00 128 sample 3164.000 ns/op
InflateTests.testDIAO:testDIAO·p0.50 128 sample 4104.000 ns/op
InflateTests.testDIAO:testDIAO·p0.90 128 sample 4488.000 ns/op
InflateTests.testDIAO:testDIAO·p0.95 128 sample 4640.000 ns/op
InflateTests.testDIAO:testDIAO·p0.99 128 sample 6192.000 ns/op
InflateTests.testDIAO:testDIAO·p0.999 128 sample 8145.736 ns/op
InflateTests.testDIAO:testDIAO·p0.9999 128 sample 12701.842 ns/op
InflateTests.testDIAO:testDIAO·p1.00 128 sample 46912.000 ns/op
InflateTests.testDIAO 1024 sample 160960 30808.034 ± 23.151 ns/op
InflateTests.testDIAO:testDIAO·p0.00 1024 sample 28032.000 ns/op
InflateTests.testDIAO:testDIAO·p0.50 1024 sample 30496.000 ns/op
InflateTests.testDIAO:testDIAO·p0.90 1024 sample 31584.000 ns/op
InflateTests.testDIAO:testDIAO·p0.95 1024 sample 32480.000 ns/op
InflateTests.testDIAO:testDIAO·p0.99 1024 sample 41664.000 ns/op
InflateTests.testDIAO:testDIAO·p0.999 1024 sample 48066.496 ns/op
InflateTests.testDIAO:testDIAO·p0.9999 1024 sample 56243.699 ns/op
InflateTests.testDIAO:testDIAO·p1.00 1024 sample 849920.000 ns/op
InflateTests.testDIDO 16 sample 347580 849.776 ± 1.366 ns/op
InflateTests.testDIDO:testDIDO·p0.00 16 sample 234.000 ns/op
InflateTests.testDIDO:testDIDO·p0.50 16 sample 831.000 ns/op
InflateTests.testDIDO:testDIDO·p0.90 16 sample 1044.000 ns/op
InflateTests.testDIDO:testDIDO·p0.95 16 sample 1114.000 ns/op
InflateTests.testDIDO:testDIDO·p0.99 16 sample 1460.000 ns/op
InflateTests.testDIDO:testDIDO·p0.999 16 sample 3640.000 ns/op
InflateTests.testDIDO:testDIDO·p0.9999 16 sample 6131.870 ns/op
InflateTests.testDIDO:testDIDO·p1.00 16 sample 13696.000 ns/op
InflateTests.testDIDO 128 sample 295207 4152.105 ± 3.356 ns/op
InflateTests.testDIDO:testDIDO·p0.00 128 sample 3136.000 ns/op
InflateTests.testDIDO:testDIDO·p0.50 128 sample 4096.000 ns/op
InflateTests.testDIDO:testDIDO·p0.90 128 sample 4496.000 ns/op
InflateTests.testDIDO:testDIDO·p0.95 128 sample 4656.000 ns/op
InflateTests.testDIDO:testDIDO·p0.99 128 sample 6432.000 ns/op
InflateTests.testDIDO:testDIDO·p0.999 128 sample 8672.000 ns/op
InflateTests.testDIDO:testDIDO·p0.9999 128 sample 13757.338 ns/op
InflateTests.testDIDO:testDIDO·p1.00 128 sample 70016.000 ns/op
InflateTests.testDIDO 1024 sample 158555 31216.219 ± 17.789 ns/op
InflateTests.testDIDO:testDIDO·p0.00 1024 sample 28160.000 ns/op
InflateTests.testDIDO:testDIDO·p0.50 1024 sample 30880.000 ns/op
InflateTests.testDIDO:testDIDO·p0.90 1024 sample 32384.000 ns/op
InflateTests.testDIDO:testDIDO·p0.95 1024 sample 33216.000 ns/op
InflateTests.testDIDO:testDIDO·p0.99 1024 sample 42624.000 ns/op
InflateTests.testDIDO:testDIDO·p0.999 1024 sample 50624.000 ns/op
InflateTests.testDIDO:testDIDO·p0.9999 1024 sample 57527.450 ns/op
InflateTests.testDIDO:testDIDO·p1.00 1024 sample 355840.000 ns/op
InflateTests.testDIHO 16 sample 332135 890.586 ± 1.392 ns/op
InflateTests.testDIHO:testDIHO·p0.00 16 sample 278.000 ns/op
InflateTests.testDIHO:testDIHO·p0.50 16 sample 872.000 ns/op
InflateTests.testDIHO:testDIHO·p0.90 16 sample 1084.000 ns/op
InflateTests.testDIHO:testDIHO·p0.95 16 sample 1154.000 ns/op
InflateTests.testDIHO:testDIHO·p0.99 16 sample 1484.000 ns/op
InflateTests.testDIHO:testDIHO·p0.999 16 sample 3688.000 ns/op
InflateTests.testDIHO:testDIHO·p0.9999 16 sample 5728.000 ns/op
InflateTests.testDIHO:testDIHO·p1.00 16 sample 35456.000 ns/op
InflateTests.testDIHO 128 sample 291971 4195.645 ± 2.912 ns/op
InflateTests.testDIHO:testDIHO·p0.00 128 sample 3176.000 ns/op
InflateTests.testDIHO:testDIHO·p0.50 128 sample 4136.000 ns/op
InflateTests.testDIHO:testDIHO·p0.90 128 sample 4544.000 ns/op
InflateTests.testDIHO:testDIHO·p0.95 128 sample 4696.000 ns/op
InflateTests.testDIHO:testDIHO·p0.99 128 sample 6464.000 ns/op
InflateTests.testDIHO:testDIHO·p0.999 128 sample 8480.000 ns/op
InflateTests.testDIHO:testDIHO·p0.9999 128 sample 12906.138 ns/op
InflateTests.testDIHO:testDIHO·p1.00 128 sample 31840.000 ns/op
InflateTests.testDIHO 1024 sample 158528 31191.515 ± 19.858 ns/op
InflateTests.testDIHO:testDIHO·p0.00 1024 sample 28032.000 ns/op
InflateTests.testDIHO:testDIHO·p0.50 1024 sample 30848.000 ns/op
InflateTests.testDIHO:testDIHO·p0.90 1024 sample 32256.000 ns/op
InflateTests.testDIHO:testDIHO·p0.95 1024 sample 33344.000 ns/op
InflateTests.testDIHO:testDIHO·p0.99 1024 sample 42304.000 ns/op
InflateTests.testDIHO:testDIHO·p0.999 1024 sample 50688.000 ns/op
InflateTests.testDIHO:testDIHO·p0.9999 1024 sample 57044.730 ns/op
InflateTests.testDIHO:testDIHO·p1.00 1024 sample 484352.000 ns/op
InflateTests.testHIAO 16 sample 319309 920.649 ± 1.436 ns/op
InflateTests.testHIAO:testHIAO·p0.00 16 sample 309.000 ns/op
InflateTests.testHIAO:testHIAO·p0.50 16 sample 904.000 ns/op
InflateTests.testHIAO:testHIAO·p0.90 16 sample 1112.000 ns/op
InflateTests.testHIAO:testHIAO·p0.95 16 sample 1178.000 ns/op
InflateTests.testHIAO:testHIAO·p0.99 16 sample 1440.000 ns/op
InflateTests.testHIAO:testHIAO·p0.999 16 sample 3684.000 ns/op
InflateTests.testHIAO:testHIAO·p0.9999 16 sample 6137.104 ns/op
InflateTests.testHIAO:testHIAO·p1.00 16 sample 39104.000 ns/op
InflateTests.testHIAO 128 sample 289823 4225.390 ± 3.155 ns/op
InflateTests.testHIAO:testHIAO·p0.00 128 sample 3204.000 ns/op
InflateTests.testHIAO:testHIAO·p0.50 128 sample 4152.000 ns/op
InflateTests.testHIAO:testHIAO·p0.90 128 sample 4568.000 ns/op
InflateTests.testHIAO:testHIAO·p0.95 128 sample 4776.000 ns/op
InflateTests.testHIAO:testHIAO·p0.99 128 sample 6416.000 ns/op
InflateTests.testHIAO:testHIAO·p0.999 128 sample 8336.000 ns/op
InflateTests.testHIAO:testHIAO·p0.9999 128 sample 12528.845 ns/op
InflateTests.testHIAO:testHIAO·p1.00 128 sample 46336.000 ns/op
InflateTests.testHIAO 1024 sample 161249 30745.929 ± 12.827 ns/op
InflateTests.testHIAO:testHIAO·p0.00 1024 sample 28032.000 ns/op
InflateTests.testHIAO:testHIAO·p0.50 1024 sample 30560.000 ns/op
InflateTests.testHIAO:testHIAO·p0.90 1024 sample 31552.000 ns/op
InflateTests.testHIAO:testHIAO·p0.95 1024 sample 32288.000 ns/op
InflateTests.testHIAO:testHIAO·p0.99 1024 sample 37952.000 ns/op
InflateTests.testHIAO:testHIAO·p0.999 1024 sample 47552.000 ns/op
InflateTests.testHIAO:testHIAO·p0.9999 1024 sample 53752.000 ns/op
InflateTests.testHIAO:testHIAO·p1.00 1024 sample 90752.000 ns/op
InflateTests.testHIDO 16 sample 332361 891.695 ± 6.406 ns/op
InflateTests.testHIDO:testHIDO·p0.00 16 sample 271.000 ns/op
InflateTests.testHIDO:testHIDO·p0.50 16 sample 870.000 ns/op
InflateTests.testHIDO:testHIDO·p0.90 16 sample 1080.000 ns/op
InflateTests.testHIDO:testHIDO·p0.95 16 sample 1148.000 ns/op
InflateTests.testHIDO:testHIDO·p0.99 16 sample 1440.000 ns/op
InflateTests.testHIDO:testHIDO·p0.999 16 sample 3788.000 ns/op
InflateTests.testHIDO:testHIDO·p0.9999 16 sample 7012.221 ns/op
InflateTests.testHIDO:testHIDO·p1.00 16 sample 618496.000 ns/op
InflateTests.testHIDO 128 sample 290853 4198.779 ± 2.973 ns/op
InflateTests.testHIDO:testHIDO·p0.00 128 sample 3168.000 ns/op
InflateTests.testHIDO:testHIDO·p0.50 128 sample 4136.000 ns/op
InflateTests.testHIDO:testHIDO·p0.90 128 sample 4544.000 ns/op
InflateTests.testHIDO:testHIDO·p0.95 128 sample 4720.000 ns/op
InflateTests.testHIDO:testHIDO·p0.99 128 sample 6448.000 ns/op
InflateTests.testHIDO:testHIDO·p0.999 128 sample 8400.000 ns/op
InflateTests.testHIDO:testHIDO·p0.9999 128 sample 11518.634 ns/op
InflateTests.testHIDO:testHIDO·p1.00 128 sample 47936.000 ns/op
InflateTests.testHIDO 1024 sample 158712 31162.902 ± 17.625 ns/op
InflateTests.testHIDO:testHIDO·p0.00 1024 sample 28128.000 ns/op
InflateTests.testHIDO:testHIDO·p0.50 1024 sample 30848.000 ns/op
InflateTests.testHIDO:testHIDO·p0.90 1024 sample 32192.000 ns/op
InflateTests.testHIDO:testHIDO·p0.95 1024 sample 33216.000 ns/op
InflateTests.testHIDO:testHIDO·p0.99 1024 sample 42048.000 ns/op
InflateTests.testHIDO:testHIDO·p0.999 1024 sample 50560.000 ns/op
InflateTests.testHIDO:testHIDO·p0.9999 1024 sample 59121.421 ns/op
InflateTests.testHIDO:testHIDO·p1.00 1024 sample 323072.000 ns/op
InflateTests.testHIHO 16 sample 318112 927.173 ± 1.529 ns/op
InflateTests.testHIHO:testHIHO·p0.00 16 sample 322.000 ns/op
InflateTests.testHIHO:testHIHO·p0.50 16 sample 907.000 ns/op
InflateTests.testHIHO:testHIHO·p0.90 16 sample 1120.000 ns/op
InflateTests.testHIHO:testHIHO·p0.95 16 sample 1192.000 ns/op
InflateTests.testHIHO:testHIHO·p0.99 16 sample 1530.000 ns/op
InflateTests.testHIHO:testHIHO·p0.999 16 sample 3772.000 ns/op
InflateTests.testHIHO:testHIHO·p0.9999 16 sample 6131.019 ns/op
InflateTests.testHIHO:testHIHO·p1.00 16 sample 48512.000 ns/op
InflateTests.testHIHO 128 sample 287766 4252.329 ± 12.322 ns/op
InflateTests.testHIHO:testHIHO·p0.00 128 sample 3188.000 ns/op
InflateTests.testHIHO:testHIHO·p0.50 128 sample 4176.000 ns/op
InflateTests.testHIHO:testHIHO·p0.90 128 sample 4592.000 ns/op
InflateTests.testHIHO:testHIHO·p0.95 128 sample 4776.000 ns/op
InflateTests.testHIHO:testHIHO·p0.99 128 sample 6674.640 ns/op
InflateTests.testHIHO:testHIHO·p0.999 128 sample 9200.000 ns/op
InflateTests.testHIHO:testHIHO·p0.9999 128 sample 14151.301 ns/op
InflateTests.testHIHO:testHIHO·p1.00 128 sample 835584.000 ns/op
InflateTests.testHIHO 1024 sample 159210 31110.602 ± 21.011 ns/op
InflateTests.testHIHO:testHIHO·p0.00 1024 sample 28192.000 ns/op
InflateTests.testHIHO:testHIHO·p0.50 1024 sample 30848.000 ns/op
InflateTests.testHIHO:testHIHO·p0.90 1024 sample 32064.000 ns/op
InflateTests.testHIHO:testHIHO·p0.95 1024 sample 33024.000 ns/op
InflateTests.testHIHO:testHIHO·p0.99 1024 sample 38144.000 ns/op
InflateTests.testHIHO:testHIHO·p0.999 1024 sample 49650.496 ns/op
InflateTests.testHIHO:testHIHO·p0.9999 1024 sample 56719.149 ns/op
InflateTests.testHIHO:testHIHO·p1.00 1024 sample 765952.000 ns/op
More information about the core-libs-dev
mailing list