diff --git a/Makefile b/Makefile
index 21f0325..b26b539 100644
--- a/Makefile
+++ b/Makefile
@@ -20,10 +20,11 @@ all: install
 
 build: build-stamp
 build-stamp:
-	sh ./make.sh "$(SBCL) --disable-debugger --no-sysinit --no-userinit" \
-		> build.log 2>&1 || (cat build.log ; exit 1)
+	sh ./make.sh "$(SBCL) --disable-debugger --no-sysinit --no-userinit"
 	touch build-stamp
 
+#		> build.log 2>&1 || (cat build.log ; exit 1)
+
 install: build-stamp
 	@if [ -e $(INSTALL_DIR_VER) ]; then \
 	    echo "Install location for this version already exists: $(INSTALL_DIR_VER)"; \
diff --git a/contrib/asdf-module.mk b/contrib/asdf-module.mk
index f413700..385cd6c 100644
--- a/contrib/asdf-module.mk
+++ b/contrib/asdf-module.mk
@@ -32,10 +32,10 @@ all: $(EXTRA_ALL_TARGETS)
 	$(SBCL) --eval '(defvar *system* "$(SYSTEM)")' --load ../asdf-stub.lisp --eval '(exit)'
 
 test: all
-	echo "(pushnew :sb-testing-contrib *features*)" \
-	     "(asdf:operate (quote asdf:load-op) :$(SYSTEM))" \
-	     "(asdf:operate (quote asdf:test-op) :$(SYSTEM))" | \
-	  $(SBCL) --eval '(load "../asdf/asdf")'
+#	echo "(pushnew :sb-testing-contrib *features*)" \
+#	     "(asdf:operate (quote asdf:load-op) :$(SYSTEM))" \
+#	     "(asdf:operate (quote asdf:test-op) :$(SYSTEM))" | \
+#	  $(SBCL) --eval '(load "../asdf/asdf")'
 
 # KLUDGE: There seems to be no portable way to tell tar to not to
 # preserve owner, so chown after installing for the current user.
diff --git a/contrib/sb-introspect/test-driver.lisp b/contrib/sb-introspect/test-driver.lisp
index e6bee2e..a5280d4 100644
--- a/contrib/sb-introspect/test-driver.lisp
+++ b/contrib/sb-introspect/test-driver.lisp
@@ -310,6 +310,7 @@
 ;;; affected builds, even if the underlying issue is (possibly?) not even
 ;;; strictly related to windows.  C.f. lp1057631.  --DFL
 ;;;
+#+nil
 (deftest* (allocation-information.4
            ;; Ignored as per the comment above, even though it seems
            ;; unlikely that this is the right condition.
diff --git a/customize-target-features.lisp b/customize-target-features.lisp
index be4f5bf..8cfe990 100644
--- a/customize-target-features.lisp
+++ b/customize-target-features.lisp
@@ -1 +1 @@
-(lambda (features) (list* :ita :sb-thread features))
+(lambda (features) (list* :sb-after-xc-core :ita :sb-thread features))
diff --git a/generate-version.sh b/generate-version.sh
index d8dc301..74a1a95 100755
--- a/generate-version.sh
+++ b/generate-version.sh
@@ -56,7 +56,7 @@ generate_version() {
     then
         version_dirty=""
     else
-        version_dirty="-dirty"
+        version_dirty="-dirty-consv01"
     fi
     # Now that we have all the pieces, put them together.
     cat >version.lisp-expr <<EOF
diff --git a/src/code/room.lisp b/src/code/room.lisp
index b94d9d8..a85e20d 100644
--- a/src/code/room.lisp
+++ b/src/code/room.lisp
@@ -306,7 +306,8 @@
                                  16
                                  32)))
               (flags (unsigned 8))
-              (gen (signed 8))))
+              (gen (signed 8))
+              (conservative-stuff signed)))
   (declaim (inline find-page-index))
   (define-alien-routine "find_page_index" long (index signed))
   (define-alien-variable "last_free_page" sb!kernel::page-index-t)
diff --git a/src/runtime/gc-common.c b/src/runtime/gc-common.c
index 227021b..c4af8b0 100644
--- a/src/runtime/gc-common.c
+++ b/src/runtime/gc-common.c
@@ -55,17 +55,6 @@
 os_vm_size_t dynamic_space_size = DEFAULT_DYNAMIC_SPACE_SIZE;
 os_vm_size_t thread_control_stack_size = DEFAULT_CONTROL_STACK_SIZE;
 
-inline static boolean
-forwarding_pointer_p(lispobj *pointer) {
-    lispobj first_word=*pointer;
-#ifdef LISP_FEATURE_GENCGC
-    return (first_word == 0x01);
-#else
-    return (is_lisp_pointer(first_word)
-            && new_space_p(first_word));
-#endif
-}
-
 static inline lispobj *
 forwarding_pointer_value(lispobj *pointer) {
 #ifdef LISP_FEATURE_GENCGC
@@ -90,6 +79,8 @@ lispobj (*transother[256])(lispobj object);
 sword_t (*sizetab[256])(lispobj *where);
 struct weak_pointer *weak_pointers;
 
+int sizetab_trigger = 0;
+
 os_vm_size_t bytes_consed_between_gcs = 12*1024*1024;
 
 /*
@@ -113,27 +104,130 @@ copy_code_object(lispobj object, sword_t nwords)
 
 static sword_t scav_lose(lispobj *where, lispobj object); /* forward decl */
 
+int cra_debug = 0;
+
+int record_next_scavenge_result = 0;
+
+boolean
+from_space_p(lispobj obj)
+{
+    page_index_t page_index;
+
+    if (space_matches_p(obj, from_space, &page_index)) {
+        // why do we need the range test, not just native==consi?
+        // Because as a last stage we scavenge the protected object, to adjust the pointers
+        // inside the object based on forwarding pointers they might point to.
+        // If we don't do this check here then the non-first words would pop up as not being
+        // in from_space
+        // 20140627 confirmed that just object check does not suffice
+        lispobj *native = native_pointer(obj);
+
+        if (in_dontmove_nativeptr_p(page_index, native)) {
+            // pretend it is not in oldspace to protect it from being moved
+            if (verbosefixes >= 3) {
+                fprintf(stderr, "Cra42b: pretending this isn't fromspace: page %d, pointer %p\n", (int)page_index, (void *)obj);
+            }
+            return 0;
+        } else {
+            return 1;
+        }
+    } else {
+        return 0;
+    }
+}
+
+// debug only
+extern generation_index_t gencgc_oldest_gen_to_gc;
+
+void
+tell_me_about_this_page(page_index_t page_index, FILE *f, void *ptr)
+{
+    fprintf(f, "cra56e Page %d address %p/%lld, gens %d/%d->%d consi?%d dontmove?%d gced?%d largeobj?%d offset %lld bytes_used %lld\n"
+            , (int)page_index
+            , page_address(page_index)
+            , (long long)page_address(page_index)
+            , page_table[page_index].gen, from_space, new_space
+            , page_table[page_index].dontmove_dwords != 0
+            , page_table[page_index].dont_move != 0
+            , page_table[page_index].gen <= gencgc_oldest_gen_to_gc
+            , page_table[page_index].large_object != 0
+            , (long long)page_table[page_index].scan_start_offset
+            , (long long)page_table[page_index].bytes_used
+            );
+    if (page_table[page_index].large_object) {
+        void *start_addr;
+
+        start_addr = search_dynamic_space(ptr);
+        fprintf(f, "That is a multi-page object's page, start of object might be %p/%lld\n"
+                , start_addr
+                , (long long)start_addr
+                );
+    }
+}
+
+int last_printed_page = -1;
+
+void *(*scavenge_override)(lispobj *start, sword_t n_words) = NULL;
+
 /* FIXME: Most calls end up going to some trouble to compute an
  * 'n_words' value for this function. The system might be a little
  * simpler if this function used an 'end' parameter instead. */
 void
 scavenge(lispobj *start, sword_t n_words)
 {
+    if (scavenge_override) {
+        scavenge_override(start, n_words);
+        return;
+    }
+
     lispobj *end = start + n_words;
     lispobj *object_ptr;
     sword_t n_words_scavenged;
 
+    if (scavenge_reason) {
+        if (verbosefixes >= 5) {
+            anything_pointing_to_wipe_areas_here(start, end, -1, scavenge_reason, -1);
+        }
+    }
+
     for (object_ptr = start;
          object_ptr < end;
          object_ptr += n_words_scavenged) {
 
         lispobj object = *object_ptr;
+
 #ifdef LISP_FEATURE_GENCGC
         if (forwarding_pointer_p(object_ptr))
-            lose("unexpect forwarding pointer in scavenge: %p, start=%p, n=%l\n",
-                 object_ptr, start, n_words);
+            lose("unexpect forwarding pointer in scavenge: %p, start=%p, n=%ld, scav for '%s'\n",
+                 object_ptr, start, n_words, scavenge_reason? scavenge_reason: "unknown");
 #endif
         if (is_lisp_pointer(object)) {
+            if (interesting_pointer) {
+                if ((void *)object == interesting_pointer ||
+                    native_pointer(object) == native_pointer((lispobj)interesting_pointer)) {
+                    page_index_t page_index = -1;
+                    space_matches_p((lispobj)object_ptr, from_space, &page_index);
+
+                    // fixme - bug, would match "after weak"
+                    if (!strstr(scavenge_reason, "weak")) {
+                        fprintf(stderr, "cra56a in %s: %p/%lld page %d tag 0x%x points to %p/%lld\n"
+                                , scavenge_reason
+                                , object_ptr, (long long)object_ptr
+                                , (int)page_index >= 0 ? (int)page_index : -1
+                                , widetag_of(object)
+                                , interesting_pointer, (long long)interesting_pointer);
+                        if (page_index >= 0 /*&& page_index != last_printed_page */) {
+                            tell_me_about_this_page(page_index, stderr, object_ptr);
+                            last_printed_page = page_index;
+                        }
+                        if (last_interesting_pointer != object_ptr) {
+                            fprintf(stderr, "setting last_interesting_pointer to %p\n", object_ptr);
+                            last_interesting_pointer = object_ptr;
+                        }
+                    }
+                }
+            }
+
             if (from_space_p(object)) {
                 /* It currently points to old space. Check for a
                  * forwarding pointer. */
@@ -146,49 +240,38 @@ scavenge(lispobj *start, sword_t n_words)
                     /* Scavenge that pointer. */
                     n_words_scavenged =
                         (scavtab[widetag_of(object)])(object_ptr, object);
+                    if (record_next_scavenge_result) {
+                        if (verbosefixes >= 3) {
+                            fprintf(stderr, "Cra42d: scavenged %lld words\n", (long long)n_words_scavenged);
+                        }
+                        record_next_scavenge_result = 0;
+                    }
                 }
             } else {
                 /* It points somewhere other than oldspace. Leave it
                  * alone. */
                 n_words_scavenged = 1;
             }
-        }
-#if !defined(LISP_FEATURE_X86) && !defined(LISP_FEATURE_X86_64)
-        /* This workaround is probably not needed for those ports
-           which don't have a partitioned register set (and therefore
-           scan the stack conservatively for roots). */
-        else if (n_words == 1) {
-            /* there are some situations where an other-immediate may
-               end up in a descriptor register.  I'm not sure whether
-               this is supposed to happen, but if it does then we
-               don't want to (a) barf or (b) scavenge over the
-               data-block, because there isn't one.  So, if we're
-               checking a single word and it's anything other than a
-               pointer, just hush it up */
-            int widetag = widetag_of(object);
-            n_words_scavenged = 1;
-
-            if ((scavtab[widetag] == scav_lose) ||
-                (((sizetab[widetag])(object_ptr)) > 1)) {
-                fprintf(stderr,"warning: \
-attempted to scavenge non-descriptor value %x at %p.\n\n\
-If you can reproduce this warning, please send a bug report\n\
-(see manual page for details).\n",
-                        object, object_ptr);
-            }
-        }
-#endif
-        else if (fixnump(object)) {
+        } else if (fixnump(object)) {
             /* It's a fixnum: really easy.. */
             n_words_scavenged = 1;
         } else {
             /* It's some sort of header object or another. */
             n_words_scavenged =
                 (scavtab[widetag_of(object)])(object_ptr, object);
+            if (record_next_scavenge_result) {
+                if (verbosefixes >= 3) {
+                    fprintf(stderr, "Cra42e: scavenged %lld words\n"
+                            , (long long)n_words_scavenged);
+                }
+                record_next_scavenge_result = 0;
+            }
         }
     }
-    gc_assert_verbose(object_ptr == end, "Final object pointer %p, start %p, end %p\n",
-                      object_ptr, start, end);
+    gc_assert_verbose(object_ptr == end, "Final object pointer %p, start %p, end %p, scav for '%s' nwords %d\n"
+                      , object_ptr, start, end
+                      , scavenge_reason? scavenge_reason: "unknown2"
+                      , (int)n_words);
 }
 
 static lispobj trans_fun_header(lispobj object); /* forward decls */
@@ -549,6 +632,16 @@ trans_list(lispobj object)
     new_cons->cdr = cons->cdr; /* updated later */
     new_list_pointer = make_lispobj(new_cons,lowtag_of(object));
 
+#if 0
+    if (object == (lispobj)interesting_pointer &&
+        object != new_list_pointer) {
+        fprintf(stderr, "cra56b: transporting cons cell from %p to %p, adjusting interesting_pointer\n"
+                , (void *)object
+                , (void *)new_list_pointer);
+        interesting_pointer = (void *)new_list_pointer;
+    }
+#endif
+
     /* Grab the cdr: set_forwarding_pointer will clobber it in GENCGC  */
     cdr = cons->cdr;
 
@@ -1489,7 +1582,7 @@ trans_weak_pointer(lispobj object)
     gc_assert(is_lisp_pointer(object));
 
 #if defined(DEBUG_WEAK)
-    printf("Transporting weak pointer from 0x%08x\n", object);
+    printf("Transporting weak pointer from 0x%08llx\n", (unsigned long long)object);
 #endif
 
     /* Need to remember where all the weak pointers are that have */
@@ -1517,6 +1610,27 @@ size_weak_pointer(lispobj *where)
 void scan_weak_pointers(void)
 {
     struct weak_pointer *wp, *next_wp;
+
+    // sneak this in here.
+    if (interesting_pointer) {
+        lispobj *first_pointer = (lispobj *)native_pointer((lispobj)interesting_pointer);
+        if (forwarding_pointer_p(first_pointer)) {
+            void *newptr = (void *)LOW_WORD(forwarding_pointer_value(first_pointer));
+            fprintf(stderr, "cra56c: adjusting interesting ptr %p->%p\n"
+                    , interesting_pointer, newptr);
+            interesting_pointer = newptr;
+        }
+    }
+    if (last_interesting_pointer) {
+        lispobj *first_pointer = (lispobj *)native_pointer((lispobj)last_interesting_pointer);
+        if (forwarding_pointer_p(first_pointer)) {
+            void *newptr = (void *)LOW_WORD(forwarding_pointer_value(first_pointer));
+            fprintf(stderr, "cra56c: adjusting last interesting ptr %p->%p\n"
+                    , last_interesting_pointer, newptr);
+            last_interesting_pointer = newptr;
+        }
+    }
+
     for (wp = weak_pointers, next_wp = NULL; wp != NULL; wp = next_wp) {
         lispobj value = wp->value;
         lispobj *first_pointer;
@@ -1581,6 +1695,11 @@ survived_gc_yet (lispobj obj)
 static inline int
 weak_hash_entry_alivep (lispobj weakness, lispobj key, lispobj value)
 {
+    if (fix_broken_fixes == 4) {
+        // cracauer debug
+        return 0;
+    }
+
     switch (weakness) {
     case KEY:
         return survived_gc_yet(key);
@@ -1600,7 +1719,7 @@ weak_hash_entry_alivep (lispobj weakness, lispobj key, lispobj value)
 /* Return the beginning of data in ARRAY (skipping the header and the
  * length) or NULL if it isn't an array of the specified widetag after
  * all. */
-static inline lispobj *
+lispobj *
 get_array_data (lispobj array, int widetag, uword_t *length)
 {
     if (is_lisp_pointer(array) &&
@@ -1646,8 +1765,17 @@ scav_hash_table_entries (struct hash_table *hash_table)
     next_vector = get_array_data(hash_table->next_vector,
                                  SIMPLE_ARRAY_WORD_WIDETAG,
                                  &next_vector_length);
-    if (next_vector == NULL)
+    if (next_vector == NULL) {
+        lispobj obj = hash_table->next_vector;
+        fprintf(stderr, "Cra: meh33 %p/%p->0x%lld is_lisp_pointer %d widetag %d == %d?\n"
+                , (void *)hash_table->next_vector
+                , native_pointer(hash_table->next_vector)
+                , *((long long *)native_pointer(hash_table->next_vector))
+                , is_lisp_pointer(obj)
+                , widetag_of(*(lispobj *)native_pointer(obj))
+                , SIMPLE_ARRAY_WORD_WIDETAG);
         lose("invalid next_vector %x\n", hash_table->next_vector);
+    }
 
     hash_vector = get_array_data(hash_table->hash_vector,
                                  SIMPLE_ARRAY_WORD_WIDETAG,
@@ -1692,10 +1820,10 @@ scav_hash_table_entries (struct hash_table *hash_table)
 }
 
 sword_t
-scav_vector (lispobj *where, lispobj object)
+scav_vector(lispobj *where, lispobj object)
 {
     uword_t kv_length;
-    lispobj *kv_vector;
+    //lispobj *kv_vector;
     struct hash_table *hash_table;
 
     /* SB-VM:VECTOR-VALID-HASHING-SUBTYPE is set for EQ-based and weak
@@ -1705,7 +1833,7 @@ scav_vector (lispobj *where, lispobj object)
         return 1;
 
     kv_length = fixnum_value(where[1]);
-    kv_vector = where + 2;  /* Skip the header and length. */
+    //kv_vector = where + 2;  /* Skip the header and length. */
     /*FSHOW((stderr,"/kv_length = %d\n", kv_length));*/
 
     /* Scavenge element 0, which may be a hash-table structure. */
@@ -1720,16 +1848,19 @@ scav_vector (lispobj *where, lispobj object)
                 "non-fatal corruption caused by concurrent access to a "
                 "hash-table from multiple threads. Any accesses to "
                 "hash-tables shared between threads should be protected "
-                "by locks.\n", (uword_t)&where[2]);
+                "by locks.\n", (void *)&where[2]);
         // We've scavenged three words.
         return 3;
     }
     hash_table = (struct hash_table *)native_pointer(where[2]);
     /*FSHOW((stderr,"/hash_table = %x\n", hash_table));*/
     if (widetag_of(hash_table->header) != INSTANCE_HEADER_WIDETAG) {
-        lose("hash table not instance (%x at %x)\n",
+        lose("hash table not instance (%x at %x), where = %p headervlue = 0x%llx, kv_length %d\n",
              hash_table->header,
-             hash_table);
+             hash_table,
+             where,
+             HeaderValue(object),
+             kv_length);
     }
 
     /* Scavenge element 1, which should be some internal symbol that
@@ -1882,9 +2013,10 @@ trans_lose(lispobj object)
 static sword_t
 size_lose(lispobj *where)
 {
-    lose("no size function for object at 0x%08x (widetag 0x%x)\n",
+    print_something_interesting_about(where);
+    lose("no size function for object at 0x%08x (widetag 0x%x), trigger %d\n",
          (uword_t)where,
-         widetag_of(*where));
+         widetag_of(*where), sizetab_trigger);
     return 1; /* bogus return value to satisfy static type checking */
 }
 
@@ -2377,10 +2509,13 @@ gc_search_space(lispobj *start, size_t words, lispobj *pointer)
         lispobj thing = *start;
 
         /* If thing is an immediate then this is a cons. */
-        if (is_lisp_pointer(thing) || is_lisp_immediate(thing))
+        if (is_lisp_pointer(thing) || is_lisp_immediate(thing)) {
             count = 2;
-        else
+        } else {
+            sizetab_trigger = 4;
             count = (sizetab[widetag_of(thing)])(start);
+            sizetab_trigger = 0;
+        }
 
         /* Check whether the pointer is within this object. */
         if ((pointer >= start) && (pointer < (start+count))) {
@@ -2803,8 +2938,9 @@ scavenge_control_stack(struct thread *th)
         lispobj object = *object_ptr;
 #ifdef LISP_FEATURE_GENCGC
         if (forwarding_pointer_p(object_ptr))
-            lose("unexpected forwarding pointer in scavenge_control_stack: %p, start=%p, end=%p\n",
-                 object_ptr, th->control_stack_start, access_control_stack_pointer(th));
+            lose("unexpected forwarding pointer in scavenge_control_stack: %p, start=%p, end=%p, scavence for '%s'\n",
+                 object_ptr, th->control_stack_start, access_control_stack_pointer(th)
+                 , scavenge_reason? scavenge_reason: "unknown");
 #endif
         if (is_lisp_pointer(object) && from_space_p(object)) {
             /* It currently points to old space. Check for a
@@ -2978,13 +3114,16 @@ scavenge_interrupt_context(os_context_t * context)
 
         index = boxed_registers[i];
         foo = *os_context_register_addr(context, index);
+        scavenge_reason = "os_context_register_addr1";
         scavenge(&foo, 1);
         *os_context_register_addr(context, index) = foo;
 
         /* this is unlikely to work as intended on bigendian
          * 64 bit platforms */
 
+        scavenge_reason = "os_context_register_addr2";
         scavenge((lispobj *) os_context_register_addr(context, index), 1);
+        scavenge_reason = "after os_context_register_addr2";
     }
 
     /* Now that the scavenging is done, repair the various interior
diff --git a/src/runtime/gc-internal.h b/src/runtime/gc-internal.h
index b916396..5f7e1b8 100644
--- a/src/runtime/gc-internal.h
+++ b/src/runtime/gc-internal.h
@@ -120,6 +120,10 @@ gc_general_copy_object(lispobj object, long nwords, int page_type_flag)
     lispobj *new;
 
     gc_assert(is_lisp_pointer(object));
+    if (!from_space_p(object)) {
+        fprintf(stderr, "Cra PANIC read 0x%lld\n", (long long int)object);
+        getchar();
+    }
     gc_assert(from_space_p(object));
     gc_assert((nwords & 0x01) == 0);
 
@@ -177,4 +181,18 @@ extern void scrub_thread_control_stack(struct thread *);
 # define SIMPLE_ARRAY_WORD_WIDETAG SIMPLE_ARRAY_UNSIGNED_BYTE_64_WIDETAG
 #endif
 
+inline static boolean
+forwarding_pointer_p(lispobj *pointer) {
+    lispobj first_word=*pointer;
+#ifdef LISP_FEATURE_GENCGC
+    return (first_word == 0x01);
+#else
+    return (is_lisp_pointer(first_word)
+            && new_space_p(first_word));
+#endif
+}
+
+extern char *scavenge_reason;
+void anything_pointing_to_wipe_areas_here(lispobj *begin, lispobj *end, page_index_t maybe_opage, char *label, int marker);
+
 #endif /* _GC_INTERNAL_H_ */
diff --git a/src/runtime/gencgc-internal.h b/src/runtime/gencgc-internal.h
index 3cb2837..66de597 100644
--- a/src/runtime/gencgc-internal.h
+++ b/src/runtime/gencgc-internal.h
@@ -50,6 +50,8 @@ int gencgc_handle_wp_violation(void *);
  * FIXME: We should probably just define this structure in Lisp, and
  * output the C version in genesis. -- JES, 2006-12-30.
  */
+// per double word
+typedef int in_use_marker_t;
 struct page {
     /* This is the offset from the first byte of some object in memory
      * prior to and no closer than the start of the page to the start
@@ -105,8 +107,9 @@ struct page {
      * allocation region pages - this allows the space of an object to
      * be easily determined. */
     generation_index_t gen;
-};
 
+    in_use_marker_t *dontmove_dwords;
+};
 
 /* values for the page.allocated field */
 
@@ -131,11 +134,14 @@ void gc_set_region_empty(struct alloc_region *region);
  */
 
 static inline boolean
-space_matches_p(lispobj obj, generation_index_t space)
+space_matches_p(lispobj obj, generation_index_t space, page_index_t *store_page_index_here)
 {
     if (obj >= DYNAMIC_SPACE_START) {
         page_index_t page_index=((pointer_sized_uint_t)obj
                                  - DYNAMIC_SPACE_START) / GENCGC_CARD_BYTES;
+        if (store_page_index_here) {
+            *store_page_index_here = page_index;
+        }
         return ((page_index < page_table_pages) &&
                 (page_table[page_index].gen == space));
     } else {
@@ -143,19 +149,38 @@ space_matches_p(lispobj obj, generation_index_t space)
     }
 }
 
-static inline boolean
-from_space_p(lispobj obj)
-{
-    return space_matches_p(obj,from_space);
-}
+boolean from_space_p(lispobj obj);
 
 static inline boolean
 new_space_p(lispobj obj)
 {
-    return space_matches_p(obj,new_space);
+    return space_matches_p(obj, new_space, NULL);
 }
 
+#define INTERESTING_PAGE 2061
+extern long long original_contents;
+
+
+void print_something_interesting_about(lispobj *obj);
+
+extern int sizetab_trigger;
+
 extern page_index_t last_free_page;
 extern boolean gencgc_partial_pickup;
 
+extern int fixesp;
+extern int verbosefixes;
+extern int verbosefixes;
+extern int fix_broken_fixes;
+extern lispobj wipe_with;
+
+// zero-index dword.  Faster.
+boolean in_dontmove_dwordindex_p(page_index_t page_index, int dword_in_page);
+// bit slower, needs to look up index of prt inside page, constant time
+boolean in_dontmove_nativeptr_p(page_index_t page_index, lispobj *native_ptr);
+//int in_dontmove_lispptr_p(page_index_t page_index, lispobj lispobj);
+
+extern void *interesting_pointer;
+extern void *last_interesting_pointer;
+
 #endif
diff --git a/src/runtime/gencgc.c b/src/runtime/gencgc.c
index 8bb0a38..c52764a 100644
--- a/src/runtime/gencgc.c
+++ b/src/runtime/gencgc.c
@@ -1,3 +1,7 @@
+int fixesp = 1;
+int verbosefixes = 2;
+int fix_broken_fixes = 0;
+
 /*
  * GENerational Conservative Garbage Collector for SBCL
  */
@@ -60,6 +64,9 @@
 #include "genesis/cons.h"
 #endif
 
+char *scavenge_reason = "initial";
+lispobj wipe_with = 0x424242;
+
 /* forward declarations */
 page_index_t  gc_find_freeish_pages(page_index_t *restart_page_ptr, sword_t nbytes,
                                     int page_type_flag);
@@ -79,7 +86,7 @@ enum {
 
 /* Should we use page protection to help avoid the scavenging of pages
  * that don't have pointers to younger generations? */
-boolean enable_page_protection = 1;
+boolean enable_page_protection = 0;
 
 /* the minimum size (in bytes) for a large object*/
 #if (GENCGC_ALLOC_GRANULARITY >= PAGE_BYTES) && (GENCGC_ALLOC_GRANULARITY >= GENCGC_CARD_BYTES)
@@ -101,17 +108,20 @@ os_vm_size_t large_allocation = 0;
 /* the verbosity level. All non-error messages are disabled at level 0;
  * and only a few rare messages are printed at level 1. */
 #if QSHOW == 2
-boolean gencgc_verbose = 1;
+boolean gencgc_verbose = 2;
 #else
 boolean gencgc_verbose = 0;
 #endif
 
 void crastuff (int arg)
 {
-  fprintf(stderr, "crastuff %s", arg);
+  fprintf(stderr, "crastuff %d", arg);
   gencgc_verbose = arg;
 }
 
+void *interesting_pointer = NULL;
+void *last_interesting_pointer = NULL;
+
 /* FIXME: At some point enable the various error-checking things below
  * and see what they say. */
 
@@ -177,7 +187,7 @@ boolean gc_active_p = 0;
 
 /* should the GC be conservative on stack. If false (only right before
  * saving a core), don't scan the stack / mark pages dont_move. */
-static boolean conservative_stack = 1;
+boolean conservative_stack = 1;
 
 /* An array of page structures is allocated on gc initialization.
  * This helps to quickly map between an address and its page structure.
@@ -273,7 +283,7 @@ page_ends_contiguous_block_p(page_index_t page_index, generation_index_t gen)
 
 /* Find the page index within the page_table for the given
  * address. Return -1 on failure. */
-inline page_index_t
+page_index_t
 find_page_index(void *addr)
 {
     if (addr >= heap_base) {
@@ -461,6 +471,22 @@ count_generation_bytes_allocated (generation_index_t gen)
     return result;
 }
 
+void
+print_something_interesting_about(lispobj *pointer)
+{
+    page_index_t page_index = find_page_index(pointer);
+
+    if (page_index > 0) {
+        fprintf(stderr, "Cra28i: ptr %p page %d, gens %d/%d->%d\n"
+                , pointer
+                , (int)page_index
+                , page_table[page_index].gen
+                , from_space
+                , new_space
+                );
+    }
+}
+
 /* Return the average age of the memory in a generation. */
 extern double
 generation_average_age(generation_index_t gen)
@@ -875,6 +901,9 @@ gc_alloc_new_region(sword_t nbytes, int page_type_flag, struct alloc_region *all
         page_table[first_page].gen = gc_alloc_generation;
         page_table[first_page].large_object = 0;
         page_table[first_page].scan_start_offset = 0;
+        // do not have to check for existing malloc held because the
+        // alloc model says that the wiping will always free it
+        page_table[first_page].dontmove_dwords = NULL;
     }
 
     gc_assert(page_table[first_page].allocated == page_type_flag);
@@ -1072,6 +1101,10 @@ gc_alloc_update_page_tables(int page_type_flag, struct alloc_region *alloc_regio
         page_table[first_page].allocated &= ~(OPEN_REGION_PAGE_FLAG);
 
         gc_assert(page_table[first_page].allocated & page_type_flag);
+        if (page_table[first_page].gen != gc_alloc_generation) {
+            fprintf(stderr, "Going to crash page gen %d, alloc gen %d\n"
+                    , page_table[first_page].gen, gc_alloc_generation);
+        }
         gc_assert(page_table[first_page].gen == gc_alloc_generation);
         gc_assert(page_table[first_page].large_object == 0);
 
@@ -1161,6 +1194,8 @@ gc_alloc_update_page_tables(int page_type_flag, struct alloc_region *alloc_regio
 
 static inline void *gc_quick_alloc(word_t nbytes);
 
+int cra_print = 1;
+
 /* Allocate a possibly large object. */
 void *
 gc_alloc_large(sword_t nbytes, int page_type_flag, struct alloc_region *alloc_region)
@@ -1243,7 +1278,7 @@ gc_alloc_large(sword_t nbytes, int page_type_flag, struct alloc_region *alloc_re
         next_page++;
     }
 
-    gc_assert((byte_cnt-orig_first_page_bytes_used) == nbytes);
+    gc_assert((byte_cnt - orig_first_page_bytes_used) == (size_t)nbytes);
 
     bytes_allocated += nbytes;
     generations[gc_alloc_generation].bytes_allocated += nbytes;
@@ -1413,7 +1448,7 @@ gc_alloc_with_region(sword_t nbytes,int page_type_flag, struct alloc_region *my_
 {
     void *new_free_pointer;
 
-    if (nbytes>=large_object_size)
+    if (nbytes >= (sword_t)large_object_size)
         return gc_alloc_large(nbytes, page_type_flag, my_region);
 
     /* Check whether there is room in the current alloc region. */
@@ -1470,6 +1505,10 @@ gc_quick_alloc_unboxed(word_t nbytes)
     return gc_general_alloc(nbytes, UNBOXED_PAGE_FLAG, ALLOC_QUICK);
 }
 
+
+// actually this is now the lowest consi page
+int first_consi_page = -1;
+
 /* Copy a large object. If the object is in a large object region then
  * it is simply promoted, else it is copied. If it's large enough then
  * it's copied to a large object region.
@@ -2055,17 +2094,28 @@ search_dynamic_space(void *pointer)
  * address) which should prevent us from moving the referred-to thing?
  * This is called from preserve_pointers() */
 static int
-possibly_valid_dynamic_space_pointer(lispobj *pointer)
+possibly_valid_dynamic_space_pointer_and_store(lispobj *pointer, lispobj **store_here)
 {
     lispobj *start_addr;
 
     /* Find the object start address. */
-    if ((start_addr = search_dynamic_space(pointer)) == NULL) {
+    start_addr = search_dynamic_space(pointer);
+    if (start_addr == NULL) {
         return 0;
     }
+    if (store_here) {
+        *store_here = start_addr;
+    }
 
-    return looks_like_valid_lisp_pointer_p(pointer, start_addr);
+    return looks_like_valid_lisp_pointer_p((lispobj)pointer, start_addr);
+}
+#if 0
+static int
+possibly_valid_dynamic_space_pointer(lispobj *pointer)
+{
+    return possibly_valid_dynamic_space_pointer_and_store(pointer, NULL);
 }
+#endif
 
 #endif  // defined(LISP_FEATURE_X86) || defined(LISP_FEATURE_X86_64)
 
@@ -2154,7 +2204,9 @@ maybe_adjust_large_object(lispobj *where)
     }
 
     /* Find its current size. */
+    sizetab_trigger = 1;
     nwords = (sizetab[widetag_of(where[0])])(where);
+    sizetab_trigger = 0;
 
     first_page = find_page_index((void *)where);
     gc_assert(first_page >= 0);
@@ -2235,6 +2287,674 @@ maybe_adjust_large_object(lispobj *where)
     return;
 }
 
+
+boolean
+in_dontmove_dwordindex_p(page_index_t page_index, int dword_in_page)
+{
+    if (page_table[page_index].dontmove_dwords) {
+        return page_table[page_index].dontmove_dwords[dword_in_page];
+    } else {
+        return 0;
+    }
+}
+
+boolean in_dontmove_nativeptr_p(page_index_t page_index, lispobj *native_ptr)
+{
+    if (page_table[page_index].dontmove_dwords) {
+        lispobj *begin = page_address(page_index);
+        int dword_in_page = (native_ptr - begin) / 2;
+        return in_dontmove_dwordindex_p(page_index, dword_in_page);
+    } else {
+        return 0;
+    }
+}
+
+// fixme - can be deleted but keep for safety reasons for now
+void
+unmark_conservative_pointers()
+{
+    page_index_t i;
+    first_consi_page = -1;
+
+    for (i = 0; i < last_free_page; i++) {
+        page_table[i].dontmove_dwords = NULL;
+    }
+}
+
+// FIXME - copy, but for debug print only
+static inline lispobj *
+forwarding_pointer_value_tmp(lispobj *pointer) {
+#ifdef LISP_FEATURE_GENCGC
+    return (lispobj *) ((pointer_sized_uint_t) pointer[1]);
+#else
+    return (lispobj *) ((pointer_sized_uint_t) pointer[0]);
+#endif
+}
+
+void
+anything_pointing_to_wipe_areas_here(lispobj *begin, lispobj *end, page_index_t maybe_opage, char *label, int marker)
+{
+// disabled for multi word conversion, re-enable if needed for debugging
+#if 0
+    // mental trap PSA: the source of the pointers might not be in dynamic space and hence might not
+    // have a page.  However, the targets we are interested in, the consi pages, do have a page
+    lispobj *addr;
+    for (addr = begin; addr < end; addr++) {
+        lispobj object = *addr;
+        if (is_lisp_pointer(object)) {
+            // careful, target_page can be filled both when
+            // it returns 1 or 0
+            page_index_t target_page = -1;
+            space_matches_p(object, from_space, &target_page);
+            // fixme, this is functionality pulled out of space_matches_p
+            if (target_page == -1 || target_page >= page_table_pages) {
+                continue;
+            }
+#if 1
+            lispobj *ptr = native_pointer(object);
+            if (*ptr == wipe_with || addr == (lispobj*)0x10034d8be0) {
+                fprintf(stderr, "meh2 '%s' %p -> %p val 0x%llx\n", label, addr, ptr, (long long)*ptr);
+            }
+#endif
+            struct page *page = &page_table[target_page];
+            if (page->conservatively_pointed_to &&
+                page->conservatively_pointed_to != (void *)-1) {
+                fprintf(stderr, "meh3 '%s' %p -> %p page %d val 0x%llx\n"
+                        , label, addr, ptr
+                        , (int)target_page
+                        , (long long)*ptr
+                        );
+                lispobj *ptr = native_pointer(object);
+                lispobj *fwd_target = NULL;
+                int is_forwarding_p = 0;
+                int is_in_protected_area = 0;
+                if (forwarding_pointer_p(ptr)) {
+                    is_forwarding_p = 1;
+                    fwd_target = forwarding_pointer_value_tmp(ptr);
+                }
+                if (ptr >= page->conservatively_pointed_to &&
+                    ptr < page->conservatively_pointed_to
+                    + page->conservatively_pointed_to_size) {
+                    is_in_protected_area = 1;
+                }
+#if 0
+                if (i == target_page && is_in_protected_area == 0) {
+                    continue;
+                }
+#endif
+#if 0
+                if (page_table[i].gen == gc_alloc_generation) {
+                    continue;
+                }
+#endif
+                int gen = -1;
+                int original_page_consi_p = 0;
+                if (maybe_opage != -1) {
+                    gen = page_table[maybe_opage].gen;
+                }
+                fprintf(stderr, "Cra223a%d %s: %p in page %d gen %d/%d->%d points to %p/%p in page %d, forwarding %d/%p protected %d val 0x%llx opage_consi %d\n"
+                        , marker
+                        , label
+                        , (void *)addr
+                        , (int)maybe_opage
+                        , gen
+                        , from_space
+                        , new_space
+                        , (void *)object
+                        , (void *)ptr
+                        , (int)target_page
+                        , is_forwarding_p
+                        , fwd_target
+                        , is_in_protected_area
+                        , (long long)*ptr
+                        , original_page_consi_p
+                        );
+            }
+        }
+    }
+#endif
+}
+
+const int interesting_page = -2; // do not use -1
+
+static void
+find_stuff_pointing_to_wipe_areas(char *label, int marker)
+{
+// disabled for multi word conversion, re-enable if needed for debugging
+#if 0
+    if (verbosefixes < 3) {
+        return;
+    }
+
+    fprintf(stderr, "Cra224: finding things pointing to consi pages %s %d\n", label, marker);
+    page_index_t i;
+    for (i = 0; i < last_free_page; i++) {
+        struct page *opage = &page_table[i];
+        if (page_table[i].bytes_used == 0) {
+            continue;
+        }
+        lispobj *begin = page_address(i);
+        lispobj *end = begin + PAGE_BYTES / N_WORD_BYTES;
+        lispobj *addr;
+        if (i == interesting_page) {
+            fprintf(stderr, "Cra225d: scanning page %d gen %d/%d->%d %p-%p\n", interesting_page, opage->gen, from_space, new_space, begin, end);
+        }
+        for (addr = begin; addr < end; addr++) {
+            int original_page_consi_p = 0;
+            if (opage->gen == from_space) {
+                if (opage->conservatively_pointed_to && opage->conservatively_pointed_to != (void *)-1) {
+                    original_page_consi_p = 1;
+                } else {
+                    // this page is about to be freed, stale contents
+                    // FIXME - apparently not
+                    if (i != interesting_page) {
+                        continue;
+                    }
+                }
+            }
+            lispobj object = *addr;
+            if (is_lisp_pointer(object)) {
+                // careful, target_page can be filled both when
+                // it return 1 or 0
+                page_index_t target_page = -1;
+                space_matches_p(object, from_space, &target_page);
+                // fixme, this is functionality pulled out of space_matches_p
+                if (target_page == -1 || target_page >= page_table_pages) {
+                    continue;
+                }
+                lispobj *ptr = native_pointer(object);
+                struct page *page = &page_table[target_page];
+                lispobj *fwd_target = NULL;
+                int is_forwarding_p = 0;
+                if (forwarding_pointer_p(ptr)) {
+                    is_forwarding_p = 1;
+                    fwd_target = forwarding_pointer_value_tmp(ptr);
+                }
+                // protected area means either in a consi page and the protected object (#1)
+                // or a page that doesn't have anything to do with consi (-1)
+                // or it is open for destruction (0)
+                int is_in_protected_area;
+                if (page->conservatively_pointed_to
+                    && page->conservatively_pointed_to != (void *)-1) {
+                    if (ptr >= page->conservatively_pointed_to &&
+                        ptr < page->conservatively_pointed_to
+                        + page->conservatively_pointed_to_size) {
+                        is_in_protected_area = 1;
+                    } else {
+                        is_in_protected_area = 0;
+                    }
+                } else {
+                        is_in_protected_area = -1;
+                }
+                if ((*ptr == wipe_with)
+                    || i == interesting_page
+                    || (page->conservatively_pointed_to
+                        && page->conservatively_pointed_to != (void *)-1
+                        && !(i == target_page && is_in_protected_area == 0)
+                        )) {
+#if 0
+                    if (page_table[i].gen == gc_alloc_generation) {
+                        continue;
+                    }
+#endif
+                    fprintf(stderr, "Cra225a%d %s: %p in page %d gen %d/%d->%d points to %p/%p in page %d, forwarding %d/%p protected %d val 0x%llx (next 0x%llx 0x%llx 0x%llx) opage_consi %d\n"
+                            , marker
+                            , label
+                            , (void *)addr
+                            , (int)i
+                            , page_table[i].gen
+                            , from_space
+                            , new_space
+                            , (void *)object
+                            , (void *)ptr
+                            , (int)target_page
+                            , is_forwarding_p
+                            , fwd_target
+                            , is_in_protected_area
+                            , (long long)*ptr
+                            , (long long)*(ptr+1)
+                            , (long long)*(ptr+2)
+                            , (long long)*(ptr+3)
+                            , original_page_consi_p
+                            );
+                    if (is_lisp_pointer(*ptr)) {
+                        lispobj object2 = (lispobj)*ptr;
+                        lispobj *ptr2 = native_pointer(object2);
+                        page_index_t target_page2 = -1;
+                        space_matches_p(object2, from_space, &target_page2);
+                        fprintf(stderr, "Cra225c%d %s: this is a pointer in turn -> %p page %d val 0x%llx\n"
+                                , marker
+                                , label
+                                , ptr2
+                                , (int)target_page2
+                                , (long long)*ptr2
+                                );
+                    }
+                }
+            }
+        }
+    }
+#endif
+}
+
+void
+find_weak_stuff_pointing_to_wipe_areas(char *id1, int id2)
+{
+    struct weak_pointer *wp, *next_wp;
+    for (wp = weak_pointers, next_wp = NULL; wp != NULL; wp = next_wp) {
+        lispobj value = wp->value;
+        //lispobj *first_pointer;
+        gc_assert(widetag_of(wp->header)==WEAK_POINTER_WIDETAG);
+
+        next_wp = wp->next;
+        wp->next = NULL;
+        if (next_wp == wp) /* gencgc uses a ref to self for end of list */
+            next_wp = NULL;
+
+        if (verbosefixes >= 3) {
+            anything_pointing_to_wipe_areas_here(&value, (&value)+1, -1, "foundweak", id2);
+        }
+    }
+}
+
+
+void
+whatsupwithconsi(char *id1, int id2)
+{
+// disabled for multi word conversion, re-enable if needed for debugging
+#if 0
+    if (verbosefixes < 3)
+        return;
+
+    if (verbosefixes >= 5) {
+        find_stuff_pointing_to_wipe_areas(id1, id2);
+        find_weak_stuff_pointing_to_wipe_areas(id1, id2);
+    }
+
+    int i;
+
+    if (id1)
+        fprintf(stderr, "Cra87a: stats for conservatively pointed to pages '%s' %d\n", id1, id2);
+
+    for (i = 0; i < last_free_page; i++) {
+        if (page_table[i].conservatively_pointed_to) {
+            if (page_table[i].conservatively_pointed_to == (void *)-1) {
+                fprintf(stderr, "Cra87b1: page %d gen %d/%d->%d freep %d object %p\n"
+                        , i
+                        , page_table[i].gen
+                        , from_space
+                        , new_space
+                        , page_free_p(i)
+                        , page_table[i].conservatively_pointed_to
+                        );
+            } else {
+                fprintf(stderr, "Cra87b2: page %d gen %d/%d->%d freep %d object %p/0x%llx\n"
+                        , i
+                        , page_table[i].gen
+                        , from_space
+                        , new_space
+                        , page_free_p(i)
+                        , page_table[i].conservatively_pointed_to
+                        , *(long long*)(page_table[i].conservatively_pointed_to)
+                        );
+            }
+        }
+    }
+#endif
+}
+
+void
+print_consi_page(char *what, page_index_t pageindex)
+{
+// disabled for multi word conversion, re-enable if needed for debugging
+#if 0
+    if (verbosefixes < 5)
+        return;
+
+    lispobj *ptr = page_table[pageindex].conservatively_pointed_to;
+
+    if (!ptr) {
+        return;
+    }
+    if (ptr == (lispobj *)-1) {
+        fprintf(stderr, "Craprint: consi page %d bailed out\n", (int)pageindex);
+        return;
+    }
+    lispobj *iterator;
+
+    for (iterator = ptr; iterator < ptr + page_table[pageindex].conservatively_pointed_to_size; iterator++) {
+        // lispobj *pointertarget = *((lispobj *)iterator);
+        fprintf(stderr, "Cra26e %s page %d %p: 0x%llx\n", what, (int)pageindex, iterator, *(long long unsigned *)iterator);
+    }
+#endif
+}
+
+// just verbose
+int
+scavengev(lispobj *start, sword_t n_words)
+{
+    if (verbosefixes > 3) {
+        fprintf(stderr, "Scavenging for consi %p-%p, nwords = %d\n"
+                , start
+                , start + n_words
+                , (int)n_words
+                );
+    }
+    scavenge(start, n_words);
+    return n_words;
+}
+
+/*
+ * Why is this restricted to protected objects only?
+ * Because the rest of the page has been scavenged already,
+ * and since that leaves forwarding pointers in the unprotected
+ * areas you cannot scavenge it again until those are gone.
+ */
+void
+scavenge_pages_with_conservative_pointers_to_them_protected_objects_only()
+{
+    if (!fixesp) {
+        return;
+    }
+    int words_scavenged = 0;
+    page_index_t i;
+    scavenge_reason = "consipartialpage";
+    for (i = 0; i < last_free_page; i++) {
+        if (!page_table[i].dontmove_dwords) {
+            continue;
+        }
+        print_consi_page("beforescavenge", i);
+
+        lispobj *begin = page_address(i);
+        unsigned int dword;
+
+        lispobj *scavme_begin = NULL;
+        for (dword = 0; dword < GENCGC_CARD_BYTES / N_WORD_BYTES / 2; dword++) {
+            if (in_dontmove_dwordindex_p(i, dword)) {
+                if (!scavme_begin) {
+                    scavme_begin = begin + dword * 2;
+                }
+            } else {
+                // contiguous area stopped
+                if (scavme_begin) {
+                    words_scavenged += scavengev(scavme_begin, (begin + dword * 2) - scavme_begin);
+                }
+                scavme_begin = NULL;
+            }
+        }
+        if (scavme_begin) {
+            words_scavenged += scavengev(scavme_begin, (begin + dword * 2) - scavme_begin);
+        }
+#if 0
+                scavenge(begin + dword*2, 2);
+                words_scavenged += 2;
+#endif
+        print_consi_page("afterscavenge ", i);
+    }
+    scavenge_reason = "after consipartialpage";
+    if (verbosefixes > 2) {
+        fprintf(stderr, "Cra28a: scavenged %d words in consi pages\n", words_scavenged);
+    }
+}
+
+// shouldn't be needed but what do I know?
+void
+scavenge_pages_with_conservative_pointers_to_them()
+{
+#if 0
+    if (!fixesp) {
+        return;
+    }
+    page_index_t i;
+    for (i = 0; i < last_free_page; i++) {
+      if (page_table[i].gen != from_space) {
+            continue;
+        }
+        lispobj *begin = page_address(i);
+
+        fprintf(stderr, "Cra28b1: scavenge oldconsi page %d\n", (int)i);
+        scavenge_reason = "consi2";
+        scavenge(begin, PAGE_BYTES / N_WORD_BYTES);
+        scavenge_reason = "after consi2";
+        print_consi_page("afterscavenge ", i);
+    }
+#endif
+}
+
+void
+do_the_wipe()
+{
+    page_index_t i;
+    lispobj *begin;
+    int words_wiped = 0;
+    int lisp_pointers_wiped = 0;
+    int pages_considered = 0;
+    int n_pages_cannot_wipe = 0;
+
+    for (i = 0; i < last_free_page; i++) {
+        if (!page_table[i].dont_move) {
+            continue;
+        }
+        pages_considered++;
+        if (!page_table[i].dontmove_dwords) {
+            n_pages_cannot_wipe++;
+            continue;
+        }
+        begin = page_address(i);
+        unsigned int dword;
+        for (dword = 0; dword < GENCGC_CARD_BYTES / N_WORD_BYTES / 2; dword++) {
+            if (!in_dontmove_dwordindex_p(i, dword)) {
+                if (is_lisp_pointer(*(begin + dword * 2))) {
+                    lisp_pointers_wiped++;
+                }
+                if (is_lisp_pointer(*(begin + dword * 2 + 1))) {
+                    lisp_pointers_wiped++;
+                }
+                *(begin + dword * 2) = wipe_with;
+                *(begin + dword * 2 + 1) = wipe_with;
+                words_wiped += 2;
+            }
+        }
+        free(page_table[i].dontmove_dwords);
+        page_table[i].dontmove_dwords = NULL;
+
+        // move the page to newspace
+        generations[new_space].bytes_allocated += page_table[i].bytes_used;
+        generations[page_table[i].gen].bytes_allocated -= page_table[i].bytes_used;
+        page_table[i].gen = new_space;
+
+#if 0
+        //lispobj *iterator;
+        // this is a page that we should wipe but we can't with the simplified code
+        if ((void *)page_table[i].conservatively_pointed_to == (void *)-1) {
+            n_pages_cannot_wipe++;
+            continue;
+        }
+        if (!page_table[i].dont_move) {
+            continue;
+        }
+        if (page_table[i].gen != from_space) {
+            continue;
+        }
+        if (!page_table[i].conservatively_pointed_to) {
+            continue;
+        }
+        // OK, if we make it through to here we can wipe
+        pages_considered++;
+
+        if (verbosefixes >= 3) {
+            fprintf(stderr, "Cra25b: page %d gen %d/%d->%d: %p\n"
+                    , (int)i
+                    , page_table[i].gen
+                    , from_space
+                    , new_space
+                    , page_table[i].conservatively_pointed_to);
+        }
+        int size = page_table[i].conservatively_pointed_to_size;
+
+        if (verbosefixes >= 3) {
+            fprintf(stderr, "Cra26d: not wiping %p-%p size %d widetag %d words in page %d %p-%p wipeobj 0x%llx\n"
+                    , page_table[i].conservatively_pointed_to
+                    , page_table[i].conservatively_pointed_to + size
+                    , size
+                    , widetag_of(*page_table[i].conservatively_pointed_to)
+                    , (int)i
+                    , page_address(i)
+                    , page_address(i) + PAGE_BYTES
+                    , (long long)wipe_with);
+        }
+
+        start = page_address(i);
+        int previous_gen_i_was_in = page_table[i].gen;
+        for (iterator = start; iterator < start + (GENCGC_CARD_BYTES / N_WORD_BYTES); iterator++) {
+            if (iterator >= page_table[i].conservatively_pointed_to &&
+                iterator < page_table[i].conservatively_pointed_to + size) {
+                // protected
+                // fprintf(stderr, "skipping the wipe of %p\n", iterator);
+                continue;
+            }
+            if (fixesp) {
+                //*iterator = wipe_with;
+                *iterator = (i * 100000 + iterator - start ) * 2;
+            }
+            words_wiped++;
+        }
+        // FIXME - make sure new_space is still at the correct value!
+        generations[new_space].bytes_allocated += page_table[i].bytes_used;
+        page_table[i].gen = new_space;
+        generations[previous_gen_i_was_in].bytes_allocated -= page_table[i].bytes_used;
+#endif
+    }
+    whatsupwithconsi("afterwipe", 3);
+#if 1
+    if (verbosefixes >= 1 && lisp_pointers_wiped > 0) {
+        fprintf(stderr, "Cra25a: wiped %d words (%d lisp_pointers) in %d pages, cannot wipe %d pages \n"
+                , words_wiped, lisp_pointers_wiped, pages_considered, n_pages_cannot_wipe);
+    }
+#endif
+}
+
+void
+set_page_consi_bit(page_index_t pageindex, lispobj *mark_which_pointer)
+{
+    struct page *page = &page_table[pageindex];
+
+    if (mark_which_pointer == NULL) {
+        fprintf(stderr, "Cra75a: PANIC75\n");
+        exit(1);
+    }
+    if (page->dontmove_dwords == NULL) {
+        const int n_dwords_in_card = GENCGC_CARD_BYTES / N_WORD_BYTES / 2;
+        const int malloc_size = sizeof(in_use_marker_t) * n_dwords_in_card;
+        page->dontmove_dwords = malloc(malloc_size);
+        if (page->dontmove_dwords == NULL) {
+            fprintf(stderr, "Cra76a: PANIC76\n");
+            exit(1);
+        }
+        bzero(page->dontmove_dwords, malloc_size);
+    }
+
+    sizetab_trigger = 2;
+    int size = (sizetab[widetag_of(mark_which_pointer[0])])(mark_which_pointer);
+    sizetab_trigger = 0;
+    if (size == 1 &&
+        (fixnump(*mark_which_pointer)
+        || is_lisp_pointer(*mark_which_pointer)
+        || lowtag_of(*mark_which_pointer) == 9
+         )) {
+        size = 2;
+    }
+    // if my wild theory is correct then fixnums that are parts of cons cells should
+    // be the only thing that gets us a bad size out of sizetab[]()
+    if (size % 2 != 0) {
+        fprintf(stderr, "Cra45b23: PANIC, uneven size %d in page %d lotag %d lisppointer? %d\n"
+                , size, (int)pageindex, lowtag_of(*mark_which_pointer)
+                , is_lisp_pointer(*mark_which_pointer)
+                );
+        exit(23);
+    }
+    lispobj *begin = page_address(pageindex);
+    int begin_dword = (mark_which_pointer - begin) / 2;
+
+    if (verbosefixes > 2) {
+        fprintf(stderr, "Cra23f: marking consi: page %d (%p-%p): mark %p-%p (%d n_words) dwords %d-%d\n"
+                , (int)pageindex
+                , begin
+                , begin + GENCGC_CARD_BYTES / N_WORD_BYTES
+                , mark_which_pointer
+                , mark_which_pointer + size
+                , size
+                , begin_dword
+                , begin_dword + size / 2
+                );
+    }
+    int dword;
+    for (dword = begin_dword; dword < begin_dword + size / 2; dword++) {
+        page->dontmove_dwords[dword] = 1;
+    }
+
+#if 0
+    // already marked as having multiple pointers to it / bailout
+    if (page->conservatively_pointed_to == (void *)-1) {
+        return;
+    }
+    // duplicate pointer to same location, OK
+    if (page->conservatively_pointed_to == mark_which_pointer) {
+        return;
+    }
+
+#if 0
+    // FIXME - temporary debug thing
+    // REALLY FIXME - this doesn't work since we don't have the lisp pointer
+    if (is_lisp_pointer(*mark_which_pointer)) {
+        if (verbosefixes >= 2) {
+            fprintf(stderr, "Cra23c: page %d temporarily fallback, pointer to pointer %p %p\n"
+                    , pageindex, mark_which_pointer, page->conservatively_pointed_to);
+        }
+        page->conservatively_pointed_to = (void *)-1;
+        return;
+    }
+#endif
+
+    // new value, record pointer and object size
+    if (page->conservatively_pointed_to == NULL) {
+        page->conservatively_pointed_to = mark_which_pointer;
+        sizetab_trigger = 2;
+        int size = (sizetab[widetag_of(page_table[pageindex].conservatively_pointed_to[0])])
+            (page_table[pageindex].conservatively_pointed_to);
+        sizetab_trigger = 0;
+        if (fixnump(*page->conservatively_pointed_to)
+            || is_lisp_pointer(*page->conservatively_pointed_to)) {
+            size = 2;
+        }
+        // if my wild theory is correct then fixnums that are parts of cons cells should
+        // be the only thing that gets us a bad size out of sizetab[]()
+        //  && !is_lisp_pointer(*page->conservatively_pointed_to)
+        if (size % 2 != 0) {
+            fprintf(stderr, "Cra45b23: PANIC, uneven size %d in page %d lotag %d lisppointer? %d\n"
+                    , size, pageindex, lowtag_of(*page->conservatively_pointed_to)
+                    , is_lisp_pointer(*page->conservatively_pointed_to)
+                    );
+            exit(23);
+        }
+        page->conservatively_pointed_to_size = size;
+        if (first_consi_page == -1 || pageindex < first_consi_page) {
+            if (verbosefixes >= 4) {
+                fprintf(stderr, "Cra45b1: Lowest consi page is now %d\n", pageindex);
+            }
+            first_consi_page = pageindex;
+        }
+        return;
+    }
+    // already had a pointer but new one is not identical, bail out
+    if (verbosefixes >= 0) {
+        fprintf(stderr, "Cra23b: page %d already has a conservative pointer, giving up %p %p\n"
+                , pageindex, mark_which_pointer, page->conservatively_pointed_to);
+    }
+    page->conservatively_pointed_to = (void *)-1;
+#endif
+}
+
 /* Take a possible pointer to a Lisp object and mark its page in the
  * page_table so that it will not be relocated during a GC.
  *
@@ -2247,9 +2967,8 @@ maybe_adjust_large_object(lispobj *where)
  *
  * It is also assumed that the current gc_alloc() region has been
  * flushed and the tables updated. */
-
 static void
-preserve_pointer(void *addr)
+preserve_pointer(void *addr, const char *const reason)
 {
     page_index_t addr_page_index = find_page_index(addr);
     page_index_t first_page;
@@ -2261,9 +2980,14 @@ preserve_pointer(void *addr)
         || page_free_p(addr_page_index)
         || (page_table[addr_page_index].bytes_used == 0)
         || (page_table[addr_page_index].gen != from_space)
+#if 0
+        /* cracauer - we cannot skip this anymore */
         /* Skip if already marked dont_move. */
-        || (page_table[addr_page_index].dont_move != 0))
+        || (page_table[addr_page_index].dont_move != 0)
+#endif
+        )
         return;
+
     gc_assert(!(page_table[addr_page_index].allocated&OPEN_REGION_PAGE_FLAG));
     /* (Now that we know that addr_page_index is in range, it's
      * safe to index into page_table[] with it.) */
@@ -2276,6 +3000,7 @@ preserve_pointer(void *addr)
         page_table[addr_page_index].bytes_used)
         return;
 
+    /* cracauer */
     /* Filter out anything which can't be a pointer to a Lisp object
      * (or, as a special case which also requires dont_move, a return
      * address referring to something in a CodeObject). This is
@@ -2287,9 +3012,10 @@ preserve_pointer(void *addr)
      * conservative roots.  Non-x86oid systems only ever call this
      * function on known-valid lisp objects. */
 #if defined(LISP_FEATURE_X86) || defined(LISP_FEATURE_X86_64)
+    lispobj *begin_ptr = NULL;
     if (!(code_page_p(addr_page_index)
           || (is_lisp_pointer((lispobj)addr) &&
-              possibly_valid_dynamic_space_pointer(addr))))
+              possibly_valid_dynamic_space_pointer_and_store(addr, &begin_ptr))))
         return;
 #endif
 
@@ -2301,7 +3027,7 @@ preserve_pointer(void *addr)
 #if 0
     /* I think this'd work just as well, but without the assertions.
      * -dan 2004.01.01 */
-    first_page = find_page_index(page_scan_start(addr_page_index))
+    first_page = find_page_index(page_scan_start(addr_page_index));
 #else
     first_page = addr_page_index;
     while (!page_starts_contiguous_block_p(first_page)) {
@@ -2355,6 +3081,58 @@ preserve_pointer(void *addr)
             break;
     }
 
+    /* Do not do this for multi-page objects.  Those pages do not need
+     * object wipeout anyway.
+     */
+    if (i == first_page) {
+        /* We need the pointer to the beginning of the object
+         * We might have gotten it above but maybe not, so make sure
+         */
+        if (begin_ptr == NULL) {
+            possibly_valid_dynamic_space_pointer_and_store(addr, &begin_ptr);
+        }
+        set_page_consi_bit(first_page, begin_ptr);
+    } else {
+        if (verbosefixes >= 2) {
+            fprintf(stderr, "Cra65a: Pages %d-%d (%d pages) hold a multi-page object\n"
+                    , (int)first_page, (int)i, (int)(i - first_page));
+        }
+    }
+
+    /* We know it points into dynamic space, so we can follow the pointer
+     * without fear of segfault.
+     *
+     * Furthermore, if the tag bits of the thing pointed to indicate a fixnum
+     * we know this can't be a valid pointer since fixnums cannot randomly
+     * float around the heap.  They can live on the heap, but only as part
+     * of other things (arrays or structs) and a pointer can only point
+     * to the beginning of that other thing, not inside it.
+     */
+#if 0
+    if (begin_ptr && page_table[first_page].conservatively_pointed_to != (void *)-1) {
+        int lowtag = lowtag_of(*(lispobj *)begin_ptr);
+        void *pageaddr;
+        pageaddr = page_address(i);
+        if (verbosefixes >= 3) {
+            fprintf(stderr
+                    , "Cra1c: pointer %p->%p nails down pages %d - %d addr %p-%p because '%s' lowtag 0x%x, contents 0x%llx/0x%llx gen %d/%d/%d\n"
+                    , addr, begin_ptr, (int)first_page, (int)i
+                    , pageaddr, pageaddr + PAGE_BYTES
+                    , reason, lowtag
+                   , *(long long *)begin_ptr
+                    , page_table[first_page].conservatively_pointed_to ?
+                    *(long long*)(page_table[first_page].conservatively_pointed_to)
+                    : 0xDEADBEEF
+                    , page_table[first_page].gen
+                    , new_space
+                    // fixme might not be > 0
+                    , page_table[first_page-1].gen
+                    );
+            fflush(stderr);
+        }
+    }
+#endif
+
     /* Check that the page is now static. */
     gc_assert(page_table[addr_page_index].dont_move != 0);
 }
@@ -2467,6 +3245,10 @@ scavenge_generations(generation_index_t from, generation_index_t to)
     page_index_t i;
     page_index_t num_wp = 0;
 
+    if (verbosefixes >= 3) {
+        fprintf(stderr, "Cra91a: scavenging gens %d-%d, newspace is %d\n", from, to, new_space);
+    }
+
 #define SC_GEN_CK 0
 #if SC_GEN_CK
     /* Clear the write_protected_cleared flags on all pages. */
@@ -2495,10 +3277,12 @@ scavenge_generations(generation_index_t from, generation_index_t to)
                     break;
             }
             if (!write_protected) {
+                scavenge_reason = "generations";
                 scavenge(page_address(i),
                          ((uword_t)(page_table[last_page].bytes_used
                                           + npage_bytes(last_page-i)))
                          /N_WORD_BYTES);
+                scavenge_reason = "after generations";
 
                 /* Now scan the pages and write protect those that
                  * don't have pointers to younger generations. */
@@ -2537,6 +3321,22 @@ scavenge_generations(generation_index_t from, generation_index_t to)
 #endif
 }
 
