~ chicken-core (chicken-5) b6c9d813f80f4e550a2e68b103ac56934eda9c4e


commit b6c9d813f80f4e550a2e68b103ac56934eda9c4e
Author:     Peter Bex <address@hidden>
AuthorDate: Wed Aug 24 21:04:37 2016 +0200
Commit:     felix <felix@call-with-current-continuation.org>
CommitDate: Thu Sep 1 13:09:03 2016 +0200

    Fix symbol GC: add wep lookup after fptr chasing
    
    Sometimes, with symbol GC enabled, a major GC might "drop" symbols which
    were still being referenced, resulting in weird errors like (eq? x 'foo)
    returning #f even if x holds the symbol 'foo.
    
    If, during marking in major GC, we encounter the bucket before we
    encounter the symbol, the bucket still refers to the symbol in its
    original location (the fromspace).  This pointer is added to the weak
    table with a counter of 0.
    
    Then, the symbol itself is scanned, and the item is found in the weak
    table, the counter is updated and the symbol is moved to the heap.  The
    header at the symbol's original location in the fromspace becomes a
    forwarding pointer.
    
    Then, when we encounter a _second_ reference to the symbol, it still
    refers to the symbol's pointer in the fromspace, but the header will be
    a forwarding pointer, so it won't match the symbol type (which we look
    for right at the start of the mark function).  This means the code code
    to update the weak entry's count won't be triggered.
    
    Instead, we should chase the forwarded pointer and *then* check if it's
    a symbol.  If it is, look up the *original* location's pointer in the
    weak table.
    
    Note: We don't need to look up the new location, because that can only
    be the case if the symbol was marked before we encountered the bucket,
    in which case it will already saturate the pointer immediately upon
    insertion of the weak table entry.
    
    Note 2: Before a reallocing GC, we reset the weak table and we never
    consult it during the reallocing GC, so all symbols will be copied.  A
    minor GC also doesn't handle symbols specially, so they'll be copied
    there too.
    
    This fixes #1173
    
    Signed-off-by: felix <felix@call-with-current-continuation.org>

diff --git a/NEWS b/NEWS
index c0ecd9c5..ec0dd93f 100644
--- a/NEWS
+++ b/NEWS
@@ -78,6 +78,7 @@
     which is faster because it is inlined (#1260, thanks to Kooda).
   - The default error handler now truncates very long condition
     messages (thanks to Lemonboy).
+  - Weak symbol GC (-:w) no longer drops random symbols (#1173).
 
 - Syntax expander
   - DSSSL lambda lists have improved hygiene, so they don't need
diff --git a/runtime.c b/runtime.c
index 5c542d38..6a50c060 100644
--- a/runtime.c
+++ b/runtime.c
@@ -3689,6 +3689,15 @@ C_regparm void C_fcall really_mark(C_word *x)
     if(is_fptr(h)) {
       val = fptr_to_ptr(h);
 
+      /* When we marked the bucket, it may have already referred to
+       * the moved symbol instead of its original location. Re-check:
+       */
+      if(C_enable_gcweak &&
+         (C_block_header(val) & C_HEADER_TYPE_BITS) == C_SYMBOL_TYPE &&
+         (wep = lookup_weak_table_entry(*x, 0)) != NULL) {
+        if((wep->container & WEAK_COUNTER_MAX) == 0) ++wep->container;
+      }
+
       if((C_uword)val >= (C_uword)tospace_start && (C_uword)val < (C_uword)tospace_top) {
 	*x = val;
 	return;
@@ -3702,6 +3711,15 @@ C_regparm void C_fcall really_mark(C_word *x)
 	/* Link points into fromspace and into a link which points into from- or tospace: */
 	val = fptr_to_ptr(h);
 	
+        /* See above: might happen twice */
+        if(C_enable_gcweak &&
+           (C_block_header(val) & C_HEADER_TYPE_BITS) == C_SYMBOL_TYPE &&
+           /* Check both the original and intermediate location: */
+           ((wep = lookup_weak_table_entry((C_word)p, 0)) != NULL ||
+            (wep = lookup_weak_table_entry(*x, 0)) != NULL)) {
+          if((wep->container & WEAK_COUNTER_MAX) == 0) ++wep->container;
+        }
+
 	if((C_uword)val >= (C_uword)tospace_start && (C_uword)val < (C_uword)tospace_top) {
 	  *x = val;
 	  return;
Trap