]> gitweb.factorcode.org Git - factor.git/blobdiff - vm/slot_visitor.hpp
GC maps for more compact inline GC checks
[factor.git] / vm / slot_visitor.hpp
index d4dd44bed1a59b81cc78b5bdc50b04dedfb8ed75..148c05df1f457fc5d0c9fe6f7f1897e2e94d6a65 100644 (file)
@@ -1,6 +1,100 @@
 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();
+
+       switch(type())
+       {
+       case ARRAY_TYPE:
+               return align(array_size((array*)this),data_alignment);
+       case BIGNUM_TYPE:
+               return align(array_size((bignum*)this),data_alignment);
+       case BYTE_ARRAY_TYPE:
+               return align(array_size((byte_array*)this),data_alignment);
+       case STRING_TYPE:
+               return align(string_size(string_capacity((string*)this)),data_alignment);
+       case TUPLE_TYPE:
+               {
+                       tuple_layout *layout = (tuple_layout *)fixup.translate_data(untag<object>(((tuple *)this)->layout));
+                       return align(tuple_size(layout),data_alignment);
+               }
+       case QUOTATION_TYPE:
+               return align(sizeof(quotation),data_alignment);
+       case WORD_TYPE:
+               return align(sizeof(word),data_alignment);
+       case FLOAT_TYPE:
+               return align(sizeof(boxed_float),data_alignment);
+       case DLL_TYPE:
+               return align(sizeof(dll),data_alignment);
+       case ALIEN_TYPE:
+               return align(sizeof(alien),data_alignment);
+       case WRAPPER_TYPE:
+               return align(sizeof(wrapper),data_alignment);
+       case CALLSTACK_TYPE:
+               return align(callstack_object_size(untag_fixnum(((callstack *)this)->length)),data_alignment);
+       default:
+               critical_error("Invalid header in size",(cell)this);
+               return 0; /* can't happen */
+       }
+}
+
+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
+{
+       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) * 3;
+       case ALIEN_TYPE:
+               return sizeof(cell) * 3;
+       case DLL_TYPE:
+               return sizeof(cell) * 2;
+       case QUOTATION_TYPE:
+               return sizeof(quotation) - sizeof(cell) * 2;
+       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);
+               }
+       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());
+}
+
 /* 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,
@@ -17,12 +111,12 @@ Iteration is driven by visit_*() methods. Some of them define GC roots:
 - visit_roots()
 - visit_contexts() */
 
-template<typename Visitor> struct slot_visitor {
+template<typename Fixup> struct slot_visitor {
        factor_vm *parent;
-       Visitor visitor;
+       Fixup fixup;
 
-       explicit slot_visitor<Visitor>(factor_vm *parent_, Visitor visitor_) :
-               parent(parent_), visitor(visitor_) {}
+       explicit slot_visitor<Fixup>(factor_vm *parent_, Fixup fixup_) :
+               parent(parent_), fixup(fixup_) {}
 
        cell visit_pointer(cell pointer);
        void visit_handle(cell *handle);
@@ -35,35 +129,36 @@ template<typename Visitor> struct slot_visitor {
        void visit_callback_roots();
        void visit_literal_table_roots();
        void visit_roots();
+       void visit_callstack_object(callstack *stack);
+       void visit_callstack(context *ctx);
        void visit_contexts();
        void visit_code_block_objects(code_block *compiled);
        void visit_embedded_literals(code_block *compiled);
 };
 
-template<typename Visitor>
-cell slot_visitor<Visitor>::visit_pointer(cell pointer)
+template<typename Fixup>
+cell slot_visitor<Fixup>::visit_pointer(cell pointer)
 {
        if(immediate_p(pointer)) return pointer;
 
-       object *untagged = untag<object>(pointer);
-       untagged = visitor(untagged);
+       object *untagged = fixup.fixup_data(untag<object>(pointer));
        return RETAG(untagged,TAG(pointer));
 }
 
-template<typename Visitor>
-void slot_visitor<Visitor>::visit_handle(cell *handle)
+template<typename Fixup>
+void slot_visitor<Fixup>::visit_handle(cell *handle)
 {
        *handle = visit_pointer(*handle);
 }
 
-template<typename Visitor>
-void slot_visitor<Visitor>::visit_object_array(cell *start, cell *end)
+template<typename Fixup>
+void slot_visitor<Fixup>::visit_object_array(cell *start, cell *end)
 {
        while(start < end) visit_handle(start++);
 }
 
-template<typename Visitor>
-void slot_visitor<Visitor>::visit_slots(object *ptr, cell payload_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);
@@ -75,20 +170,23 @@ void slot_visitor<Visitor>::visit_slots(object *ptr, cell payload_start)
        }
 }
 
-template<typename Visitor>
-void slot_visitor<Visitor>::visit_slots(object *ptr)
+template<typename Fixup>
+void slot_visitor<Fixup>::visit_slots(object *obj)
 {
-       visit_slots(ptr,ptr->binary_payload_start());
+       if(obj->type() == CALLSTACK_TYPE)
+               visit_callstack_object((callstack *)obj);
+       else
+               visit_slots(obj,obj->binary_payload_start(fixup));
 }
 
-template<typename Visitor>
-void slot_visitor<Visitor>::visit_stack_elements(segment *region, cell *top)
+template<typename Fixup>
+void slot_visitor<Fixup>::visit_stack_elements(segment *region, cell *top)
 {
        visit_object_array((cell *)region->start,top + 1);
 }
 
-template<typename Visitor>
-void slot_visitor<Visitor>::visit_data_roots()
+template<typename Fixup>
+void slot_visitor<Fixup>::visit_data_roots()
 {
        std::vector<data_root_range>::const_iterator iter = parent->data_roots.begin();
        std::vector<data_root_range>::const_iterator end = parent->data_roots.end();
@@ -97,8 +195,8 @@ void slot_visitor<Visitor>::visit_data_roots()
                visit_object_array(iter->start,iter->start + iter->len);
 }
 
-template<typename Visitor>
-void slot_visitor<Visitor>::visit_bignum_roots()
+template<typename Fixup>
+void slot_visitor<Fixup>::visit_bignum_roots()
 {
        std::vector<cell>::const_iterator iter = parent->bignum_roots.begin();
        std::vector<cell>::const_iterator end = parent->bignum_roots.end();
@@ -108,16 +206,16 @@ void slot_visitor<Visitor>::visit_bignum_roots()
                cell *handle = (cell *)(*iter);
 
                if(*handle)
-                       *handle = (cell)visitor(*(object **)handle);
+                       *handle = (cell)fixup.fixup_data(*(object **)handle);
        }
 }
 
-template<typename Visitor>
+template<typename Fixup>
 struct callback_slot_visitor {
        callback_heap *callbacks;
-       slot_visitor<Visitor> *visitor;
+       slot_visitor<Fixup> *visitor;
 
-       explicit callback_slot_visitor(callback_heap *callbacks_, slot_visitor<Visitor> *visitor_) :
+       explicit callback_slot_visitor(callback_heap *callbacks_, slot_visitor<Fixup> *visitor_) :
                callbacks(callbacks_), visitor(visitor_) {}
 
        void operator()(code_block *stub)
@@ -126,15 +224,15 @@ struct callback_slot_visitor {
        }
 };
 
-template<typename Visitor>
-void slot_visitor<Visitor>::visit_callback_roots()
+template<typename Fixup>
+void slot_visitor<Fixup>::visit_callback_roots()
 {
-       callback_slot_visitor<Visitor> callback_visitor(parent->callbacks,this);
+       callback_slot_visitor<Fixup> callback_visitor(parent->callbacks,this);
        parent->callbacks->each_callback(callback_visitor);
 }
 
-template<typename Visitor>
-void slot_visitor<Visitor>::visit_literal_table_roots()
+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>::const_iterator iter = uninitialized_blocks->begin();
@@ -151,8 +249,8 @@ void slot_visitor<Visitor>::visit_literal_table_roots()
        parent->code->uninitialized_blocks = new_uninitialized_blocks;
 }
 
-template<typename Visitor>
-void slot_visitor<Visitor>::visit_roots()
+template<typename Fixup>
+void slot_visitor<Fixup>::visit_roots()
 {
        visit_handle(&parent->true_object);
        visit_handle(&parent->bignum_zero);
@@ -167,8 +265,62 @@ void slot_visitor<Visitor>::visit_roots()
        visit_object_array(parent->special_objects,parent->special_objects + special_object_count);
 }
 
-template<typename Visitor>
-void slot_visitor<Visitor>::visit_contexts()
+template<typename Fixup>
+struct call_frame_slot_visitor {
+       factor_vm *parent;
+       slot_visitor<Fixup> *visitor;
+
+       explicit call_frame_slot_visitor(factor_vm *parent_, slot_visitor<Fixup> *visitor_) :
+               parent(parent_), visitor(visitor_) {}
+
+       /*
+       next  -> [entry_point]
+                [size]
+                [return address] -- x86 only, backend adds 1 to each spill location
+                [spill area]
+                ...
+       frame -> [entry_point]
+                [size]
+       */
+       void operator()(stack_frame *frame)
+       {
+               const code_block *compiled = visitor->fixup.translate_code(parent->frame_code(frame));
+               gc_info *info = compiled->block_gc_info();
+
+               u32 return_address = (cell)FRAME_RETURN_ADDRESS(frame,parent) - (cell)compiled->entry_point();
+               int index = info->return_address_index(return_address);
+
+               if(index != -1)
+               {
+                       u8 *bitmap = info->gc_info_bitmap();
+                       cell base = info->spill_slot_base(index);
+                       cell *stack_pointer = (cell *)(parent->frame_successor(frame) + 1);
+
+                       for(cell spill_slot = 0; spill_slot < info->gc_root_count; spill_slot++)
+                       {
+                               if(bitmap_p(bitmap,base + spill_slot))
+                                       visitor->visit_handle(&stack_pointer[spill_slot]);
+                       }
+               }
+       }
+};
+
+template<typename Fixup>
+void slot_visitor<Fixup>::visit_callstack_object(callstack *stack)
+{
+       call_frame_slot_visitor<Fixup> call_frame_visitor(parent,this);
+       parent->iterate_callstack_object(stack,call_frame_visitor);
+}
+
+template<typename Fixup>
+void slot_visitor<Fixup>::visit_callstack(context *ctx)
+{
+       call_frame_slot_visitor<Fixup> call_frame_visitor(parent,this);
+       parent->iterate_callstack(ctx,call_frame_visitor);
+}
+
+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();
@@ -179,16 +331,16 @@ void slot_visitor<Visitor>::visit_contexts()
                visit_stack_elements(ctx->datastack_seg,(cell *)ctx->datastack);
                visit_stack_elements(ctx->retainstack_seg,(cell *)ctx->retainstack);
                visit_object_array(ctx->context_objects,ctx->context_objects + context_object_count);
-
+               visit_callstack(ctx);
                begin++;
        }
 }
 
-template<typename Visitor>
+template<typename Fixup>
 struct literal_references_visitor {
-       slot_visitor<Visitor> *visitor;
+       slot_visitor<Fixup> *visitor;
 
-       explicit literal_references_visitor(slot_visitor<Visitor> *visitor_) : visitor(visitor_) {}
+       explicit literal_references_visitor(slot_visitor<Fixup> *visitor_) : visitor(visitor_) {}
 
        void operator()(instruction_operand op)
        {
@@ -197,20 +349,20 @@ struct literal_references_visitor {
        }
 };
 
-template<typename Visitor>
-void slot_visitor<Visitor>::visit_code_block_objects(code_block *compiled)
+template<typename Fixup>
+void slot_visitor<Fixup>::visit_code_block_objects(code_block *compiled)
 {
        visit_handle(&compiled->owner);
        visit_handle(&compiled->parameters);
        visit_handle(&compiled->relocation);
 }
 
-template<typename Visitor>
-void slot_visitor<Visitor>::visit_embedded_literals(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<Visitor> visitor(this);
+               literal_references_visitor<Fixup> visitor(this);
                compiled->each_instruction_operand(visitor);
        }
 }