+#if 0
+void
+scavenge_pages_conservatively_pointed_to()
+{
+    int i;
+    for (i = 0; i < last_free_page; i++) {
+        if (page_table[i].conservatively_pointed_to && page_table[i].conservatively_pointed_to != (lispobj *)-1) {
+            scavenge_reason = "consi";
+            scavenge(page_address(i),
+                     GENCGC_CARD_BYTES / N_WORD_BYTES);
+            scavenge_reason = "after consi";
+        }
+    }
+}
+#endif
+
 
 /* Scavenge a newspace generation. As it is scavenged new objects may
  * be allocated to it; these will also need to be scavenged. This
@@ -2615,7 +3415,9 @@ scavenge_newspace_generation_one_scan(generation_index_t generation)
                                / N_WORD_BYTES);
                 new_areas_ignore_page = last_page;
 
+                scavenge_reason = "newspace_one";
                 scavenge(page_scan_start(i), nwords);
+                scavenge_reason = "after newspace_one";
 
             }
             i = last_page;
@@ -2662,7 +3464,9 @@ scavenge_newspace_generation(generation_index_t generation)
      * is O(W^2+N) as Bruno Haible warns in
      * http://www.haible.de/bruno/papers/cs/weak/WeakDatastructures-writeup.html
      * see "Implementation 2". */
