Don't use retain stack for extra roots

slava 2006-11-01 05:20:49 +00:00
parent 3cdac5982d
commit 0e2871679a
9 changed files with 116 additions and 33 deletions

View File

@ -1,13 +1,13 @@
+ allot refactoring: + allot refactoring:
- rethink all string conversions - rethink all string conversions
- what if retain stack is full
- ie, inside retain stack overflow handler, don't cons?
- os-windows.c error_message &co - os-windows.c error_message &co
- inline float allocation needs a gc check - inline float allocation needs a gc check
- alien invoke, callback need a gc check - alien invoke, callback need a gc check
- relocation should not cons at all - relocation should not cons at all
- ffi_dlopen, etc - ffi_dlopen, etc
- throwing an error can fill up the extra_roots stack
- last-index miscompiles
+ ui: + ui:
@ -49,6 +49,7 @@
+ compiler/ffi: + compiler/ffi:
- we may be able to remove the dlsym primitive
- [ [ dup call ] dup call ] infer hangs - [ [ dup call ] dup call ] infer hangs
- stdcall callbacks - stdcall callbacks
- callstack overflow when compiling mutually recursive inline words - callstack overflow when compiling mutually recursive inline words
@ -77,6 +78,7 @@
+ misc: + misc:
- don't save big free chunk at the end of the code heap
- faster apropos - faster apropos
- growable data heap - growable data heap
- minor GC takes too long now, we should card mark code heap - minor GC takes too long now, we should card mark code heap

View File

@ -152,6 +152,7 @@ void box_value_pair(CELL x, CELL y)
dpush(tag_object(array)); dpush(tag_object(array));
} }
/* open a native library and push a handle */
void primitive_dlopen(void) void primitive_dlopen(void)
{ {
F_DLL* dll = allot_object(DLL_TYPE,sizeof(F_DLL)); F_DLL* dll = allot_object(DLL_TYPE,sizeof(F_DLL));
@ -160,6 +161,7 @@ void primitive_dlopen(void)
dpush(tag_object(dll)); dpush(tag_object(dll));
} }
/* look up a symbol in a native library */
void primitive_dlsym(void) void primitive_dlsym(void)
{ {
CELL dll = dpop(); CELL dll = dpop();
@ -178,6 +180,7 @@ void primitive_dlsym(void)
box_signed_cell((CELL)ffi_dlsym(d,sym,true)); box_signed_cell((CELL)ffi_dlsym(d,sym,true));
} }
/* close a native library handle */
void primitive_dlclose(void) void primitive_dlclose(void)
{ {
ffi_dlclose(untag_dll(dpop())); ffi_dlclose(untag_dll(dpop()));

View File

@ -12,11 +12,14 @@ void new_heap(F_HEAP *heap, CELL size)
heap->free_list = NULL; heap->free_list = NULL;
} }
/* Allocate a code heap during startup */
void init_code_heap(CELL size) void init_code_heap(CELL size)
{ {
new_heap(&compiling,size); new_heap(&compiling,size);
} }
/* If there is no previous block, next_free becomes the head of the free list,
else its linked in */
INLINE void update_free_list(F_HEAP *heap, F_BLOCK *prev, F_BLOCK *next_free) INLINE void update_free_list(F_HEAP *heap, F_BLOCK *prev, F_BLOCK *next_free)
{ {
if(prev) if(prev)
@ -25,7 +28,7 @@ INLINE void update_free_list(F_HEAP *heap, F_BLOCK *prev, F_BLOCK *next_free)
heap->free_list = next_free; heap->free_list = next_free;
} }
/* called after reading the code heap from the image file. we must build the /* Called after reading the code heap from the image file. We must build the
free list, and add a large free block from compiling.base + size to free list, and add a large free block from compiling.base + size to
compiling.limit. */ compiling.limit. */
void build_free_list(F_HEAP *heap, CELL size) void build_free_list(F_HEAP *heap, CELL size)
@ -34,6 +37,7 @@ void build_free_list(F_HEAP *heap, CELL size)
F_BLOCK *scan = (F_BLOCK *)heap->base; F_BLOCK *scan = (F_BLOCK *)heap->base;
F_BLOCK *end = (F_BLOCK *)(heap->base + size); F_BLOCK *end = (F_BLOCK *)(heap->base + size);
/* Add all free blocks to the free list */
while(scan && scan < end) while(scan && scan < end)
{ {
if(scan->status == B_FREE) if(scan->status == B_FREE)
@ -45,6 +49,7 @@ void build_free_list(F_HEAP *heap, CELL size)
scan = next_block(heap,scan); scan = next_block(heap,scan);
} }
/* If there is room at the end of the heap, add a free block */
if((CELL)(end + 1) <= heap->limit) if((CELL)(end + 1) <= heap->limit)
{ {
end->status = B_FREE; end->status = B_FREE;
@ -62,6 +67,7 @@ void build_free_list(F_HEAP *heap, CELL size)
update_free_list(heap,prev,end); update_free_list(heap,prev,end);
} }
/* Allocate a block of memory from the mark and sweep GC heap */
CELL heap_allot(F_HEAP *heap, CELL size) CELL heap_allot(F_HEAP *heap, CELL size)
{ {
F_BLOCK *prev = NULL; F_BLOCK *prev = NULL;
@ -151,6 +157,7 @@ void free_unmarked(F_HEAP *heap)
build_free_list(heap,heap->limit - heap->base); build_free_list(heap,heap->limit - heap->base);
} }
/* Compute total sum of sizes of free blocks */
CELL heap_free_space(F_HEAP *heap) CELL heap_free_space(F_HEAP *heap)
{ {
CELL size = 0; CELL size = 0;
@ -175,6 +182,7 @@ CELL heap_size(F_HEAP *heap)
return (CELL)scan - (CELL)start; return (CELL)scan - (CELL)start;
} }
/* Apply a function to every code block */
void iterate_code_heap(CODE_HEAP_ITERATOR iter) void iterate_code_heap(CODE_HEAP_ITERATOR iter)
{ {
F_BLOCK *scan = (F_BLOCK *)compiling.base; F_BLOCK *scan = (F_BLOCK *)compiling.base;
@ -187,6 +195,7 @@ void iterate_code_heap(CODE_HEAP_ITERATOR iter)
} }
} }
/* Copy all literals referenced from a code block to newspace */
void collect_literals_step(F_COMPILED *relocating, CELL code_start, void collect_literals_step(F_COMPILED *relocating, CELL code_start,
CELL reloc_start, CELL literal_start, CELL words_start, CELL words_end) CELL reloc_start, CELL literal_start, CELL words_start, CELL words_end)
{ {
@ -197,6 +206,8 @@ void collect_literals_step(F_COMPILED *relocating, CELL code_start,
for(scan = literal_start; scan < literal_end; scan += CELLS) for(scan = literal_start; scan < literal_end; scan += CELLS)
copy_handle((CELL*)scan); copy_handle((CELL*)scan);
/* If the block is not finalized, the words area contains pointers to
words in the data heap rather than XTs in the code heap */
if(!relocating->finalized) if(!relocating->finalized)
{ {
for(scan = words_start; scan < words_end; scan += CELLS) for(scan = words_start; scan < words_end; scan += CELLS)
@ -204,11 +215,13 @@ void collect_literals_step(F_COMPILED *relocating, CELL code_start,
} }
} }
/* Copy literals referenced from all code blocks to newspace */
void collect_literals(void) void collect_literals(void)
{ {
iterate_code_heap(collect_literals_step); iterate_code_heap(collect_literals_step);
} }
/* Mark all XTs referenced from a code block */
void mark_sweep_step(F_COMPILED *compiled, CELL code_start, void mark_sweep_step(F_COMPILED *compiled, CELL code_start,
CELL reloc_start, CELL literal_start, CELL words_start, CELL words_end) CELL reloc_start, CELL literal_start, CELL words_start, CELL words_end)
{ {
@ -221,14 +234,18 @@ void mark_sweep_step(F_COMPILED *compiled, CELL code_start,
} }
} }
/* Mark all XTs and literals referenced from a word XT */
void recursive_mark(CELL xt) void recursive_mark(CELL xt)
{ {
F_BLOCK *block = xt_to_block(xt); F_BLOCK *block = xt_to_block(xt);
/* If already marked, do nothing */
if(block->status == B_MARKED) if(block->status == B_MARKED)
return; return;
/* Mark it */
else if(block->status == B_ALLOCATED) else if(block->status == B_ALLOCATED)
block->status = B_MARKED; block->status = B_MARKED;
/* We should never be asked to mark a free block */
else else
critical_error("Marking the wrong block",(CELL)block); critical_error("Marking the wrong block",(CELL)block);
@ -237,17 +254,20 @@ void recursive_mark(CELL xt)
iterate_code_heap_step(compiled,mark_sweep_step); iterate_code_heap_step(compiled,mark_sweep_step);
} }
/* Push the free space and total size of the code heap */
void primitive_code_room(void) void primitive_code_room(void)
{ {
box_unsigned_cell(heap_free_space(&compiling)); box_unsigned_cell(heap_free_space(&compiling));
box_unsigned_cell(compiling.limit - compiling.base); box_unsigned_cell(compiling.limit - compiling.base);
} }
/* Perform a code GC */
void primitive_code_gc(void) void primitive_code_gc(void)
{ {
garbage_collection(TENURED,true); garbage_collection(TENURED,true);
} }
/* Dump all code blocks for debugging */
void dump_heap(F_HEAP *heap) void dump_heap(F_HEAP *heap)
{ {
F_BLOCK *scan = (F_BLOCK *)heap->base; F_BLOCK *scan = (F_BLOCK *)heap->base;

View File

@ -1,5 +1,7 @@
#include "factor.h" #include "factor.h"
/* References to undefined symbols are patched up to call this function on
image load */
void undefined_symbol(void) void undefined_symbol(void)
{ {
general_error(ERROR_UNDEFINED_SYMBOL,F,F,true); general_error(ERROR_UNDEFINED_SYMBOL,F,F,true);
@ -12,6 +14,7 @@ INLINE CELL get_literal(CELL literal_start, CELL num)
return get(CREF(literal_start,num)); return get(CREF(literal_start,num));
} }
/* Look up an external library symbol referenced by a compiled code block */
CELL get_rel_symbol(F_REL *rel, CELL literal_start) CELL get_rel_symbol(F_REL *rel, CELL literal_start)
{ {
CELL arg = REL_ARGUMENT(rel); CELL arg = REL_ARGUMENT(rel);
@ -31,6 +34,7 @@ CELL get_rel_symbol(F_REL *rel, CELL literal_start)
return sym; return sym;
} }
/* Compute an address to store at a relocation */
INLINE CELL compute_code_rel(F_REL *rel, INLINE CELL compute_code_rel(F_REL *rel,
CELL code_start, CELL literal_start, CELL words_start) CELL code_start, CELL literal_start, CELL words_start)
{ {
@ -58,12 +62,14 @@ INLINE CELL compute_code_rel(F_REL *rel,
} }
} }
/* Store a 32-bit value into two consecutive PowerPC LI/LIS instructions */
INLINE void reloc_set_2_2(CELL cell, CELL value) INLINE void reloc_set_2_2(CELL cell, CELL value)
{ {
put(cell - CELLS,((get(cell - CELLS) & ~0xffff) | ((value >> 16) & 0xffff))); put(cell - CELLS,((get(cell - CELLS) & ~0xffff) | ((value >> 16) & 0xffff)));
put(cell,((get(cell) & ~0xffff) | (value & 0xffff))); put(cell,((get(cell) & ~0xffff) | (value & 0xffff)));
} }
/* Store a value into a bitfield of a PowerPC instruction */
INLINE void reloc_set_masked(CELL cell, CELL value, CELL mask) INLINE void reloc_set_masked(CELL cell, CELL value, CELL mask)
{ {
u32 original = *(u32*)cell; u32 original = *(u32*)cell;
@ -71,6 +77,7 @@ INLINE void reloc_set_masked(CELL cell, CELL value, CELL mask)
*(u32*)cell = (original | (value & mask)); *(u32*)cell = (original | (value & mask));
} }
/* Perform a fixup on a code block */
void apply_relocation(F_REL *rel, void apply_relocation(F_REL *rel,
CELL code_start, CELL literal_start, CELL words_start) CELL code_start, CELL literal_start, CELL words_start)
{ {
@ -111,17 +118,19 @@ void apply_relocation(F_REL *rel,
} }
} }
/* Perform all fixups on a code block */
void relocate_code_block(F_COMPILED *relocating, CELL code_start, void relocate_code_block(F_COMPILED *relocating, CELL code_start,
CELL reloc_start, CELL literal_start, CELL words_start, CELL words_end) CELL reloc_start, CELL literal_start, CELL words_start, CELL words_end)
{ {
F_REL *rel = (F_REL *)reloc_start; F_REL *rel = (F_REL *)reloc_start;
F_REL *rel_end = (F_REL *)literal_start; F_REL *rel_end = (F_REL *)literal_start;
/* apply relocations */
while(rel < rel_end) while(rel < rel_end)
apply_relocation(rel++,code_start,literal_start,words_start); apply_relocation(rel++,code_start,literal_start,words_start);
} }
/* After compiling a batch of words, we replace all mutual word references with
direct XT references, and perform fixups */
void finalize_code_block(F_COMPILED *relocating, CELL code_start, void finalize_code_block(F_COMPILED *relocating, CELL code_start,
CELL reloc_start, CELL literal_start, CELL words_start, CELL words_end) CELL reloc_start, CELL literal_start, CELL words_start, CELL words_end)
{ {
@ -138,6 +147,7 @@ void finalize_code_block(F_COMPILED *relocating, CELL code_start,
flush_icache(code_start,reloc_start - code_start); flush_icache(code_start,reloc_start - code_start);
} }
/* Write a sequence of integers to memory, with 'format' bytes per integer */
void deposit_integers(CELL here, F_VECTOR *vector, CELL format) void deposit_integers(CELL here, F_VECTOR *vector, CELL format)
{ {
CELL count = untag_fixnum_fast(vector->top); CELL count = untag_fixnum_fast(vector->top);
@ -158,6 +168,7 @@ void deposit_integers(CELL here, F_VECTOR *vector, CELL format)
} }
} }
/* Write a sequence of tagged pointers to memory */
void deposit_objects(CELL here, F_VECTOR *vector, CELL literal_length) void deposit_objects(CELL here, F_VECTOR *vector, CELL literal_length)
{ {
F_ARRAY *array = untag_array_fast(vector->array); F_ARRAY *array = untag_array_fast(vector->array);
@ -180,29 +191,29 @@ void primitive_add_compiled_block(void)
CELL start; CELL start;
{ {
/* read parameters from stack, leaving them on the stack */ /* Read parameters from stack, leaving them on the stack */
FROB FROB
/* try allocating a new code block */ /* Try allocating a new code block */
CELL total_length = sizeof(F_COMPILED) + code_length CELL total_length = sizeof(F_COMPILED) + code_length
+ rel_length + literal_length + words_length; + rel_length + literal_length + words_length;
start = heap_allot(&compiling,total_length); start = heap_allot(&compiling,total_length);
/* if allocation failed, do a code GC */ /* If allocation failed, do a code GC */
if(start == 0) if(start == 0)
{ {
garbage_collection(TENURED,true); garbage_collection(TENURED,true);
start = heap_allot(&compiling,total_length); start = heap_allot(&compiling,total_length);
/* insufficient room even after code GC, give up */ /* Insufficient room even after code GC, give up */
if(start == 0) if(start == 0)
critical_error("code heap exhausted",0); critical_error("code heap exhausted",0);
} }
} }
/* we have to read the parameters again, since we may have called /* we have to read the parameters again, since we may have called
code GC in which case the data heap semi-spaces will have switched */ GC above in which case the data heap semi-spaces will have switched */
FROB FROB
/* now we can pop the parameters from the stack */ /* now we can pop the parameters from the stack */
@ -244,6 +255,8 @@ void primitive_add_compiled_block(void)
#undef FROB #undef FROB
/* After batch compiling a bunch of words, perform various fixups to make them
executable */
void primitive_finalize_compile(void) void primitive_finalize_compile(void)
{ {
F_ARRAY *array = untag_array(dpop()); F_ARRAY *array = untag_array(dpop());

View File

@ -1,5 +1,7 @@
#include "factor.h" #include "factor.h"
/* Test if 'fault' is in the guard page at the top or bottom (depending on
offset being 0 or -1) of area+area_size */
bool in_page(CELL fault, CELL area, CELL area_size, int offset) bool in_page(CELL fault, CELL area, CELL area_size, int offset)
{ {
const int pagesize = getpagesize(); const int pagesize = getpagesize();
@ -9,6 +11,7 @@ bool in_page(CELL fault, CELL area, CELL area_size, int offset)
return fault >= area && fault <= area + pagesize; return fault >= area && fault <= area + pagesize;
} }
/* If memory allocation fails, bail out */
void *safe_malloc(size_t size) void *safe_malloc(size_t size)
{ {
void *ptr = malloc(size); void *ptr = malloc(size);
@ -17,6 +20,7 @@ void *safe_malloc(size_t size)
return ptr; return ptr;
} }
/* Size of the object pointed to by a tagged pointer */
CELL object_size(CELL tagged) CELL object_size(CELL tagged)
{ {
if(tagged == F || TAG(tagged) == FIXNUM_TYPE) if(tagged == F || TAG(tagged) == FIXNUM_TYPE)
@ -25,11 +29,13 @@ CELL object_size(CELL tagged)
return untagged_object_size(UNTAG(tagged)); return untagged_object_size(UNTAG(tagged));
} }
/* Size of the object pointed to by an untagged pointer */
CELL untagged_object_size(CELL pointer) CELL untagged_object_size(CELL pointer)
{ {
return align8(unaligned_object_size(pointer)); return align8(unaligned_object_size(pointer));
} }
/* Size of the data area of an object pointed to by an untagged pointer */
CELL unaligned_object_size(CELL pointer) CELL unaligned_object_size(CELL pointer)
{ {
switch(untag_header(get(pointer))) switch(untag_header(get(pointer)))
@ -73,6 +79,7 @@ void primitive_size(void)
drepl(tag_fixnum(object_size(dpeek()))); drepl(tag_fixnum(object_size(dpeek())));
} }
/* Push memory usage statistics in data heap */
void primitive_data_room(void) void primitive_data_room(void)
{ {
int gen; int gen;
@ -142,7 +149,7 @@ void primitive_end_scan(void)
gc_off = false; gc_off = false;
} }
/* scan all the objects in the card */ /* Scan all the objects in the card */
INLINE void collect_card(F_CARD *ptr, CELL here) INLINE void collect_card(F_CARD *ptr, CELL here)
{ {
F_CARD c = *ptr; F_CARD c = *ptr;
@ -164,6 +171,7 @@ INLINE void collect_card(F_CARD *ptr, CELL here)
cards_scanned++; cards_scanned++;
} }
/* Copy all newspace objects referenced from marked cards to the destination */
INLINE void collect_gen_cards(CELL gen) INLINE void collect_gen_cards(CELL gen)
{ {
F_CARD *ptr = ADDR_TO_CARD(generations[gen].base); F_CARD *ptr = ADDR_TO_CARD(generations[gen].base);
@ -180,6 +188,8 @@ INLINE void collect_gen_cards(CELL gen)
} }
} }
/* After all old->new forward references have been copied over, we must unmark
the cards */
void unmark_cards(CELL from, CELL to) void unmark_cards(CELL from, CELL to)
{ {
F_CARD *ptr = ADDR_TO_CARD(generations[from].base); F_CARD *ptr = ADDR_TO_CARD(generations[from].base);
@ -190,6 +200,8 @@ void unmark_cards(CELL from, CELL to)
unmark_card(ptr); unmark_card(ptr);
} }
/* Every card stores the offset of the first object in that card, which must be
cleared when a generation has been cleared */
void clear_cards(CELL from, CELL to) void clear_cards(CELL from, CELL to)
{ {
/* NOTE: reverse order due to heap layout. */ /* NOTE: reverse order due to heap layout. */
@ -199,7 +211,8 @@ void clear_cards(CELL from, CELL to)
clear_card(ptr); clear_card(ptr);
} }
/* scan cards in all generations older than the one being collected */ /* Scan cards in all generations older than the one being collected, copying
old->new references */
void collect_cards(CELL gen) void collect_cards(CELL gen)
{ {
int i; int i;
@ -207,8 +220,6 @@ void collect_cards(CELL gen)
collect_gen_cards(i); collect_gen_cards(i);
} }
/* Generational copying garbage collector */
CELL init_zone(F_ZONE *z, CELL size, CELL base) CELL init_zone(F_ZONE *z, CELL size, CELL base)
{ {
z->base = z->here = base; z->base = z->here = base;
@ -269,6 +280,11 @@ void init_data_heap(CELL gens,
minor_collections = 0; minor_collections = 0;
cards_scanned = 0; cards_scanned = 0;
secure_gc = secure_gc_; secure_gc = secure_gc_;
data_heap_end = data_heap_start + total_size;
extra_roots_region = alloc_bounded_block(getpagesize());
extra_roots = (CELL *)extra_roots_region->start;
} }
void collect_callframe_triple(CELL *callframe, void collect_callframe_triple(CELL *callframe,
@ -281,6 +297,7 @@ void collect_callframe_triple(CELL *callframe,
*callframe_end += *callframe; *callframe_end += *callframe;
} }
/* Copy all tagged pointers in a range of memory */
void collect_stack(F_BOUNDED_BLOCK *region, CELL top) void collect_stack(F_BOUNDED_BLOCK *region, CELL top)
{ {
CELL bottom = region->start; CELL bottom = region->start;
@ -290,6 +307,7 @@ void collect_stack(F_BOUNDED_BLOCK *region, CELL top)
copy_handle((CELL*)ptr); copy_handle((CELL*)ptr);
} }
/* The callstack has a special format */
void collect_callstack(F_BOUNDED_BLOCK *region, CELL top) void collect_callstack(F_BOUNDED_BLOCK *region, CELL top)
{ {
CELL bottom = region->start; CELL bottom = region->start;
@ -300,6 +318,8 @@ void collect_callstack(F_BOUNDED_BLOCK *region, CELL top)
(CELL*)ptr + 1, (CELL*)ptr + 2); (CELL*)ptr + 1, (CELL*)ptr + 2);
} }
/* Copy roots over at the start of GC, namely various constants, stacks,
the user environment and extra roots registered with REGISTER_ROOT */
void collect_roots(void) void collect_roots(void)
{ {
int i; int i;
@ -311,6 +331,8 @@ void collect_roots(void)
copy_handle(&bignum_neg_one); copy_handle(&bignum_neg_one);
collect_callframe_triple(&callframe,&callframe_scan,&callframe_end); collect_callframe_triple(&callframe,&callframe_scan,&callframe_end);
collect_stack(extra_roots_region,(CELL)extra_roots);
save_stacks(); save_stacks();
stacks = stack_chain; stacks = stack_chain;
@ -336,7 +358,7 @@ void collect_roots(void)
copy_handle(&userenv[i]); copy_handle(&userenv[i]);
} }
/* Given a pointer to oldspace, copy it to newspace. */ /* Given a pointer to oldspace, copy it to newspace */
INLINE void *copy_untagged_object(void *pointer, CELL size) INLINE void *copy_untagged_object(void *pointer, CELL size)
{ {
void *newpointer; void *newpointer;
@ -358,7 +380,7 @@ INLINE CELL copy_object_impl(CELL pointer)
return newpointer; return newpointer;
} }
/* follow a chain of forwarding pointers */ /* Follow a chain of forwarding pointers */
CELL resolve_forwarding(CELL untagged, CELL tag) CELL resolve_forwarding(CELL untagged, CELL tag)
{ {
CELL header = get(untagged); CELL header = get(untagged);
@ -375,12 +397,10 @@ CELL resolve_forwarding(CELL untagged, CELL tag)
} }
} }
/* /* Given a pointer to a tagged pointer to oldspace, copy it to newspace.
Given a pointer to a tagged pointer to oldspace, copy it to newspace.
If the object has already been copied, return the forwarding If the object has already been copied, return the forwarding
pointer address without copying anything; otherwise, install pointer address without copying anything; otherwise, install
a new forwarding pointer. a new forwarding pointer. */
*/
CELL copy_object(CELL pointer) CELL copy_object(CELL pointer)
{ {
CELL tag; CELL tag;
@ -461,6 +481,8 @@ CELL collect_next(CELL scan)
return scan + size; return scan + size;
} }
/* After garbage collection, any generations which are now empty need to have
their allocation pointers and cards reset. */
void reset_generations(CELL from, CELL to) void reset_generations(CELL from, CELL to)
{ {
CELL i; CELL i;
@ -476,6 +498,7 @@ void reset_generations(CELL from, CELL to)
clear_cards(from,to); clear_cards(from,to);
} }
/* Prepare to start copying reachable objects into an unused zone */
void begin_gc(CELL gen, bool code_gc) void begin_gc(CELL gen, bool code_gc)
{ {
collecting_gen = gen; collecting_gen = gen;
@ -543,7 +566,7 @@ void end_gc()
} }
} }
/* collect gen and all younger generations */ /* Collect gen and all younger generations */
void garbage_collection(CELL gen, bool code_gc) void garbage_collection(CELL gen, bool code_gc)
{ {
s64 start = current_millis(); s64 start = current_millis();
@ -601,6 +624,7 @@ void primitive_data_gc(void)
garbage_collection(gen,false); garbage_collection(gen,false);
} }
/* Push total time spent on GC */
void primitive_gc_time(void) void primitive_gc_time(void)
{ {
box_unsigned_8(gc_time); box_unsigned_8(gc_time);

View File

@ -183,17 +183,33 @@ bool gc_off;
void garbage_collection(CELL gen, bool code_gc); void garbage_collection(CELL gen, bool code_gc);
#define REGISTER_ROOT(obj) rpush(obj) /* If a runtime function needs to call another function which potentially
#define UNREGISTER_ROOT(obj) obj = rpop() allocates memory, it must store any local variable references to Factor
objects on the root stack */
F_BOUNDED_BLOCK *extra_roots_region;
CELL *extra_roots;
#define REGISTER_ARRAY(obj) rpush(tag_object(obj)) INLINE void push_root(CELL tagged)
#define UNREGISTER_ARRAY(obj) obj = untag_array_fast(rpop()) {
*(extra_roots++) = tagged;
}
#define REGISTER_STRING(obj) rpush(tag_object(obj)) INLINE CELL pop_root(void)
#define UNREGISTER_STRING(obj) obj = untag_string_fast(rpop()) {
return *(--extra_roots);
}
#define REGISTER_C_STRING(obj) rpush(tag_object(((F_ARRAY *)obj) - 1)) #define REGISTER_ROOT(obj) push_root(obj)
#define UNREGISTER_C_STRING(obj) obj = ((char*)(untag_array_fast(rpop()) + 1)) #define UNREGISTER_ROOT(obj) obj = pop_root()
#define REGISTER_ARRAY(obj) push_root(tag_object(obj))
#define UNREGISTER_ARRAY(obj) obj = untag_array_fast(pop_root())
#define REGISTER_STRING(obj) push_root(tag_object(obj))
#define UNREGISTER_STRING(obj) obj = untag_string_fast(pop_root())
#define REGISTER_C_STRING(obj) push_root(tag_object(((F_ARRAY *)obj) - 1))
#define UNREGISTER_C_STRING(obj) obj = ((char*)(untag_array_fast(pop_root()) + 1))
INLINE void *allot_zone(F_ZONE *z, CELL a) INLINE void *allot_zone(F_ZONE *z, CELL a)
{ {

View File

@ -1,5 +1,6 @@
#include "factor.h" #include "factor.h"
/* Get things started */
void init_factor(const char* image, void init_factor(const char* image,
CELL ds_size, CELL rs_size, CELL cs_size, CELL ds_size, CELL rs_size, CELL cs_size,
CELL gen_count, CELL young_size, CELL aging_size, CELL gen_count, CELL young_size, CELL aging_size,

View File

@ -1,5 +1,6 @@
#include "factor.h" #include "factor.h"
/* Certain special objects in the image are known to the runtime */
void init_objects(F_HEADER *h) void init_objects(F_HEADER *h)
{ {
int i; int i;
@ -13,6 +14,7 @@ void init_objects(F_HEADER *h)
bignum_neg_one = h->bignum_neg_one; bignum_neg_one = h->bignum_neg_one;
} }
/* Read an image file from disk, only done once during startup */
void load_image(const char* filename) void load_image(const char* filename)
{ {
FILE* file; FILE* file;
@ -79,6 +81,7 @@ void load_image(const char* filename)
fflush(stdout); fflush(stdout);
} }
/* Save the current image to disk */
bool save_image(const char* filename) bool save_image(const char* filename)
{ {
FILE* file; FILE* file;
@ -121,6 +124,7 @@ void primitive_save_image(void)
save_image(to_char_string(filename,true)); save_image(to_char_string(filename,true));
} }
/* Initialize an object in a newly-loaded image */
void relocate_object(CELL relocating) void relocate_object(CELL relocating)
{ {
CELL scan = relocating; CELL scan = relocating;
@ -152,6 +156,8 @@ void relocate_object(CELL relocating)
} }
} }
/* Since the image might have been saved with a different base address than
where it is loaded, we need to fix up pointers in the image. */
void relocate_data() void relocate_data()
{ {
CELL relocating; CELL relocating;

View File

@ -71,10 +71,8 @@ void primitive_fixnum_subtract_fast(void)
dpush(tag_fixnum(x - y)); dpush(tag_fixnum(x - y));
} }
/** /* Multiply two integers, and trap overflow.
* Multiply two integers, and trap overflow. Thanks to David Blaikie (The_Vulture from freenode #java) for the hint. */
* Thanks to David Blaikie (The_Vulture from freenode #java) for the hint.
*/
void primitive_fixnum_multiply(void) void primitive_fixnum_multiply(void)
{ {
POP_FIXNUMS(x,y) POP_FIXNUMS(x,y)