Skip to content

Commit 0c6ed34

Browse files
committed
Merge remote-tracking branch 'florian/fa/numpy-building' into tim/numpy-building
2 parents be16e64 + fbe11f5 commit 0c6ed34

File tree

11 files changed

+346
-12
lines changed

11 files changed

+346
-12
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ static void initialize_capi() {
9696
initialize_type_structure(&PyCFunction_Type, "function");
9797
initialize_type_structure(&PyFrozenSet_Type, "frozenset");
9898
initialize_type_structure(&PySet_Type, "set");
99+
initialize_type_structure(&PyEllipsis_Type, "ellipsis");
99100

100101
// initialize global variables like '_Py_NoneStruct', etc.
101102
initialize_globals();
@@ -381,4 +382,3 @@ int PyTruffle_Debug(void *arg) {
381382
truffle_invoke(PY_TRUFFLE_CEXT, "PyTruffle_Debug", arg);
382383
return 0;
383384
}
384-

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ POLYGLOT_DECLARE_TYPE(PyBytesObject);
7474
POLYGLOT_DECLARE_STRUCT(_longobject);
7575
POLYGLOT_DECLARE_TYPE(PyCapsule);
7676
POLYGLOT_DECLARE_TYPE(PyMemoryViewObject);
77+
POLYGLOT_DECLARE_TYPE(PySetObject);
7778

7879

7980
extern void* to_java(PyObject* obj);

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

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -129,11 +129,6 @@ PyObject _Py_NoneStruct = {
129129
1, &_PyNone_Type
130130
};
131131

132-
PyObject _Py_EllipsisObject = {
133-
_PyObject_EXTRA_INIT
134-
1, &_PyNone_Type
135-
};
136-
137132
PyTypeObject _PyNotImplemented_Type = PY_TRUFFLE_TYPE("NotImplementedType", &PyType_Type, Py_TPFLAGS_DEFAULT);
138133

139134
PyObject _Py_NotImplementedStruct = {
@@ -167,6 +162,15 @@ Py_ssize_t PyObject_Size(PyObject *o) {
167162
return truffle_invoke_i(PY_TRUFFLE_CEXT, "PyObject_Size", to_java(o));
168163
}
169164

165+
static int add_subclass(PyTypeObject *base, PyTypeObject *type) {
166+
void* result = polyglot_invoke(PY_TRUFFLE_CEXT, "PyTruffle_Add_Subclass", to_java(base->tp_subclasses), to_java(PyLong_FromVoidPtr(type)), to_java((PyObject*)type));
167+
if (result == ERROR_MARKER) {
168+
return -1;
169+
}
170+
base->tp_subclasses = to_sulong(result);
171+
return 0;
172+
}
173+
170174
int PyType_Ready(PyTypeObject* cls) {
171175
#define ADD_IF_MISSING(attr, def) if (!(attr)) { attr = def; }
172176
#define ADD_METHOD(m) ADD_METHOD_OR_SLOT(m.ml_name, m.ml_meth, m.ml_flags, m.ml_doc)
@@ -210,13 +214,29 @@ int PyType_Ready(PyTypeObject* cls) {
210214
cls->tp_doc = "";
211215
}
212216

217+
/* Initialize tp_bases */
218+
PyObject* bases = cls->tp_bases;
219+
if (bases == NULL) {
220+
if (base == NULL) {
221+
bases = PyTuple_New(0);
222+
} else {
223+
bases = PyTuple_Pack(1, base);
224+
}
225+
if (bases == NULL) {
226+
cls->tp_flags &= ~Py_TPFLAGS_READYING;
227+
return -1;
228+
}
229+
cls->tp_bases = bases;
230+
}
231+
232+
213233
PyTypeObject* javacls = truffle_invoke(PY_TRUFFLE_CEXT,
214234
"PyType_Ready",
215235
// no conversion of cls here, because we
216236
// store this into the PyTypeObject
217237
cls,
218238
to_java_type(metaclass),
219-
to_java_type(base),
239+
to_java(bases),
220240
truffle_read_string(cls->tp_name),
221241
truffle_read_string(cls->tp_doc ? cls->tp_doc : ""));
222242
if (polyglot_is_value(javacls)) {
@@ -387,6 +407,18 @@ int PyType_Ready(PyTypeObject* cls) {
387407
// TODO ...
388408
}
389409

410+
/* Link into each base class's list of subclasses */
411+
bases = cls->tp_bases;
412+
Py_ssize_t n = PyTuple_GET_SIZE(bases);
413+
Py_ssize_t i;
414+
for (i = 0; i < n; i++) {
415+
PyTypeObject *b = polyglot_as__typeobject(PyTuple_GET_ITEM(bases, i));
416+
if (PyType_Check(b) && add_subclass((PyTypeObject *)b, cls) < 0) {
417+
cls->tp_flags &= ~Py_TPFLAGS_READYING;
418+
return -1;
419+
}
420+
}
421+
390422
// done
391423
cls->tp_flags = cls->tp_flags & ~Py_TPFLAGS_READYING;
392424
cls->tp_flags = cls->tp_flags | Py_TPFLAGS_READY;
@@ -471,7 +503,7 @@ PyObject* PyObject_CallFunctionObjArgs(PyObject *callable, ...) {
471503
PyObject* PyObject_CallMethod(PyObject* object, const char* method, const char* fmt, ...) {
472504
PyObject* args;
473505
CALL_WITH_VARARGS(args, Py_BuildValue, 3, fmt);
474-
return to_sulong(truffle_invoke(PY_TRUFFLE_CEXT, "PyObject_CallMethod", to_java(object), truffle_read_string(method), args));
506+
return to_sulong(truffle_invoke(PY_TRUFFLE_CEXT, "PyObject_CallMethod", to_java(object), truffle_read_string(method), to_java(args)));
475507
}
476508

477509
PyObject* PyObject_Type(PyObject* obj) {

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

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,19 @@
4040

4141
PyTypeObject PySet_Type = PY_TRUFFLE_TYPE("set", &PyType_Type, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC);
4242
PyTypeObject PyFrozenSet_Type = PY_TRUFFLE_TYPE("frozenset", &PyType_Type, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC);
43+
44+
PyObject * PySet_New(PyObject *iterable) {
45+
void* result = polyglot_invoke(PY_TRUFFLE_CEXT, "PySet_New", to_java(iterable));
46+
if (result == ERROR_MARKER) {
47+
return NULL;
48+
}
49+
return to_sulong(result);
50+
}
51+
52+
PyObject * PyFrozenSet_New(PyObject *iterable) {
53+
void* result = polyglot_invoke(PY_TRUFFLE_CEXT, "PyFrozenSet_New", to_java(iterable));
54+
if (result == ERROR_MARKER) {
55+
return NULL;
56+
}
57+
return to_sulong(result);
58+
}

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,10 @@
3838
*/
3939
#include "capi.h"
4040

41+
PyTypeObject PyEllipsis_Type = PY_TRUFFLE_TYPE("ellipsis", &PyType_Type, Py_TPFLAGS_DEFAULT);
4142
PyTypeObject PySlice_Type = PY_TRUFFLE_TYPE("slice", &PyType_Type, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC);
43+
44+
PyObject _Py_EllipsisObject = {
45+
_PyObject_EXTRA_INIT
46+
1, &PyEllipsis_Type
47+
};
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
# Copyright (c) 2018, Oracle and/or its affiliates.
2+
#
3+
# The Universal Permissive License (UPL), Version 1.0
4+
#
5+
# Subject to the condition set forth below, permission is hereby granted to any
6+
# person obtaining a copy of this software, associated documentation and/or data
7+
# (collectively the "Software"), free of charge and under any and all copyright
8+
# rights in the Software, and any and all patent rights owned or freely
9+
# licensable by each licensor hereunder covering either (i) the unmodified
10+
# Software as contributed to or provided by such licensor, or (ii) the Larger
11+
# Works (as defined below), to deal in both
12+
#
13+
# (a) the Software, and
14+
# (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
15+
# one is included with the Software (each a "Larger Work" to which the
16+
# Software is contributed by such licensors),
17+
#
18+
# without restriction, including without limitation the rights to copy, create
19+
# derivative works of, display, perform, and distribute the Software and make,
20+
# use, sell, offer for sale, import, export, have made, and have sold the
21+
# Software and the Larger Work(s), and to sublicense the foregoing rights on
22+
# either these or other terms.
23+
#
24+
# This license is subject to the following condition:
25+
#
26+
# The above copyright notice and either this complete permission notice or at a
27+
# minimum a reference to the UPL must be included in all copies or substantial
28+
# portions of the Software.
29+
#
30+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
31+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
32+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
33+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
34+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
35+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
36+
# SOFTWARE.
37+
38+
import sys
39+
from . import CPyExtTestCase, CPyExtFunction, CPyExtFunctionOutVars, unhandled_error_compare, GRAALPYTHON
40+
__dir__ = __file__.rpartition("/")[0]
41+
42+
class TestMisc(CPyExtTestCase):
43+
def compile_module(self, name):
44+
type(self).mro()[1].__dict__["test_%s" % name].create_module(name)
45+
super(TestMisc, self).compile_module(name)
46+
47+
test_PyEllipsis_isSingleton = CPyExtFunction(
48+
lambda args: 1,
49+
lambda: (
50+
(...,),
51+
),
52+
callfunction="CheckPyEllipsis",
53+
code="""
54+
static int CheckPyEllipsis(PyObject* ellipsis_singleton) {
55+
return ellipsis_singleton == &_Py_EllipsisObject;
56+
}
57+
""",
58+
resultspec="i",
59+
argspec="O",
60+
arguments=["PyObject* ellipsis_singleton"],
61+
)
62+
63+
test_PyEllipsis_type = CPyExtFunction(
64+
lambda args: 1,
65+
lambda: (
66+
(...,),
67+
),
68+
callfunction="CheckPyEllipsisType",
69+
code="""
70+
static int CheckPyEllipsisType(PyObject* ellipsis_singleton) {
71+
return Py_TYPE(&_Py_EllipsisObject) == &PyEllipsis_Type;
72+
}
73+
""",
74+
resultspec="i",
75+
argspec="O",
76+
arguments=["PyObject* ellipsis_singleton"],
77+
)
Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
# Copyright (c) 2018, Oracle and/or its affiliates.
2+
#
3+
# The Universal Permissive License (UPL), Version 1.0
4+
#
5+
# Subject to the condition set forth below, permission is hereby granted to any
6+
# person obtaining a copy of this software, associated documentation and/or data
7+
# (collectively the "Software"), free of charge and under any and all copyright
8+
# rights in the Software, and any and all patent rights owned or freely
9+
# licensable by each licensor hereunder covering either (i) the unmodified
10+
# Software as contributed to or provided by such licensor, or (ii) the Larger
11+
# Works (as defined below), to deal in both
12+
#
13+
# (a) the Software, and
14+
# (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
15+
# one is included with the Software (each a "Larger Work" to which the
16+
# Software is contributed by such licensors),
17+
#
18+
# without restriction, including without limitation the rights to copy, create
19+
# derivative works of, display, perform, and distribute the Software and make,
20+
# use, sell, offer for sale, import, export, have made, and have sold the
21+
# Software and the Larger Work(s), and to sublicense the foregoing rights on
22+
# either these or other terms.
23+
#
24+
# This license is subject to the following condition:
25+
#
26+
# The above copyright notice and either this complete permission notice or at a
27+
# minimum a reference to the UPL must be included in all copies or substantial
28+
# portions of the Software.
29+
#
30+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
31+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
32+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
33+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
34+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
35+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
36+
# SOFTWARE.
37+
38+
import sys
39+
from . import CPyExtTestCase, CPyExtFunction, CPyExtFunctionOutVars, unhandled_error_compare, GRAALPYTHON
40+
__dir__ = __file__.rpartition("/")[0]
41+
42+
43+
class FrozenSetSubclass(frozenset):
44+
pass
45+
46+
47+
class SetSubclass(set):
48+
pass
49+
50+
51+
default_typecheck_args = lambda: (
52+
(set(),),
53+
(set([1,2,3]),),
54+
(set({'a', 'b'}),),
55+
(set([None]),),
56+
(frozenset(),),
57+
(frozenset([1,2,3]),),
58+
(frozenset({'a', 'b'}),),
59+
(frozenset([None]),),
60+
(FrozenSetSubclass(),),
61+
(SetSubclass([None]),),
62+
({'a': "hello", 'b': "world"},),
63+
('a',),
64+
(1,),
65+
(None,),
66+
)
67+
68+
class TestPySet(CPyExtTestCase):
69+
def compile_module(self, name):
70+
type(self).mro()[1].__dict__["test_%s" % name].create_module(name)
71+
super(TestPySet, self).compile_module(name)
72+
73+
test_PySet_New = CPyExtFunction(
74+
lambda args: set(args[0]),
75+
lambda: (
76+
([1, 2, 3],),
77+
({'a': "hello", 'b': "world"},),
78+
({'a', 'b'},),
79+
('a',),
80+
(1,),
81+
),
82+
resultspec="O",
83+
argspec='O',
84+
arguments=["PyObject* iterable"],
85+
cmpfunc=unhandled_error_compare
86+
)
87+
88+
test_PyFrozenSet_New = CPyExtFunction(
89+
lambda args: frozenset(args[0]),
90+
lambda: (
91+
([1, 2, 3],),
92+
({'a': "hello", 'b': "world"},),
93+
({'a', 'b'},),
94+
('a',),
95+
(1,),
96+
),
97+
resultspec="O",
98+
argspec='O',
99+
arguments=["PyObject* iterable"],
100+
cmpfunc=unhandled_error_compare
101+
)
102+
103+
test_PyFrozenSet_Check = CPyExtFunction(
104+
lambda args: isinstance(args[0], frozenset),
105+
default_typecheck_args,
106+
resultspec="i",
107+
argspec='O',
108+
arguments=["PyObject* o"],
109+
cmpfunc=unhandled_error_compare
110+
)
111+
112+
test_PyFrozenSet_CheckExact = CPyExtFunction(
113+
lambda args: type(args[0]) is frozenset,
114+
default_typecheck_args,
115+
resultspec="i",
116+
argspec='O',
117+
arguments=["PyObject* o"],
118+
cmpfunc=unhandled_error_compare
119+
)
120+
121+
test_PyAnySet_CheckExact = CPyExtFunction(
122+
lambda args: type(args[0]) is set or type(args[0]) is frozenset,
123+
default_typecheck_args,
124+
resultspec="i",
125+
argspec='O',
126+
arguments=["PyObject* o"],
127+
cmpfunc=unhandled_error_compare
128+
)
129+
130+
test_PyAnySet_Check = CPyExtFunction(
131+
lambda args: isinstance(args[0], set) or isinstance(args[0], frozenset),
132+
default_typecheck_args,
133+
resultspec="i",
134+
argspec='O',
135+
arguments=["PyObject* o"],
136+
cmpfunc=unhandled_error_compare
137+
)
138+
139+
test_PySet_Check = CPyExtFunction(
140+
lambda args: isinstance(args[0], set),
141+
default_typecheck_args,
142+
resultspec="i",
143+
argspec='O',
144+
arguments=["PyObject* o"],
145+
cmpfunc=unhandled_error_compare
146+
)

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/TruffleCextBuiltins.java

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -493,15 +493,21 @@ abstract static class PyType_ReadyNode extends PythonBuiltinNode {
493493
@Child WriteAttributeToObjectNode writeNode = WriteAttributeToObjectNode.create();
494494

495495
@Specialization
496-
PythonClass run(TruffleObject typestruct, PythonClass metaClass, PythonClass baseClass, String name, String doc) {
497-
PythonClass cclass = factory().createNativeClassWrapper(typestruct, metaClass, name, new PythonClass[]{baseClass});
496+
PythonClass run(TruffleObject typestruct, PythonClass metaClass, PTuple baseClasses, String name, String doc) {
497+
Object[] array = baseClasses.getArray();
498+
PythonClass[] bases = new PythonClass[array.length];
499+
for (int i = 0; i < array.length; i++) {
500+
bases[i] = (PythonClass) array[i];
501+
}
502+
503+
PythonClass cclass = factory().createNativeClassWrapper(typestruct, metaClass, name, bases);
498504
writeNode.execute(cclass, SpecialAttributeNames.__DOC__, doc);
499505
return cclass;
500506
}
501507

502508
@Specialization
503-
PythonClass run(TruffleObject typestruct, PythonClass metaClass, PythonClass baseClass, PString name, PString doc) {
504-
return run(typestruct, metaClass, baseClass, name.getValue(), doc.getValue());
509+
PythonClass run(TruffleObject typestruct, PythonClass metaClass, PTuple baseClasses, PString name, PString doc) {
510+
return run(typestruct, metaClass, baseClasses, name.getValue(), doc.getValue());
505511
}
506512
}
507513

0 commit comments

Comments
 (0)