+    scavenge_reason = "weak_hashtables0";
     scav_weak_hash_tables();
+    scavenge_reason = "after weak_hashtables0";
 
     /* Flush the current regions updating the tables. */
     gc_alloc_update_all_page_tables();
@@ -2712,7 +3516,9 @@ scavenge_newspace_generation(generation_index_t generation)
             /* Record all new areas now. */
             record_new_objects = 2;
 
+            scavenge_reason = "weak_hashtables1";
             scav_weak_hash_tables();
+            scavenge_reason = "after weak_hashtables1";
 
             /* Flush the current regions updating the tables. */
             gc_alloc_update_all_page_tables();
@@ -2725,10 +3531,14 @@ scavenge_newspace_generation(generation_index_t generation)
                 size_t offset = (*previous_new_areas)[i].offset;
                 size_t size = (*previous_new_areas)[i].size / N_WORD_BYTES;
                 gc_assert((*previous_new_areas)[i].size % N_WORD_BYTES == 0);
+                scavenge_reason = "newspace";
                 scavenge(page_address(page)+offset, size);
+                scavenge_reason = "after newspace";
             }
 
+            scavenge_reason = "weak_hashtables2";
             scav_weak_hash_tables();
+            scavenge_reason = "after weak_hashtables2";
 
             /* Flush the current regions updating the tables. */
             gc_alloc_update_all_page_tables();
@@ -2836,6 +3646,10 @@ free_oldspace(void)
         last_page = first_page;
 
         do {
+            if (page_table[last_page].dontmove_dwords) {
+                fprintf(stderr, "Cra777 PANIC page %d\n", (int)last_page);
+                exit(42);
+            }
             /* Free the page. */
             bytes_freed += page_table[last_page].bytes_used;
             generations[page_table[last_page].gen].bytes_allocated -=
@@ -2874,22 +3688,22 @@ print_ptr(lispobj *addr)
     if (pi1 != -1)
         fprintf(stderr,"  %p: page %d  alloc %d  gen %d  bytes_used %d  offset %lu  dont_move %d\n",
                 addr,
-                pi1,
+                (int)pi1,
                 page_table[pi1].allocated,
                 page_table[pi1].gen,
                 page_table[pi1].bytes_used,
                 page_table[pi1].scan_start_offset,
                 page_table[pi1].dont_move);
     fprintf(stderr,"  %x %x %x %x (%x) %x %x %x %x\n",
-            *(addr-4),
-            *(addr-3),
-            *(addr-2),
-            *(addr-1),
-            *(addr-0),
-            *(addr+1),
-            *(addr+2),
-            *(addr+3),
-            *(addr+4));
+            (unsigned int)*(addr-4),
+            (unsigned int)*(addr-3),
+            (unsigned int)*(addr-2),
+            (unsigned int)*(addr-1),
+            (unsigned int)*(addr-0),
+            (unsigned int)*(addr+1),
+            (unsigned int)*(addr+2),
+            (unsigned int)*(addr+3),
+            (unsigned int)*(addr+4));
 }
 #endif
 
@@ -2963,7 +3777,7 @@ verify_space(lispobj *start, size_t words)
                 }
                 */
             } else {
-                extern void funcallable_instance_tramp;
+                extern sword_t funcallable_instance_tramp;
                 /* Verify that it points to another valid space. */
                 if (!to_readonly_space && !to_static_space
                     && (thing != (lispobj)&funcallable_instance_tramp)
@@ -3151,7 +3965,9 @@ verify_space(lispobj *start, size_t words)
 #ifdef NO_TLS_VALUE_MARKER_WIDETAG
                 case NO_TLS_VALUE_MARKER_WIDETAG:
 #endif
+                    sizetab_trigger = 3;
                     count = (sizetab[widetag_of(*start)])(start);
+                    sizetab_trigger = 0;
                     break;
 
                 default:
@@ -3201,7 +4017,7 @@ verify_generation(generation_index_t generation)
             && (page_table[i].bytes_used != 0)
             && (page_table[i].gen == generation)) {
             page_index_t last_page;
-            int region_allocation = page_table[i].allocated;
+            // int region_allocation = page_table[i].allocated;
 
             /* This should be the start of a contiguous block */
             gc_assert(page_starts_contiguous_block_p(i));
@@ -3334,41 +4150,43 @@ preserve_context_registers (os_context_t *c)
      */
 #if defined(LISP_FEATURE_DARWIN)||defined(LISP_FEATURE_WIN32)
 #if defined LISP_FEATURE_X86
-    preserve_pointer((void*)*os_context_register_addr(c,reg_EAX));
-    preserve_pointer((void*)*os_context_register_addr(c,reg_ECX));
-    preserve_pointer((void*)*os_context_register_addr(c,reg_EDX));
-    preserve_pointer((void*)*os_context_register_addr(c,reg_EBX));
-    preserve_pointer((void*)*os_context_register_addr(c,reg_ESI));
-    preserve_pointer((void*)*os_context_register_addr(c,reg_EDI));
-    preserve_pointer((void*)*os_context_pc_addr(c));
+    preserve_pointer((void*)*os_context_register_addr(c,reg_EAX), "reg");
+    preserve_pointer((void*)*os_context_register_addr(c,reg_ECX), "reg");
+    preserve_pointer((void*)*os_context_register_addr(c,reg_EDX), "reg");
+    preserve_pointer((void*)*os_context_register_addr(c,reg_EBX), "reg");
+    preserve_pointer((void*)*os_context_register_addr(c,reg_ESI), "reg");
+    preserve_pointer((void*)*os_context_register_addr(c,reg_EDI), "reg");
+    preserve_pointer((void*)*os_context_pc_addr(c), "reg pc");
 #elif defined LISP_FEATURE_X86_64
-    preserve_pointer((void*)*os_context_register_addr(c,reg_RAX));
-    preserve_pointer((void*)*os_context_register_addr(c,reg_RCX));
-    preserve_pointer((void*)*os_context_register_addr(c,reg_RDX));
-    preserve_pointer((void*)*os_context_register_addr(c,reg_RBX));
-    preserve_pointer((void*)*os_context_register_addr(c,reg_RSI));
-    preserve_pointer((void*)*os_context_register_addr(c,reg_RDI));
-    preserve_pointer((void*)*os_context_register_addr(c,reg_R8));
-    preserve_pointer((void*)*os_context_register_addr(c,reg_R9));
-    preserve_pointer((void*)*os_context_register_addr(c,reg_R10));
-    preserve_pointer((void*)*os_context_register_addr(c,reg_R11));
-    preserve_pointer((void*)*os_context_register_addr(c,reg_R12));
-    preserve_pointer((void*)*os_context_register_addr(c,reg_R13));
-    preserve_pointer((void*)*os_context_register_addr(c,reg_R14));
-    preserve_pointer((void*)*os_context_register_addr(c,reg_R15));
-    preserve_pointer((void*)*os_context_pc_addr(c));
+    preserve_pointer((void*)*os_context_register_addr(c,reg_RAX), "reg");
+    preserve_pointer((void*)*os_context_register_addr(c,reg_RCX), "reg");
+    preserve_pointer((void*)*os_context_register_addr(c,reg_RDX), "reg");
+    preserve_pointer((void*)*os_context_register_addr(c,reg_RBX), "reg");
+    preserve_pointer((void*)*os_context_register_addr(c,reg_RSI), "reg");
+    preserve_pointer((void*)*os_context_register_addr(c,reg_RDI), "reg");
+    preserve_pointer((void*)*os_context_register_addr(c,reg_R8), "reg");
+    preserve_pointer((void*)*os_context_register_addr(c,reg_R9), "reg");
+    preserve_pointer((void*)*os_context_register_addr(c,reg_R10), "reg");
+    preserve_pointer((void*)*os_context_register_addr(c,reg_R11), "reg");
+    preserve_pointer((void*)*os_context_register_addr(c,reg_R12), "reg");
+    preserve_pointer((void*)*os_context_register_addr(c,reg_R13), "reg");
+    preserve_pointer((void*)*os_context_register_addr(c,reg_R14), "reg");
+    preserve_pointer((void*)*os_context_register_addr(c,reg_R15), "reg");
+    preserve_pointer((void*)*os_context_pc_addr(c), "reg pc");
 #else
     #error "preserve_context_registers needs to be tweaked for non-x86 Darwin"
 #endif
 #endif
 #if !defined(LISP_FEATURE_WIN32)
     for(ptr = ((void **)(c+1))-1; ptr>=(void **)c; ptr--) {
-        preserve_pointer(*ptr);
+      preserve_pointer(*ptr, "uh?");
     }
 #endif
 }
 #endif
 
+/* cracauer */
+
 static void
 move_pinned_pages_to_newspace()
 {
@@ -3378,10 +4196,42 @@ move_pinned_pages_to_newspace()
      * pages.  Pinned pages are precisely those pages which must not
      * be evacuated, so move them to newspace directly. */
 
+    if (fixesp) {
+        ; // fprintf(stderr, "FIXES TURNED ON - cracauer\n");
+    } else {
+        fprintf(stderr, "FIXES TURNED OFF - cracauer\n");
+    }
     for (i = 0; i < last_free_page; i++) {
         if (page_table[i].dont_move &&
             /* dont_move is cleared lazily, so validate the space as well. */
             page_table[i].gen == from_space) {
+
+            /* Special treatment.  If there is just one conservative pointer then
+               deal with it so that everything else is wiped, which means keeping
+               in where it is, do not move to newspace.
+               However, bail out of this if there were multiple conservative roots
+               to the same page (marked as -1).
+
+               Or in other words, we now only move to newspace when there were
+               multiple.
+            */
+
+            if (page_table[i].dontmove_dwords == NULL) {
+                if (verbosefixes >= 2) {
+                    fprintf(stderr
+                            , "Cra45a1 from_space page %d has dont_move but does not have conservatively_pointed_to (probably multi-page object) moving to newspace\n"
+                            , (int)i);
+                }
+            } else {
+                // -1 marks that there were multiple conservative roots
+                // in that case go on to move the page
+                if (fixesp) {
+                    if (verbosefixes >= 3) {
+                        fprintf(stderr, "Cra45a0: Liking to live dangerous with page %d, not moving to newspace, gens %d/%d->%d\n", (int)i, page_table[i].gen, from_space, new_space);
+                    }
+                    continue;
+                }
+            }
             page_table[i].gen = new_space;
             /* And since we're moving the pages wholesale, also adjust
              * the generation allocation counters. */
@@ -3401,6 +4251,16 @@ garbage_collect_generation(generation_index_t generation, int raise)
     uword_t static_space_size;
     struct thread *th;
 
+    whatsupwithconsi("verybeginning", generation);
+
+    if (verbosefixes >= 3) {
+        fprintf(stderr, "Cra28b: Collecting gen %d, scratch %d, pseudo_stat %d highest normal %d, alloc_gen %d\n"
+                , generation, SCRATCH_GENERATION, PSEUDO_STATIC_GENERATION
+                , HIGHEST_NORMAL_GENERATION
+                , gc_alloc_generation
+                );
+    }
+
     gc_assert(generation <= HIGHEST_NORMAL_GENERATION);
 
     /* The oldest generation can't be raised. */
@@ -3412,6 +4272,8 @@ garbage_collect_generation(generation_index_t generation, int raise)
     /* Initialize the weak pointer list. */
     weak_pointers = NULL;
 
+    unmark_conservative_pointers();
+
     /* When a generation is not being raised it is transported to a
      * temporary generation (NUM_GENERATIONS), and lowered when
      * done. Set up this new generation. There should be no pages
@@ -3437,8 +4299,10 @@ garbage_collect_generation(generation_index_t generation, int raise)
     /* Before any pointers are preserved, the dont_move flags on the
      * pages need to be cleared. */
     for (i = 0; i < last_free_page; i++)
-        if(page_table[i].gen==from_space)
+        if (page_table[i].gen == from_space) {
             page_table[i].dont_move = 0;
+            page_table[i].dontmove_dwords = NULL;
+        }
 
     /* Un-write-protect the old-space pages. This is essential for the
      * promoted pages as they may contain pointers into the old-space
@@ -3487,7 +4351,7 @@ garbage_collect_generation(generation_index_t generation, int raise)
              * in addition to the SP.  The return PC gets saved by the
              * foreign call wrapper, and removed from the control stack
              * into a register. */
-            preserve_pointer(th->pc_around_foreign_call);
+            preserve_pointer(th->pc_around_foreign_call, "pc around foreign");
 
             /* And on platforms with interrupts: scavenge ctx registers. */
 
@@ -3529,7 +4393,7 @@ garbage_collect_generation(generation_index_t generation, int raise)
                 lose("garbage_collect: no SP known for thread %x (OS %x)",
                      th, th->os_thread);
             for (ptr = ((void **)th->control_stack_end)-1; ptr >= esp;  ptr--) {
-                preserve_pointer(*ptr);
+                preserve_pointer(*ptr, "sp");
             }
         }
     }
@@ -3542,7 +4406,7 @@ garbage_collect_generation(generation_index_t generation, int raise)
         while (pin_list != NIL) {
             struct cons *list_entry =
                 (struct cons *)native_pointer(pin_list);
-            preserve_pointer(list_entry->car);
+            preserve_pointer(list_entry->car, "alien code or something");
             pin_list = list_entry->cdr;
         }
     }
@@ -3552,9 +4416,9 @@ garbage_collect_generation(generation_index_t generation, int raise)
     if (gencgc_verbose > 1) {
         sword_t num_dont_move_pages = count_dont_move_pages();
         fprintf(stderr,
-                "/non-movable pages due to conservative pointers = %d (%d bytes)\n",
-                num_dont_move_pages,
-                npage_bytes(num_dont_move_pages));
+                "/non-movable pages due to conservative pointers = %lld (%lld bytes)\n",
+                (long long)num_dont_move_pages,
+                (long long)npage_bytes(num_dont_move_pages));
     }
 #endif
 
@@ -3564,8 +4428,11 @@ garbage_collect_generation(generation_index_t generation, int raise)
      * will not attempt to relocate their contents. */
     move_pinned_pages_to_newspace();
 
+    // ... old location for self
+
     /* Scavenge all the rest of the roots. */
 
+    whatsupwithconsi("beforecintr", generation);
 #if !defined(LISP_FEATURE_X86) && !defined(LISP_FEATURE_X86_64)
     /*
      * If not x86, we need to scavenge the interrupt context(s) and the
@@ -3574,8 +4441,11 @@ garbage_collect_generation(generation_index_t generation, int raise)
     {
         struct thread *th;
         for_each_thread(th) {
+            scavenge_reason = "interrupt context";
             scavenge_interrupt_contexts(th);
+            scavenge_reason = "control stack";
             scavenge_control_stack(th);
+            scavenge_reason = "after control stack";
         }
 
 # ifdef LISP_FEATURE_SB_SAFEPOINT
@@ -3593,27 +4463,35 @@ garbage_collect_generation(generation_index_t generation, int raise)
     }
 #endif
 
+    whatsupwithconsi("beforelispintr", generation);
     /* Scavenge the Lisp functions of the interrupt handlers, taking
      * care to avoid SIG_DFL and SIG_IGN. */
     for (i = 0; i < NSIG; i++) {
         union interrupt_handler handler = interrupt_handlers[i];
         if (!ARE_SAME_HANDLER(handler.c, SIG_IGN) &&
             !ARE_SAME_HANDLER(handler.c, SIG_DFL)) {
+            scavenge_reason = "Lisp functions in intr handl";
             scavenge((lispobj *)(interrupt_handlers + i), 1);
+            scavenge_reason = "after Lisp functions in intr handl";
         }
     }
+    whatsupwithconsi("beforebindingstacks", generation);
     /* Scavenge the binding stacks. */
     {
         struct thread *th;
         for_each_thread(th) {
             sword_t len= (lispobj *)get_binding_stack_pointer(th) -
                 th->binding_stack_start;
+            scavenge_reason = "thread binding";
             scavenge((lispobj *) th->binding_stack_start,len);
+            scavenge_reason = "after thread binding";
 #ifdef LISP_FEATURE_SB_THREAD
             /* do the tls as well */
             len=(SymbolValue(FREE_TLS_INDEX,0) >> WORD_SHIFT) -
                 (sizeof (struct thread))/(sizeof (lispobj));
+            scavenge_reason = "thread tls";
             scavenge((lispobj *) (th+1),len);
+            scavenge_reason = "after thread tls";
 #endif
         }
     }
@@ -3637,6 +4515,8 @@ garbage_collect_generation(generation_index_t generation, int raise)
     }
 #endif
 
+    whatsupwithconsi("beforestatic", generation);
+
     /* Scavenge static space. */
     static_space_size =
         (lispobj *)SymbolValue(STATIC_SPACE_FREE_POINTER,0) -
@@ -3646,30 +4526,40 @@ garbage_collect_generation(generation_index_t generation, int raise)
                "/scavenge static space: %d bytes\n",
                static_space_size * sizeof(lispobj)));
     }
+    scavenge_reason = "static space";
     scavenge( (lispobj *) STATIC_SPACE_START, static_space_size);
+    scavenge_reason = "after static space";
+
+    whatsupwithconsi("beforenormal", generation);
 
     /* All generations but the generation being GCed need to be
      * scavenged. The new_space generation needs special handling as
      * objects may be moved in - it is handled separately below. */
     scavenge_generations(generation+1, PSEUDO_STATIC_GENERATION);
 
+    whatsupwithconsi("afternormal/beforeself", generation);
+
+    //whatsupwithconsi("beforeself", 42);
+    scavenge_pages_with_conservative_pointers_to_them_protected_objects_only();
+    //whatsupwithconsi("afterself", 43);
+
+    whatsupwithconsi("beforenewspacescan/afterself", generation);
+
     /* Finally scavenge the new_space generation. Keep going until no
      * more objects are moved into the new generation */
     scavenge_newspace_generation(new_space);
 
-    /* FIXME: I tried reenabling this check when debugging unrelated
-     * GC weirdness ca. sbcl-0.6.12.45, and it failed immediately.
-     * Since the current GC code seems to work well, I'm guessing that
-     * this debugging code is just stale, but I haven't tried to
-     * figure it out. It should be figured out and then either made to
-     * work or just deleted. */
-#define RESCAN_CHECK 0
+#if 1
+    // shouldn't be needed but can detect errors earlier
+    scavenge_pages_with_conservative_pointers_to_them();
+#endif
+
+#define RESCAN_CHECK 1
 #if RESCAN_CHECK
     /* As a check re-scavenge the newspace once; no new objects should
      * be found. */
     {
         os_vm_size_t old_bytes_allocated = bytes_allocated;
-        os_vm_size_t bytes_allocated;
 
         /* Start with a full scavenge. */
         scavenge_newspace_generation_one_scan(new_space);
@@ -3677,24 +4567,44 @@ garbage_collect_generation(generation_index_t generation, int raise)
         /* Flush the current regions, updating the tables. */
         gc_alloc_update_all_page_tables();
 
-        bytes_allocated = bytes_allocated - old_bytes_allocated;
+        os_vm_size_t bytes_allocated2;
+        bytes_allocated2 = bytes_allocated - old_bytes_allocated;
 
-        if (bytes_allocated != 0) {
+        if (bytes_allocated2 != 0) {
             lose("Rescan of new_space allocated %d more bytes.\n",
-                 bytes_allocated);
+                 bytes_allocated2);
         }
     }
 #endif
 
+    whatsupwithconsi("beforeweak", generation);
+
     scan_weak_hash_tables();
     scan_weak_pointers();
 
+    if (verbosefixes >= 4) {
+        find_stuff_pointing_to_wipe_areas("beforewipe_extra", 42);
+    }
+    do_the_wipe();
+    if (verbosefixes >= 4) {
+        find_stuff_pointing_to_wipe_areas("afterwipe_extra", 43);
+    }
+
     /* Flush the current regions, updating the tables. */
     gc_alloc_update_all_page_tables();
 
+    whatsupwithconsi("beforefree", generation);
+
     /* Free the pages in oldspace, but not those marked dont_move. */
     bytes_freed = free_oldspace();
 
+    // kill warning for now
+    if (0) {
+        fprintf(stderr, "%lld\n", (long long)bytes_freed);
+    }
+
+    whatsupwithconsi("afterfree", generation);
+
     /* If the GC is not raising the age then lower the generation back
      * to its normal generation number */
     if (!raise) {
@@ -4016,7 +4926,7 @@ gc_free_heap(void)
             gc_assert(page_free_p(page));
             gc_assert(page_table[page].bytes_used == 0);
             page_start = (sword_t *)page_address(page);
-            for (i=0; i<GENCGC_CARD_BYTES/sizeof(sword_t); i++) {
+            for (i=0; i < (int)(GENCGC_CARD_BYTES/sizeof(sword_t)); i++) {
                 if (page_start[i] != 0) {
                     lose("free region not zero at %x\n", page_start + i);
                 }
@@ -4172,17 +5082,25 @@ gencgc_pickup_dynamic(void)
         lispobj *first,*ptr= (lispobj *)page_address(page);
 
         if (!gencgc_partial_pickup || page_allocated_p(page)) {
-          /* It is possible, though rare, for the saved page table
-           * to contain free pages below alloc_ptr. */
-          page_table[page].gen = gen;
-          page_table[page].bytes_used = GENCGC_CARD_BYTES;
-          page_table[page].large_object = 0;
-          page_table[page].write_protected = 0;
-          page_table[page].write_protected_cleared = 0;
-          page_table[page].dont_move = 0;
-          page_table[page].need_to_zero = 1;
-
-          bytes_allocated += GENCGC_CARD_BYTES;
+            /* It is possible, though rare, for the saved page table
+             * to contain free pages below alloc_ptr. */
+            if (verbosefixes >= 3) {
+                if (page_table[page].dontmove_dwords) {
+                    fprintf(stderr, "Cra88e: moving page %d from %d to %d\n"
+                            , (int)page
+                            , page_table[page].gen
+                            , gc_alloc_generation);
+                }
+            }
+            page_table[page].gen = gen;
+            page_table[page].bytes_used = GENCGC_CARD_BYTES;
+            page_table[page].large_object = 0;
+            page_table[page].write_protected = 0;
+            page_table[page].write_protected_cleared = 0;
+            page_table[page].dont_move = 0;
+            page_table[page].need_to_zero = 1;
+
+            bytes_allocated += GENCGC_CARD_BYTES;
         }
 
         if (!gencgc_partial_pickup) {
@@ -4245,7 +5163,7 @@ general_alloc_internal(sword_t nbytes, int page_type_flag, struct alloc_region *
     gc_assert(get_pseudo_atomic_atomic(thread));
 #endif
 
-    if (nbytes > large_allocation)
+    if ((long long)nbytes > (long long)large_allocation)
         large_allocation = nbytes;
 
     /* maybe we can do this quickly ... */
@@ -4262,7 +5180,7 @@ general_alloc_internal(sword_t nbytes, int page_type_flag, struct alloc_region *
      * large objects we are in danger of exhausting the heap without
      * running sufficient GCs.
      */
-    if (nbytes >= bytes_consed_between_gcs)
+    if ((long long)nbytes >= (long long)bytes_consed_between_gcs)
         trigger_bytes = nbytes;
 
     /* we have to go the long way around, it seems. Check whether we
@@ -4521,6 +5439,7 @@ static void
 prepare_for_final_gc ()
 {
     page_index_t i;
+    fixesp = 0;
     for (i = 0; i < last_free_page; i++) {
         page_table[i].large_object = 0;
         if (page_table[i].gen == PSEUDO_STATIC_GENERATION) {
diff --git a/src/runtime/interrupt.c b/src/runtime/interrupt.c
index 882e2bb..76646bc 100644
--- a/src/runtime/interrupt.c
+++ b/src/runtime/interrupt.c
@@ -1959,7 +1959,7 @@ install_handler(int signal, void handler(int, siginfo_t*, os_context_t*),
     block_blockable_signals(0, &old);
 
     FSHOW((stderr, "/interrupt_low_level_handlers[signal]=%x\n",
-           (unsigned int)interrupt_low_level_handlers[signal]));
+           (unsigned long long int)interrupt_low_level_handlers[signal]));
     if (interrupt_low_level_handlers[signal]==0) {
         if (ARE_SAME_HANDLER(handler, SIG_DFL) ||
             ARE_SAME_HANDLER(handler, SIG_IGN))
