[pypy-svn] r47434 - in pypy/dist/pypy: rpython rpython/lltypesystem rpython/memory rpython/memory/gc rpython/memory/gctransform rpython/memory/test translator/c translator/c/src translator/c/test

arigo at codespeak.net arigo at codespeak.net
Sat Oct 13 22:35:00 CEST 2007


Author: arigo
Date: Sat Oct 13 22:34:59 2007
New Revision: 47434

Modified:
   pypy/dist/pypy/rpython/llinterp.py
   pypy/dist/pypy/rpython/lltypesystem/llheap.py
   pypy/dist/pypy/rpython/lltypesystem/llmemory.py
   pypy/dist/pypy/rpython/lltypesystem/lloperation.py
   pypy/dist/pypy/rpython/lltypesystem/lltype.py
   pypy/dist/pypy/rpython/memory/gc/base.py
   pypy/dist/pypy/rpython/memory/gc/semispace.py
   pypy/dist/pypy/rpython/memory/gctransform/boehm.py
   pypy/dist/pypy/rpython/memory/gctransform/framework.py
   pypy/dist/pypy/rpython/memory/gctransform/transform.py
   pypy/dist/pypy/rpython/memory/gcwrapper.py
   pypy/dist/pypy/rpython/memory/test/test_gc.py
   pypy/dist/pypy/rpython/memory/test/test_transformed_gc.py
   pypy/dist/pypy/rpython/rmodel.py
   pypy/dist/pypy/translator/c/gc.py
   pypy/dist/pypy/translator/c/src/address.h
   pypy/dist/pypy/translator/c/test/test_boehm.py
Log:
Fix the id() in the presence of a moving GC.  This first attempt is
based on a veeeery slow implementation.

M    pypy/translator/c/test/test_boehm.py

       In Boehm the RPython-level id() no longer keeps
       the object alive

M    pypy/translator/c/gc.py
M    pypy/translator/c/src/address.h

       Delete old code

M    pypy/rpython/memory/test/test_gc.py
M    pypy/rpython/memory/test/test_transformed_gc.py

       Add tests for id()

M    pypy/rpython/lltypesystem/lloperation.py
M    pypy/rpython/lltypesystem/llheap.py
M    pypy/rpython/memory/gcwrapper.py
M    pypy/rpython/llinterp.py
M    pypy/rpython/rmodel.py

       Add 'gc_id' as an lloperation

M    pypy/rpython/memory/gctransform/transform.py
M    pypy/rpython/memory/gctransform/framework.py
M    pypy/rpython/memory/gctransform/boehm.py

       Transform this 'gc_id' in the gctransformer

M    pypy/rpython/memory/gc/semispace.py
M    pypy/rpython/memory/gc/base.py

       Generic but inefficient implementation of id()
       for all moving GCs

M    pypy/rpython/lltypesystem/llmemory.py
M    pypy/rpython/lltypesystem/lltype.py

       Add more pointer casts when required.
       Check for freed objects in _wref.


Modified: pypy/dist/pypy/rpython/llinterp.py
==============================================================================
--- pypy/dist/pypy/rpython/llinterp.py	(original)
+++ pypy/dist/pypy/rpython/llinterp.py	Sat Oct 13 22:34:59 2007
@@ -778,6 +778,9 @@
         self.setvar(v_ptr, p)
     op_gc_reload_possibly_moved.specialform = True
 
+    def op_gc_id(self, v_ptr):
+        return self.heap.gc_id(v_ptr)
+
     def op_gc_set_max_heap_size(self, maxsize):
         raise NotImplementedError("gc_set_max_heap_size")
 

Modified: pypy/dist/pypy/rpython/lltypesystem/llheap.py
==============================================================================
--- pypy/dist/pypy/rpython/lltypesystem/llheap.py	(original)
+++ pypy/dist/pypy/rpython/lltypesystem/llheap.py	Sat Oct 13 22:34:59 2007
@@ -14,3 +14,5 @@
     assert typeOf(newvalue) == INNERTYPE
     # xxx access the address object's ref() directly for performance
     inneraddr.ref()[0] = newvalue
+
+from pypy.rpython.lltypesystem.lltype import cast_ptr_to_int as gc_id

Modified: pypy/dist/pypy/rpython/lltypesystem/llmemory.py
==============================================================================
--- pypy/dist/pypy/rpython/lltypesystem/llmemory.py	(original)
+++ pypy/dist/pypy/rpython/lltypesystem/llmemory.py	Sat Oct 13 22:34:59 2007
@@ -366,45 +366,12 @@
             raise NullAddressError
         return self.ptr
 
-##    def get(self):
-##        return self.ref().get()
-
-##    def set(self, value):
-##        self.ref().set(value)
-
     def _cast_to_ptr(self, EXPECTED_TYPE):
         if self:
-            PTRTYPE = lltype.typeOf(self.ptr)
-            if (isinstance(EXPECTED_TYPE.TO, lltype.OpaqueType) or
-                isinstance(PTRTYPE.TO, lltype.OpaqueType)):
-                return lltype.cast_opaque_ptr(EXPECTED_TYPE, self.ptr)
-            else:
-                # regular case
-                return lltype.cast_pointer(EXPECTED_TYPE, self.ptr)
+            return cast_any_ptr(EXPECTED_TYPE, self.ptr)
         else:
             return lltype.nullptr(EXPECTED_TYPE.TO)
 
-##        if (isinstance(ref, _arrayitemref) and
-##            isinstance(EXPECTED_TYPE.TO, lltype.FixedSizeArray) and
-##            ref.type() == EXPECTED_TYPE.TO.OF):
-##            # special case that requires direct_arrayitems
-##            p_items = lltype.direct_arrayitems(ref.array)
-##            return lltype.direct_ptradd(p_items, ref.index)
-##        elif (isinstance(ref, _structfieldref) and
-##              isinstance(EXPECTED_TYPE.TO, lltype.FixedSizeArray) and
-##              ref.type() == EXPECTED_TYPE.TO.OF):
-##            # special case that requires direct_fieldptr
-##            return lltype.direct_fieldptr(ref.struct,
-##                                          ref.fieldname)
-##        else:
-##            result = ref.get()
-##            if (isinstance(EXPECTED_TYPE.TO, lltype.OpaqueType) or
-##                isinstance(lltype.typeOf(result).TO, lltype.OpaqueType)):
-##                return lltype.cast_opaque_ptr(EXPECTED_TYPE, result)
-##            else:
-##                # regular case
-##                return lltype.cast_pointer(EXPECTED_TYPE, result)
-
     def _cast_to_int(self):
         if self:
             return self.ptr._cast_to_int()
@@ -538,7 +505,7 @@
     if p is None:
         return lltype.nullptr(PTRTYPE.TO)
     else:
-        return lltype.cast_pointer(PTRTYPE, p)
+        return cast_any_ptr(PTRTYPE, p)
 
 class _wref(lltype._container):
     _gckind = 'gc'
@@ -553,7 +520,9 @@
 
     def _dereference(self):
         obj = self._obref()
-        if obj is None:
+        # in combination with a GC like the SemiSpace, the 'obj' can be
+        # still alive in the CPython sense but freed by the arena logic.
+        if obj is None or obj._was_freed():
             return None
         else:
             return obj._as_ptr()
@@ -584,7 +553,8 @@
     assert lltype.typeOf(pwref) == WeakRefPtr
     if pwref:
         assert isinstance(pwref._obj, _gctransformed_wref)
-        assert PTRTYPE == lltype.typeOf(pwref._obj._ptr)
+        if PTRTYPE is not None:
+            assert PTRTYPE == lltype.typeOf(pwref._obj._ptr)
         return pwref._obj._ptr
     else:
         return lltype.nullptr(PTRTYPE.TO)
@@ -636,3 +606,20 @@
     assert lltype.typeOf(source) == Address
     assert lltype.typeOf(dest)   == Address
     size.raw_memcopy(source, dest)
+
+def cast_any_ptr(EXPECTED_TYPE, ptr):
+    # this is a generalization of the various cast_xxx_ptr() functions.
+    PTRTYPE = lltype.typeOf(ptr)
+    if PTRTYPE == EXPECTED_TYPE:
+        return ptr
+    elif EXPECTED_TYPE == WeakRefPtr:
+        return cast_ptr_to_weakrefptr(ptr)
+    elif PTRTYPE == WeakRefPtr:
+        ptr = cast_weakrefptr_to_ptr(None, ptr)
+        return cast_any_ptr(EXPECTED_TYPE, ptr)
+    elif (isinstance(EXPECTED_TYPE.TO, lltype.OpaqueType) or
+        isinstance(PTRTYPE.TO, lltype.OpaqueType)):
+        return lltype.cast_opaque_ptr(EXPECTED_TYPE, ptr)
+    else:
+        # regular case
+        return lltype.cast_pointer(EXPECTED_TYPE, ptr)

Modified: pypy/dist/pypy/rpython/lltypesystem/lloperation.py
==============================================================================
--- pypy/dist/pypy/rpython/lltypesystem/lloperation.py	(original)
+++ pypy/dist/pypy/rpython/lltypesystem/lloperation.py	Sat Oct 13 22:34:59 2007
@@ -389,6 +389,7 @@
     'gc_protect':           LLOp(),
     'gc_unprotect':         LLOp(),    
     'gc_reload_possibly_moved': LLOp(),
+    'gc_id':                LLOp(canraise=(MemoryError,), sideeffects=False),
     'gc_set_max_heap_size': LLOp(),
     # experimental operations in support of thread cloning, only
     # implemented by the Mark&Sweep GC

Modified: pypy/dist/pypy/rpython/lltypesystem/lltype.py
==============================================================================
--- pypy/dist/pypy/rpython/lltypesystem/lltype.py	(original)
+++ pypy/dist/pypy/rpython/lltypesystem/lltype.py	Sat Oct 13 22:34:59 2007
@@ -1278,6 +1278,8 @@
         return self
     def _getid(self):
         return id(self)
+    def _was_freed(self):
+        return False
 
 class _parentable(_container):
     _kind = "?"
@@ -1300,6 +1302,9 @@
         self._check()   # no double-frees
         self._storage = None
 
+    def _was_freed(self):
+        return self._storage is None
+
     def _setparentstructure(self, parent, parentindex):
         self._wrparent = weakref.ref(parent)
         self._parent_type = typeOf(parent)

Modified: pypy/dist/pypy/rpython/memory/gc/base.py
==============================================================================
--- pypy/dist/pypy/rpython/memory/gc/base.py	(original)
+++ pypy/dist/pypy/rpython/memory/gc/base.py	Sat Oct 13 22:34:59 2007
@@ -68,6 +68,9 @@
         # lots of cast and reverse-cast around...
         return llmemory.cast_ptr_to_adr(ref)
 
+    def id(self, ptr):
+        return lltype.cast_ptr_to_int(ptr)
+
     def x_swap_pool(self, newpool):
         return newpool
 
@@ -78,6 +81,38 @@
         raise RuntimeError("no support for x_become in the GC")
 
 
+class MovingGCBase(GCBase):
+    moving_gc = True
+
+    def __init__(self):
+        self.wr_to_objects_with_id = []
+
+    def id(self, ptr):
+        # XXX linear search! this is probably too slow to be reasonable :-(
+        # On the other hand, it punishes you for using 'id', so that's good :-)
+        # XXX this may explode if --no-translation-rweakref is specified
+        lst = self.wr_to_objects_with_id
+        i = len(lst)
+        freeentry = -1
+        while i > 0:
+            i -= 1
+            target = llmemory.weakref_deref(llmemory.GCREF, lst[i])
+            if not target:
+                freeentry = i
+            elif target == ptr:
+                break               # found
+        else:
+            # not found
+            wr = llmemory.weakref_create(ptr)
+            if freeentry == -1:
+                i = len(lst)
+                lst.append(wr)
+            else:
+                i = freeentry       # reuse the id() of a dead object
+                lst[i] = wr
+        return i + 1       # this produces id() values 1, 2, 3, 4...
+
+
 def choose_gc_from_config(config):
     """Return a (GCClass, GC_PARAMS) from the given config object.
     """
@@ -88,7 +123,7 @@
         return MarkSweepGC, GC_PARAMS
     elif config.translation.frameworkgc == "semispace":
         GC_PARAMS = {'space_size': 8*1024*1024} # XXX adjust
