From: Dag Sverre Seljebotn Date: Mon, 25 Aug 2008 14:09:31 +0000 (+0200) Subject: Updated buffers to beta 3 of Py3 X-Git-Tag: 0.9.9.2.beta~63^2~31^2~2 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=ded64d16501852d39be84e7ed5116b865f6fe7c8;p=cython.git Updated buffers to beta 3 of Py3 --- diff --git a/Cython/Compiler/Buffer.py b/Cython/Compiler/Buffer.py index 637a11c8..ea5f167f 100644 --- a/Cython/Compiler/Buffer.py +++ b/Cython/Compiler/Buffer.py @@ -242,9 +242,7 @@ def put_acquire_arg_buffer(entry, code, pos): # entry.buffer_aux.buffer_info_var.cname)) def get_release_buffer_code(entry): - return "__Pyx_SafeReleaseBuffer((PyObject*)%s, &%s)" % ( - entry.cname, - entry.buffer_aux.buffer_info_var.cname) + return "__Pyx_SafeReleaseBuffer(&%s)" % entry.buffer_aux.buffer_info_var.cname def put_assign_to_buffer(lhs_cname, rhs_cname, buffer_aux, buffer_type, is_initialized, pos, code): @@ -274,8 +272,7 @@ def put_assign_to_buffer(lhs_cname, rhs_cname, buffer_aux, buffer_type, if is_initialized: # Release any existing buffer - code.putln('__Pyx_SafeReleaseBuffer((PyObject*)%s, &%s);' % ( - lhs_cname, bufstruct)) + code.putln('__Pyx_SafeReleaseBuffer(&%s);' % bufstruct) # Acquire retcode_cname = code.funcstate.allocate_temp(PyrexTypes.c_int_type) code.putln("%s = %s;" % (retcode_cname, getbuffer % rhs_cname)) @@ -606,7 +603,9 @@ def use_py2_buffer_functions(env): code += dedent(""" } - static void __Pyx_ReleaseBuffer(PyObject *obj, Py_buffer *view) { + static void __Pyx_ReleaseBuffer(Py_buffer *view) { + PyObject* obj = view->obj; + if (obj) { """) if len(types) > 0: clause = "if" @@ -615,6 +614,9 @@ def use_py2_buffer_functions(env): code += "%s (PyObject_TypeCheck(obj, %s)) %s(obj, view);" % (clause, t, release) clause = "else if" code += dedent(""" + Py_DECREF(obj); + view->obj = NULL; + } } #endif @@ -623,10 +625,10 @@ def use_py2_buffer_functions(env): env.use_utility_code([dedent("""\ #if (PY_MAJOR_VERSION < 3) && !(Py_TPFLAGS_DEFAULT & Py_TPFLAGS_HAVE_NEWBUFFER) static int __Pyx_GetBuffer(PyObject *obj, Py_buffer *view, int flags); - static void __Pyx_ReleaseBuffer(PyObject *obj, Py_buffer *view); + static void __Pyx_ReleaseBuffer(Py_buffer *view); #else #define __Pyx_GetBuffer PyObject_GetBuffer - #define __Pyx_ReleaseBuffer PyObject_ReleaseBuffer + #define __Pyx_ReleaseBuffer PyBuffer_Release #endif """), code], codename) @@ -655,20 +657,21 @@ static void __Pyx_RaiseBufferIndexError(int axis) { # exporter. # acquire_utility_code = ["""\ -static INLINE void __Pyx_SafeReleaseBuffer(PyObject* obj, Py_buffer* info); +static INLINE void __Pyx_SafeReleaseBuffer(Py_buffer* info); static INLINE void __Pyx_ZeroBuffer(Py_buffer* buf); /*proto*/ static INLINE const char* __Pyx_ConsumeWhitespace(const char* ts); /*proto*/ static INLINE const char* __Pyx_BufferTypestringCheckEndian(const char* ts); /*proto*/ static void __Pyx_BufferNdimError(Py_buffer* buffer, int expected_ndim); /*proto*/ """, """ -static INLINE void __Pyx_SafeReleaseBuffer(PyObject* obj, Py_buffer* info) { +static INLINE void __Pyx_SafeReleaseBuffer(Py_buffer* info) { if (info->buf == NULL) return; if (info->suboffsets == __Pyx_minusones) info->suboffsets = NULL; - __Pyx_ReleaseBuffer(obj, info); + __Pyx_ReleaseBuffer(info); } static INLINE void __Pyx_ZeroBuffer(Py_buffer* buf) { buf->buf = NULL; + buf->obj = NULL; buf->strides = __Pyx_zeros; buf->shape = __Pyx_zeros; buf->suboffsets = __Pyx_minusones; diff --git a/Cython/Compiler/Builtin.py b/Cython/Compiler/Builtin.py index 3c468fe0..3d11eeb9 100644 --- a/Cython/Compiler/Builtin.py +++ b/Cython/Compiler/Builtin.py @@ -104,14 +104,15 @@ builtin_types_table = [ builtin_structs_table = [ ('Py_buffer', 'Py_buffer', [("buf", PyrexTypes.c_void_ptr_type), + ("obj", PyrexTypes.py_object_type), ("len", PyrexTypes.c_py_ssize_t_type), + ("itemsize", PyrexTypes.c_py_ssize_t_type), ("readonly", PyrexTypes.c_bint_type), - ("format", PyrexTypes.c_char_ptr_type), ("ndim", PyrexTypes.c_int_type), + ("format", PyrexTypes.c_char_ptr_type), ("shape", PyrexTypes.c_py_ssize_t_ptr_type), ("strides", PyrexTypes.c_py_ssize_t_ptr_type), ("suboffsets", PyrexTypes.c_py_ssize_t_ptr_type), - ("itemsize", PyrexTypes.c_py_ssize_t_type), ("internal", PyrexTypes.c_void_ptr_type), ]) ] diff --git a/Cython/Compiler/ModuleNode.py b/Cython/Compiler/ModuleNode.py index 23cb1145..d7fb6b1c 100644 --- a/Cython/Compiler/ModuleNode.py +++ b/Cython/Compiler/ModuleNode.py @@ -429,14 +429,15 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): code.putln("") code.putln(" typedef struct {") code.putln(" void *buf;") + code.putln(" PyObject *obj;") code.putln(" Py_ssize_t len;") + code.putln(" Py_ssize_t itemsize;") code.putln(" int readonly;") - code.putln(" const char *format;") code.putln(" int ndim;") + code.putln(" char *format;") code.putln(" Py_ssize_t *shape;") code.putln(" Py_ssize_t *strides;") code.putln(" Py_ssize_t *suboffsets;") - code.putln(" Py_ssize_t itemsize;") code.putln(" void *internal;") code.putln(" } Py_buffer;") code.putln("") diff --git a/Cython/Compiler/Nodes.py b/Cython/Compiler/Nodes.py index d3596ea2..ce0cb38a 100644 --- a/Cython/Compiler/Nodes.py +++ b/Cython/Compiler/Nodes.py @@ -860,6 +860,9 @@ class FuncDefNode(StatNode, BlockNode): lenv = self.local_scope + is_getbuffer_slot = (self.entry.name == "__getbuffer__" and + self.entry.scope.is_c_class_scope) + # Generate C code for header and body of function code.enter_cfunc_scope() code.return_from_error_cleanup_label = code.new_label() @@ -902,6 +905,9 @@ class FuncDefNode(StatNode, BlockNode): acquire_gil = self.need_gil_acquisition(lenv) if acquire_gil: code.putln("PyGILState_STATE _save = PyGILState_Ensure();") + # ----- Automatic lead-ins for certain special functions + if is_getbuffer_slot: + self.getbuffer_init(code) # ----- Fetch arguments self.generate_argument_parsing_code(env, code) # If an argument is assigned to in the body, we must @@ -971,17 +977,27 @@ class FuncDefNode(StatNode, BlockNode): "%s = %s;" % ( Naming.retval_cname, err_val)) - if buffers_present: - # Else, non-error return will be an empty clause + + if is_getbuffer_slot: + self.getbuffer_error_cleanup(code) + + # If we are using the non-error cleanup section we should + # jump past it if we have an error. The if-test below determine + # whether this section is used. + if buffers_present or is_getbuffer_slot: code.put_goto(code.return_from_error_cleanup_label) + # ----- Non-error return cleanup - # PS! If adding something here, modify the conditions for the - # goto statement in error cleanup above + # If you add anything here, remember to add a condition to the + # if-test above in the error block (so that it can jump past this + # block). code.put_label(code.return_label) for entry in lenv.buffer_entries: if entry.used: code.putln("%s;" % Buffer.get_release_buffer_code(entry)) + if is_getbuffer_slot: + self.getbuffer_normal_cleanup(code) # ----- Return cleanup for both error and no-error return code.put_label(code.return_from_error_cleanup_label) if not Options.init_local_none: @@ -1042,8 +1058,27 @@ class FuncDefNode(StatNode, BlockNode): # For Python class methods, create and store function object if self.assmt: self.assmt.generate_execution_code(code) - + # + # Special code for the __getbuffer__ call + # + def getbuffer_init(self, code): + info = self.local_scope.arg_entries[1].cname + # Python 3.0 betas have a bug in memoryview which makes it call + # getbuffer with a NULL parameter. For now we work around this; + # the following line should be removed when this bug is fixed. + code.putln("if (%s == NULL) return 0;" % info) + code.putln("%s->obj = Py_None; Py_INCREF(Py_None);" % info) + + def getbuffer_error_cleanup(self, code): + info = self.local_scope.arg_entries[1].cname + code.putln("Py_DECREF(%s->obj); %s->obj = NULL;" % + (info, info)) + + def getbuffer_normal_cleanup(self, code): + info = self.local_scope.arg_entries[1].cname + code.putln("if (%s->obj == Py_None) { Py_DECREF(Py_None); %s->obj = NULL; }" % + (info, info)) class CFuncDefNode(FuncDefNode): # C function definition. diff --git a/Cython/Includes/numpy.pxd b/Cython/Includes/numpy.pxd index db7d4b9c..5d987418 100644 --- a/Cython/Includes/numpy.pxd +++ b/Cython/Includes/numpy.pxd @@ -43,6 +43,7 @@ cdef extern from "numpy/arrayobject.h": raise RuntimeError("Py_intptr_t and Py_ssize_t differs in size, numpy.pxd does not support this") info.buf = PyArray_DATA(self) + # info.obj = None # this is automatic info.ndim = PyArray_NDIM(self) info.strides = PyArray_STRIDES(self) info.shape = PyArray_DIMS(self) diff --git a/tests/run/bufaccess.pyx b/tests/run/bufaccess.pyx index f0f3e04f..4bfb8186 100644 --- a/tests/run/bufaccess.pyx +++ b/tests/run/bufaccess.pyx @@ -25,11 +25,11 @@ setup_string = u""" """ -def testcase(func): +def testcase2(func): __test__[func.__name__] = setup_string + func.__doc__ return func -def testcas(a): +def testcase(a): pass @@ -50,7 +50,7 @@ def printbuf(): cdef object[int, ndim=2] buf print buf -@testcase +@testcase2 def acquire_release(o1, o2): """ >>> acquire_release(A, B) @@ -949,11 +949,10 @@ cdef class MockBuffer: def __getbuffer__(MockBuffer self, Py_buffer* buffer, int flags): if self.fail: raise ValueError("Failing on purpose") - - if buffer is NULL: - print u"locking!" - return + if buffer == NULL: + return + self.recieved_flags = [] cdef int value for name, value in available_flags: @@ -961,6 +960,7 @@ cdef class MockBuffer: self.recieved_flags.append(name) buffer.buf = (self.buffer + (self.offset * self.itemsize)) + buffer.obj = self buffer.len = self.len buffer.readonly = 0 buffer.format = self.format diff --git a/tests/run/buffer.pyx b/tests/run/buffer.pyx index be93bfad..07d344e1 100644 --- a/tests/run/buffer.pyx +++ b/tests/run/buffer.pyx @@ -8,18 +8,16 @@ if sys.version_info[0] >= 3: __doc__ += u""" >>> ms = memoryview(s) >>> ms.tobytes() -bytearray(b'abcdefg') +b'abcdefg' >>> m1 = memoryview(b1) >>> m1.tobytes() -locking! -bytearray(b'abcdefg') +b'abcdefg' >>> m2 = memoryview(b2) >>> m2.tobytes() -locking! -unlocking! -bytearray(b'abcdefg') +releasing! +b'abcdefg' >>> del m1 >>> del m2 @@ -30,10 +28,8 @@ s = "abcdefg" cdef class TestBuffer: def __getbuffer__(self, Py_buffer* buffer, int flags): - if buffer is NULL: - print u"locking!" - return buffer.buf = s + buffer.obj = self buffer.len = len(s) buffer.readonly = 0 buffer.format = "B" @@ -46,7 +42,4 @@ cdef class TestBuffer: cdef class TestBufferRelease(TestBuffer): def __releasebuffer__(self, Py_buffer* buffer): - if buffer is NULL: - print u"unlocking!" - else: - print u"releasing!" + print u"releasing!"