Author: Remi Meier <[email protected]>
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
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit