[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