summaryrefslogtreecommitdiffstats
path: root/HACKING
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2015-09-02 06:55:44 -0700
committerKaz Kylheku <kaz@kylheku.com>2015-09-02 06:55:44 -0700
commit1f4c97f1362f29084f08f7d2199475bbe749eb8e (patch)
treed0e31c9ea1fc0afad2ab4c47a59df0ad48329dfa /HACKING
parent88698e57f6a41adefd0a75bf8674c2ee065d1acd (diff)
downloadtxr-1f4c97f1362f29084f08f7d2199475bbe749eb8e.tar.gz
txr-1f4c97f1362f29084f08f7d2199475bbe749eb8e.tar.bz2
txr-1f4c97f1362f29084f08f7d2199475bbe749eb8e.zip
Fix incorrect example and add one more approach.
HACKING: Fix wrong make_foo example which violates Rule One, by registering an uninitialized struct as a cobj handle, thereby making garbage traversable by gc. Also show alternative solution to the problem based on extending variable liveness via gc_hint.
Diffstat (limited to 'HACKING')
-rw-r--r--HACKING50
1 files changed, 38 insertions, 12 deletions
diff --git a/HACKING b/HACKING
index 5fb49f14..5c277a00 100644
--- a/HACKING
+++ b/HACKING
@@ -30,19 +30,19 @@ SECTION LINE
3.2 GC-safe Code 474
3.2.1 Rule One: Full Initialization 500
3.2.2 Rule Two: Make it Reachable 529
-3.3 Weak Reference Support 691
-3.4 Finalization 734
-3.5 Generational GC 758
-3.5.2 Representation of Generations 767
-3.5.3 Basic Algorithm 803
-3.5.4 Handling Backpointers 838
-3.5.5 Generational GC and Finalization 916
+3.3 Weak Reference Support 717
+3.4 Finalization 760
+3.5 Generational GC 784
+3.5.2 Representation of Generations 793
+3.5.3 Basic Algorithm 829
+3.5.4 Handling Backpointers 864
+3.5.5 Generational GC and Finalization 942
-4. Debugging 945
-4.2. Debugging the Yacc-generated Parser 1076
-4.3. Debugging GC Issues 1089
-4.4 Object Breakpoint 1112
-4.5 Valgrind: Your Friend 1131
+4. Debugging 971
+4.2. Debugging the Yacc-generated Parser 1102
+4.3. Debugging GC Issues 1115
+4.4 Object Breakpoint 1138
+4.5 Valgrind: Your Friend 1157
0. Overview
@@ -660,6 +660,10 @@ that an object may have been allocated which is not visible to gc,
/* Looks harmless: allocate structure, stick the argument object
into it and make a COBJ! */
+ typedef struct {
+ val mem;
+ } foo;
+
val make_foo(val member)
{
foo *f = (foo *) chk_malloc(sizeof *foo);
@@ -682,11 +686,33 @@ The make_foo function can be corrected like this:
{
cobj co;
foo *f = (foo *) chk_malloc(sizeof *foo);
+ f->mem = nil; /* do not forget Rule One */
co = cobj((mem_t *) f, ...);
f->mem = member;
return co;
}
+Another possible approach is to use the gc_hint function to ensure
+liveness:
+
+ val make_foo(val member)
+ {
+ foo *f = (foo *) chk_malloc(sizeof *foo);
+ val out;
+ f->mem = member; /* Oops, member is no longer live. */
+ out = cobj((mem_t *) f, ...);
+ gc_hint(member);
+ return out;
+ }
+
+gc_hint provides a data sink for the member, ensuring that this variable stays
+live across the call to cobj. The variable is no longer live at the "return
+out" statement, but at that point it doesn't matter because it has been safely
+stored in f->mem, which has been firmly installed as the handle of a cobj, and
+is visible to the garbage collector.
+
+The tradeoff is that the first approach generates two writes
+to f->mem, whereas the second makes an external function call.
3.3 Weak Reference Support