Skip to content

Commit 0cd4498

Browse files
committed
Sadly, those two putBoolean calls are required. Due to API stability across versions, UnsafeInflater is replaced with InflaterHackery, which instead just calls the appropriate methods instead of updating fields
Slight perf loss, which is depressing, but stability is a must.
1 parent f85aabd commit 0cd4498

File tree

5 files changed

+61
-93
lines changed

5 files changed

+61
-93
lines changed

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
<groupId>software.coley</groupId>
88
<artifactId>lljzip</artifactId>
9-
<version>1.6.0</version>
9+
<version>1.6.1</version>
1010

1111
<name>LL Java ZIP</name>
1212
<description>Lower level ZIP support for Java</description>

src/main/java/software/coley/llzip/format/compression/UnsafeDeflateDecompressor.java

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import software.coley.llzip.format.model.LocalFileHeader;
44
import software.coley.llzip.util.ByteData;
55
import software.coley.llzip.util.FastWrapOutputStream;
6-
import software.coley.llzip.util.UnsafeInflater;
6+
import software.coley.llzip.util.InflaterHackery;
77

88
import java.io.IOException;
99
import java.util.ArrayDeque;
@@ -43,9 +43,7 @@ public ByteData decompress(LocalFileHeader header, ByteData data) throws IOExcep
4343
if (entry == null) {
4444
entry = new DeflateEntry();
4545
} else {
46-
// Normal 'Inflater' reset() is synchronized and bottlenecks us,
47-
// but we're using 'UnsafeInflater' which bypasses that.
48-
entry.inflater.reset();
46+
InflaterHackery.reset(entry.inflater);
4947
}
5048
try {
5149
byte[] output = entry.decompress;
@@ -90,7 +88,7 @@ public ByteData decompress(LocalFileHeader header, ByteData data) throws IOExcep
9088
}
9189

9290
private static final class DeflateEntry {
93-
final Inflater inflater = new UnsafeInflater(true);
91+
final Inflater inflater = new Inflater(true);
9492
final byte[] decompress = new byte[1024];
9593
final byte[] buffer = new byte[8192];
9694
}

src/main/java/software/coley/llzip/format/compression/ZipCompressions.java

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
import software.coley.llzip.format.model.LocalFileHeader;
44
import software.coley.llzip.util.ByteData;
5-
import software.coley.llzip.util.UnsafeInflater;
65

76
import java.io.IOException;
87

@@ -210,11 +209,7 @@ static ByteData decompress(LocalFileHeader header) throws IOException {
210209
return header.getFileData();
211210
case DEFLATED:
212211
// Use unsafe decompressor if available since it is faster.
213-
if (UnsafeInflater.initFail) {
214-
return header.decompress(new DeflateDecompressor());
215-
} else {
216-
return header.decompress(new UnsafeDeflateDecompressor());
217-
}
212+
return header.decompress(new UnsafeDeflateDecompressor());
218213
default:
219214
// TODO: Support other decompressing techniques
220215
String methodName = getName(method);
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package software.coley.llzip.util;
2+
3+
import sun.misc.Unsafe;
4+
5+
import java.lang.invoke.MethodHandle;
6+
import java.lang.invoke.MethodHandles;
7+
import java.lang.invoke.MethodType;
8+
import java.lang.reflect.Field;
9+
import java.util.zip.Inflater;
10+
11+
/**
12+
* Used to more efficiently reset a {@link Inflater} than the default impl of {@link Inflater#reset()}.
13+
*
14+
* @author xDark
15+
*/
16+
public final class InflaterHackery {
17+
private static final Unsafe UNSAFE = UnsafeUtil.get();
18+
private static final MethodHandle MH_RESET;
19+
private static final MethodHandle MH_FINISHED;
20+
private static final long zRef_offset;
21+
private static final long zRef_address_offset;
22+
23+
private InflaterHackery() {
24+
}
25+
26+
/**
27+
* @param inflater
28+
* Inflater to reset.
29+
*/
30+
public static void reset(Inflater inflater) {
31+
Unsafe u = UNSAFE;
32+
long address = u.getLong(u.getObject(inflater, zRef_offset), zRef_address_offset);
33+
try {
34+
MH_RESET.invokeExact(address);
35+
MH_FINISHED.invokeExact(inflater, false);
36+
} catch (Throwable t) {
37+
throw new RuntimeException(t);
38+
}
39+
}
40+
41+
static {
42+
try {
43+
Unsafe u = UNSAFE;
44+
Field f = Inflater.class.getDeclaredField("zsRef");
45+
Class<?> zrefClass = f.getType();
46+
zRef_offset = u.objectFieldOffset(f);
47+
f = zrefClass.getDeclaredField("address");
48+
zRef_address_offset = u.objectFieldOffset(f);
49+
MethodHandles.Lookup l = UnsafeUtil.lookup();
50+
MH_RESET = l.findStatic(Inflater.class, "reset", MethodType.methodType(void.class, long.class));
51+
MH_FINISHED = l.findSetter(Inflater.class, "finished", boolean.class);
52+
} catch (ReflectiveOperationException ex) {
53+
throw new ExceptionInInitializerError(ex);
54+
}
55+
}
56+
}

src/main/java/software/coley/llzip/util/UnsafeInflater.java

Lines changed: 0 additions & 81 deletions
This file was deleted.

0 commit comments

Comments
 (0)