Author: Armin Rigo <[email protected]>
Branch: weakref
Changeset: r406:698e0c3f3413
Date: 2013-07-17 18:47 +0200
http://bitbucket.org/pypy/stmgc/changeset/698e0c3f3413/
Log: In-progress: move the weakref code in its own file, and start
writing logic for major collections.
diff --git a/c4/Makefile b/c4/Makefile
--- a/c4/Makefile
+++ b/c4/Makefile
@@ -16,10 +16,10 @@
H_FILES = atomic_ops.h stmgc.h stmimpl.h \
et.h lists.h steal.h nursery.h gcpage.h \
- stmsync.h extra.h dbgmem.h fprintcolor.h
+ stmsync.h extra.h weakref.h dbgmem.h fprintcolor.h
C_FILES = et.c lists.c steal.c nursery.c gcpage.c \
- stmsync.c extra.c dbgmem.c fprintcolor.c
+ stmsync.c extra.c weakref.c dbgmem.c fprintcolor.c
DEBUG = -g -DGC_NURSERY=0x10000 -D_GC_DEBUG=1 -DDUMP_EXTRA=1
-D_GC_DEBUGPRINTS=1
diff --git a/c4/gcpage.c b/c4/gcpage.c
--- a/c4/gcpage.c
+++ b/c4/gcpage.c
@@ -649,6 +649,8 @@
int i;
wlog_t *item;
+ stm_invalidate_old_weakrefs(gcp);
+
for (i = 1; i < GC_SMALL_REQUESTS; i++) {
sweep_pages(gcp, i);
}
diff --git a/c4/gcpage.h b/c4/gcpage.h
--- a/c4/gcpage.h
+++ b/c4/gcpage.h
@@ -45,7 +45,8 @@
/* These fields are in tx_public_descriptor rather than tx_descriptor.
The indirection allows us to keep around the lists of pages even
- after the thread finishes, until the next major collection.
+ after the thread finishes. Such a "zombie" tx_public_descriptor
+ is reused by the next thread that starts.
*/
#define GCPAGE_FIELDS_DECL \
/* The array 'pages_for_size' contains GC_SMALL_REQUESTS \
@@ -65,7 +66,10 @@
/* A set of all non-small objects (outside the nursery). \
We could also have a single global set, but this avoids \
locking in stmgcpage_malloc/free. */ \
- struct G2L nonsmall_objects;
+ struct G2L nonsmall_objects; \
+ \
+ /* Weakref support */ \
+ struct GcPtrList old_weakrefs;
#define LOCAL_GCPAGES() (thread_descriptor->public_descriptor)
diff --git a/c4/nursery.c b/c4/nursery.c
--- a/c4/nursery.c
+++ b/c4/nursery.c
@@ -101,15 +101,6 @@
return P;
}
-gcptr stm_weakref_allocate(size_t size, unsigned long tid, gcptr obj)
-{
- gcptr weakref = stm_allocate(size, tid);
- assert(stmgc_size(weakref) == size);
- WEAKREF_PTR(weakref, size) = obj;
- gcptrlist_insert(&thread_descriptor->young_weakrefs, weakref);
- return weakref;
-}
-
gcptr stmgc_duplicate(gcptr P)
{
size_t size = stmgc_size(P);
@@ -439,27 +430,6 @@
fxcache_clear(&d->recent_reads_cache);
}
-static void move_young_weakrefs(struct tx_descriptor *d)
-{
- while (gcptrlist_size(&d->young_weakrefs) > 0) {
- gcptr weakref = gcptrlist_pop(&d->young_weakrefs);
- if (!(weakref->h_tid & GCFLAG_NURSERY_MOVED))
- continue; /* the weakref itself dies */
-
- weakref = (gcptr)weakref->h_revision;
- size_t size = stmgc_size(weakref);
- gcptr obj = WEAKREF_PTR(weakref, size);
- if (!is_in_nursery(d, obj))
- continue; /* the pointer does not change */
-
- if (obj->h_tid & GCFLAG_NURSERY_MOVED)
- obj = obj->h_revision;
- else
- obj = NULL;
- WEAKREF_PTR(weakref, size) = obj;
- }
-}
-
static void setup_minor_collect(struct tx_descriptor *d)
{
spinlock_acquire(d->public_descriptor->collection_lock, 'M'); /*minor*/
@@ -507,7 +477,7 @@
surviving young-but-outside-the-nursery objects have been flagged
with GCFLAG_OLD
*/
- move_young_weakrefs(d);
+ stm_move_young_weakrefs(d);
teardown_minor_collect(d);
assert(!stm_has_got_any_lock(d));
diff --git a/c4/nursery.h b/c4/nursery.h
--- a/c4/nursery.h
+++ b/c4/nursery.h
@@ -68,7 +68,4 @@
void stmgc_trace(gcptr, void visit(gcptr *));
void stmgc_minor_collect_soon(void);
-#define WEAKREF_PTR(wr, sz) (*(gcptr *)(((char *)(wr)) + (sz) - WORD))
-
-
#endif
diff --git a/c4/stmgc.c b/c4/stmgc.c
--- a/c4/stmgc.c
+++ b/c4/stmgc.c
@@ -10,5 +10,6 @@
#include "gcpage.c"
#include "stmsync.c"
#include "extra.c"
+#include "weakref.c"
#include "dbgmem.c"
#include "fprintcolor.c"
diff --git a/c4/stmimpl.h b/c4/stmimpl.h
--- a/c4/stmimpl.h
+++ b/c4/stmimpl.h
@@ -36,5 +36,6 @@
#include "steal.h"
#include "stmsync.h"
#include "extra.h"
+#include "weakref.h"
#endif
diff --git a/c4/test/support.py b/c4/test/support.py
--- a/c4/test/support.py
+++ b/c4/test/support.py
@@ -11,11 +11,11 @@
header_files = [os.path.join(parent_dir, _n) for _n in
"et.h lists.h steal.h nursery.h gcpage.h "
- "stmsync.h extra.h dbgmem.h fprintcolor.h "
+ "stmsync.h extra.h weakref.h dbgmem.h fprintcolor.h "
"stmgc.h stmimpl.h atomic_ops.h".split()]
source_files = [os.path.join(parent_dir, _n) for _n in
"et.c lists.c steal.c nursery.c gcpage.c "
- "stmsync.c extra.c dbgmem.c fprintcolor.c".split()]
+ "stmsync.c extra.c weakref.c dbgmem.c fprintcolor.c".split()]
_pycache_ = os.path.join(parent_dir, 'test', '__pycache__')
if os.path.exists(_pycache_):
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
@@ -319,45 +319,3 @@
def test_collect_soon():
lib.stmgc_minor_collect_soon()
nalloc(HDR)
-
-def test_weakref_invalidate():
- p2 = nalloc(HDR)
- p1 = lib.stm_weakref_allocate(WEAKREF_SIZE, WEAKREF_TID, p2)
- assert p1.h_tid == WEAKREF_TID # no GC flags
- assert p1.h_revision == lib.get_private_rev_num()
- assert lib.rawgetptr(p1, 0) == p2
- lib.stm_push_root(p1)
- minor_collect()
- p1 = lib.stm_pop_root()
- assert lib.rawgetptr(p1, 0) == ffi.NULL
-
-def test_weakref_itself_dies():
- p2 = nalloc(HDR)
- p1 = lib.stm_weakref_allocate(WEAKREF_SIZE, WEAKREF_TID, p2)
- minor_collect()
-
-def test_weakref_keep():
- p2 = nalloc(HDR)
- p1 = lib.stm_weakref_allocate(WEAKREF_SIZE, WEAKREF_TID, p2)
- assert p1.h_tid == WEAKREF_TID # no GC flags
- assert p1.h_revision == lib.get_private_rev_num()
- assert lib.rawgetptr(p1, 0) == p2
- lib.stm_push_root(p1)
- lib.stm_push_root(p2)
- minor_collect()
- p2 = lib.stm_pop_root()
- p1 = lib.stm_pop_root()
- assert lib.rawgetptr(p1, 0) == p2
-
-def test_weakref_old_keep():
- p2 = oalloc(HDR)
- p1 = lib.stm_weakref_allocate(WEAKREF_SIZE, WEAKREF_TID, p2)
- assert p1.h_tid == WEAKREF_TID # no GC flags
- assert p1.h_revision == lib.get_private_rev_num()
- assert lib.rawgetptr(p1, 0) == p2
- lib.stm_push_root(p1)
- lib.stm_push_root(p2)
- minor_collect()
- p2 = lib.stm_pop_root()
- p1 = lib.stm_pop_root()
- assert lib.rawgetptr(p1, 0) == p2
diff --git a/c4/test/test_weakref.py b/c4/test/test_weakref.py
new file mode 100644
--- /dev/null
+++ b/c4/test/test_weakref.py
@@ -0,0 +1,120 @@
+import py
+from support import *
+
+
+class BaseTest(object):
+ def setup_method(self, meth):
+ lib.stm_clear_between_tests()
+ lib.stm_initialize_tests(0)
+ def teardown_method(self, meth):
+ lib.stm_finalize()
+
+
+class TestMinorCollection(BaseTest):
+
+ def test_weakref_invalidate(self):
+ p2 = nalloc(HDR)
+ p1 = lib.stm_weakref_allocate(WEAKREF_SIZE, WEAKREF_TID, p2)
+ assert p1.h_tid == WEAKREF_TID # no GC flags
+ assert p1.h_revision == lib.get_private_rev_num()
+ assert lib.rawgetptr(p1, 0) == p2
+ lib.stm_push_root(p1)
+ minor_collect()
+ p1 = lib.stm_pop_root()
+ assert lib.rawgetptr(p1, 0) == ffi.NULL
+
+ def test_weakref_itself_dies(self):
+ p2 = nalloc(HDR)
+ p1 = lib.stm_weakref_allocate(WEAKREF_SIZE, WEAKREF_TID, p2)
+ minor_collect()
+
+ def test_weakref_keep(self):
+ p2 = nalloc(HDR)
+ p1 = lib.stm_weakref_allocate(WEAKREF_SIZE, WEAKREF_TID, p2)
+ assert p1.h_tid == WEAKREF_TID # no GC flags
+ assert p1.h_revision == lib.get_private_rev_num()
+ assert lib.rawgetptr(p1, 0) == p2
+ lib.stm_push_root(p1)
+ lib.stm_push_root(p2)
+ minor_collect()
+ p2 = lib.stm_pop_root()
+ p1 = lib.stm_pop_root()
+ assert lib.rawgetptr(p1, 0) == p2
+
+ def test_weakref_old_keep(self):
+ p2 = oalloc(HDR)
+ p1 = lib.stm_weakref_allocate(WEAKREF_SIZE, WEAKREF_TID, p2)
+ assert p1.h_tid == WEAKREF_TID # no GC flags
+ assert p1.h_revision == lib.get_private_rev_num()
+ assert lib.rawgetptr(p1, 0) == p2
+ lib.stm_push_root(p1)
+ lib.stm_push_root(p2)
+ minor_collect()
+ p2 = lib.stm_pop_root()
+ p1 = lib.stm_pop_root()
+ assert lib.rawgetptr(p1, 0) == p2
+
+
+class TestMajorCollection(BaseTest):
+
+ def test_weakref_old(self):
+ p2 = nalloc(HDR)
+ p1 = lib.stm_weakref_allocate(WEAKREF_SIZE, WEAKREF_TID, p2)
+ #
+ lib.stm_push_root(p1)
+ lib.stm_push_root(p2)
+ major_collect()
+ p2 = lib.stm_pop_root()
+ p1 = lib.stm_pop_root()
+ assert lib.rawgetptr(p1, 0) == p2
+ #
+ lib.stm_push_root(p1)
+ major_collect()
+ p1 = lib.stm_pop_root()
+ assert lib.rawgetptr(p1, 0) == ffi.NULL
+
+ def test_weakref_to_prebuilt(self):
+ p2 = palloc(HDR)
+ p1 = lib.stm_weakref_allocate(WEAKREF_SIZE, WEAKREF_TID, p2)
+ #
+ lib.stm_push_root(p1)
+ major_collect()
+ p1 = lib.stm_pop_root()
+ assert lib.rawgetptr(p1, 0) == p2
+
+ def test_weakref_update_version(self):
+ p2 = oalloc(HDR + WORD); make_public(p2)
+ p1 = lib.stm_weakref_allocate(WEAKREF_SIZE, WEAKREF_TID, p2)
+ #
+ lib.stm_push_root(p1)
+ lib.stm_push_root(p2)
+ major_collect()
+ p2 = lib.stm_pop_root()
+ p1 = lib.stm_pop_root()
+ assert lib.rawgetptr(p1, 0) == p2
+ #
+ lib.stm_commit_transaction()
+ lib.stm_begin_inevitable_transaction()
+ #
+ lib.setlong(p2, 0, 912809218) # write barrier
+ assert lib.rawgetlong(p2, 0) == 0
+ lib.stm_push_root(p1)
+ lib.stm_push_root(p2)
+ major_collect()
+ p2 = lib.stm_pop_root()
+ p1 = lib.stm_pop_root()
+ assert lib.rawgetptr(p1, 0) == p2
+ assert lib.rawgetlong(p2, 0) == 0
+ #
+ lib.stm_commit_transaction()
+ lib.stm_begin_inevitable_transaction()
+ #
+ assert lib.rawgetlong(p2, 0) == 0
+ lib.stm_push_root(p1)
+ lib.stm_push_root(p2)
+ major_collect()
+ p2b = lib.stm_pop_root()
+ p1 = lib.stm_pop_root()
+ assert lib.rawgetptr(p1, 0) == p2
+ assert p2b != p2
+ assert lib.rawgetlong(p2b, 0) == 912809218
diff --git a/c4/weakref.c b/c4/weakref.c
new file mode 100644
--- /dev/null
+++ b/c4/weakref.c
@@ -0,0 +1,92 @@
+#include "stmimpl.h"
+
+#define WEAKREF_PTR(wr, sz) (*(gcptr *)(((char *)(wr)) + (sz) - WORD))
+
+
+gcptr stm_weakref_allocate(size_t size, unsigned long tid, gcptr obj)
+{
+ gcptr weakref = stm_allocate(size, tid);
+ assert(!(weakref->h_tid & GCFLAG_OLD)); /* 'size' too big? */
+ assert(stmgc_size(weakref) == size);
+ WEAKREF_PTR(weakref, size) = obj;
+ gcptrlist_insert(&thread_descriptor->young_weakrefs, weakref);
+ return weakref;
+}
+
+
+/***** Minor collection *****/
+
+static int is_in_nursery(struct tx_descriptor *d, gcptr obj)
+{
+ return (d->nursery_base <= (char*)obj && ((char*)obj) < d->nursery_end);
+}
+
+void stm_move_young_weakrefs(struct tx_descriptor *d)
+{
+ /* The code relies on the fact that no weakref can be an old object
+ weakly pointing to a young object. Indeed, weakrefs are immutable
+ so they cannot point to an object that was created after it.
+ */
+ while (gcptrlist_size(&d->young_weakrefs) > 0) {
+ gcptr weakref = gcptrlist_pop(&d->young_weakrefs);
+ if (!(weakref->h_tid & GCFLAG_NURSERY_MOVED))
+ continue; /* the weakref itself dies */
+
+ weakref = (gcptr)weakref->h_revision;
+ size_t size = stmgc_size(weakref);
+ gcptr pointing_to = WEAKREF_PTR(weakref, size);
+ assert(pointing_to != NULL);
+
+ if (is_in_nursery(d, pointing_to)) {
+ if (pointing_to->h_tid & GCFLAG_NURSERY_MOVED) {
+ WEAKREF_PTR(weakref, size) = (gcptr)pointing_to->h_revision;
+ }
+ else {
+ WEAKREF_PTR(weakref, size) = NULL;
+ continue; /* no need to remember this weakref any longer */
+ }
+ }
+ else {
+ /* # see test_weakref_to_prebuilt: it's not useful to put
+ # weakrefs into 'old_objects_with_weakrefs' if they point
+ # to a prebuilt object (they are immortal). If moreover
+ # the 'pointing_to' prebuilt object still has the
+ # GCFLAG_NO_HEAP_PTRS flag, then it's even wrong, because
+ # 'pointing_to' will not get the GCFLAG_VISITED during
+ # the next major collection. Solve this by not registering
+ # the weakref into 'old_objects_with_weakrefs'.
+ */
+ }
+ gcptrlist_insert(&d->public_descriptor->old_weakrefs, weakref);
+ }
+}
+
+
+/***** Major collection *****/
+
+void stm_invalidate_old_weakrefs(struct tx_public_descriptor *gcp)
+{
+ /* walk over list of objects that contain weakrefs. If the
+ object it references does not survive, invalidate the weakref */
+ long i;
+ gcptr *items = gcp->old_weakrefs.items;
+
+ for (i = gcp->old_weakrefs.size - 1; i >= 0; i--) {
+ gcptr weakref = items[i];
+
+ if (!(weakref->h_tid & GCFLAG_VISITED)) {
+ /* weakref itself dies */
+ }
+ else {
+ size_t size = stmgc_size(weakref);
+ gcptr pointing_to = WEAKREF_PTR(weakref, size);
+ //...;
+ abort();
+ }
+
+ /* remove this weakref from the list */
+ items[i] = items[--gcp->old_weakrefs.size];
+ }
+
+ gcptrlist_compress(&gcp->old_weakrefs);
+}
diff --git a/c4/weakref.h b/c4/weakref.h
new file mode 100644
--- /dev/null
+++ b/c4/weakref.h
@@ -0,0 +1,9 @@
+#ifndef _SRCSTM_WEAKREF_H
+#define _SRCSTM_WEAKREF_H
+
+
+void stm_move_young_weakrefs(struct tx_descriptor *);
+void stm_invalidate_old_weakrefs(struct tx_public_descriptor *);
+
+
+#endif
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit