Big VM cleanup
- Move forward declarations of 'struct factor_vm' to one place - Rename template parameters from T and TYPE to descriptive names. New convention: CamelCase for template parameters - Change some higher-order functions taking function pointers into templates, and define classes overriding operator(). There's a bit of new boilerplate here but its more consistent than the old mish-mash approaches - Put GC state into a gc_state struct - Use exceptions instead of longjmp for non-local control transfer in GC - In code GC, instead of interleaving code block tracing with copying, add code blocks which need to be revisited to an std::set stored in the gc_statedb4
parent
bcd5c5c635
commit
c4ef640f4d
|
@ -25,7 +25,7 @@ struct growable_array {
|
|||
cell count;
|
||||
gc_root<array> elements;
|
||||
|
||||
growable_array(factor_vm *myvm, cell capacity = 10) : count(0), elements(myvm->allot_array(capacity,F),myvm) {}
|
||||
explicit growable_array(factor_vm *myvm, cell capacity = 10) : count(0), elements(myvm->allot_array(capacity,F),myvm) {}
|
||||
|
||||
void add(cell elt);
|
||||
void trim();
|
||||
|
|
|
@ -44,7 +44,6 @@ enum bignum_comparison
|
|||
bignum_comparison_greater = 1
|
||||
};
|
||||
|
||||
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);
|
||||
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ struct growable_byte_array {
|
|||
cell count;
|
||||
gc_root<byte_array> elements;
|
||||
|
||||
growable_byte_array(factor_vm *myvm,cell capacity = 40) : count(0), elements(myvm->allot_byte_array(capacity),myvm) { }
|
||||
explicit growable_byte_array(factor_vm *myvm,cell capacity = 40) : count(0), elements(myvm->allot_byte_array(capacity),myvm) { }
|
||||
|
||||
void append_bytes(void *elts, cell len);
|
||||
void append_byte_array(cell elts);
|
||||
|
|
|
@ -116,7 +116,7 @@ cell factor_vm::frame_scan(stack_frame *frame)
|
|||
return F;
|
||||
else
|
||||
{
|
||||
char *return_addr = (char *)FRAME_RETURN_ADDRESS(frame);
|
||||
char *return_addr = (char *)FRAME_RETURN_ADDRESS(frame,this);
|
||||
char *quot_xt = (char *)(frame_code(frame) + 1);
|
||||
|
||||
return tag_fixnum(quot_code_offset_to_scan(
|
||||
|
@ -135,11 +135,12 @@ namespace
|
|||
{
|
||||
|
||||
struct stack_frame_accumulator {
|
||||
factor_vm *myvm;
|
||||
growable_array frames;
|
||||
|
||||
stack_frame_accumulator(factor_vm *vm) : frames(vm) {}
|
||||
explicit stack_frame_accumulator(factor_vm *myvm_) : myvm(myvm_), frames(myvm_) {}
|
||||
|
||||
void operator()(stack_frame *frame, factor_vm *myvm)
|
||||
void operator()(stack_frame *frame)
|
||||
{
|
||||
gc_root<object> executing(myvm->frame_executing(frame),myvm);
|
||||
gc_root<object> scan(myvm->frame_scan(frame),myvm);
|
||||
|
@ -204,9 +205,9 @@ void factor_vm::primitive_set_innermost_stack_frame_quot()
|
|||
jit_compile(quot.value(),true);
|
||||
|
||||
stack_frame *inner = innermost_stack_frame_quot(callstack.untagged());
|
||||
cell offset = (char *)FRAME_RETURN_ADDRESS(inner) - (char *)inner->xt;
|
||||
cell offset = (char *)FRAME_RETURN_ADDRESS(inner,this) - (char *)inner->xt;
|
||||
inner->xt = quot->xt;
|
||||
FRAME_RETURN_ADDRESS(inner) = (char *)quot->xt + offset;
|
||||
FRAME_RETURN_ADDRESS(inner,this) = (char *)quot->xt + offset;
|
||||
}
|
||||
|
||||
/* called before entry into Factor code. */
|
||||
|
|
|
@ -10,7 +10,7 @@ VM_ASM_API void save_callstack_bottom(stack_frame *callstack_bottom, factor_vm *
|
|||
|
||||
/* This is a little tricky. The iterator may allocate memory, so we
|
||||
keep the callstack in a GC root and use relative offsets */
|
||||
template<typename TYPE> void factor_vm::iterate_callstack_object(callstack *stack_, TYPE &iterator)
|
||||
template<typename Iterator> void factor_vm::iterate_callstack_object(callstack *stack_, Iterator &iterator)
|
||||
{
|
||||
gc_root<callstack> stack(stack_,this);
|
||||
fixnum frame_offset = untag_fixnum(stack->length) - sizeof(stack_frame);
|
||||
|
@ -19,38 +19,19 @@ template<typename TYPE> void factor_vm::iterate_callstack_object(callstack *stac
|
|||
{
|
||||
stack_frame *frame = stack->frame_at(frame_offset);
|
||||
frame_offset -= frame->size;
|
||||
iterator(frame,this);
|
||||
iterator(frame);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename TYPE> void factor_vm::iterate_callstack(cell top, cell bottom, TYPE &iterator)
|
||||
template<typename Iterator> void factor_vm::iterate_callstack(cell top, cell bottom, Iterator &iterator)
|
||||
{
|
||||
stack_frame *frame = (stack_frame *)bottom - 1;
|
||||
|
||||
while((cell)frame >= top)
|
||||
{
|
||||
iterator(frame,this);
|
||||
iterator(frame);
|
||||
frame = frame_successor(frame);
|
||||
}
|
||||
}
|
||||
|
||||
/* Every object has a regular representation in the runtime, which makes GC
|
||||
much simpler. Every slot of the object until binary_payload_start is a pointer
|
||||
to some other object. */
|
||||
struct factor_vm;
|
||||
inline void factor_vm::do_slots(cell obj, void (* iter)(cell *,factor_vm*))
|
||||
{
|
||||
cell scan = obj;
|
||||
cell payload_start = binary_payload_start((object *)obj);
|
||||
cell end = obj + payload_start;
|
||||
|
||||
scan += sizeof(cell);
|
||||
|
||||
while(scan < end)
|
||||
{
|
||||
iter((cell *)scan,this);
|
||||
scan += sizeof(cell);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -188,7 +188,7 @@ cell factor_vm::compute_relocation(relocation_entry rel, cell index, code_block
|
|||
#undef ARG
|
||||
}
|
||||
|
||||
void factor_vm::iterate_relocations(code_block *compiled, relocation_iterator iter)
|
||||
template<typename Iterator> void factor_vm::iterate_relocations(code_block *compiled, Iterator &iter)
|
||||
{
|
||||
if(compiled->relocation != F)
|
||||
{
|
||||
|
@ -200,7 +200,7 @@ void factor_vm::iterate_relocations(code_block *compiled, relocation_iterator it
|
|||
for(cell i = 0; i < length; i++)
|
||||
{
|
||||
relocation_entry rel = relocation->data<relocation_entry>()[i];
|
||||
(this->*iter)(rel,index,compiled);
|
||||
iter(rel,index,compiled);
|
||||
index += number_of_parameters(relocation_type_of(rel));
|
||||
}
|
||||
}
|
||||
|
@ -270,54 +270,51 @@ void factor_vm::store_address_in_code_block(cell klass, cell offset, fixnum abso
|
|||
}
|
||||
}
|
||||
|
||||
void factor_vm::update_literal_references_step(relocation_entry rel, cell index, code_block *compiled)
|
||||
{
|
||||
if(relocation_type_of(rel) == RT_IMMEDIATE)
|
||||
{
|
||||
cell offset = relocation_offset_of(rel) + (cell)(compiled + 1);
|
||||
array *literals = untag<array>(compiled->literals);
|
||||
fixnum absolute_value = array_nth(literals,index);
|
||||
store_address_in_code_block(relocation_class_of(rel),offset,absolute_value);
|
||||
}
|
||||
}
|
||||
struct literal_references_updater {
|
||||
factor_vm *myvm;
|
||||
|
||||
void update_literal_references_step(relocation_entry rel, cell index, code_block *compiled, factor_vm *myvm)
|
||||
{
|
||||
return myvm->update_literal_references_step(rel,index,compiled);
|
||||
}
|
||||
explicit literal_references_updater(factor_vm *myvm_) : myvm(myvm_) {}
|
||||
|
||||
void operator()(relocation_entry rel, cell index, code_block *compiled)
|
||||
{
|
||||
if(myvm->relocation_type_of(rel) == RT_IMMEDIATE)
|
||||
{
|
||||
cell offset = myvm->relocation_offset_of(rel) + (cell)(compiled + 1);
|
||||
array *literals = myvm->untag<array>(compiled->literals);
|
||||
fixnum absolute_value = array_nth(literals,index);
|
||||
myvm->store_address_in_code_block(myvm->relocation_class_of(rel),offset,absolute_value);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/* Update pointers to literals from compiled code. */
|
||||
void factor_vm::update_literal_references(code_block *compiled)
|
||||
{
|
||||
if(!compiled->needs_fixup)
|
||||
{
|
||||
iterate_relocations(compiled,&factor_vm::update_literal_references_step);
|
||||
literal_references_updater updater(this);
|
||||
iterate_relocations(compiled,updater);
|
||||
flush_icache_for(compiled);
|
||||
}
|
||||
}
|
||||
|
||||
/* Copy all literals referenced from a code block to newspace. Only for
|
||||
aging and nursery collections */
|
||||
void factor_vm::copy_literal_references(code_block *compiled)
|
||||
void factor_vm::trace_literal_references(code_block *compiled)
|
||||
{
|
||||
if(collecting_gen >= compiled->last_scan)
|
||||
if(current_gc->collecting_gen >= compiled->last_scan)
|
||||
{
|
||||
if(collecting_accumulation_gen_p())
|
||||
compiled->last_scan = collecting_gen;
|
||||
if(current_gc->collecting_accumulation_gen_p())
|
||||
compiled->last_scan = current_gc->collecting_gen;
|
||||
else
|
||||
compiled->last_scan = collecting_gen + 1;
|
||||
compiled->last_scan = current_gc->collecting_gen + 1;
|
||||
|
||||
/* initialize chase pointer */
|
||||
cell scan = newspace->here;
|
||||
trace_handle(&compiled->literals);
|
||||
trace_handle(&compiled->relocation);
|
||||
|
||||
copy_handle(&compiled->literals);
|
||||
copy_handle(&compiled->relocation);
|
||||
|
||||
/* do some tracing so that all reachable literals are now
|
||||
at their final address */
|
||||
copy_reachable_objects(scan,&newspace->here);
|
||||
|
||||
update_literal_references(compiled);
|
||||
/* once we finish tracing, re-visit this code block and update
|
||||
literals */
|
||||
current_gc->dirty_code_blocks.insert(compiled);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -336,22 +333,17 @@ void factor_vm::relocate_code_block_step(relocation_entry rel, cell index, code_
|
|||
compute_relocation(rel,index,compiled));
|
||||
}
|
||||
|
||||
void relocate_code_block_step(relocation_entry rel, cell index, code_block *compiled, factor_vm *myvm)
|
||||
{
|
||||
return myvm->relocate_code_block_step(rel,index,compiled);
|
||||
}
|
||||
struct word_references_updater {
|
||||
factor_vm *myvm;
|
||||
|
||||
void factor_vm::update_word_references_step(relocation_entry rel, cell index, code_block *compiled)
|
||||
{
|
||||
relocation_type type = relocation_type_of(rel);
|
||||
if(type == RT_XT || type == RT_XT_PIC || type == RT_XT_PIC_TAIL)
|
||||
relocate_code_block_step(rel,index,compiled);
|
||||
}
|
||||
|
||||
void update_word_references_step(relocation_entry rel, cell index, code_block *compiled, factor_vm *myvm)
|
||||
{
|
||||
return myvm->update_word_references_step(rel,index,compiled);
|
||||
}
|
||||
explicit word_references_updater(factor_vm *myvm_) : myvm(myvm_) {}
|
||||
void operator()(relocation_entry rel, cell index, code_block *compiled)
|
||||
{
|
||||
relocation_type type = myvm->relocation_type_of(rel);
|
||||
if(type == RT_XT || type == RT_XT_PIC || type == RT_XT_PIC_TAIL)
|
||||
myvm->relocate_code_block_step(rel,index,compiled);
|
||||
}
|
||||
};
|
||||
|
||||
/* Relocate new code blocks completely; updating references to literals,
|
||||
dlsyms, and words. For all other words in the code heap, we only need
|
||||
|
@ -372,27 +364,12 @@ void factor_vm::update_word_references(code_block *compiled)
|
|||
code->heap_free(compiled);
|
||||
else
|
||||
{
|
||||
iterate_relocations(compiled,&factor_vm::update_word_references_step);
|
||||
word_references_updater updater(this);
|
||||
iterate_relocations(compiled,updater);
|
||||
flush_icache_for(compiled);
|
||||
}
|
||||
}
|
||||
|
||||
void update_word_references(code_block *compiled, factor_vm *myvm)
|
||||
{
|
||||
return myvm->update_word_references(compiled);
|
||||
}
|
||||
|
||||
void factor_vm::update_literal_and_word_references(code_block *compiled)
|
||||
{
|
||||
update_literal_references(compiled);
|
||||
update_word_references(compiled);
|
||||
}
|
||||
|
||||
void update_literal_and_word_references(code_block *compiled, factor_vm *myvm)
|
||||
{
|
||||
return myvm->update_literal_and_word_references(compiled);
|
||||
}
|
||||
|
||||
void factor_vm::check_code_address(cell address)
|
||||
{
|
||||
#ifdef FACTOR_DEBUG
|
||||
|
@ -411,29 +388,30 @@ void factor_vm::mark_code_block(code_block *compiled)
|
|||
|
||||
code->mark_block(compiled);
|
||||
|
||||
copy_handle(&compiled->literals);
|
||||
copy_handle(&compiled->relocation);
|
||||
trace_handle(&compiled->literals);
|
||||
trace_handle(&compiled->relocation);
|
||||
}
|
||||
|
||||
void factor_vm::mark_stack_frame_step(stack_frame *frame)
|
||||
{
|
||||
mark_code_block(frame_code(frame));
|
||||
}
|
||||
struct stack_frame_marker {
|
||||
factor_vm *myvm;
|
||||
|
||||
void mark_stack_frame_step(stack_frame *frame, factor_vm *myvm)
|
||||
{
|
||||
return myvm->mark_stack_frame_step(frame);
|
||||
}
|
||||
explicit stack_frame_marker(factor_vm *myvm_) : myvm(myvm_) {}
|
||||
void operator()(stack_frame *frame)
|
||||
{
|
||||
myvm->mark_code_block(myvm->frame_code(frame));
|
||||
}
|
||||
};
|
||||
|
||||
/* Mark code blocks executing in currently active stack frames. */
|
||||
void factor_vm::mark_active_blocks(context *stacks)
|
||||
{
|
||||
if(collecting_gen == data->tenured())
|
||||
if(current_gc->collecting_tenured_p())
|
||||
{
|
||||
cell top = (cell)stacks->callstack_top;
|
||||
cell bottom = (cell)stacks->callstack_bottom;
|
||||
|
||||
iterate_callstack(top,bottom,factor::mark_stack_frame_step);
|
||||
stack_frame_marker marker(this);
|
||||
iterate_callstack(top,bottom,marker);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -460,18 +438,32 @@ void factor_vm::mark_object_code_block(object *object)
|
|||
case CALLSTACK_TYPE:
|
||||
{
|
||||
callstack *stack = (callstack *)object;
|
||||
iterate_callstack_object(stack,factor::mark_stack_frame_step);
|
||||
stack_frame_marker marker(this);
|
||||
iterate_callstack_object(stack,marker);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct code_block_relocator {
|
||||
factor_vm *myvm;
|
||||
|
||||
explicit code_block_relocator(factor_vm *myvm_) : myvm(myvm_) {}
|
||||
|
||||
void operator()(relocation_entry rel, cell index, code_block *compiled)
|
||||
{
|
||||
myvm->relocate_code_block_step(rel,index,compiled);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/* Perform all fixups on a code block */
|
||||
void factor_vm::relocate_code_block(code_block *compiled)
|
||||
{
|
||||
compiled->last_scan = data->nursery();
|
||||
compiled->needs_fixup = false;
|
||||
iterate_relocations(compiled,&factor_vm::relocate_code_block_step);
|
||||
code_block_relocator relocator(this);
|
||||
iterate_relocations(compiled,relocator);
|
||||
flush_icache_for(compiled);
|
||||
}
|
||||
|
||||
|
|
|
@ -28,31 +28,37 @@ void factor_vm::jit_compile_word(cell word_, cell def_, bool relocate)
|
|||
if(word->pic_tail_def != F) jit_compile(word->pic_tail_def,relocate);
|
||||
}
|
||||
|
||||
/* Apply a function to every code block */
|
||||
void factor_vm::iterate_code_heap(code_heap_iterator iter)
|
||||
{
|
||||
heap_block *scan = code->first_block();
|
||||
struct literal_reference_tracer {
|
||||
factor_vm *myvm;
|
||||
|
||||
while(scan)
|
||||
explicit literal_reference_tracer(factor_vm *myvm_) : myvm(myvm_) {}
|
||||
void operator()(code_block *compiled)
|
||||
{
|
||||
if(scan->status != B_FREE)
|
||||
(this->*iter)((code_block *)scan);
|
||||
scan = code->next_block(scan);
|
||||
myvm->trace_literal_references(compiled);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/* Copy literals referenced from all code blocks to newspace. Only for
|
||||
aging and nursery collections */
|
||||
void factor_vm::copy_code_heap_roots()
|
||||
void factor_vm::trace_code_heap_roots()
|
||||
{
|
||||
iterate_code_heap(&factor_vm::copy_literal_references);
|
||||
code_heap_scans++;
|
||||
|
||||
literal_reference_tracer tracer(this);
|
||||
iterate_code_heap(tracer);
|
||||
|
||||
if(current_gc->collecting_accumulation_gen_p())
|
||||
last_code_heap_scan = current_gc->collecting_gen;
|
||||
else
|
||||
last_code_heap_scan = current_gc->collecting_gen + 1;
|
||||
}
|
||||
|
||||
/* Update pointers to words referenced from all code blocks. Only after
|
||||
defining a new word. */
|
||||
void factor_vm::update_code_heap_words()
|
||||
{
|
||||
iterate_code_heap(&factor_vm::update_word_references);
|
||||
word_updater updater(this);
|
||||
iterate_code_heap(updater);
|
||||
}
|
||||
|
||||
void factor_vm::primitive_modify_code_heap()
|
||||
|
@ -122,18 +128,19 @@ code_block *factor_vm::forward_xt(code_block *compiled)
|
|||
return (code_block *)forwarding[compiled];
|
||||
}
|
||||
|
||||
void factor_vm::forward_frame_xt(stack_frame *frame)
|
||||
{
|
||||
cell offset = (cell)FRAME_RETURN_ADDRESS(frame) - (cell)frame_code(frame);
|
||||
code_block *forwarded = forward_xt(frame_code(frame));
|
||||
frame->xt = forwarded->xt();
|
||||
FRAME_RETURN_ADDRESS(frame) = (void *)((cell)forwarded + offset);
|
||||
}
|
||||
struct xt_forwarder {
|
||||
factor_vm *myvm;
|
||||
|
||||
void forward_frame_xt(stack_frame *frame,factor_vm *myvm)
|
||||
{
|
||||
return myvm->forward_frame_xt(frame);
|
||||
}
|
||||
explicit xt_forwarder(factor_vm *myvm_) : myvm(myvm_) {}
|
||||
|
||||
void operator()(stack_frame *frame)
|
||||
{
|
||||
cell offset = (cell)FRAME_RETURN_ADDRESS(frame,myvm) - (cell)myvm->frame_code(frame);
|
||||
code_block *forwarded = myvm->forward_xt(myvm->frame_code(frame));
|
||||
frame->xt = forwarded->xt();
|
||||
FRAME_RETURN_ADDRESS(frame,myvm) = (void *)((cell)forwarded + offset);
|
||||
}
|
||||
};
|
||||
|
||||
void factor_vm::forward_object_xts()
|
||||
{
|
||||
|
@ -166,7 +173,8 @@ void factor_vm::forward_object_xts()
|
|||
case CALLSTACK_TYPE:
|
||||
{
|
||||
callstack *stack = untag<callstack>(obj);
|
||||
iterate_callstack_object(stack,factor::forward_frame_xt);
|
||||
xt_forwarder forwarder(this);
|
||||
iterate_callstack_object(stack,forwarder);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
@ -212,8 +220,8 @@ do this before saving a deployed image and exiting, so performaance is not
|
|||
critical here */
|
||||
void factor_vm::compact_code_heap()
|
||||
{
|
||||
/* Free all unreachable code blocks */
|
||||
gc();
|
||||
/* Free all unreachable code blocks, don't trace contexts */
|
||||
garbage_collection(data->tenured(),false,false,0);
|
||||
|
||||
/* Figure out where the code heap blocks are going to end up */
|
||||
cell size = code->compute_heap_forwarding(forwarding);
|
||||
|
|
|
@ -8,4 +8,14 @@ inline void factor_vm::check_code_pointer(cell ptr)
|
|||
#endif
|
||||
}
|
||||
|
||||
struct word_updater {
|
||||
factor_vm *myvm;
|
||||
|
||||
explicit word_updater(factor_vm *myvm_) : myvm(myvm_) {}
|
||||
void operator()(code_block *compiled)
|
||||
{
|
||||
myvm->update_word_references(compiled);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -44,7 +44,6 @@ struct context {
|
|||
DEFPUSHPOP(d,ds)
|
||||
DEFPUSHPOP(r,rs)
|
||||
|
||||
struct factor_vm;
|
||||
VM_C_API void nest_stacks(factor_vm *vm);
|
||||
VM_C_API void unnest_stacks(factor_vm *vm);
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ namespace factor
|
|||
register cell ds asm("r5");
|
||||
register cell rs asm("r6");
|
||||
|
||||
#define FRAME_RETURN_ADDRESS(frame) *(XT *)(frame_successor(frame) + 1)
|
||||
#define FRAME_RETURN_ADDRESS(frame,vm) *(XT *)(vm->frame_successor(frame) + 1)
|
||||
|
||||
void c_to_factor(cell quot);
|
||||
void set_callstack(stack_frame *to, stack_frame *from, cell length, void *memcpy);
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
namespace factor
|
||||
{
|
||||
|
||||
#define FRAME_RETURN_ADDRESS(frame) *(void **)(frame_successor(frame) + 1)
|
||||
#define FRAME_RETURN_ADDRESS(frame,vm) *(void **)(vm->frame_successor(frame) + 1)
|
||||
|
||||
inline static void flush_icache(cell start, cell len) {}
|
||||
|
||||
|
|
391
vm/data_gc.cpp
391
vm/data_gc.cpp
|
@ -5,19 +5,29 @@ namespace factor
|
|||
|
||||
void factor_vm::init_data_gc()
|
||||
{
|
||||
performing_gc = false;
|
||||
last_code_heap_scan = data->nursery();
|
||||
collecting_aging_again = false;
|
||||
}
|
||||
|
||||
gc_state::gc_state(data_heap *data_, bool growing_data_heap_, cell collecting_gen_) :
|
||||
data(data_),
|
||||
growing_data_heap(growing_data_heap_),
|
||||
collecting_gen(collecting_gen_),
|
||||
start_time(current_micros()) { }
|
||||
|
||||
gc_state::~gc_state() { }
|
||||
|
||||
/* If a generation fills up, throw this error. It is caught in garbage_collection() */
|
||||
struct generation_full_condition { };
|
||||
|
||||
/* Given a pointer to oldspace, copy it to newspace */
|
||||
object *factor_vm::copy_untagged_object_impl(object *pointer, cell size)
|
||||
{
|
||||
if(newspace->here + size >= newspace->end)
|
||||
longjmp(gc_jmp,1);
|
||||
object *newpointer = allot_zone(newspace,size);
|
||||
if(current_gc->newspace->here + size >= current_gc->newspace->end)
|
||||
throw generation_full_condition();
|
||||
|
||||
gc_stats *s = &stats[collecting_gen];
|
||||
object *newpointer = allot_zone(current_gc->newspace,size);
|
||||
|
||||
gc_stats *s = &stats[current_gc->collecting_gen];
|
||||
s->object_count++;
|
||||
s->bytes_copied += size;
|
||||
|
||||
|
@ -34,13 +44,13 @@ object *factor_vm::copy_object_impl(object *untagged)
|
|||
|
||||
bool factor_vm::should_copy_p(object *untagged)
|
||||
{
|
||||
if(in_zone(newspace,untagged))
|
||||
if(in_zone(current_gc->newspace,untagged))
|
||||
return false;
|
||||
if(collecting_gen == data->tenured())
|
||||
if(current_gc->collecting_tenured_p())
|
||||
return true;
|
||||
else if(data->have_aging_p() && collecting_gen == data->aging())
|
||||
else if(data->have_aging_p() && current_gc->collecting_gen == data->aging())
|
||||
return !in_zone(&data->generations[data->tenured()],untagged);
|
||||
else if(collecting_gen == data->nursery())
|
||||
else if(current_gc->collecting_nursery_p())
|
||||
return in_zone(&nursery,untagged);
|
||||
else
|
||||
{
|
||||
|
@ -68,16 +78,16 @@ object *factor_vm::resolve_forwarding(object *untagged)
|
|||
}
|
||||
}
|
||||
|
||||
template <typename TYPE> TYPE *factor_vm::copy_untagged_object(TYPE *untagged)
|
||||
template<typename Type> Type *factor_vm::copy_untagged_object(Type *untagged)
|
||||
{
|
||||
check_data_pointer(untagged);
|
||||
|
||||
if(untagged->h.forwarding_pointer_p())
|
||||
untagged = (TYPE *)resolve_forwarding(untagged->h.forwarding_pointer());
|
||||
untagged = (Type *)resolve_forwarding(untagged->h.forwarding_pointer());
|
||||
else
|
||||
{
|
||||
untagged->h.check_header();
|
||||
untagged = (TYPE *)copy_object_impl(untagged);
|
||||
untagged = (Type *)copy_object_impl(untagged);
|
||||
}
|
||||
|
||||
return untagged;
|
||||
|
@ -88,7 +98,7 @@ cell factor_vm::copy_object(cell pointer)
|
|||
return RETAG(copy_untagged_object(untag<object>(pointer)),TAG(pointer));
|
||||
}
|
||||
|
||||
void factor_vm::copy_handle(cell *handle)
|
||||
void factor_vm::trace_handle(cell *handle)
|
||||
{
|
||||
cell pointer = *handle;
|
||||
|
||||
|
@ -102,7 +112,7 @@ void factor_vm::copy_handle(cell *handle)
|
|||
}
|
||||
|
||||
/* Scan all the objects in the card */
|
||||
void factor_vm::copy_card(card *ptr, cell gen, cell here)
|
||||
void factor_vm::trace_card(card *ptr, cell gen, cell here)
|
||||
{
|
||||
cell card_scan = card_to_addr(ptr) + card_offset(ptr);
|
||||
cell card_end = card_to_addr(ptr + 1);
|
||||
|
@ -115,7 +125,7 @@ void factor_vm::copy_card(card *ptr, cell gen, cell here)
|
|||
cards_scanned++;
|
||||
}
|
||||
|
||||
void factor_vm::copy_card_deck(card_deck *deck, cell gen, card mask, card unmask)
|
||||
void factor_vm::trace_card_deck(card_deck *deck, cell gen, card mask, card unmask)
|
||||
{
|
||||
card *first_card = deck_to_card(deck);
|
||||
card *last_card = deck_to_card(deck + 1);
|
||||
|
@ -136,7 +146,7 @@ void factor_vm::copy_card_deck(card_deck *deck, cell gen, card mask, card unmask
|
|||
{
|
||||
if(ptr[card] & mask)
|
||||
{
|
||||
copy_card(&ptr[card],gen,here);
|
||||
trace_card(&ptr[card],gen,here);
|
||||
ptr[card] &= ~unmask;
|
||||
}
|
||||
}
|
||||
|
@ -147,7 +157,7 @@ void factor_vm::copy_card_deck(card_deck *deck, cell gen, card mask, card unmask
|
|||
}
|
||||
|
||||
/* Copy all newspace objects referenced from marked cards to the destination */
|
||||
void factor_vm::copy_gen_cards(cell gen)
|
||||
void factor_vm::trace_generation_cards(cell gen)
|
||||
{
|
||||
card_deck *first_deck = addr_to_deck(data->generations[gen].start);
|
||||
card_deck *last_deck = addr_to_deck(data->generations[gen].end);
|
||||
|
@ -156,7 +166,7 @@ void factor_vm::copy_gen_cards(cell gen)
|
|||
|
||||
/* if we are collecting the nursery, we care about old->nursery pointers
|
||||
but not old->aging pointers */
|
||||
if(collecting_gen == data->nursery())
|
||||
if(current_gc->collecting_nursery_p())
|
||||
{
|
||||
mask = card_points_to_nursery;
|
||||
|
||||
|
@ -171,16 +181,16 @@ void factor_vm::copy_gen_cards(cell gen)
|
|||
unmask = card_mark_mask;
|
||||
else
|
||||
{
|
||||
critical_error("bug in copy_gen_cards",gen);
|
||||
critical_error("bug in trace_generation_cards",gen);
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* if we are collecting aging space into tenured space, we care about
|
||||
all old->nursery and old->aging pointers. no old->aging pointers can
|
||||
remain */
|
||||
else if(data->have_aging_p() && collecting_gen == data->aging())
|
||||
else if(data->have_aging_p() && current_gc->collecting_gen == data->aging())
|
||||
{
|
||||
if(collecting_aging_again)
|
||||
if(current_gc->collecting_aging_again)
|
||||
{
|
||||
mask = card_points_to_aging;
|
||||
unmask = card_mark_mask;
|
||||
|
@ -196,7 +206,7 @@ void factor_vm::copy_gen_cards(cell gen)
|
|||
}
|
||||
else
|
||||
{
|
||||
critical_error("bug in copy_gen_cards",gen);
|
||||
critical_error("bug in trace_generation_cards",gen);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -206,7 +216,7 @@ void factor_vm::copy_gen_cards(cell gen)
|
|||
{
|
||||
if(*ptr & mask)
|
||||
{
|
||||
copy_card_deck(ptr,gen,mask,unmask);
|
||||
trace_card_deck(ptr,gen,mask,unmask);
|
||||
*ptr &= ~unmask;
|
||||
}
|
||||
}
|
||||
|
@ -214,36 +224,36 @@ void factor_vm::copy_gen_cards(cell gen)
|
|||
|
||||
/* Scan cards in all generations older than the one being collected, copying
|
||||
old->new references */
|
||||
void factor_vm::copy_cards()
|
||||
void factor_vm::trace_cards()
|
||||
{
|
||||
u64 start = current_micros();
|
||||
|
||||
cell i;
|
||||
for(i = collecting_gen + 1; i < data->gen_count; i++)
|
||||
copy_gen_cards(i);
|
||||
for(i = current_gc->collecting_gen + 1; i < data->gen_count; i++)
|
||||
trace_generation_cards(i);
|
||||
|
||||
card_scan_time += (current_micros() - start);
|
||||
}
|
||||
|
||||
/* Copy all tagged pointers in a range of memory */
|
||||
void factor_vm::copy_stack_elements(segment *region, cell top)
|
||||
void factor_vm::trace_stack_elements(segment *region, cell top)
|
||||
{
|
||||
cell ptr = region->start;
|
||||
|
||||
for(; ptr <= top; ptr += sizeof(cell))
|
||||
copy_handle((cell*)ptr);
|
||||
trace_handle((cell*)ptr);
|
||||
}
|
||||
|
||||
void factor_vm::copy_registered_locals()
|
||||
void factor_vm::trace_registered_locals()
|
||||
{
|
||||
std::vector<cell>::const_iterator iter = gc_locals.begin();
|
||||
std::vector<cell>::const_iterator end = gc_locals.end();
|
||||
|
||||
for(; iter < end; iter++)
|
||||
copy_handle((cell *)(*iter));
|
||||
trace_handle((cell *)(*iter));
|
||||
}
|
||||
|
||||
void factor_vm::copy_registered_bignums()
|
||||
void factor_vm::trace_registered_bignums()
|
||||
{
|
||||
std::vector<cell>::const_iterator iter = gc_bignums.begin();
|
||||
std::vector<cell>::const_iterator end = gc_bignums.end();
|
||||
|
@ -267,38 +277,38 @@ void factor_vm::copy_registered_bignums()
|
|||
|
||||
/* Copy roots over at the start of GC, namely various constants, stacks,
|
||||
the user environment and extra roots registered by local_roots.hpp */
|
||||
void factor_vm::copy_roots()
|
||||
void factor_vm::trace_roots()
|
||||
{
|
||||
copy_handle(&T);
|
||||
copy_handle(&bignum_zero);
|
||||
copy_handle(&bignum_pos_one);
|
||||
copy_handle(&bignum_neg_one);
|
||||
trace_handle(&T);
|
||||
trace_handle(&bignum_zero);
|
||||
trace_handle(&bignum_pos_one);
|
||||
trace_handle(&bignum_neg_one);
|
||||
|
||||
copy_registered_locals();
|
||||
copy_registered_bignums();
|
||||
|
||||
if(!performing_compaction)
|
||||
{
|
||||
save_stacks();
|
||||
context *stacks = stack_chain;
|
||||
|
||||
while(stacks)
|
||||
{
|
||||
copy_stack_elements(stacks->datastack_region,stacks->datastack);
|
||||
copy_stack_elements(stacks->retainstack_region,stacks->retainstack);
|
||||
|
||||
copy_handle(&stacks->catchstack_save);
|
||||
copy_handle(&stacks->current_callback_save);
|
||||
|
||||
mark_active_blocks(stacks);
|
||||
|
||||
stacks = stacks->next;
|
||||
}
|
||||
}
|
||||
trace_registered_locals();
|
||||
trace_registered_bignums();
|
||||
|
||||
int i;
|
||||
for(i = 0; i < USER_ENV; i++)
|
||||
copy_handle(&userenv[i]);
|
||||
trace_handle(&userenv[i]);
|
||||
}
|
||||
|
||||
void factor_vm::trace_contexts()
|
||||
{
|
||||
save_stacks();
|
||||
context *stacks = stack_chain;
|
||||
|
||||
while(stacks)
|
||||
{
|
||||
trace_stack_elements(stacks->datastack_region,stacks->datastack);
|
||||
trace_stack_elements(stacks->retainstack_region,stacks->retainstack);
|
||||
|
||||
trace_handle(&stacks->catchstack_save);
|
||||
trace_handle(&stacks->current_callback_save);
|
||||
|
||||
mark_active_blocks(stacks);
|
||||
|
||||
stacks = stacks->next;
|
||||
}
|
||||
}
|
||||
|
||||
cell factor_vm::copy_next_from_nursery(cell scan)
|
||||
|
@ -341,8 +351,8 @@ cell factor_vm::copy_next_from_aging(cell scan)
|
|||
cell tenured_start = data->generations[data->tenured()].start;
|
||||
cell tenured_end = data->generations[data->tenured()].end;
|
||||
|
||||
cell newspace_start = newspace->start;
|
||||
cell newspace_end = newspace->end;
|
||||
cell newspace_start = current_gc->newspace->start;
|
||||
cell newspace_end = current_gc->newspace->end;
|
||||
|
||||
for(; obj < end; obj++)
|
||||
{
|
||||
|
@ -370,8 +380,8 @@ cell factor_vm::copy_next_from_tenured(cell scan)
|
|||
{
|
||||
obj++;
|
||||
|
||||
cell newspace_start = newspace->start;
|
||||
cell newspace_end = newspace->end;
|
||||
cell newspace_start = current_gc->newspace->start;
|
||||
cell newspace_end = current_gc->newspace->end;
|
||||
|
||||
for(; obj < end; obj++)
|
||||
{
|
||||
|
@ -393,179 +403,228 @@ cell factor_vm::copy_next_from_tenured(cell scan)
|
|||
|
||||
void factor_vm::copy_reachable_objects(cell scan, cell *end)
|
||||
{
|
||||
if(collecting_gen == data->nursery())
|
||||
if(current_gc->collecting_nursery_p())
|
||||
{
|
||||
while(scan < *end)
|
||||
scan = copy_next_from_nursery(scan);
|
||||
}
|
||||
else if(data->have_aging_p() && collecting_gen == data->aging())
|
||||
else if(data->have_aging_p() && current_gc->collecting_gen == data->aging())
|
||||
{
|
||||
while(scan < *end)
|
||||
scan = copy_next_from_aging(scan);
|
||||
}
|
||||
else if(collecting_gen == data->tenured())
|
||||
else if(current_gc->collecting_tenured_p())
|
||||
{
|
||||
while(scan < *end)
|
||||
scan = copy_next_from_tenured(scan);
|
||||
}
|
||||
}
|
||||
|
||||
void factor_vm::update_code_heap_roots()
|
||||
{
|
||||
if(current_gc->collecting_gen >= last_code_heap_scan)
|
||||
{
|
||||
code_heap_scans++;
|
||||
|
||||
trace_code_heap_roots();
|
||||
|
||||
if(current_gc->collecting_accumulation_gen_p())
|
||||
last_code_heap_scan = current_gc->collecting_gen;
|
||||
else
|
||||
last_code_heap_scan = current_gc->collecting_gen + 1;
|
||||
}
|
||||
}
|
||||
|
||||
struct literal_and_word_reference_updater {
|
||||
factor_vm *myvm;
|
||||
|
||||
literal_and_word_reference_updater(factor_vm *myvm_) : myvm(myvm_) {}
|
||||
|
||||
void operator()(heap_block *block)
|
||||
{
|
||||
code_block *compiled = (code_block *)block;
|
||||
myvm->update_literal_references(compiled);
|
||||
myvm->update_word_references(compiled);
|
||||
}
|
||||
};
|
||||
|
||||
void factor_vm::free_unmarked_code_blocks()
|
||||
{
|
||||
literal_and_word_reference_updater updater(this);
|
||||
code->free_unmarked(updater);
|
||||
last_code_heap_scan = current_gc->collecting_gen;
|
||||
}
|
||||
|
||||
void factor_vm::update_dirty_code_blocks()
|
||||
{
|
||||
std::set<code_block *> dirty_code_blocks = current_gc->dirty_code_blocks;
|
||||
std::set<code_block *>::const_iterator iter = dirty_code_blocks.begin();
|
||||
std::set<code_block *>::const_iterator end = dirty_code_blocks.end();
|
||||
|
||||
for(; iter != end; iter++)
|
||||
update_literal_references(*iter);
|
||||
|
||||
dirty_code_blocks.clear();
|
||||
}
|
||||
|
||||
/* Prepare to start copying reachable objects into an unused zone */
|
||||
void factor_vm::begin_gc(cell requested_bytes)
|
||||
{
|
||||
if(growing_data_heap)
|
||||
if(current_gc->growing_data_heap)
|
||||
{
|
||||
if(collecting_gen != data->tenured())
|
||||
critical_error("Invalid parameters to begin_gc",0);
|
||||
assert(current_gc->collecting_tenured_p());
|
||||
|
||||
old_data_heap = data;
|
||||
set_data_heap(grow_data_heap(old_data_heap,requested_bytes));
|
||||
newspace = &data->generations[data->tenured()];
|
||||
current_gc->old_data_heap = data;
|
||||
set_data_heap(grow_data_heap(current_gc->old_data_heap,requested_bytes));
|
||||
current_gc->newspace = &data->generations[data->tenured()];
|
||||
}
|
||||
else if(collecting_accumulation_gen_p())
|
||||
else if(current_gc->collecting_accumulation_gen_p())
|
||||
{
|
||||
/* when collecting one of these generations, rotate it
|
||||
with the semispace */
|
||||
zone z = data->generations[collecting_gen];
|
||||
data->generations[collecting_gen] = data->semispaces[collecting_gen];
|
||||
data->semispaces[collecting_gen] = z;
|
||||
reset_generation(collecting_gen);
|
||||
newspace = &data->generations[collecting_gen];
|
||||
clear_cards(collecting_gen,collecting_gen);
|
||||
clear_decks(collecting_gen,collecting_gen);
|
||||
clear_allot_markers(collecting_gen,collecting_gen);
|
||||
zone z = data->generations[current_gc->collecting_gen];
|
||||
data->generations[current_gc->collecting_gen] = data->semispaces[current_gc->collecting_gen];
|
||||
data->semispaces[current_gc->collecting_gen] = z;
|
||||
reset_generation(current_gc->collecting_gen);
|
||||
current_gc->newspace = &data->generations[current_gc->collecting_gen];
|
||||
clear_cards(current_gc->collecting_gen,current_gc->collecting_gen);
|
||||
clear_decks(current_gc->collecting_gen,current_gc->collecting_gen);
|
||||
clear_allot_markers(current_gc->collecting_gen,current_gc->collecting_gen);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* when collecting a younger generation, we copy
|
||||
reachable objects to the next oldest generation,
|
||||
so we set the newspace so the next generation. */
|
||||
newspace = &data->generations[collecting_gen + 1];
|
||||
current_gc->newspace = &data->generations[current_gc->collecting_gen + 1];
|
||||
}
|
||||
}
|
||||
|
||||
void factor_vm::end_gc(cell gc_elapsed)
|
||||
void factor_vm::end_gc()
|
||||
{
|
||||
gc_stats *s = &stats[collecting_gen];
|
||||
|
||||
gc_stats *s = &stats[current_gc->collecting_gen];
|
||||
|
||||
cell gc_elapsed = (current_micros() - current_gc->start_time);
|
||||
s->collections++;
|
||||
s->gc_time += gc_elapsed;
|
||||
if(s->max_gc_time < gc_elapsed)
|
||||
s->max_gc_time = gc_elapsed;
|
||||
|
||||
if(growing_data_heap)
|
||||
{
|
||||
delete old_data_heap;
|
||||
old_data_heap = NULL;
|
||||
growing_data_heap = false;
|
||||
}
|
||||
if(current_gc->growing_data_heap)
|
||||
delete current_gc->old_data_heap;
|
||||
|
||||
if(collecting_accumulation_gen_p())
|
||||
{
|
||||
/* all younger generations except are now empty.
|
||||
if collecting_gen == data->nursery() here, we only have 1 generation;
|
||||
old-school Cheney collector */
|
||||
if(collecting_gen != data->nursery())
|
||||
reset_generations(data->nursery(),collecting_gen - 1);
|
||||
}
|
||||
else if(collecting_gen == data->nursery())
|
||||
if(current_gc->collecting_nursery_p())
|
||||
{
|
||||
nursery.here = nursery.start;
|
||||
}
|
||||
else if(current_gc->collecting_accumulation_gen_p())
|
||||
{
|
||||
reset_generations(data->nursery(),current_gc->collecting_gen - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* all generations up to and including the one
|
||||
collected are now empty */
|
||||
reset_generations(data->nursery(),collecting_gen);
|
||||
reset_generations(data->nursery(),current_gc->collecting_gen);
|
||||
}
|
||||
|
||||
collecting_aging_again = false;
|
||||
}
|
||||
|
||||
/* Collect gen and all younger generations.
|
||||
If growing_data_heap_ is true, we must grow the data heap to such a size that
|
||||
an allocation of requested_bytes won't fail */
|
||||
void factor_vm::garbage_collection(cell gen,bool growing_data_heap_,cell requested_bytes)
|
||||
void factor_vm::garbage_collection(cell collecting_gen_, bool growing_data_heap_, bool trace_contexts_, cell requested_bytes)
|
||||
{
|
||||
if(gc_off)
|
||||
{
|
||||
critical_error("GC disabled",gen);
|
||||
critical_error("GC disabled",collecting_gen_);
|
||||
return;
|
||||
}
|
||||
|
||||
u64 start = current_micros();
|
||||
current_gc = new gc_state(data,growing_data_heap_,collecting_gen_);
|
||||
|
||||
performing_gc = true;
|
||||
growing_data_heap = growing_data_heap_;
|
||||
collecting_gen = gen;
|
||||
|
||||
/* we come back here if a generation is full */
|
||||
if(setjmp(gc_jmp))
|
||||
/* Keep trying to GC higher and higher generations until we don't run out
|
||||
of space */
|
||||
for(;;)
|
||||
{
|
||||
/* We have no older generations we can try collecting, so we
|
||||
resort to growing the data heap */
|
||||
if(collecting_gen == data->tenured())
|
||||
try
|
||||
{
|
||||
growing_data_heap = true;
|
||||
begin_gc(requested_bytes);
|
||||
|
||||
/* see the comment in unmark_marked() */
|
||||
code->unmark_marked();
|
||||
/* Initialize chase pointer */
|
||||
cell scan = current_gc->newspace->here;
|
||||
|
||||
/* Trace objects referenced from global environment */
|
||||
trace_roots();
|
||||
|
||||
/* Trace objects referenced from stacks, unless we're doing
|
||||
save-image-and-exit in which case stack objects are irrelevant */
|
||||
if(trace_contexts_) trace_contexts();
|
||||
|
||||
/* Trace objects referenced from older generations */
|
||||
trace_cards();
|
||||
|
||||
/* On minor GC, trace code heap roots if it has pointers
|
||||
to this generation or younger. Otherwise, tracing data heap objects
|
||||
will mark all reachable code blocks, and we free the unmarked ones
|
||||
after. */
|
||||
if(!current_gc->collecting_tenured_p() && current_gc->collecting_gen >= last_code_heap_scan)
|
||||
{
|
||||
update_code_heap_roots();
|
||||
}
|
||||
|
||||
/* do some copying -- this is where most of the work is done */
|
||||
copy_reachable_objects(scan,¤t_gc->newspace->here);
|
||||
|
||||
/* On minor GC, update literal references in code blocks, now that all
|
||||
data heap objects are in their final location. On a major GC,
|
||||
free all code blocks that did not get marked during tracing. */
|
||||
if(current_gc->collecting_tenured_p())
|
||||
free_unmarked_code_blocks();
|
||||
else
|
||||
update_dirty_code_blocks();
|
||||
|
||||
/* GC completed without any generations filling up; finish up */
|
||||
break;
|
||||
}
|
||||
/* we try collecting aging space twice before going on to
|
||||
collect tenured */
|
||||
else if(data->have_aging_p()
|
||||
&& collecting_gen == data->aging()
|
||||
&& !collecting_aging_again)
|
||||
catch(const generation_full_condition &c)
|
||||
{
|
||||
collecting_aging_again = true;
|
||||
}
|
||||
/* Collect the next oldest generation */
|
||||
else
|
||||
{
|
||||
collecting_gen++;
|
||||
/* We come back here if a generation is full */
|
||||
|
||||
/* We have no older generations we can try collecting, so we
|
||||
resort to growing the data heap */
|
||||
if(current_gc->collecting_tenured_p())
|
||||
{
|
||||
current_gc->growing_data_heap = true;
|
||||
|
||||
/* see the comment in unmark_marked() */
|
||||
code->unmark_marked();
|
||||
}
|
||||
/* we try collecting aging space twice before going on to
|
||||
collect tenured */
|
||||
else if(data->have_aging_p()
|
||||
&& current_gc->collecting_gen == data->aging()
|
||||
&& !current_gc->collecting_aging_again)
|
||||
{
|
||||
current_gc->collecting_aging_again = true;
|
||||
}
|
||||
/* Collect the next oldest generation */
|
||||
else
|
||||
{
|
||||
current_gc->collecting_gen++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
begin_gc(requested_bytes);
|
||||
end_gc();
|
||||
|
||||
/* initialize chase pointer */
|
||||
cell scan = newspace->here;
|
||||
|
||||
/* collect objects referenced from stacks and environment */
|
||||
copy_roots();
|
||||
/* collect objects referenced from older generations */
|
||||
copy_cards();
|
||||
|
||||
/* do some tracing */
|
||||
copy_reachable_objects(scan,&newspace->here);
|
||||
|
||||
/* don't scan code heap unless it has pointers to this
|
||||
generation or younger */
|
||||
if(collecting_gen >= last_code_heap_scan)
|
||||
{
|
||||
code_heap_scans++;
|
||||
|
||||
if(collecting_gen == data->tenured())
|
||||
code->free_unmarked((heap_iterator)&factor_vm::update_literal_and_word_references);
|
||||
else
|
||||
copy_code_heap_roots();
|
||||
|
||||
if(collecting_accumulation_gen_p())
|
||||
last_code_heap_scan = collecting_gen;
|
||||
else
|
||||
last_code_heap_scan = collecting_gen + 1;
|
||||
}
|
||||
|
||||
cell gc_elapsed = (current_micros() - start);
|
||||
|
||||
end_gc(gc_elapsed);
|
||||
|
||||
performing_gc = false;
|
||||
delete current_gc;
|
||||
current_gc = NULL;
|
||||
}
|
||||
|
||||
void factor_vm::gc()
|
||||
{
|
||||
garbage_collection(data->tenured(),false,0);
|
||||
garbage_collection(data->tenured(),false,true,0);
|
||||
}
|
||||
|
||||
void factor_vm::primitive_gc()
|
||||
|
@ -655,7 +714,7 @@ void factor_vm::inline_gc(cell *gc_roots_base, cell gc_roots_size)
|
|||
for(cell i = 0; i < gc_roots_size; i++)
|
||||
gc_locals.push_back((cell)&gc_roots_base[i]);
|
||||
|
||||
garbage_collection(data->nursery(),false,0);
|
||||
garbage_collection(data->nursery(),false,true,0);
|
||||
|
||||
for(cell i = 0; i < gc_roots_size; i++)
|
||||
gc_locals.pop_back();
|
||||
|
@ -693,7 +752,7 @@ object *factor_vm::allot_object(header header, cell size)
|
|||
{
|
||||
/* If there is insufficient room, collect the nursery */
|
||||
if(nursery.here + allot_buffer_zone + size > nursery.end)
|
||||
garbage_collection(data->nursery(),false,0);
|
||||
garbage_collection(data->nursery(),false,true,0);
|
||||
|
||||
cell h = nursery.here;
|
||||
nursery.here = h + align8(size);
|
||||
|
@ -715,7 +774,7 @@ object *factor_vm::allot_object(header header, cell size)
|
|||
/* If it still won't fit, grow the heap */
|
||||
if(tenured->here + size > tenured->end)
|
||||
{
|
||||
garbage_collection(data->tenured(),true,size);
|
||||
garbage_collection(data->tenured(),true,true,size);
|
||||
tenured = &data->generations[data->tenured()];
|
||||
}
|
||||
|
||||
|
|
|
@ -10,12 +10,57 @@ struct gc_stats {
|
|||
u64 bytes_copied;
|
||||
};
|
||||
|
||||
struct gc_state {
|
||||
/* The data heap we're collecting */
|
||||
data_heap *data;
|
||||
|
||||
/* New objects are copied here */
|
||||
zone *newspace;
|
||||
|
||||
/* sometimes we grow the heap */
|
||||
bool growing_data_heap;
|
||||
data_heap *old_data_heap;
|
||||
|
||||
/* Which generation is being collected */
|
||||
cell collecting_gen;
|
||||
|
||||
/* If true, we are collecting aging space for the second time, so if it is still
|
||||
full, we go on to collect tenured */
|
||||
bool collecting_aging_again;
|
||||
|
||||
/* A set of code blocks which need to have their literals updated */
|
||||
std::set<code_block *> dirty_code_blocks;
|
||||
|
||||
/* GC start time, for benchmarking */
|
||||
u64 start_time;
|
||||
|
||||
explicit gc_state(data_heap *data_, bool growing_data_heap_, cell collecting_gen_);
|
||||
~gc_state();
|
||||
|
||||
inline bool collecting_nursery_p()
|
||||
{
|
||||
return collecting_gen == data->nursery();
|
||||
}
|
||||
|
||||
inline bool collecting_tenured_p()
|
||||
{
|
||||
return collecting_gen == data->tenured();
|
||||
}
|
||||
|
||||
inline bool collecting_accumulation_gen_p()
|
||||
{
|
||||
return ((data->have_aging_p()
|
||||
&& collecting_gen == data->aging()
|
||||
&& !collecting_aging_again)
|
||||
|| collecting_gen == data->tenured());
|
||||
}
|
||||
};
|
||||
|
||||
/* We leave this many bytes free at the top of the nursery so that inline
|
||||
allocation (which does not call GC because of possible roots in volatile
|
||||
registers) does not run out of memory */
|
||||
static const cell allot_buffer_zone = 1024;
|
||||
|
||||
struct factor_vm;
|
||||
VM_C_API void inline_gc(cell *gc_roots_base, cell gc_roots_size, factor_vm *myvm);
|
||||
|
||||
}
|
||||
|
|
|
@ -310,12 +310,12 @@ void factor_vm::primitive_end_scan()
|
|||
gc_off = false;
|
||||
}
|
||||
|
||||
template<typename TYPE> void factor_vm::each_object(TYPE &functor)
|
||||
template<typename Iterator> void factor_vm::each_object(Iterator &iterator)
|
||||
{
|
||||
begin_scan();
|
||||
cell obj;
|
||||
while((obj = next_object()) != F)
|
||||
functor(tagged<object>(obj));
|
||||
iterator(tagged<object>(obj));
|
||||
end_scan();
|
||||
}
|
||||
|
||||
|
@ -324,13 +324,13 @@ namespace
|
|||
|
||||
struct word_counter {
|
||||
cell count;
|
||||
word_counter() : count(0) {}
|
||||
explicit word_counter() : count(0) {}
|
||||
void operator()(tagged<object> obj) { if(obj.type_p(WORD_TYPE)) count++; }
|
||||
};
|
||||
|
||||
struct word_accumulator {
|
||||
growable_array words;
|
||||
word_accumulator(int count,factor_vm *vm) : words(vm,count) {}
|
||||
explicit word_accumulator(int count,factor_vm *vm) : words(vm,count) {}
|
||||
void operator()(tagged<object> obj) { if(obj.type_p(WORD_TYPE)) words.add(obj.value()); }
|
||||
};
|
||||
|
||||
|
|
|
@ -51,7 +51,7 @@ struct data_heap {
|
|||
|
||||
bool have_aging_p() { return gen_count > 2; }
|
||||
|
||||
data_heap(factor_vm *myvm, cell gen_count, cell young_size, cell aging_size, cell tenured_size);
|
||||
explicit data_heap(factor_vm *myvm, cell gen_count, cell young_size, cell aging_size, cell tenured_size);
|
||||
~data_heap();
|
||||
};
|
||||
|
||||
|
|
83
vm/debug.cpp
83
vm/debug.cpp
|
@ -164,34 +164,35 @@ void factor_vm::print_retainstack()
|
|||
print_objects((cell *)rs_bot,(cell *)rs);
|
||||
}
|
||||
|
||||
void factor_vm::print_stack_frame(stack_frame *frame)
|
||||
{
|
||||
print_obj(frame_executing(frame));
|
||||
print_string("\n");
|
||||
print_obj(frame_scan(frame));
|
||||
print_string("\n");
|
||||
print_string("word/quot addr: ");
|
||||
print_cell_hex((cell)frame_executing(frame));
|
||||
print_string("\n");
|
||||
print_string("word/quot xt: ");
|
||||
print_cell_hex((cell)frame->xt);
|
||||
print_string("\n");
|
||||
print_string("return address: ");
|
||||
print_cell_hex((cell)FRAME_RETURN_ADDRESS(frame));
|
||||
print_string("\n");
|
||||
}
|
||||
struct stack_frame_printer {
|
||||
factor_vm *myvm;
|
||||
|
||||
void print_stack_frame(stack_frame *frame, factor_vm *myvm)
|
||||
{
|
||||
return myvm->print_stack_frame(frame);
|
||||
}
|
||||
explicit stack_frame_printer(factor_vm *myvm_) : myvm(myvm_) {}
|
||||
void operator()(stack_frame *frame)
|
||||
{
|
||||
myvm->print_obj(myvm->frame_executing(frame));
|
||||
print_string("\n");
|
||||
myvm->print_obj(myvm->frame_scan(frame));
|
||||
print_string("\n");
|
||||
print_string("word/quot addr: ");
|
||||
print_cell_hex((cell)myvm->frame_executing(frame));
|
||||
print_string("\n");
|
||||
print_string("word/quot xt: ");
|
||||
print_cell_hex((cell)frame->xt);
|
||||
print_string("\n");
|
||||
print_string("return address: ");
|
||||
print_cell_hex((cell)FRAME_RETURN_ADDRESS(frame,myvm));
|
||||
print_string("\n");
|
||||
}
|
||||
};
|
||||
|
||||
void factor_vm::print_callstack()
|
||||
{
|
||||
print_string("==== CALL STACK:\n");
|
||||
cell bottom = (cell)stack_chain->callstack_bottom;
|
||||
cell top = (cell)stack_chain->callstack_top;
|
||||
iterate_callstack(top,bottom,factor::print_stack_frame);
|
||||
stack_frame_printer printer(this);
|
||||
iterate_callstack(top,bottom,printer);
|
||||
}
|
||||
|
||||
void factor_vm::dump_cell(cell x)
|
||||
|
@ -263,30 +264,36 @@ void factor_vm::dump_objects(cell type)
|
|||
end_scan();
|
||||
}
|
||||
|
||||
void factor_vm::find_data_references_step(cell *scan)
|
||||
{
|
||||
if(look_for == *scan)
|
||||
struct data_references_finder {
|
||||
cell look_for, obj;
|
||||
factor_vm *myvm;
|
||||
|
||||
explicit data_references_finder(cell look_for_, cell obj_, factor_vm *myvm_)
|
||||
: look_for(look_for_), obj(obj_), myvm(myvm_) { }
|
||||
|
||||
void operator()(cell *scan)
|
||||
{
|
||||
print_cell_hex_pad(obj);
|
||||
print_string(" ");
|
||||
print_nested_obj(obj,2);
|
||||
nl();
|
||||
if(look_for == *scan)
|
||||
{
|
||||
print_cell_hex_pad(obj);
|
||||
print_string(" ");
|
||||
myvm->print_nested_obj(obj,2);
|
||||
nl();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void find_data_references_step(cell *scan,factor_vm *myvm)
|
||||
void factor_vm::find_data_references(cell look_for)
|
||||
{
|
||||
return myvm->find_data_references_step(scan);
|
||||
}
|
||||
|
||||
void factor_vm::find_data_references(cell look_for_)
|
||||
{
|
||||
look_for = look_for_;
|
||||
|
||||
begin_scan();
|
||||
|
||||
cell obj;
|
||||
|
||||
while((obj = next_object()) != F)
|
||||
do_slots(UNTAG(obj),factor::find_data_references_step);
|
||||
{
|
||||
data_references_finder finder(look_for,obj,this);
|
||||
do_slots(UNTAG(obj),finder);
|
||||
}
|
||||
|
||||
end_scan();
|
||||
}
|
||||
|
|
|
@ -222,7 +222,7 @@ struct startargs {
|
|||
vm_char **argv;
|
||||
};
|
||||
|
||||
factor_vm * new_factor_vm()
|
||||
factor_vm *new_factor_vm()
|
||||
{
|
||||
factor_vm *newvm = new factor_vm;
|
||||
register_vm_with_thread(newvm);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
namespace factor
|
||||
{
|
||||
|
||||
template<typename T> cell array_capacity(T *array)
|
||||
template<typename Array> cell array_capacity(Array *array)
|
||||
{
|
||||
#ifdef FACTOR_DEBUG
|
||||
assert(array->h.hi_tag() == T::type_number);
|
||||
|
@ -9,31 +9,31 @@ template<typename T> cell array_capacity(T *array)
|
|||
return array->capacity >> TAG_BITS;
|
||||
}
|
||||
|
||||
template <typename T> cell array_size(cell capacity)
|
||||
template<typename Array> cell array_size(cell capacity)
|
||||
{
|
||||
return sizeof(T) + capacity * T::element_size;
|
||||
return sizeof(Array) + capacity * Array::element_size;
|
||||
}
|
||||
|
||||
template <typename T> cell array_size(T *array)
|
||||
template<typename Array> cell array_size(Array *array)
|
||||
{
|
||||
return array_size<T>(array_capacity(array));
|
||||
return array_size<Array>(array_capacity(array));
|
||||
}
|
||||
|
||||
template <typename TYPE> TYPE *factor_vm::allot_array_internal(cell capacity)
|
||||
template<typename Array> Array *factor_vm::allot_array_internal(cell capacity)
|
||||
{
|
||||
TYPE *array = allot<TYPE>(array_size<TYPE>(capacity));
|
||||
Array *array = allot<Array>(array_size<Array>(capacity));
|
||||
array->capacity = tag_fixnum(capacity);
|
||||
return array;
|
||||
}
|
||||
|
||||
template <typename TYPE> bool factor_vm::reallot_array_in_place_p(TYPE *array, cell capacity)
|
||||
template<typename Array> bool factor_vm::reallot_array_in_place_p(Array *array, cell capacity)
|
||||
{
|
||||
return in_zone(&nursery,array) && capacity <= array_capacity(array);
|
||||
}
|
||||
|
||||
template <typename TYPE> TYPE *factor_vm::reallot_array(TYPE *array_, cell capacity)
|
||||
template<typename Array> Array *factor_vm::reallot_array(Array *array_, cell capacity)
|
||||
{
|
||||
gc_root<TYPE> array(array_,this);
|
||||
gc_root<Array> array(array_,this);
|
||||
|
||||
if(reallot_array_in_place_p(array.untagged(),capacity))
|
||||
{
|
||||
|
@ -46,11 +46,11 @@ template <typename TYPE> TYPE *factor_vm::reallot_array(TYPE *array_, cell capac
|
|||
if(capacity < to_copy)
|
||||
to_copy = capacity;
|
||||
|
||||
TYPE *new_array = allot_array_internal<TYPE>(capacity);
|
||||
Array *new_array = allot_array_internal<Array>(capacity);
|
||||
|
||||
memcpy(new_array + 1,array.untagged() + 1,to_copy * TYPE::element_size);
|
||||
memset((char *)(new_array + 1) + to_copy * TYPE::element_size,
|
||||
0,(capacity - to_copy) * TYPE::element_size);
|
||||
memcpy(new_array + 1,array.untagged() + 1,to_copy * Array::element_size);
|
||||
memset((char *)(new_array + 1) + to_copy * Array::element_size,
|
||||
0,(capacity - to_copy) * Array::element_size);
|
||||
|
||||
return new_array;
|
||||
}
|
||||
|
|
66
vm/heap.cpp
66
vm/heap.cpp
|
@ -208,55 +208,6 @@ void heap::unmark_marked()
|
|||
}
|
||||
}
|
||||
|
||||
/* After code GC, all referenced code blocks have status set to B_MARKED, so any
|
||||
which are allocated and not marked can be reclaimed. */
|
||||
void heap::free_unmarked(heap_iterator iter)
|
||||
{
|
||||
clear_free_list();
|
||||
|
||||
heap_block *prev = NULL;
|
||||
heap_block *scan = first_block();
|
||||
|
||||
while(scan)
|
||||
{
|
||||
switch(scan->status)
|
||||
{
|
||||
case B_ALLOCATED:
|
||||
if(myvm->secure_gc)
|
||||
memset(scan + 1,0,scan->size - sizeof(heap_block));
|
||||
|
||||
if(prev && prev->status == B_FREE)
|
||||
prev->size += scan->size;
|
||||
else
|
||||
{
|
||||
scan->status = B_FREE;
|
||||
prev = scan;
|
||||
}
|
||||
break;
|
||||
case B_FREE:
|
||||
if(prev && prev->status == B_FREE)
|
||||
prev->size += scan->size;
|
||||
else
|
||||
prev = scan;
|
||||
break;
|
||||
case B_MARKED:
|
||||
if(prev && prev->status == B_FREE)
|
||||
add_to_free_list((free_heap_block *)prev);
|
||||
scan->status = B_ALLOCATED;
|
||||
prev = scan;
|
||||
(myvm->*iter)(scan);
|
||||
break;
|
||||
default:
|
||||
myvm->critical_error("Invalid scan->status",(cell)scan);
|
||||
}
|
||||
|
||||
scan = next_block(scan);
|
||||
}
|
||||
|
||||
if(prev && prev->status == B_FREE)
|
||||
add_to_free_list((free_heap_block *)prev);
|
||||
}
|
||||
|
||||
/* Compute total sum of sizes of free blocks, and size of largest free block */
|
||||
void heap::heap_usage(cell *used, cell *total_free, cell *max_free)
|
||||
{
|
||||
|
@ -338,4 +289,21 @@ void heap::compact_heap(unordered_map<heap_block *,char *> &forwarding)
|
|||
}
|
||||
}
|
||||
|
||||
heap_block *heap::free_allocated(heap_block *prev, heap_block *scan)
|
||||
{
|
||||
if(myvm->secure_gc)
|
||||
memset(scan + 1,0,scan->size - sizeof(heap_block));
|
||||
|
||||
if(prev && prev->status == B_FREE)
|
||||
{
|
||||
prev->size += scan->size;
|
||||
return prev;
|
||||
}
|
||||
else
|
||||
{
|
||||
scan->status = B_FREE;
|
||||
return scan;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
44
vm/heap.hpp
44
vm/heap.hpp
|
@ -9,14 +9,12 @@ struct heap_free_list {
|
|||
free_heap_block *large_blocks;
|
||||
};
|
||||
|
||||
typedef void (factor_vm::*heap_iterator)(heap_block *compiled);
|
||||
|
||||
struct heap {
|
||||
factor_vm *myvm;
|
||||
segment *seg;
|
||||
heap_free_list free;
|
||||
|
||||
heap(factor_vm *myvm, cell size);
|
||||
explicit heap(factor_vm *myvm, cell size);
|
||||
|
||||
inline heap_block *next_block(heap_block *block)
|
||||
{
|
||||
|
@ -48,12 +46,50 @@ struct heap {
|
|||
void heap_free(heap_block *block);
|
||||
void mark_block(heap_block *block);
|
||||
void unmark_marked();
|
||||
void free_unmarked(heap_iterator iter);
|
||||
void heap_usage(cell *used, cell *total_free, cell *max_free);
|
||||
cell heap_size();
|
||||
cell compute_heap_forwarding(unordered_map<heap_block *,char *> &forwarding);
|
||||
void compact_heap(unordered_map<heap_block *,char *> &forwarding);
|
||||
|
||||
heap_block *free_allocated(heap_block *prev, heap_block *scan);
|
||||
|
||||
/* After code GC, all referenced code blocks have status set to B_MARKED, so any
|
||||
which are allocated and not marked can be reclaimed. */
|
||||
template<typename Iterator> void free_unmarked(Iterator &iter)
|
||||
{
|
||||
clear_free_list();
|
||||
|
||||
heap_block *prev = NULL;
|
||||
heap_block *scan = first_block();
|
||||
|
||||
while(scan)
|
||||
{
|
||||
switch(scan->status)
|
||||
{
|
||||
case B_ALLOCATED:
|
||||
prev = free_allocated(prev,scan);
|
||||
break;
|
||||
case B_FREE:
|
||||
if(prev && prev->status == B_FREE)
|
||||
prev->size += scan->size;
|
||||
else
|
||||
prev = scan;
|
||||
break;
|
||||
case B_MARKED:
|
||||
if(prev && prev->status == B_FREE)
|
||||
add_to_free_list((free_heap_block *)prev);
|
||||
scan->status = B_ALLOCATED;
|
||||
prev = scan;
|
||||
iter(scan);
|
||||
break;
|
||||
}
|
||||
|
||||
scan = next_block(scan);
|
||||
}
|
||||
|
||||
if(prev && prev->status == B_FREE)
|
||||
add_to_free_list((free_heap_block *)prev);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
|
65
vm/image.cpp
65
vm/image.cpp
|
@ -143,9 +143,7 @@ void factor_vm::primitive_save_image_and_exit()
|
|||
}
|
||||
|
||||
/* do a full GC + code heap compaction */
|
||||
performing_compaction = true;
|
||||
compact_code_heap();
|
||||
performing_compaction = false;
|
||||
|
||||
/* Save the image */
|
||||
if(save_image((vm_char *)(path.untagged() + 1)))
|
||||
|
@ -163,15 +161,10 @@ void factor_vm::data_fixup(cell *cell)
|
|||
*cell += (tenured->start - data_relocation_base);
|
||||
}
|
||||
|
||||
void data_fixup(cell *cell, factor_vm *myvm)
|
||||
template<typename Type> void factor_vm::code_fixup(Type **handle)
|
||||
{
|
||||
return myvm->data_fixup(cell);
|
||||
}
|
||||
|
||||
template <typename TYPE> void factor_vm::code_fixup(TYPE **handle)
|
||||
{
|
||||
TYPE *ptr = *handle;
|
||||
TYPE *new_ptr = (TYPE *)(((cell)ptr) + (code->seg->start - code_relocation_base));
|
||||
Type *ptr = *handle;
|
||||
Type *new_ptr = (Type *)(((cell)ptr) + (code->seg->start - code_relocation_base));
|
||||
*handle = new_ptr;
|
||||
}
|
||||
|
||||
|
@ -200,22 +193,34 @@ void factor_vm::fixup_alien(alien *d)
|
|||
d->expired = T;
|
||||
}
|
||||
|
||||
void factor_vm::fixup_stack_frame(stack_frame *frame)
|
||||
{
|
||||
code_fixup(&frame->xt);
|
||||
code_fixup(&FRAME_RETURN_ADDRESS(frame));
|
||||
}
|
||||
struct stack_frame_fixupper {
|
||||
factor_vm *myvm;
|
||||
|
||||
void fixup_stack_frame(stack_frame *frame, factor_vm *myvm)
|
||||
{
|
||||
return myvm->fixup_stack_frame(frame);
|
||||
}
|
||||
explicit stack_frame_fixupper(factor_vm *myvm_) : myvm(myvm_) {}
|
||||
void operator()(stack_frame *frame)
|
||||
{
|
||||
myvm->code_fixup(&frame->xt);
|
||||
myvm->code_fixup(&FRAME_RETURN_ADDRESS(frame,myvm));
|
||||
}
|
||||
};
|
||||
|
||||
void factor_vm::fixup_callstack_object(callstack *stack)
|
||||
{
|
||||
iterate_callstack_object(stack,factor::fixup_stack_frame);
|
||||
stack_frame_fixupper fixupper(this);
|
||||
iterate_callstack_object(stack,fixupper);
|
||||
}
|
||||
|
||||
struct object_fixupper {
|
||||
factor_vm *myvm;
|
||||
|
||||
explicit object_fixupper(factor_vm *myvm_) : myvm(myvm_) { }
|
||||
|
||||
void operator()(cell *scan)
|
||||
{
|
||||
myvm->data_fixup(scan);
|
||||
}
|
||||
};
|
||||
|
||||
/* Initialize an object in a newly-loaded image */
|
||||
void factor_vm::relocate_object(object *object)
|
||||
{
|
||||
|
@ -237,7 +242,8 @@ void factor_vm::relocate_object(object *object)
|
|||
}
|
||||
else
|
||||
{
|
||||
do_slots((cell)object,factor::data_fixup);
|
||||
object_fixupper fixupper(this);
|
||||
do_slots((cell)object,fixupper);
|
||||
|
||||
switch(hi_tag)
|
||||
{
|
||||
|
@ -296,14 +302,21 @@ void factor_vm::fixup_code_block(code_block *compiled)
|
|||
relocate_code_block(compiled);
|
||||
}
|
||||
|
||||
void fixup_code_block(code_block *compiled, factor_vm *myvm)
|
||||
{
|
||||
return myvm->fixup_code_block(compiled);
|
||||
}
|
||||
struct code_block_fixupper {
|
||||
factor_vm *myvm;
|
||||
|
||||
code_block_fixupper(factor_vm *myvm_) : myvm(myvm_) { }
|
||||
|
||||
void operator()(code_block *compiled)
|
||||
{
|
||||
myvm->fixup_code_block(compiled);
|
||||
}
|
||||
};
|
||||
|
||||
void factor_vm::relocate_code()
|
||||
{
|
||||
iterate_code_heap(&factor_vm::fixup_code_block);
|
||||
code_block_fixupper fixupper(this);
|
||||
iterate_code_heap(fixupper);
|
||||
}
|
||||
|
||||
/* Read an image file from disk, only done once during startup */
|
||||
|
|
|
@ -74,7 +74,7 @@ void factor_vm::update_pic_count(cell type)
|
|||
struct inline_cache_jit : public jit {
|
||||
fixnum index;
|
||||
|
||||
inline_cache_jit(cell generic_word_,factor_vm *vm) : jit(PIC_TYPE,generic_word_,vm) {};
|
||||
explicit inline_cache_jit(cell generic_word_,factor_vm *vm) : jit(PIC_TYPE,generic_word_,vm) {};
|
||||
|
||||
void emit_check(cell klass);
|
||||
void compile_inline_cache(fixnum index,
|
||||
|
|
|
@ -12,7 +12,7 @@ struct jit {
|
|||
cell offset;
|
||||
factor_vm *parent_vm;
|
||||
|
||||
jit(cell jit_type, cell owner, factor_vm *vm);
|
||||
explicit jit(cell jit_type, cell owner, factor_vm *vm);
|
||||
void compute_position(cell offset);
|
||||
|
||||
void emit_relocation(cell code_template);
|
||||
|
|
|
@ -106,9 +106,9 @@ struct header {
|
|||
cell value;
|
||||
|
||||
/* Default ctor to make gcc 3.x happy */
|
||||
header() { abort(); }
|
||||
explicit header() { abort(); }
|
||||
|
||||
header(cell value_) : value(value_ << TAG_BITS) {}
|
||||
explicit header(cell value_) : value(value_ << TAG_BITS) {}
|
||||
|
||||
void check_header() {
|
||||
#ifdef FACTOR_DEBUG
|
||||
|
@ -179,7 +179,7 @@ struct byte_array : public object {
|
|||
/* tagged */
|
||||
cell capacity;
|
||||
|
||||
template<typename T> T *data() { return (T *)(this + 1); }
|
||||
template<typename Scalar> Scalar *data() { return (Scalar *)(this + 1); }
|
||||
};
|
||||
|
||||
/* Assembly code makes assumptions about the layout of this struct */
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
namespace factor
|
||||
{
|
||||
|
||||
template <typename TYPE>
|
||||
struct gc_root : public tagged<TYPE>
|
||||
template<typename Type>
|
||||
struct gc_root : public tagged<Type>
|
||||
{
|
||||
factor_vm *parent_vm;
|
||||
|
||||
void push() { parent_vm->check_tagged_pointer(tagged<TYPE>::value()); parent_vm->gc_locals.push_back((cell)this); }
|
||||
void push() { parent_vm->check_tagged_pointer(tagged<Type>::value()); parent_vm->gc_locals.push_back((cell)this); }
|
||||
|
||||
explicit gc_root(cell value_,factor_vm *vm) : tagged<TYPE>(value_),parent_vm(vm) { push(); }
|
||||
explicit gc_root(TYPE *value_, factor_vm *vm) : tagged<TYPE>(value_),parent_vm(vm) { push(); }
|
||||
explicit gc_root(cell value_,factor_vm *vm) : tagged<Type>(value_),parent_vm(vm) { push(); }
|
||||
explicit gc_root(Type *value_, factor_vm *vm) : tagged<Type>(value_),parent_vm(vm) { push(); }
|
||||
|
||||
const gc_root<TYPE>& operator=(const TYPE *x) { tagged<TYPE>::operator=(x); return *this; }
|
||||
const gc_root<TYPE>& operator=(const cell &x) { tagged<TYPE>::operator=(x); return *this; }
|
||||
const gc_root<Type>& operator=(const Type *x) { tagged<Type>::operator=(x); return *this; }
|
||||
const gc_root<Type>& operator=(const cell &x) { tagged<Type>::operator=(x); return *this; }
|
||||
|
||||
~gc_root() {
|
||||
#ifdef FACTOR_DEBUG
|
||||
|
|
|
@ -25,23 +25,32 @@
|
|||
|
||||
/* C++ headers */
|
||||
#include <vector>
|
||||
#include <set>
|
||||
|
||||
#if __GNUC__ == 4
|
||||
#include <tr1/unordered_map>
|
||||
|
||||
namespace factor {
|
||||
using std::tr1::unordered_map;
|
||||
}
|
||||
namespace factor
|
||||
{
|
||||
using std::tr1::unordered_map;
|
||||
}
|
||||
#elif __GNUC__ == 3
|
||||
#include <boost/unordered_map.hpp>
|
||||
|
||||
namespace factor {
|
||||
using boost::unordered_map;
|
||||
}
|
||||
namespace factor
|
||||
{
|
||||
using boost::unordered_map;
|
||||
}
|
||||
#else
|
||||
#error Factor requires GCC 3.x or later
|
||||
#endif
|
||||
|
||||
/* Forward-declare this since it comes up in function prototypes */
|
||||
namespace factor
|
||||
{
|
||||
struct factor_vm;
|
||||
}
|
||||
|
||||
/* Factor headers */
|
||||
#include "layouts.hpp"
|
||||
#include "platform.hpp"
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
namespace factor
|
||||
{
|
||||
|
||||
#define FRAME_RETURN_ADDRESS(frame) *((void **)(frame_successor(frame) + 1) + 1)
|
||||
#define FRAME_RETURN_ADDRESS(frame,vm) *((void **)(vm->frame_successor(frame) + 1) + 1)
|
||||
|
||||
inline static void *ucontext_stack_pointer(void *uap)
|
||||
{
|
||||
|
|
|
@ -13,7 +13,7 @@ Used under BSD license with permission from Paolo Bonzini and Bruno Haible,
|
|||
http://sourceforge.net/mailarchive/message.php?msg_name=200503102200.32002.bruno%40clisp.org
|
||||
|
||||
Modified for Factor by Slava Pestov */
|
||||
#define FRAME_RETURN_ADDRESS(frame) *((void **)(frame_successor(frame) + 1) + 2)
|
||||
#define FRAME_RETURN_ADDRESS(frame,vm) *((void **)(vm->frame_successor(frame) + 1) + 2)
|
||||
|
||||
#define MACH_EXC_STATE_TYPE ppc_exception_state_t
|
||||
#define MACH_EXC_STATE_FLAVOR PPC_EXCEPTION_STATE
|
||||
|
|
|
@ -55,8 +55,9 @@ s64 current_micros();
|
|||
void sleep_micros(cell usec);
|
||||
|
||||
void init_platform_globals();
|
||||
struct factor_vm;
|
||||
|
||||
void register_vm_with_thread(factor_vm *vm);
|
||||
factor_vm *tls_vm();
|
||||
void open_console();
|
||||
|
||||
}
|
||||
|
|
|
@ -32,7 +32,6 @@ THREADHANDLE start_thread(void *(*start_routine)(void *),void *args);
|
|||
inline static THREADHANDLE thread_id() { return GetCurrentThread(); }
|
||||
|
||||
void init_platform_globals();
|
||||
struct factor_vm;
|
||||
void register_vm_with_thread(factor_vm *vm);
|
||||
factor_vm *tls_vm();
|
||||
|
||||
|
|
|
@ -44,7 +44,8 @@ void factor_vm::set_profiling(bool profiling)
|
|||
}
|
||||
|
||||
/* Update XTs in code heap */
|
||||
iterate_code_heap(&factor_vm::relocate_code_block);
|
||||
word_updater updater(this);
|
||||
iterate_code_heap(updater);
|
||||
}
|
||||
|
||||
void factor_vm::primitive_profiling()
|
||||
|
|
|
@ -330,7 +330,9 @@ void factor_vm::compile_all_words()
|
|||
|
||||
}
|
||||
|
||||
iterate_code_heap(&factor_vm::relocate_code_block);
|
||||
/* Update XTs in code heap */
|
||||
word_updater updater(this);
|
||||
iterate_code_heap(updater);
|
||||
}
|
||||
|
||||
/* Allocates memory */
|
||||
|
|
|
@ -5,7 +5,7 @@ struct quotation_jit : public jit {
|
|||
gc_root<array> elements;
|
||||
bool compiling, relocate;
|
||||
|
||||
quotation_jit(cell quot, bool compiling_, bool relocate_, factor_vm *vm)
|
||||
explicit quotation_jit(cell quot, bool compiling_, bool relocate_, factor_vm *vm)
|
||||
: jit(QUOTATION_TYPE,quot,vm),
|
||||
elements(owner.as<quotation>().untagged()->array,vm),
|
||||
compiling(compiling_),
|
||||
|
|
|
@ -58,7 +58,7 @@ cell factor_vm::clone_object(cell obj_)
|
|||
else
|
||||
{
|
||||
cell size = object_size(obj.value());
|
||||
object *new_obj = allot_object(obj.type(),size);
|
||||
object *new_obj = allot_object(header(obj.type()),size);
|
||||
memcpy(new_obj,obj.untagged(),size);
|
||||
return tag_dynamic(new_obj);
|
||||
}
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
namespace factor
|
||||
{
|
||||
|
||||
struct factor_vm;
|
||||
|
||||
inline cell align_page(cell a)
|
||||
{
|
||||
return align(a,getpagesize());
|
||||
|
@ -16,7 +14,7 @@ struct segment {
|
|||
cell size;
|
||||
cell end;
|
||||
|
||||
segment(factor_vm *myvm, cell size);
|
||||
explicit segment(factor_vm *myvm, cell size);
|
||||
~segment();
|
||||
};
|
||||
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
namespace factor
|
||||
{
|
||||
|
||||
template <typename TYPE> cell tag(TYPE *value)
|
||||
template<typename Type> cell tag(Type *value)
|
||||
{
|
||||
return RETAG(value,tag_for(TYPE::type_number));
|
||||
return RETAG(value,tag_for(Type::type_number));
|
||||
}
|
||||
|
||||
inline static cell tag_dynamic(object *value)
|
||||
|
@ -11,13 +11,13 @@ inline static cell tag_dynamic(object *value)
|
|||
return RETAG(value,tag_for(value->h.hi_tag()));
|
||||
}
|
||||
|
||||
template <typename TYPE>
|
||||
template<typename Type>
|
||||
struct tagged
|
||||
{
|
||||
cell value_;
|
||||
|
||||
cell value() const { return value_; }
|
||||
TYPE *untagged() const { return (TYPE *)(UNTAG(value_)); }
|
||||
Type *untagged() const { return (Type *)(UNTAG(value_)); }
|
||||
|
||||
cell type() const {
|
||||
cell tag = TAG(value_);
|
||||
|
@ -29,9 +29,9 @@ struct tagged
|
|||
|
||||
bool type_p(cell type_) const { return type() == type_; }
|
||||
|
||||
TYPE *untag_check(factor_vm *myvm) const {
|
||||
if(TYPE::type_number != TYPE_COUNT && !type_p(TYPE::type_number))
|
||||
myvm->type_error(TYPE::type_number,value_);
|
||||
Type *untag_check(factor_vm *myvm) const {
|
||||
if(Type::type_number != TYPE_COUNT && !type_p(Type::type_number))
|
||||
myvm->type_error(Type::type_number,value_);
|
||||
return untagged();
|
||||
}
|
||||
|
||||
|
@ -41,32 +41,32 @@ struct tagged
|
|||
#endif
|
||||
}
|
||||
|
||||
explicit tagged(TYPE *untagged) : value_(factor::tag(untagged)) {
|
||||
explicit tagged(Type *untagged) : value_(factor::tag(untagged)) {
|
||||
#ifdef FACTOR_DEBUG
|
||||
untag_check(SIGNAL_VM_PTR());
|
||||
#endif
|
||||
}
|
||||
|
||||
TYPE *operator->() const { return untagged(); }
|
||||
Type *operator->() const { return untagged(); }
|
||||
cell *operator&() const { return &value_; }
|
||||
|
||||
const tagged<TYPE>& operator=(const TYPE *x) { value_ = tag(x); return *this; }
|
||||
const tagged<TYPE>& operator=(const cell &x) { value_ = x; return *this; }
|
||||
const tagged<Type> &operator=(const Type *x) { value_ = tag(x); return *this; }
|
||||
const tagged<Type> &operator=(const cell &x) { value_ = x; return *this; }
|
||||
|
||||
bool operator==(const tagged<TYPE> &x) { return value_ == x.value_; }
|
||||
bool operator!=(const tagged<TYPE> &x) { return value_ != x.value_; }
|
||||
bool operator==(const tagged<Type> &x) { return value_ == x.value_; }
|
||||
bool operator!=(const tagged<Type> &x) { return value_ != x.value_; }
|
||||
|
||||
template<typename X> tagged<X> as() { return tagged<X>(value_); }
|
||||
template<typename NewType> tagged<NewType> as() { return tagged<NewType>(value_); }
|
||||
};
|
||||
|
||||
template <typename TYPE> TYPE *factor_vm::untag_check(cell value)
|
||||
template<typename Type> Type *factor_vm::untag_check(cell value)
|
||||
{
|
||||
return tagged<TYPE>(value).untag_check(this);
|
||||
return tagged<Type>(value).untag_check(this);
|
||||
}
|
||||
|
||||
template <typename TYPE> TYPE *factor_vm::untag(cell value)
|
||||
template<typename Type> Type *factor_vm::untag(cell value)
|
||||
{
|
||||
return tagged<TYPE>(value).untagged();
|
||||
return tagged<Type>(value).untagged();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
136
vm/vm.hpp
136
vm/vm.hpp
|
@ -32,7 +32,8 @@ struct factor_vm
|
|||
void primitive_check_datastack();
|
||||
|
||||
// run
|
||||
cell T; /* Canonical T object. It's just a word */
|
||||
/* Canonical T object. It's just a word */
|
||||
cell T;
|
||||
|
||||
void primitive_getenv();
|
||||
void primitive_setenv();
|
||||
|
@ -168,7 +169,7 @@ struct factor_vm
|
|||
cell next_object();
|
||||
void primitive_next_object();
|
||||
void primitive_end_scan();
|
||||
template<typename T> void each_object(T &functor);
|
||||
template<typename Iterator> void each_object(Iterator &iterator);
|
||||
cell find_all_words();
|
||||
cell object_size(cell tagged);
|
||||
|
||||
|
@ -228,53 +229,46 @@ struct factor_vm
|
|||
|
||||
// data_gc
|
||||
/* used during garbage collection only */
|
||||
zone *newspace;
|
||||
bool performing_gc;
|
||||
bool performing_compaction;
|
||||
cell collecting_gen;
|
||||
/* if true, we are collecting aging space for the second time, so if it is still
|
||||
full, we go on to collect tenured */
|
||||
bool collecting_aging_again;
|
||||
/* in case a generation fills up in the middle of a gc, we jump back
|
||||
up to try collecting the next generation. */
|
||||
jmp_buf gc_jmp;
|
||||
gc_state *current_gc;
|
||||
/* statistics */
|
||||
gc_stats stats[max_gen_count];
|
||||
u64 cards_scanned;
|
||||
u64 decks_scanned;
|
||||
u64 card_scan_time;
|
||||
cell code_heap_scans;
|
||||
/* What generation was being collected when copy_code_heap_roots() was last
|
||||
/* What generation was being collected when trace_code_heap_roots() was last
|
||||
called? Until the next call to add_code_block(), future
|
||||
collections of younger generations don't have to touch the code
|
||||
heap. */
|
||||
cell last_code_heap_scan;
|
||||
/* sometimes we grow the heap */
|
||||
bool growing_data_heap;
|
||||
data_heap *old_data_heap;
|
||||
|
||||
void init_data_gc();
|
||||
object *copy_untagged_object_impl(object *pointer, cell size);
|
||||
object *copy_object_impl(object *untagged);
|
||||
bool should_copy_p(object *untagged);
|
||||
object *resolve_forwarding(object *untagged);
|
||||
template <typename T> T *copy_untagged_object(T *untagged);
|
||||
template<typename Type> Type *copy_untagged_object(Type *untagged);
|
||||
cell copy_object(cell pointer);
|
||||
void copy_handle(cell *handle);
|
||||
void copy_card(card *ptr, cell gen, cell here);
|
||||
void copy_card_deck(card_deck *deck, cell gen, card mask, card unmask);
|
||||
void copy_gen_cards(cell gen);
|
||||
void copy_cards();
|
||||
void copy_stack_elements(segment *region, cell top);
|
||||
void copy_registered_locals();
|
||||
void copy_registered_bignums();
|
||||
void copy_roots();
|
||||
void trace_handle(cell *handle);
|
||||
void trace_card(card *ptr, cell gen, cell here);
|
||||
void trace_card_deck(card_deck *deck, cell gen, card mask, card unmask);
|
||||
void trace_generation_cards(cell gen);
|
||||
void trace_cards();
|
||||
void trace_stack_elements(segment *region, cell top);
|
||||
void trace_registered_locals();
|
||||
void trace_registered_bignums();
|
||||
void trace_roots();
|
||||
void trace_contexts();
|
||||
void update_code_heap_roots();
|
||||
cell copy_next_from_nursery(cell scan);
|
||||
cell copy_next_from_aging(cell scan);
|
||||
cell copy_next_from_tenured(cell scan);
|
||||
void copy_reachable_objects(cell scan, cell *end);
|
||||
void free_unmarked_code_blocks();
|
||||
void update_dirty_code_blocks();
|
||||
void begin_gc(cell requested_bytes);
|
||||
void end_gc(cell gc_elapsed);
|
||||
void garbage_collection(cell gen,bool growing_data_heap_,cell requested_bytes);
|
||||
void end_gc();
|
||||
void garbage_collection(cell gen, bool growing_data_heap, bool trace_contexts, cell requested_bytes);
|
||||
void gc();
|
||||
void primitive_gc();
|
||||
void primitive_gc_stats();
|
||||
|
@ -285,23 +279,15 @@ struct factor_vm
|
|||
object *allot_object(header header, cell size);
|
||||
void primitive_clear_gc_stats();
|
||||
|
||||
template<typename TYPE> TYPE *allot(cell size)
|
||||
template<typename Type> Type *allot(cell size)
|
||||
{
|
||||
return (TYPE *)allot_object(header(TYPE::type_number),size);
|
||||
}
|
||||
|
||||
inline bool collecting_accumulation_gen_p()
|
||||
{
|
||||
return ((data->have_aging_p()
|
||||
&& collecting_gen == data->aging()
|
||||
&& !collecting_aging_again)
|
||||
|| collecting_gen == data->tenured());
|
||||
return (Type *)allot_object(header(Type::type_number),size);
|
||||
}
|
||||
|
||||
inline void check_data_pointer(object *pointer)
|
||||
{
|
||||
#ifdef FACTOR_DEBUG
|
||||
if(!growing_data_heap)
|
||||
if(!(current_gc && current_gc->growing_data_heap))
|
||||
{
|
||||
assert((cell)pointer >= data->seg->start
|
||||
&& (cell)pointer < data->seg->end);
|
||||
|
@ -329,15 +315,13 @@ struct factor_vm
|
|||
std::vector<cell> gc_bignums;
|
||||
|
||||
// generic arrays
|
||||
template <typename T> T *allot_array_internal(cell capacity);
|
||||
template <typename T> bool reallot_array_in_place_p(T *array, cell capacity);
|
||||
template <typename TYPE> TYPE *reallot_array(TYPE *array_, 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> Array *reallot_array(Array *array_, cell capacity);
|
||||
|
||||
//debug
|
||||
bool fep_disabled;
|
||||
bool full_output;
|
||||
cell look_for;
|
||||
cell obj;
|
||||
|
||||
void print_chars(string* str);
|
||||
void print_word(word* word, cell nesting);
|
||||
|
@ -349,7 +333,6 @@ struct factor_vm
|
|||
void print_objects(cell *start, cell *end);
|
||||
void print_datastack();
|
||||
void print_retainstack();
|
||||
void print_stack_frame(stack_frame *frame);
|
||||
void print_callstack();
|
||||
void dump_cell(cell x);
|
||||
void dump_memory(cell from, cell to);
|
||||
|
@ -499,8 +482,8 @@ struct factor_vm
|
|||
inline double untag_float_check(cell tagged);
|
||||
inline fixnum float_to_fixnum(cell tagged);
|
||||
inline double fixnum_to_float(cell tagged);
|
||||
template <typename T> T *untag_check(cell value);
|
||||
template <typename T> T *untag(cell value);
|
||||
template<typename Type> Type *untag_check(cell value);
|
||||
template<typename Type> Type *untag(cell value);
|
||||
|
||||
//io
|
||||
void init_c_io();
|
||||
|
@ -515,8 +498,6 @@ struct factor_vm
|
|||
void primitive_fclose();
|
||||
|
||||
//code_block
|
||||
typedef void (factor_vm::*relocation_iterator)(relocation_entry rel, cell index, code_block *compiled);
|
||||
|
||||
relocation_type relocation_type_of(relocation_entry r);
|
||||
relocation_class relocation_class_of(relocation_entry r);
|
||||
cell relocation_offset_of(relocation_entry r);
|
||||
|
@ -529,20 +510,16 @@ struct factor_vm
|
|||
void undefined_symbol();
|
||||
void *get_rel_symbol(array *literals, cell index);
|
||||
cell compute_relocation(relocation_entry rel, cell index, code_block *compiled);
|
||||
void iterate_relocations(code_block *compiled, relocation_iterator iter);
|
||||
template<typename Iterator> void iterate_relocations(code_block *compiled, Iterator &iter);
|
||||
void store_address_2_2(cell *ptr, cell value);
|
||||
void store_address_masked(cell *ptr, fixnum value, cell mask, fixnum shift);
|
||||
void store_address_in_code_block(cell klass, cell offset, fixnum absolute_value);
|
||||
void update_literal_references_step(relocation_entry rel, cell index, code_block *compiled);
|
||||
void update_literal_references(code_block *compiled);
|
||||
void copy_literal_references(code_block *compiled);
|
||||
void trace_literal_references(code_block *compiled);
|
||||
void relocate_code_block_step(relocation_entry rel, cell index, code_block *compiled);
|
||||
void update_word_references_step(relocation_entry rel, cell index, code_block *compiled);
|
||||
void update_word_references(code_block *compiled);
|
||||
void update_literal_and_word_references(code_block *compiled);
|
||||
void check_code_address(cell address);
|
||||
void mark_code_block(code_block *compiled);
|
||||
void mark_stack_frame_step(stack_frame *frame);
|
||||
void mark_active_blocks(context *stacks);
|
||||
void mark_object_code_block(object *object);
|
||||
void relocate_code_block(code_block *compiled);
|
||||
|
@ -562,18 +539,29 @@ struct factor_vm
|
|||
void init_code_heap(cell size);
|
||||
bool in_code_heap_p(cell ptr);
|
||||
void jit_compile_word(cell word_, cell def_, bool relocate);
|
||||
void iterate_code_heap(code_heap_iterator iter);
|
||||
void copy_code_heap_roots();
|
||||
void trace_code_heap_roots();
|
||||
void update_code_heap_words();
|
||||
void primitive_modify_code_heap();
|
||||
void primitive_code_room();
|
||||
code_block *forward_xt(code_block *compiled);
|
||||
void forward_frame_xt(stack_frame *frame);
|
||||
void forward_object_xts();
|
||||
void fixup_object_xts();
|
||||
void compact_code_heap();
|
||||
inline void check_code_pointer(cell ptr);
|
||||
|
||||
/* Apply a function to every code block */
|
||||
template<typename Iterator> void factor_vm::iterate_code_heap(Iterator &iter)
|
||||
{
|
||||
heap_block *scan = code->first_block();
|
||||
|
||||
while(scan)
|
||||
{
|
||||
if(scan->status != B_FREE)
|
||||
iter((code_block *)scan);
|
||||
scan = code->next_block(scan);
|
||||
}
|
||||
}
|
||||
|
||||
//image
|
||||
cell code_relocation_base;
|
||||
cell data_relocation_base;
|
||||
|
@ -585,11 +573,10 @@ struct factor_vm
|
|||
void primitive_save_image();
|
||||
void primitive_save_image_and_exit();
|
||||
void data_fixup(cell *cell);
|
||||
template <typename T> void code_fixup(T **handle);
|
||||
template<typename Type> void code_fixup(Type **handle);
|
||||
void fixup_word(word *word);
|
||||
void fixup_quotation(quotation *quot);
|
||||
void fixup_alien(alien *d);
|
||||
void fixup_stack_frame(stack_frame *frame);
|
||||
void fixup_callstack_object(callstack *stack);
|
||||
void relocate_object(object *object);
|
||||
void relocate_data();
|
||||
|
@ -598,7 +585,7 @@ struct factor_vm
|
|||
void load_image(vm_parameters *p);
|
||||
|
||||
//callstack
|
||||
template<typename T> void iterate_callstack_object(callstack *stack_, T &iterator);
|
||||
template<typename Iterator> void iterate_callstack_object(callstack *stack_, Iterator &iterator);
|
||||
void check_frame(stack_frame *frame);
|
||||
callstack *allot_callstack(cell size);
|
||||
stack_frame *fix_callstack_top(stack_frame *top, stack_frame *bottom);
|
||||
|
@ -617,8 +604,25 @@ struct factor_vm
|
|||
void primitive_innermost_stack_frame_scan();
|
||||
void primitive_set_innermost_stack_frame_quot();
|
||||
void save_callstack_bottom(stack_frame *callstack_bottom);
|
||||
template<typename T> void iterate_callstack(cell top, cell bottom, T &iterator);
|
||||
inline void do_slots(cell obj, void (* iter)(cell *,factor_vm*));
|
||||
template<typename Iterator> void iterate_callstack(cell top, cell bottom, Iterator &iterator);
|
||||
|
||||
/* Every object has a regular representation in the runtime, which makes GC
|
||||
much simpler. Every slot of the object until binary_payload_start is a pointer
|
||||
to some other object. */
|
||||
template<typename Iterator> void do_slots(cell obj, Iterator &iter)
|
||||
{
|
||||
cell scan = obj;
|
||||
cell payload_start = binary_payload_start((object *)obj);
|
||||
cell end = obj + payload_start;
|
||||
|
||||
scan += sizeof(cell);
|
||||
|
||||
while(scan < end)
|
||||
{
|
||||
iter((cell *)scan);
|
||||
scan += sizeof(cell);
|
||||
}
|
||||
}
|
||||
|
||||
//alien
|
||||
char *pinned_alien_offset(cell obj);
|
||||
|
@ -742,10 +746,6 @@ struct factor_vm
|
|||
: profiling_p(false),
|
||||
secure_gc(false),
|
||||
gc_off(false),
|
||||
performing_gc(false),
|
||||
performing_compaction(false),
|
||||
collecting_aging_again(false),
|
||||
growing_data_heap(false),
|
||||
fep_disabled(false),
|
||||
full_output(false),
|
||||
max_pic_size(0)
|
||||
|
@ -796,6 +796,6 @@ struct factor_vm
|
|||
#define SIGNAL_VM_PTR() tls_vm()
|
||||
#endif
|
||||
|
||||
extern unordered_map<THREADHANDLE, factor_vm*> thread_vms;
|
||||
extern unordered_map<THREADHANDLE, factor_vm *> thread_vms;
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue