]> gitweb.factorcode.org Git - factor.git/commitdiff
VM: Refactor code_blocks to Factor style
authorErik Charlebois <erikcharlebois@gmail.com>
Sun, 12 May 2013 01:50:21 +0000 (21:50 -0400)
committerErik Charlebois <erikcharlebois@gmail.com>
Sun, 12 May 2013 17:24:42 +0000 (13:24 -0400)
vm/code_block_visitor.hpp
vm/code_blocks.cpp
vm/code_blocks.hpp

index 2baa6d1aa7650e24f6b4325edde085a9872db997..3e4cb53a9eb39867c77af92b40092b0f251a04fb 100644 (file)
@@ -1,5 +1,4 @@
-namespace factor
-{
+namespace factor {
 
 /* 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
@@ -11,131 +10,115 @@ modify-code-heap primitive.
 Iteration is driven by visit_*() methods. Some of them define GC roots:
 - visit_context_code_blocks()
 - visit_callback_code_blocks() */
-template<typename Fixup> struct code_block_visitor {
-       factor_vm *parent;
-       Fixup fixup;
 
-       explicit code_block_visitor(factor_vm *parent_, Fixup fixup_) :
-               parent(parent_), fixup(fixup_) {}
+template <typename Fixup> struct code_block_visitor {
+  factor_vm* parent;
+  Fixup fixup;
 
-       code_block *visit_code_block(code_block *compiled);
-       void visit_object_code_block(object *obj);
-       void visit_embedded_code_pointers(code_block *compiled);
-       void visit_context_code_blocks();
-       void visit_uninitialized_code_blocks();
+  explicit code_block_visitor(factor_vm* parent_, Fixup fixup_)
+      : parent(parent_), fixup(fixup_) {}
 
-       void visit_code_roots();
+  code_block* visit_code_block(code_block* compiled);
+  void visit_object_code_block(object* obj);
+  void visit_embedded_code_pointers(code_block* compiled);
+  void visit_context_code_blocks();
+  void visit_uninitialized_code_blocks();
+
+  void visit_code_roots();
 };
 
-template<typename Fixup>
-code_block *code_block_visitor<Fixup>::visit_code_block(code_block *compiled)
-{
-       return fixup.fixup_code(compiled);
+template <typename Fixup>
+code_block* code_block_visitor<Fixup>::visit_code_block(code_block* compiled) {
+  return fixup.fixup_code(compiled);
 }
 
-template<typename Fixup>
-struct call_frame_code_block_visitor {
-       factor_vm *parent;
-       Fixup fixup;
-
-       explicit call_frame_code_block_visitor(factor_vm *parent_, Fixup fixup_) :
-               parent(parent_), fixup(fixup_) {}
-
-       void operator()(void *frame_top, cell frame_size, code_block *owner, void *addr)
-       {
-               code_block *compiled = Fixup::translated_code_block_map
-                       ? owner
-                       : fixup.fixup_code(owner);
-               void *fixed_addr = compiled->address_for_offset(owner->offset(addr));
-               set_frame_return_address(frame_top, fixed_addr);
-       }
+template <typename Fixup> struct call_frame_code_block_visitor {
+  factor_vm* parent;
+  Fixup fixup;
+
+  explicit call_frame_code_block_visitor(factor_vm* parent_, Fixup fixup_)
+      : parent(parent_), fixup(fixup_) {}
+
+  void operator()(void* frame_top, cell frame_size, code_block* owner,
+                  void* addr) {
+    code_block* compiled =
+        Fixup::translated_code_block_map ? owner : fixup.fixup_code(owner);
+    void* fixed_addr = compiled->address_for_offset(owner->offset(addr));
+    set_frame_return_address(frame_top, fixed_addr);
+  }
 };
 
-template<typename Fixup>
-void code_block_visitor<Fixup>::visit_object_code_block(object *obj)
-{
-       switch(obj->type())
-       {
-       case WORD_TYPE:
-               {
-                       word *w = (word *)obj;
-                       if(w->entry_point)
-                               w->entry_point = visit_code_block(w->code())->entry_point();
-                       break;
-               }
-       case QUOTATION_TYPE:
-               {
-                       quotation *q = (quotation *)obj;
-                       if(q->entry_point)
-                               q->entry_point = visit_code_block(q->code())->entry_point();
-                       break;
-               }
-       case CALLSTACK_TYPE:
-               {
-                       callstack *stack = (callstack *)obj;
-                       call_frame_code_block_visitor<Fixup> call_frame_visitor(parent,fixup);
-                       parent->iterate_callstack_object(stack,call_frame_visitor,fixup);
-                       break;
-               }
-       }
+template <typename Fixup>
+void code_block_visitor<Fixup>::visit_object_code_block(object* obj) {
+  switch (obj->type()) {
+    case WORD_TYPE: {
+      word* w = (word*)obj;
+      if (w->entry_point)
+        w->entry_point = visit_code_block(w->code())->entry_point();
+      break;
+    }
+    case QUOTATION_TYPE: {
+      quotation* q = (quotation*)obj;
+      if (q->entry_point)
+        q->entry_point = visit_code_block(q->code())->entry_point();
+      break;
+    }
+    case CALLSTACK_TYPE: {
+      callstack* stack = (callstack*)obj;
+      call_frame_code_block_visitor<Fixup> call_frame_visitor(parent, fixup);
+      parent->iterate_callstack_object(stack, call_frame_visitor, fixup);
+      break;
+    }
+  }
 }
 
-template<typename Fixup>
-struct embedded_code_pointers_visitor {
-       Fixup fixup;
+template <typename Fixup> struct embedded_code_pointers_visitor {
+  Fixup fixup;
 
-       explicit embedded_code_pointers_visitor(Fixup fixup_) : 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()));
-       }
+  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 code_block_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);
-       }
+template <typename Fixup>
+void code_block_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);
+  }
 }
 
-template<typename Fixup>
-void code_block_visitor<Fixup>::visit_context_code_blocks()
-{
-       call_frame_code_block_visitor<Fixup> call_frame_visitor(parent,fixup);
-       parent->iterate_active_callstacks(call_frame_visitor,fixup);
+template <typename Fixup>
+void code_block_visitor<Fixup>::visit_context_code_blocks() {
+  call_frame_code_block_visitor<Fixup> call_frame_visitor(parent, fixup);
+  parent->iterate_active_callstacks(call_frame_visitor, fixup);
 }
 
-template<typename Fixup>
-void code_block_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++)
-       {
-               new_uninitialized_blocks.insert(std::make_pair(
-                       fixup.fixup_code(iter->first),
-                       iter->second));
-       }
-
-       parent->code->uninitialized_blocks = new_uninitialized_blocks;
+template <typename Fixup>
+void code_block_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++) {
+    new_uninitialized_blocks.insert(
+        std::make_pair(fixup.fixup_code(iter->first), iter->second));
+  }
+
+  parent->code->uninitialized_blocks = new_uninitialized_blocks;
 }
 
-template<typename Fixup>
-void code_block_visitor<Fixup>::visit_code_roots()
-{
-       visit_uninitialized_code_blocks();
+template <typename Fixup> void code_block_visitor<Fixup>::visit_code_roots() {
+  visit_uninitialized_code_blocks();
 }
 
 }
index 2680741dd4fff37be7079b3f61b36b3371629bf6..a4c6f6cee3e7f2bb0307a62d7d37009ff57fdeef 100644 (file)
 #include "master.hpp"
 
-namespace factor
-{
-
-cell code_block::owner_quot() const
-{
-       tagged<object> executing(owner);
-       if (!optimized_p() && executing->type() == WORD_TYPE)
-               executing = executing.as<word>()->def;
-       return executing.value();
+namespace factor {
+
+cell code_block::owner_quot() const {
+  tagged<object> executing(owner);
+  if (!optimized_p() && executing->type() == WORD_TYPE)
+    executing = executing.as<word>()->def;
+  return executing.value();
 }
 
-cell code_block::scan(factor_vm *vm, void *addr) const
-{
-       switch(type())
-       {
-       case code_block_unoptimized:
-               {
-                       tagged<object> obj(owner);
-                       if(obj.type_p(WORD_TYPE))
-                               obj = obj.as<word>()->def;
-
-                       if(obj.type_p(QUOTATION_TYPE))
-                               return tag_fixnum(vm->quot_code_offset_to_scan(obj.value(),offset(addr)));
-                       else
-                               return false_object;
-               }
-       case code_block_optimized:
-       case code_block_pic:
-               return false_object;
-       default:
-               critical_error("Bad frame type",type());
-               return false_object;
-       }
+cell code_block::scan(factor_vm* vm, void* addr) const {
+  switch (type()) {
+    case code_block_unoptimized: {
+      tagged<object> obj(owner);
+      if (obj.type_p(WORD_TYPE))
+        obj = obj.as<word>()->def;
+
+      if (obj.type_p(QUOTATION_TYPE))
+        return tag_fixnum(
+            vm->quot_code_offset_to_scan(obj.value(), offset(addr)));
+      else
+        return false_object;
+    }
+    case code_block_optimized:
+    case code_block_pic:
+      return false_object;
+    default:
+      critical_error("Bad frame type", type());
+      return false_object;
+  }
 }
 
-cell factor_vm::compute_entry_point_address(cell obj)
-{
-       switch(tagged<object>(obj).type())
-       {
-       case WORD_TYPE:
-               return (cell)untag<word>(obj)->entry_point;
-       case QUOTATION_TYPE:
-               return (cell)untag<quotation>(obj)->entry_point;
-       default:
-               critical_error("Expected word or quotation",obj);
-               return 0;
-       }
+cell factor_vm::compute_entry_point_address(cell obj) {
+  switch (tagged<object>(obj).type()) {
+    case WORD_TYPE:
+      return (cell) untag<word>(obj)->entry_point;
+    case QUOTATION_TYPE:
+      return (cell) untag<quotation>(obj)->entry_point;
+    default:
+      critical_error("Expected word or quotation", obj);
+      return 0;
+  }
 }
 
-cell factor_vm::compute_entry_point_pic_address(word *w, cell tagged_quot)
-{
-       if(!to_boolean(tagged_quot) || max_pic_size == 0)
-               return (cell)w->entry_point;
-       else
-       {
-               quotation *quot = untag<quotation>(tagged_quot);
-               if(quot_compiled_p(quot))
-                       return (cell)quot->entry_point;
-               else
-                       return (cell)w->entry_point;
-       }
+cell factor_vm::compute_entry_point_pic_address(word* w, cell tagged_quot) {
+  if (!to_boolean(tagged_quot) || max_pic_size == 0)
+    return (cell) w->entry_point;
+  else {
+    quotation* quot = untag<quotation>(tagged_quot);
+    if (quot_compiled_p(quot))
+      return (cell) quot->entry_point;
+    else
+      return (cell) w->entry_point;
+  }
 }
 
-cell factor_vm::compute_entry_point_pic_address(cell w_)
-{
-       tagged<word> w(w_);
-       return compute_entry_point_pic_address(w.untagged(),w->pic_def);
+cell factor_vm::compute_entry_point_pic_address(cell w_) {
+  tagged<word> w(w_);
+  return compute_entry_point_pic_address(w.untagged(), w->pic_def);
 }
 
-cell factor_vm::compute_entry_point_pic_tail_address(cell w_)
-{
-       tagged<word> w(w_);
-       return compute_entry_point_pic_address(w.untagged(),w->pic_tail_def);
+cell factor_vm::compute_entry_point_pic_tail_address(cell w_) {
+  tagged<word> w(w_);
+  return compute_entry_point_pic_address(w.untagged(), w->pic_tail_def);
 }
 
-cell factor_vm::code_block_owner(code_block *compiled)
-{
-       tagged<object> owner(compiled->owner);
+cell factor_vm::code_block_owner(code_block* compiled) {
+  tagged<object> owner(compiled->owner);
 
-       /* Cold generic word call sites point to quotations that call the
-       inline-cache-miss and inline-cache-miss-tail primitives. */
-       if(owner.type_p(QUOTATION_TYPE))
-       {
-               tagged<quotation> quot(owner.as<quotation>());
-               tagged<array> elements(quot->array);
+  /* Cold generic word call sites point to quotations that call the
+     inline-cache-miss and inline-cache-miss-tail primitives. */
+  if (owner.type_p(QUOTATION_TYPE)) {
+    tagged<quotation> quot(owner.as<quotation>());
+    tagged<array> elements(quot->array);
 #ifdef FACTOR_DEBUG
-               FACTOR_ASSERT(array_capacity(elements.untagged()) == 5);
-               FACTOR_ASSERT(array_nth(elements.untagged(),4) == special_objects[PIC_MISS_WORD]
-                       || array_nth(elements.untagged(),4) == special_objects[PIC_MISS_TAIL_WORD]);
+    FACTOR_ASSERT(array_capacity(elements.untagged()) == 5);
+    FACTOR_ASSERT(array_nth(elements.untagged(), 4) ==
+                      special_objects[PIC_MISS_WORD] ||
+                  array_nth(elements.untagged(), 4) ==
+                      special_objects[PIC_MISS_TAIL_WORD]);
 #endif
-               tagged<wrapper> word_wrapper(array_nth(elements.untagged(),0));
-               return word_wrapper->object;
-       }
-       else
-               return compiled->owner;
+    tagged<wrapper> word_wrapper(array_nth(elements.untagged(), 0));
+    return word_wrapper->object;
+  } else
+    return compiled->owner;
 }
 
 struct update_word_references_relocation_visitor {
-       factor_vm *parent;
-       bool reset_inline_caches;
-
-       update_word_references_relocation_visitor(
-               factor_vm *parent_,
-               bool reset_inline_caches_) :
-               parent(parent_),
-               reset_inline_caches(reset_inline_caches_) {}
-
-       void operator()(instruction_operand op)
-       {
-               switch(op.rel_type())
-               {
-               case RT_ENTRY_POINT:
-                       {
-                               code_block *compiled = op.load_code_block();
-                               cell owner = compiled->owner;
-                               if(to_boolean(owner))
-                                       op.store_value(parent->compute_entry_point_address(owner));
-                               break;
-                       }
-               case RT_ENTRY_POINT_PIC:
-                       {
-                               code_block *compiled = op.load_code_block();
-                               if(reset_inline_caches || !compiled->pic_p())
-                               {
-                                       cell owner = parent->code_block_owner(compiled);
-                                       if(to_boolean(owner))
-                                               op.store_value(parent->compute_entry_point_pic_address(owner));
-                               }
-                               break;
-                       }
-               case RT_ENTRY_POINT_PIC_TAIL:
-                       {
-                               code_block *compiled = op.load_code_block();
-                               if(reset_inline_caches || !compiled->pic_p())
-                               {
-                                       cell owner = parent->code_block_owner(compiled);
-                                       if(to_boolean(owner))
-                                               op.store_value(parent->compute_entry_point_pic_tail_address(owner));
-                               }
-                               break;
-                       }
-               default:
-                       break;
-               }
-       }
+  factor_vm* parent;
+  bool reset_inline_caches;
+
+  update_word_references_relocation_visitor(factor_vm* parent_,
+                                            bool reset_inline_caches_)
+      : parent(parent_), reset_inline_caches(reset_inline_caches_) {}
+
+  void operator()(instruction_operand op) {
+    switch (op.rel_type()) {
+      case RT_ENTRY_POINT: {
+        code_block* compiled = op.load_code_block();
+        cell owner = compiled->owner;
+        if (to_boolean(owner))
+          op.store_value(parent->compute_entry_point_address(owner));
+        break;
+      }
+      case RT_ENTRY_POINT_PIC: {
+        code_block* compiled = op.load_code_block();
+        if (reset_inline_caches || !compiled->pic_p()) {
+          cell owner = parent->code_block_owner(compiled);
+          if (to_boolean(owner))
+            op.store_value(parent->compute_entry_point_pic_address(owner));
+        }
+        break;
+      }
+      case RT_ENTRY_POINT_PIC_TAIL: {
+        code_block* compiled = op.load_code_block();
+        if (reset_inline_caches || !compiled->pic_p()) {
+          cell owner = parent->code_block_owner(compiled);
+          if (to_boolean(owner))
+            op.store_value(parent->compute_entry_point_pic_tail_address(owner));
+        }
+        break;
+      }
+      default:
+        break;
+    }
+  }
 };
 
 /* Relocate new code blocks completely; updating references to literals,
-dlsyms, and words. For all other words in the code heap, we only need
-to update references to other words, without worrying about literals
-or dlsyms. */
-void factor_vm::update_word_references(code_block *compiled, bool reset_inline_caches)
-{
-       if(code->uninitialized_p(compiled))
-               initialize_code_block(compiled);
-       /* update_word_references() is always applied to every block in
-          the code heap. Since it resets all call sites to point to
-          their canonical entry point (cold entry point for non-tail calls,
-          standard entry point for tail calls), it means that no PICs
-          are referenced after this is done. So instead of polluting
-          the code heap with dead PICs that will be freed on the next
-          GC, we add them to the free list immediately. */
-       else if(reset_inline_caches && compiled->pic_p())
-               code->free(compiled);
-       else
-       {
-               update_word_references_relocation_visitor visitor(this,reset_inline_caches);
-               compiled->each_instruction_operand(visitor);
-               compiled->flush_icache();
-       }
+   dlsyms, and words. For all other words in the code heap, we only need
+   to update references to other words, without worrying about literals
+   or dlsyms. */
+void factor_vm::update_word_references(code_block* compiled,
+                                       bool reset_inline_caches) {
+  if (code->uninitialized_p(compiled))
+    initialize_code_block(compiled);
+  /* update_word_references() is always applied to every block in
+     the code heap. Since it resets all call sites to point to
+     their canonical entry point (cold entry point for non-tail calls,
+     standard entry point for tail calls), it means that no PICs
+     are referenced after this is done. So instead of polluting
+     the code heap with dead PICs that will be freed on the next
+     GC, we add them to the free list immediately. */
+  else if (reset_inline_caches && compiled->pic_p())
+    code->free(compiled);
+  else {
+    update_word_references_relocation_visitor visitor(this,
+                                                      reset_inline_caches);
+    compiled->each_instruction_operand(visitor);
+    compiled->flush_icache();
+  }
 }
 
 /* Look up an external library symbol referenced by a compiled code block */
-cell factor_vm::compute_dlsym_address(array *parameters, cell index)
-{
-       cell symbol = array_nth(parameters,index);
-       cell library = array_nth(parameters,index + 1);
-
-       dll *d = (to_boolean(library) ? untag<dll>(library) : NULL);
-
-       void* undefined_symbol = (void*)factor::undefined_symbol;
-       undefined_symbol = FUNCTION_CODE_POINTER(undefined_symbol);
-       if(d != NULL && !d->handle)
-               return (cell)undefined_symbol;
-
-       switch(tagged<object>(symbol).type())
-       {
-       case BYTE_ARRAY_TYPE:
-               {
-                       symbol_char *name = alien_offset(symbol);
-                       void *sym = ffi_dlsym(d,name);
-
-                       if(sym)
-                               return (cell)sym;
-                       else
-                               return (cell)undefined_symbol;
-               }
-       case ARRAY_TYPE:
-               {
-                       array *names = untag<array>(symbol);
-                       for(cell i = 0; i < array_capacity(names); i++)
-                       {
-                               symbol_char *name = alien_offset(array_nth(names,i));
-                               void *sym = ffi_dlsym(d,name);
-
-                               if(sym)
-                                       return (cell)sym;
-                       }
-                       return (cell)undefined_symbol;
-               }
-       default:
-               critical_error("Bad symbol specifier",symbol);
-               return (cell)undefined_symbol;
-       }
+cell factor_vm::compute_dlsym_address(array* parameters, cell index) {
+  cell symbol = array_nth(parameters, index);
+  cell library = array_nth(parameters, index + 1);
+
+  dll* d = (to_boolean(library) ? untag<dll>(library) : NULL);
+
+  void* undefined_symbol = (void*)factor::undefined_symbol;
+  undefined_symbol = FUNCTION_CODE_POINTER(undefined_symbol);
+  if (d != NULL && !d->handle)
+    return (cell) undefined_symbol;
+
+  switch (tagged<object>(symbol).type()) {
+    case BYTE_ARRAY_TYPE: {
+      symbol_char* name = alien_offset(symbol);
+      void* sym = ffi_dlsym(d, name);
+
+      if (sym)
+        return (cell) sym;
+      else
+        return (cell) undefined_symbol;
+    }
+    case ARRAY_TYPE: {
+      array* names = untag<array>(symbol);
+      for (cell i = 0; i < array_capacity(names); i++) {
+        symbol_char* name = alien_offset(array_nth(names, i));
+        void* sym = ffi_dlsym(d, name);
+
+        if (sym)
+          return (cell) sym;
+      }
+      return (cell) undefined_symbol;
+    }
+    default:
+      critical_error("Bad symbol specifier", symbol);
+      return (cell) undefined_symbol;
+  }
 }
 
 #ifdef FACTOR_PPC
-cell factor_vm::compute_dlsym_toc_address(array *parameters, cell index)
-{
-       cell symbol = array_nth(parameters,index);
-       cell library = array_nth(parameters,index + 1);
-
-       dll *d = (to_boolean(library) ? untag<dll>(library) : NULL);
-
-       void* undefined_toc = (void*)factor::undefined_symbol;
-       undefined_toc = FUNCTION_TOC_POINTER(undefined_toc);
-       if(d != NULL && !d->handle)
-               return (cell)undefined_toc;
-
-       switch(tagged<object>(symbol).type())
-       {
-       case BYTE_ARRAY_TYPE:
-               {
-                       symbol_char *name = alien_offset(symbol);
-                       void* toc = ffi_dlsym_toc(d,name);
-                       if(toc)
-                               return (cell)toc;
-                       else
-                               return (cell)undefined_toc;
-               }
-       case ARRAY_TYPE:
-               {
-                       array *names = untag<array>(symbol);
-                       for(cell i = 0; i < array_capacity(names); i++)
-                       {
-                               symbol_char *name = alien_offset(array_nth(names,i));
-                               void *toc = ffi_dlsym_toc(d,name);
-
-                               if(toc)
-                                       return (cell)toc;
-                       }
-                       return (cell)undefined_toc;
-               }
-       default:
-               critical_error("Bad symbol specifier",symbol);
-               return (cell)undefined_toc;
-       }
+cell factor_vm::compute_dlsym_toc_address(array* parameters, cell index) {
+  cell symbol = array_nth(parameters, index);
+  cell library = array_nth(parameters, index + 1);
+
+  dll* d = (to_boolean(library) ? untag<dll>(library) : NULL);
+
+  void* undefined_toc = (void*)factor::undefined_symbol;
+  undefined_toc = FUNCTION_TOC_POINTER(undefined_toc);
+  if (d != NULL && !d->handle)
+    return (cell) undefined_toc;
+
+  switch (tagged<object>(symbol).type()) {
+    case BYTE_ARRAY_TYPE: {
+      symbol_char* name = alien_offset(symbol);
+      void* toc = ffi_dlsym_toc(d, name);
+      if (toc)
+        return (cell) toc;
+      else
+        return (cell) undefined_toc;
+    }
+    case ARRAY_TYPE: {
+      array* names = untag<array>(symbol);
+      for (cell i = 0; i < array_capacity(names); i++) {
+        symbol_char* name = alien_offset(array_nth(names, i));
+        void* toc = ffi_dlsym_toc(d, name);
+
+        if (toc)
+          return (cell) toc;
+      }
+      return (cell) undefined_toc;
+    }
+    default:
+      critical_error("Bad symbol specifier", symbol);
+      return (cell) undefined_toc;
+  }
 }
 #endif
 
-cell factor_vm::compute_vm_address(cell arg)
-{
-       return (cell)this + untag_fixnum(arg);
+cell factor_vm::compute_vm_address(cell arg) {
+  return (cell) this + untag_fixnum(arg);
 }
 
-void factor_vm::store_external_address(instruction_operand op)
-{
-       code_block *compiled = op.compiled;
-       array *parameters = (to_boolean(compiled->parameters) ? untag<array>(compiled->parameters) : NULL);
-       cell index = op.index;
-
-       switch(op.rel_type())
-       {
-       case RT_DLSYM:
-               op.store_value(compute_dlsym_address(parameters,index));
-               break;
-       case RT_THIS:
-               op.store_value((cell)compiled->entry_point());
-               break;
-       case RT_MEGAMORPHIC_CACHE_HITS:
-               op.store_value((cell)&dispatch_stats.megamorphic_cache_hits);
-               break;
-       case RT_VM:
-               op.store_value(compute_vm_address(array_nth(parameters,index)));
-               break;
-       case RT_CARDS_OFFSET:
-               op.store_value(cards_offset);
-               break;
-       case RT_DECKS_OFFSET:
-               op.store_value(decks_offset);
-               break;
+void factor_vm::store_external_address(instruction_operand op) {
+  code_block* compiled = op.compiled;
+  array* parameters =
+      (to_boolean(compiled->parameters) ? untag<array>(compiled->parameters)
+                                        : NULL);
+  cell index = op.index;
+
+  switch (op.rel_type()) {
+    case RT_DLSYM:
+      op.store_value(compute_dlsym_address(parameters, index));
+      break;
+    case RT_THIS:
+      op.store_value((cell) compiled->entry_point());
+      break;
+    case RT_MEGAMORPHIC_CACHE_HITS:
+      op.store_value((cell) & dispatch_stats.megamorphic_cache_hits);
+      break;
+    case RT_VM:
+      op.store_value(compute_vm_address(array_nth(parameters, index)));
+      break;
+    case RT_CARDS_OFFSET:
+      op.store_value(cards_offset);
+      break;
+    case RT_DECKS_OFFSET:
+      op.store_value(decks_offset);
+      break;
 #ifdef WINDOWS
-       case RT_EXCEPTION_HANDLER:
-               op.store_value((cell)&factor::exception_handler);
-               break;
+    case RT_EXCEPTION_HANDLER:
+      op.store_value((cell) & factor::exception_handler);
+      break;
 #endif
 #ifdef FACTOR_PPC
-       case RT_DLSYM_TOC:
-               op.store_value(compute_dlsym_toc_address(parameters,index));
-               break;
+    case RT_DLSYM_TOC:
+      op.store_value(compute_dlsym_toc_address(parameters, index));
+      break;
 #endif
-       case RT_INLINE_CACHE_MISS:
-               op.store_value((cell)&factor::inline_cache_miss);
-               break;
-       case RT_SAFEPOINT:
-               op.store_value((cell)code->safepoint_page);
-               break;
-       default:
-               critical_error("Bad rel type in store_external_address()",op.rel_type());
-               break;
-       }
+    case RT_INLINE_CACHE_MISS:
+      op.store_value((cell) & factor::inline_cache_miss);
+      break;
+    case RT_SAFEPOINT:
+      op.store_value((cell) code->safepoint_page);
+      break;
+    default:
+      critical_error("Bad rel type in store_external_address()", op.rel_type());
+      break;
+  }
 }
 
-cell factor_vm::compute_here_address(cell arg, cell offset, code_block *compiled)
-{
-       fixnum n = untag_fixnum(arg);
-       if(n >= 0)
-               return (cell)compiled->entry_point() + offset + n;
-       else
-               return (cell)compiled->entry_point() - n;
+cell factor_vm::compute_here_address(cell arg, cell offset,
+                                     code_block* compiled) {
+  fixnum n = untag_fixnum(arg);
+  if (n >= 0)
+    return (cell) compiled->entry_point() + offset + n;
+  else
+    return (cell) compiled->entry_point() - n;
 }
 
 struct initial_code_block_visitor {
-       factor_vm *parent;
-       cell literals;
-       cell literal_index;
-
-       explicit initial_code_block_visitor(factor_vm *parent_, cell literals_)
-               : parent(parent_), literals(literals_), literal_index(0) {}
-
-       cell next_literal()
-       {
-               return array_nth(untag<array>(literals),literal_index++);
-       }
-
-       void operator()(instruction_operand op)
-       {
-               switch(op.rel_type())
-               {
-               case RT_LITERAL:
-                       op.store_value(next_literal());
-                       break;
-               case RT_ENTRY_POINT:
-                       op.store_value(parent->compute_entry_point_address(next_literal()));
-                       break;
-               case RT_ENTRY_POINT_PIC:
-                       op.store_value(parent->compute_entry_point_pic_address(next_literal()));
-                       break;
-               case RT_ENTRY_POINT_PIC_TAIL:
-                       op.store_value(parent->compute_entry_point_pic_tail_address(next_literal()));
-                       break;
-               case RT_HERE:
-                       op.store_value(parent->compute_here_address(next_literal(),op.rel_offset(),op.compiled));
-                       break;
-               case RT_UNTAGGED:
-                       op.store_value(untag_fixnum(next_literal()));
-                       break;
-               default:
-                       parent->store_external_address(op);
-                       break;
-               }
-       }
+  factor_vm* parent;
+  cell literals;
+  cell literal_index;
+
+  explicit initial_code_block_visitor(factor_vm* parent_, cell literals_)
+      : parent(parent_), literals(literals_), literal_index(0) {}
+
+  cell next_literal() {
+    return array_nth(untag<array>(literals), literal_index++);
+  }
+
+  void operator()(instruction_operand op) {
+    switch (op.rel_type()) {
+      case RT_LITERAL:
+        op.store_value(next_literal());
+        break;
+      case RT_ENTRY_POINT:
+        op.store_value(parent->compute_entry_point_address(next_literal()));
+        break;
+      case RT_ENTRY_POINT_PIC:
+        op.store_value(parent->compute_entry_point_pic_address(next_literal()));
+        break;
+      case RT_ENTRY_POINT_PIC_TAIL:
+        op.store_value(
+            parent->compute_entry_point_pic_tail_address(next_literal()));
+        break;
+      case RT_HERE:
+        op.store_value(parent->compute_here_address(
+            next_literal(), op.rel_offset(), op.compiled));
+        break;
+      case RT_UNTAGGED:
+        op.store_value(untag_fixnum(next_literal()));
+        break;
+      default:
+        parent->store_external_address(op);
+        break;
+    }
+  }
 };
 
 /* Perform all fixups on a code block */
-void factor_vm::initialize_code_block(code_block *compiled, cell literals)
-{
-       initial_code_block_visitor visitor(this,literals);
-       compiled->each_instruction_operand(visitor);
-       compiled->flush_icache();
-
-       /* next time we do a minor GC, we have to trace this code block, since
-       the newly-installed instruction operands might point to literals in
-       nursery or aging */
-       code->write_barrier(compiled);
+void factor_vm::initialize_code_block(code_block* compiled, cell literals) {
+  initial_code_block_visitor visitor(this, literals);
+  compiled->each_instruction_operand(visitor);
+  compiled->flush_icache();
+
+  /* next time we do a minor GC, we have to trace this code block, since
+     the newly-installed instruction operands might point to literals in
+     nursery or aging */
+  code->write_barrier(compiled);
 }
 
-void factor_vm::initialize_code_block(code_block *compiled)
-{
-       std::map<code_block *,cell>::iterator iter = code->uninitialized_blocks.find(compiled);
-       initialize_code_block(compiled,iter->second);
-       code->uninitialized_blocks.erase(iter);
+void factor_vm::initialize_code_block(code_block* compiled) {
+  std::map<code_block*, cell>::iterator iter =
+      code->uninitialized_blocks.find(compiled);
+  initialize_code_block(compiled, iter->second);
+  code->uninitialized_blocks.erase(iter);
 }
 
 /* Fixup labels. This is done at compile time, not image load time */
-void factor_vm::fixup_labels(array *labels, code_block *compiled)
-{
-       cell size = array_capacity(labels);
+void factor_vm::fixup_labels(array* labels, code_block* compiled) {
+  cell size = array_capacity(labels);
 
-       for(cell i = 0; i < size; i += 3)
-       {
-               relocation_class rel_class = (relocation_class)untag_fixnum(array_nth(labels,i));
-               cell offset = untag_fixnum(array_nth(labels,i + 1));
-               cell target = untag_fixnum(array_nth(labels,i + 2));
+  for (cell i = 0; i < size; i += 3) {
+    relocation_class rel_class =
+        (relocation_class) untag_fixnum(array_nth(labels, i));
+    cell offset = untag_fixnum(array_nth(labels, i + 1));
+    cell target = untag_fixnum(array_nth(labels, i + 2));
 
-               relocation_entry new_entry(RT_HERE,rel_class,offset);
+    relocation_entry new_entry(RT_HERE, rel_class, offset);
 
-               instruction_operand op(new_entry,compiled,0);
-               op.store_value(target + (cell)compiled->entry_point());
-       }
+    instruction_operand op(new_entry, compiled, 0);
+    op.store_value(target + (cell) compiled->entry_point());
+  }
 }
 
 /* Might GC */
 /* Allocates memory */
-code_block *factor_vm::allot_code_block(cell size, code_block_type type)
-{
-       code_block *block = code->allocator->allot(size + sizeof(code_block));
-
-       /* If allocation failed, do a full GC and compact the code heap.
-       A full GC that occurs as a result of the data heap filling up does not
-       trigger a compaction. This setup ensures that most GCs do not compact
-       the code heap, but if the code fills up, it probably means it will be
-       fragmented after GC anyway, so its best to compact. */
-       if(block == NULL)
-       {
-               primitive_compact_gc();
-               block = code->allocator->allot(size + sizeof(code_block));
-
-               /* Insufficient room even after code GC, give up */
-               if(block == NULL)
-               {
-                       std::cout << "Code heap used: " << code->allocator->occupied_space() << "\n";
-                       std::cout << "Code heap free: " << code->allocator->free_space() << "\n";
-                       fatal_error("Out of memory in add-compiled-block",0);
-               }
-       }
-
-       block->set_type(type);
-       return block;
+code_block* factor_vm::allot_code_block(cell size, code_block_type type) {
+  code_block* block = code->allocator->allot(size + sizeof(code_block));
+
+  /* If allocation failed, do a full GC and compact the code heap.
+     A full GC that occurs as a result of the data heap filling up does not
+     trigger a compaction. This setup ensures that most GCs do not compact
+     the code heap, but if the code fills up, it probably means it will be
+     fragmented after GC anyway, so its best to compact. */
+  if (block == NULL) {
+    primitive_compact_gc();
+    block = code->allocator->allot(size + sizeof(code_block));
+
+    /* Insufficient room even after code GC, give up */
+    if (block == NULL) {
+      std::cout << "Code heap used: " << code->allocator->occupied_space()
+                << "\n";
+      std::cout << "Code heap free: " << code->allocator->free_space() << "\n";
+      fatal_error("Out of memory in add-compiled-block", 0);
+    }
+  }
+
+  block->set_type(type);
+  return block;
 }
 
 /* Might GC */
 /* Allocates memory */
-code_block *factor_vm::add_code_block(code_block_type type, cell code_, cell labels_,
-       cell owner_, cell relocation_, cell parameters_, cell literals_,
-       cell frame_size_untagged)
-{
-       data_root<byte_array> code(code_,this);
-       data_root<object> labels(labels_,this);
-       data_root<object> owner(owner_,this);
-       data_root<byte_array> relocation(relocation_,this);
-       data_root<array> parameters(parameters_,this);
-       data_root<array> literals(literals_,this);
-
-       cell code_length = array_capacity(code.untagged());
-       code_block *compiled = allot_code_block(code_length,type);
-
-       compiled->owner = owner.value();
-
-       /* slight space optimization */
-       if(relocation.type() == BYTE_ARRAY_TYPE && array_capacity(relocation.untagged()) == 0)
-               compiled->relocation = false_object;
-       else
-               compiled->relocation = relocation.value();
-
-       if(parameters.type() == ARRAY_TYPE && array_capacity(parameters.untagged()) == 0)
-               compiled->parameters = false_object;
-       else
-               compiled->parameters = parameters.value();
-
-       /* code */
-       memcpy(compiled + 1,code.untagged() + 1,code_length);
-
-       /* fixup labels */
-       if(to_boolean(labels.value()))
-               fixup_labels(labels.as<array>().untagged(),compiled);
-
-       compiled->set_stack_frame_size(frame_size_untagged);
-
-       /* Once we are ready, fill in literal and word references in this code
-       block's instruction operands. In most cases this is done right after this
-       method returns, except when compiling words with the non-optimizing
-       compiler at the beginning of bootstrap */
-       this->code->uninitialized_blocks.insert(std::make_pair(compiled,literals.value()));
-       this->code->all_blocks.insert((cell)compiled);
-
-       /* next time we do a minor GC, we have to trace this code block, since
-       the fields of the code_block struct might point into nursery or aging */
-       this->code->write_barrier(compiled);
-
-       return compiled;
+code_block* factor_vm::add_code_block(code_block_type type, cell code_,
+                                      cell labels_, cell owner_,
+                                      cell relocation_, cell parameters_,
+                                      cell literals_,
+                                      cell frame_size_untagged) {
+  data_root<byte_array> code(code_, this);
+  data_root<object> labels(labels_, this);
+  data_root<object> owner(owner_, this);
+  data_root<byte_array> relocation(relocation_, this);
+  data_root<array> parameters(parameters_, this);
+  data_root<array> literals(literals_, this);
+
+  cell code_length = array_capacity(code.untagged());
+  code_block* compiled = allot_code_block(code_length, type);
+
+  compiled->owner = owner.value();
+
+  /* slight space optimization */
+  if (relocation.type() == BYTE_ARRAY_TYPE &&
+      array_capacity(relocation.untagged()) == 0)
+    compiled->relocation = false_object;
+  else
+    compiled->relocation = relocation.value();
+
+  if (parameters.type() == ARRAY_TYPE &&
+      array_capacity(parameters.untagged()) == 0)
+    compiled->parameters = false_object;
+  else
+    compiled->parameters = parameters.value();
+
+  /* code */
+  memcpy(compiled + 1, code.untagged() + 1, code_length);
+
+  /* fixup labels */
+  if (to_boolean(labels.value()))
+    fixup_labels(labels.as<array>().untagged(), compiled);
+
+  compiled->set_stack_frame_size(frame_size_untagged);
+
+  /* Once we are ready, fill in literal and word references in this code
+     block's instruction operands. In most cases this is done right after this
+     method returns, except when compiling words with the non-optimizing
+     compiler at the beginning of bootstrap */
+  this->code->uninitialized_blocks
+      .insert(std::make_pair(compiled, literals.value()));
+  this->code->all_blocks.insert((cell) compiled);
+
+  /* next time we do a minor GC, we have to trace this code block, since
+     the fields of the code_block struct might point into nursery or aging */
+  this->code->write_barrier(compiled);
+
+  return compiled;
 }
 
 /* Find the RT_DLSYM relocation nearest to the given return address. */
 struct find_symbol_at_address_visitor {
-       factor_vm *parent;
-       cell return_address;
-       cell symbol;
-       cell library;
-
-       find_symbol_at_address_visitor(factor_vm *parent_, cell return_address_) :
-               parent(parent_), return_address(return_address_),
-               symbol(false_object), library(false_object) { }
-
-       void operator()(instruction_operand op)
-       {
-               if(op.rel_type() == RT_DLSYM && op.pointer <= return_address)
-               {
-                       code_block *compiled = op.compiled;
-                       array *parameters = untag<array>(compiled->parameters);
-                       cell index = op.index;
-                       symbol = array_nth(parameters,index);
-                       library = array_nth(parameters,index + 1);
-               }
-       }
+  factor_vm* parent;
+  cell return_address;
+  cell symbol;
+  cell library;
+
+  find_symbol_at_address_visitor(factor_vm* parent_, cell return_address_)
+      : parent(parent_),
+        return_address(return_address_),
+        symbol(false_object),
+        library(false_object) {}
+
+  void operator()(instruction_operand op) {
+    if (op.rel_type() == RT_DLSYM && op.pointer <= return_address) {
+      code_block* compiled = op.compiled;
+      array* parameters = untag<array>(compiled->parameters);
+      cell index = op.index;
+      symbol = array_nth(parameters, index);
+      library = array_nth(parameters, index + 1);
+    }
+  }
 };
 
 /* References to undefined symbols are patched up to call this function on
-image load. It finds the symbol and library, and throws an error. */
-void factor_vm::undefined_symbol()
-{
-       void *frame = ctx->callstack_top;
-       void *return_address = frame_return_address(frame);
-       code_block *compiled = code->code_block_for_address((cell)return_address);
-       find_symbol_at_address_visitor visitor(this, (cell)return_address);
-       compiled->each_instruction_operand(visitor);
-       if (!to_boolean(visitor.symbol))
-               critical_error("Can't find RT_DLSYM at return address", (cell)return_address);
-       else
-               general_error(ERROR_UNDEFINED_SYMBOL,visitor.symbol,visitor.library);
+   image load. It finds the symbol and library, and throws an error. */
+void factor_vm::undefined_symbol() {
+  void* frame = ctx->callstack_top;
+  void* return_address = frame_return_address(frame);
+  code_block* compiled = code->code_block_for_address((cell) return_address);
+  find_symbol_at_address_visitor visitor(this, (cell) return_address);
+  compiled->each_instruction_operand(visitor);
+  if (!to_boolean(visitor.symbol))
+    critical_error("Can't find RT_DLSYM at return address",
+                   (cell) return_address);
+  else
+    general_error(ERROR_UNDEFINED_SYMBOL, visitor.symbol, visitor.library);
 }
 
-void undefined_symbol()
-{
-       return current_vm()->undefined_symbol();
-}
+void undefined_symbol() { return current_vm()->undefined_symbol(); }
 
 }
index 4f67a199267335241d7275b183504349b5ebb6c8..7bc89f4a4c143f5d62f7f1503255e9c390b50a5c 100644 (file)
-namespace factor
-{
+namespace factor {
 
 /* The compiled code heap is structured into blocks. */
-struct code_block
-{
-       // header format (bits indexed with least significant as zero):
-       // bit   0  : free?
-       // bits  1-2: type (as a code_block_type)
-       // if not free:
-       //   bits  3-23: code size / 8
-       //   bits 24-31: stack frame size / 16
-       // if free:
-       //   bits  3-end: code size / 8
-       cell header;
-       cell owner; /* tagged pointer to word, quotation or f */
-       cell parameters; /* tagged pointer to array or f */
-       cell relocation; /* tagged pointer to byte-array or f */
-
-       bool free_p() const
-       {
-               return (header & 1) == 1;
-       }
-
-       code_block_type type() const
-       {
-               return (code_block_type)((header >> 1) & 0x3);
-       }
-
-       void set_type(code_block_type type)
-       {
-               header = ((header & ~0x7) | (type << 1));
-       }
-
-       bool pic_p() const
-       {
-               return type() == code_block_pic;
-       }
-
-       bool optimized_p() const
-       {
-               return type() == code_block_optimized;
-       }
-
-       cell size() const
-       {
-               cell size;
-               if (free_p())
-                       size = header & ~7;
-               else
-                       size = header & 0xFFFFF8;
-               FACTOR_ASSERT(size > 0);
-               return size;
-       }
-
-       cell stack_frame_size() const
-       {
-               if (free_p())
-                       return 0;
-               else
-                       return (header >> 20) & 0xFF0;
-       }
-
-       cell stack_frame_size_for_address(cell addr) const
-       {
-               cell natural_frame_size = stack_frame_size();
-               /* The first instruction in a code block is the prolog safepoint,
-               and a leaf procedure code block will record a frame size of zero.
-               If we're seeing a stack frame in either of these cases, it's a
-               fake "leaf frame" set up by the signal handler. */
-               if (natural_frame_size == 0 || (void*)addr == entry_point())
-                       return LEAF_FRAME_SIZE;
-               else
-                       return natural_frame_size;
-       }
-
-       void set_stack_frame_size(cell frame_size)
-       {
-               FACTOR_ASSERT(size() < 0xFFFFFF);
-               FACTOR_ASSERT(!free_p());
-               FACTOR_ASSERT(frame_size % 16 == 0);
-               FACTOR_ASSERT(frame_size <= 0xFF0);
-               header = (header & 0xFFFFFF) | (frame_size << 20);
-       }
-
-       template<typename Fixup> cell size(Fixup fixup) const
-       {
-               return size();
-       }
-
-       void *entry_point() const
-       {
-               return (void *)(this + 1);
-       }
-
-       /* GC info is stored at the end of the block */
-       gc_info *block_gc_info() const
-       {
-               return (gc_info *)((u8 *)this + size() - sizeof(gc_info));
-       }
-
-       void flush_icache()
-       {
-               factor::flush_icache((cell)this,size());
-       }
-
-       template<typename Iterator> void each_instruction_operand(Iterator &iter)
-       {
-               if(to_boolean(relocation))
-               {
-                       byte_array *rels = (byte_array *)UNTAG(relocation);
-
-                       cell index = 0;
-                       cell length = (rels->capacity >> TAG_BITS) / sizeof(relocation_entry);
-
-                       for(cell i = 0; i < length; i++)
-                       {
-                               relocation_entry rel = rels->data<relocation_entry>()[i];
-                               iter(instruction_operand(rel,this,index));
-                               index += rel.number_of_parameters();
-                       }
-               }
-       }
-
-       cell offset(void *addr) const
-       {
-               return (char*)addr - (char*)entry_point();
-       }
-
-       void *address_for_offset(cell offset) const
-       {
-               return (void*)((char*)entry_point() + offset);
-       }
-
-       cell scan(factor_vm *vm, void *addr) const;
-       cell owner_quot() const;
+struct code_block {
+  // header format (bits indexed with least significant as zero):
+  // bit   0  : free?
+  // bits  1-2: type (as a code_block_type)
+  // if not free:
+  //   bits  3-23: code size / 8
+  //   bits 24-31: stack frame size / 16
+  // if free:
+  //   bits  3-end: code size / 8
+  cell header;
+  cell owner;      /* tagged pointer to word, quotation or f */
+  cell parameters; /* tagged pointer to array or f */
+  cell relocation; /* tagged pointer to byte-array or f */
+
+  bool free_p() const { return (header & 1) == 1; }
+
+  code_block_type type() const {
+    return (code_block_type)((header >> 1) & 0x3);
+  }
+
+  void set_type(code_block_type type) {
+    header = ((header & ~0x7) | (type << 1));
+  }
+
+  bool pic_p() const { return type() == code_block_pic; }
+
+  bool optimized_p() const { return type() == code_block_optimized; }
+
+  cell size() const {
+    cell size;
+    if (free_p())
+      size = header & ~7;
+    else
+      size = header & 0xFFFFF8;
+    FACTOR_ASSERT(size > 0);
+    return size;
+  }
+
+  cell stack_frame_size() const {
+    if (free_p())
+      return 0;
+    else
+      return (header >> 20) & 0xFF0;
+  }
+
+  cell stack_frame_size_for_address(cell addr) const {
+    cell natural_frame_size = stack_frame_size();
+    /* The first instruction in a code block is the prolog safepoint,
+       and a leaf procedure code block will record a frame size of zero.
+       If we're seeing a stack frame in either of these cases, it's a
+       fake "leaf frame" set up by the signal handler. */
+    if (natural_frame_size == 0 || (void*)addr == entry_point())
+      return LEAF_FRAME_SIZE;
+    else
+      return natural_frame_size;
+  }
+
+  void set_stack_frame_size(cell frame_size) {
+    FACTOR_ASSERT(size() < 0xFFFFFF);
+    FACTOR_ASSERT(!free_p());
+    FACTOR_ASSERT(frame_size % 16 == 0);
+    FACTOR_ASSERT(frame_size <= 0xFF0);
+    header = (header & 0xFFFFFF) | (frame_size << 20);
+  }
+
+  template <typename Fixup> cell size(Fixup fixup) const { return size(); }
+
+  void* entry_point() const { return (void*)(this + 1); }
+
+  /* GC info is stored at the end of the block */
+  gc_info* block_gc_info() const {
+    return (gc_info*)((u8*)this + size() - sizeof(gc_info));
+  }
+
+  void flush_icache() { factor::flush_icache((cell) this, size()); }
+
+  template <typename Iterator> void each_instruction_operand(Iterator& iter) {
+    if (to_boolean(relocation)) {
+      byte_array* rels = (byte_array*)UNTAG(relocation);
+
+      cell index = 0;
+      cell length = (rels->capacity >> TAG_BITS) / sizeof(relocation_entry);
+
+      for (cell i = 0; i < length; i++) {
+        relocation_entry rel = rels->data<relocation_entry>()[i];
+        iter(instruction_operand(rel, this, index));
+        index += rel.number_of_parameters();
+      }
+    }
+  }
+
+  cell offset(void* addr) const { return (char*)addr - (char*)entry_point(); }
+
+  void* address_for_offset(cell offset) const {
+    return (void*)((char*)entry_point() + offset);
+  }
+
+  cell scan(factor_vm* vm, void* addr) const;
+  cell owner_quot() const;
 };
 
 VM_C_API void undefined_symbol(void);
 
-inline code_block *word::code() const {
-       FACTOR_ASSERT(entry_point != NULL);
-       return (code_block*)entry_point - 1;
+inline code_blockword::code() const {
+  FACTOR_ASSERT(entry_point != NULL);
+  return (code_block*)entry_point - 1;
 }
 
-inline code_block *quotation::code() const {
-       FACTOR_ASSERT(entry_point != NULL);
-       return (code_block*)entry_point - 1;
+inline code_blockquotation::code() const {
+  FACTOR_ASSERT(entry_point != NULL);
+  return (code_block*)entry_point - 1;
 }
 
 }
-
-