Author: Remi Meier <meier...@student.ethz.ch> Branch: stmgc-c4 Changeset: r65189:4820d8ea75ff Date: 2013-07-05 08:20 +0200 http://bitbucket.org/pypy/pypy/changeset/4820d8ea75ff/
Log: getting tests to run with questionable methods diff --git a/rpython/jit/backend/llsupport/gc.py b/rpython/jit/backend/llsupport/gc.py --- a/rpython/jit/backend/llsupport/gc.py +++ b/rpython/jit/backend/llsupport/gc.py @@ -493,11 +493,11 @@ def _setup_barriers_for_stm(self): from rpython.memory.gc import stmgc WBDescr = WriteBarrierDescr - self.P2Rdescr = WBDescr(self, (stmgc.GCFLAG_GLOBAL, 'P2R', + self.P2Rdescr = WBDescr(self, (0, 'P2R', 'stm_DirectReadBarrier')) - self.P2Wdescr = WBDescr(self, (stmgc.GCFLAG_NOT_WRITTEN, 'P2W', + self.P2Wdescr = WBDescr(self, (0, 'P2W', 'stm_WriteBarrier')) - self.R2Wdescr = WBDescr(self, (stmgc.GCFLAG_NOT_WRITTEN, 'R2W', + self.R2Wdescr = WBDescr(self, (0, 'R2W', 'stm_WriteBarrierFromReady')) self.write_barrier_descr = "wbdescr: do not use" # diff --git a/rpython/jit/backend/llsupport/test/test_rewrite.py b/rpython/jit/backend/llsupport/test/test_rewrite.py --- a/rpython/jit/backend/llsupport/test/test_rewrite.py +++ b/rpython/jit/backend/llsupport/test/test_rewrite.py @@ -35,6 +35,7 @@ tdescr = get_size_descr(self.gc_ll_descr, T) tdescr.tid = 5678 tzdescr = get_field_descr(self.gc_ll_descr, T, 'z') + tydescr = get_field_descr(self.gc_ll_descr, T, 'y') # A = lltype.GcArray(lltype.Signed) adescr = get_array_descr(self.gc_ll_descr, A) diff --git a/rpython/jit/backend/llsupport/test/test_stmrewrite.py b/rpython/jit/backend/llsupport/test/test_stmrewrite.py --- a/rpython/jit/backend/llsupport/test/test_stmrewrite.py +++ b/rpython/jit/backend/llsupport/test/test_stmrewrite.py @@ -1,8 +1,9 @@ from rpython.jit.backend.llsupport.descr import * from rpython.jit.backend.llsupport.gc import * from rpython.jit.metainterp.gc import get_description -from rpython.jit.backend.llsupport.test.test_rewrite import RewriteTests - +from rpython.jit.backend.llsupport.test.test_rewrite import ( + RewriteTests, BaseFakeCPU) +from rpython.rtyper.lltypesystem import lltype, rclass, rffi, llmemory class TestStm(RewriteTests): def setup_method(self, meth): @@ -17,11 +18,12 @@ self.gc_ll_descr = GcLLDescr_framework(gcdescr, None, None, None, really_not_translated=True) # - class FakeCPU(object): + class FakeCPU(BaseFakeCPU): def sizeof(self, STRUCT): descr = SizeDescrWithVTable(104) descr.tid = 9315 return descr + self.cpu = FakeCPU() def check_rewrite(self, frm_operations, to_operations, **namespace): @@ -48,6 +50,8 @@ """) def test_rewrite_setfield_gc_const(self): + TP = lltype.GcArray(lltype.Signed) + NULL = lltype.cast_opaque_ptr(llmemory.GCREF, lltype.nullptr(TP)) self.check_rewrite(""" [p1, p2] setfield_gc(ConstPtr(t), p2, descr=tzdescr) @@ -58,7 +62,7 @@ cond_call_gc_wb(p3, 0, descr=P2Wdescr) setfield_gc(p3, p2, descr=tzdescr) jump() - """) + """, t=NULL) def test_rewrite_setfield_gc_on_local(self): self.check_rewrite(""" @@ -164,6 +168,8 @@ """) def test_rewrite_getfield_gc_const(self): + TP = lltype.GcArray(lltype.Signed) + NULL = lltype.cast_opaque_ptr(llmemory.GCREF, lltype.nullptr(TP)) self.check_rewrite(""" [p1] p2 = getfield_gc(ConstPtr(t), descr=tzdescr) @@ -174,7 +180,7 @@ cond_call_gc_wb(p3, 0, descr=P2Rdescr) p2 = getfield_gc(p3, descr=tzdescr) jump(p2) - """) + """, t=NULL) # XXX could do better: G2Rdescr def test_rewrite_getarrayitem_gc(self): @@ -300,62 +306,62 @@ def test_getfield_raw(self): self.check_rewrite(""" [i1, i2] - i3 = getfield_raw(i1, descr=?) + i3 = getfield_raw(i1, descr=<?) keepalive(i3) # random ignored operation - i4 = getfield_raw(i2, descr=?) + i4 = getfield_raw(i2, descr=<?) jump(i3, i4) """, """ [i1, i2] $INEV - i3 = getfield_raw(i1, descr=?) + i3 = getfield_raw(i1, descr=<?) keepalive(i3) - i4 = getfield_raw(i2, descr=?) + i4 = getfield_raw(i2, descr=<?) jump(i3, i4) """) def test_getfield_raw_over_label(self): self.check_rewrite(""" [i1, i2] - i3 = getfield_raw(i1, descr=?) + i3 = getfield_raw(i1, descr=<?) label(i1, i2, i3) - i4 = getfield_raw(i2, descr=?) + i4 = getfield_raw(i2, descr=<?) jump(i3, i4) """, """ [i1, i2] $INEV - i3 = getfield_raw(i1, descr=?) + i3 = getfield_raw(i1, descr=<?) label(i1, i2, i3) $INEV - i4 = getfield_raw(i2, descr=?) + i4 = getfield_raw(i2, descr=<?) jump(i3, i4) """) def test_getarrayitem_raw(self): self.check_rewrite(""" [i1, i2] - i3 = getarrayitem_raw(i1, 5, descr=?) - i4 = getarrayitem_raw(i2, i3, descr=?) + i3 = getarrayitem_raw(i1, 5, descr=<?) + i4 = getarrayitem_raw(i2, i3, descr=<?) jump(i3, i4) """, """ [i1, i2] $INEV - i3 = getarrayitem_raw(i1, 5, descr=?) - i4 = getarrayitem_raw(i2, i3, descr=?) + i3 = getarrayitem_raw(i1, 5, descr=<?) + i4 = getarrayitem_raw(i2, i3, descr=<?) jump(i3, i4) """) def test_rewrite_unrelated_setarrayitem_gcs(self): self.check_rewrite(""" [p1, i1, p2, p3, i3, p4] - setarrayitem_gc(p1, i1, p2, descr=?) - setarrayitem_gc(p3, i3, p4, descr=?) + setarrayitem_gc(p1, i1, p2, descr=<?) + setarrayitem_gc(p3, i3, p4, descr=<?) jump() """, """ [p1, i1, p2, p3, i3, p4] cond_call_gc_wb(p1, 0, descr=P2Wdescr) - setarrayitem_gc(p1, i1, p2, descr=?) + setarrayitem_gc(p1, i1, p2, descr=<?) cond_call_gc_wb(p3, 0, descr=P2Wdescr) - setarrayitem_gc(p3, i3, p4, descr=?) + setarrayitem_gc(p3, i3, p4, descr=<?) jump() """) @@ -408,10 +414,12 @@ "that p1 is already a W") def test_fallback_to_inevitable(self): + T = rffi.CArrayPtr(rffi.TIME_T) + calldescr2 = get_call_descr(self.gc_ll_descr, [T], rffi.TIME_T) oplist = [ - "setfield_raw(i1, i2, descr=?)", - "setarrayitem_raw(i1, i2, i3, descr=?)", - "setinteriorfield_raw(i1, i2, i3, descr=?)", + "setfield_raw(i1, i2, descr=<?)", + "setarrayitem_raw(i1, i2, i3, descr=<?)", + "setinteriorfield_raw(i1, i2, i3, descr=<?)", "call_release_gil(123, descr=calldescr2)", "escape(i1)", # a generic unknown operation ] @@ -431,7 +439,7 @@ cond_call_gc_wb(p7, 0, descr=P2Wdescr) setfield_gc(p7, 20, descr=tydescr) jump(i2, p7) - """ % op) + """ % op, calldescr2=calldescr2) def test_copystrcontent(self): self.check_rewrite(""" @@ -468,8 +476,10 @@ """ % op) def test_call_force(self): + T = rffi.CArrayPtr(rffi.TIME_T) + calldescr2 = get_call_descr(self.gc_ll_descr, [T], rffi.TIME_T) for op in ["call(123, descr=calldescr2)", - "call_assembler(123, descr=loopdescr)", + "call_assembler(123, descr=casmdescr)", "call_may_force(123, descr=calldescr2)", "call_loopinvariant(123, descr=calldescr2)", ]: @@ -487,7 +497,7 @@ cond_call_gc_wb(p1, 0, descr=P2Wdescr) setfield_gc(p1, 20, descr=tydescr) jump(p1) - """ % op) + """ % op, calldescr2=calldescr2) def test_ptr_eq_null(self): self.check_rewrite(""" 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 @@ -8,6 +8,27 @@ from rpython.rtyper.lltypesystem import rffi from rpython.rtyper.lltypesystem.lloperation import llop from rpython.rlib.debug import ll_assert +from rpython.rlib.rarithmetic import LONG_BIT, r_uint + +WORD = LONG_BIT // 8 +NULL = llmemory.NULL + +# keep in sync with stmgc.h & et.h: +first_gcflag = 1 << (LONG_BIT//2) +GCFLAG_OLD = first_gcflag << 0 +GCFLAG_VISITED = first_gcflag << 1 +GCFLAG_PUBLIC = first_gcflag << 2 +GCFLAG_PREBUILT_ORIGINAL = first_gcflag << 3 +GCFLAG_PUBLIC_TO_PRIVATE = first_gcflag << 4 +GCFLAG_WRITE_BARRIER = first_gcflag << 5 # stmgc.h +GCFLAG_NURSERY_MOVED = first_gcflag << 6 +GCFLAG_BACKUP_COPY = first_gcflag << 7 # debug +GCFLAG_STUB = first_gcflag << 8 # debug +GCFLAG_PRIVATE_FROM_PROTECTED = first_gcflag << 9 +GCFLAG_HAS_ID = first_gcflag << 10 + +PREBUILT_FLAGS = first_gcflag * (1 + 2 + 4 + 8) +PREBUILT_REVISION = r_uint(1) class StmGC(MovingGCBase): diff --git a/rpython/translator/stm/src_stm/fprintcolor.c b/rpython/translator/stm/src_stm/fprintcolor.c --- a/rpython/translator/stm/src_stm/fprintcolor.c +++ b/rpython/translator/stm/src_stm/fprintcolor.c @@ -6,7 +6,7 @@ { va_list ap; -#ifdef _GC_DEBUG +#ifdef _GC_DEBUGPRINTS dprintf(("STM Subsystem: Fatal Error\n")); #else fprintf(stderr, "STM Subsystem: Fatal Error\n"); @@ -20,7 +20,7 @@ } -#ifdef _GC_DEBUG +#ifdef _GC_DEBUGPRINTS static __thread revision_t tcolor = 0; static revision_t tnextid = 0; diff --git a/rpython/translator/stm/src_stm/fprintcolor.h b/rpython/translator/stm/src_stm/fprintcolor.h --- a/rpython/translator/stm/src_stm/fprintcolor.h +++ b/rpython/translator/stm/src_stm/fprintcolor.h @@ -7,7 +7,7 @@ __attribute__((format (printf, 1, 2), noreturn)); -#ifdef _GC_DEBUG +#ifdef _GC_DEBUGPRINTS #define dprintf(args) threadcolor_printf args int dprintfcolor(void); diff --git a/rpython/translator/stm/src_stm/gcpage.c b/rpython/translator/stm/src_stm/gcpage.c --- a/rpython/translator/stm/src_stm/gcpage.c +++ b/rpython/translator/stm/src_stm/gcpage.c @@ -213,6 +213,29 @@ static struct GcPtrList objects_to_trace; +static void keep_original_alive(gcptr obj) +{ + /* keep alive the original of a visited object */ + gcptr id_copy = (gcptr)obj->h_original; + /* prebuilt original objects may have a predifined + hash in h_original */ + if (id_copy && !(obj->h_tid & GCFLAG_PREBUILT_ORIGINAL)) { + if (!(id_copy->h_tid & GCFLAG_PREBUILT_ORIGINAL)) { + id_copy->h_tid &= ~GCFLAG_PUBLIC_TO_PRIVATE; + /* see fix_outdated() */ + id_copy->h_tid |= GCFLAG_VISITED; + + /* XXX: may not always need tracing? */ + gcptrlist_insert(&objects_to_trace, id_copy); + } + else { + /* prebuilt originals won't get collected anyway + and if they are not reachable in any other way, + we only ever need their location, not their content */ + } + } +} + static void visit(gcptr *pobj) { gcptr obj = *pobj; @@ -227,6 +250,8 @@ obj->h_tid &= ~GCFLAG_PUBLIC_TO_PRIVATE; /* see fix_outdated() */ obj->h_tid |= GCFLAG_VISITED; gcptrlist_insert(&objects_to_trace, obj); + + keep_original_alive(obj); } } else if (obj->h_tid & GCFLAG_PUBLIC) { @@ -247,6 +272,8 @@ obj = (gcptr)(obj->h_revision - 2); if (!(obj->h_tid & GCFLAG_PUBLIC)) { prev_obj->h_tid |= GCFLAG_VISITED; + keep_original_alive(prev_obj); + assert(*pobj == prev_obj); gcptr obj1 = obj; visit(&obj1); /* recursion, but should be only once */ @@ -257,6 +284,9 @@ } if (!(obj->h_revision & 3)) { + /* obj is neither a stub nor a most recent revision: + completely ignore obj->h_revision */ + obj = (gcptr)obj->h_revision; assert(obj->h_tid & GCFLAG_PUBLIC); prev_obj->h_revision = (revision_t)obj; @@ -275,7 +305,14 @@ assert(obj->h_tid & GCFLAG_PRIVATE_FROM_PROTECTED); gcptr B = (gcptr)obj->h_revision; assert(B->h_tid & (GCFLAG_PUBLIC | GCFLAG_BACKUP_COPY)); - + + if (obj->h_original && (gcptr)obj->h_original != B) { + /* if B is original, it will be visited anyway */ + assert(obj->h_original == B->h_original); + assert(!(obj->h_tid & GCFLAG_PREBUILT_ORIGINAL)); + keep_original_alive(obj); + } + obj->h_tid |= GCFLAG_VISITED; B->h_tid |= GCFLAG_VISITED; assert(!(obj->h_tid & GCFLAG_STUB)); @@ -294,6 +331,7 @@ } } + static void visit_keep(gcptr obj) { if (!(obj->h_tid & GCFLAG_VISITED)) { @@ -305,6 +343,7 @@ assert(!(obj->h_revision & 2)); visit((gcptr *)&obj->h_revision); } + keep_original_alive(obj); } } @@ -376,8 +415,24 @@ outdated, it will be found at that time */ gcptr R = item->addr; gcptr L = item->val; + + /* Objects that were not visited yet must have the PUB_TO_PRIV + flag. Except if that transaction will abort anyway, then it + may be removed from a previous major collection that didn't + fix the PUB_TO_PRIV because the transaction was going to + abort anyway: + 1. minor_collect before major collect (R->L, R is outdated, abort) + 2. major collect removes flag + 3. major collect again, same thread, no time to abort + 4. flag still removed + */ + assert(IMPLIES(!(R->h_tid & GCFLAG_VISITED) && d->active > 0, + R->h_tid & GCFLAG_PUBLIC_TO_PRIVATE)); visit_keep(R); if (L != NULL) { + /* minor collection found R->L in public_to_young + and R was modified. It then sets item->val to NULL and wants + to abort later. */ revision_t v = L->h_revision; visit_keep(L); /* a bit of custom logic here: if L->h_revision used to @@ -385,8 +440,10 @@ keep this property, even though visit_keep(L) might decide it would be better to make it point to a more recent copy. */ - if (v == (revision_t)R) + if (v == (revision_t)R) { + assert(L->h_tid & GCFLAG_PRIVATE_FROM_PROTECTED); L->h_revision = v; /* restore */ + } } } G2L_LOOP_END; @@ -449,6 +506,7 @@ just removing it is very wrong --- we want 'd' to abort. */ if (obj->h_tid & GCFLAG_PRIVATE_FROM_PROTECTED) { + /* follow obj to its backup */ assert(IS_POINTER(obj->h_revision)); obj = (gcptr)obj->h_revision; } @@ -483,14 +541,16 @@ /* We are now after visiting all objects, and we know the * transaction isn't aborting because of this collection. We have * cleared GCFLAG_PUBLIC_TO_PRIVATE from public objects at the end - * of the chain. Now we have to set it again on public objects that - * have a private copy. + * of the chain (head revisions). Now we have to set it again on + * public objects that have a private copy. */ wlog_t *item; dprintf(("fix public_to_private on thread %p\n", d)); G2L_LOOP_FORWARD(d->public_to_private, item) { + assert(item->addr->h_tid & GCFLAG_VISITED); + assert(item->val->h_tid & GCFLAG_VISITED); assert(item->addr->h_tid & GCFLAG_PUBLIC); /* assert(is_private(item->val)); but in the other thread, diff --git a/rpython/translator/stm/src_stm/nursery.c b/rpython/translator/stm/src_stm/nursery.c --- a/rpython/translator/stm/src_stm/nursery.c +++ b/rpython/translator/stm/src_stm/nursery.c @@ -45,7 +45,12 @@ void stmgc_done_nursery(void) { struct tx_descriptor *d = thread_descriptor; - assert(!minor_collect_anything_to_do(d)); + /* someone may have called minor_collect_soon() + inbetween the preceeding minor_collect() and + this assert (committransaction() -> + updatechainheads() -> stub_malloc() -> ...): */ + assert(!minor_collect_anything_to_do(d) + || d->nursery_current == d->nursery_end); stm_free(d->nursery_base, GC_NURSERY); gcptrlist_delete(&d->old_objects_to_trace); @@ -262,7 +267,7 @@ return fresh_old_copy; } -inline void copy_to_old_id_copy(gcptr obj, gcptr id) +void copy_to_old_id_copy(gcptr obj, gcptr id) { assert(!is_in_nursery(thread_descriptor, id)); assert(id->h_tid & GCFLAG_OLD); @@ -315,6 +320,7 @@ *root = fresh_old_copy; /* add 'fresh_old_copy' to the list of objects to trace */ + assert(!(fresh_old_copy->h_tid & GCFLAG_PUBLIC)); gcptrlist_insert(&d->old_objects_to_trace, fresh_old_copy); } } @@ -426,6 +432,7 @@ gcptr P = items[i]; assert(P->h_tid & GCFLAG_PUBLIC); assert(P->h_tid & GCFLAG_OLD); + assert(P->h_tid & GCFLAG_PUBLIC_TO_PRIVATE); revision_t v = ACCESS_ONCE(P->h_revision); wlog_t *item; @@ -474,7 +481,18 @@ assert(obj->h_tid & GCFLAG_OLD); assert(!(obj->h_tid & GCFLAG_WRITE_BARRIER)); - obj->h_tid |= GCFLAG_WRITE_BARRIER; + + /* We add the WRITE_BARRIER flag to objects here, but warning: + we may occasionally see a PUBLIC object --- one that was + a private/protected object when it was added to + old_objects_to_trace, and has been stolen. So we have to + check and not do any change the obj->h_tid in that case. + Otherwise this conflicts with the rule that we may only + modify obj->h_tid of a public object in order to add + PUBLIC_TO_PRIVATE. + */ + if (!(obj->h_tid & GCFLAG_PUBLIC)) + obj->h_tid |= GCFLAG_WRITE_BARRIER; stmgc_trace(obj, &visit_if_young); } @@ -672,6 +690,7 @@ gcptr P = stmgcpage_malloc(allocate_size); memset(P, 0, allocate_size); P->h_tid = tid | GCFLAG_OLD; + assert(!(P->h_tid & GCFLAG_PUBLIC)); gcptrlist_insert(&d->old_objects_to_trace, P); return P; } diff --git a/rpython/translator/stm/src_stm/revision b/rpython/translator/stm/src_stm/revision --- a/rpython/translator/stm/src_stm/revision +++ b/rpython/translator/stm/src_stm/revision @@ -1,1 +1,1 @@ -637f6c9d19f7 +38fcfb8212e2 diff --git a/rpython/translator/stm/src_stm/steal.c b/rpython/translator/stm/src_stm/steal.c --- a/rpython/translator/stm/src_stm/steal.c +++ b/rpython/translator/stm/src_stm/steal.c @@ -2,7 +2,7 @@ #include "stmimpl.h" -inline void copy_to_old_id_copy(gcptr obj, gcptr id); +void copy_to_old_id_copy(gcptr obj, gcptr id); gcptr stm_stub_malloc(struct tx_public_descriptor *pd) { @@ -254,6 +254,7 @@ for (i = 0; i < size; i += 2) { gcptr B = items[i]; assert(!(B->h_tid & GCFLAG_BACKUP_COPY)); /* already removed */ + assert(B->h_tid & GCFLAG_PUBLIC); /* to be on the safe side --- but actually needed, see the gcptrlist_insert2(L, NULL) above */ @@ -265,6 +266,7 @@ assert(L->h_tid & GCFLAG_PRIVATE_FROM_PROTECTED); assert(IS_POINTER(L->h_revision)); + assert(B->h_tid & GCFLAG_PUBLIC_TO_PRIVATE); g2l_insert(&d->public_to_private, B, L); /* this is definitely needed: all keys in public_to_private diff --git a/rpython/translator/stm/src_stm/stmsync.c b/rpython/translator/stm/src_stm/stmsync.c --- a/rpython/translator/stm/src_stm/stmsync.c +++ b/rpython/translator/stm/src_stm/stmsync.c @@ -81,6 +81,7 @@ int stm_enter_callback_call(void) { int token = (thread_descriptor == NULL); + dprintf(("enter_callback_call(tok=%d)\n", token)); if (token == 1) { stmgcpage_acquire_global_lock(); DescriptorInit(); @@ -94,6 +95,7 @@ void stm_leave_callback_call(int token) { + dprintf(("leave_callback_call(%d)\n", token)); if (token == 1) stmgc_minor_collect(); /* force everything out of the nursery */ diff --git a/rpython/translator/stm/test/test_stmgcintf.c b/rpython/translator/stm/test/test_stmgcintf.c --- a/rpython/translator/stm/test/test_stmgcintf.c +++ b/rpython/translator/stm/test/test_stmgcintf.c @@ -11,6 +11,7 @@ struct pypy_header0 { long h_tid; Unsigned h_revision; + Unsigned h_original; }; struct pypy_pypy_rlib_rstm_Transaction0 { @@ -33,7 +34,8 @@ #define _RPyString_AsString(x) x #define RPyString_Size(x) strlen(x) - +#include "src_stm/stmgc.h" +#include "src_stm/stmimpl.h" #include "src_stm/et.h" #include "src_stm/et.c" _______________________________________________ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit