Skip to content

Commit e2baa59

Browse files
committed
[GR-58092] Implement _PyLong_FromByteArray
PullRequest: graalpython/3481
2 parents be71e0e + eee20e9 commit e2baa59

File tree

13 files changed

+159
-139
lines changed

13 files changed

+159
-139
lines changed

graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_long.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -454,3 +454,21 @@ class TestPyLong(CPyExtTestCase):
454454
arguments=["PyObject* n", "int base"],
455455
cmpfunc=unhandled_error_compare,
456456
)
457+
458+
test__PyLong_FromByteArray = CPyExtFunction(
459+
lambda args: int.from_bytes(args[0], 'little' if args[1] else 'big', signed=args[2]),
460+
lambda: (
461+
(b'', 1, 1),
462+
(b'\x00\x0009', 0, 1),
463+
(b'90\x00\x00\x00\x00\x00\x00', 1, 1),
464+
(b'\xff\xff\xcf\xc7', 0, 1),
465+
(b'\xff\xff\xff\xff\xff\xff\xff\xab', 0, 0),
466+
(b'\xab\xff\xff\xff\xff\xff\xff\xff', 1, 0),
467+
(b'\xff\xff\xff\xff\xff\xff\xff\xff', 0, 1),
468+
(b'\xff\xff\xff\xff\xff\xff\xff\xff', 1, 1),
469+
),
470+
resultspec="O",
471+
argspec="y#ii",
472+
arguments=["const char* bytes", "Py_ssize_t size", "int little_endian", "int is_signed"],
473+
cmpfunc=unhandled_error_compare,
474+
)

graalpython/com.oracle.graal.python.test/src/tests/test_int.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -460,7 +460,8 @@ def test_SignedBigEndian(self):
460460
b'\x80\x00': -32768,
461461
b'\x00\xff\xff': 65535,
462462
b'\xff\x00\x00': -65536,
463-
b'\x80\x00\x00': -8388608
463+
b'\x80\x00\x00': -8388608,
464+
b'\xa0\x00\x00\x00\x00\x00\x00\x00': -6917529027641081856,
464465
}
465466
self.check(tests1, 'big', signed=True)
466467

@@ -487,7 +488,8 @@ def test_SignedLittleEndian(self):
487488
b'\x00\x80': -32768,
488489
b'\xff\xff\x00': 65535,
489490
b'\x00\x00\xff': -65536,
490-
b'\x00\x00\x80': -8388608
491+
b'\x00\x00\x80': -8388608,
492+
b'\x00\x00\x00\x00\x00\x00\x00\xa0': -6917529027641081856,
491493
}
492494
self.check(tests2, 'little', signed=True)
493495

@@ -505,6 +507,7 @@ def test_UnsignedBigEndian(self):
505507
b'\x80\x00': 32768,
506508
b'\xff\xff': 65535,
507509
b'\x01\x00\x00': 65536,
510+
b'\xa0\x00\x00\x00\x00\x00\x00\x00': 11529215046068469760,
508511
}
509512
self.check(tests3, 'big', signed=False)
510513

@@ -522,6 +525,7 @@ def test_UnsignedLittleEndian(self):
522525
b'\x00\x80': 32768,
523526
b'\xff\xff': 65535,
524527
b'\x00\x00\x01': 65536,
528+
b'\x00\x00\x00\x00\x00\x00\x00\xa0': 11529215046068469760,
525529
}
526530
self.check(tests4, 'little', signed=False)
527531

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextLongBuiltins.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
import static com.oracle.graal.python.builtins.PythonBuiltinClassType.TypeError;
4444
import static com.oracle.graal.python.builtins.modules.cext.PythonCextBuiltins.CApiCallPath.Direct;
4545
import static com.oracle.graal.python.builtins.modules.cext.PythonCextBuiltins.CApiCallPath.Ignored;
46+
import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.CONST_UNSIGNED_CHAR_PTR;
4647
import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.Int;
4748
import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.LONG_LONG;
4849
import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.Pointer;
@@ -64,6 +65,7 @@
6465
import com.oracle.graal.python.builtins.modules.cext.PythonCextBuiltins.CApi5BuiltinNode;
6566
import com.oracle.graal.python.builtins.modules.cext.PythonCextBuiltins.CApiBinaryBuiltinNode;
6667
import com.oracle.graal.python.builtins.modules.cext.PythonCextBuiltins.CApiBuiltin;
68+
import com.oracle.graal.python.builtins.modules.cext.PythonCextBuiltins.CApiQuaternaryBuiltinNode;
6769
import com.oracle.graal.python.builtins.modules.cext.PythonCextBuiltins.CApiTernaryBuiltinNode;
6870
import com.oracle.graal.python.builtins.modules.cext.PythonCextBuiltins.CApiUnaryBuiltinNode;
6971
import com.oracle.graal.python.builtins.objects.cext.PythonNativeVoidPtr;
@@ -76,6 +78,7 @@
7678
import com.oracle.graal.python.builtins.objects.cext.structs.CStructAccess;
7779
import com.oracle.graal.python.builtins.objects.ints.IntBuiltins;
7880
import com.oracle.graal.python.builtins.objects.ints.IntBuiltins.NegNode;
81+
import com.oracle.graal.python.builtins.objects.ints.IntNodes;
7982
import com.oracle.graal.python.builtins.objects.ints.PInt;
8083
import com.oracle.graal.python.lib.PyLongFromDoubleNode;
8184
import com.oracle.graal.python.nodes.ErrorMessages;
@@ -464,4 +467,20 @@ static Object convert(TruffleString s, int base,
464467
return intNode.executeWith(null, s, base);
465468
}
466469
}
470+
471+
@CApiBuiltin(ret = PyObjectTransfer, args = {CONST_UNSIGNED_CHAR_PTR, SIZE_T, Int, Int}, call = Direct)
472+
abstract static class _PyLong_FromByteArray extends CApiQuaternaryBuiltinNode {
473+
@Specialization
474+
static Object convert(Object charPtr, long size, int littleEndian, int signed,
475+
@Bind("this") Node inliningTarget,
476+
@Cached CStructAccess.ReadByteNode readByteNode,
477+
@Cached IntNodes.PyLongFromByteArray fromByteArray,
478+
@Cached PRaiseNode.Lazy raiseNode) {
479+
if (size != (int) size) {
480+
throw raiseNode.get(inliningTarget).raise(OverflowError, ErrorMessages.BYTE_ARRAY_TOO_LONG_TO_CONVERT_TO_INT);
481+
}
482+
byte[] bytes = readByteNode.readByteArray(charPtr, (int) size);
483+
return fromByteArray.execute(inliningTarget, bytes, littleEndian != 0, signed != 0);
484+
}
485+
}
467486
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cjkcodecs/MultibyteIncrementalEncoderBuiltins.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -286,7 +286,7 @@ static Object getstate(MultibyteIncrementalEncoderObject self,
286286
// for the encoder object.
287287
// memcpy(statebytes + statesize, self.state.c, MULTIBYTECODECSTATE);
288288
// statesize += MULTIBYTECODECSTATE;
289-
Object stateobj = fromByteArray.execute(inliningTarget, statebytes, false);
289+
Object stateobj = fromByteArray.execute(inliningTarget, statebytes, true, true);
290290
assert (stateobj instanceof PInt); // since statebytes.length > 8, we will get a PInt
291291
writeHiddenAttrNode.execute(inliningTarget, (PInt) stateobj, HiddenAttr.ENCODER_OBJECT, self.state);
292292
return stateobj;

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/PTextIO.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* The Universal Permissive License (UPL), Version 1.0
@@ -47,13 +47,13 @@
4747
import static com.oracle.graal.python.util.PythonUtils.TS_ENCODING;
4848

4949
import java.io.ByteArrayOutputStream;
50-
import java.math.BigInteger;
5150

5251
import com.oracle.graal.python.builtins.objects.ints.IntBuiltins;
52+
import com.oracle.graal.python.builtins.objects.ints.IntNodes;
5353
import com.oracle.graal.python.builtins.objects.ints.PInt;
5454
import com.oracle.graal.python.nodes.PRaiseNode;
55-
import com.oracle.graal.python.runtime.object.PythonObjectFactory;
5655
import com.oracle.truffle.api.CompilerDirectives;
56+
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
5757
import com.oracle.truffle.api.memory.ByteArraySupport;
5858
import com.oracle.truffle.api.nodes.Node;
5959
import com.oracle.truffle.api.object.Shape;
@@ -413,15 +413,15 @@ protected static class CookieType {
413413
this.needEOF = 0;
414414
}
415415

416-
public static PInt build(CookieType cookie, PythonObjectFactory factory) {
416+
@TruffleBoundary
417+
public static Object build(CookieType cookie) {
417418
byte[] buffer = new byte[COOKIE_BUF_LEN];
418419
SERIALIZE.putLong(buffer, 0, cookie.startPos);
419420
SERIALIZE.putInt(buffer, Long.BYTES, cookie.decFlags);
420421
SERIALIZE.putInt(buffer, Long.BYTES + Integer.BYTES, cookie.bytesToFeed);
421422
SERIALIZE.putInt(buffer, Long.BYTES + Integer.BYTES * 2, cookie.charsToSkip);
422423
SERIALIZE.putByte(buffer, Long.BYTES + Integer.BYTES * 3, cookie.needEOF);
423-
BigInteger v = IntBuiltins.FromBytesNode.createBigInteger(buffer, false, false);
424-
return factory.createInt(v);
424+
return IntNodes.PyLongFromByteArray.executeUncached(buffer, true, false);
425425
}
426426

427427
public static CookieType parse(long v, Node inliningTarget, InlinedConditionProfile overflow, PRaiseNode.Lazy raise) {

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/TextIOWrapperBuiltins.java

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -876,11 +876,10 @@ static Object didntMove(VirtualFrame frame, PTextIO self,
876876
@Exclusive @Cached TextIOWrapperNodes.WriteFlushNode writeFlushNode,
877877
@Exclusive @Cached PyObjectCallMethodObjArgs callMethodFlush,
878878
@Exclusive @Cached PyObjectCallMethodObjArgs callMethodTell,
879-
@Exclusive @Cached PyLongAsLongNode asLongNode,
880-
@Shared @Cached PythonObjectFactory factory) {
879+
@Exclusive @Cached PyLongAsLongNode asLongNode) {
881880
PTextIO.CookieType cookie = getCookie(frame, inliningTarget, self, writeFlushNode, callMethodFlush, callMethodTell, asLongNode);
882881
/* We haven't moved from the snapshot point. */
883-
return PTextIO.CookieType.build(cookie, factory);
882+
return PTextIO.CookieType.build(cookie);
884883
}
885884

886885
@Specialization(guards = {
@@ -907,7 +906,7 @@ static Object tell(VirtualFrame frame, PTextIO self,
907906
@Exclusive @Cached PyLongAsLongNode asLongNode,
908907
@Cached PyObjectSizeNode sizeNode,
909908
@CachedLibrary(limit = "2") InteropLibrary isString,
910-
@Shared @Cached PythonObjectFactory factory,
909+
@Cached PythonObjectFactory factory,
911910
@Cached PRaiseNode.Lazy raiseNode) {
912911
PTextIO.CookieType cookie = getCookie(frame, inliningTarget, self, writeFlushNode, callMethodFlush, callMethodTell, asLongNode);
913912
byte[] snapshotNextInput = self.getSnapshotNextInput();
@@ -957,7 +956,7 @@ static Object tell(VirtualFrame frame, PTextIO self,
957956

958957
/* The returned cookie corresponds to the last safe start point. */
959958
cookie.charsToSkip = decodedCharsUsed;
960-
return PTextIO.CookieType.build(cookie, factory);
959+
return PTextIO.CookieType.build(cookie);
961960
}
962961

963962
int charsDecoded = 0;
@@ -1007,7 +1006,7 @@ static Object tell(VirtualFrame frame, PTextIO self,
10071006

10081007
/* The returned cookie corresponds to the last safe start point. */
10091008
cookie.charsToSkip = decodedCharsUsed;
1010-
return PTextIO.CookieType.build(cookie, factory);
1009+
return PTextIO.CookieType.build(cookie);
10111010
}
10121011

10131012
static void fail(VirtualFrame frame, Node inliningTarget, PTextIO self, Object savedState,

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PUnpickler.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -696,12 +696,12 @@ protected HashingStorageAddAllToOther ensureHashingStorageAddAllToOther() {
696696
return addAllToOther;
697697
}
698698

699-
protected Object longFromBytes(byte[] data, boolean bigEndian) {
699+
protected Object longFromBytes(byte[] data, boolean littleEndian) {
700700
if (pyLongFromByteArray == null) {
701701
CompilerDirectives.transferToInterpreterAndInvalidate();
702702
pyLongFromByteArray = insert(IntNodesFactory.PyLongFromByteArrayNodeGen.create());
703703
}
704-
return pyLongFromByteArray.executeCached(data, bigEndian);
704+
return pyLongFromByteArray.executeCached(data, littleEndian, true);
705705
}
706706

707707
protected void setAttribute(VirtualFrame frame, Object object, Object key, Object value) {
@@ -910,7 +910,7 @@ private void loadCountedLong(VirtualFrame frame, PUnpickler self, int n) {
910910
} else {
911911
// Read the raw little-endian bytes and convert.
912912
final ByteArrayView pdata = read(frame, self, size);
913-
value = longFromBytes(pdata.getBytes(size), false);
913+
value = longFromBytes(pdata.getBytes(size), true);
914914
}
915915
pDataPush(self, value);
916916
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/CApiFunction.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,6 @@
5656
import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.CONST_PY_SSIZE_T_PTR;
5757
import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.CONST_PY_UCS4;
5858
import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.CONST_PY_UNICODE;
59-
import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.CONST_UNSIGNED_CHAR_PTR;
6059
import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.CONST_VOID_PTR;
6160
import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.CONST_VOID_PTR_LIST;
6261
import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.CONST_WCHAR_PTR;
@@ -1066,7 +1065,6 @@ public final class CApiFunction {
10661065
@CApiBuiltin(name = "_PyLong_DivmodNear", ret = PyObject, args = {PyObject, PyObject}, call = NotImplemented)
10671066
@CApiBuiltin(name = "_PyLong_Format", ret = PyObject, args = {PyObject, Int}, call = NotImplemented)
10681067
@CApiBuiltin(name = "_PyLong_Frexp", ret = Double, args = {PyLongObject, PY_SSIZE_T_PTR}, call = NotImplemented)
1069-
@CApiBuiltin(name = "_PyLong_FromByteArray", ret = PyObject, args = {CONST_UNSIGNED_CHAR_PTR, SIZE_T, Int, Int}, call = NotImplemented)
10701068
@CApiBuiltin(name = "_PyLong_FromBytes", ret = PyObject, args = {ConstCharPtrAsTruffleString, Py_ssize_t, Int}, call = NotImplemented)
10711069
@CApiBuiltin(name = "_PyLong_GCD", ret = PyObject, args = {PyObject, PyObject}, call = NotImplemented)
10721070
@CApiBuiltin(name = "_PyLong_Lshift", ret = PyObject, args = {PyObject, SIZE_T}, call = NotImplemented)

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/transitions/ArgDescriptor.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ public enum ArgDescriptor {
184184
CONST_PY_UNICODE("const Py_UNICODE*"),
185185
CONST_PYCONFIG_PTR("const PyConfig*"),
186186
CONST_PYPRECONFIG_PTR("const PyPreConfig*"),
187-
CONST_UNSIGNED_CHAR_PTR("const unsigned char*"),
187+
CONST_UNSIGNED_CHAR_PTR(ArgBehavior.Pointer, "const unsigned char*"),
188188
CONST_VOID_PTR(ArgBehavior.Pointer, "const void*"),
189189
CONST_VOID_PTR_LIST("const void**"),
190190
CONST_WCHAR_PTR(ArgBehavior.Pointer, "const wchar_t*"),

0 commit comments

Comments
 (0)