factor/vm/compiler.c

264 lines
6.5 KiB
C

#include "factor.h"
void iterate_code_heap(CELL start, CELL end, CODE_HEAP_ITERATOR iter)
{
while(start < end)
{
F_COMPILED *compiled = (F_COMPILED *)start;
CELL code_start = start + sizeof(F_COMPILED);
CELL reloc_start = code_start + compiled->code_length;
CELL literal_start = reloc_start + compiled->reloc_length;
CELL literal_end = literal_start + compiled->literal_length;
iter(compiled,code_start,reloc_start,literal_start,literal_end);
start = literal_end;
}
}
void undefined_symbol(void)
{
general_error(ERROR_UNDEFINED_SYMBOL,F,F,true);
}
#define LITERAL_REF(literal_start,num) ((literal_start) + CELLS * (num))
INLINE CELL get_literal(CELL literal_start, CELL num)
{
return get(LITERAL_REF(literal_start,num));
}
CELL get_rel_symbol(F_REL *rel, CELL literal_start)
{
CELL arg = REL_ARGUMENT(rel);
F_ARRAY *pair = untag_array(get_literal(literal_start,arg));
F_STRING *symbol = untag_string(get(AREF(pair,0)));
CELL library = get(AREF(pair,1));
DLL *dll = (library == F ? NULL : untag_dll(library));
if(dll != NULL && !dll->dll)
return (CELL)undefined_symbol;
CELL sym = (CELL)ffi_dlsym(dll,symbol,false);
if(!sym)
return (CELL)undefined_symbol;
return sym;
}
CELL get_rel_word(F_REL *rel, CELL literal_start)
{
CELL arg = REL_ARGUMENT(rel);
F_WORD *word = untag_word(get_literal(literal_start,arg));
if(word->xt < compiling.base || word->xt >= compiling.limit)
fprintf(stderr,"Bad XT %x",tag_word(word));
return word->xt;
}
INLINE CELL compute_code_rel(F_REL *rel,
CELL code_start, CELL literal_start)
{
CELL offset = code_start + rel->offset;
switch(REL_TYPE(rel))
{
case RT_PRIMITIVE:
return primitive_to_xt(REL_ARGUMENT(rel));
case RT_DLSYM:
return get_rel_symbol(rel,literal_start);
case RT_HERE:
return offset;
case RT_CARDS:
return cards_offset;
case RT_LITERAL:
return LITERAL_REF(literal_start,REL_ARGUMENT(rel));
case RT_WORD:
return get_rel_word(rel,literal_start);
case RT_LABEL:
return code_start + REL_ARGUMENT(rel);
default:
critical_error("Bad rel type",rel->type);
return -1;
}
}
INLINE void reloc_set_2_2(CELL cell, CELL value)
{
put(cell - CELLS,((get(cell - CELLS) & ~0xffff) | ((value >> 16) & 0xffff)));
put(cell,((get(cell) & ~0xffff) | (value & 0xffff)));
}
INLINE void reloc_set_masked(CELL cell, CELL value, CELL mask)
{
u32 original = *(u32*)cell;
original &= ~mask;
*(u32*)cell = (original | (value & mask));
}
void apply_relocation(F_REL *rel, CELL code_start, CELL literal_start)
{
CELL absolute_value;
CELL relative_value;
CELL offset = rel->offset + code_start;
/* to_c_string can fill up the heap */
maybe_gc(0);
absolute_value = compute_code_rel(rel,code_start,literal_start);
relative_value = absolute_value - offset;
switch(REL_CLASS(rel))
{
case REL_ABSOLUTE_CELL:
put(offset,absolute_value);
break;
case REL_ABSOLUTE:
*(u32*)offset = absolute_value;
break;
case REL_RELATIVE:
*(u32*)offset = relative_value - sizeof(u32);
break;
case REL_ABSOLUTE_2_2:
reloc_set_2_2(offset,absolute_value);
break;
case REL_RELATIVE_2_2:
reloc_set_2_2(offset,relative_value);
break;
case REL_RELATIVE_2:
reloc_set_masked(offset,relative_value,REL_RELATIVE_2_MASK);
break;
case REL_RELATIVE_3:
reloc_set_masked(offset,relative_value,REL_RELATIVE_3_MASK);
break;
default:
critical_error("Bad rel class",REL_CLASS(rel));
return;
}
}
void finalize_code_block(F_COMPILED *relocating, CELL code_start,
CELL reloc_start, CELL literal_start, CELL literal_end)
{
F_REL *rel = (F_REL *)reloc_start;
F_REL *rel_end = (F_REL *)literal_start;
/* apply relocations */
while(rel < rel_end)
apply_relocation(rel++,code_start,literal_start);
}
void collect_literals_step(F_COMPILED *relocating, CELL code_start,
CELL reloc_start, CELL literal_start, CELL literal_end)
{
CELL scan;
for(scan = literal_start; scan < literal_end; scan += CELLS)
copy_handle((CELL*)scan);
}
void collect_literals(void)
{
iterate_code_heap(compiling.base,compiling.here,collect_literals_step);
}
void init_compiler(CELL size)
{
compiling.base = compiling.here
= (CELL)(alloc_bounded_block(size)->start);
if(compiling.base == 0)
fatal_error("Cannot allocate code heap",size);
compiling.limit = compiling.base + size;
last_flush = compiling.base;
}
void deposit_integers(F_VECTOR *vector, CELL format)
{
CELL count = untag_fixnum_fast(vector->top);
F_ARRAY *array = untag_array_fast(vector->array);
CELL i;
if(format == 1)
{
for(i = 0; i < count; i++)
cput(compiling.here + i,to_fixnum(get(AREF(array,i))));
}
else if(format == CELLS)
{
CELL dest = compiling.here;
for(i = 0; i < count; i++)
{
put(dest,to_fixnum(get(AREF(array,i))));
dest += CELLS;
}
}
else
critical_error("Bad format param to deposit_vector()",format);
}
void deposit_objects(F_VECTOR *vector, CELL literal_length)
{
F_ARRAY *array = untag_array_fast(vector->array);
memcpy((void*)compiling.here,array + 1,literal_length);
}
void add_compiled_block(CELL code_format, F_VECTOR *code,
F_VECTOR *literals, F_VECTOR *rel)
{
CELL start = compiling.here;
CELL code_length = align8(untag_fixnum_fast(code->top) * code_format);
CELL rel_length = untag_fixnum_fast(rel->top) * CELLS;
CELL literal_length = untag_fixnum_fast(literals->top) * CELLS;
/* compiled header */
F_COMPILED header;
header.code_length = code_length;
header.reloc_length = rel_length;
header.literal_length = literal_length;
memcpy((void*)compiling.here,&header,sizeof(F_COMPILED));
compiling.here += sizeof(F_COMPILED);
/* code */
deposit_integers(code,code_format);
compiling.here += code_length;
/* relation info */
deposit_integers(rel,CELLS);
compiling.here += rel_length;
/* literals */
deposit_objects(literals,literal_length);
compiling.here += literal_length;
/* push the XT of the new word on the stack */
box_unsigned_cell(start + sizeof(F_COMPILED));
}
void primitive_add_compiled_block(void)
{
CELL code_format = to_cell(dpop());
F_VECTOR *code = untag_vector(dpop());
F_VECTOR *literals = untag_vector(dpop());
F_VECTOR *rel = untag_vector(dpop());
add_compiled_block(code_format,code,literals,rel);
}
void primitive_finalize_compile(void)
{
F_ARRAY *array = untag_array(dpop());
CELL count = untag_fixnum_fast(array->capacity);
CELL i;
for(i = 0; i < count; i++)
{
F_ARRAY *pair = untag_array(get(AREF(array,i)));
F_WORD *word = untag_word(get(AREF(pair,0)));
word->xt = to_cell(get(AREF(pair,1)));
}
flush_icache((void*)last_flush,compiling.here - last_flush);
iterate_code_heap(last_flush,compiling.here,finalize_code_block);
last_flush = compiling.here;
}