[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