Skip to content

Commit 5e7ed7f

Browse files
committed
[GR-10719] Extend C API to support simple Cython generated sources
PullRequest: graalpython/110
2 parents 122ad01 + c26475d commit 5e7ed7f

File tree

71 files changed

+2442
-800
lines changed

Some content is hidden

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

71 files changed

+2442
-800
lines changed

graalpython/benchmarks/src/benchmarks/interop/python_r_image_demo.py

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
3636
# SOFTWARE.
3737

38+
import polyglot
3839
import sys
3940
import os
4041

@@ -44,21 +45,19 @@
4445

4546
from image_magix import Image
4647

47-
MIME_R = "application/x-r"
48-
49-
load_jpeg = eval(compile("""function(file.name) {
48+
load_jpeg = polyglot.eval(string="""function(file.name) {
5049
jimg <- read.csv(gzfile(file.name))
5150
return (jimg)
52-
}""", "", MIME_R))
51+
}""", language="R")
5352

5453
print("stage 1")
5554

5655
working_dir_parts.append("img.csv.gz")
5756
raw_data = load_jpeg(os.sep.join(working_dir_parts))
5857

5958
# the dimensions are R attributes; define function to access them
60-
getDim = eval(compile("function(v, pos) dim(v)[[pos]]", "", MIME_R))
61-
getDataRowMajor = eval(compile("function(v) as.vector(t(v))", "", MIME_R))
59+
getDim = polyglot.eval(string="function(v, pos) dim(v)[[pos]]", language="R")
60+
getDataRowMajor = polyglot.eval(string="function(v) as.vector(t(v))", language="R")
6261

6362
print("stage 2")
6463

@@ -77,17 +76,16 @@
7776

7877
print("stage 3")
7978

80-
draw = eval(compile("""function(processedImgObj) {
79+
draw = polyglot.eval(string="""function(processedImgObj) {
8180
require(grDevices)
8281
require(grid)
8382
mx <- matrix(processedImgObj$`@data`/255, nrow=processedImgObj$`@height`, ncol=processedImgObj$`@width`)
8483
cat("rows:", nrow(mx), "\n")
8584
grid.newpage()
8685
grid.raster(mx, height=unit(nrow(mx),"points"))
8786
cat("DONE\n")
88-
}""", "", MIME_R))
87+
}""", language="R")
8988

9089
draw(result)
9190

92-
eval(compile("dev.off()", "", MIME_R))
93-
91+
polyglot.eval(string="dev.off()", language="R")

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@
112112
#include "codecs.h"
113113
#include "frameobject.h"
114114
#include "traceback.h"
115+
#include "classobject.h"
115116

116117
#define PY_TRUFFLE_CEXT ((void*)polyglot_import("python_cext"))
117118
#define PY_BUILTIN ((void*)polyglot_import("python_builtins"))
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/* Copyright (c) 2018, Oracle and/or its affiliates.
2+
* Copyright (C) 1996-2017 Python Software Foundation
3+
*
4+
* Licensed under the PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
5+
*/
6+
/* Former class object interface -- now only bound methods are here */
7+
8+
/* Revealing some structures (not for general use) */
9+
10+
#ifndef Py_LIMITED_API
11+
#ifndef Py_CLASSOBJECT_H
12+
#define Py_CLASSOBJECT_H
13+
#ifdef __cplusplus
14+
extern "C" {
15+
#endif
16+
17+
typedef struct {
18+
PyObject_HEAD
19+
PyObject *im_func; /* The callable object implementing the method */
20+
PyObject *im_self; /* The instance it is bound to */
21+
PyObject *im_weakreflist; /* List of weak references */
22+
} PyMethodObject;
23+
24+
PyAPI_DATA(PyTypeObject) PyMethod_Type;
25+
26+
#define PyMethod_Check(op) ((op)->ob_type == &PyMethod_Type)
27+
28+
PyAPI_FUNC(PyObject *) PyMethod_New(PyObject *, PyObject *);
29+
30+
PyAPI_FUNC(PyObject *) PyMethod_Function(PyObject *);
31+
PyAPI_FUNC(PyObject *) PyMethod_Self(PyObject *);
32+
33+
/* Macros for direct access to these values. Type checks are *not*
34+
done, so use with care. */
35+
#define PyMethod_GET_FUNCTION(meth) \
36+
(((PyMethodObject *)meth) -> im_func)
37+
#define PyMethod_GET_SELF(meth) \
38+
(((PyMethodObject *)meth) -> im_self)
39+
40+
PyAPI_FUNC(int) PyMethod_ClearFreeList(void);
41+
42+
typedef struct {
43+
PyObject_HEAD
44+
PyObject *func;
45+
} PyInstanceMethodObject;
46+
47+
PyAPI_DATA(PyTypeObject) PyInstanceMethod_Type;
48+
49+
#define PyInstanceMethod_Check(op) ((op)->ob_type == &PyInstanceMethod_Type)
50+
51+
PyAPI_FUNC(PyObject *) PyInstanceMethod_New(PyObject *);
52+
PyAPI_FUNC(PyObject *) PyInstanceMethod_Function(PyObject *);
53+
54+
/* Macros for direct access to these values. Type checks are *not*
55+
done, so use with care. */
56+
#define PyInstanceMethod_GET_FUNCTION(meth) \
57+
(((PyInstanceMethodObject *)meth) -> func)
58+
59+
#ifdef __cplusplus
60+
}
61+
#endif
62+
#endif /* !Py_CLASSOBJECT_H */
63+
#endif /* Py_LIMITED_API */

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,5 +52,7 @@
5252

5353
#define HAVE_WCHAR_H 1
5454

55+
#define WITH_THREAD 1
56+
5557
#endif /*Py_PYCONFIG_H*/
5658

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,10 @@ declare_type(PyByteArray_Type, bytearray, PyByteArrayObject);
9898
declare_type(PyCFunction_Type, function, PyCFunctionObject);
9999
declare_type(_PyExc_BaseException, BaseException, PyBaseExceptionObject);
100100
declare_type(PyBuffer_Type, buffer, PyBufferDecorator);
101+
declare_type(PyMethod_Type, method, PyMethodObject);
102+
declare_type(PyCode_Type, code, PyCodeObject);
103+
declare_type(PyFrame_Type, frame, PyFrameObject);
104+
declare_type(PyTraceBack_Type, traceback, PyTracebackObject);
101105
// Below types use the same object structure as others, and thus
102106
// POLYGLOT_DECLARE_TYPE should not be called again
103107
initialize_type(PySuper_Type, super, _object);
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/*
2+
* Copyright (c) 2018, Oracle and/or its affiliates.
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 data
8+
* (collectively the "Software"), free of charge and under any and all copyright
9+
* rights in the Software, and any and all patent rights owned or freely
10+
* licensable by each licensor hereunder covering either (i) the unmodified
11+
* Software as contributed to or provided by such licensor, or (ii) the Larger
12+
* Works (as defined below), to deal in both
13+
*
14+
* (a) the Software, and
15+
* (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
16+
* one is included with the Software (each a "Larger Work" to which the
17+
* Software is contributed by such licensors),
18+
*
19+
* without restriction, including without limitation the rights to copy, create
20+
* derivative works of, display, perform, and distribute the Software and make,
21+
* use, sell, offer for sale, import, export, have made, and have sold the
22+
* Software and the Larger Work(s), and to sublicense the foregoing rights on
23+
* either these or other terms.
24+
*
25+
* This license is subject to the following condition:
26+
*
27+
* The above copyright notice and either this complete permission notice or at a
28+
* minimum a reference to the UPL must be included in all copies or substantial
29+
* portions of the Software.
30+
*
31+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
32+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
33+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
34+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
35+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
36+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
37+
* SOFTWARE.
38+
*/
39+
#include "capi.h"
40+
41+
PyTypeObject PyMethod_Type = PY_TRUFFLE_TYPE("method", &PyType_Type, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, sizeof(PyMethodObject));
42+
PyTypeObject PyInstanceMethod_Type = PY_TRUFFLE_TYPE("instancemethod", &PyType_Type, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, sizeof(PyInstanceMethodObject));
43+
44+
PyObject* PyMethod_Function(PyObject* obj) {
45+
if (PyMethod_Check(obj)) {
46+
return PyMethod_GET_FUNCTION(obj);
47+
} else {
48+
PyErr_BadInternalCall();
49+
return NULL;
50+
}
51+
}
52+
53+
PyObject* PyMethod_Self(PyObject* obj) {
54+
if (PyMethod_Check(obj)) {
55+
return PyMethod_GET_SELF(obj);
56+
} else {
57+
PyErr_BadInternalCall();
58+
return NULL;
59+
}
60+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/*
2+
* Copyright (c) 2017, 2018, Oracle and/or its affiliates.
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 data
8+
* (collectively the "Software"), free of charge and under any and all copyright
9+
* rights in the Software, and any and all patent rights owned or freely
10+
* licensable by each licensor hereunder covering either (i) the unmodified
11+
* Software as contributed to or provided by such licensor, or (ii) the Larger
12+
* Works (as defined below), to deal in both
13+
*
14+
* (a) the Software, and
15+
* (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
16+
* one is included with the Software (each a "Larger Work" to which the
17+
* Software is contributed by such licensors),
18+
*
19+
* without restriction, including without limitation the rights to copy, create
20+
* derivative works of, display, perform, and distribute the Software and make,
21+
* use, sell, offer for sale, import, export, have made, and have sold the
22+
* Software and the Larger Work(s), and to sublicense the foregoing rights on
23+
* either these or other terms.
24+
*
25+
* This license is subject to the following condition:
26+
*
27+
* The above copyright notice and either this complete permission notice or at a
28+
* minimum a reference to the UPL must be included in all copies or substantial
29+
* portions of the Software.
30+
*
31+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
32+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
33+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
34+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
35+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
36+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
37+
* SOFTWARE.
38+
*/
39+
#include "capi.h"
40+
41+
PyTypeObject PyCode_Type = PY_TRUFFLE_TYPE("code", &PyType_Type, Py_TPFLAGS_DEFAULT, sizeof(PyTypeObject));
42+
43+
PyCodeObject* PyCode_New(int argcount, int kwonlyargcount, int nlocals,
44+
int stacksize, int flags, PyObject *code,
45+
PyObject *consts, PyObject *names, PyObject *varnames,
46+
PyObject *freevars, PyObject *cellvars,
47+
PyObject *filename, PyObject *name, int firstlineno,
48+
PyObject *lnotab) {
49+
return UPCALL_CEXT_O("PyCode_New", argcount, kwonlyargcount, nlocals,
50+
stacksize, flags, native_to_java(code),
51+
native_to_java(consts), native_to_java(names), native_to_java(varnames),
52+
native_to_java(filename), native_to_java(name), firstlineno,
53+
native_to_java(lnotab));
54+
}

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,3 +103,12 @@ int PyDict_SetItemString(PyObject *d, const char *key, PyObject *item) {
103103
int PyDict_DelItemString(PyObject *d, const char *key) {
104104
return UPCALL_CEXT_I("PyDict_DelItem", native_to_java(d), polyglot_from_string(key, SRC_CS));
105105
}
106+
107+
int PyDict_Update(PyObject *a, PyObject *b) {
108+
PyObject* result = UPCALL_O(native_to_java(a), "update", native_to_java(b));
109+
if (PyErr_Occurred()) {
110+
return -1;
111+
} else {
112+
return 0;
113+
}
114+
}

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

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ void PyErr_BadInternalCall(void) {
5151

5252

5353
PyObject* PyErr_Occurred() {
54-
return UPCALL_CEXT_O("PyErr_Occurred", ERROR_MARKER);
54+
return UPCALL_CEXT_O("PyErr_Occurred", ERROR_MARKER);
5555
}
5656

5757
void PyErr_SetString(PyObject *exception, const char *string) {
@@ -107,11 +107,11 @@ static void _PyErr_GetOrFetchExcInfo(int consume, PyObject **p_type, PyObject **
107107
}
108108

109109
void PyErr_Fetch(PyObject **p_type, PyObject **p_value, PyObject **p_traceback) {
110-
_PyErr_GetOrFetchExcInfo(1, p_type, p_value, p_traceback);
110+
_PyErr_GetOrFetchExcInfo(1, p_type, p_value, p_traceback);
111111
}
112112

113113
void PyErr_GetExcInfo(PyObject **p_type, PyObject **p_value, PyObject **p_traceback) {
114-
_PyErr_GetOrFetchExcInfo(0, p_type, p_value, p_traceback);
114+
_PyErr_GetOrFetchExcInfo(0, p_type, p_value, p_traceback);
115115
Py_XINCREF(*p_type);
116116
Py_XINCREF(*p_value);
117117
Py_XINCREF(*p_traceback);
@@ -156,3 +156,13 @@ void PyErr_WriteUnraisable(PyObject *obj) {
156156
void PyErr_Display(PyObject *exception, PyObject *value, PyObject *tb) {
157157
UPCALL_CEXT_VOID("PyErr_Display", native_to_java(exception), native_to_java(value), native_to_java(tb));
158158
}
159+
160+
void PyErr_NormalizeException(PyObject **exc, PyObject **val, PyObject **tb) {
161+
// (tfel): nothing to do here from our side, the exception is already
162+
// reified
163+
return;
164+
}
165+
166+
void PyErr_SetExcInfo(PyObject *p_type, PyObject *p_value, PyObject *p_traceback) {
167+
PyErr_Restore(p_type, p_value, p_traceback);
168+
}

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

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,9 +75,13 @@ PyObject * PyExc_ZeroDivisionError = NULL;
7575
PyObject * PyExc_ArithmeticError = NULL;
7676
PyObject * PyExc_StopIteration = NULL;
7777
PyObject * PyExc_BufferError = NULL;
78+
PyObject * PyExc_AssertionError = NULL;
79+
PyObject * PyExc_UnboundLocalError = NULL;
80+
PyObject * PyExc_NotImplementedError = NULL;
7881

7982
void initialize_exceptions() {
8083
PyExc_AttributeError = PY_EXCEPTION("AttributeError");
84+
PyExc_AssertionError = PY_EXCEPTION("AssertionError");
8185
PyExc_BaseException = PY_EXCEPTION("BaseException");
8286
PyExc_BytesWarning = PY_EXCEPTION("BytesWarning");
8387
PyExc_DeprecationWarning = PY_EXCEPTION("DeprecationWarning");
@@ -107,5 +111,16 @@ void initialize_exceptions() {
107111
PyExc_ArithmeticError = PY_EXCEPTION("ArithmeticError");
108112
PyExc_StopIteration = PY_EXCEPTION("StopIteration");
109113
PyExc_BufferError = PY_EXCEPTION("BufferError");
114+
PyExc_UnboundLocalError = PY_EXCEPTION("UnboundLocalError");
115+
PyExc_NotImplementedError = PY_EXCEPTION("NotImplementedError");
110116
}
111117

118+
119+
int PyException_SetTraceback(PyObject *self, PyObject *tb) {
120+
PyObject* result = UPCALL_O(native_to_java(self), "with_traceback", native_to_java(tb));
121+
if (result == ERROR_MARKER) {
122+
return -1;
123+
} else {
124+
return 0;
125+
}
126+
}

0 commit comments

Comments
 (0)