[pypy-svn] r68393 - in pypy/branch/gc-hash/pypy: rpython/lltypesystem rpython/memory/gc rpython/memory/gctransform translator/c translator/c/test

arigo at codespeak.net arigo at codespeak.net
Tue Oct 13 20:15:53 CEST 2009


Author: arigo
Date: Tue Oct 13 20:15:53 2009
New Revision: 68393

Modified:
   pypy/branch/gc-hash/pypy/rpython/lltypesystem/lloperation.py
   pypy/branch/gc-hash/pypy/rpython/memory/gc/base.py
   pypy/branch/gc-hash/pypy/rpython/memory/gc/marksweep.py
   pypy/branch/gc-hash/pypy/rpython/memory/gctransform/framework.py
   pypy/branch/gc-hash/pypy/translator/c/database.py
   pypy/branch/gc-hash/pypy/translator/c/gc.py
   pypy/branch/gc-hash/pypy/translator/c/node.py
   pypy/branch/gc-hash/pypy/translator/c/test/test_newgc.py
Log:
Pfew.  Work until test_hash_preservation works with the mark&sweep GC.
All other framework GCs are broken right now.


Modified: pypy/branch/gc-hash/pypy/rpython/lltypesystem/lloperation.py
==============================================================================
--- pypy/branch/gc-hash/pypy/rpython/lltypesystem/lloperation.py	(original)
+++ pypy/branch/gc-hash/pypy/rpython/lltypesystem/lloperation.py	Tue Oct 13 20:15:53 2009
@@ -440,7 +440,7 @@
     'gc_pop_alive_pyobj':   LLOp(),
     'gc_reload_possibly_moved': LLOp(),
     # see rlib/objectmodel for gc_identityhash and gc_id
-    'gc_identityhash':      LLOp(canraise=(MemoryError,), sideeffects=False),
+    'gc_identityhash':      LLOp(sideeffects=False),
     'gc_id':                LLOp(canraise=(MemoryError,), sideeffects=False),
     'gc_set_max_heap_size': LLOp(),
     'gc_can_move'         : LLOp(sideeffects=False),

Modified: pypy/branch/gc-hash/pypy/rpython/memory/gc/base.py
==============================================================================
--- pypy/branch/gc-hash/pypy/rpython/memory/gc/base.py	(original)
+++ pypy/branch/gc-hash/pypy/rpython/memory/gc/base.py	Tue Oct 13 20:15:53 2009
@@ -123,9 +123,6 @@
     def malloc_nonmovable(self, typeid, length=0, zero=False):
         return self.malloc(typeid, length, zero)
 
-    def id(self, ptr):
-        return lltype.cast_ptr_to_int(ptr)
-
     def can_move(self, addr):
         return False
 

Modified: pypy/branch/gc-hash/pypy/rpython/memory/gc/marksweep.py
==============================================================================
--- pypy/branch/gc-hash/pypy/rpython/memory/gc/marksweep.py	(original)
+++ pypy/branch/gc-hash/pypy/rpython/memory/gc/marksweep.py	Tue Oct 13 20:15:53 2009
@@ -19,6 +19,9 @@
                                        ('pool',        X_POOL_PTR))
 X_CLONE_PTR = lltype.Ptr(X_CLONE)
 
+FL_WITHHASH = 0x01
+FL_CURPOOL  = 0x02
+
 memoryError = MemoryError()
 class MarkSweepGC(GCBase):
     HDR = lltype.ForwardReference()
@@ -27,9 +30,10 @@
     # systems allocator and can't walk the heap
     HDR.become(lltype.Struct('header', ('typeid16', rffi.USHORT),
                                        ('mark', lltype.Bool),
-                                       ('curpool_flag', lltype.Bool),
+                                       ('flags', lltype.Char),
                                        ('next', HDRPTR)))
     typeid_is_in_field = 'typeid16'
+    withhash_flag_is_in_field = 'flags', FL_WITHHASH
 
     POOL = lltype.GcStruct('gc_pool')
     POOLPTR = lltype.Ptr(POOL)
@@ -102,7 +106,7 @@
         hdr = llmemory.cast_adr_to_ptr(result, self.HDRPTR)
         hdr.typeid16 = typeid16
         hdr.mark = False
-        hdr.curpool_flag = False
+        hdr.flags = '\x00'
         if has_finalizer:
             hdr.next = self.malloced_objects_with_finalizer
             self.malloced_objects_with_finalizer = hdr
@@ -139,7 +143,7 @@
         hdr = llmemory.cast_adr_to_ptr(result, self.HDRPTR)
         hdr.typeid16 = typeid16
         hdr.mark = False
-        hdr.curpool_flag = False
+        hdr.flags = '\x00'
         if has_finalizer:
             hdr.next = self.malloced_objects_with_finalizer
             self.malloced_objects_with_finalizer = hdr
@@ -178,7 +182,7 @@
         hdr = llmemory.cast_adr_to_ptr(result, self.HDRPTR)
         hdr.typeid16 = typeid16
         hdr.mark = False
-        hdr.curpool_flag = False
+        hdr.flags = '\x00'
         hdr.next = self.malloced_objects
         self.malloced_objects = hdr
         self.bytes_malloced = bytes_malloced
@@ -213,7 +217,7 @@
         hdr = llmemory.cast_adr_to_ptr(result, self.HDRPTR)
         hdr.typeid16 = typeid16
         hdr.mark = False
-        hdr.curpool_flag = False
+        hdr.flags = '\x00'
         hdr.next = self.malloced_objects
         self.malloced_objects = hdr
         self.bytes_malloced = bytes_malloced
@@ -516,7 +520,7 @@
         hdr = llmemory.cast_adr_to_ptr(addr, self.HDRPTR)
         hdr.typeid16 = typeid
         hdr.mark = False
-        hdr.curpool_flag = False
+        hdr.flags = '\x00'
 
     def init_gc_object_immortal(self, addr, typeid, flags=0):
         # prebuilt gc structures always have the mark bit set
@@ -524,7 +528,7 @@
         hdr = llmemory.cast_adr_to_ptr(addr, self.HDRPTR)
         hdr.typeid16 = typeid
         hdr.mark = True
-        hdr.curpool_flag = False
+        hdr.flags = '\x00'
 
     # experimental support for thread cloning
     def x_swap_pool(self, newpool):
@@ -596,7 +600,8 @@
         hdr = hdr.next   # skip the POOL object itself
         while hdr:
             next = hdr.next
-            hdr.curpool_flag = True   # mark all objects from malloced_list
+            # mark all objects from malloced_list
+            hdr.flags = chr(ord(hdr.flags) | FL_CURPOOL)
             hdr.next = lltype.nullptr(self.HDR)  # abused to point to the copy
             oldobjects.append(llmemory.cast_ptr_to_adr(hdr))
             hdr = next
@@ -613,7 +618,7 @@
                 continue   # pointer is NULL
             oldhdr = llmemory.cast_adr_to_ptr(oldobj_addr - size_gc_header,
                                               self.HDRPTR)
-            if not oldhdr.curpool_flag:
+            if not (ord(oldhdr.flags) & FL_CURPOOL):
                 continue   # ignore objects that were not in the malloced_list
             newhdr = oldhdr.next      # abused to point to the copy
             if not newhdr:
@@ -645,13 +650,13 @@
 
                 saved_id   = newhdr.typeid16  # XXX hack needed for genc
                 saved_flg1 = newhdr.mark
-                saved_flg2 = newhdr.curpool_flag
+                saved_flg2 = newhdr.flags
                 saved_next = newhdr.next      # where size_gc_header == 0
                 raw_memcopy(oldobj_addr, newobj_addr, size)
-                newhdr.typeid16     = saved_id
-                newhdr.mark         = saved_flg1
-                newhdr.curpool_flag = saved_flg2
-                newhdr.next         = saved_next
+                newhdr.typeid16 = saved_id
+                newhdr.mark     = saved_flg1
+                newhdr.flags    = saved_flg2
+                newhdr.next     = saved_next
 
                 offsets = self.offsets_to_gc_pointers(typeid)
                 i = 0
@@ -685,7 +690,7 @@
         next = lltype.nullptr(self.HDR)
         while oldobjects.non_empty():
             hdr = llmemory.cast_adr_to_ptr(oldobjects.pop(), self.HDRPTR)
-            hdr.curpool_flag = False   # reset the flag
+            hdr.flags = chr(ord(hdr.flags) &~ FL_CURPOOL)  # reset the flag
             hdr.next = next
             next = hdr
         oldobjects.delete()
@@ -700,6 +705,17 @@
         # reinstall the pool that was current at the beginning of x_clone()
         clonedata.pool = self.x_swap_pool(curpool)
 
+    def identityhash(self, obj):
+        obj = llmemory.cast_ptr_to_adr(obj)
+        size_gc_header = self.gcheaderbuilder.size_gc_header
+        gc_info = obj - size_gc_header
+        hdr = llmemory.cast_adr_to_ptr(gc_info, self.HDRPTR)
+        if ord(hdr.flags) & FL_WITHHASH:
+            obj += self.get_size(obj)
+            return obj.signed[0]
+        else:
+            return llmemory.cast_adr_to_int(obj)
+
 
 class PrintingMarkSweepGC(MarkSweepGC):
     _alloc_flavor_ = "raw"

Modified: pypy/branch/gc-hash/pypy/rpython/memory/gctransform/framework.py
==============================================================================
--- pypy/branch/gc-hash/pypy/rpython/memory/gctransform/framework.py	(original)
+++ pypy/branch/gc-hash/pypy/rpython/memory/gctransform/framework.py	Tue Oct 13 20:15:53 2009
@@ -337,6 +337,10 @@
                 [annmodel.SomeBool()],
                 s_gcref)
 
+        self.identityhash_ptr = getfn(GCClass.identityhash.im_func,
+                                      [s_gc, s_gcref],
+                                      annmodel.SomeInteger())
+
         if GCClass.moving_gc:
             self.id_ptr = getfn(GCClass.id.im_func,
                                 [s_gc, s_gcref], annmodel.SomeInteger(),
@@ -435,7 +439,20 @@
     def gc_field_values_for(self, obj):
         hdr = self.gcdata.gc.gcheaderbuilder.header_of_object(obj)
         HDR = self._gc_HDR
-        return [getattr(hdr, fldname) for fldname in HDR._names]
+        withhash, flag = self.gcdata.gc.withhash_flag_is_in_field
+        result = []
+        for fldname in HDR._names:
+            x = getattr(hdr, fldname)
+            if fldname == withhash:
+                TYPE = lltype.typeOf(x)
+                x = lltype.cast_primitive(lltype.Signed, x)
+                if hasattr(obj._normalizedcontainer(), '_hash_cache_'):
+                    x |= flag
+                else:
+                    x &= ~flag
+                x = lltype.cast_primitive(TYPE, x)
+            result.append(x)
+        return result
 
     def finish_tables(self):
         group = self.layoutbuilder.close_table()
@@ -713,6 +730,14 @@
                            resulttype=llmemory.Address)
         hop.cast_result(v_addr)
 
+    def gct_gc_identityhash(self, hop):
+        [v_ptr] = hop.spaceop.args
+        v_adr = hop.genop("cast_ptr_to_adr", [v_ptr],
+                          resulttype=llmemory.Address)
+        hop.genop("direct_call",
+                  [self.identityhash_ptr, self.c_const_gc, v_adr],
+                  resultvar=hop.spaceop.result)
+
     def gct_gc_id(self, hop):
         if self.id_ptr is not None:
             livevars = self.push_roots(hop)

Modified: pypy/branch/gc-hash/pypy/translator/c/database.py
==============================================================================
--- pypy/branch/gc-hash/pypy/translator/c/database.py	(original)
+++ pypy/branch/gc-hash/pypy/translator/c/database.py	Tue Oct 13 20:15:53 2009
@@ -65,12 +65,17 @@
 
         self.instrument_ncounter = 0
 
-    def gettypedefnode(self, T, varlength=1):
+    def gettypedefnode(self, T, varlength=1, needs_hash=False):
         if varlength <= 1:
             varlength = 1   # it's C after all
             key = T
         else:
             key = T, varlength
+        if needs_hash:
+            if self.gcpolicy.stores_hash_at_the_end:
+                key = key, 'hash'
+            else:
+                needs_hash = False
         try:
             node = self.structdefnodes[key]
         except KeyError:
@@ -78,7 +83,7 @@
                 if isinstance(T, FixedSizeArray):
                     node = FixedSizeArrayDefNode(self, T)
                 else:
-                    node = StructDefNode(self, T, varlength)
+                    node = StructDefNode(self, T, varlength, needs_hash)
             elif isinstance(T, Array):
                 if barebonearray(T):
                     node = BareBoneArrayDefNode(self, T, varlength)
@@ -95,7 +100,8 @@
             self.pendingsetupnodes.append(node)
         return node
 
-    def gettype(self, T, varlength=1, who_asks=None, argnames=[]):
+    def gettype(self, T, varlength=1, who_asks=None, argnames=[],
+                needs_hash=False):
         if isinstance(T, Primitive) or T == GCREF:
             return PrimitiveType[T]
         elif isinstance(T, Ptr):
@@ -109,7 +115,8 @@
             typename = self.gettype(T.TO)   # who_asks not propagated
             return typename.replace('@', '*@')
         elif isinstance(T, (Struct, Array, _WeakRefType)):
-            node = self.gettypedefnode(T, varlength=varlength)
+            node = self.gettypedefnode(T, varlength=varlength,
+                                       needs_hash=needs_hash)
             if who_asks is not None:
                 who_asks.dependencies[node] = True
             return node.gettype()

Modified: pypy/branch/gc-hash/pypy/translator/c/gc.py
==============================================================================
--- pypy/branch/gc-hash/pypy/translator/c/gc.py	(original)
+++ pypy/branch/gc-hash/pypy/translator/c/gc.py	Tue Oct 13 20:15:53 2009
@@ -12,6 +12,7 @@
 
 class BasicGcPolicy(object):
     requires_stackless = False
+    stores_hash_at_the_end = False
 
     def __init__(self, db, thread_enabled=False):
         self.db = db
@@ -42,9 +43,6 @@
     def array_gcheader_initdata(self, defnode):
         return self.common_gcheader_initdata(defnode)
 
-    def struct_after_definition(self, defnode):
-        return []
-
     def compilation_info(self):
         if not self.db:
             return ExternalCompilationInfo()
@@ -290,6 +288,7 @@
 
 class FrameworkGcPolicy(BasicGcPolicy):
     transformerclass = framework.FrameworkGCTransformer
+    stores_hash_at_the_end = True
 
     def struct_setup(self, structdefnode, rtti):
         if rtti is not None and hasattr(rtti._obj, 'destructor_funcptr'):

Modified: pypy/branch/gc-hash/pypy/translator/c/node.py
==============================================================================
--- pypy/branch/gc-hash/pypy/translator/c/node.py	(original)
+++ pypy/branch/gc-hash/pypy/translator/c/node.py	Tue Oct 13 20:15:53 2009
@@ -37,11 +37,12 @@
 
 class StructDefNode:
     typetag = 'struct'
-    def __init__(self, db, STRUCT, varlength=1):
+    def __init__(self, db, STRUCT, varlength=1, hash_at_end=False):
         self.db = db
         self.STRUCT = STRUCT
         self.LLTYPE = STRUCT
         self.varlength = varlength
+        self.hash_at_end = hash_at_end
         if varlength == 1:
             basename = STRUCT._name
             with_number = True
@@ -49,6 +50,8 @@
             basename = db.gettypedefnode(STRUCT).barename
             basename = '%s_len%d' % (basename, varlength)
             with_number = False
+        if hash_at_end:
+            basename += '_hash'
         if STRUCT._hints.get('union'):
             self.typetag = 'union'
             assert STRUCT._gckind == 'raw'   # not supported: "GcUnion"
@@ -94,6 +97,8 @@
             else:
                 typename = db.gettype(T, who_asks=self)
             self.fields.append((self.c_struct_field_name(name), typename))
+        if self.hash_at_end:
+            self.fields.append(('_hash', 'long @'))
         self.gcinfo  # force it to be computed
 
     def computegcinfo(self):
@@ -149,8 +154,6 @@
         if is_empty:
             yield '\t' + 'char _dummy; /* this struct is empty */'
         yield '};'
-        for line in self.db.gcpolicy.struct_after_definition(self):
-            yield line
 
     def visitor_lines(self, prefix, on_field):
         for name in self.fieldnames:
@@ -448,7 +451,8 @@
         self.obj = obj
         #self.dependencies = {}
         self.typename = db.gettype(T)  #, who_asks=self)
-        self.implementationtypename = db.gettype(T, varlength=self.getlength())
+        self.implementationtypename = db.gettype(T, varlength=self.getlength(),
+                                       needs_hash=hasattr(obj, '_hash_cache_'))
         parent, parentindex = parentlink(obj)
         if parent is None:
             self.name = db.namespace.uniquename('g_' + self.basename())
@@ -519,7 +523,8 @@
         data = []
 
         if needs_gcheader(self.T):
-            for i, thing in enumerate(self.db.gcpolicy.struct_gcheader_initdata(self)):
+            hdr = self.db.gcpolicy.struct_gcheader_initdata(self)
+            for i, thing in enumerate(hdr):
                 data.append(('gcheader%d'%i, thing))
         
         for name in defnode.fieldnames:
@@ -533,6 +538,9 @@
         if hasattr(self.T, "_hints") and self.T._hints.get('union'):
             data = data[0:1]
 
+        if hasattr(self.obj, '_hash_cache_'):
+            data.append(('_hash', self.obj._hash_cache_))
+
         for name, value in data:
             c_expr = defnode.access_expr(self.name, name)
             lines = generic_initializationexpr(self.db, value, c_expr,

Modified: pypy/branch/gc-hash/pypy/translator/c/test/test_newgc.py
==============================================================================
--- pypy/branch/gc-hash/pypy/translator/c/test/test_newgc.py	(original)
+++ pypy/branch/gc-hash/pypy/translator/c/test/test_newgc.py	Tue Oct 13 20:15:53 2009
@@ -689,6 +689,31 @@
     def test_resizable_buffer(self):
         assert self.run('resizable_buffer')
 
+    def define_hash_preservation(cls):
+        from pypy.rlib.objectmodel import compute_hash
+        from pypy.rlib.objectmodel import current_object_addr_as_int
+        class C:
+            pass
+        class D(C):
+            pass
+        c = C()
+        d = D()
+        h_d = compute_hash(d)     # force to be cached on 'd', but not on 'c'
+        h_t = compute_hash(("Hi", None, (7.5, 2, d)))
+        #
+        def f():
+            d2 = D()
+            if compute_hash(d2) != current_object_addr_as_int(d2): return 11
+            if compute_hash(c) != compute_hash(c): return 12
+            if compute_hash(d) != h_d: return 13
+            if compute_hash(("Hi", None, (7.5, 2, d))) != h_t: return 14
+            return 42
+        return f
+
+    def test_hash_preservation(self):
+        res = self.run('hash_preservation')
+        assert res == 42
+
 class TestSemiSpaceGC(TestUsingFramework, snippet.SemiSpaceGCTestDefines):
     gcpolicy = "semispace"
     should_be_moving = True



More information about the Pypy-commit mailing list