[pypy-commit] stmgc copy-over-original2: Experimental: during major collection, find out private/protected
arigo
noreply at buildbot.pypy.org
Fri Jul 26 11:07:32 CEST 2013
Author: Armin Rigo <arigo at tunes.org>
Branch: copy-over-original2
Changeset: r447:2cd9cc934675
Date: 2013-07-26 11:07 +0200
http://bitbucket.org/pypy/stmgc/changeset/2cd9cc934675/
Log: Experimental: during major collection, find out private/protected
objects that point to public objects with a most recent version that
is also private/protected by the same thread. In this case we can
replace the pointer with a direct pointer.
diff --git a/c4/gcpage.c b/c4/gcpage.c
--- a/c4/gcpage.c
+++ b/c4/gcpage.c
@@ -245,7 +245,7 @@
objsize = stmgc_size(obj);
assert(objsize > sizeof(struct stm_stub_s) - WORD);
}
- dprintf(("copy %p over %p (%ld bytes)\n", obj, id_copy, objsize));
+ dprintf(("copy %p over %p (%zd bytes)\n", obj, id_copy, objsize));
memcpy(id_copy + 1, obj + 1, objsize - sizeof(struct stm_object_s));
/* copy the object's h_revision number */
@@ -258,8 +258,15 @@
return id_copy;
}
-static void visit_nonpublic(gcptr obj)
+static void visit_nonpublic(gcptr obj, struct tx_public_descriptor *gcp)
{
+ /* Visit a protected or private object. 'gcp' must be either NULL or
+ point to the thread that has got the object. This 'gcp' is only an
+ optimization: it lets us trace (most) private/protected objects
+ and replace pointers to public objects in them with pointers to
+ private/protected objects if they are the most recent ones,
+ provided they belong to the same thread.
+ */
assert(!(obj->h_tid & GCFLAG_PUBLIC));
assert(!(obj->h_tid & GCFLAG_STUB));
assert(!(obj->h_tid & GCFLAG_HAS_ID));
@@ -270,14 +277,15 @@
return; /* already visited */
obj->h_tid |= GCFLAG_VISITED;
- gcptrlist_insert(&objects_to_trace, obj);
+ gcptrlist_insert2(&objects_to_trace, obj, (gcptr)gcp);
}
-static gcptr visit_public(gcptr obj)
+static gcptr visit_public(gcptr obj, struct tx_public_descriptor *gcp)
{
/* The goal is to walk to the most recent copy, then copy its
content back into the h_original, and finally returns this
- h_original.
+ h_original. Or, if gcp != NULL and the most recent copy is
+ protected by precisely 'gcp', then we return it instead.
*/
gcptr original;
if (obj->h_original != 0 &&
@@ -335,6 +343,10 @@
The pair obj2/obj3 was or will be handled by
mark_all_stack_roots(). */
assert(obj3->h_tid & GCFLAG_BACKUP_COPY);
+
+ assert(STUB_THREAD(obj) != NULL);
+ if (STUB_THREAD(obj) == gcp)
+ return obj2;
break;
}
}
@@ -343,7 +355,11 @@
The head of the public chain is obj. We have to
explicitly keep obj2 alive. */
assert(!IS_POINTER(obj2->h_revision));
- visit_nonpublic(obj2);
+ visit_nonpublic(obj2, STUB_THREAD(obj));
+
+ assert(STUB_THREAD(obj) != NULL);
+ if (STUB_THREAD(obj) == gcp)
+ return obj2;
break;
}
}
@@ -355,15 +371,19 @@
/* return this original */
original->h_tid |= GCFLAG_VISITED;
if (!(original->h_tid & GCFLAG_STUB))
- gcptrlist_insert(&objects_to_trace, original);
+ gcptrlist_insert2(&objects_to_trace, original, NULL);
return original;
}
-static void visit(gcptr *pobj)
+static struct tx_public_descriptor *visit_protected_gcp;
+
+static void visit_take_protected(gcptr *pobj)
{
/* Visits '*pobj', marking it as surviving and possibly adding it to
objects_to_trace. Fixes *pobj to point to the exact copy that
- survived.
+ survived. This function will replace *pobj with a protected
+ copy if it belongs to the thread 'visit_protected_gcp', so the
+ latter must be initialized before any call!
*/
gcptr obj = *pobj;
if (obj == NULL)
@@ -371,25 +391,33 @@
if (!(obj->h_tid & GCFLAG_PUBLIC)) {
/* 'obj' is a private or protected copy. */
- visit_nonpublic(obj);
+ visit_nonpublic(obj, visit_protected_gcp);
}
else {
- *pobj = visit_public(obj);
+ *pobj = visit_public(obj, visit_protected_gcp);
}
}
gcptr stmgcpage_visit(gcptr obj)
{
- visit(&obj);
+ if (!(obj->h_tid & GCFLAG_PUBLIC)) {
+ visit_nonpublic(obj, NULL);
+ }
+ else {
+ obj = visit_public(obj, NULL);
+ }
return obj;
}
static void visit_all_objects(void)
{
while (gcptrlist_size(&objects_to_trace) > 0) {
+ visit_protected_gcp =
+ (struct tx_public_descriptor *)gcptrlist_pop(&objects_to_trace);
gcptr obj = gcptrlist_pop(&objects_to_trace);
- stmgc_trace(obj, &visit);
+ stmgc_trace(obj, &visit_take_protected);
}
+ visit_protected_gcp = NULL;
}
static void mark_prebuilt_roots(void)
@@ -407,7 +435,7 @@
obj->h_tid &= ~GCFLAG_VISITED;
assert(obj->h_tid & GCFLAG_PREBUILT_ORIGINAL);
- obj2 = visit_public(obj);
+ obj2 = visit_public(obj, NULL);
assert(obj2 == obj); /* it is its own original */
}
}
@@ -422,7 +450,7 @@
if (((revision_t)item) & ~((revision_t)END_MARKER_OFF |
(revision_t)END_MARKER_ON)) {
/* 'item' is a regular, non-null pointer */
- visit(root);
+ visit_take_protected(root);
dprintf(("visit stack root: %p -> %p\n", item, *root));
}
else if (item == END_MARKER_OFF) {
@@ -440,13 +468,14 @@
for (d = stm_tx_head; d; d = d->tx_next) {
assert(!stm_has_got_any_lock(d));
+ visit_protected_gcp = d->public_descriptor;
/* the roots pushed on the shadowstack */
mark_roots(d->shadowstack, *d->shadowstack_end_ref);
/* the thread-local object */
- visit(d->thread_local_obj_ref);
- visit(&d->old_thread_local_obj);
+ visit_take_protected(d->thread_local_obj_ref);
+ visit_take_protected(&d->old_thread_local_obj);
/* the current transaction's private copies of public objects */
wlog_t *item;
@@ -456,8 +485,10 @@
gcptr R = item->addr;
gcptr L = item->val;
- /* we visit the public object R */
- gcptr new_R = visit_public(R);
+ /* we visit the public object R. Must keep a public object
+ here, so we pass NULL as second argument. */
+ gcptr new_R = visit_public(R, NULL);
+ assert(new_R->h_tid & GCFLAG_PUBLIC);
if (new_R != R) {
/* we have to update the key in public_to_private, which
@@ -471,7 +502,7 @@
should be private, possibly private_from_protected,
so visit() should return the same private copy */
if (L != NULL) {
- visit_nonpublic(L);
+ visit_nonpublic(L, visit_protected_gcp);
}
} G2L_LOOP_END;
@@ -489,8 +520,13 @@
for (i = d->private_from_protected.size - 1; i >= 0; i--) {
gcptr obj = items[i];
assert(obj->h_tid & GCFLAG_PRIVATE_FROM_PROTECTED);
- visit_nonpublic(obj);
- visit((gcptr *)&obj->h_revision);
+ visit_nonpublic(obj, visit_protected_gcp);
+
+ gcptr backup_obj = (gcptr)obj->h_revision;
+ if (!(backup_obj->h_tid & GCFLAG_PUBLIC))
+ visit_nonpublic(backup_obj, visit_protected_gcp);
+ else
+ obj->h_revision = (revision_t)visit_public(backup_obj, NULL);
}
/* make sure that the other lists are empty */
@@ -509,6 +545,7 @@
d->num_private_from_protected_known_old);
}
+ visit_protected_gcp = NULL;
gcptrlist_delete(&new_public_to_private);
}
@@ -516,7 +553,7 @@
{
long i;
gcptr *items;
- assert(d->old_objects_to_trace.size == 0);
+ assert(d->old_objects_to_trace.size == 0);
/* If we're aborting this transaction anyway, we don't need to do
* more here.
More information about the pypy-commit
mailing list