factor/vm/compiler.c

291 lines
7.7 KiB
C
Raw Normal View History

2006-08-09 16:15:27 -04:00
#include "factor.h"
2006-11-01 00:20:49 -05:00
/* References to undefined symbols are patched up to call this function on
image load */
2006-08-09 16:15:27 -04:00
void undefined_symbol(void)
{
general_error(ERROR_UNDEFINED_SYMBOL,F,F,true);
}
2006-09-02 01:58:23 -04:00
#define CREF(array,i) ((CELL)(array) + CELLS * (i))
2006-08-09 16:15:27 -04:00
INLINE CELL get_literal(CELL literal_start, CELL num)
{
2006-09-02 01:58:23 -04:00
return get(CREF(literal_start,num));
2006-08-09 16:15:27 -04:00
}
2006-11-01 00:20:49 -05:00
/* Look up an external library symbol referenced by a compiled code block */
2006-08-09 16:15:27 -04:00
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));
2006-11-02 18:29:11 -05:00
char *symbol = alien_offset(get(AREF(pair,0)));
2006-08-09 16:15:27 -04:00
CELL library = get(AREF(pair,1));
F_DLL *dll = (library == F ? NULL : untag_dll(library));
2006-08-09 16:15:27 -04:00
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;
}
2006-11-01 00:20:49 -05:00
/* Compute an address to store at a relocation */
2006-08-09 16:15:27 -04:00
INLINE CELL compute_code_rel(F_REL *rel,
2006-09-02 01:58:23 -04:00
CELL code_start, CELL literal_start, CELL words_start)
2006-08-09 16:15:27 -04:00
{
CELL offset = code_start + rel->offset;
2006-08-09 16:15:27 -04:00
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:
2006-09-02 01:58:23 -04:00
return CREF(literal_start,REL_ARGUMENT(rel));
case RT_XT:
return get(CREF(words_start,REL_ARGUMENT(rel)));
2006-08-09 16:15:27 -04:00
case RT_LABEL:
2006-08-10 00:14:43 -04:00
return code_start + REL_ARGUMENT(rel);
2006-08-09 16:15:27 -04:00
default:
critical_error("Bad rel type",rel->type);
2006-08-09 16:15:27 -04:00
return -1;
}
}
2006-11-01 00:20:49 -05:00
/* Store a 32-bit value into two consecutive PowerPC LI/LIS instructions */
2006-08-09 16:15:27 -04:00
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)));
}
2006-11-01 00:20:49 -05:00
/* Store a value into a bitfield of a PowerPC instruction */
INLINE void reloc_set_masked(CELL cell, CELL value, CELL mask)
{
u32 original = *(u32*)cell;
original &= ~mask;
*(u32*)cell = (original | (value & mask));
}
2006-11-01 00:20:49 -05:00
/* Perform a fixup on a code block */
2006-09-02 01:58:23 -04:00
void apply_relocation(F_REL *rel,
CELL code_start, CELL literal_start, CELL words_start)
2006-08-09 16:15:27 -04:00
{
CELL absolute_value;
CELL relative_value;
CELL offset = rel->offset + code_start;
2006-09-02 01:58:23 -04:00
absolute_value = compute_code_rel(rel,
code_start,literal_start,words_start);
2006-08-09 16:15:27 -04:00
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);
2006-08-09 16:15:27 -04:00
break;
case REL_RELATIVE_3:
reloc_set_masked(offset,relative_value,REL_RELATIVE_3_MASK);
2006-08-09 16:15:27 -04:00
break;
default:
critical_error("Bad rel class",REL_CLASS(rel));
2006-08-09 16:15:27 -04:00
return;
}
}
2006-11-01 00:20:49 -05:00
/* Perform all fixups on a code block */
2006-09-24 22:29:52 -04:00
void relocate_code_block(F_COMPILED *relocating, CELL code_start,
CELL reloc_start, CELL literal_start, CELL words_start, CELL words_end)
2006-08-09 16:15:27 -04:00
{
F_REL *rel = (F_REL *)reloc_start;
F_REL *rel_end = (F_REL *)literal_start;
2006-09-24 22:29:52 -04:00
while(rel < rel_end)
apply_relocation(rel++,code_start,literal_start,words_start);
}
2006-11-01 00:20:49 -05:00
/* After compiling a batch of words, we replace all mutual word references with
direct XT references, and perform fixups */
2006-09-24 22:29:52 -04:00
void finalize_code_block(F_COMPILED *relocating, CELL code_start,
CELL reloc_start, CELL literal_start, CELL words_start, CELL words_end)
2006-09-24 22:29:52 -04:00
{
2006-09-26 16:42:29 -04:00
CELL scan;
2006-09-24 22:29:52 -04:00
2006-09-26 16:42:29 -04:00
for(scan = words_start; scan < words_end; scan += CELLS)
put(scan,untag_word(get(scan))->xt);
2006-09-02 01:58:23 -04:00
2006-09-26 16:42:29 -04:00
relocating->finalized = true;
2006-09-02 01:58:23 -04:00
2006-09-26 16:42:29 -04:00
relocate_code_block(relocating,code_start,reloc_start,
literal_start,words_start,words_end);
2006-09-26 16:42:29 -04:00
flush_icache(code_start,reloc_start - code_start);
2006-08-09 16:15:27 -04:00
}
2006-11-01 00:20:49 -05:00
/* Write a sequence of integers to memory, with 'format' bytes per integer */
2006-09-24 22:29:52 -04:00
void deposit_integers(CELL here, F_VECTOR *vector, CELL format)
2006-08-09 16:15:27 -04:00
{
CELL count = untag_fixnum_fast(vector->top);
F_ARRAY *array = untag_array_fast(vector->array);
CELL i;
2006-10-24 20:26:32 -04:00
for(i = 0; i < count; i++)
2006-08-09 16:15:27 -04:00
{
2006-10-24 20:26:32 -04:00
F_FIXNUM value = to_fixnum(get(AREF(array,i)));
if(format == 1)
cput(here + i,value);
else if(format == sizeof(unsigned int))
*(unsigned int *)(here + format * i) = value;
else if(format == CELLS)
2006-11-02 03:00:02 -05:00
put(CREF(here,i),value);
2006-10-24 20:26:32 -04:00
else
critical_error("Bad format in deposit_integers()",format);
2006-08-09 16:15:27 -04:00
}
}
2006-11-01 00:20:49 -05:00
/* Write a sequence of tagged pointers to memory */
2006-09-24 22:29:52 -04:00
void deposit_objects(CELL here, F_VECTOR *vector, CELL literal_length)
{
F_ARRAY *array = untag_array_fast(vector->array);
2006-09-24 22:29:52 -04:00
memcpy((void*)here,array + 1,literal_length);
2006-08-09 16:15:27 -04:00
}
2006-10-16 17:43:11 -04:00
#define FROB \
CELL code_format = to_cell(get(ds)); \
F_VECTOR *code = untag_vector(get(ds - CELLS)); \
F_VECTOR *words = untag_vector(get(ds - CELLS * 2)); \
F_VECTOR *literals = untag_vector(get(ds - CELLS * 3)); \
F_VECTOR *rel = untag_vector(get(ds - CELLS * 4)); \
CELL code_length = align8(untag_fixnum_fast(code->top) * code_format); \
2006-10-24 20:26:32 -04:00
CELL rel_length = untag_fixnum_fast(rel->top) * sizeof(unsigned int); \
2006-10-16 17:43:11 -04:00
CELL literal_length = untag_fixnum_fast(literals->top) * CELLS; \
CELL words_length = untag_fixnum_fast(words->top) * CELLS;
2006-08-09 16:15:27 -04:00
void primitive_add_compiled_block(void)
{
2006-10-16 17:43:11 -04:00
CELL start;
{
2006-11-01 00:20:49 -05:00
/* Read parameters from stack, leaving them on the stack */
2006-10-16 17:43:11 -04:00
FROB
2006-11-02 03:00:02 -05:00
if(code->header != tag_header(VECTOR_TYPE))
critical_error("FUCKUP 1",0);
2006-10-16 17:43:11 -04:00
2006-11-01 00:20:49 -05:00
/* Try allocating a new code block */
2006-10-16 17:43:11 -04:00
CELL total_length = sizeof(F_COMPILED) + code_length
+ rel_length + literal_length + words_length;
start = heap_allot(&compiling,total_length);
2006-11-01 00:20:49 -05:00
/* If allocation failed, do a code GC */
2006-10-16 17:43:11 -04:00
if(start == 0)
{
garbage_collection(TENURED,true);
start = heap_allot(&compiling,total_length);
2006-11-01 00:20:49 -05:00
/* Insufficient room even after code GC, give up */
2006-10-16 17:43:11 -04:00
if(start == 0)
2006-11-02 03:00:02 -05:00
critical_error("Out of memory in add-compiled-block",0);
2006-10-16 17:43:11 -04:00
}
}
/* we have to read the parameters again, since we may have called
2006-11-01 00:20:49 -05:00
GC above in which case the data heap semi-spaces will have switched */
2006-10-16 17:43:11 -04:00
FROB
/* now we can pop the parameters from the stack */
ds -= CELLS * 5;
/* begin depositing the code block's contents */
CELL here = start;
/* compiled header */
F_COMPILED header;
header.code_length = code_length;
header.reloc_length = rel_length;
header.literal_length = literal_length;
header.words_length = words_length;
header.finalized = false;
memcpy((void*)here,&header,sizeof(F_COMPILED));
here += sizeof(F_COMPILED);
/* code */
deposit_integers(here,code,code_format);
here += code_length;
/* relation info */
2006-10-24 20:26:32 -04:00
deposit_integers(here,rel,sizeof(unsigned int));
2006-10-16 17:43:11 -04:00
here += rel_length;
/* literals */
deposit_objects(here,literals,literal_length);
here += literal_length;
/* words */
deposit_objects(here,words,words_length);
here += words_length;
2006-08-09 16:15:27 -04:00
2006-09-02 01:58:23 -04:00
/* push the XT of the new word on the stack */
2006-10-16 17:43:11 -04:00
box_unsigned_cell(start + sizeof(F_COMPILED));
2006-08-09 16:15:27 -04:00
}
2006-10-16 17:43:11 -04:00
#undef FROB
2006-11-01 00:20:49 -05:00
/* After batch compiling a bunch of words, perform various fixups to make them
executable */
2006-08-09 16:15:27 -04:00
void primitive_finalize_compile(void)
{
F_ARRAY *array = untag_array(dpop());
2006-09-26 16:42:29 -04:00
/* set word XT's */
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)));
2006-11-18 04:04:11 -05:00
CELL xt = to_cell(get(AREF(pair,1)));
F_BLOCK *block = xt_to_block(xt);
if(block->status != B_ALLOCATED)
critical_error("bad XT",xt);
word->xt = xt;
word->compiledp = T;
}
2006-09-11 00:12:42 -04:00
2006-09-26 16:42:29 -04:00
/* perform relocation */
for(i = 0; i < count; i++)
{
F_ARRAY *pair = untag_array(get(AREF(array,i)));
2006-11-18 04:04:11 -05:00
F_WORD *word = untag_word(get(AREF(pair,0)));
CELL xt = word->xt;
iterate_code_heap_step(xt_to_compiled(xt),finalize_code_block);
2006-09-26 16:42:29 -04:00
}
2006-08-09 16:15:27 -04:00
}