def f(): libc = CDLL(get_libc_name()) qsort = libc.getpointer( 'qsort', [ffi_type_pointer, ffi_size_t, ffi_size_t, ffi_type_pointer], ffi_type_void) ptr = CallbackFuncPtr([ffi_type_pointer, ffi_type_pointer], ffi_type_sint, callback) TP = rffi.CArray(rffi.LONG) to_sort = lltype.malloc(TP, 4, flavor='raw') to_sort[0] = 4 to_sort[1] = 3 to_sort[2] = 1 to_sort[3] = 2 qsort.push_arg(rffi.cast(rffi.VOIDP, to_sort)) qsort.push_arg(rffi.cast(rffi.SIZE_T, 4)) qsort.push_arg(rffi.cast(rffi.SIZE_T, rffi.sizeof(rffi.LONG))) qsort.push_arg(rffi.cast(rffi.VOIDP, ptr.ll_closure)) qsort.call(lltype.Void) result = [to_sort[i] for i in range(4)] == [1, 2, 3, 4] lltype.free(to_sort, flavor='raw') keepalive_until_here(ptr) return int(result)
def ll_arraycopy(source, dest, source_start, dest_start, length): from pypy.rpython.lltypesystem.lloperation import llop from pypy.rpython.lltypesystem import lltype, llmemory from pypy.rlib.objectmodel import keepalive_until_here # supports non-overlapping copies only if not we_are_translated(): if source == dest: assert (source_start + length <= dest_start or dest_start + length <= source_start) TP = lltype.typeOf(source).TO assert TP == lltype.typeOf(dest).TO if isinstance(TP.OF, lltype.Ptr) and TP.OF.TO._gckind == 'gc': # perform a write barrier that copies necessary flags from # source to dest if not llop.gc_writebarrier_before_copy(lltype.Bool, source, dest): # if the write barrier is not supported, copy by hand for i in range(length): dest[i + dest_start] = source[i + source_start] return source_addr = llmemory.cast_ptr_to_adr(source) dest_addr = llmemory.cast_ptr_to_adr(dest) cp_source_addr = (source_addr + llmemory.itemoffsetof(TP, 0) + llmemory.sizeof(TP.OF) * source_start) cp_dest_addr = (dest_addr + llmemory.itemoffsetof(TP, 0) + llmemory.sizeof(TP.OF) * dest_start) llmemory.raw_memcopy(cp_source_addr, cp_dest_addr, llmemory.sizeof(TP.OF) * length) keepalive_until_here(source) keepalive_until_here(dest)
def str_from_buffer(raw_buf, gc_buf, allocated_size, needed_size): """ Converts from a pair returned by alloc_buffer to a high-level string. The returned string will be truncated to needed_size. """ assert allocated_size >= needed_size if gc_buf and (allocated_size == needed_size): return hlstrtype(gc_buf) new_buf = lltype.malloc(STRTYPE, needed_size) try: str_chars_offset = (offsetof(STRTYPE, 'chars') + \ itemoffsetof(STRTYPE.chars, 0)) if gc_buf: src = cast_ptr_to_adr(gc_buf) + str_chars_offset else: src = cast_ptr_to_adr(raw_buf) + itemoffsetof(TYPEP.TO, 0) dest = cast_ptr_to_adr(new_buf) + str_chars_offset ## FIXME: This is bad, because dest could potentially move ## if there are threads involved. raw_memcopy(src, dest, llmemory.sizeof(ll_char_type) * needed_size) return hlstrtype(new_buf) finally: keepalive_until_here(new_buf)
def ll_shrink_array(p, smallerlength): from pypy.rpython.lltypesystem.lloperation import llop from pypy.rlib.objectmodel import keepalive_until_here if llop.shrink_array(lltype.Bool, p, smallerlength): return p # done by the GC # XXX we assume for now that the type of p is GcStruct containing a # variable array, with no further pointers anywhere, and exactly one # field in the fixed part -- like STR and UNICODE. TP = lltype.typeOf(p).TO newp = lltype.malloc(TP, smallerlength) assert len(TP._names) == 2 field = getattr(p, TP._names[0]) setattr(newp, TP._names[0], field) ARRAY = getattr(TP, TP._arrayfld) offset = (llmemory.offsetof(TP, TP._arrayfld) + llmemory.itemoffsetof(ARRAY, 0)) source_addr = llmemory.cast_ptr_to_adr(p) + offset dest_addr = llmemory.cast_ptr_to_adr(newp) + offset llmemory.raw_memcopy(source_addr, dest_addr, llmemory.sizeof(ARRAY.OF) * smallerlength) keepalive_until_here(p) keepalive_until_here(newp) return newp
def ll_arraycopy(source, dest, source_start, dest_start, length): from pypy.rpython.lltypesystem.lloperation import llop from pypy.rlib.objectmodel import keepalive_until_here # supports non-overlapping copies only if not we_are_translated(): if source == dest: assert (source_start + length <= dest_start or dest_start + length <= source_start) TP = lltype.typeOf(source).TO assert TP == lltype.typeOf(dest).TO if isinstance(TP.OF, lltype.Ptr) and TP.OF.TO._gckind == 'gc': # perform a write barrier that copies necessary flags from # source to dest if not llop.gc_writebarrier_before_copy(lltype.Bool, source, dest): # if the write barrier is not supported, copy by hand for i in range(length): dest[i + dest_start] = source[i + source_start] return source_addr = llmemory.cast_ptr_to_adr(source) dest_addr = llmemory.cast_ptr_to_adr(dest) cp_source_addr = (source_addr + llmemory.itemoffsetof(TP, 0) + llmemory.sizeof(TP.OF) * source_start) cp_dest_addr = (dest_addr + llmemory.itemoffsetof(TP, 0) + llmemory.sizeof(TP.OF) * dest_start) llmemory.raw_memcopy(cp_source_addr, cp_dest_addr, llmemory.sizeof(TP.OF) * length) keepalive_until_here(source) keepalive_until_here(dest)
def test_callback(self): slong = cast_type_to_ffitype(rffi.LONG) libc = self.get_libc() qsort = libc.getpointer("qsort", [ffi_type_pointer, slong, slong, ffi_type_pointer], ffi_type_void) def callback(ll_args, ll_res, stuff): p_a1 = rffi.cast(rffi.VOIDPP, ll_args[0])[0] p_a2 = rffi.cast(rffi.VOIDPP, ll_args[1])[0] a1 = rffi.cast(rffi.INTP, p_a1)[0] a2 = rffi.cast(rffi.INTP, p_a2)[0] res = rffi.cast(rffi.INTP, ll_res) if a1 > a2: res[0] = rffi.cast(rffi.INT, 1) else: res[0] = rffi.cast(rffi.INT, -1) ptr = CallbackFuncPtr([ffi_type_pointer, ffi_type_pointer], ffi_type_sint, callback) TP = rffi.CArray(rffi.INT) to_sort = lltype.malloc(TP, 4, flavor="raw") to_sort[0] = rffi.cast(rffi.INT, 4) to_sort[1] = rffi.cast(rffi.INT, 3) to_sort[2] = rffi.cast(rffi.INT, 1) to_sort[3] = rffi.cast(rffi.INT, 2) qsort.push_arg(rffi.cast(rffi.VOIDP, to_sort)) qsort.push_arg(rffi.sizeof(rffi.INT)) qsort.push_arg(4) qsort.push_arg(ptr.ll_closure) qsort.call(lltype.Void) assert [rffi.cast(lltype.Signed, to_sort[i]) for i in range(4)] == [1, 2, 3, 4] lltype.free(to_sort, flavor="raw") keepalive_until_here(ptr) # <= this test is not translated, but don't
def free_nonmovingbuffer(data, buf): """ Either free a non-moving buffer or keep the original storage alive. """ if rgc.can_move(data): lltype.free(buf, flavor='raw') else: keepalive_until_here(data)
def fn1(x, y): if x > 0: t = x + y, x - y else: t = x - y, x + y s, d = t keepalive_until_here(t) return s * d
def fn1(x, y): if x > 0: t = x+y, x-y else: t = x-y, x+y s, d = t keepalive_until_here(t) return s*d
def f(i): c = g() c.y if i: n = c.z1 else: n = c.z2 objectmodel.keepalive_until_here(c, n)
def copy_string_contents(src, dst, srcstart, dststart, length): assert srcstart >= 0 assert dststart >= 0 assert length >= 0 src = llmemory.cast_ptr_to_adr(src) + _str_ofs(srcstart) dst = llmemory.cast_ptr_to_adr(dst) + _str_ofs(dststart) llmemory.raw_memcopy(src, dst, llmemory.sizeof(CHAR_TP) * length) keepalive_until_here(src) keepalive_until_here(dst)
def jit_debug(string, arg1=-sys.maxint - 1, arg2=-sys.maxint - 1, arg3=-sys.maxint - 1, arg4=-sys.maxint - 1): """When JITted, cause an extra operation JIT_DEBUG to appear in the graphs. Should not be left after debugging.""" keepalive_until_here( string) # otherwise the whole function call is removed
def ll_function(flag): t = lltype.malloc(T) t.s.n = 3 t.s1.n = 3 if flag: s = t.s else: s = t.s1 objectmodel.keepalive_until_here(t) return s, t
def keep_buffer_alive_until_here(raw_buf, gc_buf): """ Keeps buffers alive or frees temporary buffers created by alloc_buffer. This must be called after a call to alloc_buffer, usually in a try/finally block. """ if gc_buf: keepalive_until_here(gc_buf) elif raw_buf: lltype.free(raw_buf, flavor='raw')
def start_all_threads(): s = allocate_stuff() ident1 = new_thread() ident2 = new_thread() ident3 = new_thread() ident4 = new_thread() ident5 = new_thread() # wait for 4 more seconds, which should be plenty of time time.sleep(4) keepalive_until_here(s)
def myfunc(): b = B() b.keep = A() b.data = llmemory.cast_adr_to_ptr(b.keep.addr, PARRAY) b.data[0] = 42 ptr = b.data # normally 'b' could go away as early as here, which would free # the memory held by the instance of A in b.keep... res = ptr[0] # ...so we explicitly keep 'b' alive until here objectmodel.keepalive_until_here(b) return res
def _digest(self, space): copy = self.copy(space) ctx = copy.ctx digest_size = self._digest_size() digest = lltype.malloc(rffi.CCHARP.TO, digest_size, flavor='raw') try: ropenssl.EVP_DigestFinal(ctx, digest, None) return rffi.charpsize2str(digest, digest_size) finally: keepalive_until_here(copy) lltype.free(digest, flavor='raw')
def f(n): states = [] while n > 0: mydriver.jit_merge_point(n=n, states=states) state = State() states.append(state) x = X(state) do_stuff() state.num *= 1000 do_stuff() keepalive_until_here(x) n -= 1 return states
def f(): x = lltype.malloc(S) x.x = 10 y = lltype.malloc(S) y.x = 20 z = x llop.gc_x_become(lltype.Void, llmemory.cast_ptr_to_adr(x), llmemory.cast_ptr_to_adr(y)) # keep 'y' alive until the x_become() is finished, because in # theory it could go away as soon as only its address is present objectmodel.keepalive_until_here(y) return z.x
def _ll_list_resize_really(l, newsize): """ Ensure l.items has room for at least newsize elements, and set l.length to newsize. Note that l.items may change, and even if newsize is less than l.length on entry. """ allocated = len(l.items) # This over-allocates proportional to the list size, making room # for additional growth. The over-allocation is mild, but is # enough to give linear-time amortized behavior over a long # sequence of appends() in the presence of a poorly-performing # system malloc(). # The growth pattern is: 0, 4, 8, 16, 25, 35, 46, 58, 72, 88, ... if newsize <= 0: ll_assert(newsize == 0, "negative list length") l.length = 0 l.items = _ll_new_empty_item_array(typeOf(l).TO) return else: if newsize < 9: some = 3 else: some = 6 some += newsize >> 3 try: new_allocated = ovfcheck(newsize + some) except OverflowError: raise MemoryError # XXX consider to have a real realloc items = l.items newitems = malloc(typeOf(l).TO.items.TO, new_allocated) before_len = l.length if before_len < new_allocated: p = before_len - 1 else: p = new_allocated - 1 ITEM = typeOf(l).TO.ITEM if isinstance(ITEM, Ptr): while p >= 0: newitems[p] = items[p] items[p] = nullptr(ITEM.TO) p -= 1 else: source = cast_ptr_to_adr(items) + itemoffsetof(typeOf(l.items).TO, 0) dest = cast_ptr_to_adr(newitems) + itemoffsetof(typeOf(l.items).TO, 0) s = p + 1 raw_memcopy(source, dest, sizeof(ITEM) * s) keepalive_until_here(items) l.length = newsize l.items = newitems
def free_nonmovingbuffer(data, buf): """ Either free a non-moving buffer or keep the original storage alive. """ # We cannot rely on rgc.can_move(data) here, because its result # might have changed since get_nonmovingbuffer(). Instead we check # if 'buf' points inside 'data'. This is only possible if we # followed the 2nd case in get_nonmovingbuffer(); in the first case, # 'buf' points to its own raw-malloced memory. data = llstrtype(data) data_start = cast_ptr_to_adr(data) + offsetof(STRTYPE, "chars") + itemoffsetof(STRTYPE.chars, 0) followed_2nd_path = buf == cast(TYPEP, data_start) keepalive_until_here(data) if not followed_2nd_path: lltype.free(buf, flavor="raw")
def free_nonmovingbuffer(data, buf): """ Either free a non-moving buffer or keep the original storage alive. """ # We cannot rely on rgc.can_move(data) here, because its result # might have changed since get_nonmovingbuffer(). Instead we check # if 'buf' points inside 'data'. This is only possible if we # followed the 2nd case in get_nonmovingbuffer(); in the first case, # 'buf' points to its own raw-malloced memory. data = llstrtype(data) data_start = cast_ptr_to_adr(data) + \ offsetof(STRTYPE, 'chars') + itemoffsetof(STRTYPE.chars, 0) followed_2nd_path = (buf == cast(TYPEP, data_start)) keepalive_until_here(data) if not followed_2nd_path: lltype.free(buf, flavor='raw')
def copy_string_contents(src, dst, srcstart, dststart, length): """Copies 'length' characters from the 'src' string to the 'dst' string, starting at position 'srcstart' and 'dststart'.""" # xxx Warning: don't try to do this at home. It relies on a lot # of details to be sure that it works correctly in all cases. # Notably: no GC operation at all from the first cast_ptr_to_adr() # because it might move the strings. The keepalive_until_here() # are obscurely essential to make sure that the strings stay alive # longer than the raw_memcopy(). assert srcstart >= 0 assert dststart >= 0 assert length >= 0 src = llmemory.cast_ptr_to_adr(src) + _str_ofs(srcstart) dst = llmemory.cast_ptr_to_adr(dst) + _str_ofs(dststart) llmemory.raw_memcopy(src, dst, llmemory.sizeof(CHAR_TP) * length) keepalive_until_here(src) keepalive_until_here(dst)
def str_from_buffer(raw_buf, gc_buf, allocated_size, needed_size): """ Converts from a pair returned by alloc_buffer to a high-level string. The returned string will be truncated to needed_size. """ assert allocated_size >= needed_size if gc_buf and (allocated_size == needed_size): return hlstrtype(gc_buf) new_buf = lltype.malloc(STRTYPE, needed_size) str_chars_offset = offsetof(STRTYPE, "chars") + itemoffsetof(STRTYPE.chars, 0) if gc_buf: src = cast_ptr_to_adr(gc_buf) + str_chars_offset else: src = cast_ptr_to_adr(raw_buf) + itemoffsetof(TYPEP.TO, 0) dest = cast_ptr_to_adr(new_buf) + str_chars_offset raw_memcopy(src, dest, llmemory.sizeof(ll_char_type) * needed_size) keepalive_until_here(gc_buf) keepalive_until_here(new_buf) return hlstrtype(new_buf)
def str_from_buffer(raw_buf, gc_buf, allocated_size, needed_size): """ Converts from a pair returned by alloc_buffer to a high-level string. The returned string will be truncated to needed_size. """ assert allocated_size >= needed_size if gc_buf and (allocated_size == needed_size): return hlstrtype(gc_buf) new_buf = lltype.malloc(STRTYPE, needed_size) str_chars_offset = (offsetof(STRTYPE, 'chars') + \ itemoffsetof(STRTYPE.chars, 0)) if gc_buf: src = cast_ptr_to_adr(gc_buf) + str_chars_offset else: src = cast_ptr_to_adr(raw_buf) + itemoffsetof(TYPEP.TO, 0) dest = cast_ptr_to_adr(new_buf) + str_chars_offset raw_memcopy(src, dest, llmemory.sizeof(ll_char_type) * needed_size) keepalive_until_here(gc_buf) keepalive_until_here(new_buf) return hlstrtype(new_buf)
def fn(n): keepalive = [] weakrefs = [] a = None for i in range(n): if i & 1 == 0: a = A() a.index = i assert a is not None weakrefs.append(weakref.ref(a)) if i % 7 == 6: keepalive.append(a) rgc.collect() count_free = 0 for i in range(n): a = weakrefs[i]() if i % 7 == 6: assert a is not None if a is not None: assert a.index == i & ~1 else: count_free += 1 keepalive_until_here(keepalive) return count_free
def f(): libc = CDLL(get_libc_name()) qsort = libc.getpointer('qsort', [ffi_type_pointer, ffi_size_t, ffi_size_t, ffi_type_pointer], ffi_type_void) ptr = CallbackFuncPtr([ffi_type_pointer, ffi_type_pointer], ffi_type_sint, callback) TP = rffi.CArray(rffi.LONG) to_sort = lltype.malloc(TP, 4, flavor='raw') to_sort[0] = 4 to_sort[1] = 3 to_sort[2] = 1 to_sort[3] = 2 qsort.push_arg(rffi.cast(rffi.VOIDP, to_sort)) qsort.push_arg(rffi.cast(rffi.SIZE_T, 4)) qsort.push_arg(rffi.cast(rffi.SIZE_T, rffi.sizeof(rffi.LONG))) qsort.push_arg(rffi.cast(rffi.VOIDP, ptr.ll_closure)) qsort.call(lltype.Void) result = [to_sort[i] for i in range(4)] == [1,2,3,4] lltype.free(to_sort, flavor='raw') keepalive_until_here(ptr) return int(result)
def test_callback(self): slong = cast_type_to_ffitype(rffi.LONG) libc = self.get_libc() qsort = libc.getpointer( 'qsort', [ffi_type_pointer, slong, slong, ffi_type_pointer], ffi_type_void) def callback(ll_args, ll_res, stuff): p_a1 = rffi.cast(rffi.VOIDPP, ll_args[0])[0] p_a2 = rffi.cast(rffi.VOIDPP, ll_args[1])[0] a1 = rffi.cast(rffi.INTP, p_a1)[0] a2 = rffi.cast(rffi.INTP, p_a2)[0] res = rffi.cast(rffi.INTP, ll_res) if a1 > a2: res[0] = rffi.cast(rffi.INT, 1) else: res[0] = rffi.cast(rffi.INT, -1) ptr = CallbackFuncPtr([ffi_type_pointer, ffi_type_pointer], ffi_type_sint, callback) TP = rffi.CArray(rffi.INT) to_sort = lltype.malloc(TP, 4, flavor='raw') to_sort[0] = rffi.cast(rffi.INT, 4) to_sort[1] = rffi.cast(rffi.INT, 3) to_sort[2] = rffi.cast(rffi.INT, 1) to_sort[3] = rffi.cast(rffi.INT, 2) qsort.push_arg(rffi.cast(rffi.VOIDP, to_sort)) qsort.push_arg(rffi.sizeof(rffi.INT)) qsort.push_arg(4) qsort.push_arg(ptr.ll_closure) qsort.call(lltype.Void) assert ([rffi.cast(lltype.Signed, to_sort[i]) for i in range(4)] == [1, 2, 3, 4]) lltype.free(to_sort, flavor='raw') keepalive_until_here(ptr) # <= this test is not translated, but don't
def fn(): s = lltype.malloc(S) s.u = lltype.malloc(U) s.u.next = lltype.malloc(U) s.u.next.next = lltype.malloc(U) a = lltype.malloc(A, 1000) s2 = lltype.malloc(S) # fd1 = os.open(filename1, os.O_WRONLY | os.O_CREAT, 0666) fd2 = os.open(filename2, os.O_WRONLY | os.O_CREAT, 0666) rgc.dump_rpy_heap(fd1) rgc.dump_rpy_heap(fd2) # try twice in a row keepalive_until_here(s2) keepalive_until_here(s) keepalive_until_here(a) os.close(fd1) os.close(fd2) return 0
def annotate_interface_functions(self): annhelper = self.hrtyper.annhelper RGenOp = self.RGenOp SEPLINE = self.SEPLINE ml_generate_code = self.ml_generate_code argcolors = list(self.argcolors) if hasattr(self.ll_function, 'convert_arguments'): decoders = self.ll_function.convert_arguments assert len(decoders) == len(argcolors) else: decoders = [int] * len(argcolors) argcolors_decoders = zip(argcolors, decoders) argcolors_decoders = unrolling_iterable(argcolors_decoders) convert_result = getattr(self.ll_function, 'convert_result', str) def ll_main(argv): i = 1 mainargs = () residualargs = () if len(argv) == 2 and argv[1] == '--help': os.write(1, 'usage: ' + argv[0]) for color, decoder in argcolors_decoders: os.write(1, ' ') if color == 'green': os.write(1, decoder.__name__) else: os.write(1, "-const|-var "+decoder.__name__) os.write(1, '\n') return 0 for color, decoder in argcolors_decoders: try: if color == 'green': llvalue = decoder(argv[i]) mainargs += (llvalue,) i = i + 1 else: if argv[i] == '-const': is_const = True elif argv[i] == '-var': is_const = False else: raise ValueError() i += 1 llvalue = decoder(argv[i]) mainargs += (is_const, llvalue) residualargs += (llvalue,) i += 1 except (ValueError, IndexError): j = 1 while j < len(argv): arg = argv[j] if j == i: os.write(1, '--> ') else: os.write(1, ' ') os.write(1, arg+'\n') j += 1 if j == i: os.write(1, '-->\n') return 1 rgenop = RGenOp() generated = ml_generate_code(rgenop, *mainargs) os.write(1, SEPLINE) bench = Benchmark() while 1: try: res = generated(*residualargs) except Exception, e: os.write(1, 'EXCEPTION: %s\n' % (e,)) return 0 if bench.stop(): break os.write(1, convert_result(res) + '\n') rgenop.check_no_open_mc() keepalive_until_here(rgenop) # to keep the code blocks alive return 0
def f(): x = [1] y = ['b'] objectmodel.keepalive_until_here(x,y) return 1
def assert_green(value): """Very strong assert: checks that 'value' is a green (a JIT compile-time constant).""" keepalive_until_here(value)
def f(x): p = g() q = g() keepalive_until_here(p) keepalive_until_here(q) return x
def unlock(self): """To call after we're done with the pointer returned by lock(). Note that locking and unlocking costs nothing at run-time. """ keepalive_until_here(self)
def fn(): s = lltype.malloc(S1) s.x = 12 objectmodel.keepalive_until_here(s) return s.x
def unlock(self): """To call after using self.stream.""" self._lock.release() keepalive_until_here(self)
def virtual_ref_finish(x): """See docstring in virtual_ref(x). Note that virtual_ref_finish takes as argument the real object, not the vref.""" keepalive_until_here(x) # otherwise the whole function call is removed
def virtual_ref_finish(vref, x): """See docstring in virtual_ref(x)""" keepalive_until_here(x) # otherwise the whole function call is removed _virtual_ref_finish(vref, x)
def jit_debug(string, arg1=-sys.maxint-1, arg2=-sys.maxint-1, arg3=-sys.maxint-1, arg4=-sys.maxint-1): """When JITted, cause an extra operation JIT_DEBUG to appear in the graphs. Should not be left after debugging.""" keepalive_until_here(string) # otherwise the whole function call is removed
def _charbuf_stop(self): keepalive_until_here(self)