|
40 | 40 | */
|
41 | 41 | #include "capi.h"
|
42 | 42 |
|
| 43 | +#if SIZEOF_SIZE_T == 8 |
| 44 | +#define polyglot_from_size_array polyglot_from_i64_array |
| 45 | +#elif SIZEOF_SIZE_T == 4 |
| 46 | +#define polyglot_from_size_array polyglot_from_i32_array |
| 47 | +#endif |
| 48 | + |
| 49 | +/* Macros taken from CPython */ |
| 50 | +/* Memoryview buffer properties */ |
| 51 | +#define MV_C_CONTIGUOUS(flags) (flags&(_Py_MEMORYVIEW_SCALAR|_Py_MEMORYVIEW_C)) |
| 52 | +#define MV_F_CONTIGUOUS(flags) \ |
| 53 | + (flags&(_Py_MEMORYVIEW_SCALAR|_Py_MEMORYVIEW_FORTRAN)) |
| 54 | +#define MV_ANY_CONTIGUOUS(flags) \ |
| 55 | + (flags&(_Py_MEMORYVIEW_SCALAR|_Py_MEMORYVIEW_C|_Py_MEMORYVIEW_FORTRAN)) |
| 56 | + |
| 57 | +/* getbuffer() requests */ |
| 58 | +#define REQ_INDIRECT(flags) ((flags&PyBUF_INDIRECT) == PyBUF_INDIRECT) |
| 59 | +#define REQ_C_CONTIGUOUS(flags) ((flags&PyBUF_C_CONTIGUOUS) == PyBUF_C_CONTIGUOUS) |
| 60 | +#define REQ_F_CONTIGUOUS(flags) ((flags&PyBUF_F_CONTIGUOUS) == PyBUF_F_CONTIGUOUS) |
| 61 | +#define REQ_ANY_CONTIGUOUS(flags) ((flags&PyBUF_ANY_CONTIGUOUS) == PyBUF_ANY_CONTIGUOUS) |
| 62 | +#define REQ_STRIDES(flags) ((flags&PyBUF_STRIDES) == PyBUF_STRIDES) |
| 63 | +#define REQ_SHAPE(flags) ((flags&PyBUF_ND) == PyBUF_ND) |
| 64 | +#define REQ_WRITABLE(flags) (flags&PyBUF_WRITABLE) |
| 65 | +#define REQ_FORMAT(flags) (flags&PyBUF_FORMAT) |
| 66 | + |
| 67 | +#define BASE_INACCESSIBLE(mv) \ |
| 68 | + (((PyMemoryViewObject *)mv)->flags&_Py_MEMORYVIEW_RELEASED) |
| 69 | +#define CHECK_RELEASED(mv) \ |
| 70 | + if (BASE_INACCESSIBLE(mv)) { \ |
| 71 | + PyErr_SetString(PyExc_ValueError, \ |
| 72 | + "operation forbidden on released memoryview object"); \ |
| 73 | + return NULL; \ |
| 74 | + } |
| 75 | +#define CHECK_RELEASED_INT(mv) \ |
| 76 | + if (BASE_INACCESSIBLE(mv)) { \ |
| 77 | + PyErr_SetString(PyExc_ValueError, \ |
| 78 | + "operation forbidden on released memoryview object"); \ |
| 79 | + return -1; \ |
| 80 | + } |
| 81 | + |
43 | 82 | PyTypeObject PyMemoryView_Type = PY_TRUFFLE_TYPE_WITH_ITEMSIZE("memoryview", &PyType_Type, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, offsetof(PyMemoryViewObject, ob_array), sizeof(Py_ssize_t));
|
44 | 83 | PyTypeObject PyBuffer_Type = PY_TRUFFLE_TYPE("buffer", &PyType_Type, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, sizeof(PyBufferDecorator));
|
45 | 84 |
|
46 | 85 | int bufferdecorator_getbuffer(PyBufferDecorator *self, Py_buffer *view, int flags) {
|
47 | 86 | return PyBuffer_FillInfo(view, (PyObject*)self, polyglot_get_member(self, "buf_delegate"), PyObject_Size((PyObject *)self) * sizeof(PyObject*), self->readonly, flags);
|
48 | 87 | }
|
49 | 88 |
|
50 |
| -PyObject * PyMemoryView_FromObject(PyObject *v) { |
51 |
| - // TODO(fa): This needs to be fixed. The actual implementation is located in |
52 |
| - // '_memoryview.c'. However, the current way we use it does not allow C exts |
53 |
| - // to link to it. We need to restructure this. |
54 |
| - return NULL; |
| 89 | +/* called from memoryview implementation to do pointer arithmetics currently not possible from Java */ |
| 90 | +int8_t* truffle_add_suboffset(int8_t *ptr, Py_ssize_t offset, Py_ssize_t suboffset, Py_ssize_t remaining_length) { |
| 91 | + return polyglot_from_i8_array(*(int8_t**)(ptr + offset) + suboffset, remaining_length); |
| 92 | +} |
| 93 | + |
| 94 | +UPCALL_ID(PyMemoryView_FromObject) |
| 95 | +PyObject* PyMemoryView_FromObject(PyObject *v) { |
| 96 | + return UPCALL_CEXT_O(_jls_PyMemoryView_FromObject, native_to_java(v)); |
| 97 | +} |
| 98 | + |
| 99 | +/* called back from the above upcall only if the object was native */ |
| 100 | +PyObject* PyTruffle_MemoryViewFromObject(PyObject *v) { |
| 101 | + if (PyObject_CheckBuffer(v)) { |
| 102 | + Py_buffer* buffer = malloc(sizeof(Py_buffer)); |
| 103 | + if (PyObject_GetBuffer(v, buffer, PyBUF_FULL_RO) < 0) { |
| 104 | + return NULL; |
| 105 | + } |
| 106 | + Py_ssize_t ndim = buffer->ndim; |
| 107 | + int needs_release = 0; |
| 108 | + if (buffer->obj != NULL) { |
| 109 | + PyBufferProcs *pb; |
| 110 | + pb = Py_TYPE(buffer->obj)->tp_as_buffer; |
| 111 | + if (pb) { |
| 112 | + needs_release = pb->bf_releasebuffer != NULL; |
| 113 | + } |
| 114 | + } |
| 115 | + PyObject *mv = polyglot_invoke(PY_TRUFFLE_CEXT, "PyTruffle_MemoryViewFromBuffer", |
| 116 | + needs_release ? buffer : NULL, /* We only need the ptr for the release */ |
| 117 | + native_to_java(buffer->obj), |
| 118 | + buffer->len, |
| 119 | + buffer->readonly, |
| 120 | + buffer->itemsize, |
| 121 | + polyglot_from_string(buffer->format ? buffer->format : "B", "ascii"), |
| 122 | + buffer->ndim, |
| 123 | + polyglot_from_i8_array(buffer->buf, buffer->len), |
| 124 | + buffer->shape ? polyglot_from_size_array(buffer->shape, ndim) : NULL, |
| 125 | + buffer->strides ? polyglot_from_size_array(buffer->strides, ndim) : NULL, |
| 126 | + buffer->suboffsets ? polyglot_from_size_array(buffer->suboffsets, ndim) : NULL); |
| 127 | + if (!needs_release) { |
| 128 | + free(buffer); |
| 129 | + } |
| 130 | + return mv; |
| 131 | + } |
| 132 | + |
| 133 | + PyErr_Format(PyExc_TypeError, |
| 134 | + "memoryview: a bytes-like object is required, not '%.200s'", |
| 135 | + Py_TYPE(v)->tp_name); |
| 136 | + return NULL; |
| 137 | +} |
| 138 | + |
| 139 | +/* Release buffer struct allocated in PyTruffle_MemoryViewFromObject */ |
| 140 | +void PyTruffle_ReleaseBuffer(Py_buffer* buffer) { |
| 141 | + if (buffer->obj != NULL) { |
| 142 | + PyBufferProcs *pb; |
| 143 | + pb = Py_TYPE(buffer->obj)->tp_as_buffer; |
| 144 | + if (pb) { |
| 145 | + pb->bf_releasebuffer(buffer->obj, buffer); |
| 146 | + } |
| 147 | + } |
| 148 | + free(buffer); |
| 149 | +} |
| 150 | + |
| 151 | +PyObject* PyMemoryView_FromBuffer(Py_buffer *buffer) { |
| 152 | + Py_ssize_t ndim = buffer->ndim; |
| 153 | + if (buffer->buf == NULL) { |
| 154 | + PyErr_SetString(PyExc_ValueError, |
| 155 | + "PyMemoryView_FromBuffer(): info->buf must not be NULL"); |
| 156 | + return NULL; |
| 157 | + } |
| 158 | + return polyglot_invoke(PY_TRUFFLE_CEXT, "PyTruffle_MemoryViewFromBuffer", |
| 159 | + NULL, |
| 160 | + NULL, |
| 161 | + buffer->len, |
| 162 | + buffer->readonly, |
| 163 | + buffer->itemsize, |
| 164 | + polyglot_from_string(buffer->format ? buffer->format : "B", "ascii"), |
| 165 | + buffer->ndim, |
| 166 | + polyglot_from_i8_array(buffer->buf, buffer->len), |
| 167 | + buffer->shape ? polyglot_from_size_array(buffer->shape, ndim) : NULL, |
| 168 | + buffer->strides ? polyglot_from_size_array(buffer->strides, ndim) : NULL, |
| 169 | + buffer->suboffsets ? polyglot_from_size_array(buffer->suboffsets, ndim) : NULL); |
| 170 | +} |
| 171 | + |
| 172 | +PyObject *PyMemoryView_FromMemory(char *mem, Py_ssize_t size, int flags) { |
| 173 | + assert(mem != NULL); |
| 174 | + assert(flags == PyBUF_READ || flags == PyBUF_WRITE); |
| 175 | + int readonly = (flags == PyBUF_WRITE) ? 0 : 1; |
| 176 | + return polyglot_invoke(PY_TRUFFLE_CEXT, "PyTruffle_MemoryViewFromBuffer", |
| 177 | + NULL, NULL, size, readonly, 1, polyglot_from_string("B", "ascii"), 1, polyglot_from_i8_array((int8_t*)mem, size), NULL, NULL, NULL); |
| 178 | +} |
| 179 | + |
| 180 | +UPCALL_ID(PyMemoryView_GetContiguous) |
| 181 | +PyObject* PyMemoryView_GetContiguous(PyObject *obj, int buffertype, char order) { |
| 182 | + return UPCALL_CEXT_O(_jls_PyMemoryView_GetContiguous, native_to_java(obj), buffertype, (int)order); |
| 183 | +} |
| 184 | + |
| 185 | +/* Taken from CPython memoryobject.c: memory_getbuf */ |
| 186 | +int memoryview_getbuffer(PyMemoryViewObject *self, Py_buffer *view, int flags) |
| 187 | +{ |
| 188 | + Py_buffer *base = &self->view; |
| 189 | + int baseflags = self->flags; |
| 190 | + |
| 191 | + CHECK_RELEASED_INT(self); |
| 192 | + |
| 193 | + /* start with complete information */ |
| 194 | + //*view = *base; |
| 195 | + view->buf = base->buf; |
| 196 | + view->format = base->format; |
| 197 | + view->itemsize = base->itemsize; |
| 198 | + view->len = base->len; |
| 199 | + view->ndim = base->ndim; |
| 200 | + view->readonly = base->readonly; |
| 201 | + view->shape = base->shape; |
| 202 | + view->strides = base->strides; |
| 203 | + view->suboffsets = base->suboffsets; |
| 204 | + view->obj = NULL; |
| 205 | + |
| 206 | + if (REQ_WRITABLE(flags) && base->readonly) { |
| 207 | + PyErr_SetString(PyExc_BufferError, |
| 208 | + "memoryview: underlying buffer is not writable"); |
| 209 | + return -1; |
| 210 | + } |
| 211 | + if (!REQ_FORMAT(flags)) { |
| 212 | + /* NULL indicates that the buffer's data type has been cast to 'B'. |
| 213 | + view->itemsize is the _previous_ itemsize. If shape is present, |
| 214 | + the equality product(shape) * itemsize = len still holds at this |
| 215 | + point. The equality calcsize(format) = itemsize does _not_ hold |
| 216 | + from here on! */ |
| 217 | + view->format = NULL; |
| 218 | + } |
| 219 | + |
| 220 | + if (REQ_C_CONTIGUOUS(flags) && !MV_C_CONTIGUOUS(baseflags)) { |
| 221 | + PyErr_SetString(PyExc_BufferError, |
| 222 | + "memoryview: underlying buffer is not C-contiguous"); |
| 223 | + return -1; |
| 224 | + } |
| 225 | + if (REQ_F_CONTIGUOUS(flags) && !MV_F_CONTIGUOUS(baseflags)) { |
| 226 | + PyErr_SetString(PyExc_BufferError, |
| 227 | + "memoryview: underlying buffer is not Fortran contiguous"); |
| 228 | + return -1; |
| 229 | + } |
| 230 | + if (REQ_ANY_CONTIGUOUS(flags) && !MV_ANY_CONTIGUOUS(baseflags)) { |
| 231 | + PyErr_SetString(PyExc_BufferError, |
| 232 | + "memoryview: underlying buffer is not contiguous"); |
| 233 | + return -1; |
| 234 | + } |
| 235 | + if (!REQ_INDIRECT(flags) && (baseflags & _Py_MEMORYVIEW_PIL)) { |
| 236 | + PyErr_SetString(PyExc_BufferError, |
| 237 | + "memoryview: underlying buffer requires suboffsets"); |
| 238 | + return -1; |
| 239 | + } |
| 240 | + if (!REQ_STRIDES(flags)) { |
| 241 | + if (!MV_C_CONTIGUOUS(baseflags)) { |
| 242 | + PyErr_SetString(PyExc_BufferError, |
| 243 | + "memoryview: underlying buffer is not C-contiguous"); |
| 244 | + return -1; |
| 245 | + } |
| 246 | + view->strides = NULL; |
| 247 | + } |
| 248 | + if (!REQ_SHAPE(flags)) { |
| 249 | + /* PyBUF_SIMPLE or PyBUF_WRITABLE: at this point buf is C-contiguous, |
| 250 | + so base->buf = ndbuf->data. */ |
| 251 | + if (view->format != NULL) { |
| 252 | + /* PyBUF_SIMPLE|PyBUF_FORMAT and PyBUF_WRITABLE|PyBUF_FORMAT do |
| 253 | + not make sense. */ |
| 254 | + PyErr_Format(PyExc_BufferError, |
| 255 | + "memoryview: cannot cast to unsigned bytes if the format flag " |
| 256 | + "is present"); |
| 257 | + return -1; |
| 258 | + } |
| 259 | + /* product(shape) * itemsize = len and calcsize(format) = itemsize |
| 260 | + do _not_ hold from here on! */ |
| 261 | + view->ndim = 1; |
| 262 | + view->shape = NULL; |
| 263 | + } |
| 264 | + |
| 265 | + |
| 266 | + view->obj = (PyObject *)self; |
| 267 | + Py_INCREF(view->obj); |
| 268 | + self->exports++; |
| 269 | + |
| 270 | + return 0; |
| 271 | +} |
| 272 | + |
| 273 | +void memoryview_releasebuffer(PyMemoryViewObject *self, Py_buffer *view) { |
| 274 | + self->exports--; |
55 | 275 | }
|
0 commit comments