[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