[pypy-svn] r51624 - pypy/branch/no-forw-ptr/pypy/rpython/memory/gc
arigo at codespeak.net
arigo at codespeak.net
Tue Feb 19 12:32:14 CET 2008
Author: arigo
Date: Tue Feb 19 12:32:13 2008
New Revision: 51624
Modified:
pypy/branch/no-forw-ptr/pypy/rpython/memory/gc/semispace.py
Log:
Remove the 'forw' pointer from the header.
test_gc.TestSemiSpaceGC passes :-)
Modified: pypy/branch/no-forw-ptr/pypy/rpython/memory/gc/semispace.py
==============================================================================
--- pypy/branch/no-forw-ptr/pypy/rpython/memory/gc/semispace.py (original)
+++ pypy/branch/no-forw-ptr/pypy/rpython/memory/gc/semispace.py Tue Feb 19 12:32:13 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):
@@ -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,23 @@
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 == 0, "get_type_id on forwarded obj")
+ # 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 +390,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 +405,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 +421,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 +458,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.
More information about the Pypy-commit
mailing list