factor/vm/image.c

209 lines
4.7 KiB
C

#include "factor.h"
/* Certain special objects in the image are known to the runtime */
void init_objects(F_HEADER *h)
{
int i;
for(i = 0; i < USER_ENV; i++)
userenv[i] = F;
userenv[GLOBAL_ENV] = h->global;
userenv[BOOT_ENV] = h->boot;
T = h->t;
bignum_zero = h->bignum_zero;
bignum_pos_one = h->bignum_pos_one;
bignum_neg_one = h->bignum_neg_one;
}
INLINE void load_data_heap(FILE *file, F_HEADER *h, F_PARAMETERS *p)
{
CELL good_size = h->data_size * 2;
if(good_size > p->aging_size)
p->aging_size = good_size;
init_data_heap(p->gen_count,p->young_size,p->aging_size,p->secure_gc);
if(fread((void*)tenured.start,h->data_size,1,file) != 1)
fatal_error("load_data_heap failed",0);
tenured.here = tenured.start + h->data_size;
data_relocation_base = h->data_relocation_base;
}
INLINE void load_code_heap(FILE *file, F_HEADER *h, F_PARAMETERS *p)
{
CELL good_size = h->code_size * 2;
if(good_size > p->code_size)
p->code_size = good_size;
init_code_heap(p->code_size);
if(h->code_size != 0
&& fread(first_block(&code_heap),h->code_size,1,file) != 1)
fatal_error("load_code_heap failed",0);
code_relocation_base = h->code_relocation_base;
build_free_list(&code_heap,h->code_size);
}
/* Read an image file from disk, only done once during startup */
/* This function also initializes the data and code heaps */
void load_image(F_PARAMETERS *p)
{
FILE *file = fopen(p->image,"rb");
if(file == NULL)
{
fprintf(stderr,"Cannot open image file: %s\n",p->image);
fprintf(stderr,"%s\n",strerror(errno));
exit(1);
}
F_HEADER h;
fread(&h,sizeof(F_HEADER),1,file);
if(h.magic != IMAGE_MAGIC)
fatal_error("Bad image: magic number check failed",h.magic);
if(h.version != IMAGE_VERSION)
fatal_error("Bad image: version number check failed",h.version);
load_data_heap(file,&h,p);
load_code_heap(file,&h,p);
fclose(file);
init_objects(&h);
relocate_data();
relocate_code();
/* Store image path name */
userenv[IMAGE_ENV] = tag_object(from_char_string(p->image));
}
/* Save the current image to disk */
bool save_image(const char* filename)
{
FILE* file;
F_HEADER h;
fprintf(stderr,"*** Saving %s...\n",filename);
file = fopen(filename,"wb");
if(file == NULL)
fatal_error("Cannot open image for writing",errno);
h.magic = IMAGE_MAGIC;
h.version = IMAGE_VERSION;
h.data_relocation_base = tenured.start;
h.boot = userenv[BOOT_ENV];
h.data_size = tenured.here - tenured.start;
h.global = userenv[GLOBAL_ENV];
h.t = T;
h.bignum_zero = bignum_zero;
h.bignum_pos_one = bignum_pos_one;
h.bignum_neg_one = bignum_neg_one;
h.code_size = heap_size(&code_heap);
h.code_relocation_base = code_heap.segment->start;
fwrite(&h,sizeof(F_HEADER),1,file);
fwrite((void*)tenured.start,h.data_size,1,file);
fwrite(first_block(&code_heap),h.code_size,1,file);
fclose(file);
return true;
}
void primitive_save_image(void)
{
/* do a full GC to push everything into tenured space */
primitive_code_gc();
F_STRING* filename = untag_string(dpop());
save_image(to_char_string(filename,true));
}
/* Initialize an object in a newly-loaded image */
void relocate_object(CELL relocating)
{
CELL scan = relocating;
CELL payload_start = binary_payload_start(scan);
CELL end = scan + payload_start;
scan += CELLS;
while(scan < end)
{
data_fixup((CELL*)scan);
scan += CELLS;
}
switch(untag_header(get(relocating)))
{
case WORD_TYPE:
fixup_word((F_WORD*)relocating);
break;
case STRING_TYPE:
rehash_string((F_STRING*)relocating);
break;
case DLL_TYPE:
ffi_dlopen((F_DLL*)relocating,false);
break;
case ALIEN_TYPE:
fixup_alien((F_ALIEN*)relocating);
break;
}
}
/* 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()
{
CELL relocating;
data_fixup(&userenv[BOOT_ENV]);
data_fixup(&userenv[GLOBAL_ENV]);
data_fixup(&T);
data_fixup(&bignum_zero);
data_fixup(&bignum_pos_one);
data_fixup(&bignum_neg_one);
for(relocating = tenured.start;
relocating < tenured.here;
relocating += untagged_object_size(relocating))
{
allot_barrier(relocating);
relocate_object(relocating);
}
}
void fixup_code_block(F_COMPILED *relocating, CELL code_start,
CELL reloc_start, CELL literal_start, CELL words_start, CELL words_end)
{
/* relocate literal table data */
CELL scan;
CELL literal_end = literal_start + relocating->literal_length;
for(scan = literal_start; scan < literal_end; scan += CELLS)
data_fixup((CELL*)scan);
for(scan = words_start; scan < words_end; scan += CELLS)
{
if(relocating->finalized)
code_fixup((XT*)scan);
else
data_fixup((CELL*)scan);
}
relocate_code_block(relocating,code_start,reloc_start,
literal_start,words_start,words_end);
}
void relocate_code()
{
iterate_code_heap(fixup_code_block);
}