Author: Armin Rigo <ar...@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 _______________________________________________ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit