Skip to content

Commit 40edc74

Browse files
committed
[GR-54287] Support numpy 2.0
PullRequest: graalpython/3349
2 parents 28ffa30 + 7fbb404 commit 40edc74

File tree

13 files changed

+238
-47
lines changed

13 files changed

+238
-47
lines changed

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright (c) 2018, 2023, Oracle and/or its affiliates.
1+
/* Copyright (c) 2018, 2024, Oracle and/or its affiliates.
22
* Copyright (C) 1996-2020 Python Software Foundation
33
*
44
* Licensed under the PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
@@ -125,6 +125,10 @@ PyAPI_FUNC(PyObject *) PyCMethod_New(PyMethodDef *, PyObject *,
125125
#define METH_METHOD 0x0200
126126
#endif
127127

128+
// GraalPy public API functions
129+
PyAPI_FUNC(const char*) GraalPyCFunction_GetDoc(PyObject *func);
130+
PyAPI_FUNC(void) GraalPyCFunction_SetDoc(PyObject *func, const char *doc);
131+
128132

129133
#ifndef Py_LIMITED_API
130134
# define Py_CPYTHON_METHODOBJECT_H

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,3 +102,17 @@ void _PyCFunction_SetModule(PyObject *func, PyObject *mod) {
102102
void _PyCFunction_SetMethodDef(PyObject *func, PyMethodDef *def) {
103103
set_PyCFunctionObject_m_ml(func, def);
104104
}
105+
106+
// GraalPy additions
107+
const char *
108+
GraalPyCFunction_GetDoc(PyObject *func) {
109+
return PyCFunctionObject_m_ml(func)->ml_doc;
110+
}
111+
112+
void
113+
GraalPyCFunction_SetDoc(PyObject *func, const char *doc) {
114+
PyCFunctionObject_m_ml(func)->ml_doc = doc;
115+
if (points_to_py_handle_space(func)) {
116+
GraalPyTruffleCFunction_SetDoc(func, doc);
117+
}
118+
}

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

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,13 @@
4545

4646
NativeTypeWithDict = CPyExtType(
4747
name='NativeTypeWithDict',
48-
cmembers='PyObject* dict;',
48+
cmembers='int some_field; PyObject* dict;',
4949
tp_dictoffset='offsetof(NativeTypeWithDictObject, dict)',
5050
tp_getset='{"__dict__", PyObject_GenericGetDict, PyObject_GenericSetDict}',
5151
)
5252

5353
NativeHeapTypeWithoutDict = CPyExtHeapType(
54+
cmembers='int some_field;',
5455
name='NativeTypeWithManagedDict',
5556
)
5657

@@ -75,7 +76,7 @@
7576

7677

7778
# TODO it would be great if we could test creating heap types with Py_TPFLAGS_MANAGED_DICT, because pybind11 does that,
78-
# but there's no way to do that without abusing abusing implementations details
79+
# but there's no way to do that without abusing implementations details
7980

8081

8182
class NativeSubtypeWithDict(NativeTypeWithDict):
@@ -107,3 +108,15 @@ def test_dict(self):
107108
self.assert_has_working_dict(NativeHeapTypeWithDict())
108109
self.assert_has_working_dict(NativeSubtypeWithDict())
109110
self.assert_has_working_dict(NativeSubtypeWithAddedDict())
111+
112+
def test_multiple_inheritance(self):
113+
class Base1(NativeTypeWithoutDict):
114+
pass
115+
116+
class Base2(NativeTypeWithoutDict):
117+
pass
118+
119+
class Derived(Base1, Base2):
120+
pass
121+
122+
self.assert_has_working_dict(Derived())

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

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2022, 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
@@ -41,16 +41,27 @@
4141
package com.oracle.graal.python.builtins.modules.cext;
4242

4343
import static com.oracle.graal.python.builtins.modules.cext.PythonCextBuiltins.CApiCallPath.Direct;
44+
import static com.oracle.graal.python.builtins.modules.cext.PythonCextBuiltins.CApiCallPath.Ignored;
45+
import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.ConstCharPtrAsTruffleString;
4446
import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.PyObject;
4547
import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.PyObjectTransfer;
48+
import static com.oracle.graal.python.nodes.SpecialAttributeNames.T___DOC__;
4649

4750
import com.oracle.graal.python.builtins.PythonBuiltinClassType;
51+
import com.oracle.graal.python.builtins.modules.cext.PythonCextBuiltins.CApiBinaryBuiltinNode;
4852
import com.oracle.graal.python.builtins.modules.cext.PythonCextBuiltins.CApiBuiltin;
4953
import com.oracle.graal.python.builtins.modules.cext.PythonCextBuiltins.CApiUnaryBuiltinNode;
54+
import com.oracle.graal.python.builtins.objects.PNone;
55+
import com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor;
56+
import com.oracle.graal.python.builtins.objects.function.PBuiltinFunction;
57+
import com.oracle.graal.python.builtins.objects.method.PBuiltinMethod;
5058
import com.oracle.graal.python.builtins.objects.method.PDecoratedMethod;
5159
import com.oracle.graal.python.runtime.object.PythonObjectFactory;
60+
import com.oracle.truffle.api.CompilerDirectives;
61+
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
5262
import com.oracle.truffle.api.dsl.Cached;
5363
import com.oracle.truffle.api.dsl.Specialization;
64+
import com.oracle.truffle.api.strings.TruffleString;
5465

5566
public final class PythonCextFuncBuiltins {
5667

@@ -73,4 +84,22 @@ static Object staticmethod(Object callable,
7384
return factory.createClassmethodFromCallableObj(callable);
7485
}
7586
}
87+
88+
@CApiBuiltin(ret = ArgDescriptor.Void, args = {PyObject, ConstCharPtrAsTruffleString}, call = Ignored)
89+
abstract static class PyTruffleCFunction_SetDoc extends CApiBinaryBuiltinNode {
90+
@Specialization
91+
@TruffleBoundary
92+
static Object set(Object functionObj, TruffleString doc) {
93+
PBuiltinFunction function;
94+
if (functionObj instanceof PBuiltinFunction builtinFunction) {
95+
function = builtinFunction;
96+
} else if (functionObj instanceof PBuiltinMethod builtinMethod) {
97+
function = builtinMethod.getBuiltinFunction();
98+
} else {
99+
throw CompilerDirectives.shouldNotReachHere("Unexpected object passed to GraalPyCFunction_SetDoc");
100+
}
101+
function.setAttribute(T___DOC__, doc != null ? doc : PNone.NONE);
102+
return PNone.NO_VALUE;
103+
}
104+
}
76105
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/type/TypeNodes.java

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2356,18 +2356,24 @@ private static void addNativeSlots(TypeNewContext ctx, PythonManagedClass python
23562356
long dictOffset = GetDictOffsetNode.executeUncached(base);
23572357
long weakListOffset = GetWeakListOffsetNode.executeUncached(base);
23582358
long itemSize = GetItemSizeNode.executeUncached(base);
2359-
if (ctx.addDict) {
2360-
if (itemSize != 0) {
2361-
dictOffset = -SIZEOF_PY_OBJECT_PTR;
2362-
} else {
2363-
dictOffset = slotOffset;
2364-
}
2359+
if (ctx.addDict && itemSize != 0) {
2360+
dictOffset = -SIZEOF_PY_OBJECT_PTR;
23652361
slotOffset += SIZEOF_PY_OBJECT_PTR;
23662362
}
23672363
if (ctx.addWeak) {
23682364
weakListOffset = slotOffset;
23692365
slotOffset += SIZEOF_PY_OBJECT_PTR;
23702366
}
2367+
if (ctx.addDict && itemSize == 0) {
2368+
long flags = GetTypeFlagsNode.executeUncached(pythonClass) | MANAGED_DICT;
2369+
SetTypeFlagsNode.executeUncached(pythonClass, flags);
2370+
/*
2371+
* Negative offsets are computed from the end of the structure. Our managed dict is
2372+
* right before the start of the object. CPython has 3 fields there, so our formula
2373+
* differs.
2374+
*/
2375+
dictOffset = -slotOffset - SIZEOF_PY_OBJECT_PTR;
2376+
}
23712377
SetDictOffsetNode.executeUncached(pythonClass, dictOffset);
23722378
SetBasicSizeNode.executeUncached(pythonClass, slotOffset);
23732379
SetItemSizeNode.executeUncached(pythonClass, itemSize);

graalpython/lib-graalpython/modules/autopatch_capi.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ def consume_whitespace_forward(idx):
156156
r'\W(ob_refcnt)\W': (replace_field_access, 'Py_REFCNT(%receiver)'),
157157
r'\W(ob_item)\W': (replace_field_access, 'PySequence_Fast_ITEMS((PyObject*)%receiver)'),
158158
r'^\s*()(std::)?free\((const_cast<char \*>)?\(?\w+->m_ml->ml_doc\)?\);': (simple_replace, '//'),
159-
r'\W(m_ml\s*->\s*ml_doc)\W': (replace_field_access, 'PyObject_GetDoc((PyObject*)(%receiver))', 'PyObject_SetDoc((PyObject*)(%receiver), %value)'),
159+
r'\W(m_ml\s*->\s*ml_doc)\W': (replace_field_access, 'GraalPyCFunction_GetDoc((PyObject*)(%receiver))', 'GraalPyCFunction_SetDoc((PyObject*)(%receiver), %value)'),
160160
# Py_CLEAR/Py_VISIT on a function's module is skipped for us, Java GC takes care of it
161161
r'(Py_(?:CLEAR|VISIT)\((?:(?:\(?\([a-zA-Z0-9_]|[a-zA-Z0-9_])(?:[a-zA-Z0-9_]|\)|\*\)|->)*)->m_module\);)': (simple_replace, ''),
162162
r'\W(m_ml)\W': (replace_field_access, '_PyCFunction_GetMethodDef((PyObject*)(%receiver))', '_PyCFunction_SetMethodDef((PyObject*)(%receiver), %value)'),

graalpython/lib-graalpython/patches/Cython/Cython-3.0.10.patch

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,9 +222,18 @@ index 3ea60f5..18d1842 100644
222222
#endif
223223
else if (PyMethod_Check(method)) {
224224
diff --git a/Cython/Utility/ModuleSetupCode.c b/Cython/Utility/ModuleSetupCode.c
225-
index d8f60a4..8ede926 100644
225+
index d8f60a4..cd61759 100644
226226
--- a/Cython/Utility/ModuleSetupCode.c
227227
+++ b/Cython/Utility/ModuleSetupCode.c
228+
@@ -113,7 +113,7 @@
229+
#undef CYTHON_USE_DICT_VERSIONS
230+
#define CYTHON_USE_DICT_VERSIONS 0
231+
#undef CYTHON_USE_EXC_INFO_STACK
232+
- #define CYTHON_USE_EXC_INFO_STACK 0
233+
+ #define CYTHON_USE_EXC_INFO_STACK 1
234+
#ifndef CYTHON_UPDATE_DESCRIPTOR_DOC
235+
#define CYTHON_UPDATE_DESCRIPTOR_DOC 0
236+
#endif
228237
@@ -995,7 +995,7 @@ static CYTHON_INLINE int __Pyx__IsSameCFunction(PyObject *func, void *cfunc) {
229238
#define __Pyx_PyFrame_SetLineNumber(frame, lineno)
230239
#else

graalpython/lib-graalpython/patches/numpy/metadata.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
[[rules]]
2+
version = '>= 2.0.0rc1, < 2.1'
3+
patch = 'numpy-2.0.0.patch'
4+
dist-type = 'sdist'
5+
ignore-rule-on-llvm = true
6+
17
[[rules]]
28
version = '== 1.26.4'
39
patch = 'numpy-1.26.4.patch'

graalpython/lib-graalpython/patches/numpy/numpy-1.26.4.patch

Lines changed: 18 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,5 @@
11
diff --git a/numpy/core/include/numpy/ndarrayobject.h b/numpy/core/include/numpy/ndarrayobject.h
22
index d4b73eb..af90a68 100644
3-
--- a/vendored-meson/meson/mesonbuild/utils/universal.py
4-
+++ b/vendored-meson/meson/mesonbuild/utils/universal.py
5-
@@ -727,6 +727,7 @@ def windows_detect_native_arch() -> str:
6-
"""
7-
if sys.platform != 'win32':
8-
return ''
9-
+ return 'amd64' # Workaround for GraalPy bug on Windows with kernel32.GetCurrentProcess()
10-
try:
11-
import ctypes
12-
process_arch = ctypes.c_ushort()
133
--- a/numpy/core/include/numpy/ndarrayobject.h
144
+++ b/numpy/core/include/numpy/ndarrayobject.h
155
@@ -225,7 +225,7 @@ NPY_TITLE_KEY_check(PyObject *key, PyObject *value)
@@ -71,46 +61,46 @@ index 2890406..353a657 100644
7161
#include <feature_detection_misc.h>
7262

7363
diff --git a/numpy/core/src/npymath/ieee754.c.src b/numpy/core/src/npymath/ieee754.c.src
74-
index 8fccc9a..e7f79e1 100644
64+
index 8fccc9a..3bb9cf0 100644
7565
--- a/numpy/core/src/npymath/ieee754.c.src
7666
+++ b/numpy/core/src/npymath/ieee754.c.src
77-
@@ -362,6 +362,17 @@ int npy_get_floatstatus_barrier(char* param)
67+
@@ -362,6 +362,11 @@ int npy_get_floatstatus_barrier(char* param)
7868
* By using a volatile, the compiler cannot reorder this call
7969
*/
8070
if (param != NULL) {
8171
+ // GraalPy change: the pointer needs to be dereferenced to establish
8272
+ // a data dependency to to ensure the compiler won't reorder the call
83-
+#define HANDLE_BASE 0x8000000000000000ULL
84-
+#define points_to_py_handle_space(PTR) ((((uintptr_t) (PTR)) & HANDLE_BASE) != 0)
85-
+#define pointer_to_stub(PTR) ((PyObject *)(((uintptr_t) (PTR)) & ~HANDLE_BASE))
8673
+ if (points_to_py_handle_space(param)) {
87-
+ param = pointer_to_stub(param);
74+
+ param = (char*)pointer_to_stub(param);
8875
+ }
89-
+#undef points_to_py_handle_space
90-
+#undef pointer_to_stub
91-
+#undef HANDLE_BASE
9276
volatile char NPY_UNUSED(c) = *(char*)param;
9377
}
9478

9579
diff --git a/numpy/core/src/npymath/ieee754.cpp b/numpy/core/src/npymath/ieee754.cpp
96-
index 1c59bf3..131985e 100644
80+
index 1c59bf3..519fabc 100644
9781
--- a/numpy/core/src/npymath/ieee754.cpp
9882
+++ b/numpy/core/src/npymath/ieee754.cpp
99-
@@ -428,6 +428,17 @@ npy_get_floatstatus_barrier(char *param)
83+
@@ -428,6 +428,11 @@ npy_get_floatstatus_barrier(char *param)
10084
* By using a volatile, the compiler cannot reorder this call
10185
*/
10286
if (param != NULL) {
10387
+ // GraalPy change: the pointer needs to be dereferenced to establish
10488
+ // a data dependency to to ensure the compiler won't reorder the call
105-
+#define HANDLE_BASE 0x8000000000000000ULL
106-
+#define points_to_py_handle_space(PTR) ((((uintptr_t) (PTR)) & HANDLE_BASE) != 0)
107-
+#define pointer_to_stub(PTR) ((PyObject *)(((uintptr_t) (PTR)) & ~HANDLE_BASE))
10889
+ if (points_to_py_handle_space(param)) {
109-
+ param = pointer_to_stub(param);
90+
+ param = (char*)pointer_to_stub(param);
11091
+ }
111-
+#undef points_to_py_handle_space
112-
+#undef pointer_to_stub
113-
+#undef HANDLE_BASE
11492
volatile char NPY_UNUSED(c) = *(char *)param;
11593
}
11694

95+
diff --git a/vendored-meson/meson/mesonbuild/utils/universal.py b/vendored-meson/meson/mesonbuild/utils/universal.py
96+
index 1694912..a555fe3 100644
97+
--- a/vendored-meson/meson/mesonbuild/utils/universal.py
98+
+++ b/vendored-meson/meson/mesonbuild/utils/universal.py
99+
@@ -727,6 +727,7 @@ def windows_detect_native_arch() -> str:
100+
"""
101+
if sys.platform != 'win32':
102+
return ''
103+
+ return 'amd64' # Workaround for GraalPy bug on Windows with kernel32.GetCurrentProcess()
104+
try:
105+
import ctypes
106+
process_arch = ctypes.c_ushort()

0 commit comments

Comments
 (0)