Author: Armin Rigo <[email protected]>
Branch: gc-del
Changeset: r62804:0c3d7f55af78
Date: 2013-03-26 13:52 +0100
http://bitbucket.org/pypy/pypy/changeset/0c3d7f55af78/
Log: Found out a simpler solution.
diff --git a/rpython/memory/gc/minimark.py b/rpython/memory/gc/minimark.py
--- a/rpython/memory/gc/minimark.py
+++ b/rpython/memory/gc/minimark.py
@@ -1243,7 +1243,6 @@
#
# Before everything else, remove from 'old_objects_pointing_to_young'
# the young arrays.
- self.remember_young_rawmalloced_visited = None
if self.young_rawmalloced_objects:
self.remove_young_arrays_from_old_objects_pointing_to_young()
#
@@ -1370,6 +1369,7 @@
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.
+ self.record_duplicates = False
oldlist = self.old_objects_pointing_to_young
while True:
if oldlist.non_empty():
@@ -1402,6 +1402,9 @@
# Both 'old_objects_pointing_to_young' and
# 'old_objects_with_cards_set' are now empty: done
break
+ #
+ if not we_are_translated():
+ del self.record_duplicates
def trace_and_drag_out_of_nursery(self, obj):
@@ -1454,7 +1457,13 @@
#
# 'obj' was already forwarded. Change the original reference
# to point to its forwarding address, and we're done.
- root.address[0] = self.get_forwarding_address(obj)
+ newobj = self.get_forwarding_address(obj)
+ root.address[0] = newobj
+ #
+ # Avoid the following useless append(), unless we are tracing
+ # from dying objects with finalizers
+ if self.record_duplicates:
+ self.old_objects_pointing_to_young.append(newobj)
return
#
else:
@@ -1493,7 +1502,7 @@
# We will fix such references to point to the copy of the young
# objects when we walk 'old_objects_pointing_to_young'.
self.old_objects_pointing_to_young.append(newobj)
- debug_print("adding", newobj)
+ #debug_print("adding", newobj)
_trace_drag_out._always_inline_ = True
def _visit_young_rawmalloced_object(self, obj):
@@ -1523,10 +1532,6 @@
added_somewhere = True
#
ll_assert(added_somewhere, "wrong flag combination on young array")
- #
- # If 'remember_young_rawmalloced_visited', record it there as well
- if self.remember_young_rawmalloced_visited:
- self.remember_young_rawmalloced_visited.append(obj)
def _malloc_out_of_nursery(self, totalsize):
@@ -1927,75 +1932,88 @@
objects with finalizers. As these survive for a bit longer,
we also need to copy them out of the nursery. The tricky part
here is to enqueue them in topological order, if possible.
-
- This is done as three steps: first we find which objects are
- not reachable at all from 'outside'; then we copy them outside
- the nursery together with everything they point to; and finally
- we use on them the generic _deal_with_objects_with_finalizers().
"""
ll_assert(not self.old_objects_pointing_to_young.non_empty(),
"deal_with_young_objects_with_finalizers: "
"old_objects_pointing_to_young should be empty")
- ll_assert(not self.objects_to_trace.non_empty(),
- "objects_to_trace non empty [deal_young_finalizer]")
finalizer_funcs = self.AddressDict()
+ self.finalizers_scheduled = self.AddressStack()
+ self.record_duplicates = True
#
while self.young_objects_with_finalizers.non_empty():
func = self.young_objects_with_finalizers.pop()
obj = self.young_objects_with_finalizers.pop()
#
- survives = False
+ # The following lines move 'obj' out of the nursery and add it to
+ # 'self.old_objects_pointing_to_young' --- unless the object
+ # survive, in which case it was already seen and the following
+ # lines have no effect.
+ root = self.temp_root
+ root.address[0] = obj
+ self._trace_drag_out1(root)
+ objcopy = root.address[0]
+ #debug_print("finalizer for", obj)
+ #debug_print("object moving to", objcopy)
#
- if self.is_in_nursery(obj):
- if self.is_forwarded(obj):
- obj = self.get_forwarding_address(obj)
- survives = True
- else:
- #
- # The following lines move 'obj' out of the nursery and
- # add it to 'self.old_objects_pointing_to_young'.
- root = self.temp_root
- root.address[0] = obj
- self._trace_drag_out1(root)
- obj = root.address[0]
+ # Remember the finalizer in the dict
+ finalizer_funcs.setitem(objcopy, func)
#
- elif (bool(self.young_rawmalloced_objects) and
- self.young_rawmalloced_objects.contains(obj)):
- if self.header(obj).tid & GCFLAG_VISITED:
- survives = True
- #
- if survives:
- self.old_objects_with_finalizers.append(obj)
- self.old_objects_with_finalizers.append(func)
+ # Now follow all the refs
+ self._follow_references_from_young_object_with_finalizer()
+ #
+ if not we_are_translated():
+ del self.record_duplicates
+ #
+ # Copy the objects scheduled into 'run_finalizers_queue', in
+ # reverse order.
+ while self.finalizers_scheduled.non_empty():
+ obj = self.finalizers_scheduled.pop()
+ func = finalizer_funcs.get(obj)
+ ll_assert(func != NULL, "lost finalizer [1]")
+ self.run_finalizers_queue.append(obj)
+ self.run_finalizers_funcs.append(func)
+ finalizer_funcs.setitem(obj, NULL)
+ self.finalizers_scheduled.delete()
+ #
+ # The non-NULL entries remaining in 'finalizer_funcs' correspond
+ # to objects that survived, because they have not been traced by
+ # this function but already before.
+ finalizer_funcs.foreach(self._move_to_old_finalizer,
+ self.old_objects_with_finalizers)
+ finalizer_funcs.delete()
+
+ def _follow_references_from_young_object_with_finalizer(self):
+ pending = self.old_objects_pointing_to_young
+ while pending.non_empty():
+ assert not self.old_objects_with_cards_set.non_empty(), "XXX"
+ obj = pending.pop()
+ #debug_print("popping", obj)
+ if obj:
+ #
+ if self.header(obj).tid & GCFLAG_HAS_FINALIZER:
+ self.header(obj).tid &= ~GCFLAG_HAS_FINALIZER
+ #debug_print("this object has a finalizer")
+ pending.append(obj)
+ pending.append(NULL) # marker
+ #
+ if self.header(obj).tid & GCFLAG_TRACK_YOUNG_PTRS == 0:
+ self.header(obj).tid |= GCFLAG_TRACK_YOUNG_PTRS
+ self.trace_and_drag_out_of_nursery(obj)
+ #
else:
- # Remember the finalizer in the dict
- finalizer_funcs.setitem(obj, func)
- self.objects_to_trace.append(obj)
- #
- # Follow all refs
- self.remember_young_rawmalloced_visited = self.AddressStack()
- self.collect_oldrefs_to_nursery()
- #
- # Reset GCFLAG_VISITED on young rawmalloced objects added just before
- self.remember_young_rawmalloced_visited.foreach(
- self._remove_gcflag_visited, None)
- self.remember_young_rawmalloced_visited.delete()
- self.remember_young_rawmalloced_visited = None
- #
- # At this point all objects reachable from 'finalizer_funcs'
- # are disconnected from the rest of the world, and none has
- # the GCFLAG_VISITED set. Use the generic method.
- self._deal_with_objects_with_finalizers(finalizer_funcs)
+ # seen a NULL marker
+ obj = pending.pop()
+ #debug_print("adding to scheduled", obj)
+ self.finalizers_scheduled.append(obj)
+ @staticmethod
+ def _move_to_old_finalizer(obj, finalizer, old_objects_with_finalizers):
+ if finalizer != NULL:
+ old_objects_with_finalizers.append(obj)
+ old_objects_with_finalizers.append(finalizer)
- def _remove_gcflag_visited(self, obj, ignored):
- # 'obj' has GCFLAG_VISITED; remove it.
- ll_assert(self.header(obj).tid & GCFLAG_VISITED != 0,
- "remove_gcflag_visited: not?")
- self.header(obj).tid &= ~GCFLAG_VISITED
-
- def _deal_with_objects_with_finalizers(self, finalizer_funcs):
+ def deal_with_old_objects_with_finalizers(self):
# Walk over list of objects with finalizers.
# If it is not surviving, add it to the list of to-be-called
# finalizers and make it survive, to make the finalizer runnable.
@@ -2003,7 +2021,28 @@
# CPython does. The details of this algorithm are in
# pypy/doc/discussion/finalizer-order.txt.
#
- xxxxxxxxxxx
+ ll_assert(not self.objects_to_trace.non_empty(),
+ "objects_to_trace non empty [deal_old_finalizer]")
+ #
+ old_objs = self.old_objects_with_finalizers
+ self.old_objects_with_finalizers = self.AddressStack()
+ finalizer_funcs = self.AddressDict()
+ #
+ while old_objs.non_empty():
+ func = old_objs.pop()
+ obj = old_objs.pop()
+ ll_assert(bool(self.header(obj).tid & GCFLAG_HAS_FINALIZER),
+ "lost GCFLAG_HAS_FINALIZER")
+ #
+ if self.header(obj).tid & GCFLAG_VISITED:
+ # surviving
+ self.old_objects_with_finalizers.append(obj)
+ self.old_objects_with_finalizers.append(func)
+ #
+ else:
+ # dying
+ self.objects_to_trace.append(obj)
+ finalizer_funcs.setitem(obj, func)
#
# Now follow all the refs
finalizers_scheduled = self.AddressStack()
@@ -2037,33 +2076,6 @@
old_objs.delete()
- def deal_with_old_objects_with_finalizers(self):
- ll_assert(not self.objects_to_trace.non_empty(),
- "objects_to_trace non empty [deal_old_finalizer]")
- #
- old_objs = self.old_objects_with_finalizers
- self.old_objects_with_finalizers = self.AddressStack()
- finalizer_funcs = self.AddressDict()
- #
- while old_objs.non_empty():
- func = old_objs.pop()
- obj = old_objs.pop()
- ll_assert(bool(self.header(obj).tid & GCFLAG_HAS_FINALIZER),
- "lost GCFLAG_HAS_FINALIZER")
- #
- if self.header(obj).tid & GCFLAG_VISITED:
- # surviving
- self.old_objects_with_finalizers.append(obj)
- self.old_objects_with_finalizers.append(func)
- #
- else:
- # dying
- self.objects_to_trace.append(obj)
- finalizer_funcs.setitem(obj, func)
- #
- self._deal_with_objects_with_finalizers(finalizer_funcs)
-
-
# ----------
# Weakrefs
diff --git a/rpython/memory/test/snippet.py b/rpython/memory/test/snippet.py
--- a/rpython/memory/test/snippet.py
+++ b/rpython/memory/test/snippet.py
@@ -12,7 +12,6 @@
def definestr_finalizer_order(cls):
import random
x = random.randrange(0,10000)
- x = 2696
print "R"*1000
print x
print '-'*60
@@ -20,7 +19,7 @@
from rpython.tool.algo import graphlib
cls.finalizer_order_examples = examples = []
- if 1: # cls.large_tests_ok:
+ if cls.large_tests_ok:
letters = 'abcdefghijklmnopqrstuvwxyz'
COUNT = 20
else:
@@ -77,7 +76,7 @@
vertices[c].refs.append(vertices[d])
def f(_):
- i = 2
+ i = 0
while i < len(examples):
debug_print("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<")
input, components, strict = examples[i]
diff --git a/rpython/memory/test/test_gc.py b/rpython/memory/test/test_gc.py
--- a/rpython/memory/test/test_gc.py
+++ b/rpython/memory/test/test_gc.py
@@ -1061,7 +1061,7 @@
class TestMiniMarkGCLargeNursery(TestMiniMarkGC):
GC_PARAMS = {'nursery_size': 16384*WORD}
- #def setup_class(cls):
- # py.test.skip("takes a lot of extra time to run")
- #def teardown_class(cls):
- # pass
+ def setup_class(cls):
+ py.test.skip("takes a lot of extra time to run")
+ def teardown_class(cls):
+ pass
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit