Author: Devin Jeanpierre <[email protected]>
Branch: cpyext-old-buffers
Changeset: r84753:5370a01c9140
Date: 2016-05-27 18:14 -0700
http://bitbucket.org/pypy/pypy/changeset/5370a01c9140/
Log: Special-case buffer in typeobject.py instead of leaking for
get_raw_address().
diff --git a/pypy/module/cpyext/bufferobject.py
b/pypy/module/cpyext/bufferobject.py
--- a/pypy/module/cpyext/bufferobject.py
+++ b/pypy/module/cpyext/bufferobject.py
@@ -1,4 +1,4 @@
-from rpython.rlib.buffer import Buffer, StringBuffer, SubBuffer
+from rpython.rlib.buffer import StringBuffer, SubBuffer
from rpython.rtyper.lltypesystem import rffi, lltype
from pypy.interpreter.error import oefmt
from pypy.module.cpyext.api import (
@@ -9,54 +9,6 @@
from pypy.objspace.std.bufferobject import W_Buffer
-class LeakedBuffer(Buffer):
- __slots__ = ['buf','ptr']
- _immutable_ = True
-
- def __init__(self, buffer):
- if not buffer.readonly:
- raise ValueError("Can only leak a copy of a readonly buffer.")
- self.buf = buffer
- self.readonly = True
- self.ptr = rffi.cast(rffi.VOIDP, rffi.str2charp(self.buf.as_str()))
-
- def getlength(self):
- return self.buf.getlength()
-
- def as_str(self):
- return self.buf.as_str()
-
- def as_str_and_offset_maybe(self):
- return self.buf.as_str_and_offset_maybe()
-
- def getitem(self, index):
- return self.buf.getitem(index)
-
- def getslice(self, start, stop, step, size):
- return self.buf.getslice(start, stop, step, size)
-
- def setitem(self, index, char):
- return self.buf.setitem(index)
-
- def setslice(self, start, string):
- return self.buf.setslice(start, string)
-
- def get_raw_address(self):
- return self.ptr
-
-
-def leak_stringbuffer(buf):
- if isinstance(buf, StringBuffer):
- return LeakedBuffer(buf)
- elif isinstance(buf, SubBuffer):
- leaked = leak_stringbuffer(buf.buffer)
- if leaked is None:
- return leaked
- return SubBuffer(leaked, buf.offset, buf.size)
- else:
- return None
-
-
PyBufferObjectStruct = lltype.ForwardReference()
PyBufferObject = lltype.Ptr(PyBufferObjectStruct)
PyBufferObjectFields = PyObjectFields + (
@@ -91,19 +43,17 @@
assert isinstance(w_obj, W_Buffer)
buf = w_obj.buf
- w_obj.buf = buf = leak_stringbuffer(buf) or buf
- # Now, if it was backed by a StringBuffer, it is now a LeakedBuffer.
- # We deliberately copy the string so that we can have a pointer to it,
- # and we make it accessible in the buffer through get_raw_address(), so
that
- # we can reuse it elsewhere in the C API.
-
if isinstance(buf, SubBuffer):
py_buf.c_b_offset = buf.offset
buf = buf.buffer
- if isinstance(buf, LeakedBuffer):
+ # If buf already allocated a fixed buffer, use it, and keep a
+ # reference to buf.
+ # Otherwise, b_base stays NULL, and we own the b_ptr.
+
+ if isinstance(buf, StringBuffer):
py_buf.c_b_base = lltype.nullptr(PyObject.TO)
- py_buf.c_b_ptr = buf.get_raw_address()
+ py_buf.c_b_ptr = rffi.cast(rffi.VOIDP, rffi.str2charp(buf.value))
py_buf.c_b_size = buf.getlength()
elif isinstance(buf, ArrayBuffer):
w_base = buf.array
diff --git a/pypy/module/cpyext/typeobject.py b/pypy/module/cpyext/typeobject.py
--- a/pypy/module/cpyext/typeobject.py
+++ b/pypy/module/cpyext/typeobject.py
@@ -453,7 +453,7 @@
def bf_getreadbuffer(space, w_buf, segment, ref):
if segment != 0:
raise oefmt(space.w_SystemError,
- "accessing non-existent buffer segment")
+ "accessing non-existent segment")
buf = space.readbuf_w(w_buf)
address = buf.get_raw_address()
ref[0] = address
@@ -464,19 +464,17 @@
def bf_getcharbuffer(space, w_buf, segment, ref):
return bf_getreadbuffer(space, w_buf, segment, rffi.cast(rffi.VOIDPP, ref))
-
@cpython_api([PyObject, Py_ssize_t, rffi.VOIDPP], lltype.Signed,
header=None, error=-1)
def bf_getwritebuffer(space, w_buf, segment, ref):
if segment != 0:
raise oefmt(space.w_SystemError,
- "accessing non-existent buffer segment")
+ "accessing non-existent segment")
buf = space.writebuf_w(w_buf)
ref[0] = buf.get_raw_address()
return len(buf)
-
@cpython_api([PyObject, Py_ssize_t, rffi.VOIDPP], lltype.Signed,
header=None, error=-1)
def str_getreadbuffer(space, w_str, segment, ref):
@@ -490,12 +488,26 @@
Py_DecRef(space, pyref)
return space.len_w(w_str)
-
@cpython_api([PyObject, Py_ssize_t, rffi.CCHARPP], lltype.Signed,
header=None, error=-1)
def str_getcharbuffer(space, w_buf, segment, ref):
return str_getreadbuffer(space, w_buf, segment, rffi.cast(rffi.VOIDPP,
ref))
+@cpython_api([PyObject, Py_ssize_t, rffi.VOIDPP], lltype.Signed,
+ header=None, error=-1)
+def buf_getreadbuffer(space, pyref, segment, ref):
+ from pypy.module.cpyext.bufferobject import PyBufferObject
+ if segment != 0:
+ raise oefmt(space.w_SystemError,
+ "accessing non-existent buffer segment")
+ py_buf = rffi.cast(PyBufferObject, pyref)
+ ref[0] = py_buf.c_b_ptr
+ return py_buf.c_b_size
+
+@cpython_api([PyObject, Py_ssize_t, rffi.CCHARPP], lltype.Signed,
+ header=None, error=-1)
+def buf_getcharbuffer(space, w_buf, segment, ref):
+ return buf_getreadbuffer(space, w_buf, segment, rffi.cast(rffi.VOIDPP,
ref))
def setup_buffer_procs(space, w_type, pto):
bufspec = w_type.layout.typedef.buffer
@@ -516,6 +528,17 @@
c_buf.c_bf_getcharbuffer = llhelper(
str_getcharbuffer.api_func.functype,
str_getcharbuffer.api_func.get_wrapper(space))
+ elif space.is_w(w_type, space.w_buffer):
+ # Special case: we store a permanent address on the cpyext wrapper,
+ # so we'll reuse that.
+ # Note: we could instead store a permanent address on the buffer
object,
+ # and use get_raw_address()
+ c_buf.c_bf_getreadbuffer = llhelper(
+ buf_getreadbuffer.api_func.functype,
+ buf_getreadbuffer.api_func.get_wrapper(space))
+ c_buf.c_bf_getcharbuffer = llhelper(
+ buf_getcharbuffer.api_func.functype,
+ buf_getcharbuffer.api_func.get_wrapper(space))
else:
# use get_raw_address()
c_buf.c_bf_getreadbuffer = llhelper(bf_getreadbuffer.api_func.functype,
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit