]> gitweb.factorcode.org Git - factor.git/blobdiff - vm/code_heap.cpp
vm: strip out call-counting profiler
[factor.git] / vm / code_heap.cpp
index 44a7a54dfa8f0ae51b7517161e90d33673987964..f46891f7b8268164f0de1a331df12f2e267469b8 100755 (executable)
@@ -5,10 +5,17 @@ namespace factor
 
 code_heap::code_heap(cell size)
 {
-       if(size > (1L << (sizeof(cell) * 8 - 6))) fatal_error("Heap too large",size);
+       if(size > ((u64)1 << (sizeof(cell) * 8 - 6))) fatal_error("Heap too large",size);
        seg = new segment(align_page(size),true);
-       if(!seg) fatal_error("Out of memory in heap allocator",size);
-       allocator = new free_list_allocator<code_block>(size,seg->start);
+       if(!seg) fatal_error("Out of memory in code_heap constructor",size);
+
+       cell start = seg->start + getpagesize() + seh_area_size;
+
+       allocator = new free_list_allocator<code_block>(seg->end - start,start);
+
+       /* See os-windows-x86.64.cpp for seh_area usage */
+       safepoint_page = (void *)seg->start;
+       seh_area = (char *)seg->start + getpagesize();
 }
 
 code_heap::~code_heap()
@@ -31,9 +38,9 @@ void code_heap::clear_remembered_set()
        points_to_aging.clear();
 }
 
-bool code_heap::needs_fixup_p(code_block *compiled)
+bool code_heap::uninitialized_p(code_block *compiled)
 {
-       return needs_fixup.count(compiled) > 0;
+       return uninitialized_blocks.count(compiled) > 0;
 }
 
 bool code_heap::marked_p(code_block *compiled)
@@ -51,99 +58,90 @@ void code_heap::clear_mark_bits()
        allocator->state.clear_mark_bits();
 }
 
-void code_heap::code_heap_free(code_block *compiled)
+void code_heap::free(code_block *compiled)
 {
+       assert(!uninitialized_p(compiled));
        points_to_nursery.erase(compiled);
        points_to_aging.erase(compiled);
-       needs_fixup.erase(compiled);
        allocator->free(compiled);
 }
 
-/* Allocate a code heap during startup */
-void factor_vm::init_code_heap(cell size)
+void code_heap::flush_icache()
 {
-       code = new code_heap(size);
-}
-
-bool factor_vm::in_code_heap_p(cell ptr)
-{
-       return (ptr >= code->seg->start && ptr <= code->seg->end);
-}
-
-/* Compile a word definition with the non-optimizing compiler. Allocates memory */
-void factor_vm::jit_compile_word(cell word_, cell def_, bool relocate)
-{
-       data_root<word> word(word_,this);
-       data_root<quotation> def(def_,this);
-
-       jit_compile(def.value(),relocate);
-
-       word->code = def->code;
-
-       if(to_boolean(word->pic_def)) jit_compile(word->pic_def,relocate);
-       if(to_boolean(word->pic_tail_def)) jit_compile(word->pic_tail_def,relocate);
+       factor::flush_icache(seg->start,seg->size);
 }
 
-struct word_updater {
-       factor_vm *parent;
+struct address_finder {
+       cell address;
+       code_block *found_code_block;
 
-       explicit word_updater(factor_vm *parent_) : parent(parent_) {}
+       address_finder(cell address)
+               : address(address), found_code_block(NULL) {}
 
-       void operator()(code_block *compiled, cell size)
+       void operator()(code_block *block, cell size)
        {
-               parent->update_word_references(compiled);
+               if ((cell)block->entry_point() <= address
+                       && address - (cell)block->entry_point() < block->size())
+               {
+                       assert(found_code_block == NULL);
+                       found_code_block = block;
+               }
        }
 };
 
-/* Update pointers to words referenced from all code blocks. Only after
-defining a new word. */
-void factor_vm::update_code_heap_words()
+code_block *code_heap::code_block_for_address(cell address)
 {
-       word_updater updater(this);
-       iterate_code_heap(updater);
+       address_finder finder(address);
+       allocator->iterate(finder);
+       return finder.found_code_block;
 }
 
-/* After a full GC that did not grow the heap, we have to update references
-to literals and other words. */
-struct word_and_literal_code_heap_updater {
+/* Allocate a code heap during startup */
+void factor_vm::init_code_heap(cell size)
+{
+       code = new code_heap(size);
+}
+
+struct word_updater {
        factor_vm *parent;
+       bool reset_inline_caches;
 
-       explicit word_and_literal_code_heap_updater(factor_vm *parent_) : parent(parent_) {}
+       word_updater(factor_vm *parent_, bool reset_inline_caches_) :
+               parent(parent_), reset_inline_caches(reset_inline_caches_) {}
 
-       void operator()(code_block *block, cell size)
+       void operator()(code_block *compiled, cell size)
        {
-               parent->update_code_block_words_and_literals(block);
+               parent->update_word_references(compiled,reset_inline_caches);
        }
 };
 
-void factor_vm::update_code_heap_words_and_literals()
+/* Update pointers to words referenced from all code blocks.
+Only needed after redefining an existing word.
+If generic words were redefined, inline caches need to be reset. */
+void factor_vm::update_code_heap_words(bool reset_inline_caches)
 {
-       word_and_literal_code_heap_updater updater(this);
-       iterate_code_heap(updater);
+       word_updater updater(this,reset_inline_caches);
+       each_code_block(updater);
 }
 
-/* After growing the heap, we have to perform a full relocation to update
-references to card and deck arrays. */
-struct code_heap_relocator {
-       factor_vm *parent;
+/* Fix up new words only.
+Fast path for compilation units that only define new words. */
+void factor_vm::initialize_code_blocks()
+{
+       std::map<code_block *, cell>::const_iterator iter = code->uninitialized_blocks.begin();
+       std::map<code_block *, cell>::const_iterator end = code->uninitialized_blocks.end();
 
-       explicit code_heap_relocator(factor_vm *parent_) : parent(parent_) {}
+       for(; iter != end; iter++)
+               initialize_code_block(iter->first,iter->second);
 
-       void operator()(code_block *block, cell size)
-       {
-               parent->relocate_code_block(block);
-       }
-};
-
-void factor_vm::relocate_code_heap()
-{
-       code_heap_relocator relocator(this);
-       code->allocator->sweep(relocator);
+       code->uninitialized_blocks.clear();
 }
 
 void factor_vm::primitive_modify_code_heap()
 {
-       data_root<array> alist(dpop(),this);
+       bool reset_inline_caches = to_boolean(ctx->pop());
+       bool update_existing_words = to_boolean(ctx->pop());
+       data_root<array> alist(ctx->pop(),this);
 
        cell count = array_capacity(alist.untagged());
 
@@ -165,7 +163,7 @@ void factor_vm::primitive_modify_code_heap()
                case ARRAY_TYPE:
                        {
                                array *compiled_data = data.as<array>().untagged();
-                               cell owner = array_nth(compiled_data,0);
+                               cell parameters = array_nth(compiled_data,0);
                                cell literals = array_nth(compiled_data,1);
                                cell relocation = array_nth(compiled_data,2);
                                cell labels = array_nth(compiled_data,3);
@@ -175,22 +173,24 @@ void factor_vm::primitive_modify_code_heap()
                                        code_block_optimized,
                                        code,
                                        labels,
-                                       owner,
+                                       word.value(),
                                        relocation,
+                                       parameters,
                                        literals);
 
-                               word->code = compiled;
+                               word->entry_point = compiled->entry_point();
                        }
                        break;
                default:
                        critical_error("Expected a quotation or an array",data.value());
                        break;
                }
-
-               update_word_xt(word.untagged());
        }
 
-       update_code_heap_words();
+       if(update_existing_words)
+               update_code_heap_words(reset_inline_caches);
+       else
+               initialize_code_blocks();
 }
 
 code_heap_room factor_vm::code_room()
@@ -209,7 +209,7 @@ code_heap_room factor_vm::code_room()
 void factor_vm::primitive_code_room()
 {
        code_heap_room room = code_room();
-       dpush(tag<byte_array>(byte_array_from_value(&room)));
+       ctx->push(tag<byte_array>(byte_array_from_value(&room)));
 }
 
 struct stack_trace_stripper {
@@ -224,7 +224,44 @@ struct stack_trace_stripper {
 void factor_vm::primitive_strip_stack_traces()
 {
        stack_trace_stripper stripper;
-       iterate_code_heap(stripper);
+       each_code_block(stripper);
+}
+
+struct code_block_accumulator {
+       std::vector<cell> objects;
+
+       void operator()(code_block *compiled, cell size)
+       {
+               objects.push_back(compiled->owner);
+               objects.push_back(compiled->parameters);
+               objects.push_back(compiled->relocation);
+
+               objects.push_back(tag_fixnum(compiled->type()));
+               objects.push_back(tag_fixnum(compiled->size()));
+
+               /* Note: the entry point is always a multiple of the heap
+               alignment (16 bytes). We cannot allocate while iterating
+               through the code heap, so it is not possible to call
+               from_unsigned_cell() here. It is OK, however, to add it as
+               if it were a fixnum, and have library code shift it to the
+               left by 4. */
+               cell entry_point = (cell)compiled->entry_point();
+               assert((entry_point & (data_alignment - 1)) == 0);
+               assert((entry_point & TAG_MASK) == FIXNUM_TYPE);
+               objects.push_back(entry_point);
+       }
+};
+
+cell factor_vm::code_blocks()
+{
+       code_block_accumulator accum;
+       each_code_block(accum);
+       return std_vector_to_array(accum.objects);
+}
+
+void factor_vm::primitive_code_blocks()
+{
+       ctx->push(code_blocks());
 }
 
 }