Skip to content

Commit 6c681e6

Browse files
committed
implement zlib._ZlibDecompressor
1 parent 4a16952 commit 6c681e6

8 files changed

Lines changed: 726 additions & 18 deletions

File tree

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/Python3Core.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,7 @@
216216
import com.oracle.graal.python.builtins.modules.zlib.ZLibModuleBuiltins;
217217
import com.oracle.graal.python.builtins.modules.zlib.ZlibCompressBuiltins;
218218
import com.oracle.graal.python.builtins.modules.zlib.ZlibDecompressBuiltins;
219+
import com.oracle.graal.python.builtins.modules.zlib.ZlibDecompressorBuiltins;
219220
import com.oracle.graal.python.builtins.objects.NoneBuiltins;
220221
import com.oracle.graal.python.builtins.objects.NotImplementedBuiltins;
221222
import com.oracle.graal.python.builtins.objects.PNone;
@@ -719,6 +720,7 @@ private static PythonBuiltins[] initializeBuiltins(boolean nativeAccessAllowed,
719720
PythonImageBuildOptions.WITHOUT_COMPRESSION_LIBRARIES ? null : new ZLibModuleBuiltins(),
720721
PythonImageBuildOptions.WITHOUT_COMPRESSION_LIBRARIES ? null : new ZlibCompressBuiltins(),
721722
PythonImageBuildOptions.WITHOUT_COMPRESSION_LIBRARIES ? null : new ZlibDecompressBuiltins(),
723+
PythonImageBuildOptions.WITHOUT_COMPRESSION_LIBRARIES ? null : new ZlibDecompressorBuiltins(),
722724

723725
new MMapModuleBuiltins(),
724726
new FcntlModuleBuiltins(),

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/PythonBuiltinClassType.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,7 @@ public enum PythonBuiltinClassType implements TruffleObject {
335335
// zlib
336336
ZlibCompress("Compress", "zlib"),
337337
ZlibDecompress("Decompress", "zlib"),
338+
ZlibDecompressor("_ZlibDecompressor", "zlib"),
338339

339340
// io
340341
PIOBase("_IOBase", "_io", Flags.PUBLIC_BASE_WDICT),

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/zlib/ZlibDecompressorBuiltins.java

Lines changed: 294 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
/*
2+
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* The Universal Permissive License (UPL), Version 1.0
6+
*
7+
* Subject to the condition set forth below, permission is hereby granted to any
8+
* person obtaining a copy of this software, associated documentation and/or
9+
* data (collectively the "Software"), free of charge and under any and all
10+
* copyright rights in the Software, and any and all patent rights owned or
11+
* freely licensable by each licensor hereunder covering either (i) the
12+
* unmodified Software as contributed to or provided by such licensor, or (ii)
13+
* the Larger Works (as defined below), to deal in both
14+
*
15+
* (a) the Software, and
16+
*
17+
* (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
18+
* one is included with the Software each a "Larger Work" to which the Software
19+
* is contributed by such licensors),
20+
*
21+
* without restriction, including without limitation the rights to copy, create
22+
* derivative works of, display, perform, and distribute the Software and make,
23+
* use, sell, offer for sale, import, export, have made, and have sold the
24+
* Software and the Larger Work(s), and to sublicense the foregoing rights on
25+
* either these or other terms.
26+
*
27+
* This license is subject to the following condition:
28+
*
29+
* The above copyright notice and either this complete permission notice or at a
30+
* minimum a reference to the UPL must be included in all copies or substantial
31+
* portions of the Software.
32+
*
33+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
34+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
35+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
36+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
37+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
38+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
39+
* SOFTWARE.
40+
*/
41+
package com.oracle.graal.python.builtins.modules.zlib;
42+
43+
import com.oracle.graal.python.builtins.modules.zlib.ZLibCompObject.JavaZlibCompObject;
44+
import com.oracle.graal.python.builtins.modules.zlib.ZLibCompObject.NativeZlibCompObject;
45+
import com.oracle.graal.python.builtins.objects.bytes.PBytes;
46+
import com.oracle.graal.python.builtins.objects.object.PythonBuiltinObject;
47+
import com.oracle.graal.python.runtime.NFIZlibSupport;
48+
import com.oracle.truffle.api.object.Shape;
49+
50+
public class ZlibDecompressorObject extends PythonBuiltinObject {
51+
52+
private final ZLibCompObject compObject; // mq: we are reusing ZLibCompObject to reduce code
53+
// footprint.
54+
55+
/*
56+
* zst>avail_in is only 32 bit, so we store the true length separately. Conversion and looping
57+
* is encapsulated in decompress_buf()
58+
*/
59+
private long availInReal;
60+
private boolean needsInput;
61+
62+
// native
63+
private ZlibDecompressorObject(Object cls, Shape instanceShape, Object zst, NFIZlibSupport zlibSupport) {
64+
super(cls, instanceShape);
65+
this.compObject = ZLibCompObject.createNative(cls, instanceShape, zst, zlibSupport);
66+
this.availInReal = 0;
67+
}
68+
69+
// Java
70+
private ZlibDecompressorObject(Object cls, Shape instanceShape, Object stream, int wbits, byte[] zdict) {
71+
super(cls, instanceShape);
72+
this.compObject = ZLibCompObject.createJava(cls, instanceShape, stream, wbits, zdict);
73+
this.availInReal = 0;
74+
}
75+
76+
public boolean isInitialized() {
77+
return compObject.isInitialized();
78+
}
79+
80+
public boolean isEof() {
81+
return compObject.isEof();
82+
}
83+
84+
public void setEof(boolean eof) {
85+
compObject.setEof(eof);
86+
}
87+
88+
public Object getZst() {
89+
assert isNative();
90+
return ((NativeZlibCompObject) compObject).getZst();
91+
}
92+
93+
public JavaZlibCompObject getStream() {
94+
assert !isNative();
95+
return ((JavaZlibCompObject) compObject);
96+
}
97+
98+
public long getAvailInReal() {
99+
return availInReal;
100+
}
101+
102+
public void setAvailInReal(long avail_in_real) {
103+
this.availInReal = avail_in_real;
104+
}
105+
106+
public boolean isNeedsInput() {
107+
return needsInput;
108+
}
109+
110+
public void setNeedsInput(boolean needs_input) {
111+
this.needsInput = needs_input;
112+
}
113+
114+
public PBytes getUnusedData() {
115+
return compObject.getUnusedData();
116+
}
117+
118+
public void setUnusedData(PBytes unusedData) {
119+
compObject.setUnusedData(unusedData);
120+
}
121+
122+
public PBytes getUnconsumedTail() {
123+
return compObject.getUnconsumedTail();
124+
}
125+
126+
public void setUnconsumedTail(PBytes unconsumedTail) {
127+
compObject.setUnconsumedTail(unconsumedTail);
128+
}
129+
130+
public boolean isNative() {
131+
return compObject instanceof ZLibCompObject.NativeZlibCompObject;
132+
}
133+
134+
public static ZlibDecompressorObject createNative(Object cls, Shape instanceShape, Object zst, NFIZlibSupport zlibSupport) {
135+
return new ZlibDecompressorObject(cls, instanceShape, zst, zlibSupport);
136+
}
137+
138+
public static ZlibDecompressorObject createJava(Object cls, Shape instanceShape, Object stream, int wbits, byte[] zdict) {
139+
return new ZlibDecompressorObject(cls, instanceShape, stream, wbits, zdict);
140+
}
141+
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/zlib/ZlibNodes.java

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,6 @@
7575

7676
import com.oracle.graal.python.PythonLanguage;
7777
import com.oracle.graal.python.builtins.objects.bytes.BytesNodes;
78-
import com.oracle.graal.python.builtins.objects.ints.PInt;
7978
import com.oracle.graal.python.builtins.objects.str.StringUtils.SimpleTruffleStringFormatNode;
8079
import com.oracle.graal.python.nodes.ErrorMessages;
8180
import com.oracle.graal.python.nodes.PNodeWithContext;
@@ -84,9 +83,7 @@
8483
import com.oracle.graal.python.runtime.NativeLibrary;
8584
import com.oracle.graal.python.runtime.PythonContext;
8685
import com.oracle.graal.python.runtime.object.PFactory;
87-
import com.oracle.graal.python.util.OverflowException;
8886
import com.oracle.graal.python.util.PythonUtils;
89-
import com.oracle.truffle.api.CompilerDirectives;
9087
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
9188
import com.oracle.truffle.api.dsl.Bind;
9289
import com.oracle.truffle.api.dsl.Cached;
@@ -193,6 +190,28 @@ static byte[] nativeDecompress(Node inliningTarget, ZLibCompObject.NativeZlibCom
193190

194191
}
195192

193+
@GenerateInline
194+
@GenerateCached(false)
195+
public abstract static class ZlibNativeDecompressor extends PNodeWithContext {
196+
197+
public abstract byte[] execute(Node inliningTarget, ZlibDecompressorObject self, PythonContext context, byte[] bytes, int len, int maxLength);
198+
199+
@Specialization
200+
static byte[] nativeDecompressBuf(Node inliningTarget, ZlibDecompressorObject self, PythonContext context, byte[] bytes, int len, int maxLength,
201+
@Cached(inline = false) NativeLibrary.InvokeNativeFunction decompressor,
202+
@Cached GetNativeBufferNode getBuffer,
203+
@Cached ZlibNativeErrorHandling errorHandling) {
204+
NFIZlibSupport zlibSupport = context.getNFIZlibSupport();
205+
Object in = context.getEnv().asGuestValue(bytes);
206+
int ret = zlibSupport.decompressor(self.getZst(), in, len, maxLength, decompressor);
207+
if (ret < 0) {
208+
errorHandling.execute(inliningTarget, self.getZst(), ret, zlibSupport, false);
209+
}
210+
self.setNeedsInput(ret == 1);
211+
return getBuffer.getOutputBuffer(inliningTarget, self.getZst(), context);
212+
}
213+
}
214+
196215
@GenerateInline
197216
@GenerateCached(false)
198217
public abstract static class ZlibNativeDecompress extends PNodeWithContext {
@@ -645,15 +664,6 @@ public static int getRemaining(Inflater inflater) {
645664
return inflater.getRemaining();
646665
}
647666

648-
@TruffleBoundary
649-
public static int getBytesRead(Inflater inflater) {
650-
try {
651-
return PInt.intValueExact(inflater.getBytesRead());
652-
} catch (OverflowException e) {
653-
throw CompilerDirectives.shouldNotReachHere("input size is larger than an int!");
654-
}
655-
}
656-
657667
@TruffleBoundary
658668
public static boolean isFinished(Inflater inflater) {
659669
return inflater.finished();

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NFIZlibSupport.java

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,9 @@ int zlib_Decompress_flush(zlib_stream *zst, ssize_t length)
244244
nfi_function: name('decompressObjCopy') map('zlib_stream*', 'POINTER')
245245
int zlib_Decompress_copy(zlib_stream *zst, zlib_stream *new_copy)
246246
*/
247-
zlib_Decompress_copy("(POINTER, POINTER): SINT32");
247+
zlib_Decompress_copy("(POINTER, POINTER): SINT32"),
248+
249+
zlib_decompress("(POINTER, [UINT8], SINT64, SINT64): SINT32");
248250

249251
private final String signature;
250252

@@ -664,4 +666,18 @@ public int decompressObjCopy(Object zst, Object new_copy,
664666
return invokeNode.callInt(typedNativeLib, ZlibNativeFunctions.zlib_Decompress_copy, zst, new_copy);
665667
}
666668

669+
/**
670+
* returns needs_input flag if the value isn't less than 0, otherwise it returns the zlib error
671+
* code.
672+
*
673+
* @param zst zlib_stream *zst
674+
* @param data Byte *data
675+
* @param len size_t len
676+
* @param max_length ssize_t max_length
677+
* @return int
678+
*/
679+
public int decompressor(Object zst, Object data, long len, long max_length,
680+
NativeLibrary.InvokeNativeFunction invokeNode) {
681+
return invokeNode.callInt(typedNativeLib, ZlibNativeFunctions.zlib_decompress, zst, data, len, max_length);
682+
}
667683
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/object/PFactory.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@
8282
import com.oracle.graal.python.builtins.modules.pickle.PUnpickler;
8383
import com.oracle.graal.python.builtins.modules.pickle.PUnpicklerMemoProxy;
8484
import com.oracle.graal.python.builtins.modules.zlib.ZLibCompObject;
85+
import com.oracle.graal.python.builtins.modules.zlib.ZlibDecompressorObject;
8586
import com.oracle.graal.python.builtins.objects.PNone;
8687
import com.oracle.graal.python.builtins.objects.array.PArray;
8788
import com.oracle.graal.python.builtins.objects.asyncio.PAsyncGen;
@@ -1226,6 +1227,14 @@ public static ZLibCompObject createNativeZLibCompObject(PythonLanguage language,
12261227
return trace(language, ZLibCompObject.createNative(cls, shape, zst, zlibSupport));
12271228
}
12281229

1230+
public static ZlibDecompressorObject createJavaZlibDecompressorObject(PythonLanguage language, Object stream, int wbits, byte[] zdict) {
1231+
return trace(language, ZlibDecompressorObject.createJava(PythonBuiltinClassType.ZlibDecompressor, PythonBuiltinClassType.ZlibDecompressor.getInstanceShape(language), stream, wbits, zdict));
1232+
}
1233+
1234+
public static ZlibDecompressorObject createNativeZlibDecompressorObject(PythonLanguage language, Object zst, NFIZlibSupport zlibSupport) {
1235+
return trace(language, ZlibDecompressorObject.createNative(PythonBuiltinClassType.ZlibDecompressor, PythonBuiltinClassType.ZlibDecompressor.getInstanceShape(language), zst, zlibSupport));
1236+
}
1237+
12291238
public static LZMAObject.LZMADecompressor createLZMADecompressor(PythonLanguage language, Object cls, Shape shape, boolean isNative) {
12301239
return trace(language, LZMAObject.createDecompressor(cls, shape, isNative));
12311240
}

0 commit comments

Comments
 (0)