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 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 struct code_block_visitor { factor_vm *parent; Visitor visitor; explicit code_block_visitor(factor_vm *parent_, Visitor visitor_) : parent(parent_), visitor(visitor_) {} 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(); }; template code_block *code_block_visitor::visit_code_block(code_block *compiled) { return visitor(compiled); } template struct call_frame_code_block_visitor { factor_vm *parent; Visitor visitor; explicit call_frame_code_block_visitor(factor_vm *parent_, Visitor visitor_) : parent(parent_), visitor(visitor_) {} void operator()(stack_frame *frame) { cell offset = (cell)FRAME_RETURN_ADDRESS(frame,parent) - (cell)frame->entry_point; code_block *new_block = visitor(parent->frame_code(frame)); frame->entry_point = new_block->entry_point(); FRAME_RETURN_ADDRESS(frame,parent) = (void *)((cell)frame->entry_point + offset); } }; template void code_block_visitor::visit_object_code_block(object *obj) { switch(obj->type()) { case WORD_TYPE: { word *w = (word *)obj; if(w->code) w->code = visitor(w->code); if(w->profiling) w->profiling = visitor(w->profiling); parent->update_word_entry_point(w); break; } case QUOTATION_TYPE: { quotation *q = (quotation *)obj; if(q->code) parent->set_quot_entry_point(q,visitor(q->code)); break; } case CALLSTACK_TYPE: { callstack *stack = (callstack *)obj; call_frame_code_block_visitor call_frame_visitor(parent,visitor); parent->iterate_callstack_object(stack,call_frame_visitor); break; } } } template struct embedded_code_pointers_visitor { Visitor visitor; explicit embedded_code_pointers_visitor(Visitor visitor_) : visitor(visitor_) {} 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(visitor(op.load_code_block())); } }; template void code_block_visitor::visit_embedded_code_pointers(code_block *compiled) { if(!parent->code->uninitialized_p(compiled)) { embedded_code_pointers_visitor visitor(this->visitor); compiled->each_instruction_operand(visitor); } } template void code_block_visitor::visit_context_code_blocks() { call_frame_code_block_visitor call_frame_visitor(parent,visitor); parent->iterate_active_callstacks(call_frame_visitor); } template void code_block_visitor::visit_uninitialized_code_blocks() { std::map *uninitialized_blocks = &parent->code->uninitialized_blocks; std::map::const_iterator iter = uninitialized_blocks->begin(); std::map::const_iterator end = uninitialized_blocks->end(); std::map new_uninitialized_blocks; for(; iter != end; iter++) { new_uninitialized_blocks.insert(std::make_pair( visitor(iter->first), iter->second)); } parent->code->uninitialized_blocks = new_uninitialized_blocks; } }