Skip to content

Commit fc1d5bd

Browse files
committed
[GR-47145][GR-45804] Various fixes for MCD
PullRequest: graalpython/2866
2 parents ab8aa20 + 4db48d3 commit fc1d5bd

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+1039
-1229
lines changed

graalpython/com.oracle.graal.python.cext/include/listobject.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright (c) 2018, 2022, Oracle and/or its affiliates.
1+
/* Copyright (c) 2018, 2023, Oracle and/or its affiliates.
22
* Copyright (C) 1996-2017 Python Software Foundation
33
*
44
* Licensed under the PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
@@ -45,6 +45,11 @@ PyAPI_FUNC(int) PyList_Sort(PyObject *);
4545
PyAPI_FUNC(int) PyList_Reverse(PyObject *);
4646
PyAPI_FUNC(PyObject *) PyList_AsTuple(PyObject *);
4747

48+
/*
49+
* GraalPy-specific, used to implement cython's array.resize_smart
50+
*/
51+
PyAPI_FUNC(int) _PyArray_Resize(PyObject* array, Py_ssize_t new_size);
52+
4853
#ifndef Py_LIMITED_API
4954
# define Py_CPYTHON_LISTOBJECT_H
5055
# include "cpython/listobject.h"

graalpython/com.oracle.graal.python.cext/src/capi.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2420,6 +2420,10 @@ PyAPI_FUNC(PyObject*) Py_GenericAlias(PyObject* a, PyObject* b) {
24202420
PyAPI_FUNC(void) Py_LeaveRecursiveCall() {
24212421
GraalPy_LeaveRecursiveCall();
24222422
}
2423+
#undef _PyArray_Resize
2424+
PyAPI_FUNC(int) _PyArray_Resize(PyObject* a, Py_ssize_t b) {
2425+
return Graal_PyArray_Resize(a, b);
2426+
}
24232427
#undef _PyBytes_Join
24242428
PyAPI_FUNC(PyObject*) _PyBytes_Join(PyObject* a, PyObject* b) {
24252429
return Graal_PyBytes_Join(a, b);

graalpython/com.oracle.graal.python.cext/src/capi.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -607,6 +607,7 @@ typedef struct {
607607
BUILTIN(Py_set_PyTypeObject_tp_vectorcall_offset, void, PyTypeObject*, Py_ssize_t) \
608608
BUILTIN(Py_set_PyTypeObject_tp_weaklistoffset, void, PyTypeObject*, Py_ssize_t) \
609609
BUILTIN(Py_set_PyVarObject_ob_size, void, PyVarObject*, Py_ssize_t) \
610+
BUILTIN(_PyArray_Resize, int, PyObject*, Py_ssize_t) \
610611
BUILTIN(_PyBytes_Join, PyObject*, PyObject*, PyObject*) \
611612
BUILTIN(_PyDict_Pop, PyObject*, PyObject*, PyObject*, PyObject*) \
612613
BUILTIN(_PyDict_SetItem_KnownHash, int, PyObject*, PyObject*, PyObject*, Py_hash_t) \

graalpython/com.oracle.graal.python.jni/src/capi_forwards.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1236,6 +1236,7 @@ void unimplemented(const char* name) {
12361236
#undef _PyArg_VaParseTupleAndKeywordsFast_SizeT
12371237
#undef _PyArg_VaParseTupleAndKeywords_SizeT
12381238
#undef _PyArg_VaParse_SizeT
1239+
#undef _PyArray_Resize
12391240
#undef _PyAsyncGenValueWrapperNew
12401241
#undef _PyByteArray_Start
12411242
#undef _PyBytesWriter_Alloc
@@ -4797,6 +4798,10 @@ PyAPI_FUNC(int) _PyArg_VaParse_SizeT(PyObject* a, const char* b, va_list c) {
47974798
int result = (int) __target___PyArg_VaParse_SizeT(a, b, c);
47984799
return result;
47994800
}
4801+
PyAPI_FUNC(int) _PyArray_Resize(PyObject* a, Py_ssize_t b) {
4802+
int result = (int) Graal_PyArray_Resize(a, b);
4803+
return result;
4804+
}
48004805
PyAPI_FUNC(PyObject*) _PyAsyncGenValueWrapperNew(PyObject* a) {
48014806
unimplemented("_PyAsyncGenValueWrapperNew"); exit(-1);
48024807
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -426,6 +426,7 @@ def __get__(self, instance, typ=None):
426426
return self
427427
else:
428428
CPyExtFunction.test.__name__ = self.name
429+
CPyExtFunction.test.__qualname__ = f'{CPyExtFunction.__name__}.test_{self.name}'
429430
return self.test
430431

431432

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
# Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
2+
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3+
#
4+
# The Universal Permissive License (UPL), Version 1.0
5+
#
6+
# Subject to the condition set forth below, permission is hereby granted to any
7+
# person obtaining a copy of this software, associated documentation and/or
8+
# data (collectively the "Software"), free of charge and under any and all
9+
# copyright rights in the Software, and any and all patent rights owned or
10+
# freely licensable by each licensor hereunder covering either (i) the
11+
# unmodified Software as contributed to or provided by such licensor, or (ii)
12+
# the Larger Works (as defined below), to deal in both
13+
#
14+
# (a) the Software, and
15+
#
16+
# (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
17+
# one is included with the Software each a "Larger Work" to which the Software
18+
# is contributed by such licensors),
19+
#
20+
# without restriction, including without limitation the rights to copy, create
21+
# derivative works of, display, perform, and distribute the Software and make,
22+
# use, sell, offer for sale, import, export, have made, and have sold the
23+
# Software and the Larger Work(s), and to sublicense the foregoing rights on
24+
# either these or other terms.
25+
#
26+
# This license is subject to the following condition:
27+
#
28+
# The above copyright notice and either this complete permission notice or at a
29+
# minimum a reference to the UPL must be included in all copies or substantial
30+
# portions of the Software.
31+
#
32+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
33+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
34+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
35+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
36+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
37+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
38+
# SOFTWARE.
39+
import sys
40+
from array import array
41+
42+
from tests.cpyext import CPyExtTestCase, CPyExtFunction, unhandled_error_compare
43+
44+
45+
def reference_array_resize(args):
46+
a, n = args
47+
if n < len(a):
48+
del a[n:]
49+
else:
50+
a.extend([0 for i in range(n - len(a))])
51+
return a
52+
53+
54+
class TestPyArray(CPyExtTestCase):
55+
56+
def compile_module(self, name):
57+
type(self).mro()[1].__dict__["test_%s" % name].create_module(name)
58+
super().compile_module(name)
59+
60+
if sys.implementation.name == 'graalpy':
61+
test__PyArray_Resize = CPyExtFunction(
62+
reference_array_resize,
63+
lambda: (
64+
(array('i', [1, 2, 3]), 1),
65+
(array('i'), 3),
66+
),
67+
code="""
68+
PyObject* wrap__PyArray_Resize(PyObject* array, Py_ssize_t new_size) {
69+
if (_PyArray_Resize(array, new_size) < 0)
70+
return NULL;
71+
Py_INCREF(array);
72+
return array;
73+
}
74+
""",
75+
callfunction="wrap__PyArray_Resize",
76+
resultspec="O",
77+
argspec='On',
78+
arguments=["PyObject* array", "Py_ssize_t new_size"],
79+
cmpfunc=unhandled_error_compare,
80+
)

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

Lines changed: 107 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,15 @@
3636
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
3737
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
3838
# SOFTWARE.
39+
import math
40+
41+
from . import CPyExtType, CPyExtTestCase, CPyExtFunction, CPyExtFunctionOutVars, unhandled_error_compare, \
42+
is_native_object
3943

40-
import sys
41-
from . import CPyExtType, CPyExtTestCase, CPyExtFunction, CPyExtFunctionOutVars, unhandled_error_compare, GRAALPYTHON
4244
__dir__ = __file__.rpartition("/")[0]
4345

4446

4547
def _float_compare(x, y):
46-
4748
def isNan(x):
4849
return isinstance(x, float) and x != x
4950

@@ -77,6 +78,17 @@ def __float__(self):
7778
return 2.71828
7879

7980

81+
NativeFloatSubclass = CPyExtType(
82+
'TestFloatNativeFloatSubclass',
83+
'',
84+
struct_base='PyFloatObject base',
85+
tp_base="&PyFloat_Type",
86+
tp_new='0',
87+
tp_alloc='0',
88+
tp_free='0',
89+
)
90+
91+
8092
class TestPyFloat(CPyExtTestCase):
8193

8294
def compile_module(self, name):
@@ -185,39 +197,107 @@ def compile_module(self, name):
185197
cmpfunc=unhandled_error_compare
186198
)
187199

200+
188201
class TestPyOSDouble:
189202
def test_PyOS_double_to_string(self):
190-
TestPyOS_Double_To_String = CPyExtType("TestPyOS_Double_To_String",
191-
'''
192-
static PyObject* testPyOS_D_to_Str(PyObject* self, PyObject *pyval) {
193-
double val = PyFloat_AsDouble(pyval);
194-
char *str = PyOS_double_to_string(val, 'f', 6, 0x2, NULL);
195-
return PyUnicode_FromString(str);
196-
}
197-
''',
198-
tp_methods='{"PyOS_double_to_string_test", (PyCFunction)testPyOS_D_to_Str, METH_O, ""}',
199-
)
203+
TestPyOS_Double_To_String = CPyExtType(
204+
"TestPyOS_Double_To_String",
205+
'''
206+
static PyObject* testPyOS_D_to_Str(PyObject* self, PyObject *pyval) {
207+
double val = PyFloat_AsDouble(pyval);
208+
char *str = PyOS_double_to_string(val, 'f', 6, 0x2, NULL);
209+
return PyUnicode_FromString(str);
210+
}
211+
''',
212+
tp_methods='{"PyOS_double_to_string_test", (PyCFunction)testPyOS_D_to_Str, METH_O, ""}',
213+
)
200214
tester = TestPyOS_Double_To_String()
201215
assert tester.PyOS_double_to_string_test(150.604459) == '150.604459'
202216
assert tester.PyOS_double_to_string_test(174.426353) == '174.426353'
203217
assert tester.PyOS_double_to_string_test(151.074362) == '151.074362'
204218
assert tester.PyOS_double_to_string_test(190.08) == '190.080000'
205219

206220
def test_PyOS_string_to_double(self):
207-
TestPyOS_String_To_Double = CPyExtType("TestPyOS_String_To_Double",
208-
'''
209-
static PyObject* testPyOS_Str_to_D(PyObject* self, PyObject *str) {
210-
char *endptr;
211-
const char *s = (char *) PyUnicode_AsUTF8(str);
212-
double ret = PyOS_string_to_double(s, &endptr, NULL);
213-
if (PyErr_Occurred()) {
214-
return NULL;
215-
}
216-
return PyFloat_FromDouble(ret);
217-
}
218-
''',
219-
tp_methods='{"PyOS_string_to_double_test", (PyCFunction)testPyOS_Str_to_D, METH_O, ""}',
220-
)
221+
TestPyOS_String_To_Double = CPyExtType(
222+
"TestPyOS_String_To_Double",
223+
'''
224+
static PyObject* testPyOS_Str_to_D(PyObject* self, PyObject *str) {
225+
char *endptr;
226+
const char *s = (char *) PyUnicode_AsUTF8(str);
227+
double ret = PyOS_string_to_double(s, &endptr, NULL);
228+
if (PyErr_Occurred()) {
229+
return NULL;
230+
}
231+
return PyFloat_FromDouble(ret);
232+
}
233+
''',
234+
tp_methods='{"PyOS_string_to_double_test", (PyCFunction)testPyOS_Str_to_D, METH_O, ""}',
235+
)
221236
tester = TestPyOS_String_To_Double()
222237
assert tester.PyOS_string_to_double_test('5') == float(5)
223238
assert tester.PyOS_string_to_double_test('150.604459') == float(150.604459)
239+
240+
241+
class TestNativeFloatSubclass:
242+
def test_create(self):
243+
f = NativeFloatSubclass(1.0)
244+
assert is_native_object(f)
245+
246+
class ManagedSubclass(NativeFloatSubclass):
247+
pass
248+
249+
f = ManagedSubclass(1.0)
250+
assert is_native_object(f)
251+
252+
def test_methods(self):
253+
f = NativeFloatSubclass(1.1)
254+
zero = NativeFloatSubclass(0.0)
255+
nan = NativeFloatSubclass('nan')
256+
257+
assert bool(f)
258+
assert not bool(zero)
259+
260+
assert f == 1.1
261+
assert nan != nan
262+
assert f != zero
263+
assert +f == 1.1
264+
assert -f == -1.1
265+
assert f > 0
266+
assert f < 2
267+
assert f >= 1.1
268+
assert f <= 1.1
269+
assert str(f) == '1.1'
270+
assert repr(f) == '1.1'
271+
assert int(f) == 1
272+
assert format(f, 'f') == '1.100000'
273+
assert abs(NativeFloatSubclass(-2.1)) == 2.1
274+
assert round(f) == 1.0
275+
assert f + 1.0 == 2.1
276+
assert 1.0 + f == 2.1
277+
assert f * 2 == 2.2
278+
assert f - 1.6 == -0.5
279+
assert f // 2 == 0.0
280+
assert f % 2 == 1.1
281+
assert f / 2.0 == 0.55
282+
assert f ** 0 == 1.0
283+
assert divmod(f, 2) == (0.0, 1.1)
284+
assert hash(f) == hash(1.1)
285+
assert f.hex() == (1.1).hex()
286+
assert f.real == 1.1
287+
assert f.imag == 0.0
288+
assert f.conjugate() == 1.1
289+
assert not f.is_integer()
290+
assert f.as_integer_ratio() == (1.1).as_integer_ratio()
291+
assert f.__getnewargs__() == (1.1,)
292+
293+
def test_math(self):
294+
assert math.isnan(NativeFloatSubclass('nan'))
295+
assert math.isinf(NativeFloatSubclass('inf'))
296+
assert not math.isfinite(NativeFloatSubclass('inf'))
297+
f = NativeFloatSubclass(0.9)
298+
for fn in [math.ceil, math.floor, math.sqrt, math.exp, math.expm1, math.frexp, math.modf, math.sin, math.asin,
299+
math.cos, math.acos, math.tan, math.atan, math.log2, math.log10, math.log1p, math.fabs, math.trunc,
300+
math.degrees, math.radians, math.gamma, math.lgamma, math.sqrt]:
301+
assert fn(f) == fn(0.9)
302+
303+
assert math.log(f, 10) == math.log(0.9, 10)

0 commit comments

Comments
 (0)