Author: Armin Rigo <[email protected]>
Branch: copy-over-original2
Changeset: r449:e35685ae86d0
Date: 2013-07-26 12:28 +0200
http://bitbucket.org/pypy/stmgc/changeset/e35685ae86d0/
Log: Make two flags: VISITED vs MARKED. See doc in et.h.
diff --git a/c4/et.h b/c4/et.h
--- a/c4/et.h
+++ b/c4/et.h
@@ -25,7 +25,11 @@
*
* GCFLAG_OLD is set on old objects.
*
- * GCFLAG_VISITED is used temporarily during major collections.
+ * GCFLAG_VISITED and GCFLAG_MARKED are used temporarily during major
+ * collections. The objects are MARKED|VISITED as soon as they have been
+ * added to 'objects_to_trace', and so will be or have been traced. The
+ * objects are only MARKED if their memory must be kept alive, but (so far)
+ * we found that tracing them is not useful.
*
* GCFLAG_PUBLIC is set on public objects.
*
@@ -74,10 +78,12 @@
static const revision_t GCFLAG_HAS_ID = STM_FIRST_GCFLAG << 10;
static const revision_t GCFLAG_IMMUTABLE = STM_FIRST_GCFLAG << 11;
static const revision_t GCFLAG_SMALLSTUB = STM_FIRST_GCFLAG << 12;
+static const revision_t GCFLAG_MARKED = STM_FIRST_GCFLAG << 13;
/* this value must be reflected in PREBUILT_FLAGS in stmgc.h */
#define GCFLAG_PREBUILT (GCFLAG_VISITED | \
+ GCFLAG_MARKED | \
GCFLAG_PREBUILT_ORIGINAL | \
GCFLAG_OLD | \
GCFLAG_PUBLIC)
@@ -88,12 +94,14 @@
"PREBUILT_ORIGINAL", \
"PUBLIC_TO_PRIVATE", \
"WRITE_BARRIER", \
- "MOVED", \
+ "MOVED", \
"BACKUP_COPY", \
"STUB", \
"PRIVATE_FROM_PROTECTED", \
- "HAS_ID", \
- "IMMUTABLE", \
+ "HAS_ID", \
+ "IMMUTABLE", \
+ "SMALLSTUB", \
+ "MARKED", \
NULL }
#define IS_POINTER(v) (!((v) & 1)) /* even-valued number */
diff --git a/c4/gcpage.c b/c4/gcpage.c
--- a/c4/gcpage.c
+++ b/c4/gcpage.c
@@ -276,8 +276,12 @@
if (obj->h_tid & GCFLAG_VISITED)
return; /* already visited */
- obj->h_tid |= GCFLAG_VISITED;
+ obj->h_tid |= GCFLAG_VISITED | GCFLAG_MARKED;
gcptrlist_insert2(&objects_to_trace, obj, (gcptr)gcp);
+
+ obj = (gcptr)obj->h_original;
+ if (obj != NULL)
+ obj->h_tid |= GCFLAG_MARKED;
}
static gcptr visit_public(gcptr obj, struct tx_public_descriptor *gcp)
@@ -369,7 +373,7 @@
copy_over_original(obj, original);
/* return this original */
- original->h_tid |= GCFLAG_VISITED;
+ original->h_tid |= GCFLAG_VISITED | GCFLAG_MARKED;
if (!(original->h_tid & GCFLAG_STUB))
gcptrlist_insert2(&objects_to_trace, original, NULL);
return original;
@@ -426,13 +430,15 @@
contains all the ones that have been modified. Because they are
themselves not in any page managed by this file, their
GCFLAG_VISITED is not removed at the end of the current
- collection. That's why we remove it here. */
+ collection. That's why we remove it here. GCFLAG_MARKED is not
+ relevant for prebuilt objects, but we avoid objects with MARKED
+ but not VISITED, which trigger some asserts. */
gcptr *pobj = stm_prebuilt_gcroots.items;
gcptr *pend = stm_prebuilt_gcroots.items + stm_prebuilt_gcroots.size;
gcptr obj, obj2;
for (; pobj != pend; pobj++) {
obj = *pobj;
- obj->h_tid &= ~GCFLAG_VISITED;
+ obj->h_tid &= ~(GCFLAG_VISITED | GCFLAG_MARKED);
assert(obj->h_tid & GCFLAG_PREBUILT_ORIGINAL);
obj2 = visit_public(obj, NULL);
@@ -680,7 +686,9 @@
and the flag is removed; other locations are marked as free. */
p = (gcptr)(lpage + 1);
for (j = 0; j < objs_per_page; j++) {
- if (p->h_tid & GCFLAG_VISITED)
+ assert(IMPLIES(p->h_tid & GCFLAG_VISITED,
+ p->h_tid & GCFLAG_MARKED));
+ if (p->h_tid & GCFLAG_MARKED)
break; /* first object that stays alive */
p = (gcptr)(((char *)p) + obj_size);
}
@@ -690,8 +698,10 @@
surviving_pages = lpage;
p = (gcptr)(lpage + 1);
for (j = 0; j < objs_per_page; j++) {
- if (p->h_tid & GCFLAG_VISITED) {
- p->h_tid &= ~GCFLAG_VISITED;
+ assert(IMPLIES(p->h_tid & GCFLAG_VISITED,
+ p->h_tid & GCFLAG_MARKED));
+ if (p->h_tid & GCFLAG_MARKED) {
+ p->h_tid &= ~(GCFLAG_VISITED | GCFLAG_MARKED);
mc_total_in_use += obj_size;
}
else {
@@ -717,6 +727,7 @@
p = (gcptr)(lpage + 1);
for (j = 0; j < objs_per_page; j++) {
assert(!(p->h_tid & GCFLAG_VISITED));
+ assert(!(p->h_tid & GCFLAG_MARKED));
if (p->h_tid != DEBUG_WORD(0xDD)) {
dprintf(("| freeing %p (with page %p)\n", p, lpage));
}
@@ -746,8 +757,10 @@
G2L_LOOP_FORWARD(gcp->nonsmall_objects, item) {
gcptr p = item->addr;
- if (p->h_tid & GCFLAG_VISITED) {
- p->h_tid &= ~GCFLAG_VISITED;
+ assert(IMPLIES(p->h_tid & GCFLAG_VISITED,
+ p->h_tid & GCFLAG_MARKED));
+ if (p->h_tid & GCFLAG_MARKED) {
+ p->h_tid &= ~(GCFLAG_VISITED | GCFLAG_MARKED);
}
else {
G2L_LOOP_DELETE(item);
diff --git a/c4/stmgc.h b/c4/stmgc.h
--- a/c4/stmgc.h
+++ b/c4/stmgc.h
@@ -23,7 +23,8 @@
#define STM_SIZE_OF_USER_TID (sizeof(revision_t) / 2) /* in bytes */
#define STM_FIRST_GCFLAG (1L << (8 * STM_SIZE_OF_USER_TID))
#define STM_USER_TID_MASK (STM_FIRST_GCFLAG - 1)
-#define PREBUILT_FLAGS (STM_FIRST_GCFLAG * (1 + 2 + 4 + 8))
+#define PREBUILT_FLAGS (STM_FIRST_GCFLAG * ((1<<0) | (1<<1) | \
+ (1<<2) | (1<<3) | (1<<13)))
#define PREBUILT_REVISION 1
diff --git a/c4/test/test_extra.py b/c4/test/test_extra.py
--- a/c4/test/test_extra.py
+++ b/c4/test/test_extra.py
@@ -104,7 +104,7 @@
assert ffi.string(c).endswith("ei424242ee")
def test_pointer_equal():
- p = palloc(HDR)
+ p = palloc(HDR + WORD)
assert lib.stm_pointer_equal(p, p)
assert not lib.stm_pointer_equal(p, ffi.NULL)
assert not lib.stm_pointer_equal(ffi.NULL, p)
diff --git a/c4/test/test_gcpage.py b/c4/test/test_gcpage.py
--- a/c4/test/test_gcpage.py
+++ b/c4/test/test_gcpage.py
@@ -511,3 +511,24 @@
#
major_collect()
check_free_old(p1)
+
+def test_keep_original_alive():
+ p2 = oalloc(HDR + WORD); make_public(p2)
+ p2b = lib.stm_write_barrier(p2)
+ lib.stm_push_root(p2)
+ minor_collect()
+ p2 = lib.stm_pop_root()
+ p2b = lib.stm_write_barrier(p2)
+ assert not lib.in_nursery(p2)
+ assert not lib.in_nursery(p2b)
+ lib.stm_commit_transaction()
+ lib.stm_begin_inevitable_transaction()
+ assert classify(p2) == "public"
+ assert classify(p2b) == "protected"
+ assert ffi.cast("gcptr", p2b.h_original) == p2
+ lib.stm_push_root(p2b)
+ major_collect()
+ p2c = lib.stm_pop_root()
+ check_not_free(ffi.cast("gcptr", p2c.h_original))
+ assert p2c == p2b
+ assert ffi.cast("gcptr", p2c.h_original) == p2
diff --git a/c4/test/test_nursery.py b/c4/test/test_nursery.py
--- a/c4/test/test_nursery.py
+++ b/c4/test/test_nursery.py
@@ -279,7 +279,7 @@
assert classify(p2) == "private"
def test_new_version():
- p1 = oalloc(HDR)
+ p1 = oalloc(HDR + WORD)
assert lib.stm_write_barrier(p1) == p1
lib.stm_push_root(p1)
transaction_break()
@@ -300,7 +300,7 @@
assert classify(p2) == "private_from_protected"
def test_prebuilt_version():
- p1 = lib.pseudoprebuilt(HDR, 42 + HDR)
+ p1 = lib.pseudoprebuilt(HDR + WORD, 42 + HDR + WORD)
p2 = lib.stm_write_barrier(p1)
assert p2 != p1
check_prebuilt(p1)
diff --git a/c4/weakref.c b/c4/weakref.c
--- a/c4/weakref.c
+++ b/c4/weakref.c
@@ -68,49 +68,25 @@
static _Bool is_partially_visited(gcptr obj)
{
- /* Based on gcpage.c:visit(). Check the code here if we simplify
- visit(). Returns True or False depending on whether we find any
+ /* Based on gcpage.c:visit_public(). Check the code here if we change
+ visit_public(). Returns True or False depending on whether we find any
version of 'obj' to be VISITED or not.
*/
- restart:
+ assert(IMPLIES(obj->h_tid & GCFLAG_VISITED,
+ obj->h_tid & GCFLAG_MARKED));
if (obj->h_tid & GCFLAG_VISITED)
return 1;
- if (obj->h_revision & 1) {
- assert(!(obj->h_tid & GCFLAG_PRIVATE_FROM_PROTECTED));
- assert(!(obj->h_tid & GCFLAG_STUB));
+ if (!(obj->h_tid & GCFLAG_PUBLIC))
return 0;
- }
- else if (obj->h_tid & GCFLAG_PUBLIC) {
- /* h_revision is a ptr: we have a more recent version */
- if (!(obj->h_revision & 2)) {
- /* go visit the more recent version */
- obj = (gcptr)obj->h_revision;
- }
- else {
- /* it's a stub */
- assert(obj->h_tid & GCFLAG_STUB);
- obj = (gcptr)(obj->h_revision - 2);
- }
- goto restart;
- }
- else {
- assert(obj->h_tid & GCFLAG_PRIVATE_FROM_PROTECTED);
- gcptr B = (gcptr)obj->h_revision;
- assert(B->h_tid & (GCFLAG_PUBLIC | GCFLAG_BACKUP_COPY));
- if (B->h_tid & GCFLAG_VISITED)
+
+ if (obj->h_original != 0 &&
+ !(obj->h_tid & GCFLAG_PREBUILT_ORIGINAL)) {
+ gcptr original = (gcptr)obj->h_original;
+ assert(IMPLIES(original->h_tid & GCFLAG_VISITED,
+ original->h_tid & GCFLAG_MARKED));
+ if (original->h_tid & GCFLAG_MARKED)
return 1;
- assert(!(obj->h_tid & GCFLAG_STUB));
- assert(!(B->h_tid & GCFLAG_STUB));
-
- if (IS_POINTER(B->h_revision)) {
- assert(B->h_tid & GCFLAG_PUBLIC);
- assert(!(B->h_tid & GCFLAG_BACKUP_COPY));
- assert(!(B->h_revision & 2));
-
- obj = (gcptr)B->h_revision;
- goto restart;
- }
}
return 0;
}
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit