[pypy-commit] pypy stm: Support fields of various types, including smaller arithmetic types.

arigo noreply at buildbot.pypy.org
Tue Sep 27 21:53:20 CEST 2011


Author: Armin Rigo <arigo at tunes.org>
Branch: stm
Changeset: r47636:a52e42745258
Date: 2011-09-27 21:26 +0200
http://bitbucket.org/pypy/pypy/changeset/a52e42745258/

Log:	Support fields of various types, including smaller arithmetic types.

diff --git a/pypy/translator/c/funcgen.py b/pypy/translator/c/funcgen.py
--- a/pypy/translator/c/funcgen.py
+++ b/pypy/translator/c/funcgen.py
@@ -475,23 +475,14 @@
     def generic_get(self, op, sourceexpr):
         T = self.lltypemap(op.result)
         newvalue = self.expr(op.result, special_case_void=False)
-        if op.opname.startswith('stm_'):
-            typename = self.db.gettype(T)
-            result = '%s = (%s)stm_read_word((void**)&%s);' % (
-                newvalue, cdecl(typename, ''), sourceexpr)
-        else:
-            result = '%s = %s;' % (newvalue, sourceexpr)
+        result = '%s = %s;' % (newvalue, sourceexpr)
         if T is Void:
             result = '/* %s */' % result
         return result
 
     def generic_set(self, op, targetexpr):
         newvalue = self.expr(op.args[-1], special_case_void=False)
-        if op.opname.startswith('stm_'):
-            result = 'stm_write_word((void**)&%s, (void*)%s);' % (
-                targetexpr, newvalue)
-        else:
-            result = '%s = %s;' % (targetexpr, newvalue)
+        result = '%s = %s;' % (targetexpr, newvalue)
         T = self.lltypemap(op.args[-1])
         if T is Void:
             result = '/* %s */' % result
@@ -598,8 +589,13 @@
             return '%s = %s.length;'%(self.expr(op.result), expr)
 
 
-    OP_STM_GETFIELD = OP_GETFIELD
-    OP_STM_SETFIELD = OP_BARE_SETFIELD
+    def _OP_STM(self, op):
+        if not hasattr(self, 'op_stm'):
+            from pypy.translator.stm.funcgen import op_stm
+            self.__class__.op_stm = op_stm
+        return self.op_stm(op)
+    OP_STM_GETFIELD = _OP_STM
+    OP_STM_SETFIELD = _OP_STM
 
 
     def OP_PTR_NONZERO(self, op):
diff --git a/pypy/translator/stm/_rffi_stm.py b/pypy/translator/stm/_rffi_stm.py
--- a/pypy/translator/stm/_rffi_stm.py
+++ b/pypy/translator/stm/_rffi_stm.py
@@ -18,6 +18,8 @@
     return rffi.llexternal(name, args, result, compilation_info=eci,
                            _nowrapper=True, **kwds)
 
+SignedP = lltype.Ptr(lltype.Array(lltype.Signed, hints={'nolength': True}))
+
 
 descriptor_init = llexternal('stm_descriptor_init', [], lltype.Void)
 descriptor_done = llexternal('stm_descriptor_done', [], lltype.Void)
@@ -25,8 +27,8 @@
 begin_transaction = llexternal('stm_begin_transaction_inline',[], lltype.Void)
 commit_transaction = llexternal('stm_commit_transaction', [], lltype.Signed)
 
-stm_read_word = llexternal('stm_read_word', [rffi.VOIDPP], rffi.VOIDP)
-stm_write_word = llexternal('stm_write_word', [rffi.VOIDPP, rffi.VOIDP],
+stm_read_word = llexternal('stm_read_word', [SignedP], lltype.Signed)
+stm_write_word = llexternal('stm_write_word', [SignedP, lltype.Signed],
                             lltype.Void)
 
 CALLBACK = lltype.Ptr(lltype.FuncType([rffi.VOIDP], rffi.VOIDP))
diff --git a/pypy/translator/stm/funcgen.py b/pypy/translator/stm/funcgen.py
new file mode 100644
--- /dev/null
+++ b/pypy/translator/stm/funcgen.py
@@ -0,0 +1,40 @@
+from pypy.rpython.lltypesystem import lltype, rffi
+from pypy.objspace.flow.model import Constant
+from pypy.translator.c.support import cdecl
+from pypy.translator.stm.rstm import size_of_voidp
+
+
+def stm_getfield(funcgen, op):
+    STRUCT = funcgen.lltypemap(op.args[0]).TO
+    structdef = funcgen.db.gettypedefnode(STRUCT)
+    baseexpr_is_const = isinstance(op.args[0], Constant)
+    basename = funcgen.expr(op.args[0])
+    fieldname = op.args[1].value
+    T = funcgen.lltypemap(op.result)
+    fieldtypename = funcgen.db.gettype(T)
+    cfieldtypename = cdecl(fieldtypename, '')
+    newvalue = funcgen.expr(op.result, special_case_void=False)
+    #
+    assert T is not lltype.Void     # XXX
+    fieldsize = rffi.sizeof(T)
+    if fieldsize >= size_of_voidp:
+        assert 1      # xxx assert somehow that the field is aligned
+        assert fieldsize == size_of_voidp     # XXX
+        expr = structdef.ptr_access_expr(basename,
+                                         fieldname,
+                                         baseexpr_is_const)
+        return '%s = (%s)stm_read_word((long*)&%s);' % (
+            newvalue, cfieldtypename, expr)
+    else:
+        # assume that the object is aligned, and any possible misalignment
+        # comes from the field offset, so that it can be resolved at
+        # compile-time (by using C macros)
+        return '%s = stm_read_partial_word(%s, %s, offsetof(%s, %s));' % (
+            newvalue, cfieldtypename, basename,
+            cdecl(funcgen.db.gettype(STRUCT), ''),
+            structdef.c_struct_field_name(fieldname))
+
+
+def op_stm(funcgen, op):
+    func = globals()[op.opname]
+    return func(funcgen, op)
diff --git a/pypy/translator/stm/rstm.py b/pypy/translator/stm/rstm.py
--- a/pypy/translator/stm/rstm.py
+++ b/pypy/translator/stm/rstm.py
@@ -1,30 +1,67 @@
+import sys
 from pypy.rpython.lltypesystem import lltype, rffi
 from pypy.rpython.extregistry import ExtRegistryEntry
 from pypy.translator.stm import _rffi_stm
 from pypy.annotation import model as annmodel
 from pypy.objspace.flow.model import Constant
 
+size_of_voidp = rffi.sizeof(rffi.VOIDP)
+assert size_of_voidp & (size_of_voidp - 1) == 0
+
+assert sys.byteorder == 'little'   # xxx fix here and in funcgen.py
+
 
 def stm_getfield(structptr, fieldname):
+    STRUCT = lltype.typeOf(structptr).TO
+    FIELD = getattr(STRUCT, fieldname)
     p = lltype.direct_fieldptr(structptr, fieldname)
-    p = rffi.cast(rffi.VOIDPP, p)
-    res = _rffi_stm.stm_read_word(p)
-    return rffi.cast(lltype.Signed, res)
+    p = rffi.cast(lltype.Signed, p)
+    misalignment = p & (size_of_voidp - 1)
+    fieldsize = rffi.sizeof(FIELD)
+    p = rffi.cast(_rffi_stm.SignedP, p - misalignment)
+    if fieldsize >= size_of_voidp:
+        assert misalignment == 0
+        assert fieldsize == size_of_voidp   # XXX
+        res = _rffi_stm.stm_read_word(p)
+    else:
+        assert misalignment + fieldsize <= size_of_voidp
+        res = _rffi_stm.stm_read_word(p)
+        res = res >> (misalignment * 8)
+    return rffi.cast(FIELD, res)
 
 def stm_setfield(structptr, fieldname, newvalue):
+    STRUCT = lltype.typeOf(structptr).TO
+    FIELD = getattr(STRUCT, fieldname)
     p = lltype.direct_fieldptr(structptr, fieldname)
-    p = rffi.cast(rffi.VOIDPP, p)
-    pval = rffi.cast(rffi.VOIDP, newvalue)
-    _rffi_stm.stm_write_word(p, pval)
-
+    p = rffi.cast(lltype.Signed, p)
+    misalignment = p & (size_of_voidp - 1)
+    fieldsize = rffi.sizeof(FIELD)
+    #print 'setfield %x size %d:' % (p, fieldsize),
+    p = rffi.cast(_rffi_stm.SignedP, p - misalignment)
+    if fieldsize >= size_of_voidp:
+        assert misalignment == 0
+        assert fieldsize == size_of_voidp   # XXX
+        _rffi_stm.stm_write_word(p, rffi.cast(lltype.Signed, newvalue))
+        #print 'ok'
+    else:
+        # bah, must read the complete word in order to modify only a part
+        assert misalignment + fieldsize <= size_of_voidp
+        val = rffi.cast(lltype.Signed, newvalue)
+        val = val << (misalignment * 8)
+        word = _rffi_stm.stm_read_word(p)
+        mask = (1 << (misalignment * 8)) * ((1 << (fieldsize * 8)) - 1)
+        val = (val & mask) | (word & ~mask)
+        #print 'getting %x, mask=%x, replacing with %x' % (word, mask, val)
+        _rffi_stm.stm_write_word(p, val)
 
 # ____________________________________________________________
 
+
 class ExtEntry(ExtRegistryEntry):
     _about_ = stm_getfield
 
     def compute_result_annotation(self, s_structptr, s_fieldname):
-        return annmodel.SomeInteger()
+        return s_structptr.getattr(s_fieldname)
 
     def specialize_call(self, hop):
         r_structptr = hop.args_r[0]
@@ -32,7 +69,7 @@
         fieldname = hop.args_v[1].value
         c_fieldname = hop.inputconst(lltype.Void, fieldname)
         return hop.genop('stm_getfield', [v_structptr, c_fieldname],
-                         resulttype = lltype.Signed)
+                         resulttype = hop.r_result)
 
 
 class ExtEntry(ExtRegistryEntry):
diff --git a/pypy/translator/stm/src_stm/et.c b/pypy/translator/stm/src_stm/et.c
--- a/pypy/translator/stm/src_stm/et.c
+++ b/pypy/translator/stm/src_stm/et.c
@@ -40,6 +40,9 @@
 inline static volatile orec_t* get_orec(void* addr)
 {
   unsigned long index = (unsigned long)addr;
+#ifdef RPY_ASSERT
+  assert(!(index & (sizeof(orec_t)-1)));
+#endif
   char *p = orecs + (index & ((NUM_STRIPES-1) * sizeof(orec_t)));
   return (volatile orec_t *)p;
 }
@@ -453,7 +456,7 @@
 }
 
 /* lazy/lazy read instrumentation */
-void* stm_read_word(void** addr)
+long stm_read_word(long* addr)
 {
   struct tx_descriptor *d = thread_descriptor;
 
@@ -500,7 +503,7 @@
     }
 
   // orec is unlocked, with ts <= start_time.  read the location
-  void* tmp = *addr;
+  long tmp = *addr;
 
   // postvalidate AFTER reading addr:
   CFENCE;
@@ -514,7 +517,7 @@
   return tmp;
 }
 
-void stm_write_word(void** addr, void* val)
+void stm_write_word(long* addr, long val)
 {
   struct tx_descriptor *d = thread_descriptor;
   redolog_insert(&d->redolog, addr, val);
diff --git a/pypy/translator/stm/src_stm/et.h b/pypy/translator/stm/src_stm/et.h
--- a/pypy/translator/stm/src_stm/et.h
+++ b/pypy/translator/stm/src_stm/et.h
@@ -16,8 +16,8 @@
 void* stm_perform_transaction(void*(*)(void*), void*);
 void stm_begin_transaction(jmp_buf* buf);
 long stm_commit_transaction(void);
-void* stm_read_word(void** addr);
-void stm_write_word(void** addr, void* val);
+long stm_read_word(long* addr);
+void stm_write_word(long* addr, long val);
 void stm_try_inevitable(void);
 void stm_begin_inevitable_transaction(void);
 void stm_abort_and_retry(void);
@@ -27,5 +27,11 @@
        setjmp(_jmpbuf);                   \
        stm_begin_transaction(&_jmpbuf)
 
+// XXX little-endian only!
+#define stm_read_partial_word(T, base, offset)                          \
+    (T)(stm_read_word(                                                  \
+           (long*)(((char*)(base)) + ((offset) & ~(sizeof(void*)-1))))  \
+        >> (8 * ((offset) & (sizeof(void*)-1))))
+
 
 #endif  /* _ET_H */
diff --git a/pypy/translator/stm/src_stm/lists.c b/pypy/translator/stm/src_stm/lists.c
--- a/pypy/translator/stm/src_stm/lists.c
+++ b/pypy/translator/stm/src_stm/lists.c
@@ -21,8 +21,8 @@
 #define TREE_MASK   ((TREE_ARITY - 1) * sizeof(void*))
 
 typedef struct {
-  void** addr;
-  void* val;
+  long* addr;
+  long val;
   owner_version_t p;   // the previous version number (if locked)
 } wlog_t;
 
@@ -109,7 +109,7 @@
     goto_not_found;                                             \
 }
 
-static wlog_t *_redolog_find(char *entry, void** addr)
+static wlog_t *_redolog_find(char *entry, long* addr)
 {
   unsigned long key = (unsigned long)addr;
   while (((long)entry) & 1)
@@ -120,7 +120,7 @@
   return (wlog_t *)entry;   /* may be NULL */
 }
 
-static void redolog_insert(struct RedoLog *redolog, void** addr, void* val);
+static void redolog_insert(struct RedoLog *redolog, long* addr, long val);
 
 static void _redolog_grow(struct RedoLog *redolog, long extra)
 {
@@ -156,7 +156,7 @@
   return result;
 }
 
-static void redolog_insert(struct RedoLog *redolog, void** addr, void* val)
+static void redolog_insert(struct RedoLog *redolog, long* addr, long val)
 {
  retry:;
   wlog_t *wlog;
diff --git a/pypy/translator/stm/test/test_rstm.py b/pypy/translator/stm/test/test_rstm.py
--- a/pypy/translator/stm/test/test_rstm.py
+++ b/pypy/translator/stm/test/test_rstm.py
@@ -4,15 +4,23 @@
 from pypy.rpython.annlowlevel import llhelper
 
 
-A = lltype.Struct('A', ('x', lltype.Signed), ('y', lltype.Signed))
+A = lltype.Struct('A', ('x', lltype.Signed), ('y', lltype.Signed),
+                       ('c1', lltype.Char), ('c2', lltype.Char),
+                       ('c3', lltype.Char))
 
 def callback1(a):
     a = rffi.cast(lltype.Ptr(A), a)
     assert a.x == -611
+    assert a.c1 == '/'
+    assert a.c2 == '\\'
+    assert a.c3 == '!'
     assert stm_getfield(a, 'x') == -611
+    assert stm_getfield(a, 'c2') == '\\'
+    assert stm_getfield(a, 'c1') == '/'
+    assert stm_getfield(a, 'c3') == '!'
     p = lltype.direct_fieldptr(a, 'x')
-    p = rffi.cast(rffi.VOIDPP, p)
-    stm_write_word(p, rffi.cast(rffi.VOIDP, 42 * a.y))
+    p = rffi.cast(SignedP, p)
+    stm_write_word(p, 42 * a.y)
     assert stm_getfield(a, 'x') == 42 * a.y
     assert a.x == -611 # xxx still the old value when reading non-transact.
     if a.y < 10:
@@ -23,21 +31,42 @@
 def test_stm_getfield():
     a = lltype.malloc(A, flavor='raw')
     a.x = -611
+    a.c1 = '/'
+    a.c2 = '\\'
+    a.c3 = '!'
     a.y = 0
     descriptor_init()
     perform_transaction(llhelper(CALLBACK, callback1),
                         rffi.cast(rffi.VOIDP, a))
     descriptor_done()
     assert a.x == 420
+    assert a.c1 == '/'
+    assert a.c2 == '\\'
+    assert a.c3 == '!'
     lltype.free(a, flavor='raw')
 
 def callback2(a):
     a = rffi.cast(lltype.Ptr(A), a)
     assert a.x == -611
+    assert a.c1 == '&'
+    assert a.c2 == '*'
+    assert a.c3 == '#'
     assert stm_getfield(a, 'x') == -611
+    assert stm_getfield(a, 'c1') == '&'
+    assert stm_getfield(a, 'c2') == '*'
+    assert stm_getfield(a, 'c3') == '#'
     stm_setfield(a, 'x', 42 * a.y)
+    stm_setfield(a, 'c1', '(')
+    stm_setfield(a, 'c2', '?')
+    stm_setfield(a, 'c3', ')')
     assert stm_getfield(a, 'x') == 42 * a.y
+    assert stm_getfield(a, 'c1') == '('
+    assert stm_getfield(a, 'c2') == '?'
+    assert stm_getfield(a, 'c3') == ')'
     assert a.x == -611 # xxx still the old value when reading non-transact.
+    assert a.c1 == '&'
+    assert a.c2 == '*'
+    assert a.c3 == '#'
     if a.y < 10:
         a.y += 1    # non-transactionally
         abort_and_retry()
@@ -46,12 +75,18 @@
 def test_stm_setfield():
     a = lltype.malloc(A, flavor='raw')
     a.x = -611
+    a.c1 = '&'
+    a.c2 = '*'
+    a.c3 = '#'
     a.y = 0
     descriptor_init()
     perform_transaction(llhelper(CALLBACK, callback2),
                         rffi.cast(rffi.VOIDP, a))
     descriptor_done()
     assert a.x == 420
+    assert a.c1 == '('
+    assert a.c2 == '?'
+    assert a.c3 == ')'
     lltype.free(a, flavor='raw')
 
 # ____________________________________________________________
@@ -59,16 +94,23 @@
 from pypy.translator.translator import TranslationContext
 from pypy.annotation.listdef import s_list_of_strings
 from pypy.translator.c.genc import CStandaloneBuilder
+from pypy.translator.tool.cbuild import ExternalCompilationInfo
 
 class StmTests(object):
     config = None
 
     def compile(self, entry_point):
         t = TranslationContext(self.config)
+        t.config.translation.gc = 'boehm'
         t.buildannotator().build_types(entry_point, [s_list_of_strings])
         t.buildrtyper().specialize()
         cbuilder = CStandaloneBuilder(t, entry_point, t.config)
-        cbuilder.generate_source(defines=cbuilder.DEBUG_DEFINES)
+        force_debug = ExternalCompilationInfo(pre_include_bits=[
+            "#define RPY_ASSERT 1\n"
+            "#define RPY_LL_ASSERT 1\n"
+            ])
+        cbuilder.eci = cbuilder.eci.merge(force_debug)
+        cbuilder.generate_source()
         cbuilder.compile()
         return t, cbuilder
 


More information about the pypy-commit mailing list