[pypy-commit] pypy null_byte_after_str: cffi: tentatively pass the raw address inside RPython strings
arigo
pypy.commits at gmail.com
Fri Jul 29 14:10:03 EDT 2016
Author: Armin Rigo <arigo at tunes.org>
Branch: null_byte_after_str
Changeset: r85916:f2f9031b0f4b
Date: 2016-07-29 20:11 +0200
http://bitbucket.org/pypy/pypy/changeset/f2f9031b0f4b/
Log: cffi: tentatively pass the raw address inside RPython strings
diff --git a/pypy/module/_cffi_backend/ctypefunc.py b/pypy/module/_cffi_backend/ctypefunc.py
--- a/pypy/module/_cffi_backend/ctypefunc.py
+++ b/pypy/module/_cffi_backend/ctypefunc.py
@@ -177,9 +177,12 @@
if isinstance(argtype, W_CTypePointer):
data = rffi.ptradd(buffer, cif_descr.exchange_args[i])
flag = get_mustfree_flag(data)
+ raw_cdata = rffi.cast(rffi.CCHARPP, data)[0]
if flag == 1:
- raw_cdata = rffi.cast(rffi.CCHARPP, data)[0]
lltype.free(raw_cdata, flavor='raw')
+ elif flag >= 4:
+ value = args_w[i].str_w(space)
+ rffi.free_nonmovingbuffer(value, raw_cdata, chr(flag))
lltype.free(buffer, flavor='raw')
keepalive_until_here(args_w)
return w_res
diff --git a/pypy/module/_cffi_backend/ctypeptr.py b/pypy/module/_cffi_backend/ctypeptr.py
--- a/pypy/module/_cffi_backend/ctypeptr.py
+++ b/pypy/module/_cffi_backend/ctypeptr.py
@@ -14,8 +14,8 @@
class W_CTypePtrOrArray(W_CType):
- _attrs_ = ['ctitem', 'can_cast_anything', 'length']
- _immutable_fields_ = ['ctitem', 'can_cast_anything', 'length']
+ _attrs_ = ['ctitem', 'can_cast_anything', 'accept_str', 'length']
+ _immutable_fields_ = ['ctitem', 'can_cast_anything', 'accept_str', 'length']
length = -1
def __init__(self, space, size, extra, extra_position, ctitem,
@@ -28,6 +28,9 @@
# - for functions, it is the return type
self.ctitem = ctitem
self.can_cast_anything = could_cast_anything and ctitem.cast_anything
+ self.accept_str = (self.can_cast_anything or
+ (ctitem.is_primitive_integer and
+ ctitem.size == rffi.sizeof(lltype.Char)))
def is_unichar_ptr_or_array(self):
return isinstance(self.ctitem, ctypeprim.W_CTypePrimitiveUniChar)
@@ -70,9 +73,7 @@
pass
else:
self._convert_array_from_listview(cdata, space.listview(w_ob))
- elif (self.can_cast_anything or
- (self.ctitem.is_primitive_integer and
- self.ctitem.size == rffi.sizeof(lltype.Char))):
+ elif self.accept_str:
if not space.isinstance_w(w_ob, space.w_str):
raise self._convert_error("str or list or tuple", w_ob)
s = space.str_w(w_ob)
@@ -262,6 +263,15 @@
def _prepare_pointer_call_argument(self, w_init, cdata):
space = self.space
+ if self.accept_str and space.isinstance_w(w_init, space.w_str):
+ # special case to optimize strings passed to a "char *" argument
+ # WARNING: this relies on the fact that w_init.str_w() returns
+ # always the same object for the same w_init!
+ value = w_init.str_w(space)
+ buf, buf_flag = rffi.get_nonmovingbuffer_final_null(value)
+ rffi.cast(rffi.CCHARPP, cdata)[0] = buf
+ return ord(buf_flag) # 4, 5 or 6
+ #
if (space.isinstance_w(w_init, space.w_list) or
space.isinstance_w(w_init, space.w_tuple)):
length = space.int_w(space.len(w_init))
diff --git a/pypy/module/_ssl/interp_ssl.py b/pypy/module/_ssl/interp_ssl.py
--- a/pypy/module/_ssl/interp_ssl.py
+++ b/pypy/module/_ssl/interp_ssl.py
@@ -135,7 +135,7 @@
def __init__(self, ctx, protos):
self.protos = protos
- self.buf, self.pinned, self.is_raw = rffi.get_nonmovingbuffer(protos)
+ self.buf, self.bufflag = rffi.get_nonmovingbuffer(protos)
NPN_STORAGE.set(rffi.cast(lltype.Unsigned, self.buf), self)
# set both server and client callbacks, because the context
@@ -147,7 +147,7 @@
def __del__(self):
rffi.free_nonmovingbuffer(
- self.protos, self.buf, self.pinned, self.is_raw)
+ self.protos, self.buf, self.bufflag)
@staticmethod
def advertiseNPN_cb(s, data_ptr, len_ptr, args):
@@ -181,7 +181,7 @@
def __init__(self, ctx, protos):
self.protos = protos
- self.buf, self.pinned, self.is_raw = rffi.get_nonmovingbuffer(protos)
+ self.buf, self.bufflag = rffi.get_nonmovingbuffer(protos)
ALPN_STORAGE.set(rffi.cast(lltype.Unsigned, self.buf), self)
with rffi.scoped_str2charp(protos) as protos_buf:
@@ -193,7 +193,7 @@
def __del__(self):
rffi.free_nonmovingbuffer(
- self.protos, self.buf, self.pinned, self.is_raw)
+ self.protos, self.buf, self.bufflag)
@staticmethod
def selectALPN_cb(s, out_ptr, outlen_ptr, client, client_len, args):
diff --git a/pypy/objspace/std/bytesobject.py b/pypy/objspace/std/bytesobject.py
--- a/pypy/objspace/std/bytesobject.py
+++ b/pypy/objspace/std/bytesobject.py
@@ -451,6 +451,9 @@
return self._value
def str_w(self, space):
+ # WARNING: _cffi_backend/ctypeptr.py depends on the fact that
+ # w_obj.str_w() called twice on the same object returns the
+ # exact same string object!
return self._value
def buffer_w(self, space, flags):
diff --git a/rpython/rtyper/lltypesystem/rffi.py b/rpython/rtyper/lltypesystem/rffi.py
--- a/rpython/rtyper/lltypesystem/rffi.py
+++ b/rpython/rtyper/lltypesystem/rffi.py
@@ -816,9 +816,10 @@
string is already nonmovable or could be pinned. Must be followed by a
free_nonmovingbuffer call.
- First bool returned indicates if 'data' was pinned. Second bool returned
- indicates if we did a raw alloc because pinning failed. Both bools
- should never be true at the same time.
+ Also returns a char:
+ * \4: no pinning, returned pointer is inside 'data' which is nonmovable
+ * \5: 'data' was pinned, returned pointer is inside
+ * \6: pinning failed, returned pointer is raw malloced
For strings (not unicodes), the len()th character of the resulting
raw buffer is available, but not initialized. Use
@@ -829,15 +830,16 @@
lldata = llstrtype(data)
count = len(data)
- pinned = False
- if rgc.can_move(data):
+ if not rgc.can_move(data):
+ flag = '\x04'
+ else:
if rgc.pin(data):
- pinned = True
+ flag = '\x05'
else:
- count += has_final_null_char(TYPEP)
- buf = lltype.malloc(TYPEP.TO, count, flavor='raw')
+ buf = lltype.malloc(TYPEP.TO, count + (TYPEP is CCHARP),
+ flavor='raw')
copy_string_to_raw(lldata, buf, 0, count)
- return buf, pinned, True
+ return buf, '\x06'
# ^^^ raw malloc used to get a nonmovable copy
#
# following code is executed if:
@@ -846,7 +848,7 @@
data_start = cast_ptr_to_adr(lldata) + \
offsetof(STRTYPE, 'chars') + itemoffsetof(STRTYPE.chars, 0)
- return cast(TYPEP, data_start), pinned, False
+ return cast(TYPEP, data_start), flag
# ^^^ already nonmovable. Therefore it's not raw allocated nor
# pinned.
get_nonmovingbuffer._always_inline_ = 'try' # get rid of the returned tuple
@@ -854,28 +856,28 @@
@jit.dont_look_inside
def get_nonmovingbuffer_final_null(data):
- buf, is_pinned, is_raw = get_nonmovingbuffer(data)
+ buf, flag = get_nonmovingbuffer(data)
buf[len(data)] = lastchar
- return buf, is_pinned, is_raw
+ return buf, flag
get_nonmovingbuffer_final_null._always_inline_ = 'try'
get_nonmovingbuffer_final_null._annenforceargs_ = [strtype]
- # (str, char*, bool, bool) -> None
+ # (str, char*, char) -> None
# Can't inline this because of the raw address manipulation.
@jit.dont_look_inside
- def free_nonmovingbuffer(data, buf, is_pinned, is_raw):
+ def free_nonmovingbuffer(data, buf, flag):
"""
- Keep 'data' alive and unpin it if it was pinned ('is_pinned' is true).
- Otherwise free the non-moving copy ('is_raw' is true).
+ Keep 'data' alive and unpin it if it was pinned (flag==\5).
+ Otherwise free the non-moving copy (flag==\6).
"""
- if is_pinned:
+ if flag == '\x05':
rgc.unpin(data)
- if is_raw:
+ if flag == '\x06':
lltype.free(buf, flavor='raw')
- # if is_pinned and is_raw are false: data was already nonmovable,
+ # if flag == '\x04': data was already nonmovable,
# we have nothing to clean up
keepalive_until_here(data)
- free_nonmovingbuffer._annenforceargs_ = [strtype, None, bool, bool]
+ free_nonmovingbuffer._annenforceargs_ = [strtype, None, None]
# int -> (char*, str, int)
# Can't inline this because of the raw address manipulation.
@@ -1209,10 +1211,10 @@
def __init__(self, data):
self.data = data
def __enter__(self):
- self.buf, self.pinned, self.is_raw = get_nonmovingbuffer(self.data)
+ self.buf, self.flag = get_nonmovingbuffer(self.data)
return self.buf
def __exit__(self, *args):
- free_nonmovingbuffer(self.data, self.buf, self.pinned, self.is_raw)
+ free_nonmovingbuffer(self.data, self.buf, self.flag)
__init__._always_inline_ = 'try'
__enter__._always_inline_ = 'try'
__exit__._always_inline_ = 'try'
@@ -1221,11 +1223,10 @@
def __init__(self, data):
self.data = data
def __enter__(self):
- self.buf, self.pinned, self.is_raw = (
- get_nonmovingbuffer_final_null(self.data))
+ self.buf, self.flag = get_nonmovingbuffer_final_null(self.data)
return self.buf
def __exit__(self, *args):
- free_nonmovingbuffer(self.data, self.buf, self.pinned, self.is_raw)
+ free_nonmovingbuffer(self.data, self.buf, self.flag)
__init__._always_inline_ = 'try'
__enter__._always_inline_ = 'try'
__exit__._always_inline_ = 'try'
@@ -1234,10 +1235,10 @@
def __init__(self, data):
self.data = data
def __enter__(self):
- self.buf, self.pinned, self.is_raw = get_nonmoving_unicodebuffer(self.data)
+ self.buf, self.flag = get_nonmoving_unicodebuffer(self.data)
return self.buf
def __exit__(self, *args):
- free_nonmoving_unicodebuffer(self.data, self.buf, self.pinned, self.is_raw)
+ free_nonmoving_unicodebuffer(self.data, self.buf, self.flag)
__init__._always_inline_ = 'try'
__enter__._always_inline_ = 'try'
__exit__._always_inline_ = 'try'
diff --git a/rpython/rtyper/lltypesystem/test/test_rffi.py b/rpython/rtyper/lltypesystem/test/test_rffi.py
--- a/rpython/rtyper/lltypesystem/test/test_rffi.py
+++ b/rpython/rtyper/lltypesystem/test/test_rffi.py
@@ -516,7 +516,7 @@
def test_nonmovingbuffer(self):
d = 'some cool data that should not move'
def f():
- buf, is_pinned, is_raw = get_nonmovingbuffer(d)
+ buf, flag = get_nonmovingbuffer(d)
try:
counter = 0
for i in range(len(d)):
@@ -524,7 +524,7 @@
counter += 1
return counter
finally:
- free_nonmovingbuffer(d, buf, is_pinned, is_raw)
+ free_nonmovingbuffer(d, buf, flag)
assert f() == len(d)
fn = self.compile(f, [], gcpolicy='ref')
assert fn() == len(d)
@@ -534,13 +534,13 @@
def f():
counter = 0
for n in range(32):
- buf, is_pinned, is_raw = get_nonmovingbuffer(d)
+ buf, flag = get_nonmovingbuffer(d)
try:
for i in range(len(d)):
if buf[i] == d[i]:
counter += 1
finally:
- free_nonmovingbuffer(d, buf, is_pinned, is_raw)
+ free_nonmovingbuffer(d, buf, flag)
return counter
fn = self.compile(f, [], gcpolicy='semispace')
# The semispace gc uses raw_malloc for its internal data structs
@@ -555,13 +555,13 @@
def f():
counter = 0
for n in range(32):
- buf, is_pinned, is_raw = get_nonmovingbuffer(d)
+ buf, flag = get_nonmovingbuffer(d)
try:
for i in range(len(d)):
if buf[i] == d[i]:
counter += 1
finally:
- free_nonmovingbuffer(d, buf, is_pinned, is_raw)
+ free_nonmovingbuffer(d, buf, flag)
return counter
fn = self.compile(f, [], gcpolicy='incminimark')
# The incminimark gc uses raw_malloc for its internal data structs
More information about the pypy-commit
mailing list