]> gitweb.factorcode.org Git - factor.git/blobdiff - vm/code_heap.cpp
webapps.wiki: adding search bar
[factor.git] / vm / code_heap.cpp
old mode 100755 (executable)
new mode 100644 (file)
index 1d978f2..77aa7ae
 #include "master.hpp"
 
-namespace factor
-{
+namespace factor {
 
-code_heap::code_heap(cell 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 code_heap constructor",size);
+code_heap::code_heap(cell size) {
+  if (size > ((uint64_t)1 << (sizeof(cell) * 8 - 5)))
+    fatal_error("Heap too large", size);
+  seg = new segment(align_page(size), true);
+  if (!seg)
+    fatal_error("Out of memory in code_heap constructor", size);
 
-       cell start = seg->start + getpagesize() + seh_area_size;
+  cell start = seg->start + getpagesize() + seh_area_size;
 
-       allocator = new free_list_allocator<code_block>(seg->end - start,start);
+  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();
+  // See os-windows-x86.64.cpp for seh_area usage
+  safepoint_page = seg->start;
+  seh_area = (char*)seg->start + getpagesize();
 }
 
-code_heap::~code_heap()
-{
-       delete allocator;
-       allocator = NULL;
-       delete seg;
-       seg = NULL;
+code_heap::~code_heap() {
+  delete allocator;
+  allocator = NULL;
+  delete seg;
+  seg = NULL;
 }
 
-void code_heap::write_barrier(code_block *compiled)
-{
-       points_to_nursery.insert(compiled);
-       points_to_aging.insert(compiled);
-}
-
-void code_heap::clear_remembered_set()
-{
-       points_to_nursery.clear();
-       points_to_aging.clear();
-}
-
-bool code_heap::uninitialized_p(code_block *compiled)
-{
-       return uninitialized_blocks.count(compiled) > 0;
-}
-
-bool code_heap::marked_p(code_block *compiled)
-{
-       return allocator->state.marked_p(compiled);
-}
+void code_heap::write_barrier(code_block* compiled) {
+  points_to_nursery.insert(compiled);
+  points_to_aging.insert(compiled);
+}
 
-void code_heap::set_marked_p(code_block *compiled)
-{
-       allocator->state.set_marked_p(compiled);
+void code_heap::clear_remembered_set() {
+  points_to_nursery.clear();
+  points_to_aging.clear();
 }
 
-void code_heap::clear_mark_bits()
-{
-       allocator->state.clear_mark_bits();
+bool code_heap::uninitialized_p(code_block* compiled) {
+  return uninitialized_blocks.count(compiled) > 0;
 }
 
-void code_heap::free(code_block *compiled)
-{
-       assert(!uninitialized_p(compiled));
-       points_to_nursery.erase(compiled);
-       points_to_aging.erase(compiled);
-       allocator->free(compiled);
+void code_heap::free(code_block* compiled) {
+  FACTOR_ASSERT(!uninitialized_p(compiled));
+  points_to_nursery.erase(compiled);
+  points_to_aging.erase(compiled);
+  all_blocks.erase((cell)compiled);
+  allocator->free(compiled);
 }
 
-void code_heap::flush_icache()
-{
-       factor::flush_icache(seg->start,seg->size);
-}
-
-/* Allocate a code heap during startup */
-void factor_vm::init_code_heap(cell size)
-{
-       code = new code_heap(size);
-}
-
-bool factor_vm::in_code_heap_p(cell ptr)
-{
-       return (ptr >= code->seg->start && ptr <= code->seg->end);
-}
-
-struct word_updater {
-       factor_vm *parent;
-       bool reset_inline_caches;
-
-       word_updater(factor_vm *parent_, bool reset_inline_caches_) :
-               parent(parent_), reset_inline_caches(reset_inline_caches_) {}
-
-       void operator()(code_block *compiled, cell size)
-       {
-               parent->update_word_references(compiled,reset_inline_caches);
-       }
-};
-
-/* 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_updater updater(this,reset_inline_caches);
-       each_code_block(updater);
-}
-
-/* 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();
-
-       for(; iter != end; iter++)
-               initialize_code_block(iter->first,iter->second);
-
-       code->uninitialized_blocks.clear();
-}
-
-void factor_vm::primitive_modify_code_heap()
-{
-       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());
-
-       if(count == 0)
-               return;
-
-       for(cell i = 0; i < count; i++)
-       {
-               data_root<array> pair(array_nth(alist.untagged(),i),this);
-
-               data_root<word> word(array_nth(pair.untagged(),0),this);
-               data_root<object> data(array_nth(pair.untagged(),1),this);
-
-               switch(data.type())
-               {
-               case QUOTATION_TYPE:
-                       jit_compile_word(word.value(),data.value(),false);
-                       break;
-               case ARRAY_TYPE:
-                       {
-                               array *compiled_data = data.as<array>().untagged();
-                               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);
-                               cell code = array_nth(compiled_data,4);
-
-                               code_block *compiled = add_code_block(
-                                       code_block_optimized,
-                                       code,
-                                       labels,
-                                       word.value(),
-                                       relocation,
-                                       parameters,
-                                       literals);
-
-                               word->code = compiled;
-                       }
-                       break;
-               default:
-                       critical_error("Expected a quotation or an array",data.value());
-                       break;
-               }
-
-               update_word_entry_point(word.untagged());
-       }
-
-       if(update_existing_words)
-               update_code_heap_words(reset_inline_caches);
-       else
-               initialize_code_blocks();
-}
-
-code_heap_room factor_vm::code_room()
-{
-       code_heap_room room;
-
-       room.size             = code->allocator->size;
-       room.occupied_space   = code->allocator->occupied_space();
-       room.total_free       = code->allocator->free_space();
-       room.contiguous_free  = code->allocator->largest_free_block();
-       room.free_block_count = code->allocator->free_block_count();
-
-       return room;
-}
-
-void factor_vm::primitive_code_room()
-{
-       code_heap_room room = code_room();
-       ctx->push(tag<byte_array>(byte_array_from_value(&room)));
-}
-
-struct stack_trace_stripper {
-       explicit stack_trace_stripper() {}
-
-       void operator()(code_block *compiled, cell size)
-       {
-               compiled->owner = false_object;
-       }
-};
-
-void factor_vm::primitive_strip_stack_traces()
-{
-       stack_trace_stripper 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());
+void code_heap::flush_icache() { factor::flush_icache(seg->start, seg->size); }
+
+void code_heap::set_safepoint_guard(bool locked) {
+  if (!set_memory_locked(safepoint_page, getpagesize(), locked)) {
+    fatal_error("Cannot (un)protect safepoint guard page", safepoint_page);
+  }
+}
+
+void code_heap::sweep() {
+  auto clear_free_blocks_from_all_blocks = [&](code_block* block, cell size) {
+    std::set<cell>::iterator erase_from =
+      all_blocks.lower_bound((cell)block);
+    std::set<cell>::iterator erase_to =
+      all_blocks.lower_bound((cell)block + size);
+    all_blocks.erase(erase_from, erase_to);
+  };
+  allocator->sweep(clear_free_blocks_from_all_blocks);
+#ifdef FACTOR_DEBUG
+  verify_all_blocks_set();
+#endif
+}
+
+void code_heap::verify_all_blocks_set() {
+  auto all_blocks_set_verifier = [&](code_block* block, cell size) {
+    (void)block;
+    (void)size;
+    FACTOR_ASSERT(all_blocks.find((cell)block) != all_blocks.end());
+  };
+  allocator->iterate(all_blocks_set_verifier, no_fixup());
+}
+
+code_block* code_heap::code_block_for_address(cell address) {
+  std::set<cell>::const_iterator blocki = all_blocks.upper_bound(address);
+  FACTOR_ASSERT(blocki != all_blocks.begin());
+  --blocki;
+  code_block* found_block = (code_block*)*blocki;
+  FACTOR_ASSERT(found_block->entry_point() <=
+                address // XXX this isn't valid during fixup. should store the
+                        //     size in the map
+                        //    && address - found_block->entry_point() <
+                        //       found_block->size()
+                );
+  return found_block;
+}
+
+cell code_heap::frame_predecessor(cell frame_top) {
+  cell addr = *(cell*)frame_top;
+  FACTOR_ASSERT(seg->in_segment_p(addr));
+  code_block* owner = code_block_for_address(addr);
+  cell frame_size = owner->stack_frame_size_for_address(addr);
+  return frame_top + frame_size;
+}
+
+// Recomputes the all_blocks set of code blocks
+void code_heap::initialize_all_blocks_set() {
+  all_blocks.clear();
+  auto all_blocks_set_inserter = [&](code_block* block, cell size) {
+    (void)size;
+    all_blocks.insert((cell)block);
+  };
+  allocator->iterate(all_blocks_set_inserter, no_fixup());
+#ifdef FACTOR_DEBUG
+  verify_all_blocks_set();
+#endif
+}
+
+// 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) {
+  auto word_updater = [&](code_block* block, cell size) {
+    (void)size;
+    update_word_references(block, reset_inline_caches);
+  };
+  each_code_block(word_updater);
+}
+
+// Allocates memory
+void factor_vm::primitive_modify_code_heap() {
+  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());
+
+  if (count == 0)
+    return;
+
+  for (cell i = 0; i < count; i++) {
+    data_root<array> pair(array_nth(alist.untagged(), i), this);
+
+    data_root<word> word(array_nth(pair.untagged(), 0), this);
+    data_root<object> data(array_nth(pair.untagged(), 1), this);
+
+    switch (data.type()) {
+      case QUOTATION_TYPE:
+        jit_compile_word(word.value(), data.value(), false);
+        break;
+      case ARRAY_TYPE: {
+        array* compiled_data = data.as<array>().untagged();
+        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);
+        cell code = array_nth(compiled_data, 4);
+        cell frame_size = untag_fixnum(array_nth(compiled_data, 5));
+
+        code_block* compiled =
+            add_code_block(CODE_BLOCK_OPTIMIZED, code, labels, word.value(),
+                           relocation, parameters, literals, frame_size);
+
+        word->entry_point = compiled->entry_point();
+      } break;
+      default:
+        critical_error("Expected a quotation or an array", data.value());
+        break;
+    }
+  }
+
+  if (update_existing_words)
+    update_code_heap_words(reset_inline_caches);
+  else {
+    // Fast path for compilation units that only define new words.
+    FACTOR_FOR_EACH(code->uninitialized_blocks) {
+      initialize_code_block(iter->first, iter->second);
+    }
+    code->uninitialized_blocks.clear();
+  }
+  FACTOR_ASSERT(code->uninitialized_blocks.size() == 0);
+}
+
+// Allocates memory
+void factor_vm::primitive_code_room() {
+  allocator_room room = code->allocator->as_allocator_room();
+  ctx->push(tag<byte_array>(byte_array_from_value(&room)));
+}
+
+void factor_vm::primitive_strip_stack_traces() {
+  auto stack_trace_stripper = [](code_block* block, cell size) {
+    (void)size;
+    block->owner = false_object;
+  };
+  each_code_block(stack_trace_stripper);
+}
+
+// Allocates memory
+void factor_vm::primitive_code_blocks() {
+  std::vector<cell> objects;
+  auto code_block_accumulator = [&](code_block* block, cell size) {
+    (void)size;
+    objects.push_back(block->owner);
+    objects.push_back(block->parameters);
+    objects.push_back(block->relocation);
+
+    objects.push_back(tag_fixnum(block->type()));
+    objects.push_back(tag_fixnum(block->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 = block->entry_point();
+    FACTOR_ASSERT((entry_point & (data_alignment - 1)) == 0);
+    FACTOR_ASSERT((entry_point & TAG_MASK) == FIXNUM_TYPE);
+    objects.push_back(entry_point);
+  };
+  each_code_block(code_block_accumulator);
+  ctx->push(std_vector_to_array(objects));
 }
 
 }