[pypy-commit] pypy stmgc-c7: Mostly implement stmgc's hashtables in RPython.

arigo noreply at buildbot.pypy.org
Tue Nov 11 16:21:27 CET 2014


Author: Armin Rigo <arigo at tunes.org>
Branch: stmgc-c7
Changeset: r74447:55d1033012f1
Date: 2014-11-11 16:20 +0100
http://bitbucket.org/pypy/pypy/changeset/55d1033012f1/

Log:	Mostly implement stmgc's hashtables in RPython.

diff --git a/rpython/memory/gc/stmgc.py b/rpython/memory/gc/stmgc.py
--- a/rpython/memory/gc/stmgc.py
+++ b/rpython/memory/gc/stmgc.py
@@ -102,8 +102,8 @@
 
 
     def can_move(self, obj):
-        """Means the reference will stay valid, except if not
-        seen by the GC, then it can get collected."""
+        """An object that cannot move means the pointer to it will stay valid,
+        as long as it is not actually collected."""
         return llop.stm_can_move(lltype.Bool, obj)
 
 
diff --git a/rpython/rlib/rstm.py b/rpython/rlib/rstm.py
--- a/rpython/rlib/rstm.py
+++ b/rpython/rlib/rstm.py
@@ -1,6 +1,7 @@
 from rpython.rlib.objectmodel import we_are_translated, specialize
 from rpython.rlib.objectmodel import CDefinedIntSymbolic
-from rpython.rlib.rgc import stm_is_enabled
+from rpython.rlib.nonconst import NonConstant
+from rpython.rlib import rgc
 from rpython.rtyper.lltypesystem import lltype, rffi, rstr, llmemory
 from rpython.rtyper.lltypesystem.lloperation import llop
 from rpython.rtyper.extregistry import ExtRegistryEntry
@@ -54,7 +55,7 @@
     """ keep: should be True for checks that are absolutely
     needed. False means the JIT only keeps the check if it
     thinks that it helps """
-    if stm_is_enabled():
+    if rgc.stm_is_enabled():
         if llop.stm_should_break_transaction(lltype.Bool, keep):
             break_transaction()
 
@@ -171,3 +172,67 @@
         hop.exception_cannot_occur()
         if hop.rtyper.annotator.translator.config.translation.stm:
             hop.genop('stm_rewind_jmp_frame', [], resulttype=lltype.Void)
+
+# ____________________________________________________________
+
+_STM_HASHTABLE_P = rffi.COpaquePtr('stm_hashtable_t')
+
+_STM_HASHTABLE_ENTRY = lltype.GcStruct('HASHTABLE_ENTRY',
+                                       ('index', lltype.Unsigned),
+                                       ('object', llmemory.GCREF))
+
+
+class Hashtable(object):
+
+    def __new__(cls):
+        "NOT_RPYTHON: for tests, return a HashtableForTest instance"
+        return HashtableForTest()
+
+    def __init__(self):
+        # Pass a null pointer to _STM_HASHTABLE_ENTRY to stm_hashtable_create().
+        # Make sure we see a malloc() of it, so that its typeid is correctly
+        # initialized.  It can be done in a NonConstant(False) path so that
+        # the C compiler will actually drop it.
+        if NonConstant(False):
+            p = lltype.malloc(_STM_HASHTABLE_ENTRY)
+        else:
+            p = lltype.nullptr(_STM_HASHTABLE_ENTRY)
+        self.ll_raw_hashtable = llop.stm_hashtable_create(_STM_HASHTABLE_P, p)
+
+    @rgc.must_be_light_finalizer
+    def __del__(self):
+        llop.stm_hashtable_free(lltype.Void, self.ll_raw_hashtable)
+
+    def get(self, key):
+        # 'key' must be a plain integer.  Returns a GCREF.
+        return llop.stm_hashtable_read(llmemory.GCREF, self,
+                                       self.ll_raw_hashtable, key)
+
+    def set(self, key, value):
+        llop.stm_hashtable_write(lltype.Void, self,
+                                 self.ll_raw_hashtable, key, value)
+
+
+class HashtableForTest(object):
+    _NULL = lltype.nullptr(llmemory.GCREF.TO)
+
+    def __init__(self):
+        self._content = {}      # dict {integer: GCREF}
+
+    def _cleanup_(self):
+        raise Exception("cannot translate a prebuilt rstm.Hashtable object")
+
+    def get(self, key):
+        assert type(key) is int
+        return self._content.get(key, self._NULL)
+
+    def set(self, key, value):
+        assert type(key) is int
+        assert lltype.typeOf(value) == llmemory.GCREF
+        if value:
+            self._content[key] = value
+        else:
+            try:
+                del self._content[key]
+            except KeyError:
+                pass
diff --git a/rpython/rtyper/annlowlevel.py b/rpython/rtyper/annlowlevel.py
--- a/rpython/rtyper/annlowlevel.py
+++ b/rpython/rtyper/annlowlevel.py
@@ -512,7 +512,7 @@
 @specialize.arg(0)
 def cast_gcref_to_instance(Class, ptr):
     """Reverse the hacking done in cast_instance_to_gcref()."""
-    from rpython.rtyper.rclass import OBJECTPTR
+    from rpython.rtyper.lltypesystem.rclass import OBJECTPTR
     ptr = lltype.cast_opaque_ptr(OBJECTPTR, ptr)
     return cast_base_ptr_to_instance(Class, ptr)
 
diff --git a/rpython/rtyper/lltypesystem/lloperation.py b/rpython/rtyper/lltypesystem/lloperation.py
--- a/rpython/rtyper/lltypesystem/lloperation.py
+++ b/rpython/rtyper/lltypesystem/lloperation.py
@@ -461,6 +461,11 @@
     'stm_count':                 LLOp(canrun=True),
     'stm_really_force_cast_ptr': LLOp(),
 
+    'stm_hashtable_create':   LLOp(),
+    'stm_hashtable_free':     LLOp(),
+    'stm_hashtable_read':     LLOp(),
+    'stm_hashtable_write':    LLOp(),
+
     # __________ address operations __________
 
     'boehm_malloc':         LLOp(),
diff --git a/rpython/translator/backendopt/finalizer.py b/rpython/translator/backendopt/finalizer.py
--- a/rpython/translator/backendopt/finalizer.py
+++ b/rpython/translator/backendopt/finalizer.py
@@ -18,7 +18,7 @@
     """
     ok_operations = ['ptr_nonzero', 'ptr_eq', 'ptr_ne', 'free', 'same_as',
                      'direct_ptradd', 'force_cast', 'track_alloc_stop',
-                     'raw_free', 'debug_print']
+                     'raw_free', 'debug_print', 'stm_hashtable_free']
 
     def analyze_light_finalizer(self, graph):
         result = self.analyze_direct_call(graph)
diff --git a/rpython/translator/stm/funcgen.py b/rpython/translator/stm/funcgen.py
--- a/rpython/translator/stm/funcgen.py
+++ b/rpython/translator/stm/funcgen.py
@@ -283,3 +283,31 @@
     arg = funcgen.expr(op.args[0])
     typename = cdecl(funcgen.lltypename(op.result), '')
     return '%s = (%s)(uintptr_t)%s;' % (result, typename, arg)
+
+def stm_hashtable_create(funcgen, op):
+    _STM_HASHTABLE_ENTRY = op.args[0].concretetype.TO
+    type_id = funcgen.db.gctransformer.get_type_id(_STM_HASHTABLE_ENTRY)
+    expr_type_id = funcgen.expr(Constant(type_id, lltype.typeOf(type_id)))
+    result = funcgen.expr(op.result)
+    return ('stm_hashtable_entry_userdata = %s; '
+            '%s = stm_hashtable_create();' % (expr_type_id, result,))
+
+def stm_hashtable_free(funcgen, op):
+    arg = funcgen.expr(op.args[0])
+    return 'stm_hashtable_free(%s);' % (arg,)
+
+def stm_hashtable_read(funcgen, op):
+    arg0 = funcgen.expr(op.args[0])
+    arg1 = funcgen.expr(op.args[1])
+    arg2 = funcgen.expr(op.args[2])
+    result = funcgen.expr(op.result)
+    return '%s = (rpygcchar_t *)stm_hashtable_read((object_t *)%s, %s, %s);' % (
+        result, arg0, arg1, arg2)
+
+def stm_hashtable_write(funcgen, op):
+    arg0 = funcgen.expr(op.args[0])
+    arg1 = funcgen.expr(op.args[1])
+    arg2 = funcgen.expr(op.args[2])
+    arg3 = funcgen.expr(op.args[3])
+    return ('stm_hashtable_write((object_t *)%s, %s, %s, (object_t *)%s, '
+            '&stm_thread_local);' % (arg0, arg1, arg2, arg3))
diff --git a/rpython/translator/stm/test/test_ztranslated.py b/rpython/translator/stm/test/test_ztranslated.py
--- a/rpython/translator/stm/test/test_ztranslated.py
+++ b/rpython/translator/stm/test/test_ztranslated.py
@@ -4,6 +4,8 @@
 from rpython.rtyper.lltypesystem import lltype, llmemory, rffi
 from rpython.rtyper.lltypesystem.rclass import OBJECTPTR
 from rpython.rtyper.lltypesystem.lloperation import llop
+from rpython.rtyper.annlowlevel import cast_instance_to_gcref
+from rpython.rtyper.annlowlevel import cast_gcref_to_instance
 from rpython.translator.stm.test.support import CompiledSTMTests
 from rpython.translator.stm.test import targetdemo2
 
@@ -549,3 +551,38 @@
         t, cbuilder = self.compile(main)
         data, err = cbuilder.cmdexec('', err=True)
         assert '<del>' in err
+
+    def test_hashtable(self):
+        py.test.skip("missing: custom tracer on Hashtable")
+
+        class X(object):
+            pass
+
+        def main(argv):
+            h = rstm.Hashtable()
+            p = h.get(-1234)
+            assert p == lltype.nullptr(llmemory.GCREF.TO)
+            #
+            x1 = X()
+            p1 = cast_instance_to_gcref(x1)
+            h.set(-1234, p1)
+            #
+            p2 = h.get(-1234)
+            x2 = cast_gcref_to_instance(X, p2)
+            assert x2 is x1
+            #
+            rgc.collect()
+            #
+            p2 = h.get(-1234)
+            x2 = cast_gcref_to_instance(X, p2)
+            assert x2 is x1
+            #
+            print "ok!"
+            return 0
+
+        res = main([])      # direct run
+        assert res == 0
+
+        t, cbuilder = self.compile(main)
+        data = cbuilder.cmdexec('')
+        assert 'ok!\n' in data


More information about the pypy-commit mailing list