From d2fe86eb7ee1c06ab1aae670ac82a736879c01c0 Mon Sep 17 00:00:00 2001 From: Erik Charlebois Date: Sat, 11 May 2013 21:50:21 -0400 Subject: [PATCH] VM: Refactor code_blocks to Factor style --- vm/code_block_visitor.hpp | 187 ++++----- vm/code_blocks.cpp | 813 ++++++++++++++++++-------------------- vm/code_blocks.hpp | 210 ++++------ 3 files changed, 561 insertions(+), 649 deletions(-) diff --git a/vm/code_block_visitor.hpp b/vm/code_block_visitor.hpp index 2baa6d1aa7..3e4cb53a9e 100644 --- a/vm/code_block_visitor.hpp +++ b/vm/code_block_visitor.hpp @@ -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 struct code_block_visitor { - factor_vm *parent; - Fixup fixup; - explicit code_block_visitor(factor_vm *parent_, Fixup fixup_) : - parent(parent_), fixup(fixup_) {} +template 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 -code_block *code_block_visitor::visit_code_block(code_block *compiled) -{ - return fixup.fixup_code(compiled); +template +code_block* code_block_visitor::visit_code_block(code_block* compiled) { + return fixup.fixup_code(compiled); } -template -struct call_frame_code_block_visitor { - factor_vm *parent; - Fixup fixup; +template 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_) {} + 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); - } + 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 -void code_block_visitor::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 call_frame_visitor(parent,fixup); - parent->iterate_callstack_object(stack,call_frame_visitor,fixup); - break; - } - } +template +void code_block_visitor::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 call_frame_visitor(parent, fixup); + parent->iterate_callstack_object(stack, call_frame_visitor, fixup); + break; + } + } } -template -struct embedded_code_pointers_visitor { - Fixup fixup; +template 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 -void code_block_visitor::visit_embedded_code_pointers(code_block *compiled) -{ - if(!parent->code->uninitialized_p(compiled)) - { - embedded_code_pointers_visitor operand_visitor(fixup); - compiled->each_instruction_operand(operand_visitor); - } +template +void code_block_visitor::visit_embedded_code_pointers( + code_block* compiled) { + if (!parent->code->uninitialized_p(compiled)) { + embedded_code_pointers_visitor operand_visitor(fixup); + compiled->each_instruction_operand(operand_visitor); + } } -template -void code_block_visitor::visit_context_code_blocks() -{ - call_frame_code_block_visitor call_frame_visitor(parent,fixup); - parent->iterate_active_callstacks(call_frame_visitor,fixup); +template +void code_block_visitor::visit_context_code_blocks() { + call_frame_code_block_visitor call_frame_visitor(parent, fixup); + parent->iterate_active_callstacks(call_frame_visitor, fixup); } -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(); +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( - fixup.fixup_code(iter->first), - iter->second)); - } + std::map 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; + parent->code->uninitialized_blocks = new_uninitialized_blocks; } -template -void code_block_visitor::visit_code_roots() -{ - visit_uninitialized_code_blocks(); +template void code_block_visitor::visit_code_roots() { + visit_uninitialized_code_blocks(); } } diff --git a/vm/code_blocks.cpp b/vm/code_blocks.cpp index 2680741dd4..a4c6f6cee3 100644 --- a/vm/code_blocks.cpp +++ b/vm/code_blocks.cpp @@ -1,530 +1,495 @@ #include "master.hpp" -namespace factor -{ +namespace factor { -cell code_block::owner_quot() const -{ - tagged executing(owner); - if (!optimized_p() && executing->type() == WORD_TYPE) - executing = executing.as()->def; - return executing.value(); +cell code_block::owner_quot() const { + tagged executing(owner); + if (!optimized_p() && executing->type() == WORD_TYPE) + executing = executing.as()->def; + return executing.value(); } -cell code_block::scan(factor_vm *vm, void *addr) const -{ - switch(type()) - { - case code_block_unoptimized: - { - tagged obj(owner); - if(obj.type_p(WORD_TYPE)) - obj = obj.as()->def; +cell code_block::scan(factor_vm* vm, void* addr) const { + switch (type()) { + case code_block_unoptimized: { + tagged obj(owner); + if (obj.type_p(WORD_TYPE)) + obj = obj.as()->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; - } + 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(obj).type()) - { - case WORD_TYPE: - return (cell)untag(obj)->entry_point; - case QUOTATION_TYPE: - return (cell)untag(obj)->entry_point; - default: - critical_error("Expected word or quotation",obj); - return 0; - } +cell factor_vm::compute_entry_point_address(cell obj) { + switch (tagged(obj).type()) { + case WORD_TYPE: + return (cell) untag(obj)->entry_point; + case QUOTATION_TYPE: + return (cell) untag(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(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(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 w(w_); - return compute_entry_point_pic_address(w.untagged(),w->pic_def); +cell factor_vm::compute_entry_point_pic_address(cell w_) { + tagged 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 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 w(w_); + return compute_entry_point_pic_address(w.untagged(), w->pic_tail_def); } -cell factor_vm::code_block_owner(code_block *compiled) -{ - tagged owner(compiled->owner); +cell factor_vm::code_block_owner(code_block* compiled) { + tagged 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 quot(owner.as()); - tagged 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 quot(owner.as()); + tagged 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 word_wrapper(array_nth(elements.untagged(),0)); - return word_wrapper->object; - } - else - return compiled->owner; + tagged 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; + 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_) {} + 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; - } - } + 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); +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(library) : NULL); + dll* d = (to_boolean(library) ? untag(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; + 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(symbol).type()) - { - case BYTE_ARRAY_TYPE: - { - symbol_char *name = alien_offset(symbol); - void *sym = ffi_dlsym(d,name); + switch (tagged(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(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; + else + return (cell) undefined_symbol; + } + case ARRAY_TYPE: { + array* names = untag(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; - } + 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); +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(library) : NULL); + dll* d = (to_boolean(library) ? untag(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; + 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(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(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); + switch (tagged(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(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; - } + 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(compiled->parameters) : NULL); - cell index = op.index; +void factor_vm::store_external_address(instruction_operand op) { + code_block* compiled = op.compiled; + array* parameters = + (to_boolean(compiled->parameters) ? untag(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; + 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; + 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) {} + explicit initial_code_block_visitor(factor_vm* parent_, cell literals_) + : parent(parent_), literals(literals_), literal_index(0) {} - cell next_literal() - { - return array_nth(untag(literals),literal_index++); - } + cell next_literal() { + return array_nth(untag(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; - } - } + 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(); +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); + /* 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::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::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)); +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)); + /* 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); - } - } + /* 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; + 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 code(code_,this); - data_root labels(labels_,this); - data_root owner(owner_,this); - data_root relocation(relocation_,this); - data_root parameters(parameters_,this); - data_root literals(literals_,this); +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 code(code_, this); + data_root labels(labels_, this); + data_root owner(owner_, this); + data_root relocation(relocation_, this); + data_root parameters(parameters_, this); + data_root literals(literals_, this); - cell code_length = array_capacity(code.untagged()); - code_block *compiled = allot_code_block(code_length,type); + cell code_length = array_capacity(code.untagged()); + code_block* compiled = allot_code_block(code_length, type); - compiled->owner = owner.value(); + 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(); + /* 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(); + 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); + /* code */ + memcpy(compiled + 1, code.untagged() + 1, code_length); - /* fixup labels */ - if(to_boolean(labels.value())) - fixup_labels(labels.as().untagged(),compiled); + /* fixup labels */ + if (to_boolean(labels.value())) + fixup_labels(labels.as().untagged(), compiled); - compiled->set_stack_frame_size(frame_size_untagged); + 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); + /* 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); + /* 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; + 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; + 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) { } + 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(compiled->parameters); - cell index = op.index; - symbol = array_nth(parameters,index); - library = array_nth(parameters,index + 1); - } - } + void operator()(instruction_operand op) { + if (op.rel_type() == RT_DLSYM && op.pointer <= return_address) { + code_block* compiled = op.compiled; + array* parameters = untag(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(); } } diff --git a/vm/code_blocks.hpp b/vm/code_blocks.hpp index 4f67a19926..7bc89f4a4c 100644 --- a/vm/code_blocks.hpp +++ b/vm/code_blocks.hpp @@ -1,153 +1,117 @@ -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 */ +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; - } + bool free_p() const { return (header & 1) == 1; } - code_block_type type() const - { - return (code_block_type)((header >> 1) & 0x3); - } + code_block_type type() const { + return (code_block_type)((header >> 1) & 0x3); + } - void set_type(code_block_type type) - { - header = ((header & ~0x7) | (type << 1)); - } + void set_type(code_block_type type) { + header = ((header & ~0x7) | (type << 1)); + } - bool pic_p() const - { - return type() == code_block_pic; - } + bool pic_p() const { return type() == code_block_pic; } - bool optimized_p() const - { - return type() == code_block_optimized; - } + 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 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() 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; - } + 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); - } + 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 cell size(Fixup fixup) const - { - return size(); - } + template cell size(Fixup fixup) const { return size(); } - void *entry_point() const - { - return (void *)(this + 1); - } + 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)); - } + /* 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()); - } + void flush_icache() { factor::flush_icache((cell) this, size()); } - template void each_instruction_operand(Iterator &iter) - { - if(to_boolean(relocation)) - { - byte_array *rels = (byte_array *)UNTAG(relocation); + template 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); + cell index = 0; + cell length = (rels->capacity >> TAG_BITS) / sizeof(relocation_entry); - for(cell i = 0; i < length; i++) - { - relocation_entry rel = rels->data()[i]; - iter(instruction_operand(rel,this,index)); - index += rel.number_of_parameters(); - } - } - } + for (cell i = 0; i < length; i++) { + relocation_entry rel = rels->data()[i]; + iter(instruction_operand(rel, this, index)); + index += rel.number_of_parameters(); + } + } + } - cell offset(void *addr) const - { - return (char*)addr - (char*)entry_point(); - } + cell offset(void* addr) const { return (char*)addr - (char*)entry_point(); } - void *address_for_offset(cell offset) const - { - return (void*)((char*)entry_point() + offset); - } + 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; + 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_block* word::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_block* quotation::code() const { + FACTOR_ASSERT(entry_point != NULL); + return (code_block*)entry_point - 1; } } - -