-        from pypy.rpython.memory.gc.marksweep import SemiSpaceGC
+        from pypy.rpython.memory.gc.semispace import SemiSpaceGC
         return SemiSpaceGC, GC_PARAMS
     else:
         raise ValueError("unknown value for frameworkgc: %r" % (

Modified: pypy/dist/pypy/rpython/memory/gc/semispace.py
==============================================================================
--- pypy/dist/pypy/rpython/memory/gc/semispace.py	(original)
+++ pypy/dist/pypy/rpython/memory/gc/semispace.py	Sat Oct 13 22:34:59 2007
@@ -7,16 +7,15 @@
 from pypy.rlib.objectmodel import free_non_gc_object, debug_assert
 from pypy.rpython.lltypesystem.lloperation import llop
 from pypy.rlib.rarithmetic import ovfcheck
-from pypy.rpython.memory.gc.base import GCBase
+from pypy.rpython.memory.gc.base import MovingGCBase
 
 
 import sys, os
 
 memoryError = MemoryError()
 
-class SemiSpaceGC(GCBase):
+class SemiSpaceGC(MovingGCBase):
     _alloc_flavor_ = "raw"
-    moving_gc = True
     inline_simple_malloc = True
 
     HDR = lltype.Struct('header', ('forw', llmemory.Address),
@@ -25,6 +24,7 @@
     def __init__(self, AddressLinkedList, space_size=4096,
                  max_space_size=sys.maxint//2+1,
                  get_roots=None):
+        MovingGCBase.__init__(self)
         self.space_size = space_size
         self.max_space_size = max_space_size
         self.get_roots = get_roots

Modified: pypy/dist/pypy/rpython/memory/gctransform/boehm.py
==============================================================================
--- pypy/dist/pypy/rpython/memory/gctransform/boehm.py	(original)
+++ pypy/dist/pypy/rpython/memory/gctransform/boehm.py	Sat Oct 13 22:34:59 2007
@@ -147,6 +147,12 @@
                            resulttype=llmemory.Address)
         hop.cast_result(v_addr)
 
+    def gct_gc_id(self, hop):
+        # this is the logic from the HIDE_POINTER macro in <gc/gc.h>
+        v_int = hop.genop('cast_ptr_to_int', [hop.spaceop.args[0]],
+                          resulttype = lltype.Signed)
+        hop.genop('int_invert', [v_int], resultvar=hop.spaceop.result)
+
 
 ########## weakrefs ##########
 # Boehm: weakref objects are small structures containing only a Boehm

Modified: pypy/dist/pypy/rpython/memory/gctransform/framework.py
==============================================================================
--- pypy/dist/pypy/rpython/memory/gctransform/framework.py	(original)
+++ pypy/dist/pypy/rpython/memory/gctransform/framework.py	Sat Oct 13 22:34:59 2007
@@ -238,6 +238,14 @@
         else:
             self.malloc_fast_ptr = self.malloc_fixedsize_ptr
 
+        if GCClass.moving_gc:
+            self.id_ptr = getfn(GCClass.id.im_func,
+                                [s_gc, s_gcref], annmodel.SomeInteger(),
+                                inline = False,
+                                minimal_transform = False)
+        else:
+            self.id_ptr = None
+
         self.statistics_ptr = getfn(GCClass.statistics.im_func,
                                     [s_gc, annmodel.SomeInteger()],
                                     annmodel.SomeInteger())
@@ -523,6 +531,18 @@
                            resulttype=llmemory.Address)
         hop.cast_result(v_addr)
 
+    def gct_gc_id(self, hop):
+        if self.id_ptr is not None:
+            self.push_roots(hop)
+            [v_ptr] = hop.spaceop.args
+            v_ptr = hop.genop("cast_opaque_ptr", [v_ptr],
+                              resulttype=llmemory.GCREF)
+            hop.genop("direct_call", [self.id_ptr, self.c_const_gc, v_ptr],
+                      resultvar=hop.spaceop.result)
+            self.pop_roots(hop)
+        else:
+            hop.rename('cast_ptr_to_int')     # works nicely for non-moving GCs
+
     def push_alive_nopyobj(self, var, llops):
         pass
 

Modified: pypy/dist/pypy/rpython/memory/gctransform/transform.py
==============================================================================
--- pypy/dist/pypy/rpython/memory/gctransform/transform.py	(original)
+++ pypy/dist/pypy/rpython/memory/gctransform/transform.py	Sat Oct 13 22:34:59 2007
@@ -325,6 +325,10 @@
     def gct_zero_gc_pointers_inside(self, hop):
         pass
 
+    def gct_gc_id(self, hop):
+        # this assumes a non-moving GC.  Moving GCs need to override this
+        hop.rename('cast_ptr_to_int')
+
 
 class MinimalGCTransformer(BaseGCTransformer):
     def __init__(self, parenttransformer):

Modified: pypy/dist/pypy/rpython/memory/gcwrapper.py
==============================================================================
--- pypy/dist/pypy/rpython/memory/gcwrapper.py	(original)
+++ pypy/dist/pypy/rpython/memory/gcwrapper.py	Sat Oct 13 22:34:59 2007
@@ -85,6 +85,10 @@
         addr = gctypelayout.ll_weakref_deref(obj)
         return llmemory.cast_adr_to_ptr(addr, PTRTYPE)
 
+    def gc_id(self, ptr):
+        ptr = lltype.cast_opaque_ptr(llmemory.GCREF, ptr)
+        return self.gc.id(ptr)
+
     # ____________________________________________________________
 
 class RootLinkedList(object):

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	Sat Oct 13 22:34:59 2007
@@ -251,6 +251,25 @@
         res = self.interpret(f, [])
         assert res
 
+    def test_id(self):
+        class A(object):
+            pass
+        a1 = A()
+        def f():
+            a2 = A()
+            a3 = A()
+            id1 = id(a1)
+            id2 = id(a2)
+            id3 = id(a3)
+            llop.gc__collect(lltype.Void)
+            error = 0
+            if id1 != id(a1): error += 1
+            if id2 != id(a2): error += 2
+            if id3 != id(a3): error += 4
+            return error
+        res = self.interpret(f, [])
+        assert res == 0
+
 
 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	Sat Oct 13 22:34:59 2007
@@ -376,6 +376,26 @@
         res = run([])
         assert res == 111111
 
+    def test_id(self):
+        class A(object):
+            pass
+        a1 = A()
+        def func():
+            a2 = A()
+            a3 = A()
+            id1 = id(a1)
+            id2 = id(a2)
+            id3 = id(a3)
+            llop.gc__collect(lltype.Void)
+            error = 0
+            if id1 != id(a1): error += 1
+            if id2 != id(a2): error += 2
+            if id3 != id(a3): error += 4
+            return error
+        run = self.runner(func)
+        res = run([])
+        assert res == 0
+
 class TestMarkSweepGC(GenericGCTests):
     class gcpolicy(gc.FrameworkGcPolicy):
         class transformerclass(framework.FrameworkGCTransformer):

Modified: pypy/dist/pypy/rpython/rmodel.py
==============================================================================
--- pypy/dist/pypy/rpython/rmodel.py	(original)
+++ pypy/dist/pypy/rpython/rmodel.py	Sat Oct 13 22:34:59 2007
@@ -220,9 +220,7 @@
             raise TyperError('id() of an instance of the non-pointer %r' % (
                 self,))
         vobj, = hop.inputargs(self)
-        # XXX I am still not sure whether this is the right thing to do,
-        # since the int might keep things alive with boehm
-        return hop.genop('cast_ptr_to_int', [vobj], resulttype=Signed)
+        return hop.genop('gc_id', [vobj], resulttype=Signed)
 
     def rtype_hash(self, hop):
         ll_hash = self.get_ll_hash_function()

Modified: pypy/dist/pypy/translator/c/gc.py
==============================================================================
--- pypy/dist/pypy/translator/c/gc.py	(original)
+++ pypy/dist/pypy/translator/c/gc.py	Sat Oct 13 22:34:59 2007
@@ -199,7 +199,6 @@
         if sys.platform != "win32":
             # GC_REDIRECT_TO_LOCAL is not supported on Win32 by gc6.8
             yield "#define GC_REDIRECT_TO_LOCAL 1"
-        yield "#define GC_I_HIDE_POINTERS 1"
         yield '#include <gc/gc.h>'
         yield '#define USING_BOEHM_GC'
 

Modified: pypy/dist/pypy/translator/c/src/address.h
==============================================================================
--- pypy/dist/pypy/translator/c/src/address.h	(original)
+++ pypy/dist/pypy/translator/c/src/address.h	Sat Oct 13 22:34:59 2007
@@ -18,11 +18,3 @@
 
 #define OP_CAST_ADR_TO_INT(x, r)     r = ((long)x)
 #define OP_CAST_INT_TO_ADR(x, r)     r = ((void *)(x))
-
-#ifndef HIDE_POINTER
-#define HIDE_POINTER(p) (p)
-#ifdef REVEAL_POINTER
-#error HIDE_POINTER but not REVEAL_POINTER?
-#endif
-#define REVEAL_POINTER(p) (p)
-#endif

Modified: pypy/dist/pypy/translator/c/test/test_boehm.py
==============================================================================
--- pypy/dist/pypy/translator/c/test/test_boehm.py	(original)
+++ pypy/dist/pypy/translator/c/test/test_boehm.py	Sat Oct 13 22:34:59 2007
@@ -102,7 +102,6 @@
 
     def test_id_is_weak(self):
         # test that id(obj) does not keep obj alive
-        py.test.skip("fails")
         from pypy.rpython.lltypesystem.lloperation import llop
         class State:
             pass



More information about the Pypy-commit mailing list