237 lines
5.2 KiB
C
Executable File
237 lines
5.2 KiB
C
Executable File
#include "master.h"
|
|
|
|
/* Allocate a code heap during startup */
|
|
void init_code_heap(CELL size)
|
|
{
|
|
new_heap(&code_heap,size);
|
|
}
|
|
|
|
bool in_code_heap_p(CELL ptr)
|
|
{
|
|
return (ptr >= code_heap.segment->start
|
|
&& ptr <= code_heap.segment->end);
|
|
}
|
|
|
|
void set_word_code(F_WORD *word, F_CODE_BLOCK *compiled)
|
|
{
|
|
if(compiled->type != WORD_TYPE)
|
|
critical_error("bad param to set_word_xt",(CELL)compiled);
|
|
|
|
word->code = compiled;
|
|
word->optimizedp = T;
|
|
}
|
|
|
|
/* Allocates memory */
|
|
void default_word_code(F_WORD *word, bool relocate)
|
|
{
|
|
REGISTER_UNTAGGED(word);
|
|
jit_compile(word->def,relocate);
|
|
UNREGISTER_UNTAGGED(word);
|
|
|
|
word->code = untag_quotation(word->def)->code;
|
|
word->optimizedp = F;
|
|
}
|
|
|
|
/* Apply a function to every code block */
|
|
void iterate_code_heap(CODE_HEAP_ITERATOR iter)
|
|
{
|
|
F_BLOCK *scan = first_block(&code_heap);
|
|
|
|
while(scan)
|
|
{
|
|
if(scan->status != B_FREE)
|
|
iter(block_to_compiled(scan));
|
|
scan = next_block(&code_heap,scan);
|
|
}
|
|
}
|
|
|
|
/* Copy literals referenced from all code blocks to newspace. Only for
|
|
aging and nursery collections */
|
|
void copy_code_heap_roots(void)
|
|
{
|
|
iterate_code_heap(copy_literal_references);
|
|
}
|
|
|
|
/* Update literals referenced from all code blocks. Only for tenured
|
|
collections, done at the end. */
|
|
void update_code_heap_roots(void)
|
|
{
|
|
iterate_code_heap(update_literal_references);
|
|
}
|
|
|
|
/* Update pointers to words referenced from all code blocks. Only after
|
|
defining a new word. */
|
|
void update_code_heap_words(void)
|
|
{
|
|
iterate_code_heap(update_word_references);
|
|
}
|
|
|
|
void primitive_modify_code_heap(void)
|
|
{
|
|
F_ARRAY *alist = untag_array(dpop());
|
|
|
|
CELL count = untag_fixnum_fast(alist->capacity);
|
|
if(count == 0)
|
|
return;
|
|
|
|
CELL i;
|
|
for(i = 0; i < count; i++)
|
|
{
|
|
F_ARRAY *pair = untag_array(array_nth(alist,i));
|
|
|
|
F_WORD *word = untag_word(array_nth(pair,0));
|
|
|
|
CELL data = array_nth(pair,1);
|
|
|
|
if(data == F)
|
|
{
|
|
REGISTER_UNTAGGED(alist);
|
|
REGISTER_UNTAGGED(word);
|
|
default_word_code(word,false);
|
|
UNREGISTER_UNTAGGED(word);
|
|
UNREGISTER_UNTAGGED(alist);
|
|
}
|
|
else
|
|
{
|
|
F_ARRAY *compiled_code = untag_array(data);
|
|
|
|
F_ARRAY *literals = untag_array(array_nth(compiled_code,0));
|
|
CELL relocation = array_nth(compiled_code,1);
|
|
F_ARRAY *labels = untag_array(array_nth(compiled_code,2));
|
|
F_ARRAY *code = untag_array(array_nth(compiled_code,3));
|
|
|
|
REGISTER_UNTAGGED(alist);
|
|
REGISTER_UNTAGGED(word);
|
|
|
|
F_CODE_BLOCK *compiled = add_compiled_block(
|
|
WORD_TYPE,
|
|
code,
|
|
labels,
|
|
relocation,
|
|
tag_object(literals));
|
|
|
|
UNREGISTER_UNTAGGED(word);
|
|
UNREGISTER_UNTAGGED(alist);
|
|
|
|
set_word_code(word,compiled);
|
|
}
|
|
|
|
REGISTER_UNTAGGED(alist);
|
|
update_word_xt(word);
|
|
UNREGISTER_UNTAGGED(alist);
|
|
}
|
|
|
|
update_code_heap_words();
|
|
}
|
|
|
|
/* Push the free space and total size of the code heap */
|
|
void primitive_code_room(void)
|
|
{
|
|
CELL used, total_free, max_free;
|
|
heap_usage(&code_heap,&used,&total_free,&max_free);
|
|
dpush(tag_fixnum((code_heap.segment->size) / 1024));
|
|
dpush(tag_fixnum(used / 1024));
|
|
dpush(tag_fixnum(total_free / 1024));
|
|
dpush(tag_fixnum(max_free / 1024));
|
|
}
|
|
|
|
F_CODE_BLOCK *forward_xt(F_CODE_BLOCK *compiled)
|
|
{
|
|
return block_to_compiled(compiled_to_block(compiled)->forwarding);
|
|
}
|
|
|
|
void forward_frame_xt(F_STACK_FRAME *frame)
|
|
{
|
|
CELL offset = (CELL)FRAME_RETURN_ADDRESS(frame) - (CELL)frame_code(frame);
|
|
F_CODE_BLOCK *forwarded = forward_xt(frame_code(frame));
|
|
frame->xt = (XT)(forwarded + 1);
|
|
FRAME_RETURN_ADDRESS(frame) = (XT)((CELL)forwarded + offset);
|
|
}
|
|
|
|
void forward_object_xts(void)
|
|
{
|
|
begin_scan();
|
|
|
|
CELL obj;
|
|
|
|
while((obj = next_object()) != F)
|
|
{
|
|
if(type_of(obj) == WORD_TYPE)
|
|
{
|
|
F_WORD *word = untag_object(obj);
|
|
|
|
word->code = forward_xt(word->code);
|
|
if(word->profiling)
|
|
word->profiling = forward_xt(word->profiling);
|
|
}
|
|
else if(type_of(obj) == QUOTATION_TYPE)
|
|
{
|
|
F_QUOTATION *quot = untag_object(obj);
|
|
|
|
if(quot->compiledp != F)
|
|
quot->code = forward_xt(quot->code);
|
|
}
|
|
else if(type_of(obj) == CALLSTACK_TYPE)
|
|
{
|
|
F_CALLSTACK *stack = untag_object(obj);
|
|
iterate_callstack_object(stack,forward_frame_xt);
|
|
}
|
|
}
|
|
|
|
/* End the heap scan */
|
|
gc_off = false;
|
|
}
|
|
|
|
/* Set the XT fields now that the heap has been compacted */
|
|
void fixup_object_xts(void)
|
|
{
|
|
begin_scan();
|
|
|
|
CELL obj;
|
|
|
|
while((obj = next_object()) != F)
|
|
{
|
|
if(type_of(obj) == WORD_TYPE)
|
|
{
|
|
F_WORD *word = untag_object(obj);
|
|
update_word_xt(word);
|
|
}
|
|
else if(type_of(obj) == QUOTATION_TYPE)
|
|
{
|
|
F_QUOTATION *quot = untag_object(obj);
|
|
|
|
if(quot->compiledp != F)
|
|
set_quot_xt(quot,quot->code);
|
|
}
|
|
}
|
|
|
|
/* End the heap scan */
|
|
gc_off = false;
|
|
}
|
|
|
|
/* Move all free space to the end of the code heap. This is not very efficient,
|
|
since it makes several passes over the code and data heaps, but we only ever
|
|
do this before saving a deployed image and exiting, so performaance is not
|
|
critical here */
|
|
void compact_code_heap(void)
|
|
{
|
|
/* Free all unreachable code blocks */
|
|
gc();
|
|
|
|
/* Figure out where the code heap blocks are going to end up */
|
|
CELL size = compute_heap_forwarding(&code_heap);
|
|
|
|
/* Update word and quotation code pointers */
|
|
forward_object_xts();
|
|
|
|
/* Actually perform the compaction */
|
|
compact_heap(&code_heap);
|
|
|
|
/* Update word and quotation XTs */
|
|
fixup_object_xts();
|
|
|
|
/* Now update the free list; there will be a single free block at
|
|
the end */
|
|
build_free_list(&code_heap,size);
|
|
}
|