]> gitweb.factorcode.org Git - factor.git/blobdiff - vm/slot_visitor.hpp
Put brackets around ipv6 addresses in `inet6 present`
[factor.git] / vm / slot_visitor.hpp
index 7bd7a1c7ea0684179fe5dca54704a908ee77890a..79bc3eb367f5c134333eba382d764c108a295dab 100644 (file)
 namespace factor {
 
-/* Size of the object pointed to by an untagged pointer */
-template <typename Fixup> cell object::size(Fixup fixup) const {
-  if (free_p())
-    return ((free_heap_block*)this)->size();
-
+// Size sans alignment.
+template <typename Fixup>
+cell object::base_size(Fixup fixup) const {
   switch (type()) {
     case ARRAY_TYPE:
-      return align(array_size((array*)this), data_alignment);
+      return array_size((array*)this);
     case BIGNUM_TYPE:
-      return align(array_size((bignum*)this), data_alignment);
+      return array_size((bignum*)this);
     case BYTE_ARRAY_TYPE:
-      return align(array_size((byte_array*)this), data_alignment);
+      return array_size((byte_array*)this);
     case STRING_TYPE:
-      return align(string_size(string_capacity((string*)this)), data_alignment);
+      return string_size(string_capacity((string*)this));
     case TUPLE_TYPE: {
       tuple_layout* layout = (tuple_layout*)fixup.translate_data(
           untag<object>(((tuple*)this)->layout));
-      return align(tuple_size(layout), data_alignment);
+      return tuple_size(layout);
     }
     case QUOTATION_TYPE:
-      return align(sizeof(quotation), data_alignment);
+      return sizeof(quotation);
     case WORD_TYPE:
-      return align(sizeof(word), data_alignment);
+      return sizeof(word);
     case FLOAT_TYPE:
-      return align(sizeof(boxed_float), data_alignment);
+      return sizeof(boxed_float);
     case DLL_TYPE:
-      return align(sizeof(dll), data_alignment);
+      return sizeof(dll);
     case ALIEN_TYPE:
-      return align(sizeof(alien), data_alignment);
+      return sizeof(alien);
     case WRAPPER_TYPE:
-      return align(sizeof(wrapper), data_alignment);
-    case CALLSTACK_TYPE:
-      return align(
-          callstack_object_size(untag_fixnum(((callstack*)this)->length)),
-          data_alignment);
+      return sizeof(wrapper);
+    case CALLSTACK_TYPE: {
+      cell callstack_length = untag_fixnum(((callstack*)this)->length);
+      return callstack_object_size(callstack_length);
+    }
     default:
-      critical_error("Invalid header in size", (cell)this);
-      return 0; /* can't happen */
+      critical_error("Invalid header in base_size", (cell)this);
+      return 0;
   }
 }
 
+// Size of the object pointed to by an untagged pointer
+template <typename Fixup>
+cell object::size(Fixup fixup) const {
+  if (free_p())
+    return ((free_heap_block*)this)->size();
+  return align(base_size(fixup), data_alignment);
+}
+
 inline cell object::size() const { return size(no_fixup()); }
 
-/* The number of cells from the start of the object which should be scanned by
-the GC. Some types have a binary payload at the end (string, word, DLL) which
-we ignore. */
-template <typename Fixup> cell object::binary_payload_start(Fixup fixup) const {
+// The number of slots (cells) in an object which should be scanned by
+// the GC. The number can vary in arrays and tuples, in all other
+// types the number is a constant.
+template <typename Fixup>
+inline cell object::slot_count(Fixup fixup) const {
   if (free_p())
     return 0;
 
-  switch (type()) {
-    /* these objects do not refer to other objects at all */
-    case FLOAT_TYPE:
-    case BYTE_ARRAY_TYPE:
-    case BIGNUM_TYPE:
-    case CALLSTACK_TYPE:
-      return 0;
-    /* these objects have some binary data at the end */
-    case WORD_TYPE:
-      return sizeof(word) - sizeof(cell);
-    case ALIEN_TYPE:
-      return sizeof(cell) * 3;
-    case DLL_TYPE:
-      return sizeof(cell) * 2;
-    case QUOTATION_TYPE:
-      return sizeof(quotation) - sizeof(cell);
-    case STRING_TYPE:
-      return sizeof(string);
-    /* everything else consists entirely of pointers */
-    case ARRAY_TYPE:
-      return array_size<array>(array_capacity((array*)this));
-    case TUPLE_TYPE: {
-      tuple_layout* layout = (tuple_layout*)fixup.translate_data(
-          untag<object>(((tuple*)this)->layout));
-      return tuple_size(layout);
+  cell t = type();
+  if (t == ARRAY_TYPE) {
+    // capacity + n slots
+    return 1 + array_capacity((array*)this);
+  } else if (t == TUPLE_TYPE) {
+    tuple_layout* layout = (tuple_layout*)fixup.translate_data(
+        untag<object>(((tuple*)this)->layout));
+    // layout + n slots
+    return 1 + tuple_capacity(layout);
+  } else {
+    switch (t) {
+      // these objects do not refer to other objects at all
+      case FLOAT_TYPE:
+      case BYTE_ARRAY_TYPE:
+      case BIGNUM_TYPE:
+      case CALLSTACK_TYPE: return 0;
+      case WORD_TYPE: return 8;
+      case ALIEN_TYPE: return 2;
+      case DLL_TYPE: return 1;
+      case QUOTATION_TYPE: return 3;
+      case STRING_TYPE: return 3;
+      case WRAPPER_TYPE: return 1;
+      default:
+        critical_error("Invalid header in slot_count", (cell)this);
+        return 0; // can't happen
     }
-    case WRAPPER_TYPE:
-      return sizeof(wrapper);
-    default:
-      critical_error("Invalid header in binary_payload_start", (cell)this);
-      return 0; /* can't happen */
   }
 }
 
-inline cell object::binary_payload_start() const {
-  return binary_payload_start(no_fixup());
+inline cell object::slot_count() const {
+  return slot_count(no_fixup());
 }
 
-/* Slot visitors iterate over the slots of an object, applying a functor to
-each one that is a non-immediate slot. The pointer is untagged first. The
-functor returns a new untagged object pointer. The return value may or may not
-equal the old one,
-however the new pointer receives the same tag before being stored back to the
-original location.
+// Slot visitors iterate over the slots of an object, applying a functor to
+// each one that is a non-immediate slot. The pointer is untagged first.
+// The functor returns a new untagged object pointer. The return value may
+// or may not equal the old one, however the new pointer receives the same
+// tag before being stored back to the original location.
 
-Slots storing immediate values are left unchanged and the visitor does inspect
-them.
+// Slots storing immediate values are left unchanged and the visitor does
+// inspect them.
 
-This is used by GC's copying, sweep and compact phases, and the implementation
-of the become primitive.
+// This is used by GC's copying, sweep and compact phases, and the
+// implementation of the become primitive.
 
-Iteration is driven by visit_*() methods. Only one of them define GC roots:
-- visit_all_roots()
+// Iteration is driven by visit_*() methods. Only one of them define GC
+// roots:
+//  - visit_all_roots()
 
-Code block visitors iterate over sets of code blocks, applying a functor to
-each one. The functor returns a new code_block pointer, which may or may not
-equal the old one. This is stored back to the original location.
+// Code block visitors iterate over sets of code blocks, applying a functor
+// to each one. The functor returns a new code_block pointer, which may or
+// may not equal the old one. This is stored back to the original location.
 
-This is used by GC's sweep and compact phases, and the implementation of the
-modify-code-heap primitive.
+// This is used by GC's sweep and compact phases, and the implementation of
+// the modify-code-heap primitive.
 
-Iteration is driven by visit_*() methods. Some of them define GC roots:
-- visit_context_code_blocks()
-- visit_callback_code_blocks() */
+// Iteration is driven by visit_*() methods. Some of them define GC roots:
+//  - visit_context_code_blocks()
+//  - visit_callback_code_blocks()
 
 template <typename Fixup> struct slot_visitor {
   factor_vm* parent;
   Fixup fixup;
+  cell cards_scanned;
+  cell decks_scanned;
 
   slot_visitor<Fixup>(factor_vm* parent, Fixup fixup)
-      : parent(parent), fixup(fixup) {}
+  : parent(parent),
+    fixup(fixup),
+    cards_scanned(0),
+    decks_scanned(0) {}
 
   cell visit_pointer(cell pointer);
   void visit_handle(cell* handle);
   void visit_object_array(cell* start, cell* end);
-  void visit_slots(object* ptr, cell payload_start);
+  void visit_partial_objects(cell start, cell card_start, cell card_end);
   void visit_slots(object* ptr);
   void visit_stack_elements(segment* region, cell* top);
-  void visit_data_roots();
-  void visit_callback_roots();
-  void visit_literal_table_roots();
   void visit_all_roots();
   void visit_callstack_object(callstack* stack);
   void visit_callstack(context* ctx);
   void visit_context(context *ctx);
-  void visit_contexts();
-  void visit_code_block_objects(code_block* compiled);
-  void visit_embedded_literals(code_block* compiled);
-  void visit_sample_callstacks();
-  void visit_sample_threads();
   void visit_object_code_block(object* obj);
   void visit_context_code_blocks();
   void visit_uninitialized_code_blocks();
-  void visit_embedded_code_pointers(code_block* compiled);
   void visit_object(object* obj);
   void visit_mark_stack(std::vector<cell>* mark_stack);
+
+
+  template <typename SourceGeneration>
+  cell visit_card(SourceGeneration* gen, cell index, cell start);
+  template <typename SourceGeneration>
+  void visit_cards(SourceGeneration* gen, card mask, card unmask);
+
+
+  template <typename TargetGeneration>
+  void cheneys_algorithm(TargetGeneration* gen, cell scan);
+
+  // Visits the data pointers in code blocks in the remembered set.
+  void visit_code_heap_roots(std::set<code_block*>* remembered_set);
+
+  // Visits pointers embedded in instructions in code blocks.
+  void visit_instruction_operands(code_block* block, cell rel_base);
+  void visit_embedded_code_pointers(code_block* compiled);
+  void visit_embedded_literals(code_block* compiled);
+
+  // Visits data pointers in code blocks.
+  void visit_code_block_objects(code_block* compiled);
 };
 
 template <typename Fixup>
 cell slot_visitor<Fixup>::visit_pointer(cell pointer) {
-  if (immediate_p(pointer))
-    return pointer;
-
   object* untagged = fixup.fixup_data(untag<object>(pointer));
   return RETAG(untagged, TAG(pointer));
 }
 
 template <typename Fixup> void slot_visitor<Fixup>::visit_handle(cell* handle) {
-  *handle = visit_pointer(*handle);
+  if (!immediate_p(*handle)) {
+    *handle = visit_pointer(*handle);
+  }
 }
 
 template <typename Fixup>
@@ -167,22 +185,14 @@ void slot_visitor<Fixup>::visit_object_array(cell* start, cell* end) {
     visit_handle(start++);
 }
 
-template <typename Fixup>
-void slot_visitor<Fixup>::visit_slots(object* ptr, cell payload_start) {
-  cell* slot = (cell*)ptr;
-  cell* end = (cell*)((cell)ptr + payload_start);
-
-  if (slot != end) {
-    slot++;
-    visit_object_array(slot, end);
-  }
-}
-
 template <typename Fixup> void slot_visitor<Fixup>::visit_slots(object* obj) {
   if (obj->type() == CALLSTACK_TYPE)
     visit_callstack_object((callstack*)obj);
-  else
-    visit_slots(obj, obj->binary_payload_start(fixup));
+  else {
+    cell* start = (cell*)obj + 1;
+    cell* end = start + obj->slot_count(fixup);
+    visit_object_array(start, end);
+  }
 }
 
 template <typename Fixup>
@@ -190,113 +200,53 @@ void slot_visitor<Fixup>::visit_stack_elements(segment* region, cell* top) {
   visit_object_array((cell*)region->start, top + 1);
 }
 
-template <typename Fixup> void slot_visitor<Fixup>::visit_data_roots() {
-  std::vector<cell*>::const_iterator iter =
-      parent->data_roots.begin();
-  std::vector<cell*>::const_iterator end =
-      parent->data_roots.end();
-
-  for (; iter < end; iter++) {
+template <typename Fixup> void slot_visitor<Fixup>::visit_all_roots() {
+  FACTOR_FOR_EACH(parent->data_roots) {
     visit_handle(*iter);
   }
-}
-
-template <typename Fixup> struct callback_slot_visitor {
-  slot_visitor<Fixup>* visitor;
 
-  callback_slot_visitor(slot_visitor<Fixup>* visitor) : visitor(visitor) {}
+  auto callback_slot_visitor = [&](code_block* stub, cell size) {
+         (void)size;
+    visit_handle(&stub->owner);
+  };
+  parent->callbacks->allocator->iterate(callback_slot_visitor, no_fixup());
 
-  void operator()(code_block* stub, cell size) {
-    visitor->visit_handle(&stub->owner);
-  }
-};
-
-template <typename Fixup> void slot_visitor<Fixup>::visit_callback_roots() {
-  callback_slot_visitor<Fixup> callback_visitor(this);
-  parent->callbacks->allocator->iterate(callback_visitor);
-}
-
-template <typename Fixup>
-void slot_visitor<Fixup>::visit_literal_table_roots() {
-  std::map<code_block*, cell>* uninitialized_blocks =
-      &parent->code->uninitialized_blocks;
-  std::map<code_block*, cell>::iterator iter =
-      uninitialized_blocks->begin();
-  std::map<code_block*, cell>::iterator end = uninitialized_blocks->end();
-
-  for (; iter != end; iter++) {
+  FACTOR_FOR_EACH(parent->code->uninitialized_blocks) {
     iter->second = visit_pointer(iter->second);
   }
-}
-
-template <typename Fixup> void slot_visitor<Fixup>::visit_sample_callstacks() {
-  for (std::vector<cell>::iterator iter = parent->sample_callstacks.begin();
-       iter != parent->sample_callstacks.end(); ++iter) {
-    visit_handle(&*iter);
-  }
-}
 
-template <typename Fixup> void slot_visitor<Fixup>::visit_sample_threads() {
-  for (std::vector<profiling_sample>::iterator iter = parent->samples.begin();
-       iter != parent->samples.end(); ++iter) {
+  FACTOR_FOR_EACH(parent->samples) {
     visit_handle(&iter->thread);
   }
-}
-
-template <typename Fixup> void slot_visitor<Fixup>::visit_all_roots() {
-  visit_handle(&parent->true_object);
-  visit_handle(&parent->bignum_zero);
-  visit_handle(&parent->bignum_pos_one);
-  visit_handle(&parent->bignum_neg_one);
-
-  visit_data_roots();
-  visit_callback_roots();
-  visit_literal_table_roots();
-  visit_sample_callstacks();
-  visit_sample_threads();
 
   visit_object_array(parent->special_objects,
                      parent->special_objects + special_object_count);
 
-  visit_contexts();
+  FACTOR_FOR_EACH(parent->active_contexts) {
+    visit_context(*iter);
+  }
 }
 
-/* primitive_minor_gc() is invoked by inline GC checks, and it needs to fill in
-   uninitialized stack locations before actually calling the GC. See the
-   documentation in compiler.cfg.stacks.vacant for details.
+// primitive_minor_gc() is invoked by inline GC checks, and it needs to
+// visit spill slots which references objects in the heap.
 
-   So for each call frame:
+// So for each call frame:
+//  - trace roots in spill slots
 
-    - scrub some uninitialized locations
-    - trace roots in spill slots
-*/
 template <typename Fixup> struct call_frame_slot_visitor {
   slot_visitor<Fixup>* visitor;
-  /* NULL in case we're a visitor for a callstack object. */
-  context* ctx;
 
-  void scrub_stack(cell stack, uint8_t* bitmap, cell base, uint32_t count) {
-    for (cell loc = 0; loc < count; loc++) {
-      if (bitmap_p(bitmap, base + loc)) {
-#ifdef DEBUG_GC_MAPS
-        FACTOR_PRINT("scrubbing stack location " << loc);
-#endif
-        *((cell*)stack - loc) = 0;
-      }
-    }
-  }
+  call_frame_slot_visitor(slot_visitor<Fixup>* visitor)
+      : visitor(visitor) {}
 
-  call_frame_slot_visitor(slot_visitor<Fixup>* visitor, context* ctx)
-      : visitor(visitor), ctx(ctx) {}
+  // frame top -> [return address]
+  //              [spill area]
+  //              ...
+  //              [entry_point]
+  //              [size]
 
-  /*
-       frame top -> [return address]
-                    [spill area]
-                    ...
-                    [entry_point]
-                    [size]
-       */
   void operator()(cell frame_top, cell size, code_block* owner, cell addr) {
+         (void)size;
     cell return_address = owner->offset(addr);
 
     code_block* compiled =
@@ -316,19 +266,7 @@ template <typename Fixup> struct call_frame_slot_visitor {
     cell* stack_pointer = (cell*)frame_top;
     uint8_t* bitmap = info->gc_info_bitmap();
 
-    if (ctx) {
-      /* Scrub vacant stack locations. */
-      scrub_stack(ctx->datastack,
-                  bitmap,
-                  info->callsite_scrub_d(callsite),
-                  info->scrub_d_count);
-      scrub_stack(ctx->retainstack,
-                  bitmap,
-                  info->callsite_scrub_r(callsite),
-                  info->scrub_r_count);
-    }
-
-    /* Subtract old value of base pointer from every derived pointer. */
+    // Subtract old value of base pointer from every derived pointer.
     for (cell spill_slot = 0; spill_slot < info->derived_root_count;
          spill_slot++) {
       uint32_t base_pointer = info->lookup_base_pointer(callsite, spill_slot);
@@ -341,19 +279,19 @@ template <typename Fixup> struct call_frame_slot_visitor {
       }
     }
 
-    /* Update all GC roots, including base pointers. */
+    // Update all GC roots, including base pointers.
     cell callsite_gc_roots = info->callsite_gc_roots(callsite);
 
     for (cell spill_slot = 0; spill_slot < info->gc_root_count; spill_slot++) {
       if (bitmap_p(bitmap, callsite_gc_roots + spill_slot)) {
-#ifdef DEBUG_GC_MAPS
+        #ifdef DEBUG_GC_MAPS
         FACTOR_PRINT("visiting GC root " << spill_slot);
-#endif
+        #endif
         visitor->visit_handle(stack_pointer + spill_slot);
       }
     }
 
-    /* Add the base pointers to obtain new derived pointer values. */
+    // Add the base pointers to obtain new derived pointer values.
     for (cell spill_slot = 0; spill_slot < info->derived_root_count;
          spill_slot++) {
       uint32_t base_pointer = info->lookup_base_pointer(callsite, spill_slot);
@@ -365,20 +303,18 @@ template <typename Fixup> struct call_frame_slot_visitor {
 
 template <typename Fixup>
 void slot_visitor<Fixup>::visit_callstack_object(callstack* stack) {
-  call_frame_slot_visitor<Fixup> call_frame_visitor(this, NULL);
+  call_frame_slot_visitor<Fixup> call_frame_visitor(this);
   parent->iterate_callstack_object(stack, call_frame_visitor, fixup);
 }
 
 template <typename Fixup>
 void slot_visitor<Fixup>::visit_callstack(context* ctx) {
-  call_frame_slot_visitor<Fixup> call_frame_visitor(this, ctx);
+  call_frame_slot_visitor<Fixup> call_frame_visitor(this);
   parent->iterate_callstack(ctx, call_frame_visitor, fixup);
 }
 
 template <typename Fixup>
 void slot_visitor<Fixup>::visit_context(context* ctx) {
-  /* Callstack is visited first because it scrubs the data and retain
-     stacks. */
   visit_callstack(ctx);
 
   cell ds_ptr = ctx->datastack;
@@ -390,33 +326,12 @@ void slot_visitor<Fixup>::visit_context(context* ctx) {
   visit_object_array(ctx->context_objects,
                      ctx->context_objects + context_object_count);
 
-  /* Clear out the space not visited with a known pattern. That makes
-     it easier to see if uninitialized reads are made. */
+  // Clear out the space not visited with a known pattern. That makes
+  // it easier to see if uninitialized reads are made.
   ctx->fill_stack_seg(ds_ptr, ds_seg, 0xbaadbadd);
-  ctx->fill_stack_seg(rs_ptr, rs_seg, 0xdaabdaab);
+  ctx->fill_stack_seg(rs_ptr, rs_seg, 0xdaabdabb);
 }
 
-template <typename Fixup> void slot_visitor<Fixup>::visit_contexts() {
-  std::set<context*>::const_iterator begin = parent->active_contexts.begin();
-  std::set<context*>::const_iterator end = parent->active_contexts.end();
-  while (begin != end) {
-    visit_context(*begin);
-    begin++;
-  }
-}
-
-template <typename Fixup> struct literal_references_visitor {
-  slot_visitor<Fixup>* visitor;
-
-  explicit literal_references_visitor(slot_visitor<Fixup>* visitor)
-      : visitor(visitor) {}
-
-  void operator()(instruction_operand op) {
-    if (op.rel_type() == RT_LITERAL)
-      op.store_value(visitor->visit_pointer(op.load_value()));
-  }
-};
-
 template <typename Fixup>
 void slot_visitor<Fixup>::visit_code_block_objects(code_block* compiled) {
   visit_handle(&compiled->owner);
@@ -426,20 +341,28 @@ void slot_visitor<Fixup>::visit_code_block_objects(code_block* compiled) {
 
 template <typename Fixup>
 void slot_visitor<Fixup>::visit_embedded_literals(code_block* compiled) {
-  if (!parent->code->uninitialized_p(compiled)) {
-    literal_references_visitor<Fixup> visitor(this);
-    compiled->each_instruction_operand(visitor);
-  }
+  if (parent->code->uninitialized_p(compiled))
+    return;
+
+  auto update_literal_refs = [&](instruction_operand op) {
+    if (op.rel.type() == RT_LITERAL) {
+      cell value = op.load_value(op.pointer);
+      if (!immediate_p(value)) {
+        op.store_value(visit_pointer(value));
+      }
+    }
+  };
+  compiled->each_instruction_operand(update_literal_refs);
 }
 
 template <typename Fixup> struct call_frame_code_block_visitor {
   Fixup fixup;
 
-  call_frame_code_block_visitor(Fixup fixup)
-      : fixup(fixup) {}
+  call_frame_code_block_visitor(Fixup fixup) : fixup(fixup) {}
 
   void operator()(cell frame_top, cell size, code_block* owner, cell addr) {
-    code_block* compiled =
+    (void)size;
+         code_block* compiled =
         Fixup::translated_code_block_map ? owner : fixup.fixup_code(owner);
     cell fixed_addr = compiled->address_for_offset(owner->offset(addr));
 
@@ -474,50 +397,35 @@ void slot_visitor<Fixup>::visit_object_code_block(object* obj) {
 template <typename Fixup>
 void slot_visitor<Fixup>::visit_context_code_blocks() {
   call_frame_code_block_visitor<Fixup> call_frame_visitor(fixup);
-  std::set<context*>::const_iterator begin = parent->active_contexts.begin();
-  std::set<context*>::const_iterator end = parent->active_contexts.end();
-  while (begin != end) {
-    parent->iterate_callstack(*begin, call_frame_visitor, fixup);
-    begin++;
+  FACTOR_FOR_EACH(parent->active_contexts) {
+    parent->iterate_callstack(*iter, call_frame_visitor, fixup);
   }
 }
 
 template <typename Fixup>
 void slot_visitor<Fixup>::visit_uninitialized_code_blocks() {
-  std::map<code_block*, cell>* uninitialized_blocks =
-      &parent->code->uninitialized_blocks;
-  std::map<code_block*, cell>::const_iterator iter =
-      uninitialized_blocks->begin();
-  std::map<code_block*, cell>::const_iterator end = uninitialized_blocks->end();
-
   std::map<code_block*, cell> new_uninitialized_blocks;
-  for (; iter != end; iter++) {
+  FACTOR_FOR_EACH(parent->code->uninitialized_blocks) {
     new_uninitialized_blocks.insert(
         std::make_pair(fixup.fixup_code(iter->first), iter->second));
   }
-
   parent->code->uninitialized_blocks = new_uninitialized_blocks;
 }
 
-template <typename Fixup> struct embedded_code_pointers_visitor {
-  Fixup fixup;
-
-  explicit embedded_code_pointers_visitor(Fixup fixup) : fixup(fixup) {}
-
-  void operator()(instruction_operand op) {
-    relocation_type type = op.rel_type();
-    if (type == RT_ENTRY_POINT || type == RT_ENTRY_POINT_PIC ||
-        type == RT_ENTRY_POINT_PIC_TAIL)
-      op.store_code_block(fixup.fixup_code(op.load_code_block()));
-  }
-};
-
 template <typename Fixup>
 void slot_visitor<Fixup>::visit_embedded_code_pointers(code_block* compiled) {
-  if (!parent->code->uninitialized_p(compiled)) {
-    embedded_code_pointers_visitor<Fixup> operand_visitor(fixup);
-    compiled->each_instruction_operand(operand_visitor);
-  }
+  if (parent->code->uninitialized_p(compiled))
+    return;
+  auto update_code_block_refs = [&](instruction_operand op){
+    relocation_type type = op.rel.type();
+    if (type == RT_ENTRY_POINT ||
+        type == RT_ENTRY_POINT_PIC ||
+        type == RT_ENTRY_POINT_PIC_TAIL) {
+      code_block* block = fixup.fixup_code(op.load_code_block());
+      op.store_value(block->entry_point());
+    }
+  };
+  compiled->each_instruction_operand(update_code_block_refs);
 }
 
 template <typename Fixup>
@@ -527,14 +435,13 @@ void slot_visitor<Fixup>::visit_object(object *ptr) {
     ((alien*)ptr)->update_address();
 }
 
-/* Pops items from the mark stack and visits them until the stack is
-   empty. Used when doing a full collection and when collecting to
-   tenured space. */
+// Pops items from the mark stack and visits them until the stack is
+// empty. Used when doing a full collection and when collecting to
+// tenured space.
 template <typename Fixup>
 void slot_visitor<Fixup>::visit_mark_stack(std::vector<cell>* mark_stack) {
   while (!mark_stack->empty()) {
     cell ptr = mark_stack->back();
-    // TJaba
     mark_stack->pop_back();
 
     if (ptr & 1) {
@@ -550,4 +457,142 @@ void slot_visitor<Fixup>::visit_mark_stack(std::vector<cell>* mark_stack) {
   }
 }
 
+// Visits the instruction operands in a code block. If the operand is
+// a pointer to a code block or data object, then the fixup is applied
+// to it. Otherwise, if it is an external addess, that address is
+// recomputed. If it is an untagged number literal (RT_UNTAGGED) or an
+// immediate value, then nothing is done with it.
+template <typename Fixup>
+void slot_visitor<Fixup>::visit_instruction_operands(code_block* block,
+                                                     cell rel_base) {
+  auto visit_func = [&](instruction_operand op){
+    cell old_offset = rel_base + op.rel.offset();
+    cell old_value = op.load_value(old_offset);
+    switch (op.rel.type()) {
+      case RT_LITERAL: {
+        if (!immediate_p(old_value)) {
+          op.store_value(visit_pointer(old_value));
+        }
+        break;
+      }
+      case RT_ENTRY_POINT:
+      case RT_ENTRY_POINT_PIC:
+      case RT_ENTRY_POINT_PIC_TAIL:
+      case RT_HERE: {
+        cell offset = TAG(old_value);
+        code_block* compiled = (code_block*)UNTAG(old_value);
+        op.store_value(RETAG(fixup.fixup_code(compiled), offset));
+        break;
+      }
+      case RT_UNTAGGED:
+        break;
+      default:
+        op.store_value(parent->compute_external_address(op));
+        break;
+    }
+  };
+  if (parent->code->uninitialized_p(block))
+    return;
+  block->each_instruction_operand(visit_func);
+}
+
+template <typename Fixup>
+void slot_visitor<Fixup>::visit_partial_objects(cell start,
+                                                cell card_start,
+                                                cell card_end) {
+  cell *scan_start = (cell*)start + 1;
+  cell *scan_end = scan_start + ((object*)start)->slot_count();
+
+  scan_start = std::max(scan_start, (cell*)card_start);
+  scan_end = std::min(scan_end, (cell*)card_end);
+
+  visit_object_array(scan_start, scan_end);
+}
+
+template <typename Fixup>
+template <typename SourceGeneration>
+cell slot_visitor<Fixup>::visit_card(SourceGeneration* gen,
+                                     cell index, cell start) {
+  cell heap_base = parent->data->start;
+  cell start_addr = heap_base + index * card_size;
+  cell end_addr = start_addr + card_size;
+
+  // Forward to the next object whose address is in the card.
+  if (!start || (start + ((object*)start)->size()) < start_addr) {
+    // Optimization because finding the objects in a memory range is
+    // expensive. It helps a lot when tracing consecutive cards.
+    cell gen_start_card = (gen->start - heap_base) / card_size;
+    start = gen->starts
+        .find_object_containing_card(index - gen_start_card);
+  }
+
+  while (start && start < end_addr) {
+    visit_partial_objects(start, start_addr, end_addr);
+    if ((start + ((object*)start)->size()) >= end_addr) {
+      // The object can overlap the card boundary, then the
+      // remainder of it will be handled in the next card
+      // tracing if that card is marked.
+      break;
+    }
+    start = gen->next_object_after(start);
+  }
+  return start;
+}
+
+template <typename Fixup>
+template <typename SourceGeneration>
+void slot_visitor<Fixup>::visit_cards(SourceGeneration* gen,
+                                      card mask, card unmask) {
+  card_deck* decks = parent->data->decks;
+  card_deck* cards = parent->data->cards;
+  cell heap_base = parent->data->start;
+
+  cell first_deck = (gen->start - heap_base) / deck_size;
+  cell last_deck = (gen->end - heap_base) / deck_size;
+
+  // Address of last traced object.
+  cell start = 0;
+  for (cell di = first_deck; di < last_deck; di++) {
+    if (decks[di] & mask) {
+      decks[di] &= ~unmask;
+      decks_scanned++;
+
+      cell first_card = cards_per_deck * di;
+      cell last_card = first_card + cards_per_deck;
+
+      for (cell ci = first_card; ci < last_card; ci++) {
+        if (cards[ci] & mask) {
+          cards[ci] &= ~unmask;
+          cards_scanned++;
+
+          start = visit_card(gen, ci, start);
+          if (!start) {
+            // At end of generation, no need to scan more cards.
+            return;
+          }
+        }
+      }
+    }
+  }
+}
+
+template <typename Fixup>
+void slot_visitor<Fixup>::visit_code_heap_roots(std::set<code_block*>* remembered_set) {
+  FACTOR_FOR_EACH(*remembered_set) {
+    code_block* compiled = *iter;
+    visit_code_block_objects(compiled);
+    visit_embedded_literals(compiled);
+    compiled->flush_icache();
+  }
+}
+
+template <typename Fixup>
+template <typename TargetGeneration>
+void slot_visitor<Fixup>::cheneys_algorithm(TargetGeneration* gen, cell scan) {
+  while (scan && scan < gen->here) {
+    visit_object((object*)scan);
+    scan = gen->next_object_after(scan);
+  }
+}
+
 }