-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 */
- }
+namespace factor {
+
+// Size sans alignment.
+template <typename Fixup>
+cell object::base_size(Fixup fixup) const {
+ switch (type()) {
+ case ARRAY_TYPE:
+ return array_size((array*)this);
+ case BIGNUM_TYPE:
+ return array_size((bignum*)this);
+ case BYTE_ARRAY_TYPE:
+ return array_size((byte_array*)this);
+ case STRING_TYPE:
+ return string_size(string_capacity((string*)this));
+ case TUPLE_TYPE: {
+ tuple_layout* layout = (tuple_layout*)fixup.translate_data(
+ untag<object>(((tuple*)this)->layout));
+ return tuple_size(layout);
+ }
+ case QUOTATION_TYPE:
+ return sizeof(quotation);
+ case WORD_TYPE:
+ return sizeof(word);
+ case FLOAT_TYPE:
+ return sizeof(boxed_float);
+ case DLL_TYPE:
+ return sizeof(dll);
+ case ALIEN_TYPE:
+ return sizeof(alien);
+ case WRAPPER_TYPE:
+ 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 base_size", (cell)this);
+ return 0;
+ }
}
-inline cell object::size() const
-{
- return size(no_fixup());
+// 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);
}
-/* 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::size() const { return size(no_fixup()); }
+
+// 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;
+
+ 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
+ }
+ }
}
-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.
-
-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.
-
-Iteration is driven by visit_*() methods. Some of them define GC roots:
-- visit_roots()
-- visit_contexts() */
-
-template<typename Fixup> struct slot_visitor {
- factor_vm *parent;
- Fixup fixup;
-
- explicit slot_visitor<Fixup>(factor_vm *parent_, Fixup fixup_) :
- parent(parent_), fixup(fixup_) {}
-
- 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_slots(object *ptr);
- void visit_stack_elements(segment *region, cell *top);
- void visit_data_roots();
- void visit_bignum_roots();
- 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);
+// 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.
+
+// 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()
+
+// 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.
+
+// 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),
+ 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_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_all_roots();
+ void visit_callstack_object(callstack* stack);
+ void visit_callstack(context* ctx);
+ void visit_context(context *ctx);
+ void visit_object_code_block(object* obj);
+ void visit_context_code_blocks();
+ void visit_uninitialized_code_blocks();
+ 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>
+cell slot_visitor<Fixup>::visit_pointer(cell 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);
+template <typename Fixup> void slot_visitor<Fixup>::visit_handle(cell* handle) {
+ if (!immediate_p(*handle)) {
+ *handle = visit_pointer(*handle);
+ }
}
-template<typename Fixup>
-void slot_visitor<Fixup>::visit_object_array(cell *start, cell *end)
-{
- while(start < end) visit_handle(start++);
+template <typename Fixup>
+void slot_visitor<Fixup>::visit_object_array(cell* start, cell* end) {
+ while (start < 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 {
+ cell* start = (cell*)obj + 1;
+ cell* end = start + obj->slot_count(fixup);
+ visit_object_array(start, 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));
+template <typename Fixup>
+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_stack_elements(segment *region, cell *top)
-{
- visit_object_array((cell *)region->start,top + 1);
-}
+template <typename Fixup> void slot_visitor<Fixup>::visit_all_roots() {
+ FACTOR_FOR_EACH(parent->data_roots) {
+ visit_handle(*iter);
+ }
-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();
+ auto callback_slot_visitor = [&](code_block* stub, cell size) {
+ (void)size;
+ visit_handle(&stub->owner);
+ };
+ parent->callbacks->allocator->iterate(callback_slot_visitor, no_fixup());
- for(; iter < end; iter++)
- visit_object_array(iter->start,iter->start + iter->len);
-}
+ FACTOR_FOR_EACH(parent->code->uninitialized_blocks) {
+ iter->second = visit_pointer(iter->second);
+ }
-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();
+ FACTOR_FOR_EACH(parent->samples) {
+ visit_handle(&iter->thread);
+ }
- for(; iter < end; iter++)
- {
- cell *handle = (cell *)(*iter);
+ visit_object_array(parent->special_objects,
+ parent->special_objects + special_object_count);
- if(*handle)
- *handle = (cell)fixup.fixup_data(*(object **)handle);
- }
+ FACTOR_FOR_EACH(parent->active_contexts) {
+ visit_context(*iter);
+ }
}
-template<typename Fixup>
-struct callback_slot_visitor {
- callback_heap *callbacks;
- slot_visitor<Fixup> *visitor;
+// 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:
+// - trace roots in spill slots
+
+template <typename Fixup> struct call_frame_slot_visitor {
+ slot_visitor<Fixup>* visitor;
+
+ call_frame_slot_visitor(slot_visitor<Fixup>* visitor)
+ : visitor(visitor) {}
+
+ // 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 =
+ Fixup::translated_code_block_map ? owner
+ : visitor->fixup.translate_code(owner);
+ gc_info* info = compiled->block_gc_info();
- explicit callback_slot_visitor(callback_heap *callbacks_, slot_visitor<Fixup> *visitor_) :
- callbacks(callbacks_), visitor(visitor_) {}
+ FACTOR_ASSERT(return_address < compiled->size());
+ cell callsite = info->return_address_index(return_address);
+ if (callsite == (cell)-1)
+ return;
- void operator()(code_block *stub)
- {
- visitor->visit_handle(&stub->owner);
- }
+#ifdef DEBUG_GC_MAPS
+ FACTOR_PRINT("call frame code block " << compiled << " with offset "
+ << return_address);
+#endif
+ cell* stack_pointer = (cell*)frame_top;
+ uint8_t* bitmap = info->gc_info_bitmap();
+
+ // 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);
+ if (base_pointer != (uint32_t)-1) {
+#ifdef DEBUG_GC_MAPS
+ FACTOR_PRINT("visiting derived root " << spill_slot
+ << " with base pointer " << base_pointer);
+#endif
+ stack_pointer[spill_slot] -= stack_pointer[base_pointer];
+ }
+ }
+
+ // 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
+ FACTOR_PRINT("visiting GC root " << spill_slot);
+ #endif
+ visitor->visit_handle(stack_pointer + spill_slot);
+ }
+ }
+
+ // 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);
+ if (base_pointer != (uint32_t)-1)
+ stack_pointer[spill_slot] += stack_pointer[base_pointer];
+ }
+ }
};
-template<typename Fixup>
-void slot_visitor<Fixup>::visit_callback_roots()
-{
- callback_slot_visitor<Fixup> callback_visitor(parent->callbacks,this);
- parent->callbacks->each_callback(callback_visitor);
+template <typename Fixup>
+void slot_visitor<Fixup>::visit_callstack_object(callstack* stack) {
+ 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_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();
- 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(
- iter->first,
- visit_pointer(iter->second)));
- }
-
- parent->code->uninitialized_blocks = new_uninitialized_blocks;
+template <typename Fixup>
+void slot_visitor<Fixup>::visit_callstack(context* 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_roots()
-{
- visit_handle(&parent->true_object);
- visit_handle(&parent->bignum_zero);
- visit_handle(&parent->bignum_pos_one);
- visit_handle(&parent->bignum_neg_one);
+template <typename Fixup>
+void slot_visitor<Fixup>::visit_context(context* ctx) {
+ visit_callstack(ctx);
+
+ cell ds_ptr = ctx->datastack;
+ cell rs_ptr = ctx->retainstack;
+ segment* ds_seg = ctx->datastack_seg;
+ segment* rs_seg = ctx->retainstack_seg;
+ visit_stack_elements(ds_seg, (cell*)ds_ptr);
+ visit_stack_elements(rs_seg, (cell*)rs_ptr);
+ 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.
+ ctx->fill_stack_seg(ds_ptr, ds_seg, 0xbaadbadd);
+ ctx->fill_stack_seg(rs_ptr, rs_seg, 0xdaabdabb);
+}
- visit_data_roots();
- visit_bignum_roots();
- visit_callback_roots();
- visit_literal_table_roots();
+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);
+}
- visit_object_array(parent->special_objects,parent->special_objects + special_object_count);
+template <typename Fixup>
+void slot_visitor<Fixup>::visit_embedded_literals(code_block* compiled) {
+ 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_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)
- {
- cell return_address = parent->frame_offset(frame);
- if(return_address == (cell)-1)
- return;
-
- code_block *compiled = visitor->fixup.translate_code(parent->frame_code(frame));
- gc_info *info = compiled->block_gc_info();
-
- assert(return_address < compiled->size());
- cell callsite = info->return_address_index(return_address);
- if(callsite == (cell)-1)
- return;
+template <typename Fixup> struct call_frame_code_block_visitor {
+ Fixup fixup;
-#ifdef DEBUG_GC_MAPS
- std::cout << "call frame code block " << compiled << " with offset " << return_address << std::endl;
-#endif
- cell *stack_pointer = (cell *)(parent->frame_successor(frame) + 1);
- u8 *bitmap = info->gc_info_bitmap();
-
- /* Subtract old value of base pointer from every derived pointer. */
- for(cell spill_slot = 0; spill_slot < info->derived_root_count; spill_slot++)
- {
- u32 base_pointer = info->lookup_base_pointer(callsite, spill_slot);
- if(base_pointer != (u32)-1)
- {
-#ifdef DEBUG_GC_MAPS
- std::cout << "visiting derived root " << spill_slot
- << " with base pointer " << base_pointer
- << std::endl;
-#endif
- stack_pointer[spill_slot] -= stack_pointer[base_pointer];
- }
- }
+ call_frame_code_block_visitor(Fixup fixup) : fixup(fixup) {}
- /* Update all GC roots, including base pointers. */
- cell callsite_gc_roots = info->callsite_gc_roots(callsite);
+ void operator()(cell frame_top, cell size, code_block* owner, cell addr) {
+ (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));
- 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
- std::cout << "visiting GC root " << spill_slot << std::endl;
-#endif
- visitor->visit_handle(stack_pointer + spill_slot);
- }
- }
-
- /* Add the base pointers to obtain new derived pointer values. */
- for(cell spill_slot = 0; spill_slot < info->derived_root_count; spill_slot++)
- {
- u32 base_pointer = info->lookup_base_pointer(callsite, spill_slot);
- if(base_pointer != (u32)-1)
- stack_pointer[spill_slot] += stack_pointer[base_pointer];
- }
- }
+ *(cell*)frame_top = fixed_addr;
+ }
};
-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_object_code_block(object* obj) {
+ switch (obj->type()) {
+ case WORD_TYPE: {
+ word* w = (word*)obj;
+ if (w->entry_point)
+ w->entry_point = fixup.fixup_code(w->code())->entry_point();
+ break;
+ }
+ case QUOTATION_TYPE: {
+ quotation* q = (quotation*)obj;
+ if (q->entry_point)
+ q->entry_point = fixup.fixup_code(q->code())->entry_point();
+ break;
+ }
+ case CALLSTACK_TYPE: {
+ callstack* stack = (callstack*)obj;
+ call_frame_code_block_visitor<Fixup> call_frame_visitor(fixup);
+ parent->iterate_callstack_object(stack, call_frame_visitor, fixup);
+ break;
+ }
+ }
}
-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_context_code_blocks() {
+ call_frame_code_block_visitor<Fixup> call_frame_visitor(fixup);
+ FACTOR_FOR_EACH(parent->active_contexts) {
+ parent->iterate_callstack(*iter, call_frame_visitor, fixup);
+ }
}
-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)
- {
- context *ctx = *begin;
-
- 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 Fixup>
+void slot_visitor<Fixup>::visit_uninitialized_code_blocks() {
+ std::map<code_block*, cell> new_uninitialized_blocks;
+ 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 literal_references_visitor {
- slot_visitor<Fixup> *visitor;
+template <typename Fixup>
+void slot_visitor<Fixup>::visit_embedded_code_pointers(code_block* compiled) {
+ 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);
+}
- explicit literal_references_visitor(slot_visitor<Fixup> *visitor_) : visitor(visitor_) {}
+template <typename Fixup>
+void slot_visitor<Fixup>::visit_object(object *ptr) {
+ visit_slots(ptr);
+ if (ptr->type() == ALIEN_TYPE)
+ ((alien*)ptr)->update_address();
+}
- void operator()(instruction_operand op)
- {
- if(op.rel_type() == RT_LITERAL)
- op.store_value(visitor->visit_pointer(op.load_value()));
- }
-};
+// 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();
+ mark_stack->pop_back();
+
+ if (ptr & 1) {
+ code_block* compiled = (code_block*)(ptr - 1);
+ visit_code_block_objects(compiled);
+ visit_embedded_literals(compiled);
+ visit_embedded_code_pointers(compiled);
+ } else {
+ object* obj = (object*)ptr;
+ visit_object(obj);
+ visit_object_code_block(obj);
+ }
+ }
+}
+
+// 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_block_objects(code_block *compiled)
-{
- visit_handle(&compiled->owner);
- visit_handle(&compiled->parameters);
- visit_handle(&compiled->relocation);
+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>
-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);
- }
+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);
+ }
}
}