VM: Refactor code_heap to Factor style

db4
Erik Charlebois 2013-05-11 21:51:54 -04:00
parent d2fe86eb7e
commit 7f56458820
2 changed files with 224 additions and 268 deletions

View File

@ -1,95 +1,80 @@
#include "master.hpp" #include "master.hpp"
namespace factor namespace factor {
{
code_heap::code_heap(cell size) code_heap::code_heap(cell size) {
{ if (size > ((u64) 1 << (sizeof(cell) * 8 - 6)))
if(size > ((u64)1 << (sizeof(cell) * 8 - 6))) fatal_error("Heap too large",size); fatal_error("Heap too large", size);
seg = new segment(align_page(size),true); seg = new segment(align_page(size), true);
if(!seg) fatal_error("Out of memory in code_heap constructor",size); 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 */ /* See os-windows-x86.64.cpp for seh_area usage */
safepoint_page = (void *)seg->start; safepoint_page = (void*)seg->start;
seh_area = (char *)seg->start + getpagesize(); seh_area = (char*)seg->start + getpagesize();
} }
code_heap::~code_heap() code_heap::~code_heap() {
{
delete allocator; delete allocator;
allocator = NULL; allocator = NULL;
delete seg; delete seg;
seg = NULL; seg = NULL;
} }
void code_heap::write_barrier(code_block *compiled) void code_heap::write_barrier(code_block* compiled) {
{
points_to_nursery.insert(compiled); points_to_nursery.insert(compiled);
points_to_aging.insert(compiled); points_to_aging.insert(compiled);
} }
void code_heap::clear_remembered_set() void code_heap::clear_remembered_set() {
{
points_to_nursery.clear(); points_to_nursery.clear();
points_to_aging.clear(); points_to_aging.clear();
} }
bool code_heap::uninitialized_p(code_block *compiled) bool code_heap::uninitialized_p(code_block* compiled) {
{
return uninitialized_blocks.count(compiled) > 0; return uninitialized_blocks.count(compiled) > 0;
} }
bool code_heap::marked_p(code_block *compiled) bool code_heap::marked_p(code_block* compiled) {
{
return allocator->state.marked_p(compiled); return allocator->state.marked_p(compiled);
} }
void code_heap::set_marked_p(code_block *compiled) void code_heap::set_marked_p(code_block* compiled) {
{
allocator->state.set_marked_p(compiled); allocator->state.set_marked_p(compiled);
} }
void code_heap::clear_mark_bits() void code_heap::clear_mark_bits() { allocator->state.clear_mark_bits(); }
{
allocator->state.clear_mark_bits();
}
void code_heap::free(code_block *compiled) void code_heap::free(code_block* compiled) {
{
FACTOR_ASSERT(!uninitialized_p(compiled)); FACTOR_ASSERT(!uninitialized_p(compiled));
points_to_nursery.erase(compiled); points_to_nursery.erase(compiled);
points_to_aging.erase(compiled); points_to_aging.erase(compiled);
all_blocks.erase((cell)compiled); all_blocks.erase((cell) compiled);
allocator->free(compiled); allocator->free(compiled);
} }
void code_heap::flush_icache() void code_heap::flush_icache() { factor::flush_icache(seg->start, seg->size); }
{
factor::flush_icache(seg->start,seg->size);
}
struct clear_free_blocks_from_all_blocks_iterator struct clear_free_blocks_from_all_blocks_iterator {
{ code_heap* code;
code_heap *code;
clear_free_blocks_from_all_blocks_iterator(code_heap *code) : code(code) {} clear_free_blocks_from_all_blocks_iterator(code_heap* code) : code(code) {}
void operator()(code_block *free_block, cell size) { void operator()(code_block* free_block, cell size) {
std::set<cell>::iterator erase_from = std::set<cell>::iterator erase_from =
code->all_blocks.lower_bound((cell)free_block); code->all_blocks.lower_bound((cell) free_block);
std::set<cell>::iterator erase_to = std::set<cell>::iterator erase_to =
code->all_blocks.lower_bound((cell)free_block + size); code->all_blocks.lower_bound((cell) free_block + size);
code->all_blocks.erase(erase_from, erase_to); code->all_blocks.erase(erase_from, erase_to);
} }
}; };
void code_heap::sweep() void code_heap::sweep() {
{
clear_free_blocks_from_all_blocks_iterator clearer(this); clear_free_blocks_from_all_blocks_iterator clearer(this);
allocator->sweep(clearer); allocator->sweep(clearer);
#ifdef FACTOR_DEBUG #ifdef FACTOR_DEBUG
@ -98,48 +83,45 @@ void code_heap::sweep()
} }
struct all_blocks_set_verifier { struct all_blocks_set_verifier {
std::set<cell> *all_blocks; std::set<cell>* all_blocks;
all_blocks_set_verifier(std::set<cell> *all_blocks) : all_blocks(all_blocks) {} all_blocks_set_verifier(std::set<cell>* all_blocks)
: all_blocks(all_blocks) {}
void operator()(code_block *block, cell size) void operator()(code_block* block, cell size) {
{ FACTOR_ASSERT(all_blocks->find((cell) block) != all_blocks->end());
FACTOR_ASSERT(all_blocks->find((cell)block) != all_blocks->end());
} }
}; };
void code_heap::verify_all_blocks_set() void code_heap::verify_all_blocks_set() {
{
all_blocks_set_verifier verifier(&all_blocks); all_blocks_set_verifier verifier(&all_blocks);
allocator->iterate(verifier); allocator->iterate(verifier);
} }
code_block *code_heap::code_block_for_address(cell address) code_block* code_heap::code_block_for_address(cell address) {
{ std::set<cell>::const_iterator blocki = all_blocks.upper_bound(address);
std::set<cell>::const_iterator blocki =
all_blocks.upper_bound(address);
FACTOR_ASSERT(blocki != all_blocks.begin()); FACTOR_ASSERT(blocki != all_blocks.begin());
--blocki; --blocki;
code_block* found_block = (code_block*)*blocki; code_block* found_block = (code_block*)*blocki;
FACTOR_ASSERT((cell)found_block->entry_point() <= address FACTOR_ASSERT((cell) found_block->entry_point() <=
/* XXX this isn't valid during fixup. should store the size in the map address /* XXX this isn't valid during fixup. should store the
&& address - (cell)found_block->entry_point() < found_block->size()*/); size in the map
&& address - (cell)found_block->entry_point() <
found_block->size()*/);
return found_block; return found_block;
} }
struct all_blocks_set_inserter { struct all_blocks_set_inserter {
code_heap *code; code_heap* code;
all_blocks_set_inserter(code_heap *code) : code(code) {} all_blocks_set_inserter(code_heap* code) : code(code) {}
void operator()(code_block *block, cell size) void operator()(code_block* block, cell size) {
{ code->all_blocks.insert((cell) block);
code->all_blocks.insert((cell)block);
} }
}; };
void code_heap::initialize_all_blocks_set() void code_heap::initialize_all_blocks_set() {
{
all_blocks.clear(); all_blocks.clear();
all_blocks_set_inserter inserter(this); all_blocks_set_inserter inserter(this);
allocator->iterate(inserter); allocator->iterate(inserter);
@ -149,107 +131,91 @@ void code_heap::initialize_all_blocks_set()
} }
/* Allocate a code heap during startup */ /* Allocate a code heap during startup */
void factor_vm::init_code_heap(cell size) void factor_vm::init_code_heap(cell size) { code = new code_heap(size); }
{
code = new code_heap(size);
}
struct word_updater { struct word_updater {
factor_vm *parent; factor_vm* parent;
bool reset_inline_caches; bool reset_inline_caches;
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_) {} : parent(parent_), reset_inline_caches(reset_inline_caches_) {}
void operator()(code_block *compiled, cell size) void operator()(code_block* compiled, cell size) {
{ parent->update_word_references(compiled, reset_inline_caches);
parent->update_word_references(compiled,reset_inline_caches);
} }
}; };
/* Update pointers to words referenced from all code blocks. /* Update pointers to words referenced from all code blocks.
Only needed after redefining an existing word. Only needed after redefining an existing word.
If generic words were redefined, inline caches need to be reset. */ If generic words were redefined, inline caches need to be reset. */
void factor_vm::update_code_heap_words(bool reset_inline_caches) void factor_vm::update_code_heap_words(bool reset_inline_caches) {
{ word_updater updater(this, reset_inline_caches);
word_updater updater(this,reset_inline_caches);
each_code_block(updater); each_code_block(updater);
} }
/* Fix up new words only. /* Fix up new words only.
Fast path for compilation units that only define new words. */ Fast path for compilation units that only define new words. */
void factor_vm::initialize_code_blocks() void factor_vm::initialize_code_blocks() {
{ std::map<code_block*, cell>::const_iterator iter =
std::map<code_block *, cell>::const_iterator iter = code->uninitialized_blocks.begin(); code->uninitialized_blocks.begin();
std::map<code_block *, cell>::const_iterator end = code->uninitialized_blocks.end(); std::map<code_block*, cell>::const_iterator end =
code->uninitialized_blocks.end();
for(; iter != end; iter++) for (; iter != end; iter++)
initialize_code_block(iter->first,iter->second); initialize_code_block(iter->first, iter->second);
code->uninitialized_blocks.clear(); code->uninitialized_blocks.clear();
} }
/* Allocates memory */ /* Allocates memory */
void factor_vm::primitive_modify_code_heap() void factor_vm::primitive_modify_code_heap() {
{
bool reset_inline_caches = to_boolean(ctx->pop()); bool reset_inline_caches = to_boolean(ctx->pop());
bool update_existing_words = to_boolean(ctx->pop()); bool update_existing_words = to_boolean(ctx->pop());
data_root<array> alist(ctx->pop(),this); data_root<array> alist(ctx->pop(), this);
cell count = array_capacity(alist.untagged()); cell count = array_capacity(alist.untagged());
if(count == 0) if (count == 0)
return; return;
for(cell i = 0; i < count; i++) for (cell i = 0; i < count; i++) {
{ data_root<array> pair(array_nth(alist.untagged(), i), this);
data_root<array> pair(array_nth(alist.untagged(),i),this);
data_root<word> word(array_nth(pair.untagged(),0),this); data_root<word> word(array_nth(pair.untagged(), 0), this);
data_root<object> data(array_nth(pair.untagged(),1),this); data_root<object> data(array_nth(pair.untagged(), 1), this);
switch(data.type()) switch (data.type()) {
{
case QUOTATION_TYPE: case QUOTATION_TYPE:
jit_compile_word(word.value(),data.value(),false); jit_compile_word(word.value(), data.value(), false);
break; break;
case ARRAY_TYPE: case ARRAY_TYPE: {
{ array* compiled_data = data.as<array>().untagged();
array *compiled_data = data.as<array>().untagged(); cell parameters = array_nth(compiled_data, 0);
cell parameters = array_nth(compiled_data,0); cell literals = array_nth(compiled_data, 1);
cell literals = array_nth(compiled_data,1); cell relocation = array_nth(compiled_data, 2);
cell relocation = array_nth(compiled_data,2); cell labels = array_nth(compiled_data, 3);
cell labels = array_nth(compiled_data,3); cell code = array_nth(compiled_data, 4);
cell code = array_nth(compiled_data,4); cell frame_size = untag_fixnum(array_nth(compiled_data, 5));
cell frame_size = untag_fixnum(array_nth(compiled_data,5));
code_block *compiled = add_code_block( code_block* compiled =
code_block_optimized, add_code_block(code_block_optimized, code, labels, word.value(),
code, relocation, parameters, literals, frame_size);
labels,
word.value(),
relocation,
parameters,
literals,
frame_size);
word->entry_point = compiled->entry_point(); word->entry_point = compiled->entry_point();
} } break;
break;
default: default:
critical_error("Expected a quotation or an array",data.value()); critical_error("Expected a quotation or an array", data.value());
break; break;
} }
} }
if(update_existing_words) if (update_existing_words)
update_code_heap_words(reset_inline_caches); update_code_heap_words(reset_inline_caches);
else else
initialize_code_blocks(); initialize_code_blocks();
} }
code_heap_room factor_vm::code_room() code_heap_room factor_vm::code_room() {
{
code_heap_room room; code_heap_room room;
room.size = code->allocator->size; room.size = code->allocator->size;
@ -262,8 +228,7 @@ code_heap_room factor_vm::code_room()
} }
/* Allocates memory */ /* Allocates memory */
void factor_vm::primitive_code_room() void factor_vm::primitive_code_room() {
{
code_heap_room room = code_room(); code_heap_room room = code_room();
ctx->push(tag<byte_array>(byte_array_from_value(&room))); ctx->push(tag<byte_array>(byte_array_from_value(&room)));
} }
@ -271,14 +236,12 @@ void factor_vm::primitive_code_room()
struct stack_trace_stripper { struct stack_trace_stripper {
explicit stack_trace_stripper() {} explicit stack_trace_stripper() {}
void operator()(code_block *compiled, cell size) void operator()(code_block* compiled, cell size) {
{
compiled->owner = false_object; compiled->owner = false_object;
} }
}; };
void factor_vm::primitive_strip_stack_traces() void factor_vm::primitive_strip_stack_traces() {
{
stack_trace_stripper stripper; stack_trace_stripper stripper;
each_code_block(stripper); each_code_block(stripper);
} }
@ -286,8 +249,7 @@ void factor_vm::primitive_strip_stack_traces()
struct code_block_accumulator { struct code_block_accumulator {
std::vector<cell> objects; std::vector<cell> objects;
void operator()(code_block *compiled, cell size) void operator()(code_block* compiled, cell size) {
{
objects.push_back(compiled->owner); objects.push_back(compiled->owner);
objects.push_back(compiled->parameters); objects.push_back(compiled->parameters);
objects.push_back(compiled->relocation); objects.push_back(compiled->relocation);
@ -301,7 +263,7 @@ struct code_block_accumulator {
from_unsigned_cell() here. It is OK, however, to add it as 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 if it were a fixnum, and have library code shift it to the
left by 4. */ left by 4. */
cell entry_point = (cell)compiled->entry_point(); cell entry_point = (cell) compiled->entry_point();
FACTOR_ASSERT((entry_point & (data_alignment - 1)) == 0); FACTOR_ASSERT((entry_point & (data_alignment - 1)) == 0);
FACTOR_ASSERT((entry_point & TAG_MASK) == FIXNUM_TYPE); FACTOR_ASSERT((entry_point & TAG_MASK) == FIXNUM_TYPE);
objects.push_back(entry_point); objects.push_back(entry_point);
@ -309,17 +271,13 @@ struct code_block_accumulator {
}; };
/* Allocates memory */ /* Allocates memory */
cell factor_vm::code_blocks() cell factor_vm::code_blocks() {
{
code_block_accumulator accum; code_block_accumulator accum;
each_code_block(accum); each_code_block(accum);
return std_vector_to_array(accum.objects); return std_vector_to_array(accum.objects);
} }
/* Allocates memory */ /* Allocates memory */
void factor_vm::primitive_code_blocks() void factor_vm::primitive_code_blocks() { ctx->push(code_blocks()); }
{
ctx->push(code_blocks());
}
} }

View File

@ -1,47 +1,46 @@
namespace factor namespace factor {
{
#if defined(WINDOWS) && defined(FACTOR_64) #if defined(WINDOWS) && defined(FACTOR_64)
const cell seh_area_size = 1024; const cell seh_area_size = 1024;
#else #else
const cell seh_area_size = 0; const cell seh_area_size = 0;
#endif #endif
struct code_heap { struct code_heap {
/* The actual memory area */ /* The actual memory area */
segment *seg; segment* seg;
/* Memory area reserved for safepoint guard page */ /* Memory area reserved for safepoint guard page */
void *safepoint_page; void* safepoint_page;
/* Memory area reserved for SEH. Only used on Windows */ /* Memory area reserved for SEH. Only used on Windows */
char *seh_area; char* seh_area;
/* Memory allocator */ /* Memory allocator */
free_list_allocator<code_block> *allocator; free_list_allocator<code_block>* allocator;
std::set<cell> all_blocks; std::set<cell> all_blocks;
/* Keys are blocks which need to be initialized by initialize_code_block(). /* Keys are blocks which need to be initialized by initialize_code_block().
Values are literal tables. Literal table arrays are GC roots until the Values are literal tables. Literal table arrays are GC roots until the
time the block is initialized, after which point they are discarded. */ time the block is initialized, after which point they are discarded. */
std::map<code_block *, cell> uninitialized_blocks; std::map<code_block*, cell> uninitialized_blocks;
/* Code blocks which may reference objects in the nursery */ /* Code blocks which may reference objects in the nursery */
std::set<code_block *> points_to_nursery; std::set<code_block*> points_to_nursery;
/* Code blocks which may reference objects in aging space or the nursery */ /* Code blocks which may reference objects in aging space or the nursery */
std::set<code_block *> points_to_aging; std::set<code_block*> points_to_aging;
explicit code_heap(cell size); explicit code_heap(cell size);
~code_heap(); ~code_heap();
void write_barrier(code_block *compiled); void write_barrier(code_block* compiled);
void clear_remembered_set(); void clear_remembered_set();
bool uninitialized_p(code_block *compiled); bool uninitialized_p(code_block* compiled);
bool marked_p(code_block *compiled); bool marked_p(code_block* compiled);
void set_marked_p(code_block *compiled); void set_marked_p(code_block* compiled);
void clear_mark_bits(); void clear_mark_bits();
void free(code_block *compiled); void free(code_block* compiled);
void flush_icache(); void flush_icache();
void guard_safepoint(); void guard_safepoint();
void unguard_safepoint(); void unguard_safepoint();
@ -50,12 +49,11 @@ struct code_heap {
void sweep(); void sweep();
code_block *code_block_for_address(cell address); code_block* code_block_for_address(cell address);
bool safepoint_p(cell addr) bool safepoint_p(cell addr) {
{
cell page_mask = ~(getpagesize() - 1); cell page_mask = ~(getpagesize() - 1);
return (addr & page_mask) == (cell)safepoint_page; return (addr & page_mask) == (cell) safepoint_page;
} }
}; };