def make_a_nonmoving_copy(self, obj, objsize): # NB. the object can have a finalizer or be a weakref, but # it's not an issue. totalsize = self.size_gc_header() + objsize tid = self.header(obj).tid if tid & GCFLAG_HASHMASK: totalsize_incl_hash = totalsize + llmemory.sizeof(lltype.Signed) else: totalsize_incl_hash = totalsize newaddr = self.allocate_external_object(totalsize_incl_hash) if not newaddr: return llmemory.NULL # can't raise MemoryError during a collect() self._nonmoving_copy_count += 1 self._nonmoving_copy_size += raw_malloc_usage(totalsize) llmemory.raw_memcopy(obj - self.size_gc_header(), newaddr, totalsize) if tid & GCFLAG_HASHMASK: hash = self._get_object_hash(obj, objsize, tid) (newaddr + totalsize).signed[0] = hash tid |= GC_HASH_HASFIELD # # GCFLAG_UNVISITED is not set # GCFLAG_NO_HEAP_PTRS is not set either, conservatively. It may be # set by the next collection's collect_last_generation_roots(). # This old object is immediately put at generation 3. newobj = newaddr + self.size_gc_header() hdr = self.header(newobj) hdr.tid = tid | self.GCFLAGS_FOR_NEW_EXTERNAL_OBJECTS ll_assert(self.is_last_generation(newobj), "make_a_nonmoving_copy: object too young") self.gen3_rawmalloced_objects.append(newobj) self.last_generation_root_objects.append(newobj) self.rawmalloced_objects_to_trace.append(newobj) # visit me return newobj
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 length >= 0 ll_assert(srcstart >= 0, "copystrc: negative srcstart") ll_assert(srcstart + length <= len(src.chars), "copystrc: src ovf") ll_assert(dststart >= 0, "copystrc: negative dststart") ll_assert(dststart + length <= len(dst.chars), "copystrc: dst ovf") # # 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] = src.chars[srcstart + i] i += 1 return # # # from here, no GC operations can happen asrc = _get_raw_buf(SRC_TP, src, srcstart) adst = _get_raw_buf(DST_TP, dst, dststart) llmemory.raw_memcopy(asrc, adst, llmemory.sizeof(CHAR_TP) * length) # end of "no GC" section keepalive_until_here(src) keepalive_until_here(dst)
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 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_prepare_free_slot(_unused): """Free up a slot in the array of MAX entries, ready for storing a new shadowstackref. Return the memory of the now-unused full shadowstack. """ index = fullstack_cache[0] if index > 0: return llmemory.NULL # there is already at least one free slot # # make a compact copy in one old entry and return the # original full-sized memory index = -index ll_assert(index > 0, "prepare_free_slot: cache[0] == 0") compacting = lltype.cast_int_to_ptr(SHADOWSTACKREFPTR, fullstack_cache[index]) index += 1 if index >= ShadowStackPool.MAX: index = 1 fullstack_cache[0] = -index # update to the next value in order # compacting.detach() original = compacting.base size = compacting.top - original new = llmemory.raw_malloc(size) if new == llmemory.NULL: return llmemory.NULL llmemory.raw_memcopy(original, new, size) compacting.base = new compacting.top = new + size return original
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 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 _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_populate_list_from_raw_array(ll_list, src_ptr, length): ITEM = lltype.typeOf(src_ptr).TO.OF size = llmemory.sizeof(ITEM) * length ll_list._ll_resize(length) # start of no-GC section src_adr = get_raw_buf(src_ptr) dst_adr = get_raw_buf(ll_list.ll_items()) llmemory.raw_memcopy(src_adr, dst_adr, size)
def sscopy_attach_shadow_stack(sscopy): base = llop.gc_adr_of_root_stack_base(llmemory.Address).address[0] ll_assert(llop.gc_adr_of_root_stack_top(llmemory.Address).address[0]==base, "attach_shadow_stack: ss is not empty?") length_bytes = sscopy.signed[0] llmemory.raw_memcopy(sscopy + SIZEADDR, base, length_bytes) llop.gc_adr_of_root_stack_top(llmemory.Address).address[0] = ( base + length_bytes) llmemory.raw_free(sscopy)
def ll_copy_list_to_raw_array(ll_list, dst_ptr): # this code is delicate: we must ensure that there are no GC operations # around the call to raw_memcopy # ITEM = lltype.typeOf(dst_ptr).TO.OF size = llmemory.sizeof(ITEM) * ll_list.ll_length() # start of no-GC section src_adr = get_raw_buf(ll_list.ll_items()) dst_adr = get_raw_buf(dst_ptr) llmemory.raw_memcopy(src_adr, dst_adr, size)
def sscopy_attach_shadow_stack(sscopy): base = llop.gc_adr_of_root_stack_base(llmemory.Address).address[0] ll_assert( llop.gc_adr_of_root_stack_top(llmemory.Address).address[0] == base, "attach_shadow_stack: ss is not empty?") length_bytes = sscopy.signed[0] llmemory.raw_memcopy(sscopy + SIZEADDR, base, length_bytes) llop.gc_adr_of_root_stack_top(llmemory.Address).address[0] = (base + length_bytes) llmemory.raw_free(sscopy)
def sscopy_detach_shadow_stack(): base = llop.gc_adr_of_root_stack_base(llmemory.Address).address[0] top = llop.gc_adr_of_root_stack_top(llmemory.Address).address[0] length_bytes = top - base result = llmemory.raw_malloc(SIZEADDR + length_bytes) if result: result.signed[0] = length_bytes llmemory.raw_memcopy(base, result + SIZEADDR, length_bytes) llop.gc_adr_of_root_stack_top(llmemory.Address).address[0] = base return result
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 ll_populate_list_from_raw_array(ll_list, src_ptr, length): ll_list._ll_resize(length) if rgc.must_split_gc_address_space(): for i in range(length): ll_list.ll_setitem_fast(i, src_ptr[i]) return ITEM = lltype.typeOf(src_ptr).TO.OF size = llmemory.sizeof(ITEM) * length # start of no-GC section src_adr = get_raw_buf(src_ptr) dst_adr = get_raw_buf(ll_list.ll_items()) llmemory.raw_memcopy(src_adr, dst_adr, size)
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 ll_copy_list_to_raw_array(ll_list, dst_ptr): if rgc.must_split_gc_address_space(): for i in range(ll_list.ll_length()): dst_ptr[i] = ll_list.ll_getitem_fast(i) return # this code is delicate: we must ensure that there are no GC operations # around the call to raw_memcopy # ITEM = lltype.typeOf(dst_ptr).TO.OF size = llmemory.sizeof(ITEM) * ll_list.ll_length() # start of no-GC section src_adr = get_raw_buf(ll_list.ll_items()) dst_adr = get_raw_buf(dst_ptr) llmemory.raw_memcopy(src_adr, dst_adr, size)
def ll_rebuild(shadowstackref, fullstack_base): if shadowstackref.fsindex > 0: shadowstackref.detach() return fullstack_base else: # make an expanded copy of the compact shadowstack stored in # 'shadowstackref' and free that compact = shadowstackref.base size = shadowstackref.top - compact shadowstackref.base = fullstack_base shadowstackref.top = fullstack_base + size llmemory.raw_memcopy(compact, fullstack_base, size) llmemory.raw_free(compact) return llmemory.NULL
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 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 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 _make_a_copy_with_tid(self, obj, objsize, tid): totalsize = self.size_gc_header() + objsize newaddr = self.free llarena.arena_reserve(newaddr, totalsize) raw_memcopy(obj - self.size_gc_header(), newaddr, totalsize) if tid & GCFLAG_HASHMASK: hash = self._get_object_hash(obj, objsize, tid) llarena.arena_reserve(newaddr + totalsize, llmemory.sizeof(lltype.Signed)) (newaddr + totalsize).signed[0] = hash tid |= GC_HASH_HASFIELD totalsize += llmemory.sizeof(lltype.Signed) self.free += totalsize newhdr = llmemory.cast_adr_to_ptr(newaddr, lltype.Ptr(self.HDR)) newhdr.tid = tid newobj = newaddr + self.size_gc_header() return newobj
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 length >= 0 # from here, no GC operations can happen src = _get_raw_buf(SRC_TP, src, srcstart) dst = _get_raw_buf(DST_TP, dst, dststart) llmemory.raw_memcopy(src, dst, llmemory.sizeof(CHAR_TP) * length) # end of "no GC" section keepalive_until_here(src) keepalive_until_here(dst)
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_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 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 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 op_raw_memcopy(self, fromaddr, toaddr, size): checkadr(fromaddr) checkadr(toaddr) llmemory.raw_memcopy(fromaddr, toaddr, size)