vm: more code cleanups

db4
Slava Pestov 2009-10-07 08:33:54 -05:00
parent 1f76a64e91
commit 5c774d8c84
16 changed files with 201 additions and 187 deletions

View File

@ -3,12 +3,12 @@
namespace factor namespace factor
{ {
code_heap::code_heap(factor_vm *myvm, cell size) : heap(myvm,size) {} code_heap::code_heap(bool secure_gc, cell size) : heap(secure_gc,size) {}
void code_heap::write_barrier(code_block *compiled) void code_heap::write_barrier(code_block *compiled)
{ {
remembered_set[compiled] = myvm->data->nursery(); remembered_set[compiled] = nursery_gen;
youngest_referenced_generation = myvm->data->nursery(); youngest_referenced_generation = nursery_gen;
} }
bool code_heap::needs_fixup_p(code_block *compiled) bool code_heap::needs_fixup_p(code_block *compiled)
@ -26,7 +26,7 @@ void code_heap::code_heap_free(code_block *compiled)
/* 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(this,size); code = new code_heap(secure_gc,size);
} }
bool factor_vm::in_code_heap_p(cell ptr) bool factor_vm::in_code_heap_p(cell ptr)
@ -228,7 +228,7 @@ critical here */
void factor_vm::compact_code_heap() void factor_vm::compact_code_heap()
{ {
/* Free all unreachable code blocks, don't trace contexts */ /* Free all unreachable code blocks, don't trace contexts */
garbage_collection(data->tenured(),false,false,0); garbage_collection(tenured_gen,false,false,0);
/* Figure out where the code heap blocks are going to end up */ /* Figure out where the code heap blocks are going to end up */
cell size = code->compute_heap_forwarding(); cell size = code->compute_heap_forwarding();

View File

@ -13,7 +13,7 @@ struct code_heap : heap {
/* Minimum value in the above map. */ /* Minimum value in the above map. */
cell youngest_referenced_generation; cell youngest_referenced_generation;
explicit code_heap(factor_vm *myvm, cell size); explicit code_heap(bool secure_gc, cell size);
void write_barrier(code_block *compiled); void write_barrier(code_block *compiled);
bool needs_fixup_p(code_block *compiled); bool needs_fixup_p(code_block *compiled);
void code_heap_free(code_block *compiled); void code_heap_free(code_block *compiled);

View File

@ -44,8 +44,8 @@ context *factor_vm::alloc_context()
else else
{ {
new_context = new context; new_context = new context;
new_context->datastack_region = new segment(this,ds_size); new_context->datastack_region = new segment(ds_size);
new_context->retainstack_region = new segment(this,rs_size); new_context->retainstack_region = new segment(rs_size);
} }
return new_context; return new_context;

View File

@ -5,7 +5,7 @@ namespace factor
void factor_vm::init_data_gc() void factor_vm::init_data_gc()
{ {
code->youngest_referenced_generation = data->nursery(); code->youngest_referenced_generation = nursery_gen;
} }
gc_state::gc_state(data_heap *data_, bool growing_data_heap_, cell collecting_gen_) : gc_state::gc_state(data_heap *data_, bool growing_data_heap_, cell collecting_gen_) :
@ -71,7 +71,7 @@ template<typename Strategy> object *factor_vm::promote_object(object *untagged,
object *newpointer = strategy.allot(size); object *newpointer = strategy.allot(size);
if(!newpointer) longjmp(current_gc->gc_unwind,1); if(!newpointer) longjmp(current_gc->gc_unwind,1);
gc_stats *s = &stats[current_gc->collecting_gen]; generation_stats *s = &stats.generations[current_gc->collecting_gen];
s->object_count++; s->object_count++;
s->bytes_copied += size; s->bytes_copied += size;
@ -91,7 +91,7 @@ template<typename Strategy> void factor_vm::trace_card(card *ptr, cell gen, cell
strategy.copy_reachable_objects(card_scan,&card_end); strategy.copy_reachable_objects(card_scan,&card_end);
cards_scanned++; stats.cards_scanned++;
} }
template<typename Strategy> void factor_vm::trace_card_deck(card_deck *deck, cell gen, card mask, card unmask, Strategy &strategy) template<typename Strategy> void factor_vm::trace_card_deck(card_deck *deck, cell gen, card mask, card unmask, Strategy &strategy)
@ -122,7 +122,7 @@ template<typename Strategy> void factor_vm::trace_card_deck(card_deck *deck, cel
} }
} }
decks_scanned++; stats.decks_scanned++;
} }
/* Trace all objects referenced from marked cards */ /* Trace all objects referenced from marked cards */
@ -142,11 +142,11 @@ template<typename Strategy> void factor_vm::trace_generation_cards(cell gen, Str
/* after the collection, no old->nursery pointers remain /* after the collection, no old->nursery pointers remain
anywhere, but old->aging pointers might remain in tenured anywhere, but old->aging pointers might remain in tenured
space */ space */
if(gen == data->tenured()) if(gen == tenured_gen)
unmask = card_points_to_nursery; unmask = card_points_to_nursery;
/* after the collection, all cards in aging space can be /* after the collection, all cards in aging space can be
cleared */ cleared */
else if(gen == data->aging()) else if(gen == aging_gen)
unmask = card_mark_mask; unmask = card_mark_mask;
else else
{ {
@ -201,7 +201,7 @@ template<typename Strategy> void factor_vm::trace_cards(Strategy &strategy)
for(i = current_gc->collecting_gen + 1; i < gen_count; i++) for(i = current_gc->collecting_gen + 1; i < gen_count; i++)
trace_generation_cards(i,strategy); trace_generation_cards(i,strategy);
card_scan_time += (current_micros() - start); stats.card_scan_time += (current_micros() - start);
} }
/* Copy all tagged pointers in a range of memory */ /* Copy all tagged pointers in a range of memory */
@ -353,7 +353,7 @@ template<typename Strategy> void factor_vm::trace_code_heap_roots(Strategy &stra
trace_literal_references(iter->first,strategy); trace_literal_references(iter->first,strategy);
} }
code_heap_scans++; stats.code_heap_scans++;
} }
} }
@ -385,7 +385,7 @@ void factor_vm::free_unmarked_code_blocks()
literal_and_word_reference_updater updater(this); literal_and_word_reference_updater updater(this);
code->free_unmarked(updater); code->free_unmarked(updater);
code->remembered_set.clear(); code->remembered_set.clear();
code->youngest_referenced_generation = data->tenured(); code->youngest_referenced_generation = tenured_gen;
} }
void factor_vm::update_dirty_code_blocks() void factor_vm::update_dirty_code_blocks()
@ -429,7 +429,11 @@ template<typename Strategy> Strategy &copying_collector<Strategy>::strategy()
template<typename Strategy> object *copying_collector<Strategy>::allot(cell size) template<typename Strategy> object *copying_collector<Strategy>::allot(cell size)
{ {
if(newspace->here + size <= newspace->end) if(newspace->here + size <= newspace->end)
return myvm->allot_zone(newspace,size); {
object *obj = newspace->allot(size);
myvm->allot_barrier(obj);
return obj;
}
else else
return NULL; return NULL;
} }
@ -478,7 +482,7 @@ struct aging_collector : copying_collector<aging_collector>
explicit aging_collector(factor_vm *myvm_, zone *newspace_) : explicit aging_collector(factor_vm *myvm_, zone *newspace_) :
copying_collector<aging_collector>(myvm_,newspace_), copying_collector<aging_collector>(myvm_,newspace_),
tenured(&myvm->data->generations[myvm->data->tenured()]) {} tenured(&myvm->data->generations[tenured_gen]) {}
bool should_copy_p(object *untagged) bool should_copy_p(object *untagged)
{ {
@ -532,7 +536,7 @@ struct tenured_collector : copying_collector<tenured_collector>
void factor_vm::collect_nursery() void factor_vm::collect_nursery()
{ {
nursery_collector collector(this,&data->generations[data->aging()]); nursery_collector collector(this,&data->generations[aging_gen]);
trace_roots(collector); trace_roots(collector);
trace_contexts(collector); trace_contexts(collector);
@ -546,10 +550,10 @@ void factor_vm::collect_nursery()
void factor_vm::collect_aging() void factor_vm::collect_aging()
{ {
std::swap(data->generations[data->aging()],data->semispaces[data->aging()]); std::swap(data->generations[aging_gen],data->semispaces[aging_gen]);
reset_generation(data->aging()); reset_generation(aging_gen);
aging_collector collector(this,&data->generations[data->aging()]); aging_collector collector(this,&data->generations[aging_gen]);
trace_roots(collector); trace_roots(collector);
trace_contexts(collector); trace_contexts(collector);
@ -563,7 +567,7 @@ void factor_vm::collect_aging()
void factor_vm::collect_aging_again() void factor_vm::collect_aging_again()
{ {
aging_again_collector collector(this,&data->generations[data->tenured()]); aging_again_collector collector(this,&data->generations[tenured_gen]);
trace_roots(collector); trace_roots(collector);
trace_contexts(collector); trace_contexts(collector);
@ -572,7 +576,7 @@ void factor_vm::collect_aging_again()
collector.go(); collector.go();
update_dirty_code_blocks(); update_dirty_code_blocks();
reset_generation(data->aging()); reset_generation(aging_gen);
nursery.here = nursery.start; nursery.here = nursery.start;
} }
@ -585,18 +589,18 @@ void factor_vm::collect_tenured(cell requested_bytes, bool trace_contexts_)
} }
else else
{ {
std::swap(data->generations[data->tenured()],data->semispaces[data->tenured()]); std::swap(data->generations[tenured_gen],data->semispaces[tenured_gen]);
reset_generation(data->tenured()); reset_generation(tenured_gen);
} }
tenured_collector collector(this,&data->generations[data->tenured()]); tenured_collector collector(this,&data->generations[tenured_gen]);
trace_roots(collector); trace_roots(collector);
if(trace_contexts_) trace_contexts(collector); if(trace_contexts_) trace_contexts(collector);
collector.go(); collector.go();
free_unmarked_code_blocks(); free_unmarked_code_blocks();
reset_generation(data->aging()); reset_generation(aging_gen);
nursery.here = nursery.start; nursery.here = nursery.start;
if(current_gc->growing_data_heap) if(current_gc->growing_data_heap)
@ -605,7 +609,7 @@ void factor_vm::collect_tenured(cell requested_bytes, bool trace_contexts_)
void factor_vm::record_gc_stats() void factor_vm::record_gc_stats()
{ {
gc_stats *s = &stats[current_gc->collecting_gen]; generation_stats *s = &stats.generations[current_gc->collecting_gen];
cell gc_elapsed = (current_micros() - current_gc->start_time); cell gc_elapsed = (current_micros() - current_gc->start_time);
s->collections++; s->collections++;
@ -673,7 +677,7 @@ void factor_vm::garbage_collection(cell collecting_gen_, bool growing_data_heap_
void factor_vm::gc() void factor_vm::gc()
{ {
garbage_collection(data->tenured(),false,true,0); garbage_collection(tenured_gen,false,true,0);
} }
void factor_vm::primitive_gc() void factor_vm::primitive_gc()
@ -690,7 +694,7 @@ void factor_vm::primitive_gc_stats()
for(i = 0; i < gen_count; i++) for(i = 0; i < gen_count; i++)
{ {
gc_stats *s = &stats[i]; generation_stats *s = &stats.generations[i];
result.add(allot_cell(s->collections)); result.add(allot_cell(s->collections));
result.add(tag<bignum>(long_long_to_bignum(s->gc_time))); result.add(tag<bignum>(long_long_to_bignum(s->gc_time)));
result.add(tag<bignum>(long_long_to_bignum(s->max_gc_time))); result.add(tag<bignum>(long_long_to_bignum(s->max_gc_time)));
@ -702,10 +706,10 @@ void factor_vm::primitive_gc_stats()
} }
result.add(tag<bignum>(ulong_long_to_bignum(total_gc_time))); result.add(tag<bignum>(ulong_long_to_bignum(total_gc_time)));
result.add(tag<bignum>(ulong_long_to_bignum(cards_scanned))); result.add(tag<bignum>(ulong_long_to_bignum(stats.cards_scanned)));
result.add(tag<bignum>(ulong_long_to_bignum(decks_scanned))); result.add(tag<bignum>(ulong_long_to_bignum(stats.decks_scanned)));
result.add(tag<bignum>(ulong_long_to_bignum(card_scan_time))); result.add(tag<bignum>(ulong_long_to_bignum(stats.card_scan_time)));
result.add(allot_cell(code_heap_scans)); result.add(allot_cell(stats.code_heap_scans));
result.trim(); result.trim();
dpush(result.elements.value()); dpush(result.elements.value());
@ -713,13 +717,7 @@ void factor_vm::primitive_gc_stats()
void factor_vm::clear_gc_stats() void factor_vm::clear_gc_stats()
{ {
for(cell i = 0; i < gen_count; i++) memset(&stats,0,sizeof(gc_stats));
memset(&stats[i],0,sizeof(gc_stats));
cards_scanned = 0;
decks_scanned = 0;
card_scan_time = 0;
code_heap_scans = 0;
} }
void factor_vm::primitive_clear_gc_stats() void factor_vm::primitive_clear_gc_stats()
@ -763,7 +761,7 @@ void factor_vm::inline_gc(cell *gc_roots_base, cell gc_roots_size)
for(cell i = 0; i < gc_roots_size; i++) for(cell i = 0; i < gc_roots_size; i++)
gc_locals.push_back((cell)&gc_roots_base[i]); gc_locals.push_back((cell)&gc_roots_base[i]);
garbage_collection(data->nursery(),false,true,0); garbage_collection(nursery_gen,false,true,0);
for(cell i = 0; i < gc_roots_size; i++) for(cell i = 0; i < gc_roots_size; i++)
gc_locals.pop_back(); gc_locals.pop_back();
@ -775,15 +773,6 @@ VM_C_API void inline_gc(cell *gc_roots_base, cell gc_roots_size, factor_vm *myvm
VM_PTR->inline_gc(gc_roots_base,gc_roots_size); VM_PTR->inline_gc(gc_roots_base,gc_roots_size);
} }
inline object *factor_vm::allot_zone(zone *z, cell a)
{
cell h = z->here;
z->here = h + align8(a);
object *obj = (object *)h;
allot_barrier(obj);
return obj;
}
/* /*
* It is up to the caller to fill in the object's fields in a meaningful * It is up to the caller to fill in the object's fields in a meaningful
* fashion! * fashion!
@ -801,33 +790,32 @@ object *factor_vm::allot_object(header header, cell size)
{ {
/* If there is insufficient room, collect the nursery */ /* If there is insufficient room, collect the nursery */
if(nursery.here + size > nursery.end) if(nursery.here + size > nursery.end)
garbage_collection(data->nursery(),false,true,0); garbage_collection(nursery_gen,false,true,0);
cell h = nursery.here; obj = nursery.allot(size);
nursery.here = h + align8(size);
obj = (object *)h;
} }
/* If the object is bigger than the nursery, allocate it in /* If the object is bigger than the nursery, allocate it in
tenured space */ tenured space */
else else
{ {
zone *tenured = &data->generations[data->tenured()]; zone *tenured = &data->generations[tenured_gen];
/* If tenured space does not have enough room, collect */ /* If tenured space does not have enough room, collect */
if(tenured->here + size > tenured->end) if(tenured->here + size > tenured->end)
{ {
gc(); gc();
tenured = &data->generations[data->tenured()]; tenured = &data->generations[tenured_gen];
} }
/* If it still won't fit, grow the heap */ /* If it still won't fit, grow the heap */
if(tenured->here + size > tenured->end) if(tenured->here + size > tenured->end)
{ {
garbage_collection(data->tenured(),true,true,size); garbage_collection(tenured_gen,true,true,size);
tenured = &data->generations[data->tenured()]; tenured = &data->generations[tenured_gen];
} }
obj = allot_zone(tenured,size); obj = tenured->allot(size);
allot_barrier(obj);
/* Allows initialization code to store old->new pointers /* Allows initialization code to store old->new pointers
without hitting the write barrier in the common case of without hitting the write barrier in the common case of

View File

@ -2,7 +2,7 @@ namespace factor
{ {
/* statistics */ /* statistics */
struct gc_stats { struct generation_stats {
cell collections; cell collections;
u64 gc_time; u64 gc_time;
u64 max_gc_time; u64 max_gc_time;
@ -10,6 +10,14 @@ struct gc_stats {
u64 bytes_copied; u64 bytes_copied;
}; };
struct gc_stats {
generation_stats generations[gen_count];
u64 cards_scanned;
u64 decks_scanned;
u64 card_scan_time;
cell code_heap_scans;
};
struct gc_state { struct gc_state {
/* The data heap we're collecting */ /* The data heap we're collecting */
data_heap *data; data_heap *data;
@ -35,17 +43,17 @@ struct gc_state {
inline bool collecting_nursery_p() inline bool collecting_nursery_p()
{ {
return collecting_gen == data->nursery(); return collecting_gen == nursery_gen;
} }
inline bool collecting_aging_p() inline bool collecting_aging_p()
{ {
return collecting_gen == data->aging(); return collecting_gen == aging_gen;
} }
inline bool collecting_tenured_p() inline bool collecting_tenured_p()
{ {
return collecting_gen == data->tenured(); return collecting_gen == tenured_gen;
} }
inline bool collecting_accumulation_gen_p() inline bool collecting_accumulation_gen_p()

View File

@ -25,7 +25,7 @@ data_heap::data_heap(factor_vm *myvm, cell young_size_, cell aging_size_, cell t
total_size += deck_size; total_size += deck_size;
seg = new segment(myvm,total_size); seg = new segment(total_size);
generations = new zone[gen_count]; generations = new zone[gen_count];
semispaces = new zone[gen_count]; semispaces = new zone[gen_count];
@ -43,17 +43,17 @@ data_heap::data_heap(factor_vm *myvm, cell young_size_, cell aging_size_, cell t
cell alloter = align(seg->start,deck_size); cell alloter = align(seg->start,deck_size);
alloter = generations[tenured()].init_zone(tenured_size,alloter); alloter = generations[tenured_gen].init_zone(tenured_size,alloter);
alloter = semispaces[tenured()].init_zone(tenured_size,alloter); alloter = semispaces[tenured_gen].init_zone(tenured_size,alloter);
alloter = generations[aging()].init_zone(aging_size,alloter); alloter = generations[aging_gen].init_zone(aging_size,alloter);
alloter = semispaces[aging()].init_zone(aging_size,alloter); alloter = semispaces[aging_gen].init_zone(aging_size,alloter);
alloter = generations[nursery()].init_zone(young_size,alloter); alloter = generations[nursery_gen].init_zone(young_size,alloter);
alloter = semispaces[nursery()].init_zone(0,alloter); alloter = semispaces[nursery_gen].init_zone(0,alloter);
if(seg->end - alloter > deck_size) if(seg->end - alloter > deck_size)
myvm->critical_error("Bug in alloc_data_heap",alloter); critical_error("Bug in alloc_data_heap",alloter);
} }
data_heap *factor_vm::grow_data_heap(data_heap *data, cell requested_bytes) data_heap *factor_vm::grow_data_heap(data_heap *data, cell requested_bytes)
@ -103,7 +103,7 @@ void factor_vm::clear_allot_markers(cell gen)
their allocation pointers and cards reset. */ their allocation pointers and cards reset. */
void factor_vm::reset_generation(cell gen) void factor_vm::reset_generation(cell gen)
{ {
assert(gen != data->nursery()); assert(gen != nursery_gen);
zone *z = &data->generations[gen]; zone *z = &data->generations[gen];
z->here = z->start; z->here = z->start;
@ -117,11 +117,11 @@ void factor_vm::reset_generation(cell gen)
void factor_vm::set_data_heap(data_heap *data_) void factor_vm::set_data_heap(data_heap *data_)
{ {
data = data_; data = data_;
nursery = data->generations[data->nursery()]; nursery = data->generations[nursery_gen];
nursery.here = nursery.start; nursery.here = nursery.start;
init_card_decks(); init_card_decks();
reset_generation(data->aging()); reset_generation(aging_gen);
reset_generation(data->tenured()); reset_generation(tenured_gen);
} }
void factor_vm::init_data_heap(cell young_size, cell aging_size, cell tenured_size, bool secure_gc_) void factor_vm::init_data_heap(cell young_size, cell aging_size, cell tenured_size, bool secure_gc_)
@ -234,7 +234,7 @@ void factor_vm::primitive_data_room()
cell gen; cell gen;
for(gen = 0; gen < gen_count; gen++) for(gen = 0; gen < gen_count; gen++)
{ {
zone *z = (gen == data->nursery() ? &nursery : &data->generations[gen]); zone *z = (gen == nursery_gen ? &nursery : &data->generations[gen]);
a.add(tag_fixnum((z->end - z->here) >> 10)); a.add(tag_fixnum((z->end - z->here) >> 10));
a.add(tag_fixnum((z->size) >> 10)); a.add(tag_fixnum((z->size) >> 10));
} }
@ -246,7 +246,7 @@ void factor_vm::primitive_data_room()
/* Disables GC and activates next-object ( -- obj ) primitive */ /* Disables GC and activates next-object ( -- obj ) primitive */
void factor_vm::begin_scan() void factor_vm::begin_scan()
{ {
heap_scan_ptr = data->generations[data->tenured()].start; heap_scan_ptr = data->generations[tenured_gen].start;
gc_off = true; gc_off = true;
} }
@ -265,7 +265,7 @@ cell factor_vm::next_object()
if(!gc_off) if(!gc_off)
general_error(ERROR_HEAP_SCAN,F,F,NULL); general_error(ERROR_HEAP_SCAN,F,F,NULL);
if(heap_scan_ptr >= data->generations[data->tenured()].here) if(heap_scan_ptr >= data->generations[tenured_gen].here)
return F; return F;
object *obj = (object *)heap_scan_ptr; object *obj = (object *)heap_scan_ptr;

View File

@ -22,6 +22,13 @@ struct zone {
{ {
return ((cell)pointer - start) < size; return ((cell)pointer - start) < size;
} }
inline object *allot(cell size)
{
cell h = here;
here = h + align8(size);
return (object *)h;
}
}; };
struct data_heap { struct data_heap {
@ -43,19 +50,13 @@ struct data_heap {
char *decks; char *decks;
char *decks_end; char *decks_end;
/* the 0th generation is where new objects are allocated. */
cell nursery() { return 0; }
/* where objects hang around */
cell aging() { return 1; }
/* the oldest generation */
cell tenured() { return 2; }
explicit data_heap(factor_vm *myvm, cell young_size, cell aging_size, cell tenured_size); explicit data_heap(factor_vm *myvm, cell young_size, cell aging_size, cell tenured_size);
~data_heap(); ~data_heap();
}; };
static const cell nursery_gen = 0;
static const cell aging_gen = 1;
static const cell tenured_gen = 2;
static const cell gen_count = 3; static const cell gen_count = 3;
} }

View File

@ -3,13 +3,6 @@
namespace factor namespace factor
{ {
void factor_vm::out_of_memory()
{
print_string("Out of memory\n\n");
dump_generations();
exit(1);
}
void fatal_error(const char *msg, cell tagged) void fatal_error(const char *msg, cell tagged)
{ {
print_string("fatal_error: "); print_string(msg); print_string("fatal_error: "); print_string(msg);
@ -17,12 +10,19 @@ void fatal_error(const char* msg, cell tagged)
exit(1); exit(1);
} }
void factor_vm::critical_error(const char* msg, cell tagged) void critical_error(const char *msg, cell tagged)
{ {
print_string("You have triggered a bug in Factor. Please report.\n"); print_string("You have triggered a bug in Factor. Please report.\n");
print_string("critical_error: "); print_string(msg); print_string("critical_error: "); print_string(msg);
print_string(": "); print_cell_hex(tagged); nl(); print_string(": "); print_cell_hex(tagged); nl();
factorbug(); SIGNAL_VM_PTR()->factorbug();
}
void out_of_memory()
{
print_string("Out of memory\n\n");
SIGNAL_VM_PTR()->dump_generations();
exit(1);
} }
void factor_vm::throw_error(cell error, stack_frame *callstack_top) void factor_vm::throw_error(cell error, stack_frame *callstack_top)

View File

@ -24,6 +24,8 @@ enum vm_error_type
}; };
void fatal_error(const char *msg, cell tagged); void fatal_error(const char *msg, cell tagged);
void critical_error(const char *msg, cell tagged);
void out_of_memory();
void memory_signal_handler_impl(); void memory_signal_handler_impl();
void fp_signal_handler_impl(); void fp_signal_handler_impl();
void misc_signal_handler_impl(); void misc_signal_handler_impl();

View File

@ -11,10 +11,9 @@ void heap::clear_free_list()
memset(&free,0,sizeof(heap_free_list)); memset(&free,0,sizeof(heap_free_list));
} }
heap::heap(factor_vm *myvm_, cell size) heap::heap(bool secure_gc_, cell size) : secure_gc(secure_gc_)
{ {
myvm = myvm_; seg = new segment(align_page(size));
seg = new segment(myvm,align_page(size));
if(!seg) fatal_error("Out of memory in new_heap",size); if(!seg) fatal_error("Out of memory in new_heap",size);
clear_free_list(); clear_free_list();
} }
@ -85,7 +84,7 @@ void heap::build_free_list(cell size)
void heap::assert_free_block(free_heap_block *block) void heap::assert_free_block(free_heap_block *block)
{ {
if(block->type() != FREE_BLOCK_TYPE) if(block->type() != FREE_BLOCK_TYPE)
myvm->critical_error("Invalid block in free list",(cell)block); critical_error("Invalid block in free list",(cell)block);
} }
free_heap_block *heap::find_free_block(cell size) free_heap_block *heap::find_free_block(cell size)
@ -263,7 +262,7 @@ void heap::compact_heap()
heap_block *heap::free_allocated(heap_block *prev, heap_block *scan) heap_block *heap::free_allocated(heap_block *prev, heap_block *scan)
{ {
if(myvm->secure_gc) if(secure_gc)
memset(scan + 1,0,scan->size() - sizeof(heap_block)); memset(scan + 1,0,scan->size() - sizeof(heap_block));
if(prev && prev->type() == FREE_BLOCK_TYPE) if(prev && prev->type() == FREE_BLOCK_TYPE)

View File

@ -10,12 +10,12 @@ struct heap_free_list {
}; };
struct heap { struct heap {
factor_vm *myvm; bool secure_gc;
segment *seg; segment *seg;
heap_free_list free; heap_free_list free;
unordered_map<heap_block *, char *> forwarding; unordered_map<heap_block *, char *> forwarding;
explicit heap(factor_vm *myvm, cell size); explicit heap(bool secure_gc_, cell size);
inline heap_block *next_block(heap_block *block) inline heap_block *next_block(heap_block *block)
{ {

View File

@ -28,7 +28,7 @@ void factor_vm::load_data_heap(FILE *file, image_header *h, vm_parameters *p)
clear_gc_stats(); clear_gc_stats();
zone *tenured = &data->generations[data->tenured()]; zone *tenured = &data->generations[tenured_gen];
fixnum bytes_read = fread((void*)tenured->start,1,h->data_size,file); fixnum bytes_read = fread((void*)tenured->start,1,h->data_size,file);
@ -85,7 +85,7 @@ bool factor_vm::save_image(const vm_char *filename)
return false; return false;
} }
zone *tenured = &data->generations[data->tenured()]; zone *tenured = &data->generations[tenured_gen];
h.magic = image_magic; h.magic = image_magic;
h.version = image_version; h.version = image_version;
@ -156,7 +156,7 @@ void factor_vm::data_fixup(cell *cell)
if(immediate_p(*cell)) if(immediate_p(*cell))
return; return;
zone *tenured = &data->generations[data->tenured()]; zone *tenured = &data->generations[tenured_gen];
*cell += (tenured->start - data_relocation_base); *cell += (tenured->start - data_relocation_base);
} }
@ -280,7 +280,7 @@ void factor_vm::relocate_data()
data_fixup(&bignum_pos_one); data_fixup(&bignum_pos_one);
data_fixup(&bignum_neg_one); data_fixup(&bignum_neg_one);
zone *tenured = &data->generations[data->tenured()]; zone *tenured = &data->generations[tenured_gen];
for(relocating = tenured->start; for(relocating = tenured->start;
relocating < tenured->here; relocating < tenured->here;

View File

@ -83,9 +83,8 @@ void factor_vm::primitive_existsp()
box_boolean(stat(path,&sb) >= 0); box_boolean(stat(path,&sb) >= 0);
} }
segment::segment(factor_vm *myvm_, cell size_) segment::segment(cell size_)
{ {
myvm = myvm_;
size = size_; size = size_;
int pagesize = getpagesize(); int pagesize = getpagesize();
@ -94,8 +93,7 @@ segment::segment(factor_vm *myvm_, cell size_)
PROT_READ | PROT_WRITE | PROT_EXEC, PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_ANON | MAP_PRIVATE,-1,0); MAP_ANON | MAP_PRIVATE,-1,0);
if(array == (char*)-1) if(array == (char*)-1) out_of_memory();
myvm->out_of_memory();
if(mprotect(array,pagesize,PROT_NONE) == -1) if(mprotect(array,pagesize,PROT_NONE) == -1)
fatal_error("Cannot protect low guard page",(cell)array); fatal_error("Cannot protect low guard page",(cell)array);

View File

@ -96,9 +96,8 @@ void factor_vm::primitive_existsp()
box_boolean(windows_stat(path)); box_boolean(windows_stat(path));
} }
segment::segment(factor_vm *myvm_, cell size_) segment::segment(cell size_)
{ {
myvm = myvm_;
size = size_; size = size_;
char *mem; char *mem;
@ -106,7 +105,7 @@ segment::segment(factor_vm *myvm_, cell size_)
if((mem = (char *)VirtualAlloc(NULL, getpagesize() * 2 + size, if((mem = (char *)VirtualAlloc(NULL, getpagesize() * 2 + size,
MEM_COMMIT, PAGE_EXECUTE_READWRITE)) == 0) MEM_COMMIT, PAGE_EXECUTE_READWRITE)) == 0)
myvm->out_of_memory(); out_of_memory();
if (!VirtualProtect(mem, getpagesize(), PAGE_NOACCESS, &ignore)) if (!VirtualProtect(mem, getpagesize(), PAGE_NOACCESS, &ignore))
fatal_error("Cannot allocate low guard page", (cell)mem); fatal_error("Cannot allocate low guard page", (cell)mem);

View File

@ -9,12 +9,11 @@ inline cell align_page(cell a)
/* segments set up guard pages to check for under/overflow. /* segments set up guard pages to check for under/overflow.
size must be a multiple of the page size */ size must be a multiple of the page size */
struct segment { struct segment {
factor_vm *myvm;
cell start; cell start;
cell size; cell size;
cell end; cell end;
explicit segment(factor_vm *myvm, cell size); explicit segment(cell size);
~segment(); ~segment();
}; };

148
vm/vm.hpp
View File

@ -4,16 +4,97 @@ namespace factor
struct factor_vm struct factor_vm
{ {
// First five fields accessed directly by assembler. See vm.factor // First five fields accessed directly by assembler. See vm.factor
/* Current stacks */
context *stack_chain; context *stack_chain;
zone nursery; /* new objects are allocated here */
/* New objects are allocated here */
zone nursery;
/* Add this to a shifted address to compute write barrier offsets */
cell cards_offset; cell cards_offset;
cell decks_offset; cell decks_offset;
cell userenv[USER_ENV]; /* TAGGED user environment data; see getenv/setenv prims */
// contexts /* TAGGED user environment data; see getenv/setenv prims */
cell userenv[USER_ENV];
/* Data stack and retain stack sizes */
cell ds_size, rs_size; cell ds_size, rs_size;
/* Pooling unused contexts to make callbacks cheaper */
context *unused_contexts; context *unused_contexts;
/* Canonical T object. It's just a word */
cell T;
/* Is call counting enabled? */
bool profiling_p;
/* Global variables used to pass fault handler state from signal handler to
user-space */
cell signal_number;
cell signal_fault_addr;
unsigned int signal_fpu_status;
stack_frame *signal_callstack_top;
/* Zeroes out deallocated memory; set by the -securegc command line argument */
bool secure_gc;
/* A heap walk allows useful things to be done, like finding all
references to an object for debugging purposes. */
cell heap_scan_ptr;
/* GC is off during heap walking */
bool gc_off;
/* Data heap */
data_heap *data;
/* Where we store object start offsets in cards */
cell allot_markers_offset;
/* Only set if we're performing a GC */
gc_state *current_gc;
/* Statistics */
gc_stats stats;
/* Code heap */
code_heap *code;
/* If a runtime function needs to call another function which potentially
allocates memory, it must wrap any local variable references to Factor
objects in gc_root instances */
std::vector<cell> gc_locals;
std::vector<cell> gc_bignums;
/* Debugger */
bool fep_disabled;
bool full_output;
/* Canonical bignums */
cell bignum_zero;
cell bignum_pos_one;
cell bignum_neg_one;
/* Only used during image loading */
cell code_relocation_base;
cell data_relocation_base;
/* Method dispatch statistics */
cell megamorphic_cache_hits;
cell megamorphic_cache_misses;
cell cold_call_to_ic_transitions;
cell ic_to_pic_transitions;
cell pic_to_mega_transitions;
/* Indexed by PIC_TAG, PIC_HI_TAG, PIC_TUPLE, PIC_HI_TAG_TUPLE */
cell pic_counts[4];
/* Number of entries in a polymorphic inline cache */
cell max_pic_size;
// contexts
void reset_datastack(); void reset_datastack();
void reset_retainstack(); void reset_retainstack();
void fix_stacks(); void fix_stacks();
@ -32,9 +113,6 @@ struct factor_vm
void primitive_check_datastack(); void primitive_check_datastack();
// run // run
/* Canonical T object. It's just a word */
cell T;
void primitive_getenv(); void primitive_getenv();
void primitive_setenv(); void primitive_setenv();
void primitive_exit(); void primitive_exit();
@ -46,23 +124,12 @@ struct factor_vm
void primitive_clone(); void primitive_clone();
// profiler // profiler
bool profiling_p;
void init_profiler(); void init_profiler();
code_block *compile_profiling_stub(cell word_); code_block *compile_profiling_stub(cell word_);
void set_profiling(bool profiling); void set_profiling(bool profiling);
void primitive_profiling(); void primitive_profiling();
// errors // errors
/* Global variables used to pass fault handler state from signal handler to
user-space */
cell signal_number;
cell signal_fault_addr;
unsigned int signal_fpu_status;
stack_frame *signal_callstack_top;
void out_of_memory();
void critical_error(const char* msg, cell tagged);
void throw_error(cell error, stack_frame *callstack_top); void throw_error(cell error, stack_frame *callstack_top);
void not_implemented_error(); void not_implemented_error();
bool in_page(cell fault, cell area, cell area_size, int offset); bool in_page(cell fault, cell area, cell area_size, int offset);
@ -142,13 +209,6 @@ struct factor_vm
bignum *digit_stream_to_bignum(unsigned int n_digits, unsigned int (*producer)(unsigned int, factor_vm *), unsigned int radix, int negative_p); bignum *digit_stream_to_bignum(unsigned int n_digits, unsigned int (*producer)(unsigned int, factor_vm *), unsigned int radix, int negative_p);
//data_heap //data_heap
bool secure_gc; /* Set by the -securegc command line argument */
bool gc_off; /* GC is off during heap walking */
data_heap *data;
/* A heap walk allows useful things to be done, like finding all
references to an object for debugging purposes. */
cell heap_scan_ptr;
void init_card_decks(); void init_card_decks();
data_heap *grow_data_heap(data_heap *data, cell requested_bytes); data_heap *grow_data_heap(data_heap *data, cell requested_bytes);
void clear_cards(cell gen); void clear_cards(cell gen);
@ -173,8 +233,6 @@ struct factor_vm
cell object_size(cell tagged); cell object_size(cell tagged);
//write barrier //write barrier
cell allot_markers_offset;
inline card *addr_to_card(cell a) inline card *addr_to_card(cell a)
{ {
return (card*)(((cell)(a) >> card_bits) + cards_offset); return (card*)(((cell)(a) >> card_bits) + cards_offset);
@ -227,15 +285,6 @@ struct factor_vm
} }
// data_gc // data_gc
/* used during garbage collection only */
gc_state *current_gc;
/* statistics */
gc_stats stats[gen_count];
u64 cards_scanned;
u64 decks_scanned;
u64 card_scan_time;
cell code_heap_scans;
void init_data_gc(); void init_data_gc();
template<typename Strategy> object *resolve_forwarding(object *untagged, Strategy &strategy); template<typename Strategy> object *resolve_forwarding(object *untagged, Strategy &strategy);
template<typename Strategy> void trace_handle(cell *handle, Strategy &strategy); template<typename Strategy> void trace_handle(cell *handle, Strategy &strategy);
@ -269,7 +318,6 @@ struct factor_vm
void clear_gc_stats(); void clear_gc_stats();
void primitive_become(); void primitive_become();
void inline_gc(cell *gc_roots_base, cell gc_roots_size); void inline_gc(cell *gc_roots_base, cell gc_roots_size);
inline object *allot_zone(zone *z, cell a);
object *allot_object(header header, cell size); object *allot_object(header header, cell size);
void primitive_clear_gc_stats(); void primitive_clear_gc_stats();
@ -301,22 +349,12 @@ struct factor_vm
#endif #endif
} }
// local roots
/* If a runtime function needs to call another function which potentially
allocates memory, it must wrap any local variable references to Factor
objects in gc_root instances */
std::vector<cell> gc_locals;
std::vector<cell> gc_bignums;
// generic arrays // generic arrays
template<typename Array> Array *allot_array_internal(cell capacity); template<typename Array> Array *allot_array_internal(cell capacity);
template<typename Array> bool reallot_array_in_place_p(Array *array, cell capacity); template<typename Array> bool reallot_array_in_place_p(Array *array, cell capacity);
template<typename Array> Array *reallot_array(Array *array_, cell capacity); template<typename Array> Array *reallot_array(Array *array_, cell capacity);
//debug //debug
bool fep_disabled;
bool full_output;
void print_chars(string* str); void print_chars(string* str);
void print_word(word* word, cell nesting); void print_word(word* word, cell nesting);
void print_factor_string(string* str); void print_factor_string(string* str);
@ -389,10 +427,6 @@ struct factor_vm
void primitive_wrapper(); void primitive_wrapper();
//math //math
cell bignum_zero;
cell bignum_pos_one;
cell bignum_neg_one;
void primitive_bignum_to_fixnum(); void primitive_bignum_to_fixnum();
void primitive_float_to_fixnum(); void primitive_float_to_fixnum();
void primitive_fixnum_divint(); void primitive_fixnum_divint();
@ -519,8 +553,6 @@ struct factor_vm
code_block *add_code_block(cell type, cell code_, cell labels_, cell owner_, cell relocation_, cell literals_); code_block *add_code_block(cell type, cell code_, cell labels_, cell owner_, cell relocation_, cell literals_);
//code_heap //code_heap
code_heap *code;
inline void check_code_pointer(cell ptr) inline void check_code_pointer(cell ptr)
{ {
#ifdef FACTOR_DEBUG #ifdef FACTOR_DEBUG
@ -554,9 +586,6 @@ struct factor_vm
} }
//image //image
cell code_relocation_base;
cell data_relocation_base;
void init_objects(image_header *h); void init_objects(image_header *h);
void load_data_heap(FILE *file, image_header *h, vm_parameters *p); void load_data_heap(FILE *file, image_header *h, vm_parameters *p);
void load_code_heap(FILE *file, image_header *h, vm_parameters *p); void load_code_heap(FILE *file, image_header *h, vm_parameters *p);
@ -646,9 +675,6 @@ struct factor_vm
void primitive_quot_compiled_p(); void primitive_quot_compiled_p();
//dispatch //dispatch
cell megamorphic_cache_hits;
cell megamorphic_cache_misses;
cell search_lookup_alist(cell table, cell klass); cell search_lookup_alist(cell table, cell klass);
cell search_lookup_hash(cell table, cell klass, cell hashcode); cell search_lookup_hash(cell table, cell klass, cell hashcode);
cell nth_superclass(tuple_layout *layout, fixnum echelon); cell nth_superclass(tuple_layout *layout, fixnum echelon);
@ -666,12 +692,6 @@ struct factor_vm
void primitive_dispatch_stats(); void primitive_dispatch_stats();
//inline cache //inline cache
cell max_pic_size;
cell cold_call_to_ic_transitions;
cell ic_to_pic_transitions;
cell pic_to_mega_transitions;
cell pic_counts[4]; /* PIC_TAG, PIC_HI_TAG, PIC_TUPLE, PIC_HI_TAG_TUPLE */
void init_inline_caching(int max_size); void init_inline_caching(int max_size);
void deallocate_inline_cache(cell return_address); void deallocate_inline_cache(cell return_address);
cell determine_inline_cache_type(array *cache_entries); cell determine_inline_cache_type(array *cache_entries);