Skip to content

Commit cca1881

Browse files
committed
[GR-34614][GR-44689] More fixes for PyTorch - native tuples, destructors
PullRequest: graalpython/2671
2 parents 43b4afb + af3b39a commit cca1881

File tree

19 files changed

+587
-236
lines changed

19 files changed

+587
-236
lines changed

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ static void object_dealloc(PyObject *self) {
9898

9999
/* prototype */
100100
PyObject* PyTruffle_Tuple_Alloc(PyTypeObject* cls, Py_ssize_t nitems);
101+
void PyTruffle_Tuple_Dealloc(PyTupleObject* tuple);
101102

102103
PyAPI_DATA(PyTypeObject) _PyExc_BaseException;
103104
PyAPI_DATA(PyTypeObject) _PyExc_StopIteration;
@@ -145,7 +146,7 @@ PyTypeObject PySlice_Type = PY_TRUFFLE_TYPE("slice", &PyType_Type, Py_TPFLAG
145146
PyTypeObject PyStaticMethod_Type = PY_TRUFFLE_TYPE("staticmethod", &PyType_Type, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, sizeof(PyType_Type));
146147
PyTypeObject PySuper_Type = PY_TRUFFLE_TYPE("super", &PyType_Type, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE, sizeof(superobject));
147148
PyTypeObject PyTraceBack_Type = PY_TRUFFLE_TYPE("traceback", &PyType_Type, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, sizeof(PyTypeObject));
148-
PyTypeObject PyTuple_Type = PY_TRUFFLE_TYPE_GENERIC("tuple", &PyType_Type, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_TUPLE_SUBCLASS | _Py_TPFLAGS_MATCH_SELF | Py_TPFLAGS_SEQUENCE, sizeof(PyTupleObject) - sizeof(PyObject *), sizeof(PyObject *), PyTruffle_Tuple_Alloc, 0, 0, 0);
149+
PyTypeObject PyTuple_Type = PY_TRUFFLE_TYPE_GENERIC("tuple", &PyType_Type, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_TUPLE_SUBCLASS | _Py_TPFLAGS_MATCH_SELF | Py_TPFLAGS_SEQUENCE, sizeof(PyTupleObject) - sizeof(PyObject *), sizeof(PyObject *), PyTruffle_Tuple_Alloc, (destructor)PyTruffle_Tuple_Dealloc, 0, 0);
149150
PyTypeObject PyType_Type = PY_TRUFFLE_TYPE_WITH_ITEMSIZE("type", &PyType_Type, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_TYPE_SUBCLASS, sizeof(PyHeapTypeObject), sizeof(PyMemberDef));
150151
PyTypeObject PyUnicode_Type = PY_TRUFFLE_TYPE("str", &PyType_Type, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_UNICODE_SUBCLASS | _Py_TPFLAGS_MATCH_SELF, sizeof(PyUnicodeObject));
151152
/* NOTE: we use the same Python type (namely 'PBuiltinFunction') for 'wrapper_descriptor' as for 'method_descriptor'; so the flags must be the same! */
@@ -906,6 +907,10 @@ void PyTruffle_ObjectArrayFree(PyObject** array, int32_t size) {
906907
free(array);
907908
}
908909

910+
void PyTruffle_SetStorageItem(PyObject** ptr, int32_t index, PyObject* newitem) {
911+
Py_XSETREF(ptr[index], newitem);
912+
}
913+
909914
PyAPI_FUNC(Py_ssize_t) PyTruffle_Object_Size(PyObject *op) {
910915
return ((PyVarObject*)op)->ob_size;
911916
}

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

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2019, 2023, 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
@@ -40,18 +40,15 @@
4040
*/
4141
#include "capi.h"
4242

43+
int Py_IsInitialized(void) {
44+
return 1;
45+
}
46+
47+
#ifndef COMPILING_NATIVE_CAPI
4348
void _Py_NO_RETURN _Py_FatalErrorFunc(const char *func, const char *msg) {
4449
GraalPyTruffle_FatalErrorFunc(func != NULL? truffleString(func): NULL, truffleString(msg), -1);
4550
/* If the above upcall returns, then we just fall through to the 'abort' call. */
4651
abort();
4752
}
53+
#endif // COMPILING_NATIVE_CAPI
4854

49-
PyOS_sighandler_t PyOS_setsig(int sig, PyOS_sighandler_t handler) {
50-
PyErr_SetString(PyExc_SystemError, "'PyOS_setsig' not implemented");
51-
return NULL;
52-
}
53-
54-
int PyOS_InterruptOccurred(void) {
55-
PyErr_SetString(PyExc_SystemError, "'PyOS_InterruptOccurred' not implemented");
56-
return -1;
57-
}

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

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,6 @@ PyObject * tuple_subtype_new(PyTypeObject *type, PyObject *iterable) {
7979
if (newobj == NULL) {
8080
return NULL;
8181
}
82-
newobj->ob_item = (PyObject **) ((char *)newobj + offsetof(PyTupleObject, ob_item) + sizeof(PyObject **));
8382

8483
// This polyglot type cast is important such that we can directly read and
8584
// write members of the pointer from Java code.
@@ -95,15 +94,6 @@ PyObject * tuple_subtype_new(PyTypeObject *type, PyObject *iterable) {
9594
return (PyObject*) newobj;
9695
}
9796

98-
int PyTruffle_Tuple_SetItem(PyObject* tuple, Py_ssize_t position, PyObject* item) {
99-
PyTuple_SET_ITEM(tuple, position, item);
100-
return 0;
101-
}
102-
103-
PyObject* PyTruffle_Tuple_GetItem(PyObject* tuple, Py_ssize_t position) {
104-
return PyTuple_GET_ITEM(tuple, position);
105-
}
106-
10797
PyObject* PyTruffle_Tuple_Alloc(PyTypeObject* cls, Py_ssize_t nitems) {
10898
/*
10999
* TODO(fa): For 'PyVarObjects' (i.e. 'nitems > 0') we increase the size by 'sizeof(void *)'
@@ -118,6 +108,22 @@ PyObject* PyTruffle_Tuple_Alloc(PyTypeObject* cls, Py_ssize_t nitems) {
118108
*((PyObject **) ((char *)newObj + cls->tp_dictoffset)) = NULL;
119109
}
120110
PyObject_INIT_VAR(newObj, cls, nitems);
111+
((PyTupleObject*)newObj)->ob_item = (PyObject **) ((char *)newObj + offsetof(PyTupleObject, ob_item) + sizeof(PyObject **));
121112
return newObj;
122113
}
123114

115+
void PyTruffle_Tuple_Dealloc(PyTupleObject* self) {
116+
Py_ssize_t len = PyTuple_GET_SIZE(self);
117+
if (len > 0) {
118+
Py_ssize_t i = len;
119+
while (--i >= 0) {
120+
Py_XDECREF(self->ob_item[i]);
121+
}
122+
}
123+
Py_TYPE(self)->tp_free((PyObject *)self);
124+
}
125+
126+
void* PyTruffle_NativeTupleItems(PyTupleObject* tuple) {
127+
return polyglot_from_PyObjectPtr_array(tuple->ob_item, tuple->ob_base.ob_size);
128+
}
129+

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

Lines changed: 24 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2018, 2023, 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
@@ -306,29 +306,31 @@ static void inherit_slots(PyTypeObject *type, PyTypeObject *base) {
306306
COPYSLOT(tp_iter);
307307
COPYSLOT(tp_iternext);
308308
}
309-
310-
if ((PyTypeObject_tp_flags(type) & Py_TPFLAGS_HAVE_FINALIZE) &&
311-
(PyTypeObject_tp_flags(base) & Py_TPFLAGS_HAVE_FINALIZE)) {
312-
COPYSLOT(tp_finalize);
313-
}
314-
if ((PyTypeObject_tp_flags(type) & Py_TPFLAGS_HAVE_GC) ==
315-
(PyTypeObject_tp_flags(base) & Py_TPFLAGS_HAVE_GC)) {
316-
/* They agree about gc. */
317-
COPYSLOT(tp_free);
318-
}
319-
else if ((PyTypeObject_tp_flags(type) & Py_TPFLAGS_HAVE_GC) &&
320-
PyTypeObject_tp_free(type) == NULL &&
321-
PyTypeObject_tp_free(base) == PyObject_Free) {
322-
/* A bit of magic to plug in the correct default
323-
* tp_free function when a derived class adds gc,
324-
* didn't define tp_free, and the base uses the
325-
* default non-gc tp_free.
309+
{
310+
COPYSLOT(tp_alloc);
311+
if ((PyTypeObject_tp_flags(type) & Py_TPFLAGS_HAVE_FINALIZE) &&
312+
(PyTypeObject_tp_flags(base) & Py_TPFLAGS_HAVE_FINALIZE)) {
313+
COPYSLOT(tp_finalize);
314+
}
315+
if ((PyTypeObject_tp_flags(type) & Py_TPFLAGS_HAVE_GC) ==
316+
(PyTypeObject_tp_flags(base) & Py_TPFLAGS_HAVE_GC)) {
317+
/* They agree about gc. */
318+
COPYSLOT(tp_free);
319+
}
320+
else if ((PyTypeObject_tp_flags(type) & Py_TPFLAGS_HAVE_GC) &&
321+
PyTypeObject_tp_free(type) == NULL &&
322+
PyTypeObject_tp_free(base) == PyObject_Free) {
323+
/* A bit of magic to plug in the correct default
324+
* tp_free function when a derived class adds gc,
325+
* didn't define tp_free, and the base uses the
326+
* default non-gc tp_free.
327+
*/
328+
set_PyTypeObject_tp_free(type, PyObject_GC_Del);
329+
}
330+
/* else they didn't agree about gc, and there isn't something
331+
* obvious to be done -- the type is on its own.
326332
*/
327-
set_PyTypeObject_tp_free(type, PyObject_GC_Del);
328333
}
329-
/* else they didn't agree about gc, and there isn't something
330-
* obvious to be done -- the type is on its own.
331-
*/
332334
}
333335

334336
static int add_member(PyTypeObject* cls, PyObject* type_dict, const char* mname, int mtype, Py_ssize_t moffset, int mflags, char* mdoc) {

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

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3354,10 +3354,8 @@ PyAPI_FUNC(PyObject*) PyOS_FSPath(PyObject* a) {
33543354
PyObject* result = (PyObject*) __target__PyOS_FSPath(a);
33553355
return result;
33563356
}
3357-
int (*__target__PyOS_InterruptOccurred)() = NULL;
33583357
PyAPI_FUNC(int) PyOS_InterruptOccurred() {
3359-
int result = (int) __target__PyOS_InterruptOccurred();
3360-
return result;
3358+
unimplemented("PyOS_InterruptOccurred"); exit(-1);
33613359
}
33623360
PyAPI_FUNC(char*) PyOS_Readline(FILE* a, FILE* b, const char* c) {
33633361
unimplemented("PyOS_Readline"); exit(-1);
@@ -3376,10 +3374,8 @@ PyAPI_FUNC(int) PyOS_mystricmp(const char* a, const char* b) {
33763374
PyAPI_FUNC(int) PyOS_mystrnicmp(const char* a, const char* b, Py_ssize_t c) {
33773375
unimplemented("PyOS_mystrnicmp"); exit(-1);
33783376
}
3379-
PyOS_sighandler_t (*__target__PyOS_setsig)(int, PyOS_sighandler_t) = NULL;
33803377
PyAPI_FUNC(PyOS_sighandler_t) PyOS_setsig(int a, PyOS_sighandler_t b) {
3381-
PyOS_sighandler_t result = (PyOS_sighandler_t) __target__PyOS_setsig(a, b);
3382-
return result;
3378+
unimplemented("PyOS_setsig"); exit(-1);
33833379
}
33843380
double (*__target__PyOS_string_to_double)(const char*, char**, PyObject*) = NULL;
33853381
PyAPI_FUNC(double) PyOS_string_to_double(const char* a, char** b, PyObject* c) {
@@ -4957,9 +4953,6 @@ PyAPI_FUNC(int) Py_IsFalse(PyObject* a) {
49574953
int result = (int) __target__Py_IsFalse(a);
49584954
return result;
49594955
}
4960-
PyAPI_FUNC(int) Py_IsInitialized() {
4961-
unimplemented("Py_IsInitialized"); exit(-1);
4962-
}
49634956
int (*__target__Py_IsNone)(PyObject*) = NULL;
49644957
PyAPI_FUNC(int) Py_IsNone(PyObject* a) {
49654958
int result = (int) __target__Py_IsNone(a);
@@ -6879,9 +6872,7 @@ void initializeCAPIForwards(void* (*getAPI)(const char*)) {
68796872
__target__PyNumber_TrueDivide = getAPI("PyNumber_TrueDivide");
68806873
__target__PyNumber_Xor = getAPI("PyNumber_Xor");
68816874
__target__PyOS_FSPath = getAPI("PyOS_FSPath");
6882-
__target__PyOS_InterruptOccurred = getAPI("PyOS_InterruptOccurred");
68836875
__target__PyOS_double_to_string = getAPI("PyOS_double_to_string");
6884-
__target__PyOS_setsig = getAPI("PyOS_setsig");
68856876
__target__PyOS_string_to_double = getAPI("PyOS_string_to_double");
68866877
__target__PyOS_strtol = getAPI("PyOS_strtol");
68876878
__target__PyOS_strtoul = getAPI("PyOS_strtoul");

graalpython/com.oracle.graal.python.jni/src/capi_native.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,16 @@ void Py_IncRef(PyObject *a) {
422422
}
423423
*/
424424

425+
/*
426+
This is a workaround for C++ modules, namely PyTorch, that declare global/static variables with destructors that call
427+
_Py_DECREF. The destructors get called by libc during exit during which we cannot make upcalls as that would segfault.
428+
So we rebind them to no-ops when exitting.
429+
*/
430+
static void nop_Py_DecRef(PyObject* obj) {}
431+
void finalizeCAPI() {
432+
__target___Py_DecRef = nop_Py_DecRef;
433+
__target__Py_DecRef = nop_Py_DecRef;
434+
}
425435

426436
PyObject* PyTuple_Pack(Py_ssize_t n, ...) {
427437
va_list vargs;
@@ -557,11 +567,13 @@ char _PyByteArray_empty_string[] = "";
557567
* The following source files contain code that can be compiled directly and does not need to be called via stubs in Sulong:
558568
*/
559569

570+
#define COMPILING_NATIVE_CAPI
560571
#include "_warnings.c"
561572
#include "boolobject.c"
562573
#include "complexobject.c"
563574
#include "dictobject.c"
564575
#include "modsupport_shared.c"
576+
#include "pylifecycle.c"
565577

566578
/*
567579
* This mirrors the definition in capi.c that we us on Sulong, and needs to be

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -490,7 +490,7 @@ def CPyExtType(name, code, **kwargs):
490490
{includes}
491491
492492
typedef struct {{
493-
PyObject_HEAD;
493+
{struct_base};
494494
{cmembers}
495495
}} {name}Object;
496496
@@ -636,6 +636,7 @@ def CPyExtType(name, code, **kwargs):
636636
kwargs.setdefault("tp_free", "PyObject_Del")
637637
kwargs.setdefault("cmembers", "")
638638
kwargs.setdefault("includes", "")
639+
kwargs.setdefault("struct_base", "PyObject_HEAD")
639640
c_source = UnseenFormatter().format(template, **kwargs)
640641

641642
source_file = "%s/%s.c" % (__dir__, name)

0 commit comments

Comments
 (0)