[pypy-commit] stmgc card-marking: fixes
Raemi
noreply at buildbot.pypy.org
Tue May 20 14:29:49 CEST 2014
Author: Remi Meier <remi.meier at inf.ethz.ch>
Branch: card-marking
Changeset: r1219:a290c9b39ef9
Date: 2014-05-20 14:30 +0200
http://bitbucket.org/pypy/stmgc/changeset/a290c9b39ef9/
Log: fixes
diff --git a/c7/stm/core.c b/c7/stm/core.c
--- a/c7/stm/core.c
+++ b/c7/stm/core.c
@@ -42,6 +42,9 @@
static void _stm_mark_card(object_t *obj, uintptr_t card_index)
{
+ assert(card_index > 0);
+ dprintf(("mark %p card %lu\n", obj, card_index));
+
if (!(obj->stm_flags & GCFLAG_CARDS_SET)) {
/* not yet in the list */
if (STM_PSEGMENT->old_objects_with_cards) {
@@ -56,8 +59,11 @@
to know what may have changed.
We already own the object here or it is an overflow obj. */
uintptr_t card_lock_idx = get_write_lock_idx((uintptr_t)obj) + card_index;
+
assert(write_locks[card_lock_idx] == 0
|| write_locks[card_lock_idx] == STM_PSEGMENT->write_lock_num);
+ assert(get_write_lock_idx((uintptr_t)obj) != card_lock_idx);
+
if (!write_locks[card_lock_idx])
write_locks[card_lock_idx] = STM_PSEGMENT->write_lock_num;
}
@@ -175,7 +181,8 @@
}
}
else if (write_locks[base_lock_idx] == lock_num) {
- OPT_ASSERT(STM_PSEGMENT->objects_pointing_to_nursery != NULL);
+ assert(IMPLY(!(obj->stm_flags & GCFLAG_CARDS_SET),
+ STM_PSEGMENT->objects_pointing_to_nursery != NULL));
#ifdef STM_TESTS
bool found = false;
LIST_FOREACH_R(STM_PSEGMENT->modified_old_objects, object_t *,
diff --git a/c7/stm/misc.c b/c7/stm/misc.c
--- a/c7/stm/misc.c
+++ b/c7/stm/misc.c
@@ -67,6 +67,13 @@
return list_count(STM_PSEGMENT->objects_pointing_to_nursery);
}
+long _stm_count_old_objects_with_cards(void)
+{
+ if (STM_PSEGMENT->old_objects_with_cards == NULL)
+ return -1;
+ return list_count(STM_PSEGMENT->old_objects_with_cards);
+}
+
object_t *_stm_enum_modified_old_objects(long index)
{
return (object_t *)list_item(
@@ -79,6 +86,12 @@
STM_PSEGMENT->objects_pointing_to_nursery, index);
}
+object_t *_stm_enum_old_objects_with_cards(long index)
+{
+ return (object_t *)list_item(
+ STM_PSEGMENT->old_objects_with_cards, index);
+}
+
uint64_t _stm_total_allocated(void)
{
return increment_total_allocated(0);
diff --git a/c7/stm/nursery.c b/c7/stm/nursery.c
--- a/c7/stm/nursery.c
+++ b/c7/stm/nursery.c
@@ -183,6 +183,23 @@
minor_trace_if_young(&tl->thread_local_obj);
}
+static void _reset_cards(object_t *obj)
+{
+ char *realobj = REAL_ADDRESS(STM_SEGMENT->segment_base, obj);
+ size_t size = stmcb_size_rounded_up((struct object_s *)realobj);
+
+ uintptr_t first_card_index = get_write_lock_idx((uintptr_t)obj);
+ uintptr_t card_index = 1;
+ uintptr_t last_card_index = get_card_index(size - 1);
+ OPT_ASSERT(last_card_index >= card_index);
+ while (card_index <= last_card_index) {
+ write_locks[first_card_index + card_index] = 0;
+ card_index++;
+ }
+
+ obj->stm_flags &= ~GCFLAG_CARDS_SET;
+}
+
static __thread object_t *_card_base_obj;
static void minor_trace_if_young_cards(object_t **pobj)
{
@@ -205,37 +222,51 @@
/* XXX HACK XXX: */
_card_base_obj = obj;
assert(!_is_in_nursery(obj));
+ assert(obj->stm_flags & GCFLAG_CARDS_SET);
+
+ dprintf(("_trace_card_object(%p)\n", obj));
+
char *realobj = REAL_ADDRESS(STM_SEGMENT->segment_base, obj);
stmcb_trace((struct object_s *)realobj, &minor_trace_if_young_cards);
+
+ _reset_cards(obj);
}
+
+
static inline void _collect_now(object_t *obj)
{
assert(!_is_young(obj));
dprintf(("_collect_now: %p\n", obj));
- assert(IMPLY(obj->stm_flags & GCFLAG_WRITE_BARRIER,
- obj->stm_flags & GCFLAG_CARDS_SET));
+
if (!(obj->stm_flags & GCFLAG_WRITE_BARRIER)) {
- /* do normal full trace, even if also card-marked */
- obj->stm_flags |= GCFLAG_WRITE_BARRIER;
- dprintf(("-> has no cards\n"));
/* Trace the 'obj' to replace pointers to nursery with pointers
outside the nursery, possibly forcing nursery objects out and
adding them to 'objects_pointing_to_nursery' as well. */
char *realobj = REAL_ADDRESS(STM_SEGMENT->segment_base, obj);
stmcb_trace((struct object_s *)realobj, &minor_trace_if_young);
- } else {
- /* only trace cards */
- dprintf(("-> has cards\n"));
+
+ obj->stm_flags |= GCFLAG_WRITE_BARRIER;
+ if (obj->stm_flags & GCFLAG_CARDS_SET) {
+ _reset_cards(obj);
+ }
+ } if (obj->stm_flags & GCFLAG_CARDS_SET) {
_trace_card_object(obj);
}
+}
- /* clear the CARDS_SET, but not the real cards since they are
- still needed by STM conflict detection
- XXX: maybe separate them since we now have to also trace all
- these cards again in the next minor_collection */
- obj->stm_flags &= ~GCFLAG_CARDS_SET;
+
+static void collect_cardrefs_to_nursery(void)
+{
+ struct list_s *lst = STM_PSEGMENT->old_objects_with_cards;
+
+ while (!list_is_empty(lst)) {
+ object_t *obj = (object_t*)list_pop_item(lst);
+
+ assert(obj->stm_flags & GCFLAG_CARDS_SET);
+ _collect_now(obj);
+ }
}
static void collect_oldrefs_to_nursery(void)
@@ -270,8 +301,9 @@
static void collect_modified_old_objects(void)
{
- LIST_FOREACH_R(STM_PSEGMENT->modified_old_objects, object_t * /*item*/,
- _collect_now(item));
+ LIST_FOREACH_R(
+ STM_PSEGMENT->modified_old_objects, object_t * /*item*/,
+ _collect_now(item));
}
static void collect_roots_from_markers(uintptr_t num_old)
@@ -371,6 +403,7 @@
to hold the ones we didn't trace so far. */
uintptr_t num_old;
if (STM_PSEGMENT->objects_pointing_to_nursery == NULL) {
+ assert(STM_PSEGMENT->old_objects_with_cards == NULL);
STM_PSEGMENT->objects_pointing_to_nursery = list_create();
STM_PSEGMENT->old_objects_with_cards = list_create();
@@ -390,7 +423,9 @@
collect_roots_in_nursery();
+ collect_cardrefs_to_nursery();
collect_oldrefs_to_nursery();
+ assert(list_is_empty(STM_PSEGMENT->old_objects_with_cards));
/* now all surviving nursery objects have been moved out */
stm_move_young_weakrefs();
diff --git a/c7/stmgc.h b/c7/stmgc.h
--- a/c7/stmgc.h
+++ b/c7/stmgc.h
@@ -138,8 +138,10 @@
void _stm_set_nursery_free_count(uint64_t free_count);
long _stm_count_modified_old_objects(void);
long _stm_count_objects_pointing_to_nursery(void);
+long _stm_count_old_objects_with_cards(void);
object_t *_stm_enum_modified_old_objects(long index);
object_t *_stm_enum_objects_pointing_to_nursery(long index);
+object_t *_stm_enum_old_objects_with_cards(long index);
uint64_t _stm_total_allocated(void);
#endif
diff --git a/c7/test/support.py b/c7/test/support.py
--- a/c7/test/support.py
+++ b/c7/test/support.py
@@ -101,8 +101,11 @@
long _stm_count_modified_old_objects(void);
long _stm_count_objects_pointing_to_nursery(void);
+long _stm_count_old_objects_with_cards(void);
object_t *_stm_enum_modified_old_objects(long index);
object_t *_stm_enum_objects_pointing_to_nursery(long index);
+object_t *_stm_enum_old_objects_with_cards(long index);
+
void stm_collect(long level);
uint64_t _stm_total_allocated(void);
@@ -496,6 +499,14 @@
return None
return map(lib._stm_enum_objects_pointing_to_nursery, range(count))
+def old_objects_with_cards():
+ count = lib._stm_count_old_objects_with_cards()
+ if count < 0:
+ return None
+ return map(lib._stm_enum_old_objects_with_cards, range(count))
+
+
+
SHADOWSTACK_LENGTH = 1000
_keepalive = weakref.WeakKeyDictionary()
diff --git a/c7/test/test_card_marking.py b/c7/test/test_card_marking.py
--- a/c7/test/test_card_marking.py
+++ b/c7/test/test_card_marking.py
@@ -54,3 +54,66 @@
dn = stm_get_ref(o, 0)
assert is_in_nursery(dn)
assert dn == d
+
+ assert not stm_was_written(o)
+ stm_write_card(o, 2)
+ assert stm_was_written_card(o)
+
+ # card cleared after last collection,
+ # so no retrace of index 199:
+ d2 = stm_allocate(64, True)
+ # without a write-barrier:
+ lib._set_ptr(o, 199, d2)
+ self.push_root(o)
+ stm_minor_collect()
+ o = self.pop_root()
+ # d2 was not traced!
+ dn = stm_get_ref(o, 199)
+ assert is_in_nursery(dn)
+ assert dn == d2
+
+ def test_nursery2(self):
+ o = stm_allocate_old_refs(200, True)
+ self.start_transaction()
+ p = stm_allocate(64)
+ d = stm_allocate(64)
+ e = stm_allocate(64)
+ stm_set_ref(o, 199, p, True)
+ stm_set_ref(o, 1, d, False)
+ lib._set_ptr(o, 100, e)
+
+ self.push_root(o)
+ stm_minor_collect()
+ o = self.pop_root()
+
+ # stm_write in stm_set_ref made it trace everything
+ assert not is_in_nursery(stm_get_ref(o, 199))
+ assert not is_in_nursery(stm_get_ref(o, 1))
+ assert not is_in_nursery(stm_get_ref(o, 100))
+
+ def test_nursery3(self):
+ o = stm_allocate_old_refs(200, True)
+ self.start_transaction()
+ stm_minor_collect()
+
+ p = stm_allocate(64)
+ d = stm_allocate(64)
+ e = stm_allocate(64)
+ stm_set_ref(o, 199, p, True)
+ stm_set_ref(o, 1, d, True)
+ lib._set_ptr(o, 100, e) # no card marked!
+
+ assert not stm_was_written(o)
+ assert stm_was_written_card(o)
+
+ print modified_old_objects()
+ print objects_pointing_to_nursery()
+ print old_objects_with_cards()
+
+ self.push_root(o)
+ stm_minor_collect()
+ o = self.pop_root()
+
+ assert not is_in_nursery(stm_get_ref(o, 199))
+ assert not is_in_nursery(stm_get_ref(o, 1))
+ assert stm_get_ref(o, 100) == e # not traced
More information about the pypy-commit
mailing list