Author: Maciej Fijalkowski <[email protected]>
Branch: gc-minimark-pinning
Changeset: r54992:96708b4d184f
Date: 2012-05-08 17:50 +0200
http://bitbucket.org/pypy/pypy/changeset/96708b4d184f/
Log: use direct pinning in rffi, leave few unclear comments about the
JIT, looks good
diff --git a/pypy/rpython/lltypesystem/rffi.py
b/pypy/rpython/lltypesystem/rffi.py
--- a/pypy/rpython/lltypesystem/rffi.py
+++ b/pypy/rpython/lltypesystem/rffi.py
@@ -703,7 +703,8 @@
i += 1
return assert_str0(b.build())
- # str -> char*
+ # str -> char*, bool, bool
+ # XXX is still the JIT unhappy with that? investigate
# Can't inline this because of the raw address manipulation.
@jit.dont_look_inside
def get_nonmovingbuffer(data):
@@ -729,7 +730,8 @@
return cast(TYPEP, data_start), pinned, False
get_nonmovingbuffer._annenforceargs_ = [strtype]
- # (str, char*) -> None
+ # (str, char*, bool, bool) -> None
+ # XXX is still the JIT unhappy with that? investigate
# Can't inline this because of the raw address manipulation.
@jit.dont_look_inside
def free_nonmovingbuffer(data, buf, pinned, is_raw):
@@ -748,34 +750,41 @@
keepalive_until_here(data)
free_nonmovingbuffer._annenforceargs_ = [strtype, None, bool, bool]
- # int -> (char*, str)
+ # int -> (char*, str, bool)
def alloc_buffer(count):
"""
- Returns a (raw_buffer, gc_buffer) pair, allocated with count bytes.
- The raw_buffer can be safely passed to a native function which expects
- it to not move. Call str_from_buffer with the returned values to get a
- safe high-level string. When the garbage collector cooperates, this
+ Returns a (raw_buffer, gc_buffer, pinned) triplet, allocated
+ with count bytes. The raw_buffer can be safely passed to a
+ native function which expects it to not move. Call
+ str_from_buffer with the returned values to get a safe
+ high-level string. When the garbage collector cooperates, this
allows for the process to be performed without an extra copy.
- Make sure to call keep_buffer_alive_until_here on the returned values.
+ Make sure to call keep_buffer_alive_until_here on the returned
+ values.
- Right now this is a version optimized for minimark which can pin values
- in the nursery.
+ Right now this is a version optimized for minimark which can
+ pin values in the nursery.
"""
- ll_s = rgc.malloc_and_pin(STRTYPE, count)
- if not ll_s:
- raw_buf = lltype.malloc(TYPEP.TO, count, flavor='raw')
- return raw_buf, lltype.nullptr(STRTYPE)
+ ll_s = lltype.malloc(STRTYPE, count)
+ if rgc.can_move(ll_s):
+ pinned = rgc.pin(ll_s)
+ if not pinned:
+ raw_buf = lltype.malloc(TYPEP.TO, count, flavor='raw')
+ return raw_buf, lltype.nullptr(STRTYPE), False
else:
- data_start = cast_ptr_to_adr(ll_s) + \
- offsetof(STRTYPE, 'chars') + itemoffsetof(STRTYPE.chars, 0)
- raw_buf = cast(TYPEP, data_start)
- return raw_buf, ll_s
+ pinned = False
+ data_start = cast_ptr_to_adr(ll_s) + \
+ offsetof(STRTYPE, 'chars') + itemoffsetof(STRTYPE.chars,
0)
+ raw_buf = cast(TYPEP, data_start)
+ return raw_buf, ll_s, pinned
alloc_buffer._always_inline_ = True # to get rid of the returned tuple
alloc_buffer._annenforceargs_ = [int]
- # (char*, str, int, int) -> None
+ # (char*, str, int, int, bool) -> None
+ # XXX is still the JIT unhappy with that? investigate
@jit.dont_look_inside
- def str_from_buffer(raw_buf, gc_buf, allocated_size, needed_size):
+ def str_from_buffer(raw_buf, gc_buf, allocated_size, needed_size,
+ is_pinned):
"""
Converts from a pair returned by alloc_buffer to a high-level string.
The returned string will be truncated to needed_size.
@@ -783,7 +792,8 @@
assert allocated_size >= needed_size
if gc_buf:
- rgc.unpin(gc_buf)
+ if is_pinned:
+ rgc.unpin(gc_buf)
if allocated_size != needed_size:
gc_buf = rgc.ll_shrink_array(gc_buf, needed_size)
return hlstrtype(gc_buf)
@@ -803,6 +813,7 @@
return hlstrtype(new_buf)
# (char*, str) -> None
+ # XXX is the JIT unhappy?
@jit.dont_look_inside
def keep_buffer_alive_until_here(raw_buf, gc_buf):
"""
@@ -1088,23 +1099,25 @@
def __init__(self, size):
self.size = size
def __enter__(self):
- self.raw, self.gc_buf = alloc_buffer(self.size)
+ self.raw, self.gc_buf, self.pinned = alloc_buffer(self.size)
return self
def __exit__(self, *args):
keep_buffer_alive_until_here(self.raw, self.gc_buf)
def str(self, length):
- return str_from_buffer(self.raw, self.gc_buf, self.size, length)
+ return str_from_buffer(self.raw, self.gc_buf, self.size, length,
+ self.pinned)
class scoped_alloc_unicodebuffer:
def __init__(self, size):
self.size = size
def __enter__(self):
- self.raw, self.gc_buf = alloc_unicodebuffer(self.size)
+ self.raw, self.gc_buf, self.pinned = alloc_unicodebuffer(self.size)
return self
def __exit__(self, *args):
keep_unicodebuffer_alive_until_here(self.raw, self.gc_buf)
def str(self, length):
- return unicode_from_buffer(self.raw, self.gc_buf, self.size, length)
+ return unicode_from_buffer(self.raw, self.gc_buf, self.size, length,
+ self.pinned)
# You would have to have a *huge* amount of data for this to block long enough
# to be worth it to release the GIL.
diff --git a/pypy/rpython/module/ll_os.py b/pypy/rpython/module/ll_os.py
--- a/pypy/rpython/module/ll_os.py
+++ b/pypy/rpython/module/ll_os.py
@@ -880,20 +880,15 @@
[rffi.INT, rffi.VOIDP, rffi.SIZE_T],
rffi.SIZE_T)
- offset = offsetof(STR, 'chars') + itemoffsetof(STR.chars, 0)
-
def os_read_llimpl(fd, count):
if count < 0:
raise OSError(errno.EINVAL, None)
- raw_buf, gc_buf = rffi.alloc_buffer(count)
- try:
- void_buf = rffi.cast(rffi.VOIDP, raw_buf)
+ with rffi.scoped_alloc_buffer(count) as buf:
+ void_buf = rffi.cast(rffi.VOIDP, buf.raw)
got = rffi.cast(lltype.Signed, os_read(fd, void_buf, count))
if got < 0:
raise OSError(rposix.get_errno(), "os_read failed")
- return rffi.str_from_buffer(raw_buf, gc_buf, count, got)
- finally:
- rffi.keep_buffer_alive_until_here(raw_buf, gc_buf)
+ return buf.str(got)
def os_read_oofakeimpl(fd, count):
return OOSupport.to_rstr(os.read(fd, count))
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit