Skip to content

Commit 019cf2e

Browse files
committed
Implement buffer procs.
1 parent f151a66 commit 019cf2e

File tree

9 files changed

+125
-32
lines changed

9 files changed

+125
-32
lines changed

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

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,3 +263,52 @@ PyObject * PyMapping_GetItemString(PyObject *o, const char *key) {
263263
return to_sulong(result);
264264
}
265265

266+
int PyObject_GetBuffer(PyObject *obj, Py_buffer *view, int flags) {
267+
PyBufferProcs *pb = obj->ob_type->tp_as_buffer;
268+
269+
if (pb == NULL || pb->bf_getbuffer == NULL) {
270+
PyErr_Format(PyExc_TypeError,
271+
"a bytes-like object is required, not '%.100s'",
272+
Py_TYPE(obj)->tp_name);
273+
return -1;
274+
}
275+
return (*pb->bf_getbuffer)(obj, view, flags);
276+
}
277+
278+
// taken from CPython "Objects/abstract.c"
279+
/* we do this in native code since we need to fill in the values in a given 'Py_buffer' struct */
280+
int PyBuffer_FillInfo(Py_buffer *view, PyObject *obj, void *buf, Py_ssize_t len, int readonly, int flags) {
281+
if (view == NULL) {
282+
PyErr_SetString(PyExc_BufferError,
283+
"PyBuffer_FillInfo: view==NULL argument is obsolete");
284+
return -1;
285+
}
286+
287+
if (((flags & PyBUF_WRITABLE) == PyBUF_WRITABLE) &&
288+
(readonly == 1)) {
289+
PyErr_SetString(PyExc_BufferError,
290+
"Object is not writable.");
291+
return -1;
292+
}
293+
294+
view->obj = obj;
295+
if (obj)
296+
Py_INCREF(obj);
297+
view->buf = buf;
298+
view->len = len;
299+
view->readonly = readonly;
300+
view->itemsize = 1;
301+
view->format = NULL;
302+
if ((flags & PyBUF_FORMAT) == PyBUF_FORMAT)
303+
view->format = "B";
304+
view->ndim = 1;
305+
view->shape = NULL;
306+
if ((flags & PyBUF_ND) == PyBUF_ND)
307+
view->shape = &(view->len);
308+
view->strides = NULL;
309+
if ((flags & PyBUF_STRIDES) == PyBUF_STRIDES)
310+
view->strides = &(view->itemsize);
311+
view->suboffsets = NULL;
312+
view->internal = NULL;
313+
return 0;
314+
}

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,3 +273,7 @@ void PyBytes_ConcatAndDel(PyObject **bytes, PyObject *newpart) {
273273
Py_ssize_t PyBytes_Size(PyObject *bytes) {
274274
return truffle_invoke_i(PY_TRUFFLE_CEXT, "PyBytes_Size", to_java(bytes));
275275
}
276+
277+
int bytes_buffer_getbuffer(PyBytesObject *self, Py_buffer *view, int flags) {
278+
return PyBuffer_FillInfo(view, (PyObject*)self, (void *)self->ob_sval, Py_SIZE(self), 1, flags);
279+
}

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,11 @@ static void initialize_globals() {
7979
truffle_assign_managed(&marker_struct, jerrormarker);
8080
}
8181

82+
static void initialize_bufferprocs() {
83+
polyglot_invoke(PY_TRUFFLE_CEXT, "PyTruffle_SetBufferProcs", to_java((PyObject*)&PyBytes_Type), (getbufferproc)bytes_buffer_getbuffer, (releasebufferproc)NULL);
84+
polyglot_invoke(PY_TRUFFLE_CEXT, "PyTruffle_SetBufferProcs", to_java((PyObject*)&PyByteArray_Type), (getbufferproc)NULL, (releasebufferproc)NULL);
85+
}
86+
8287
__attribute__((constructor))
8388
static void initialize_capi() {
8489
// initialize base types
@@ -112,6 +117,7 @@ static void initialize_capi() {
112117

113118
initialize_exceptions();
114119
initialize_hashes();
120+
initialize_bufferprocs();
115121
}
116122

117123
void* native_to_java(PyObject* obj) {

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -238,11 +238,12 @@ extern PyObject marker_struct;
238238
/* internal functions to avoid unnecessary managed <-> native conversions */
239239

240240
/* UNICODE */
241-
242241
void* PyTruffle_Unicode_FromString(const char* o);
243242

244243
/* DICT */
245-
246244
void* PyTruffle_Tuple_GetItem(void* jtuple, Py_ssize_t position);
247245

246+
/* BYTES */
247+
int bytes_buffer_getbuffer(PyBytesObject *self, Py_buffer *view, int flags);
248+
248249
#endif

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

Lines changed: 31 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -72,36 +72,38 @@ PyObject * PyExc_ResourceWarning = NULL;
7272
PyObject * PyExc_ZeroDivisionError = NULL;
7373
PyObject * PyExc_ArithmeticError = NULL;
7474
PyObject * PyExc_StopIteration = NULL;
75+
PyObject * PyExc_BufferError = NULL;
7576

7677
void initialize_exceptions() {
77-
PyExc_AttributeError = PY_EXCEPTION("AttributeError");
78-
PyExc_BaseException = PY_EXCEPTION("BaseException");
79-
PyExc_BytesWarning = PY_EXCEPTION("BytesWarning");
80-
PyExc_DeprecationWarning = PY_EXCEPTION("DeprecationWarning");
81-
PyExc_Exception = PY_EXCEPTION("Exception");
82-
PyExc_FloatingPointError = PY_EXCEPTION("FloatingPointError");
83-
PyExc_IOError = PY_EXCEPTION("IOError");
84-
PyExc_ImportError = PY_EXCEPTION("ImportError");
85-
PyExc_ImportWarning = PY_EXCEPTION("ImportWarning");
86-
PyExc_IndexError = PY_EXCEPTION("IndexError");
87-
PyExc_KeyError = PY_EXCEPTION("KeyError");
88-
PyExc_MemoryError = PY_EXCEPTION("MemoryError");
89-
PyExc_NameError = PY_EXCEPTION("NameError");
90-
PyExc_OSError = PY_EXCEPTION("OSError");
91-
PyExc_OverflowError = PY_EXCEPTION("OverflowError");
92-
PyExc_PendingDeprecationWarning = PY_EXCEPTION("PendingDeprecationWarning");
93-
PyExc_ResourceWarning = PY_EXCEPTION("ResourceWarning");
94-
PyExc_RuntimeError = PY_EXCEPTION("RuntimeError");
95-
PyExc_RuntimeWarning = PY_EXCEPTION("RuntimeWarning");
96-
PyExc_SyntaxWarning = PY_EXCEPTION("SyntaxWarning");
97-
PyExc_SystemError = PY_EXCEPTION("SystemError");
98-
PyExc_TypeError = PY_EXCEPTION("TypeError");
99-
PyExc_UnicodeWarning = PY_EXCEPTION("UnicodeWarning");
100-
PyExc_UserWarning = PY_EXCEPTION("UserWarning");
101-
PyExc_ValueError = PY_EXCEPTION("ValueError");
102-
PyExc_Warning = PY_EXCEPTION("Warning");
103-
PyExc_ZeroDivisionError = PY_EXCEPTION("ZeroDivisionError");
104-
PyExc_ArithmeticError = PY_EXCEPTION("ArithmeticError");
105-
PyExc_StopIteration = PY_EXCEPTION("StopIteration");
78+
PyExc_AttributeError = PY_EXCEPTION("AttributeError");
79+
PyExc_BaseException = PY_EXCEPTION("BaseException");
80+
PyExc_BytesWarning = PY_EXCEPTION("BytesWarning");
81+
PyExc_DeprecationWarning = PY_EXCEPTION("DeprecationWarning");
82+
PyExc_Exception = PY_EXCEPTION("Exception");
83+
PyExc_FloatingPointError = PY_EXCEPTION("FloatingPointError");
84+
PyExc_IOError = PY_EXCEPTION("IOError");
85+
PyExc_ImportError = PY_EXCEPTION("ImportError");
86+
PyExc_ImportWarning = PY_EXCEPTION("ImportWarning");
87+
PyExc_IndexError = PY_EXCEPTION("IndexError");
88+
PyExc_KeyError = PY_EXCEPTION("KeyError");
89+
PyExc_MemoryError = PY_EXCEPTION("MemoryError");
90+
PyExc_NameError = PY_EXCEPTION("NameError");
91+
PyExc_OSError = PY_EXCEPTION("OSError");
92+
PyExc_OverflowError = PY_EXCEPTION("OverflowError");
93+
PyExc_PendingDeprecationWarning = PY_EXCEPTION("PendingDeprecationWarning");
94+
PyExc_ResourceWarning = PY_EXCEPTION("ResourceWarning");
95+
PyExc_RuntimeError = PY_EXCEPTION("RuntimeError");
96+
PyExc_RuntimeWarning = PY_EXCEPTION("RuntimeWarning");
97+
PyExc_SyntaxWarning = PY_EXCEPTION("SyntaxWarning");
98+
PyExc_SystemError = PY_EXCEPTION("SystemError");
99+
PyExc_TypeError = PY_EXCEPTION("TypeError");
100+
PyExc_UnicodeWarning = PY_EXCEPTION("UnicodeWarning");
101+
PyExc_UserWarning = PY_EXCEPTION("UserWarning");
102+
PyExc_ValueError = PY_EXCEPTION("ValueError");
103+
PyExc_Warning = PY_EXCEPTION("Warning");
104+
PyExc_ZeroDivisionError = PY_EXCEPTION("ZeroDivisionError");
105+
PyExc_ArithmeticError = PY_EXCEPTION("ArithmeticError");
106+
PyExc_StopIteration = PY_EXCEPTION("StopIteration");
107+
PyExc_BufferError = PY_EXCEPTION("BufferError");
106108
}
107109

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@
6868
import com.oracle.graal.python.builtins.objects.function.Arity;
6969
import com.oracle.graal.python.builtins.objects.function.PArguments;
7070
import com.oracle.graal.python.builtins.objects.ints.PInt;
71+
import com.oracle.graal.python.builtins.objects.object.PythonObject;
7172
import com.oracle.graal.python.builtins.objects.str.PString;
7273
import com.oracle.graal.python.builtins.objects.traceback.PTraceback;
7374
import com.oracle.graal.python.builtins.objects.tuple.PTuple;
@@ -1050,4 +1051,16 @@ PythonObjectNativeWrapper doPythonObject(PythonObjectNativeWrapper nativeWrapper
10501051
return nativeWrapper;
10511052
}
10521053
}
1054+
1055+
@Builtin(name = "PyTruffle_SetBufferProcs", fixedNumOfArguments = 3)
1056+
@GenerateNodeFactory
1057+
abstract static class PyTruffle_SetBufferProcs extends NativeBuiltin {
1058+
1059+
@Specialization
1060+
Object doPythonObject(PythonObject obj, Object getBufferProc, Object releaseBufferProc) {
1061+
obj.setAttribute(SpecialAttributeNames.__GET_BUFFER__, getBufferProc);
1062+
obj.setAttribute(SpecialAttributeNames.__RELEASE_BUFFER__, releaseBufferProc);
1063+
return PNone.NO_VALUE;
1064+
}
1065+
}
10531066
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/PythonObjectNativeWrapperMR.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242

4343
import com.oracle.graal.python.builtins.objects.PNone;
4444
import com.oracle.graal.python.builtins.objects.PythonAbstractObject;
45+
import com.oracle.graal.python.builtins.objects.bytes.PByteArray;
4546
import com.oracle.graal.python.builtins.objects.bytes.PBytes;
4647
import com.oracle.graal.python.builtins.objects.cext.CExtNodes.ToSulongNode;
4748
import com.oracle.graal.python.builtins.objects.cext.PythonObjectNativeWrapperMRFactory.ReadNativeMemberNodeGen;
@@ -202,6 +203,16 @@ Object doTpAsNumber(PythonClass object, @SuppressWarnings("unused") String key)
202203
return new PyNumberMethodsWrapper(object);
203204
}
204205

206+
@Specialization(guards = "eq(TP_AS_BUFFER, key)")
207+
Object doTpAsBuffer(PythonObject object, @SuppressWarnings("unused") String key) {
208+
if (object instanceof PBytes || object instanceof PByteArray) {
209+
return new PyBufferProcsWrapper(object);
210+
}
211+
212+
// NULL pointer
213+
return PNone.NO_VALUE;
214+
}
215+
205216
@Specialization(guards = "eq(TP_HASH, key)")
206217
Object doTpHash(PythonClass object, @SuppressWarnings("unused") String key,
207218
@Cached("create()") GetAttributeNode getHashNode) {

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/SpecialAttributeNames.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@
3838
*/
3939
package com.oracle.graal.python.nodes;
4040

41+
import com.oracle.truffle.api.object.HiddenKey;
42+
4143
public abstract class SpecialAttributeNames {
4244
public static final String __DOC__ = "__doc__";
4345
public static final String __DEFAULTS__ = "__defaults__";
@@ -63,4 +65,8 @@ public abstract class SpecialAttributeNames {
6365
public static final String __CACHED__ = "__cached__";
6466
public static final String __TRACEBACK__ = "__traceback__";
6567
public static final String __BASICSIZE__ = "__basicsize__";
68+
69+
/* hidden keys */
70+
public static final HiddenKey __GET_BUFFER__ = new HiddenKey("__get_buffer__");
71+
public static final HiddenKey __RELEASE_BUFFER__ = new HiddenKey("__release_buffer__");
6672
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/exception/PythonErrorType.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,5 +62,6 @@ public enum PythonErrorType {
6262
UserWarning,
6363
ValueError,
6464
Warning,
65-
ZeroDivisionError;
65+
ZeroDivisionError,
66+
BufferError;
6667
}

0 commit comments

Comments
 (0)