diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2015-09-02 06:55:44 -0700 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2015-09-02 06:55:44 -0700 |
commit | 1f4c97f1362f29084f08f7d2199475bbe749eb8e (patch) | |
tree | d0e31c9ea1fc0afad2ab4c47a59df0ad48329dfa /HACKING | |
parent | 88698e57f6a41adefd0a75bf8674c2ee065d1acd (diff) | |
download | txr-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-- | HACKING | 50 |
1 files changed, 38 insertions, 12 deletions
@@ -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 |