def gc_pointers_inside(v, adr, mutable_only=False): t = lltype.typeOf(v) if isinstance(t, lltype.Struct): skip = () if mutable_only: if t._hints.get('immutable'): return if 'immutable_fields' in t._hints: skip = t._hints['immutable_fields'].all_immutable_fields() for n, t2 in t._flds.iteritems(): if isinstance(t2, lltype.Ptr) and t2.TO._gckind == 'gc': if n not in skip: yield adr + llmemory.offsetof(t, n) elif isinstance(t2, (lltype.Array, lltype.Struct)): for a in gc_pointers_inside(getattr(v, n), adr + llmemory.offsetof(t, n), mutable_only): yield a elif isinstance(t, lltype.Array): if mutable_only and t._hints.get('immutable'): return if isinstance(t.OF, lltype.Ptr) and t.OF.TO._gckind == 'gc': for i in range(len(v.items)): yield adr + llmemory.itemoffsetof(t, i) elif isinstance(t.OF, lltype.Struct): for i in range(len(v.items)): for a in gc_pointers_inside(v.items[i], adr + llmemory.itemoffsetof(t, i), mutable_only): yield a
def ll_string2list(RESLIST, src): length = len(src.chars) lst = RESLIST.ll_newlist(length) dst = lst.ll_items() SRC = typeOf(src).TO # STR or UNICODE DST = typeOf(dst).TO # GcArray assert DST.OF is SRC.chars.OF # # If the 'split_gc_address_space' option is set, we must copy # manually, character-by-character if rgc.must_split_gc_address_space(): i = 0 while i < length: dst[i] = src.chars[i] i += 1 return lst # # from here, no GC operations can happen asrc = llmemory.cast_ptr_to_adr(src) + (llmemory.offsetof( SRC, 'chars') + llmemory.itemoffsetof(SRC.chars, 0)) adst = llmemory.cast_ptr_to_adr(dst) + llmemory.itemoffsetof(DST, 0) llmemory.raw_memcopy(asrc, adst, llmemory.sizeof(DST.OF) * length) # end of "no GC" section keepalive_until_here(src) keepalive_until_here(dst) return lst
def encode_type_shape(builder, info, TYPE, index): """Encode the shape of the TYPE into the TYPE_INFO structure 'info'.""" offsets = offsets_to_gc_pointers(TYPE) infobits = index info.ofstoptrs = builder.offsets2table(offsets, TYPE) if len(offsets) > 0: infobits |= T_HAS_GCPTR # fptrs = builder.special_funcptr_for_type(TYPE) if fptrs: if "destructor" in fptrs: info.customfunc = fptrs["destructor"] if "old_style_finalizer" in fptrs: info.customfunc = fptrs["old_style_finalizer"] infobits |= T_HAS_OLDSTYLE_FINALIZER # if not TYPE._is_varsize(): info.fixedsize = llarena.round_up_for_allocation( llmemory.sizeof(TYPE), builder.GCClass.object_minimal_size) # note about round_up_for_allocation(): in the 'info' table # we put a rounded-up size only for fixed-size objects. For # varsize ones, the GC must anyway compute the size at run-time # and round up that result. else: infobits |= T_IS_VARSIZE varinfo = lltype.cast_pointer(GCData.VARSIZE_TYPE_INFO_PTR, info) info.fixedsize = llmemory.sizeof(TYPE, 0) if isinstance(TYPE, lltype.Struct): ARRAY = TYPE._flds[TYPE._arrayfld] ofs1 = llmemory.offsetof(TYPE, TYPE._arrayfld) varinfo.ofstolength = ofs1 + llmemory.ArrayLengthOffset(ARRAY) varinfo.ofstovar = ofs1 + llmemory.itemoffsetof(ARRAY, 0) else: assert isinstance(TYPE, lltype.GcArray) ARRAY = TYPE if (isinstance(ARRAY.OF, lltype.Ptr) and ARRAY.OF.TO._gckind == 'gc'): infobits |= T_IS_GCARRAY_OF_GCPTR varinfo.ofstolength = llmemory.ArrayLengthOffset(ARRAY) varinfo.ofstovar = llmemory.itemoffsetof(TYPE, 0) assert isinstance(ARRAY, lltype.Array) if ARRAY.OF != lltype.Void: offsets = offsets_to_gc_pointers(ARRAY.OF) else: offsets = () if len(offsets) > 0: infobits |= T_HAS_GCPTR_IN_VARSIZE | T_HAS_GCPTR varinfo.varofstoptrs = builder.offsets2table(offsets, ARRAY.OF) varinfo.varitemsize = llmemory.sizeof(ARRAY.OF) if builder.is_weakref_type(TYPE): infobits |= T_IS_WEAKREF if is_subclass_of_object(TYPE): infobits |= T_IS_RPYTHON_INSTANCE info.infobits = infobits | T_KEY_VALUE
def encode_type_shape(builder, info, TYPE, index): """Encode the shape of the TYPE into the TYPE_INFO structure 'info'.""" offsets = offsets_to_gc_pointers(TYPE) infobits = index info.ofstoptrs = builder.offsets2table(offsets, TYPE) if len(offsets) > 0: infobits |= T_HAS_GCPTR # fptrs = builder.special_funcptr_for_type(TYPE) if fptrs: if "finalizer" in fptrs: info.finalizer = fptrs["finalizer"] if "light_finalizer" in fptrs: info.finalizer = fptrs["light_finalizer"] infobits |= T_HAS_LIGHTWEIGHT_FINALIZER # if not TYPE._is_varsize(): info.fixedsize = llarena.round_up_for_allocation( llmemory.sizeof(TYPE), builder.GCClass.object_minimal_size) # note about round_up_for_allocation(): in the 'info' table # we put a rounded-up size only for fixed-size objects. For # varsize ones, the GC must anyway compute the size at run-time # and round up that result. else: infobits |= T_IS_VARSIZE varinfo = lltype.cast_pointer(GCData.VARSIZE_TYPE_INFO_PTR, info) info.fixedsize = llmemory.sizeof(TYPE, 0) if isinstance(TYPE, lltype.Struct): ARRAY = TYPE._flds[TYPE._arrayfld] ofs1 = llmemory.offsetof(TYPE, TYPE._arrayfld) varinfo.ofstolength = ofs1 + llmemory.ArrayLengthOffset(ARRAY) varinfo.ofstovar = ofs1 + llmemory.itemoffsetof(ARRAY, 0) else: assert isinstance(TYPE, lltype.GcArray) ARRAY = TYPE if (isinstance(ARRAY.OF, lltype.Ptr) and ARRAY.OF.TO._gckind == 'gc'): infobits |= T_IS_GCARRAY_OF_GCPTR varinfo.ofstolength = llmemory.ArrayLengthOffset(ARRAY) varinfo.ofstovar = llmemory.itemoffsetof(TYPE, 0) assert isinstance(ARRAY, lltype.Array) if ARRAY.OF != lltype.Void: offsets = offsets_to_gc_pointers(ARRAY.OF) else: offsets = () if len(offsets) > 0: infobits |= T_HAS_GCPTR_IN_VARSIZE | T_HAS_GCPTR varinfo.varofstoptrs = builder.offsets2table(offsets, ARRAY.OF) varinfo.varitemsize = llmemory.sizeof(ARRAY.OF) if builder.is_weakref_type(TYPE): infobits |= T_IS_WEAKREF if is_subclass_of_object(TYPE): infobits |= T_IS_RPYTHON_INSTANCE info.infobits = infobits | T_KEY_VALUE
def ll_arraycopy(source, dest, source_start, dest_start, length): from rpython.rtyper.lltypesystem.lloperation import llop from rpython.rlib.objectmodel import keepalive_until_here # XXX: Hack to ensure that we get a proper effectinfo.write_descrs_arrays # and also, maybe, speed up very small cases if length <= 1: if length == 1: copy_item(source, dest, source_start, dest_start) return # 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 slowpath = False if must_split_gc_address_space(): slowpath = True elif _contains_gcptr(TP.OF): # perform a write barrier that copies necessary flags from # source to dest if not llop.gc_writebarrier_before_copy(lltype.Bool, source, dest, source_start, dest_start, length): slowpath = True if slowpath: # if the write barrier is not supported, or if we translate with # the option 'split_gc_address_space', then copy by hand i = 0 while i < length: copy_item(source, dest, i + source_start, i + dest_start) i += 1 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 get_raw_address_of_string(space, w_x): """Special case for ffi.from_buffer(string). Returns a 'char *' that is valid as long as the string object is alive. Two calls to ffi.from_buffer(same_string) are guaranteed to return the same pointer. """ from rpython.rtyper.annlowlevel import llstr from rpython.rtyper.lltypesystem.rstr import STR from rpython.rtyper.lltypesystem import llmemory from rpython.rlib import rgc cache = space.fromcache(RawBytesCache) rawbytes = cache.wdict.get(w_x) if rawbytes is None: data = space.bytes_w(w_x) if (we_are_translated() and not rgc.can_move(data) and not rgc.must_split_gc_address_space()): lldata = llstr(data) data_start = (llmemory.cast_ptr_to_adr(lldata) + rffi.offsetof(STR, 'chars') + llmemory.itemoffsetof(STR.chars, 0)) data_start = rffi.cast(rffi.CCHARP, data_start) data_start[len(data)] = '\x00' # write the final extra null return data_start rawbytes = RawBytes(data) cache.wdict.set(w_x, rawbytes) return rawbytes.ptr
def alloc_buffer(count): """ Returns a (raw_buffer, gc_buffer, case_num) triple, 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. """ new_buf = mallocfn(count) pinned = 0 if rgc.can_move(new_buf): if rgc.pin(new_buf): pinned = 1 else: raw_buf = lltype.malloc(TYPEP.TO, count, flavor='raw') return raw_buf, new_buf, 2 # # following code is executed if: # - rgc.can_move(data) and rgc.pin(data) both returned true # - rgc.can_move(data) returned false data_start = cast_ptr_to_adr(new_buf) + \ offsetof(STRTYPE, 'chars') + itemoffsetof(STRTYPE.chars, 0) return cast(TYPEP, data_start), new_buf, pinned
def get_raw_address_of_string(space, w_x): """Special case for ffi.from_buffer(string). Returns a 'char *' that is valid as long as the string object is alive. Two calls to ffi.from_buffer(same_string) are guaranteed to return the same pointer. """ from rpython.rtyper.annlowlevel import llstr from rpython.rtyper.lltypesystem.rstr import STR from rpython.rtyper.lltypesystem import llmemory from rpython.rlib import rgc cache = space.fromcache(RawBytesCache) rawbytes = cache.wdict.get(w_x) if rawbytes is None: data = space.str_w(w_x) if we_are_translated() and not rgc.can_move(data): lldata = llstr(data) data_start = (llmemory.cast_ptr_to_adr(lldata) + rffi.offsetof(STR, 'chars') + llmemory.itemoffsetof(STR.chars, 0)) data_start = rffi.cast(rffi.CCHARP, data_start) data_start[len(data)] = '\x00' # write the final extra null return data_start rawbytes = RawBytes(data) cache.wdict.set(w_x, rawbytes) return rawbytes.ptr
def ll_string2list(RESLIST, src): length = len(src.chars) lst = RESLIST.ll_newlist(length) dst = lst.ll_items() SRC = typeOf(src).TO # STR or UNICODE DST = typeOf(dst).TO # GcArray assert DST.OF is SRC.chars.OF # from here, no GC operations can happen asrc = llmemory.cast_ptr_to_adr(src) + (llmemory.offsetof( SRC, 'chars') + llmemory.itemoffsetof(SRC.chars, 0)) adst = llmemory.cast_ptr_to_adr(dst) + llmemory.itemoffsetof(DST, 0) llmemory.raw_memcopy(asrc, adst, llmemory.sizeof(DST.OF) * length) # end of "no GC" section keepalive_until_here(src) keepalive_until_here(dst) return lst
def ll_shrink_array(p, smallerlength): from rpython.rtyper.lltypesystem.lloperation import llop from rpython.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 get_nonmovingbuffer(data): """ Either returns a non-moving copy or performs neccessary pointer arithmetic to return a pointer to the characters of a string if the 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. """ lldata = llstrtype(data) count = len(data) pinned = False if rgc.can_move(data): if rgc.pin(data): pinned = True else: buf = lltype.malloc(TYPEP.TO, count, flavor='raw') copy_string_to_raw(lldata, buf, 0, count) return buf, pinned, True # ^^^ raw malloc used to get a nonmovable copy # # following code is executed if: # - rgc.can_move(data) and rgc.pin(data) both returned true # - rgc.can_move(data) returned false data_start = cast_ptr_to_adr(lldata) + \ offsetof(STRTYPE, 'chars') + itemoffsetof(STRTYPE.chars, 0) return cast(TYPEP, data_start), pinned, False
def copy_string_to_raw(src, ptrdst, srcstart, length): """ Copies 'length' characters from the 'src' string to the 'ptrdst' buffer, starting at position 'srcstart'. 'ptrdst' must be a non-gc Array of Char. """ # xxx Warning: same note as above apply: don't do this at home assert length >= 0 # # If the 'split_gc_address_space' option is set, we must copy # manually, character-by-character if rgc.must_split_gc_address_space(): i = 0 while i < length: ptrdst[i] = src.chars[srcstart + i] i += 1 return # # from here, no GC operations can happen asrc = _get_raw_buf(SRC_TP, src, srcstart) adst = llmemory.cast_ptr_to_adr(ptrdst) adst = adst + llmemory.itemoffsetof(typeOf(ptrdst).TO, 0) llmemory.raw_memcopy(asrc, adst, llmemory.sizeof(CHAR_TP) * length) # end of "no GC" section keepalive_until_here(src)
def ll_shrink_array(p, smallerlength): from rpython.rtyper.lltypesystem.lloperation import llop from rpython.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 f(): a = llstr("xyz") b = (llmemory.cast_ptr_to_adr(a) + llmemory.offsetof(STR, 'chars') + llmemory.itemoffsetof(STR.chars, 0)) buf = rffi.cast(rffi.VOIDP, b) return buf[2]
def _raw_memcopy_opaque(source, dest, size): # push push push at the llmemory interface (with hacks that are all # removed after translation) zero = llmemory.itemoffsetof(rffi.CCHARP.TO, 0) llmemory.raw_memcopy( llmemory.cast_ptr_to_adr(source) + zero, llmemory.cast_ptr_to_adr(dest) + zero, size * llmemory.sizeof(lltype.Char))
def ll_string2list(RESLIST, src): length = len(src.chars) lst = RESLIST.ll_newlist(length) dst = lst.ll_items() SRC = typeOf(src).TO # STR or UNICODE DST = typeOf(dst).TO # GcArray assert DST.OF is SRC.chars.OF # from here, no GC operations can happen asrc = llmemory.cast_ptr_to_adr(src) + ( llmemory.offsetof(SRC, 'chars') + llmemory.itemoffsetof(SRC.chars, 0)) adst = llmemory.cast_ptr_to_adr(dst) + llmemory.itemoffsetof(DST, 0) llmemory.raw_memcopy(asrc, adst, llmemory.sizeof(DST.OF) * length) # end of "no GC" section keepalive_until_here(src) keepalive_until_here(dst) return lst
def str_storage_getitem(TP, s, byte_offset): # WARNING: the 'byte_offset' is, as its name says, measured in bytes; # however, it should be aligned for TP, otherwise on some platforms this # code will crash! lls = llstr(s) base_ofs = (llmemory.offsetof(STR, 'chars') + llmemory.itemoffsetof(STR.chars, 0)) scale_factor = llmemory.sizeof(lltype.Char) return llop.gc_load_indexed(TP, lls, byte_offset, scale_factor, base_ofs)
def ll_arrayclear(p): # Equivalent to memset(array, 0). Only for GcArray(primitive-type) for now. from rpython.rlib.objectmodel import keepalive_until_here length = len(p) ARRAY = lltype.typeOf(p).TO offset = llmemory.itemoffsetof(ARRAY, 0) dest_addr = llmemory.cast_ptr_to_adr(p) + offset llmemory.raw_memclear(dest_addr, llmemory.sizeof(ARRAY.OF) * length) keepalive_until_here(p)
def ll_arraycopy(source, dest, source_start, dest_start, length): from rpython.rtyper.lltypesystem.lloperation import llop from rpython.rlib.objectmodel import keepalive_until_here # XXX: Hack to ensure that we get a proper effectinfo.write_descrs_arrays # and also, maybe, speed up very small cases if length <= 1: if length == 1: copy_item(source, dest, source_start, dest_start) return # 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 _contains_gcptr(TP.OF): # perform a write barrier that copies necessary flags from # source to dest if not llop.gc_writebarrier_before_copy(lltype.Bool, source, dest, source_start, dest_start, length): # if the write barrier is not supported, copy by hand i = 0 while i < length: copy_item(source, dest, i + source_start, i + dest_start) i += 1 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 longername(a, b, size): if 1: baseofs = itemoffsetof(TP, 0) onesize = sizeof(TP.OF) size = baseofs + onesize * (size - 1) raw_memcopy(cast_ptr_to_adr(b) + baseofs, cast_ptr_to_adr(a) + baseofs, size) else: a = [] for i in range(x): a.append(i) return 0
def copy_raw_to_string(ptrsrc, dst, dststart, length): # xxx Warning: same note as above apply: don't do this at home assert length >= 0 # from here, no GC operations can happen adst = _get_raw_buf(SRC_TP, dst, dststart) asrc = llmemory.cast_ptr_to_adr(ptrsrc) asrc = asrc + llmemory.itemoffsetof(typeOf(ptrsrc).TO, 0) llmemory.raw_memcopy(asrc, adst, llmemory.sizeof(CHAR_TP) * length) # end of "no GC" section keepalive_until_here(dst)
def getinneraddr(self, obj, *offsets): TYPE = lltype.typeOf(obj).TO addr = llmemory.cast_ptr_to_adr(obj) for o in offsets: if isinstance(o, str): addr += llmemory.offsetof(TYPE, o) TYPE = getattr(TYPE, o) else: addr += llmemory.itemoffsetof(TYPE, o) TYPE = TYPE.OF return addr, TYPE
def newlist_and_gc_store(TYPE, value): size = rffi.sizeof(TYPE) lst = resizable_list_supporting_raw_ptr(['\x00'] * size) ll_data = ll_for_resizable_list(lst) ll_items = ll_data.items LIST = lltype.typeOf(ll_data).TO # rlist.LIST_OF(lltype.Char) base_ofs = llmemory.itemoffsetof(LIST.items.TO, 0) scale_factor = llmemory.sizeof(lltype.Char) value = lltype.cast_primitive(TYPE, value) llop.gc_store_indexed(lltype.Void, ll_items, 0, value, scale_factor, base_ofs) return lst
def test_offsetof_nogc(): ARR = lltype.Array(lltype.Signed) offsetx = llmemory.arraylengthoffset(ARR) offsety = llmemory.itemoffsetof(ARR, 0) ARR2 = lltype.GcArray(lltype.Signed) offsetx2 = llmemory.arraylengthoffset(ARR2) offsety2 = llmemory.itemoffsetof(ARR2, 0) def f(): a = lltype.malloc(ARR, 5, flavor='raw') a2 = lltype.malloc(ARR2, 6, flavor='raw') a2[0] = 1 a[0] = 3 adr = llmemory.cast_ptr_to_adr(a) adr2 = llmemory.cast_ptr_to_adr(a2) return ((adr + offsetx).signed[0] * 1000 + (adr + offsety).signed[0] * 100 + (adr2 + offsetx2).signed[0] * 10 + (adr2 + offsety2).signed[0]) fn = compile(f, []) res = fn() assert res == 5361
def longername(a, b, size): if 1: baseofs = itemoffsetof(TP, 0) onesize = sizeof(TP.OF) size = baseofs + onesize * (size - 1) raw_memcopy( cast_ptr_to_adr(b) + baseofs, cast_ptr_to_adr(a) + baseofs, size) else: a = [] for i in range(x): a.append(i) return 0
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 ll_write_final_null_char(s): """'s' is a low-level STR; writes a terminating NULL character after the other characters in 's'. Warning, this only works because of the 'extra_item_after_alloc' hack inside the definition of STR. """ from rpython.rtyper.lltypesystem import rffi PSTR = lltype.typeOf(s) assert has_final_null_char(PSTR) == 1 n = llmemory.offsetof(PSTR.TO, 'chars') n += llmemory.itemoffsetof(PSTR.TO.chars, 0) n = llmemory.raw_malloc_usage(n) n += len(s.chars) # no GC operation from here! ptr = rffi.cast(rffi.CCHARP, s) ptr[n] = '\x00'
def copy_string_to_raw(src, ptrdst, srcstart, length): """ Copies 'length' characters from the 'src' string to the 'ptrdst' buffer, starting at position 'srcstart'. 'ptrdst' must be a non-gc Array of Char. """ # xxx Warning: same note as above apply: don't do this at home assert length >= 0 # from here, no GC operations can happen asrc = _get_raw_buf(SRC_TP, src, srcstart) adst = llmemory.cast_ptr_to_adr(ptrdst) adst = adst + llmemory.itemoffsetof(typeOf(ptrdst).TO, 0) llmemory.raw_memcopy(asrc, adst, llmemory.sizeof(CHAR_TP) * length) # end of "no GC" section keepalive_until_here(src)
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 get_nonmovingbuffer(data): """ Either returns a non-moving copy or performs neccessary pointer arithmetic to return a pointer to the characters of a string if the string is already nonmovable. Must be followed by a free_nonmovingbuffer call. """ lldata = llstrtype(data) if rgc.can_move(data): count = len(data) buf = lltype.malloc(TYPEP.TO, count, flavor='raw') copy_string_to_raw(lldata, buf, 0, count) return buf else: data_start = cast_ptr_to_adr(lldata) + \ offsetof(STRTYPE, 'chars') + itemoffsetof(STRTYPE.chars, 0) return cast(TYPEP, data_start)
def ll_arrayclear(p): # Equivalent to memset(array, 0). Only for GcArray(primitive-type) for now. from rpython.rlib.objectmodel import keepalive_until_here length = len(p) ARRAY = lltype.typeOf(p).TO if must_split_gc_address_space(): # do the clearing element by element from rpython.rtyper.lltypesystem import rffi ZERO = rffi.cast(ARRAY.OF, 0) i = 0 while i < length: p[i] = ZERO i += 1 else: offset = llmemory.itemoffsetof(ARRAY, 0) dest_addr = llmemory.cast_ptr_to_adr(p) + offset llmemory.raw_memclear(dest_addr, llmemory.sizeof(ARRAY.OF) * length) keepalive_until_here(p)
def test_itemoffsetof_fixedsizearray(): ARRAY = lltype.FixedSizeArray(lltype.Signed, 5) itemoffsets = [llmemory.itemoffsetof(ARRAY, i) for i in range(5)] a = lltype.malloc(ARRAY, immortal=True) def f(): adr = llmemory.cast_ptr_to_adr(a) result = 0 for i in range(5): a[i] = i + 1 for i in range(5): result = result * 10 + (adr + itemoffsets[i]).signed[0] for i in range(5): (adr + itemoffsets[i]).signed[0] = i for i in range(5): result = 10 * result + a[i] return result fn = compile(f, []) res = fn() assert res == 1234501234
def copy_raw_to_string(ptrsrc, dst, dststart, length): # xxx Warning: same note as above apply: don't do this at home assert length >= 0 # # If the 'split_gc_address_space' option is set, we must copy # manually, character-by-character if rgc.must_split_gc_address_space(): i = 0 while i < length: dst.chars[dststart + i] = ptrsrc[i] i += 1 return # # from here, no GC operations can happen adst = _get_raw_buf(SRC_TP, dst, dststart) asrc = llmemory.cast_ptr_to_adr(ptrsrc) asrc = asrc + llmemory.itemoffsetof(typeOf(ptrsrc).TO, 0) llmemory.raw_memcopy(asrc, adst, llmemory.sizeof(CHAR_TP) * length) # end of "no GC" section keepalive_until_here(dst)
def test_structarray_add(self): from rpython.rtyper.lltypesystem import llmemory S = Struct("S", ("x", Signed)) PS = Ptr(S) size = llmemory.sizeof(S) A = GcArray(S) itemoffset = llmemory.itemoffsetof(A, 0) def llf(n): a = malloc(A, 5) a[0].x = 1 a[1].x = 2 a[2].x = 3 a[3].x = 42 a[4].x = 4 adr_s = llmemory.cast_ptr_to_adr(a) adr_s += itemoffset + size * n s = llmemory.cast_adr_to_ptr(adr_s, PS) return s.x fn = self.getcompiled(llf, [int]) res = fn(3) assert res == 42
def get_nonmovingbuffer(data): """ Either returns a non-moving copy or performs neccessary pointer arithmetic to return a pointer to the characters of a string if the string is already nonmovable or could be pinned. Must be followed by a free_nonmovingbuffer call. 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 get_nonmovingbuffer_final_null() instead of get_nonmovingbuffer() to get a regular null-terminated "char *". """ lldata = llstrtype(data) count = len(data) if we_are_translated_to_c() and not rgc.can_move(data): flag = '\x04' else: if we_are_translated_to_c() and rgc.pin(data): flag = '\x05' else: buf = lltype.malloc(TYPEP.TO, count + (TYPEP is CCHARP), flavor='raw') copy_string_to_raw(lldata, buf, 0, count) return buf, '\x06' # ^^^ raw malloc used to get a nonmovable copy # # following code is executed after we're translated to C, if: # - rgc.can_move(data) and rgc.pin(data) both returned true # - rgc.can_move(data) returned false data_start = cast_ptr_to_adr(lldata) + \ offsetof(STRTYPE, 'chars') + itemoffsetof(STRTYPE.chars, 0) return cast(TYPEP, data_start), flag
def get_raw_buf(ptr): ofs = llmemory.itemoffsetof(lltype.typeOf(ptr).TO, 0) return llmemory.cast_ptr_to_adr(ptr) + ofs
def _get_gc_data_offset(): return (llmemory.offsetof(STR, 'chars') + llmemory.itemoffsetof(STR.chars, 0))
def _str_ofs(TP, item): return (llmemory.offsetof(TP, 'chars') + llmemory.itemoffsetof(TP.chars, 0) + llmemory.sizeof(CHAR_TP) * item)
('jf_frame', lltype.Array(lltype.Signed)), # note that we keep length field, because it's crucial to have the data # about GCrefs here and not in frame info which might change adtmeths = { 'allocate': jitframe_allocate, 'resolve': jitframe_resolve, }, rtti = True, )) @specialize.memo() def getofs(name): return llmemory.offsetof(JITFRAME, name) GCMAPLENGTHOFS = llmemory.arraylengthoffset(GCMAP) GCMAPBASEOFS = llmemory.itemoffsetof(GCMAP, 0) BASEITEMOFS = llmemory.itemoffsetof(JITFRAME.jf_frame, 0) LENGTHOFS = llmemory.arraylengthoffset(JITFRAME.jf_frame) SIGN_SIZE = llmemory.sizeof(lltype.Signed) UNSIGN_SIZE = llmemory.sizeof(lltype.Unsigned) STACK_DEPTH_OFS = getofs('jf_extra_stack_depth') def jitframe_trace(gc, obj_addr, callback, arg): gc._trace_callback(callback, arg, obj_addr + getofs('jf_descr')) gc._trace_callback(callback, arg, obj_addr + getofs('jf_force_descr')) gc._trace_callback(callback, arg, obj_addr + getofs('jf_savedata')) gc._trace_callback(callback, arg, obj_addr + getofs('jf_guard_exc')) gc._trace_callback(callback, arg, obj_addr + getofs('jf_forward')) if IS_32BIT: MAX = 32
def setarrayitem(self, array, index, newitem): ARRAY = lltype.typeOf(array).TO addr = llmemory.cast_ptr_to_adr(array) addr += llmemory.itemoffsetof(ARRAY, index) self.setinterior(array, addr, ARRAY.OF, newitem, (index,))
def str_gc_load(TYPE, buf, offset): base_ofs = (llmemory.offsetof(STR, 'chars') + llmemory.itemoffsetof(STR.chars, 0)) scale_factor = llmemory.sizeof(lltype.Char) lls = llstr(buf) return llop.gc_load_indexed(TYPE, lls, offset, scale_factor, base_ofs)
def get_gc_data_offset_for_list_of_chars(): LIST = LIST_OF(lltype.Char) return llmemory.itemoffsetof(LIST.items.TO, 0)