Author: Maciej Fijalkowski <fij...@gmail.com> 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 pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit