[pypy-commit] pypy stm-gc: Weakrefs again.
arigo
noreply at buildbot.pypy.org
Wed Apr 18 18:07:41 CEST 2012
Author: Armin Rigo <arigo at tunes.org>
Branch: stm-gc
Changeset: r54502:7f73ab377959
Date: 2012-04-18 16:50 +0200
http://bitbucket.org/pypy/pypy/changeset/7f73ab377959/
Log: Weakrefs again.
diff --git a/pypy/rpython/memory/gc/stmgc.py b/pypy/rpython/memory/gc/stmgc.py
--- a/pypy/rpython/memory/gc/stmgc.py
+++ b/pypy/rpython/memory/gc/stmgc.py
@@ -42,8 +42,7 @@
GCFLAG_WAS_COPIED = first_gcflag << 1 # keep in sync with et.c
GCFLAG_HAS_SHADOW = first_gcflag << 2
GCFLAG_FIXED_HASH = first_gcflag << 3
-GCFLAG_WEAKREF = first_gcflag << 4
-GCFLAG_VISITED = first_gcflag << 5
+GCFLAG_VISITED = first_gcflag << 4
def always_inline(fn):
@@ -161,15 +160,15 @@
# Get the memory from the nursery.
size_gc_header = self.gcheaderbuilder.size_gc_header
totalsize = size_gc_header + size
- result = self.get_tls().allocate_bump_pointer(totalsize)
+ tls = self.get_tls()
+ result = tls.allocate_bump_pointer(totalsize)
#
# Build the object.
llarena.arena_reserve(result, totalsize)
obj = result + size_gc_header
- flags = 0
+ self.init_gc_object(result, typeid, flags=0)
if contains_weakptr: # check constant-folded
- flags |= GCFLAG_WEAKREF
- self.init_gc_object(result, typeid, flags=flags)
+ tls.fresh_new_weakref(obj)
#
return llmemory.cast_adr_to_ptr(obj, llmemory.GCREF)
diff --git a/pypy/rpython/memory/gc/stmshared.py b/pypy/rpython/memory/gc/stmshared.py
--- a/pypy/rpython/memory/gc/stmshared.py
+++ b/pypy/rpython/memory/gc/stmshared.py
@@ -43,7 +43,7 @@
adr1 = adr2 - self.gc.gcheaderbuilder.size_gc_header
llarena.arena_free(llarena.getfakearenaaddress(adr1))
- def clear(self):
+ def free_and_clear(self):
obj = self.chained_list
self.chained_list = NULL
while obj:
diff --git a/pypy/rpython/memory/gc/stmtls.py b/pypy/rpython/memory/gc/stmtls.py
--- a/pypy/rpython/memory/gc/stmtls.py
+++ b/pypy/rpython/memory/gc/stmtls.py
@@ -38,25 +38,21 @@
self.nursery_size = self.gc.nursery_size
self.nursery_start = self._alloc_nursery(self.nursery_size)
#
- # --- the local raw-malloced objects (chained list via hdr.version)
- #self.rawmalloced_objects = NULL
- # --- the local "normal" old objects (chained list via hdr.version)
- #self.old_objects = NULL
- # --- the local objects with weakrefs (chained list via hdr.version)
- #self.young_objects_with_weakrefs = NULL
- #self.old_objects_with_weakrefs = NULL
- #
# --- a thread-local allocator for the shared area
from pypy.rpython.memory.gc.stmshared import StmGCThreadLocalAllocator
self.sharedarea_tls = StmGCThreadLocalAllocator(self.gc.sharedarea)
# --- the LOCAL objects with GCFLAG_WAS_COPIED
self.copied_local_objects = self.AddressStack()
+ # --- the LOCAL objects which are weakrefs. They are also listed
+ # in the appropriate place, like sharedarea_tls, if needed.
+ self.local_weakrefs = self.AddressStack()
#
self._register_with_C_code()
def teardown_thread(self):
self._cleanup_state()
self._unregister_with_C_code()
+ self.local_weakrefs.delete()
self.copied_local_objects.delete()
self.sharedarea_tls.delete()
self._free_nursery(self.nursery_start)
@@ -199,9 +195,9 @@
# Now repeatedly follow objects until 'pending' is empty.
self.collect_flush_pending()
#
- # Walk the list of LOCAL raw-malloced objects, and free them if
- # necessary.
- #self.free_local_rawmalloced_objects()
+ # Walk the list of LOCAL weakrefs, and update it if necessary.
+ if self.local_weakrefs.non_empty():
+ self.update_local_weakrefs()
#
# Visit all previous OLD objects. Free the ones that have not been
# visited above, and reset GCFLAG_VISITED on the others.
@@ -253,6 +249,9 @@
self.copied_local_objects.append(localobj)
return localobj
+ def fresh_new_weakref(self, obj):
+ self.local_weakrefs.append(obj)
+
# ------------------------------------------------------------
def _promote_locals_to_globals(self):
@@ -275,12 +274,14 @@
# free the old unused local objects still allocated in the
# StmGCThreadLocalAllocator
- self.sharedarea_tls.clear()
+ self.sharedarea_tls.free_and_clear()
# free the local copies. Note that commonly, they are leftovers
# from the previous transaction running in this thread. The C code
# has just copied them over the corresponding GLOBAL objects at the
# very end of that transaction.
self._free_and_clear_list(self.copied_local_objects)
+ # forget the local weakrefs.
+ self.local_weakrefs.clear()
def _free_and_clear_list(self, lst):
while lst.non_empty():
@@ -302,6 +303,33 @@
def _trace_drag_out1(self, root):
self._trace_drag_out(root, None)
+ @always_inline
+ def categorize_object(self, obj, can_be_in_nursery):
+ """Return the current surviving state of the object:
+ 0: not marked as surviving, so far
+ 1: survives and does not move
+ 2: survives, but moves to 'hdr.version'
+ """
+ hdr = self.gc.header(obj)
+ flag_combination = hdr.tid & (GCFLAG_GLOBAL |
+ GCFLAG_WAS_COPIED |
+ GCFLAG_VISITED)
+ if flag_combination == 0:
+ return 0 # not marked as surviving, so far
+
+ if flag_combination == self.detect_flag_combination:
+ # At a normal time, self.detect_flag_combination is -1
+ # and this case is never seen. At end of transactions,
+ # detect_flag_combination is GCFLAG_WAS_COPIED|GCFLAG_VISITED.
+ # This case is to force pointers to the LOCAL copy to be
+ # replaced with pointers to the GLOBAL copy.
+ return 2
+
+ if can_be_in_nursery and self.is_in_nursery(obj):
+ return 2
+ else:
+ return 1
+
def _trace_drag_out(self, root, ignored):
"""Trace callback: 'root' is the address of some pointer. If that
pointer points to a YOUNG object, allocate an OLD copy of it and
@@ -317,18 +345,11 @@
if not self.is_in_nursery(obj):
# we ignore both GLOBAL objects and objects which have already
# been VISITED
- flag_combination = hdr.tid & (GCFLAG_GLOBAL |
- GCFLAG_WAS_COPIED |
- GCFLAG_VISITED)
- if flag_combination == 0:
+ cat = self.categorize_object(obj, can_be_in_nursery=False)
+ if cat == 0:
hdr.tid |= GCFLAG_VISITED
self.pending.append(obj)
- elif flag_combination == self.detect_flag_combination:
- # At a normal time, self.detect_flag_combination is -1
- # and this case is never seen. At end of transactions,
- # detect_flag_combination is GCFLAG_WAS_COPIED|GCFLAG_VISITED.
- # Replace references to the local copy with references
- # to the global copy
+ elif cat == 2:
root.address[0] = hdr.version
return
#
@@ -437,6 +458,34 @@
self.trace_and_drag_out_of_nursery(obj)
self.pending.delete()
+ def update_local_weakrefs(self):
+ old = self.local_weakrefs
+ new = self.AddressStack()
+ while old.non_empty():
+ obj = old.pop()
+ hdr = self.gc.header(obj)
+ if hdr.tid & GCFLAG_VISITED == 0:
+ continue # weakref itself dies
+ #
+ if self.is_in_nursery(obj):
+ obj = hdr.version
+ hdr = self.gc.header(obj)
+ offset = self.gc.weakpointer_offset(self.gc.get_type_id(obj))
+ pointing_to = (obj + offset).address[0]
+ cat = self.categorize_object(pointing_to, can_be_in_nursery=True)
+ if cat == 0:
+ # the weakref points to a dying object; no need to rememeber it
+ (obj + offset).address[0] = llmemory.NULL
+ else:
+ # the weakref points to an object that stays alive
+ if cat == 2:
+ pointing_hdr = self.gc.header(pointing_to)
+ (obj + offset).address[0] = pointing_hdr.version
+ new.append(obj) # stays alive
+ #
+ self.local_weakrefs = new
+ old.delete()
+
def mass_free_old_local(self, previous_sharedarea_tls):
obj = previous_sharedarea_tls.chained_list
previous_sharedarea_tls.delete()
diff --git a/pypy/rpython/memory/gc/test/test_stmgc.py b/pypy/rpython/memory/gc/test/test_stmgc.py
--- a/pypy/rpython/memory/gc/test/test_stmgc.py
+++ b/pypy/rpython/memory/gc/test/test_stmgc.py
@@ -582,7 +582,7 @@
twr1.wr = wr1
self.gc.commit_transaction()
wr2 = twr1.wr # twr1 is a root, so not copied yet
- assert wr2 and wr2 != wr1
+ assert wr2 and wr2._obj0 != wr1._obj0
assert wr2.wadr == s2_adr # survives
def test_weakref_to_local_dying(self):
@@ -596,7 +596,7 @@
twr1.wr = wr1
self.gc.commit_transaction()
wr2 = twr1.wr # twr1 is a root, so not copied yet
- assert wr2 and wr2 != wr1
+ assert wr2 and wr2._obj0 != wr1._obj0
assert wr2.wadr == llmemory.NULL # dies
def test_weakref_to_local_surviving(self):
@@ -615,8 +615,8 @@
t2.a = 4242
self.gc.commit_transaction()
wr2 = twr1.wr # twr1 is a root, so not copied yet
- assert wr2 and wr2 != wr1
- assert wr2.wadr and wr2.wadr != t2_adr # survives
+ assert wr2 and wr2._obj0 != wr1._obj0
+ assert wr2.wadr and wr2.wadr.ptr._obj0 != t2_adr.ptr._obj0 # survives
s2 = llmemory.cast_adr_to_ptr(wr2.wadr, lltype.Ptr(S))
assert s2.a == 4242
assert s2 == tr1.s1 # tr1 is a root, so not copied yet
More information about the pypy-commit
mailing list