[pypy-svn] r47611 - in pypy/dist/pypy/rpython/memory: gc test
arigo at codespeak.net
arigo at codespeak.net
Fri Oct 19 22:01:26 CEST 2007
Author: arigo
Date: Fri Oct 19 22:01:25 2007
New Revision: 47611
Modified:
pypy/dist/pypy/rpython/memory/gc/generation.py
pypy/dist/pypy/rpython/memory/test/test_gc.py
pypy/dist/pypy/rpython/memory/test/test_transformed_gc.py
Log:
(cfbolz, arigo) Fix weakrefs for the GenerationGC.
Modified: pypy/dist/pypy/rpython/memory/gc/generation.py
==============================================================================
--- pypy/dist/pypy/rpython/memory/gc/generation.py (original)
+++ pypy/dist/pypy/rpython/memory/gc/generation.py Fri Oct 19 22:01:25 2007
@@ -34,6 +34,7 @@
self.reset_nursery()
self.old_objects_pointing_to_young = nonnull_endmarker
# ^^^ the head of a linked list inside the old objects space
+ self.young_objects_with_weakrefs = self.AddressLinkedList()
def reset_nursery(self):
self.nursery = llmemory.NULL
@@ -45,8 +46,9 @@
def malloc_fixedsize(self, typeid, size, can_collect, has_finalizer=False,
contains_weakptr=False):
- if (has_finalizer or contains_weakptr or not can_collect or
+ if (has_finalizer or not can_collect or
raw_malloc_usage(size) >= self.nursery_size // 2):
+ debug_assert(not contains_weakptr, "wrong case for mallocing weakref")
# "non-simple" case or object too big: don't use the nursery
return SemiSpaceGC.malloc_fixedsize(self, typeid, size,
can_collect, has_finalizer,
@@ -59,6 +61,8 @@
llarena.arena_reserve(result, totalsize)
self.init_gc_object(result, typeid)
self.nursery_free = result + totalsize
+ if contains_weakptr:
+ self.young_objects_with_weakrefs.append(result + size_gc_header)
return llmemory.cast_adr_to_ptr(result+size_gc_header, llmemory.GCREF)
def malloc_varsize(self, typeid, length, size, itemsize, offset_to_length,
@@ -86,6 +90,7 @@
def semispace_collect(self, size_changing=False):
self.reset_forwarding() # we are doing a full collection anyway
+ self.weakrefs_grow_older()
self.reset_nursery()
SemiSpaceGC.semispace_collect(self, size_changing)
@@ -97,6 +102,11 @@
hdr.forw = llmemory.NULL
self.old_objects_pointing_to_young = nonnull_endmarker
+ def weakrefs_grow_older(self):
+ while self.young_objects_with_weakrefs.non_empty():
+ obj = self.young_objects_with_weakrefs.pop()
+ self.objects_with_weakrefs.append(obj)
+
def collect_nursery(self):
if self.nursery_size > self.top_of_space - self.free:
# the semispace is running out, do a full collect
@@ -109,6 +119,8 @@
self.collect_oldrefs_to_nursery()
self.collect_roots_in_nursery()
self.scan_objects_just_copied_out_of_nursery(scan)
+ if self.young_objects_with_weakrefs.non_empty():
+ self.invalidate_young_weakrefs()
self.notify_objects_just_moved()
# mark the nursery as free and fill it with zeroes again
llarena.arena_reset(self.nursery, self.nursery_size, True)
@@ -185,6 +197,25 @@
j += 1
i += 1
+ def invalidate_young_weakrefs(self):
+ # walk over the list of objects that contain weakrefs and are in the
+ # nursery. if the object it references survives then update the
+ # weakref; otherwise invalidate the weakref
+ while self.young_objects_with_weakrefs.non_empty():
+ obj = self.young_objects_with_weakrefs.pop()
+ if not self.is_forwarded(obj):
+ continue # weakref itself dies
+ obj = self.get_forwarding_address(obj)
+ offset = self.weakpointer_offset(self.header(obj).typeid)
+ pointing_to = (obj + offset).address[0]
+ if self.is_in_nursery(pointing_to):
+ if self.is_forwarded(pointing_to):
+ (obj + offset).address[0] = self.get_forwarding_address(
+ pointing_to)
+ self.objects_with_weakrefs.append(obj)
+ else:
+ (obj + offset).address[0] = NULL
+
def write_barrier(self, addr, addr_to, addr_struct):
if not self.is_in_nursery(addr_struct) and self.is_in_nursery(addr):
oldhdr = self.header(addr_struct)
Modified: pypy/dist/pypy/rpython/memory/test/test_gc.py
==============================================================================
--- pypy/dist/pypy/rpython/memory/test/test_gc.py (original)
+++ pypy/dist/pypy/rpython/memory/test/test_gc.py Fri Oct 19 22:01:25 2007
@@ -307,6 +307,25 @@
res = self.interpret(f, [500])
assert res == 1 + 500
+ def test_weakref_across_minor_collection(self):
+ import weakref
+ class A:
+ pass
+ def f(x):
+ a = A()
+ a.foo = x
+ ref = weakref.ref(a)
+ all = [None] * x
+ i = 0
+ while i < x:
+ all[i] = [i] * i
+ i += 1
+ assert ref() is a
+ llop.gc__collect(lltype.Void)
+ assert ref() is a
+ return a.foo + len(all)
+ res = self.interpret(f, [20]) # for GenerationGC, enough for a minor collection
+ assert res == 20 + 20
class TestMarkSweepGC(GCTest):
from pypy.rpython.memory.gc.marksweep import MarkSweepGC as GCClass
Modified: pypy/dist/pypy/rpython/memory/test/test_transformed_gc.py
==============================================================================
--- pypy/dist/pypy/rpython/memory/test/test_transformed_gc.py (original)
+++ pypy/dist/pypy/rpython/memory/test/test_transformed_gc.py Fri Oct 19 22:01:25 2007
@@ -736,3 +736,25 @@
GC_PARAMS = {'space_size': 2048,
'nursery_size': 128}
root_stack_depth = 200
+
+ def test_weakref_across_minor_collection(self):
+ import weakref
+ class A:
+ pass
+ def f():
+ x = 20 # for GenerationGC, enough for a minor collection
+ a = A()
+ a.foo = x
+ ref = weakref.ref(a)
+ all = [None] * x
+ i = 0
+ while i < x:
+ all[i] = [i] * i
+ i += 1
+ assert ref() is a
+ llop.gc__collect(lltype.Void)
+ assert ref() is a
+ return a.foo + len(all)
+ run = self.runner(f)
+ res = run([])
+ assert res == 20 + 20
More information about the Pypy-commit
mailing list