}
};
-template <typename Fixup>
-fixnum compute_operand_value(factor_vm* parent,
- cell old_entry_point,
- Fixup fixup,
- instruction_operand op) {
- cell old_offset = op.rel_offset() + old_entry_point;
- switch (op.rel_type()) {
- case RT_LITERAL: {
- cell value = op.load_value(old_offset);
- if (immediate_p(value))
- return value;
- return RETAG(fixup.fixup_data(untag<object>(value)), TAG(value));
- }
- case RT_ENTRY_POINT:
- case RT_ENTRY_POINT_PIC:
- case RT_ENTRY_POINT_PIC_TAIL:
- case RT_HERE: {
- cell value = op.load_value(old_offset);
- cell offset = TAG(value);
- code_block* compiled = (code_block*)UNTAG(value);
- return (cell)fixup.fixup_code(compiled) + offset;
- }
- case RT_THIS:
- case RT_CARDS_OFFSET:
- case RT_DECKS_OFFSET:
- return parent->compute_external_address(op);
- default:
- return op.load_value(old_offset);
- }
-}
-
/* After a compaction, invalidate any code heap roots which are not
marked, and also slide the valid roots up so that call sites can be updated
correctly in case an inline cache compilation triggered compaction. */
/* Slide everything in the code heap up, and update data and code heap
pointers inside code blocks. */
- auto compact_data_func = [&](code_block* old_addr,
+ auto compact_code_func = [&](code_block* old_addr,
code_block* new_addr,
cell size) {
forwarder.visit_code_block_objects(new_addr);
cell old_entry_point = old_addr->entry_point();
- auto update_func = [&](instruction_operand op) {
- op.store_value(compute_operand_value(this,
- old_entry_point,
- forwarder.fixup,
- op));
- };
- new_addr->each_instruction_operand(update_func);
+ forwarder.visit_instruction_operands(new_addr, old_entry_point);
};
- code->allocator->compact(compact_data_func, fixup, &code_finger);
+ code->allocator->compact(compact_code_func, fixup, &code_finger);
forwarder.visit_all_roots();
forwarder.visit_context_code_blocks();
data->tenured->iterate(start_object_updater, fixup);
}
-struct startup_code_block_relocation_visitor {
- factor_vm* parent;
- startup_fixup fixup;
- slot_visitor<startup_fixup> visitor;
-
- startup_code_block_relocation_visitor(factor_vm* parent,
- startup_fixup fixup)
- : parent(parent),
- fixup(fixup),
- visitor(slot_visitor<startup_fixup>(parent, fixup)) {}
-
- fixnum compute_operand_value(instruction_operand op) {
- code_block* compiled = op.compiled;
- cell old_offset =
- op.rel_offset() + compiled->entry_point() - fixup.code_offset;
- switch (op.rel_type()) {
- case RT_LITERAL: {
- cell value = op.load_value(old_offset);
- if (immediate_p(value))
- return value;
- return RETAG(fixup.fixup_data(untag<object>(value)), TAG(value));
- }
- case RT_ENTRY_POINT:
- case RT_ENTRY_POINT_PIC:
- case RT_ENTRY_POINT_PIC_TAIL:
- case RT_HERE: {
- cell value = op.load_value(old_offset);
- cell offset = TAG(value);
- code_block* compiled = (code_block*)UNTAG(value);
- return (cell)fixup.fixup_code(compiled) + offset;
- }
- case RT_UNTAGGED:
- return op.load_value(old_offset);
- default:
- return parent->compute_external_address(op);
- }
- }
-
- void operator()(instruction_operand op) {
- op.store_value(compute_operand_value(op));
- }
-};
-
void factor_vm::fixup_code(cell data_offset, cell code_offset) {
startup_fixup fixup(data_offset, code_offset);
auto updater = [&](code_block* compiled, cell size) {
slot_visitor<startup_fixup> visitor(this, fixup);
visitor.visit_code_block_objects(compiled);
-
- startup_code_block_relocation_visitor code_visitor(this, fixup);
- compiled->each_instruction_operand(code_visitor);
+ cell rel_base = compiled->entry_point() - fixup.code_offset;
+ visitor.visit_instruction_operands(compiled, rel_base);
};
code->allocator->iterate(updater, fixup);
}
void visit_embedded_code_pointers(code_block* compiled);
void visit_object(object* obj);
void visit_mark_stack(std::vector<cell>* mark_stack);
+ void visit_instruction_operands(code_block* block, cell rel_base);
};
template <typename Fixup>
}
}
+/* 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 value = op.load_value(old_offset);
+ switch (op.rel_type()) {
+ case RT_LITERAL: {
+ value = visit_pointer(value);
+ break;
+ }
+ case RT_ENTRY_POINT:
+ case RT_ENTRY_POINT_PIC:
+ case RT_ENTRY_POINT_PIC_TAIL:
+ case RT_HERE: {
+ cell offset = TAG(value);
+ code_block* compiled = (code_block*)UNTAG(value);
+ value = RETAG(fixup.fixup_code(compiled), offset);
+ break;
+ }
+ case RT_UNTAGGED:
+ break;
+ default:
+ value = parent->compute_external_address(op);
+ break;
+ }
+ op.store_value(value);
+ };
+ block->each_instruction_operand(visit_func);
+}
+
}