[pypy-svn] r47357 - in pypy/dist/pypy/rpython: . lltypesystem memory memory/test
cfbolz at codespeak.net
cfbolz at codespeak.net
Tue Oct 9 18:31:53 CEST 2007
Author: cfbolz
Date: Tue Oct 9 18:31:52 2007
New Revision: 47357
Modified:
pypy/dist/pypy/rpython/llinterp.py
pypy/dist/pypy/rpython/lltypesystem/llheap.py
pypy/dist/pypy/rpython/memory/gc.py
pypy/dist/pypy/rpython/memory/gcwrapper.py
pypy/dist/pypy/rpython/memory/test/test_gc.py
Log:
attempt to implement weakrefs with the semispace GC. does not work completely
yet, but some tests are passing.
Modified: pypy/dist/pypy/rpython/llinterp.py
==============================================================================
--- pypy/dist/pypy/rpython/llinterp.py (original)
+++ pypy/dist/pypy/rpython/llinterp.py Tue Oct 9 18:31:52 2007
@@ -723,10 +723,10 @@
op_weakref_deref.need_result_type = True
def op_cast_ptr_to_weakrefptr(self, obj):
- return self.heap.cast_ptr_to_weakrefptr(obj)
+ return llmemory.cast_ptr_to_weakrefptr(obj)
def op_cast_weakrefptr_to_ptr(self, PTRTYPE, obj):
- return self.heap.cast_weakrefptr_to_ptr(PTRTYPE, obj)
+ return llmemory.cast_weakrefptr_to_ptr(PTRTYPE, obj)
op_cast_weakrefptr_to_ptr.need_result_type = True
def op_gc__collect(self):
@@ -1236,12 +1236,26 @@
if index != 0:
raise IndexError("address of local vars only support [0] indexing")
p = self.frame.getval(self.v)
- return llmemory.cast_ptr_to_adr(p)
+ result = llmemory.cast_ptr_to_adr(p)
+ # the GC should never see instances of _gctransformed_wref
+ result = self.unwrap_possible_weakref(result)
+ return result
def __setitem__(self, index, newvalue):
if index != 0:
raise IndexError("address of local vars only support [0] indexing")
- p = llmemory.cast_adr_to_ptr(newvalue, self.v.concretetype)
+ if self.v.concretetype == llmemory.WeakRefPtr:
+ # fish some more
+ assert isinstance(newvalue, llmemory.fakeaddress)
+ p = llmemory.cast_ptr_to_weakrefptr(newvalue.ptr)
+ else:
+ p = llmemory.cast_adr_to_ptr(newvalue, self.v.concretetype)
self.frame.setvar(self.v, p)
+ def unwrap_possible_weakref(self, addr):
+ # fish fish fish
+ if isinstance(addr.ptr._obj, llmemory._gctransformed_wref):
+ return llmemory.fakeaddress(addr.ptr._obj._ptr)
+ return addr
+
# by default we route all logging messages to nothingness
# e.g. tests can then switch on logging to get more help
Modified: pypy/dist/pypy/rpython/lltypesystem/llheap.py
==============================================================================
--- pypy/dist/pypy/rpython/lltypesystem/llheap.py (original)
+++ pypy/dist/pypy/rpython/lltypesystem/llheap.py Tue Oct 9 18:31:52 2007
@@ -4,8 +4,7 @@
from pypy.rpython.lltypesystem.llmemory import raw_malloc, raw_free
from pypy.rpython.lltypesystem.llmemory import raw_memclear, raw_memcopy
from pypy.rpython.lltypesystem.llmemory import raw_malloc_usage, \
- weakref_create, weakref_deref, cast_weakrefptr_to_ptr, \
- cast_ptr_to_weakrefptr
+ weakref_create, weakref_deref
setfield = setattr
from operator import setitem as setarrayitem
Modified: pypy/dist/pypy/rpython/memory/gc.py
==============================================================================
--- pypy/dist/pypy/rpython/memory/gc.py (original)
+++ pypy/dist/pypy/rpython/memory/gc.py Tue Oct 9 18:31:52 2007
@@ -56,7 +56,14 @@
"""
size = self.fixed_size(typeid)
needs_finalizer = bool(self.getfinalizer(typeid))
- contains_weakptr = self.weakpointer_offset(typeid) != -1
+ weakptr_offset = self.weakpointer_offset(typeid)
+ #XXX cannot compare weakptr_offset with -1
+ #contains_weakptr = weakpointer_offset. != -1
+ if isinstance(weakptr_offset, int):
+ assert weakptr_offset == -1
+ contains_weakptr = False
+ else:
+ contains_weakptr = True
assert not (needs_finalizer and contains_weakptr)
if self.is_varsize(typeid):
assert not contains_weakptr
@@ -966,11 +973,10 @@
self.free = self.tospace
self.objects_with_finalizers = self.AddressLinkedList()
self.run_finalizers = self.AddressLinkedList()
+ self.objects_with_weakrefs = self.AddressLinkedList()
def malloc_fixedsize(self, typeid, size, can_collect, has_finalizer=False,
contains_weakptr=False):
- if contains_weakptr:
- raise NotImplementedError("weakptr in SemiSpaceGC")
size_gc_header = self.gcheaderbuilder.size_gc_header
totalsize = size_gc_header + size
if raw_malloc_usage(totalsize) > self.top_of_space - self.free:
@@ -987,12 +993,12 @@
self.free += totalsize
if has_finalizer:
self.objects_with_finalizers.append(result + size_gc_header)
+ if contains_weakptr:
+ self.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,
can_collect, has_finalizer=False):
- if has_finalizer:
- raise NotImplementedError("finalizers in SemiSpaceGC")
size_gc_header = self.gcheaderbuilder.size_gc_header
nonvarsize = size_gc_header + size
try:
@@ -1037,6 +1043,25 @@
root.address[0] = self.copy(root.address[0])
free_non_gc_object(roots)
scan = self.scan_copied(scan)
+ # walk over list of objects that contain weakrefs
+ # if the object it references survives and invalidate it otherwise
+ new_with_weakref = self.AddressLinkedList()
+ while self.objects_with_weakrefs.non_empty():
+ obj = self.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 pointing_to:
+ if self.is_forwarded(pointing_to):
+ (obj + offset).address[0] = self.get_forwarding_address(
+ pointing_to)
+ else:
+ (obj + offset).address[0] = NULL
+ new_with_weakref.append(obj)
+ self.objects_with_weakrefs.delete()
+ self.objects_with_weakrefs = new_with_weakref
# walk over list of objects with finalizers
# if it is not copied, add it to the list of to-be-called finalizers
# and copy it, to me make the finalizer runnable
Modified: pypy/dist/pypy/rpython/memory/gcwrapper.py
==============================================================================
--- pypy/dist/pypy/rpython/memory/gcwrapper.py (original)
+++ pypy/dist/pypy/rpython/memory/gcwrapper.py Tue Oct 9 18:31:52 2007
@@ -67,6 +67,17 @@
def collect(self):
self.gc.collect()
+ def weakref_create(self, obj):
+ type_id = self.get_type_id(gctypelayout.WEAKREF)
+ addr = self.gc.malloc(type_id, None, zero=False)
+ result = llmemory.cast_adr_to_ptr(addr, gctypelayout.WEAKREFPTR)
+ result.weakptr = llmemory.cast_ptr_to_adr(obj)
+ return llmemory.cast_ptr_to_weakrefptr(result)
+
+ def weakref_deref(self, PTRTYPE, obj):
+ addr = gctypelayout.ll_weakref_deref(obj)
+ return llmemory.cast_adr_to_ptr(addr, PTRTYPE)
+
# ____________________________________________________________
@@ -89,11 +100,15 @@
assert not type_contains_pyobjs(TYPE), "not implemented"
def ll_finalizer(addr):
+ old_active_frame = self.llinterp.active_frame
try:
v = llmemory.cast_adr_to_ptr(addr, DESTR_ARG)
self.llinterp.eval_graph(destrgraph, [v])
except llinterp.LLException:
- print "a destructor raised an exception, ignoring it"
+ raise RuntimeError(
+ "a finalizer raised an exception, shouldn't happen")
+ finally:
+ self.llinterp.active_frame = old_active_frame
return ll_finalizer
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 Tue Oct 9 18:31:52 2007
@@ -183,6 +183,46 @@
res = self.interpret(f, [5])
assert 160 <= res <= 165
+ def test_weakref(self):
+ import weakref, gc
+ class A(object):
+ pass
+ def g():
+ a = A()
+ return weakref.ref(a)
+ def f():
+ a = A()
+ ref = weakref.ref(a)
+ result = ref() is a
+ ref = g()
+ llop.gc__collect(lltype.Void)
+ result = result and (ref() is None)
+ # check that a further collection is fine
+ llop.gc__collect(lltype.Void)
+ result = result and (ref() is None)
+ return result
+ res = self.interpret(f, [])
+ assert res
+
+ def test_weakref_to_object_with_finalizer(self):
+ import weakref, gc
+ class A(object):
+ count = 0
+ a = A()
+ class B(object):
+ def __del__(self):
+ a.count += 1
+ def g():
+ b = B()
+ return weakref.ref(b)
+ def f():
+ ref = g()
+ llop.gc__collect(lltype.Void)
+ llop.gc__collect(lltype.Void)
+ result = a.count == 1 and (ref() is None)
+ return result
+ res = self.interpret(f, [])
+ assert res
class TestMarkSweepGC(GCTest):
from pypy.rpython.memory.gc import MarkSweepGC as GCClass
More information about the Pypy-commit
mailing list