[pypy-svn] r51799 - in pypy/branch/unified-rtti/pypy/rpython: lltypesystem lltypesystem/test memory memory/gc
arigo at codespeak.net
arigo at codespeak.net
Fri Feb 22 16:19:03 CET 2008
Author: arigo
Date: Fri Feb 22 16:19:03 2008
New Revision: 51799
Modified:
pypy/branch/unified-rtti/pypy/rpython/lltypesystem/llarena.py
pypy/branch/unified-rtti/pypy/rpython/lltypesystem/llmemory.py
pypy/branch/unified-rtti/pypy/rpython/lltypesystem/lltype.py
pypy/branch/unified-rtti/pypy/rpython/lltypesystem/test/test_llarena.py
pypy/branch/unified-rtti/pypy/rpython/memory/gc/generation.py
pypy/branch/unified-rtti/pypy/rpython/memory/gc/semispace.py
pypy/branch/unified-rtti/pypy/rpython/memory/gcheader.py
pypy/branch/unified-rtti/pypy/rpython/memory/support.py
Log:
Merge r51675 from the trunk.
Modified: pypy/branch/unified-rtti/pypy/rpython/lltypesystem/llarena.py
==============================================================================
--- pypy/branch/unified-rtti/pypy/rpython/lltypesystem/llarena.py (original)
+++ pypy/branch/unified-rtti/pypy/rpython/lltypesystem/llarena.py Fri Feb 22 16:19:03 2008
@@ -1,4 +1,4 @@
-import array
+import array, weakref
from pypy.rpython.lltypesystem import lltype, llmemory
# An "arena" is a large area of memory which can hold a number of
@@ -15,6 +15,7 @@
class Arena(object):
object_arena_location = {} # {container: (arena, offset)}
+ old_object_arena_location = weakref.WeakKeyDictionary()
def __init__(self, nbytes, zero):
self.nbytes = nbytes
@@ -29,7 +30,7 @@
if size is None:
stop = self.nbytes
else:
- stop = start + size
+ stop = start + llmemory.raw_malloc_usage(size)
assert 0 <= start <= stop <= self.nbytes
for offset, ptr in self.objectptrs.items():
size = self.objectsizes[offset]
@@ -79,9 +80,7 @@
addr2 = size._raw_malloc([], zero=zero)
pattern = 'X' + 'x'*(bytes-1)
self.usagemap[offset:offset+bytes] = array.array('c', pattern)
- self.objectptrs[offset] = addr2.ptr
- self.objectsizes[offset] = bytes
- Arena.object_arena_location[addr2.ptr._obj] = self, offset
+ self.setobject(addr2, offset, bytes)
# common case: 'size' starts with a GCHeaderOffset. In this case
# we can also remember that the real object starts after the header.
while isinstance(size, RoundedUpForAllocation):
@@ -91,12 +90,17 @@
objaddr = addr2 + size.offsets[0]
hdrbytes = llmemory.raw_malloc_usage(size.offsets[0])
objoffset = offset + hdrbytes
- assert objoffset not in self.objectptrs
- self.objectptrs[objoffset] = objaddr.ptr
- self.objectsizes[objoffset] = bytes - hdrbytes
- Arena.object_arena_location[objaddr.ptr._obj] = self, objoffset
+ self.setobject(objaddr, objoffset, bytes - hdrbytes)
return addr2
+ def setobject(self, objaddr, offset, bytes):
+ assert offset not in self.objectptrs
+ self.objectptrs[offset] = objaddr.ptr
+ self.objectsizes[offset] = bytes
+ container = objaddr.ptr._obj
+ Arena.object_arena_location[container] = self, offset
+ Arena.old_object_arena_location[container] = self, offset
+
class fakearenaaddress(llmemory.fakeaddress):
def __init__(self, arena, offset):
@@ -148,6 +152,7 @@
return True
def compare_with_fakeaddr(self, other):
+ other = other._fixup()
if not other:
return None, None
obj = other.ptr._obj
@@ -205,6 +210,30 @@
return self.arena._getid() + self.offset
+def _getfakearenaaddress(addr):
+ """Logic to handle test_replace_object_with_stub()."""
+ if isinstance(addr, fakearenaaddress):
+ return addr
+ else:
+ assert isinstance(addr, llmemory.fakeaddress)
+ assert addr, "NULL address"
+ # it must be possible to use the address of an already-freed
+ # arena object
+ obj = addr.ptr._getobj(check=False)
+ return _oldobj_to_address(obj)
+
+def _oldobj_to_address(obj):
+ obj = obj._normalizedcontainer(check=False)
+ try:
+ arena, offset = Arena.old_object_arena_location[obj]
+ except KeyError:
+ if obj._was_freed():
+ msg = "taking address of %r, but it was freed"
+ else:
+ msg = "taking address of %r, but it is not in an arena"
+ raise RuntimeError(msg % (obj,))
+ return arena.getaddr(offset)
+
class RoundedUpForAllocation(llmemory.AddressOffset):
"""A size that is rounded up in order to preserve alignment of objects
following it. For arenas containing heterogenous objects.
@@ -247,7 +276,7 @@
"""Free all objects in the arena, which can then be reused.
The arena is filled with zeroes if 'zero' is True. This can also
be used on a subrange of the arena."""
- assert isinstance(arena_addr, fakearenaaddress)
+ arena_addr = _getfakearenaaddress(arena_addr)
arena_addr.arena.reset(zero, arena_addr.offset, size)
def arena_reserve(addr, size, check_alignment=True):
@@ -256,7 +285,7 @@
overlap. The size must be symbolic; in non-translated version
this is used to know what type of lltype object to allocate."""
from pypy.rpython.memory.lltypelayout import memory_alignment
- assert isinstance(addr, fakearenaaddress)
+ addr = _getfakearenaaddress(addr)
if check_alignment and (addr.offset & (memory_alignment-1)) != 0:
raise ArenaError("object at offset %d would not be correctly aligned"
% (addr.offset,))
Modified: pypy/branch/unified-rtti/pypy/rpython/lltypesystem/llmemory.py
==============================================================================
--- pypy/branch/unified-rtti/pypy/rpython/lltypesystem/llmemory.py (original)
+++ pypy/branch/unified-rtti/pypy/rpython/lltypesystem/llmemory.py Fri Feb 22 16:19:03 2008
@@ -372,7 +372,9 @@
# NOTE: the 'ptr' in the addresses must be normalized.
# Use cast_ptr_to_adr() instead of directly fakeaddress() if unsure.
def __init__(self, ptr):
- self.ptr = ptr or None # null ptr => None
+ if ptr is not None and ptr._obj0 is None:
+ ptr = None # null ptr => None
+ self.ptr = ptr
def __repr__(self):
if self.ptr is None:
@@ -407,8 +409,8 @@
def __eq__(self, other):
if isinstance(other, fakeaddress):
- obj1 = self.ptr
- obj2 = other.ptr
+ obj1 = self._fixup().ptr
+ obj2 = other._fixup().ptr
if obj1 is not None: obj1 = obj1._obj
if obj2 is not None: obj2 = obj2._obj
return obj1 == obj2
@@ -450,8 +452,9 @@
return self.ptr
def _cast_to_ptr(self, EXPECTED_TYPE):
- if self:
- return cast_any_ptr(EXPECTED_TYPE, self.ptr)
+ addr = self._fixup()
+ if addr:
+ return cast_any_ptr(EXPECTED_TYPE, addr.ptr)
else:
return lltype.nullptr(EXPECTED_TYPE.TO)
@@ -461,6 +464,14 @@
else:
return 0
+ def _fixup(self):
+ if self.ptr is not None and self.ptr._was_freed():
+ # hack to support llarena.test_replace_object_with_stub()
+ from pypy.rpython.lltypesystem import llarena
+ return llarena._getfakearenaaddress(self)
+ else:
+ return self
+
# ____________________________________________________________
class fakeaddresswithflags(object):
Modified: pypy/branch/unified-rtti/pypy/rpython/lltypesystem/lltype.py
==============================================================================
--- pypy/branch/unified-rtti/pypy/rpython/lltypesystem/lltype.py (original)
+++ pypy/branch/unified-rtti/pypy/rpython/lltypesystem/lltype.py Fri Feb 22 16:19:03 2008
@@ -956,7 +956,7 @@
self._set_solid(solid)
self._set_obj0(obj0)
- def _getobj(self):
+ def _getobj(self, check=True):
obj = self._obj0
if obj is not None:
if self._weak:
@@ -965,12 +965,17 @@
raise RuntimeError("accessing already garbage collected %r"
% (self._T,))
if isinstance(obj, _container):
- obj._check()
+ if check:
+ obj._check()
elif isinstance(obj, str) and obj.startswith("delayed!"):
raise DelayedPointer
return obj
_obj = property(_getobj)
+ def _was_freed(self):
+ return (self._obj0 is not None and
+ self._getobj(check=False)._was_freed())
+
def __getattr__(self, field_name): # ! can only return basic or ptr !
if isinstance(self._T, Struct):
if field_name in self._T._flds:
@@ -1171,6 +1176,10 @@
from pypy.rpython.lltypesystem import llmemory
if isinstance(self._T, FuncType):
return llmemory.fakeaddress(self)
+ elif self._was_freed():
+ # hack to support llarena.test_replace_object_with_stub()
+ from pypy.rpython.lltypesystem import llarena
+ return llarena._oldobj_to_address(self._getobj(check=False))
elif isinstance(self._obj, _subarray):
return llmemory.fakeaddress(self)
## # return an address built as an offset in the whole array
@@ -1185,8 +1194,8 @@
def _as_ptr(self):
return self
- def _as_obj(self):
- return self._obj
+ def _as_obj(self, check=True):
+ return self._getobj(check=check)
def _expose(self, offset, val):
"""XXX A nice docstring here"""
@@ -1251,13 +1260,13 @@
class _container(object):
__slots__ = ()
- def _parentstructure(self):
+ def _parentstructure(self, check=True):
return None
def _check(self):
pass
def _as_ptr(self):
return _ptr(Ptr(self._TYPE), self, True)
- def _as_obj(self):
+ def _as_obj(self, check=True):
return self
def _normalizedcontainer(self):
return self
@@ -1288,7 +1297,16 @@
self._storage = None
def _was_freed(self):
- return self._storage is None
+ if self._storage is None:
+ return True
+ if self._wrparent is None:
+ return False
+ parent = self._wrparent()
+ if parent is None:
+ raise RuntimeError("accessing sub%s %r,\n"
+ "but already garbage collected parent %r"
+ % (self._kind, self, self._parent_type))
+ return parent._was_freed()
def _setparentstructure(self, parent, parentindex):
self._wrparent = weakref.ref(parent)
@@ -1300,14 +1318,15 @@
# keep strong reference to parent, we share the same allocation
self._keepparent = parent
- def _parentstructure(self):
+ def _parentstructure(self, check=True):
if self._wrparent is not None:
parent = self._wrparent()
if parent is None:
raise RuntimeError("accessing sub%s %r,\n"
"but already garbage collected parent %r"
% (self._kind, self, self._parent_type))
- parent._check()
+ if check:
+ parent._check()
return parent
return None
@@ -1316,14 +1335,15 @@
raise RuntimeError("accessing freed %r" % self._TYPE)
self._parentstructure()
- def _normalizedcontainer(self):
+ def _normalizedcontainer(self, check=True):
# if we are the first inlined substructure of a structure,
# return the whole (larger) structure instead
container = self
while True:
- parent, index = parentlink(container)
+ parent = container._parentstructure(check=check)
if parent is None:
break
+ index = container._parent_index
T = typeOf(parent)
if (not isinstance(T, Struct) or T._first_struct()[0] != index
or isinstance(T, FixedSizeArray)):
@@ -1518,7 +1538,7 @@
def __repr__(self):
return '<_subarray at %r in %r>' % (self._parent_index,
- self._parentstructure())
+ self._parentstructure(check=False))
def getlength(self):
assert isinstance(self._TYPE, FixedSizeArray)
Modified: pypy/branch/unified-rtti/pypy/rpython/lltypesystem/test/test_llarena.py
==============================================================================
--- pypy/branch/unified-rtti/pypy/rpython/lltypesystem/test/test_llarena.py (original)
+++ pypy/branch/unified-rtti/pypy/rpython/lltypesystem/test/test_llarena.py Fri Feb 22 16:19:03 2008
@@ -165,6 +165,8 @@
plist.append(llmemory.cast_adr_to_ptr(b, SPTR))
# clear blist[1] and blist[2] but not blist[0] nor blist[3]
arena_reset(blist[1], llmemory.raw_malloc_usage(precomputed_size)*2, False)
+ py.test.raises(RuntimeError, "plist[1].x") # marked as freed
+ py.test.raises(RuntimeError, "plist[2].x") # marked as freed
# re-reserve object at index 1 and 2
blist[1] = reserve(1)
blist[2] = reserve(2)
@@ -173,6 +175,10 @@
assert plist[3].x == 103
py.test.raises(RuntimeError, "plist[1].x") # marked as freed
py.test.raises(RuntimeError, "plist[2].x") # marked as freed
+ # but we can still cast the old ptrs to addresses, which compare equal
+ # to the new ones we gotq
+ assert llmemory.cast_ptr_to_adr(plist[1]) == blist[1]
+ assert llmemory.cast_ptr_to_adr(plist[2]) == blist[2]
# check via addresses
assert (blist[0] + llmemory.offsetof(SX, 'x')).signed[0] == 100
assert (blist[3] + llmemory.offsetof(SX, 'x')).signed[0] == 103
@@ -204,6 +210,45 @@
assert llmemory.cast_adr_to_int(a) == llmemory.cast_adr_to_int(a1)
assert llmemory.cast_adr_to_int(a+1) == llmemory.cast_adr_to_int(a1) + 1
+def test_replace_object_with_stub():
+ from pypy.rpython.memory.gcheader import GCHeaderBuilder
+ HDR = lltype.Struct('HDR', ('x', lltype.Signed))
+ S = lltype.GcStruct('S', ('y', lltype.Signed), ('z', lltype.Signed))
+ STUB = lltype.GcStruct('STUB', ('t', lltype.Char))
+ gcheaderbuilder = GCHeaderBuilder(HDR)
+ size_gc_header = gcheaderbuilder.size_gc_header
+
+ a = arena_malloc(50, True)
+ hdraddr = a + 12
+ arena_reserve(hdraddr, size_gc_header + llmemory.sizeof(S))
+ hdr = llmemory.cast_adr_to_ptr(hdraddr, lltype.Ptr(HDR))
+ hdr.x = 42
+ obj = llmemory.cast_adr_to_ptr(hdraddr + size_gc_header, lltype.Ptr(S))
+ obj.y = -5
+ obj.z = -6
+
+ hdraddr = llmemory.cast_ptr_to_adr(obj) - size_gc_header
+ arena_reset(hdraddr, size_gc_header + llmemory.sizeof(S), False)
+ arena_reserve(hdraddr, size_gc_header + llmemory.sizeof(STUB))
+
+ # check that it possible to reach the newly reserved HDR+STUB
+ # via the header of the old 'obj' pointer, both via the existing
+ # 'hdraddr':
+ hdr = llmemory.cast_adr_to_ptr(hdraddr, lltype.Ptr(HDR))
+ hdr.x = 46
+ stub = llmemory.cast_adr_to_ptr(hdraddr + size_gc_header, lltype.Ptr(STUB))
+ stub.t = '!'
+
+ # and via a (now-invalid) pointer to the old 'obj': (this is needed
+ # because during a garbage collection there are still pointers to
+ # the old 'obj' around to be fixed)
+ hdraddr = llmemory.cast_ptr_to_adr(obj) - size_gc_header
+ hdr = llmemory.cast_adr_to_ptr(hdraddr, lltype.Ptr(HDR))
+ assert hdr.x == 46
+ stub = llmemory.cast_adr_to_ptr(hdraddr + size_gc_header,
+ lltype.Ptr(STUB))
+ assert stub.t == '!'
+
def test_llinterpreted():
from pypy.rpython.test.test_llinterp import interpret
Modified: pypy/branch/unified-rtti/pypy/rpython/memory/gc/generation.py
==============================================================================
--- pypy/branch/unified-rtti/pypy/rpython/memory/gc/generation.py (original)
+++ pypy/branch/unified-rtti/pypy/rpython/memory/gc/generation.py Fri Feb 22 16:19:03 2008
@@ -22,8 +22,8 @@
class GenerationGC(SemiSpaceGC):
"""A basic generational GC: it's a SemiSpaceGC with an additional
nursery for young objects. A write barrier is used to ensure that
- old objects that contain pointers to young objects are in a linked
- list, chained to each other via their 'forw' header field.
+ old objects that contain pointers to young objects are recorded in
+ a list.
"""
inline_simple_malloc = True
inline_simple_malloc_varsize = True
@@ -44,19 +44,16 @@
self.initial_nursery_size = nursery_size
self.auto_nursery_size = auto_nursery_size
self.min_nursery_size = min_nursery_size
-
- def setup(self):
- SemiSpaceGC.setup(self)
- self.reset_nursery()
- self.old_objects_pointing_to_young = NULL
- # ^^^ the head of a linked list inside the old objects space; it
+ self.old_objects_pointing_to_young = self.AddressStack()
+ # ^^^ a list of addresses inside the old objects space; it
# may contain static prebuilt objects as well. More precisely,
# it lists exactly the old and static objects whose
- # GCFLAG_NO_YOUNG_PTRS bit is not set. The 'forw' header field
- # of such objects is abused for this linked list; it needs to be
- # reset to its correct value when GCFLAG_NO_YOUNG_PTRS is set
- # again at the start of a collection.
+ # GCFLAG_NO_YOUNG_PTRS bit is not set.
self.young_objects_with_weakrefs = self.AddressStack()
+ self.reset_nursery()
+
+ def setup(self):
+ SemiSpaceGC.setup(self)
self.set_nursery_size(self.initial_nursery_size)
# the GC is fully setup now. The rest can make use of it.
if self.auto_nursery_size:
@@ -226,14 +223,11 @@
# the next usage.
def reset_young_gcflags(self):
- obj = self.old_objects_pointing_to_young
- while obj:
+ oldlist = self.old_objects_pointing_to_young
+ while oldlist.non_empty():
+ obj = oldlist.pop()
hdr = self.header(obj)
hdr.tid |= GCFLAG_NO_YOUNG_PTRS
- nextobj = hdr.forw
- self.init_forwarding(obj)
- obj = nextobj
- self.old_objects_pointing_to_young = NULL
def weakrefs_grow_older(self):
while self.young_objects_with_weakrefs.non_empty():
@@ -278,19 +272,15 @@
def collect_oldrefs_to_nursery(self):
# Follow the old_objects_pointing_to_young list and move the
- # young objects they point to out of the nursery. The 'forw'
- # fields are reset to their correct value along the way.
+ # young objects they point to out of the nursery.
count = 0
- obj = self.old_objects_pointing_to_young
- while obj:
+ oldlist = self.old_objects_pointing_to_young
+ while oldlist.non_empty():
count += 1
- nextobj = self.header(obj).forw
- self.init_forwarding(obj)
+ obj = oldlist.pop()
self.trace_and_drag_out_of_nursery(obj)
- obj = nextobj
if DEBUG_PRINT:
llop.debug_print(lltype.Void, "collect_oldrefs_to_nursery", count)
- self.old_objects_pointing_to_young = NULL
def collect_roots_in_nursery(self):
# we don't need to trace prebuilt GcStructs during a minor collect:
@@ -362,8 +352,7 @@
"nursery object with GCFLAG_NO_YOUNG_PTRS")
oldhdr = self.header(addr_struct)
if self.is_in_nursery(addr):
- oldhdr.forw = self.old_objects_pointing_to_young
- self.old_objects_pointing_to_young = addr_struct
+ self.old_objects_pointing_to_young.append(addr_struct)
oldhdr.tid &= ~GCFLAG_NO_YOUNG_PTRS
if oldhdr.tid & GCFLAG_NO_HEAP_PTRS:
self.move_to_static_roots(addr_struct)
Modified: pypy/branch/unified-rtti/pypy/rpython/memory/gc/semispace.py
==============================================================================
--- pypy/branch/unified-rtti/pypy/rpython/memory/gc/semispace.py (original)
+++ pypy/branch/unified-rtti/pypy/rpython/memory/gc/semispace.py Fri Feb 22 16:19:03 2008
@@ -15,8 +15,9 @@
TYPEID_MASK = 0xffff
first_gcflag = 1 << 16
-GCFLAG_IMMORTAL = first_gcflag
-GCFLAG_FINALIZATION_ORDERING = first_gcflag << 1
+GCFLAG_FORWARDED = first_gcflag
+GCFLAG_IMMORTAL = first_gcflag << 1
+GCFLAG_FINALIZATION_ORDERING = first_gcflag << 2
DEBUG_PRINT = False
memoryError = MemoryError()
@@ -26,12 +27,14 @@
inline_simple_malloc = True
inline_simple_malloc_varsize = True
needs_zero_gc_pointers = False
- first_unused_gcflag = first_gcflag << 2
+ first_unused_gcflag = first_gcflag << 3
total_collection_time = 0.0
total_collection_count = 0
- HDR = lltype.Struct('header', ('forw', llmemory.Address),
- ('tid', lltype.Signed))
+ HDR = lltype.Struct('header', ('tid', lltype.Signed))
+ FORWARDSTUB = lltype.GcStruct('forwarding_stub',
+ ('forw', llmemory.Address))
+ FORWARDSTUBPTR = lltype.Ptr(FORWARDSTUB)
def __init__(self, chunk_size=DEFAULT_CHUNK_SIZE, space_size=4096,
max_space_size=sys.maxint//2+1):
@@ -41,6 +44,8 @@
self.gcheaderbuilder = GCHeaderBuilder(self.HDR)
self.AddressStack = get_address_stack(chunk_size)
self.AddressDeque = get_address_deque(chunk_size)
+ self.finalizer_lock_count = 0
+ self.red_zone = 0
def setup(self):
if DEBUG_PRINT:
@@ -55,8 +60,6 @@
self.objects_with_finalizers = self.AddressDeque()
self.run_finalizers = self.AddressDeque()
self.objects_with_weakrefs = self.AddressStack()
- self.finalizer_lock_count = 0
- self.red_zone = 0
def disable_finalizers(self):
self.finalizer_lock_count += 1
@@ -289,15 +292,13 @@
root.address[0] = self.copy(root.address[0])
def copy(self, obj):
- # Objects not living the GC heap have all been initialized by
- # setting their 'forw' address so that it points to themselves.
- # The logic below will thus simply return 'obj' if 'obj' is prebuilt.
if self.is_forwarded(obj):
#llop.debug_print(lltype.Void, obj, "already copied to", self.get_forwarding_address(obj))
return self.get_forwarding_address(obj)
else:
newaddr = self.free
- totalsize = self.size_gc_header() + self.get_size(obj)
+ objsize = self.get_size(obj)
+ totalsize = self.size_gc_header() + objsize
llarena.arena_reserve(newaddr, totalsize)
raw_memcopy(obj - self.size_gc_header(), newaddr, totalsize)
self.free += totalsize
@@ -305,7 +306,7 @@
#llop.debug_print(lltype.Void, obj, "copied to", newobj,
# "tid", self.header(obj).tid,
# "size", totalsize)
- self.set_forwarding_address(obj, newobj)
+ self.set_forwarding_address(obj, newobj, objsize)
return newobj
def trace_and_copy(self, obj):
@@ -316,14 +317,35 @@
pointer.address[0] = self.copy(pointer.address[0])
def is_forwarded(self, obj):
- return self.header(obj).forw != NULL
+ return self.header(obj).tid & GCFLAG_FORWARDED != 0
+ # note: all prebuilt objects also have this flag set
def get_forwarding_address(self, obj):
- return self.header(obj).forw
+ tid = self.header(obj).tid
+ if tid & GCFLAG_IMMORTAL:
+ return obj # prebuilt objects are "forwarded" to themselves
+ else:
+ stub = llmemory.cast_adr_to_ptr(obj, self.FORWARDSTUBPTR)
+ return stub.forw
- def set_forwarding_address(self, obj, newobj):
- gc_info = self.header(obj)
- gc_info.forw = newobj
+ def set_forwarding_address(self, obj, newobj, objsize):
+ # To mark an object as forwarded, we set the GCFLAG_FORWARDED and
+ # overwrite the object with a FORWARDSTUB. Doing so is a bit
+ # long-winded on llarena, but it all melts down to two memory
+ # writes after translation to C.
+ size_gc_header = self.size_gc_header()
+ stubsize = llmemory.sizeof(self.FORWARDSTUB)
+ tid = self.header(obj).tid
+ ll_assert(tid & GCFLAG_IMMORTAL == 0, "unexpected GCFLAG_IMMORTAL")
+ ll_assert(tid & GCFLAG_FORWARDED == 0, "unexpected GCFLAG_FORWARDED")
+ # replace the object at 'obj' with a FORWARDSTUB.
+ hdraddr = obj - size_gc_header
+ llarena.arena_reset(hdraddr, size_gc_header + objsize, False)
+ llarena.arena_reserve(hdraddr, size_gc_header + stubsize)
+ hdr = llmemory.cast_adr_to_ptr(hdraddr, lltype.Ptr(self.HDR))
+ hdr.tid = tid | GCFLAG_FORWARDED
+ stub = llmemory.cast_adr_to_ptr(obj, self.FORWARDSTUBPTR)
+ stub.forw = newobj
def get_size(self, obj):
typeid = self.get_type_id(obj)
@@ -340,26 +362,24 @@
return llmemory.cast_adr_to_ptr(addr, lltype.Ptr(self.HDR))
def get_type_id(self, addr):
- return self.header(addr).tid & TYPEID_MASK
+ tid = self.header(addr).tid
+ ll_assert(tid & (GCFLAG_FORWARDED|GCFLAG_IMMORTAL) != GCFLAG_FORWARDED,
+ "get_type_id on forwarded obj")
+ # Non-prebuilt forwarded objects are overwritten with a FORWARDSTUB.
+ # Although calling get_type_id() on a forwarded object works by itself,
+ # we catch it as an error because it's likely that what is then
+ # done with the typeid is bogus.
+ return tid & TYPEID_MASK
def init_gc_object(self, addr, typeid, flags=0):
hdr = llmemory.cast_adr_to_ptr(addr, lltype.Ptr(self.HDR))
- #hdr.forw = NULL -- unneeded, the space is initially filled with zero
hdr.tid = typeid | flags
def init_gc_object_immortal(self, addr, typeid, flags=0):
- # immortal objects always have forward to themselves
hdr = llmemory.cast_adr_to_ptr(addr, lltype.Ptr(self.HDR))
- hdr.tid = typeid | flags | GCFLAG_IMMORTAL
- self.init_forwarding(addr + self.gcheaderbuilder.size_gc_header)
-
- def init_forwarding(self, obj):
- hdr = self.header(obj)
- if hdr.tid & GCFLAG_IMMORTAL:
- hdr.forw = obj # prebuilt objects point to themselves,
- # so that a collection does not move them
- else:
- hdr.forw = NULL
+ hdr.tid = typeid | flags | GCFLAG_IMMORTAL | GCFLAG_FORWARDED
+ # immortal objects always have GCFLAG_FORWARDED set;
+ # see get_forwarding_address().
def deal_with_objects_with_finalizers(self, scan):
# walk over list of objects with finalizers
@@ -371,6 +391,7 @@
new_with_finalizer = self.AddressDeque()
marked = self.AddressDeque()
pending = self.AddressStack()
+ self.tmpstack = self.AddressStack()
while self.objects_with_finalizers.non_empty():
x = self.objects_with_finalizers.popleft()
ll_assert(self._finalization_state(x) != 1,
@@ -385,11 +406,9 @@
state = self._finalization_state(y)
if state == 0:
self._bump_finalization_state_from_0_to_1(y)
+ self.trace(y, self._append_if_nonnull, pending)
elif state == 2:
- self._bump_finalization_state_from_2_to_3(y)
- else:
- continue # don't need to recurse inside y
- self.trace(y, self._append_if_nonnull, pending)
+ self._recursively_bump_finalization_state_from_2_to_3(y)
scan = self._recursively_bump_finalization_state_from_1_to_2(
x, scan)
@@ -403,16 +422,11 @@
# we must also fix the state from 2 to 3 here, otherwise
# we leave the GCFLAG_FINALIZATION_ORDERING bit behind
# which will confuse the next collection
- pending.append(x)
- while pending.non_empty():
- y = pending.pop()
- state = self._finalization_state(y)
- if state == 2:
- self._bump_finalization_state_from_2_to_3(y)
- self.trace(y, self._append_if_nonnull, pending)
+ self._recursively_bump_finalization_state_from_2_to_3(x)
else:
new_with_finalizer.append(newx)
+ self.tmpstack.delete()
pending.delete()
marked.delete()
self.objects_with_finalizers.delete()
@@ -445,12 +459,19 @@
hdr = self.header(obj)
hdr.tid |= GCFLAG_FINALIZATION_ORDERING
- def _bump_finalization_state_from_2_to_3(self, obj):
+ def _recursively_bump_finalization_state_from_2_to_3(self, obj):
ll_assert(self._finalization_state(obj) == 2,
"unexpected finalization state != 2")
newobj = self.get_forwarding_address(obj)
- hdr = self.header(newobj)
- hdr.tid &= ~GCFLAG_FINALIZATION_ORDERING
+ pending = self.tmpstack
+ ll_assert(not pending.non_empty(), "tmpstack not empty")
+ pending.append(newobj)
+ while pending.non_empty():
+ y = pending.pop()
+ hdr = self.header(y)
+ if hdr.tid & GCFLAG_FINALIZATION_ORDERING: # state 2 ?
+ hdr.tid &= ~GCFLAG_FINALIZATION_ORDERING # change to state 3
+ self.trace(y, self._append_if_nonnull, pending)
def _recursively_bump_finalization_state_from_1_to_2(self, obj, scan):
# recursively convert objects from state 1 to state 2.
Modified: pypy/branch/unified-rtti/pypy/rpython/memory/gcheader.py
==============================================================================
--- pypy/branch/unified-rtti/pypy/rpython/memory/gcheader.py (original)
+++ pypy/branch/unified-rtti/pypy/rpython/memory/gcheader.py Fri Feb 22 16:19:03 2008
@@ -21,17 +21,17 @@
def header_of_object(self, gcptr):
# XXX hackhackhack
- gcptr = gcptr._as_obj()
+ gcptr = gcptr._as_obj(check=False)
if isinstance(gcptr, llmemory._gctransformed_wref):
- return self.obj2header[gcptr._ptr._as_obj()]
+ return self.obj2header[gcptr._ptr._as_obj(check=False)]
return self.obj2header[gcptr]
def object_from_header(headerptr):
- return header2obj[headerptr._as_obj()]
+ return header2obj[headerptr._as_obj(check=False)]
object_from_header = staticmethod(object_from_header)
def get_header(self, gcptr):
- return self.obj2header.get(gcptr._as_obj(), None)
+ return self.obj2header.get(gcptr._as_obj(check=False), None)
def attach_header(self, gcptr, headerptr):
gcobj = gcptr._as_obj()
Modified: pypy/branch/unified-rtti/pypy/rpython/memory/support.py
==============================================================================
--- pypy/branch/unified-rtti/pypy/rpython/memory/support.py (original)
+++ pypy/branch/unified-rtti/pypy/rpython/memory/support.py Fri Feb 22 16:19:03 2008
@@ -27,7 +27,10 @@
def get(self):
if not self.free_list:
- return lltype.malloc(CHUNK, flavor="raw")
+ # we zero-initialize the chunks to make the translation
+ # backends happy, but we don't need to do it at run-time.
+ zero = not we_are_translated()
+ return lltype.malloc(CHUNK, flavor="raw", zero=zero)
result = self.free_list
self.free_list = result.next
More information about the Pypy-commit
mailing list