class HeapDumper(object): _alloc_flavor_ = "raw" BUFSIZE = 8192 # words def __init__(self, gc, fd): self.gc = gc self.gcflag = gc.gcflag_extra self.fd = rffi.cast(rffi.INT, fd) self.writebuffer = lltype.malloc(rffi.SIGNEDP.TO, self.BUFSIZE, flavor='raw') self.buf_count = 0 if self.gcflag == 0: self.seen = AddressDict() self.pending = AddressStack() def delete(self): if self.gcflag == 0: self.seen.delete() self.pending.delete() lltype.free(self.writebuffer, flavor='raw') free_non_gc_object(self) @jit.dont_look_inside def flush(self): if self.buf_count > 0: bytes = self.buf_count * rffi.sizeof(rffi.LONG) count = raw_os_write(self.fd, rffi.cast(llmemory.Address, self.writebuffer), rffi.cast(rffi.SIZE_T, bytes)) if rffi.cast(lltype.Signed, count) != bytes: raise OSError(rffi.cast(lltype.Signed, rposix._get_errno()), "raw_os_write failed") self.buf_count = 0 flush._dont_inline_ = True def write(self, value): x = self.buf_count self.writebuffer[x] = value x += 1 self.buf_count = x if x == self.BUFSIZE: self.flush() write._always_inline_ = True # ---------- def write_marker(self): self.write(0) self.write(0) self.write(0) self.write(-1) def writeobj(self, obj): gc = self.gc typeid = gc.get_type_id(obj) self.write(llmemory.cast_adr_to_int(obj)) self.write(gc.get_member_index(typeid)) self.write(gc.get_size_incl_hash(obj)) gc.trace(obj, self._writeref, None) self.write(-1) def _writeref(self, pointer, _): obj = pointer.address[0] self.write(llmemory.cast_adr_to_int(obj)) self.add(obj) def add(self, obj): if self.gcflag == 0: if not self.seen.contains(obj): self.seen.setitem(obj, obj) self.pending.append(obj) else: hdr = self.gc.header(obj) if (hdr.tid & self.gcflag) == 0: hdr.tid |= self.gcflag self.pending.append(obj) def add_roots(self): self.gc.enumerate_all_roots(_hd_add_root, self) pendingroots = self.pending self.pending = AddressStack() self.walk(pendingroots) pendingroots.delete() self.write_marker() def walk(self, pending): while pending.non_empty(): self.writeobj(pending.pop()) # ---------- # A simplified copy of the above, to make sure we walk again all the # objects to clear the 'gcflag'. def unwriteobj(self, obj): gc = self.gc gc.trace(obj, self._unwriteref, None) def _unwriteref(self, pointer, _): obj = pointer.address[0] self.unadd(obj) def unadd(self, obj): assert self.gcflag != 0 hdr = self.gc.header(obj) if (hdr.tid & self.gcflag) != 0: hdr.tid &= ~self.gcflag self.pending.append(obj) def clear_gcflag_again(self): self.gc.enumerate_all_roots(_hd_unadd_root, self) pendingroots = self.pending self.pending = AddressStack() self.unwalk(pendingroots) pendingroots.delete() def unwalk(self, pending): while pending.non_empty(): self.unwriteobj(pending.pop())
class BaseWalker(object): _alloc_flavor_ = 'raw' def __init__(self, gc): self.gc = gc self.gcflag = gc.gcflag_extra if self.gcflag == 0: self.seen = AddressDict() self.pending = AddressStack() def delete(self): if self.gcflag == 0: self.seen.delete() self.pending.delete() free_non_gc_object(self) def add_roots(self): self.gc.enumerate_all_roots(_hd_add_root, self) pendingroots = self.pending self.pending = AddressStack() self.walk(pendingroots) pendingroots.delete() self.end_add_roots_marker() def end_add_roots_marker(self): pass def add(self, obj): if self.gcflag == 0: if not self.seen.contains(obj): self.seen.setitem(obj, obj) self.pending.append(obj) else: hdr = self.gc.header(obj) if (hdr.tid & self.gcflag) == 0: hdr.tid |= self.gcflag self.pending.append(obj) def walk(self, pending): while pending.non_empty(): self.processobj(pending.pop()) # ---------- # A simplified copy of the above, to make sure we walk again all the # objects to clear the 'gcflag'. def unobj(self, obj): gc = self.gc gc.trace(obj, self._unref, None) def _unref(self, pointer, _): obj = pointer.address[0] self.unadd(obj) def unadd(self, obj): assert self.gcflag != 0 hdr = self.gc.header(obj) if (hdr.tid & self.gcflag) != 0: hdr.tid &= ~self.gcflag self.pending.append(obj) def clear_gcflag_again(self): self.gc.enumerate_all_roots(_hd_unadd_root, self) pendingroots = self.pending self.pending = AddressStack() self.unwalk(pendingroots) pendingroots.delete() def unwalk(self, pending): while pending.non_empty(): self.unobj(pending.pop()) def finish_processing(self): if self.gcflag != 0: self.clear_gcflag_again() self.unwalk(self.pending) def process(self): self.add_roots() self.walk(self.pending)