Skip to content

Commit 953dc00

Browse files
committed
[GR-12552] [GR-13072] [GR-17067] [GR-17531] Preparation for SciPy support
PullRequest: graalpython/580
2 parents f645159 + 27b0a31 commit 953dc00

File tree

21 files changed

+528
-139
lines changed

21 files changed

+528
-139
lines changed

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ declare_type(PyMethod_Type, method, PyMethodObject);
153153
declare_type(PyCode_Type, code, PyCodeObject);
154154
declare_type(PyFrame_Type, frame, PyFrameObject);
155155
declare_type(PyTraceBack_Type, traceback, PyTracebackObject);
156+
declare_type(_PyWeakref_RefType, ReferenceType, PyWeakReference);
156157
// Below types use the same object structure as others, and thus
157158
// POLYGLOT_DECLARE_TYPE should not be called again
158159
initialize_type(PySuper_Type, super, _object);
@@ -162,6 +163,8 @@ initialize_type(PyBool_Type, bool, _longobject);
162163
initialize_type(_PyNotImplemented_Type, NotImplementedType, _object);
163164
initialize_type(PyDictProxy_Type, mappingproxy, _object);
164165
initialize_type(PyEllipsis_Type, ellipsis, _object);
166+
initialize_type(_PyWeakref_ProxyType, ProxyType, PyWeakReference);
167+
initialize_type(_PyWeakref_CallableProxyType, CallableProxyType, PyWeakReference);
165168

166169
POLYGLOT_DECLARE_TYPE(PyThreadState);
167170

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

Lines changed: 112 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -364,14 +364,39 @@ int PyObject_Print(PyObject* object, FILE* fd, int flags) {
364364
return 0;
365365
}
366366

367-
UPCALL_ID(PyObject_GetAttr);
368-
PyObject* PyObject_GetAttrString(PyObject* obj, const char* attr) {
369-
return UPCALL_CEXT_O(_jls_PyObject_GetAttr, native_to_java(obj), polyglot_from_string(attr, SRC_CS));
367+
// taken from CPython "Objects/object.c"
368+
PyObject * PyObject_GetAttrString(PyObject *v, const char *name) {
369+
PyObject *w, *res;
370+
371+
if (Py_TYPE(v)->tp_getattr != NULL) {
372+
return (*Py_TYPE(v)->tp_getattr)(v, (char*)name);
373+
}
374+
w = PyUnicode_FromString(name);
375+
if (w == NULL) {
376+
return NULL;
377+
}
378+
res = PyObject_GetAttr(v, w);
379+
return res;
370380
}
371381

372-
UPCALL_ID(PyObject_SetAttr);
373-
int PyObject_SetAttrString(PyObject* obj, const char* attr, PyObject* value) {
374-
return UPCALL_CEXT_I(_jls_PyObject_SetAttr, native_to_java(obj), polyglot_from_string(attr, SRC_CS), native_to_java(value));
382+
383+
// taken from CPython "Objects/object.c"
384+
int PyObject_SetAttrString(PyObject *v, const char *name, PyObject *w) {
385+
PyObject *s;
386+
int res;
387+
PyTypeObject *type = Py_TYPE(v);
388+
389+
if (type->tp_setattr != NULL) {
390+
return (*type->tp_setattr)(v, (char*)name, w);
391+
}
392+
// TODO(fa): CPython interns strings; verify if that makes sense for us as well
393+
// s = PyUnicode_InternFromString(name);
394+
s = PyUnicode_FromString(name);
395+
if (s == NULL) {
396+
return -1;
397+
}
398+
res = PyObject_SetAttr(v, s, w);
399+
return res;
375400
}
376401

377402
UPCALL_ID(PyObject_HasAttr);
@@ -383,20 +408,94 @@ int PyObject_HasAttrString(PyObject* obj, const char* attr) {
383408
return UPCALL_CEXT_I(_jls_PyObject_HasAttr, native_to_java(obj), polyglot_from_string(attr, SRC_CS));
384409
}
385410

386-
PyObject* PyObject_GetAttr(PyObject* obj, PyObject* attr) {
387-
return UPCALL_CEXT_O(_jls_PyObject_GetAttr, native_to_java(obj), native_to_java(attr));
411+
/* Note: We must implement this in native because it might happen that this function is used on an
412+
uninitialized type which means that a managed attribute lookup won't work. */
413+
// taken from CPython "Objects/object.c"
414+
PyObject * PyObject_GetAttr(PyObject *v, PyObject *name) {
415+
PyTypeObject *tp = Py_TYPE(v);
416+
417+
if (!PyUnicode_Check(name)) {
418+
PyErr_Format(PyExc_TypeError,
419+
"attribute name must be string, not '%.200s'",
420+
name->ob_type->tp_name);
421+
return NULL;
422+
}
423+
if (tp->tp_getattro != NULL) {
424+
return (*tp->tp_getattro)(v, name);
425+
}
426+
if (tp->tp_getattr != NULL) {
427+
const char *name_str = PyUnicode_AsUTF8(name);
428+
if (name_str == NULL) {
429+
return NULL;
430+
}
431+
return (*tp->tp_getattr)(v, (char *)name_str);
432+
}
433+
PyErr_Format(PyExc_AttributeError,
434+
"'%.50s' object has no attribute '%U'",
435+
tp->tp_name, name);
436+
return NULL;
388437
}
389438

439+
UPCALL_ID(PyObject_GenericGetAttr);
390440
PyObject* PyObject_GenericGetAttr(PyObject* obj, PyObject* attr) {
391-
return PyObject_GetAttr(obj, attr);
441+
PyTypeObject *tp = Py_TYPE(obj);
442+
if (tp->tp_dict == NULL && PyType_Ready(tp) < 0) {
443+
return NULL;
444+
}
445+
return UPCALL_CEXT_O(_jls_PyObject_GenericGetAttr, native_to_java(obj), native_to_java(attr));
392446
}
393447

394-
int PyObject_SetAttr(PyObject* obj, PyObject* attr, PyObject* value) {
395-
return PyObject_SetAttrString(obj, as_char_pointer(attr), value);
448+
/* Note: We must implement this in native because it might happen that this function is used on an
449+
unitialized type which means that a managed attribute lookup won't work. */
450+
// taken from CPython "Objects/object.c"
451+
int PyObject_SetAttr(PyObject *v, PyObject *name, PyObject *value) {
452+
PyTypeObject *tp = Py_TYPE(v);
453+
int err;
454+
455+
if (!PyUnicode_Check(name)) {
456+
PyErr_Format(PyExc_TypeError,
457+
"attribute name must be string, not '%.200s'",
458+
name->ob_type->tp_name);
459+
return -1;
460+
}
461+
462+
// TODO(fa): CPython interns strings; verify if that makes sense for us as well
463+
// PyUnicode_InternInPlace(&name);
464+
if (tp->tp_setattro != NULL) {
465+
err = (*tp->tp_setattro)(v, name, value);
466+
return err;
467+
}
468+
if (tp->tp_setattr != NULL) {
469+
const char *name_str = PyUnicode_AsUTF8(name);
470+
if (name_str == NULL)
471+
return -1;
472+
err = (*tp->tp_setattr)(v, (char *)name_str, value);
473+
return err;
474+
}
475+
if (tp->tp_getattr == NULL && tp->tp_getattro == NULL)
476+
PyErr_Format(PyExc_TypeError,
477+
"'%.100s' object has no attributes "
478+
"(%s .%U)",
479+
tp->tp_name,
480+
value==NULL ? "del" : "assign to",
481+
name);
482+
else
483+
PyErr_Format(PyExc_TypeError,
484+
"'%.100s' object has only read-only attributes "
485+
"(%s .%U)",
486+
tp->tp_name,
487+
value==NULL ? "del" : "assign to",
488+
name);
489+
return -1;
396490
}
397491

492+
UPCALL_ID(PyObject_GenericSetAttr);
398493
int PyObject_GenericSetAttr(PyObject* obj, PyObject* attr, PyObject* value) {
399-
return PyObject_SetAttr(obj, attr, value);
494+
PyTypeObject *tp = Py_TYPE(obj);
495+
if (tp->tp_dict == NULL && PyType_Ready(tp) < 0) {
496+
return -1;
497+
}
498+
return (int) UPCALL_CEXT_L(_jls_PyObject_GenericSetAttr, native_to_java(obj), native_to_java(attr), native_to_java(value));
400499
}
401500

402501
Py_hash_t PyObject_Hash(PyObject* obj) {
@@ -471,7 +570,7 @@ PyObject* PyObject_Init(PyObject *op, PyTypeObject *tp) {
471570
return op;
472571
}
473572

474-
// taken from CPython 3.6.4 "Objects/object.c"
573+
// taken from CPython "Objects/object.c"
475574
PyVarObject * PyObject_InitVar(PyVarObject *op, PyTypeObject *tp, Py_ssize_t size) {
476575
if (op == NULL) {
477576
return (PyVarObject *) PyErr_NoMemory();

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

Lines changed: 43 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -76,19 +76,22 @@ static int add_subclass(PyTypeObject *base, PyTypeObject *type) {
7676
/* Special C landing functions that convert some arguments to primitives. */
7777

7878
static PyObject* wrap_allocfunc(allocfunc f, PyTypeObject* klass, PyObject* n) {
79-
return f(klass, PyLong_AsSsize_t(n));
79+
return native_to_java(f(klass, PyLong_AsSsize_t(n)));
8080
}
8181

8282
/* Wrapper around a native function to be called by Python code. */
8383
static PyObject* wrap_getattrfunc(getattrfunc f, PyObject* obj, PyObject* unicode) {
8484
// we really need to provide 'char *' since this often runs non-Sulong code
85-
return f(obj, as_char_pointer(unicode));
85+
return native_to_java(f(obj, as_char_pointer(unicode)));
8686
}
8787

8888
/* Wrapper around the native function to be called by Python code. */
8989
static PyObject* wrap_setattrfunc(setattrfunc f, PyObject* obj, PyObject* unicode, PyObject* value) {
9090
// we really need to provide 'char *' since this often runs non-Sulong code
91-
return f(obj, as_char_pointer(unicode), value);
91+
if (f(obj, as_char_pointer(unicode), value) < 0) {
92+
return NULL;
93+
}
94+
return Py_None;
9295
}
9396

9497
static PyObject* wrap_setattrofunc(setattrofunc f, PyObject* obj, PyObject* key, PyObject* item) {
@@ -108,7 +111,7 @@ static PyObject* wrap_descrgetfunc(descrgetfunc f, PyObject* self, PyObject* obj
108111
}
109112

110113
static PyObject* wrap_richcmpfunc(richcmpfunc f, PyObject* a, PyObject* b, PyObject* n) {
111-
return f(a, b, (int)PyLong_AsLong(n));
114+
return native_to_java(f(a, b, (int)PyLong_AsLong(n)));
112115
}
113116

114117
#undef RICHCMP_WRAPPER
@@ -182,9 +185,12 @@ static PyObject* wrap_reverse_binop(binaryfunc f, PyObject* a, PyObject* b) {
182185
return f(b, a);
183186
}
184187

185-
static void
186-
inherit_special(PyTypeObject *type, PyTypeObject *base)
187-
{
188+
UPCALL_ID(PyTruffle_Type_Modified);
189+
void PyType_Modified(PyTypeObject* type) {
190+
UPCALL_CEXT_VOID(_jls_PyTruffle_Type_Modified, native_type_to_java(type), polyglot_from_string(type->tp_name, SRC_CS), native_to_java(type->tp_mro));
191+
}
192+
193+
static void inherit_special(PyTypeObject *type, PyTypeObject *base) {
188194

189195
/* Copying basicsize is connected to the GC flags */
190196
if (!(type->tp_flags & Py_TPFLAGS_HAVE_GC) &&
@@ -245,6 +251,17 @@ inherit_special(PyTypeObject *type, PyTypeObject *base)
245251
type->tp_flags |= Py_TPFLAGS_DICT_SUBCLASS;
246252
}
247253

254+
static void inherit_slots(PyTypeObject *type, PyTypeObject *base) {
255+
if (type->tp_getattr == NULL && type->tp_getattro == NULL) {
256+
type->tp_getattr = base->tp_getattr;
257+
type->tp_getattro = base->tp_getattro;
258+
}
259+
if (type->tp_setattr == NULL && type->tp_setattro == NULL) {
260+
type->tp_setattr = base->tp_setattr;
261+
type->tp_setattro = base->tp_setattro;
262+
}
263+
}
264+
248265
// TODO support member flags other than READONLY
249266
UPCALL_ID(AddMember);
250267
static void add_member(PyTypeObject* cls, PyObject* type_dict, PyObject* mname, int mtype, Py_ssize_t moffset, int mflags, char* mdoc) {
@@ -295,6 +312,9 @@ int PyType_Ready(PyTypeObject* cls) {
295312
add_method_or_slot(cls, dict, (__name__), (__meth__), (__clanding__), (__flags__), (__doc__)); \
296313
}
297314

315+
Py_ssize_t n;
316+
Py_ssize_t i;
317+
298318
// https://docs.python.org/3/c-api/typeobj.html#Py_TPFLAGS_READY
299319
if ((cls->tp_flags & Py_TPFLAGS_READY) || (cls->tp_flags & Py_TPFLAGS_READYING)) {
300320
return 0;
@@ -408,6 +428,17 @@ int PyType_Ready(PyTypeObject* cls) {
408428
if (cls->tp_base != NULL)
409429
inherit_special(cls, cls->tp_base);
410430

431+
/* Initialize tp_dict properly */
432+
bases = cls->tp_mro;
433+
assert(bases != NULL);
434+
assert(PyTuple_Check(bases));
435+
n = PyTuple_GET_SIZE(bases);
436+
for (i = 1; i < n; i++) {
437+
PyObject *b = PyTuple_GET_ITEM(bases, i);
438+
if (PyType_Check(b))
439+
inherit_slots(cls, (PyTypeObject *)b);
440+
}
441+
411442
ADD_IF_MISSING(cls->tp_alloc, PyType_GenericAlloc);
412443
ADD_IF_MISSING(cls->tp_new, PyType_GenericNew);
413444

@@ -456,6 +487,7 @@ int PyType_Ready(PyTypeObject* cls) {
456487
ADD_SLOT("__sub__", numbers->nb_subtract, -2);
457488
ADD_SLOT_CONV("__rsub__", wrap_reverse_binop, numbers->nb_subtract, -2);
458489
ADD_SLOT("__mul__", numbers->nb_multiply, -2);
490+
ADD_SLOT_CONV("__rmul__", wrap_reverse_binop, numbers->nb_multiply, -2);
459491
ADD_SLOT("__mod__", numbers->nb_remainder, -2);
460492
ADD_SLOT_CONV("__rmod__", wrap_reverse_binop, numbers->nb_remainder, -2);
461493
ADD_SLOT("__divmod__", numbers->nb_divmod, -2);
@@ -540,8 +572,7 @@ int PyType_Ready(PyTypeObject* cls) {
540572

541573
/* Link into each base class's list of subclasses */
542574
bases = cls->tp_bases;
543-
Py_ssize_t n = PyTuple_GET_SIZE(bases);
544-
Py_ssize_t i;
575+
n = PyTuple_GET_SIZE(bases);
545576
for (i = 0; i < n; i++) {
546577
PyObject* base_class_object = PyTuple_GetItem(bases, i);
547578
PyTypeObject* b = (PyTypeObject*) base_class_object;
@@ -554,6 +585,9 @@ int PyType_Ready(PyTypeObject* cls) {
554585
cls->tp_flags = cls->tp_flags & ~Py_TPFLAGS_READYING;
555586
cls->tp_flags = cls->tp_flags | Py_TPFLAGS_READY;
556587

588+
// it may be that the type was used uninitialized
589+
UPCALL_CEXT_VOID(_jls_PyTruffle_Type_Modified, cls, polyglot_from_string(cls->tp_name, SRC_CS), Py_NoValue);
590+
557591
return 0;
558592

559593
#undef ADD_IF_MISSING
@@ -562,11 +596,6 @@ int PyType_Ready(PyTypeObject* cls) {
562596
#undef ADD_METHOD_OR_SLOT
563597
}
564598

565-
UPCALL_ID(PyTruffle_Type_Modified);
566-
void PyType_Modified(PyTypeObject* type) {
567-
UPCALL_CEXT_VOID(_jls_PyTruffle_Type_Modified, native_type_to_java(type), polyglot_from_string(type->tp_name, SRC_CS), native_to_java(type->tp_mro));
568-
}
569-
570599
MUST_INLINE static int valid_identifier(PyObject *s) {
571600
if (!PyUnicode_Check(s)) {
572601
PyErr_Format(PyExc_TypeError,
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*
2+
* Copyright (c) 2019, 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+
#include "capi.h"
42+
43+
PyTypeObject _PyWeakref_RefType = PY_TRUFFLE_TYPE("weakref", &PyType_Type, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE, sizeof(PyWeakReference));
44+
PyTypeObject _PyWeakref_ProxyType = PY_TRUFFLE_TYPE("weakproxy", &PyType_Type, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, sizeof(PyWeakReference));
45+
PyTypeObject _PyWeakref_CallableProxyType = PY_TRUFFLE_TYPE("weakcallableproxy", &PyType_Type, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, sizeof(PyWeakReference));

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,4 +40,5 @@
4040
"""PACKAGE DOC"""
4141

4242
from .lib import *
43+
from .lib1 import *
4344
from . import exported

0 commit comments

Comments
 (0)