VM: Refactor image.cpp/hpp to Factor style

db4
Erik Charlebois 2013-05-11 22:05:00 -04:00
parent 4ea2e9ed06
commit cae6a5e855
2 changed files with 297 additions and 331 deletions

View File

@ -1,389 +1,356 @@
#include "master.hpp" #include "master.hpp"
namespace factor namespace factor {
{
/* Certain special objects in the image are known to the runtime */ /* Certain special objects in the image are known to the runtime */
void factor_vm::init_objects(image_header *h) void factor_vm::init_objects(image_header* h) {
{ memcpy(special_objects, h->special_objects, sizeof(special_objects));
memcpy(special_objects,h->special_objects,sizeof(special_objects));
true_object = h->true_object; true_object = h->true_object;
bignum_zero = h->bignum_zero; bignum_zero = h->bignum_zero;
bignum_pos_one = h->bignum_pos_one; bignum_pos_one = h->bignum_pos_one;
bignum_neg_one = h->bignum_neg_one; bignum_neg_one = h->bignum_neg_one;
} }
void factor_vm::load_data_heap(FILE *file, image_header *h, vm_parameters *p) void factor_vm::load_data_heap(FILE* file, image_header* h, vm_parameters* p) {
{ p->tenured_size = std::max((h->data_size * 3) / 2, p->tenured_size);
p->tenured_size = std::max((h->data_size * 3) / 2,p->tenured_size);
init_data_heap(p->young_size, init_data_heap(p->young_size, p->aging_size, p->tenured_size);
p->aging_size,
p->tenured_size);
fixnum bytes_read = safe_fread((void*)data->tenured->start,1,h->data_size,file); fixnum bytes_read =
safe_fread((void*)data->tenured->start, 1, h->data_size, file);
if((cell)bytes_read != h->data_size) if ((cell) bytes_read != h->data_size) {
{ std::cout << "truncated image: " << bytes_read << " bytes read, ";
std::cout << "truncated image: " << bytes_read << " bytes read, "; std::cout << h->data_size << " bytes expected\n";
std::cout << h->data_size << " bytes expected\n"; fatal_error("load_data_heap failed", 0);
fatal_error("load_data_heap failed",0); }
}
data->tenured->initial_free_list(h->data_size); data->tenured->initial_free_list(h->data_size);
} }
void factor_vm::load_code_heap(FILE *file, image_header *h, vm_parameters *p) void factor_vm::load_code_heap(FILE* file, image_header* h, vm_parameters* p) {
{ if (h->code_size > p->code_size)
if(h->code_size > p->code_size) fatal_error("Code heap too small to fit image", h->code_size);
fatal_error("Code heap too small to fit image",h->code_size);
init_code_heap(p->code_size); init_code_heap(p->code_size);
if(h->code_size != 0) if (h->code_size != 0) {
{ size_t bytes_read =
size_t bytes_read = safe_fread(code->allocator->first_block(),1,h->code_size,file); safe_fread(code->allocator->first_block(), 1, h->code_size, file);
if(bytes_read != h->code_size) if (bytes_read != h->code_size) {
{ std::cout << "truncated image: " << bytes_read << " bytes read, ";
std::cout << "truncated image: " << bytes_read << " bytes read, "; std::cout << h->code_size << " bytes expected\n";
std::cout << h->code_size << " bytes expected\n"; fatal_error("load_code_heap failed", 0);
fatal_error("load_code_heap failed",0); }
} }
}
code->allocator->initial_free_list(h->code_size); code->allocator->initial_free_list(h->code_size);
code->initialize_all_blocks_set(); code->initialize_all_blocks_set();
} }
struct startup_fixup { struct startup_fixup {
static const bool translated_code_block_map = true; static const bool translated_code_block_map = true;
cell data_offset; cell data_offset;
cell code_offset; cell code_offset;
explicit startup_fixup(cell data_offset_, cell code_offset_) : explicit startup_fixup(cell data_offset_, cell code_offset_)
data_offset(data_offset_), code_offset(code_offset_) {} : data_offset(data_offset_), code_offset(code_offset_) {}
object *fixup_data(object *obj) object* fixup_data(object* obj) {
{ return (object*)((cell) obj + data_offset);
return (object *)((cell)obj + data_offset); }
}
code_block *fixup_code(code_block *obj) code_block* fixup_code(code_block* obj) {
{ return (code_block*)((cell) obj + code_offset);
return (code_block *)((cell)obj + code_offset); }
}
object *translate_data(const object *obj) object* translate_data(const object* obj) { return fixup_data((object*)obj); }
{
return fixup_data((object *)obj);
}
code_block *translate_code(const code_block *compiled) code_block* translate_code(const code_block* compiled) {
{ return fixup_code((code_block*)compiled);
return fixup_code((code_block *)compiled); }
}
cell size(const object *obj) cell size(const object* obj) { return obj->size(*this); }
{
return obj->size(*this);
}
cell size(code_block *compiled) cell size(code_block* compiled) { return compiled->size(*this); }
{
return compiled->size(*this);
}
}; };
struct start_object_updater { struct start_object_updater {
factor_vm *parent; factor_vm* parent;
startup_fixup fixup; startup_fixup fixup;
slot_visitor<startup_fixup> data_visitor; slot_visitor<startup_fixup> data_visitor;
code_block_visitor<startup_fixup> code_visitor; code_block_visitor<startup_fixup> code_visitor;
start_object_updater(factor_vm *parent_, startup_fixup fixup_) : start_object_updater(factor_vm* parent_, startup_fixup fixup_)
parent(parent_), : parent(parent_),
fixup(fixup_), fixup(fixup_),
data_visitor(slot_visitor<startup_fixup>(parent_,fixup_)), data_visitor(slot_visitor<startup_fixup>(parent_, fixup_)),
code_visitor(code_block_visitor<startup_fixup>(parent_,fixup_)) {} code_visitor(code_block_visitor<startup_fixup>(parent_, fixup_)) {}
void operator()(object *obj, cell size) void operator()(object* obj, cell size) {
{ parent->data->tenured->starts.record_object_start_offset(obj);
parent->data->tenured->starts.record_object_start_offset(obj);
data_visitor.visit_slots(obj); data_visitor.visit_slots(obj);
switch(obj->type()) switch (obj->type()) {
{ case ALIEN_TYPE: {
case ALIEN_TYPE:
{
alien *ptr = (alien *)obj; alien* ptr = (alien*)obj;
if(to_boolean(ptr->base)) if (to_boolean(ptr->base))
ptr->update_address(); ptr->update_address();
else else
ptr->expired = parent->true_object; ptr->expired = parent->true_object;
break; break;
} }
case DLL_TYPE: case DLL_TYPE: {
{ parent->ffi_dlopen((dll*)obj);
parent->ffi_dlopen((dll *)obj); break;
break; }
} default: {
default: code_visitor.visit_object_code_block(obj);
{ break;
code_visitor.visit_object_code_block(obj); }
break; }
} }
}
}
}; };
void factor_vm::fixup_data(cell data_offset, cell code_offset) void factor_vm::fixup_data(cell data_offset, cell code_offset) {
{ startup_fixup fixup(data_offset, code_offset);
startup_fixup fixup(data_offset,code_offset); slot_visitor<startup_fixup> data_workhorse(this, fixup);
slot_visitor<startup_fixup> data_workhorse(this,fixup); data_workhorse.visit_roots();
data_workhorse.visit_roots();
start_object_updater updater(this,fixup); start_object_updater updater(this, fixup);
data->tenured->iterate(updater,fixup); data->tenured->iterate(updater, fixup);
} }
struct startup_code_block_relocation_visitor { struct startup_code_block_relocation_visitor {
factor_vm *parent; factor_vm* parent;
startup_fixup fixup; startup_fixup fixup;
slot_visitor<startup_fixup> data_visitor; slot_visitor<startup_fixup> data_visitor;
startup_code_block_relocation_visitor(factor_vm *parent_, startup_fixup fixup_) : startup_code_block_relocation_visitor(factor_vm* parent_,
parent(parent_), startup_fixup fixup_)
fixup(fixup_), : parent(parent_),
data_visitor(slot_visitor<startup_fixup>(parent_,fixup_)) {} fixup(fixup_),
data_visitor(slot_visitor<startup_fixup>(parent_, fixup_)) {}
void operator()(instruction_operand op) void operator()(instruction_operand op) {
{ code_block* compiled = op.compiled;
code_block *compiled = op.compiled; cell old_offset =
cell old_offset = op.rel_offset() + (cell)compiled->entry_point() - fixup.code_offset; op.rel_offset() + (cell) compiled->entry_point() - fixup.code_offset;
switch(op.rel_type()) switch (op.rel_type()) {
{ case RT_LITERAL: {
case RT_LITERAL: cell value = op.load_value(old_offset);
{ if (immediate_p(value))
cell value = op.load_value(old_offset); op.store_value(value);
if(immediate_p(value)) else
op.store_value(value); op.store_value(
else RETAG(fixup.fixup_data(untag<object>(value)), TAG(value)));
op.store_value(RETAG(fixup.fixup_data(untag<object>(value)),TAG(value))); break;
break; }
} case RT_ENTRY_POINT:
case RT_ENTRY_POINT: case RT_ENTRY_POINT_PIC:
case RT_ENTRY_POINT_PIC: case RT_ENTRY_POINT_PIC_TAIL:
case RT_ENTRY_POINT_PIC_TAIL: case RT_HERE: {
case RT_HERE: cell value = op.load_value(old_offset);
{ cell offset = TAG(value);
cell value = op.load_value(old_offset); code_block* compiled = (code_block*)UNTAG(value);
cell offset = TAG(value); op.store_value((cell) fixup.fixup_code(compiled) + offset);
code_block *compiled = (code_block *)UNTAG(value); break;
op.store_value((cell)fixup.fixup_code(compiled) + offset); }
break; case RT_UNTAGGED:
} break;
case RT_UNTAGGED: default:
break; parent->store_external_address(op);
default: break;
parent->store_external_address(op); }
break; }
}
}
}; };
struct startup_code_block_updater { struct startup_code_block_updater {
factor_vm *parent; factor_vm* parent;
startup_fixup fixup; startup_fixup fixup;
startup_code_block_updater(factor_vm *parent_, startup_fixup fixup_) : startup_code_block_updater(factor_vm* parent_, startup_fixup fixup_)
parent(parent_), fixup(fixup_) {} : parent(parent_), fixup(fixup_) {}
void operator()(code_block *compiled, cell size) void operator()(code_block* compiled, cell size) {
{ slot_visitor<startup_fixup> data_visitor(parent, fixup);
slot_visitor<startup_fixup> data_visitor(parent,fixup); data_visitor.visit_code_block_objects(compiled);
data_visitor.visit_code_block_objects(compiled);
startup_code_block_relocation_visitor code_visitor(parent,fixup); startup_code_block_relocation_visitor code_visitor(parent, fixup);
compiled->each_instruction_operand(code_visitor); compiled->each_instruction_operand(code_visitor);
} }
}; };
void factor_vm::fixup_code(cell data_offset, cell code_offset) void factor_vm::fixup_code(cell data_offset, cell code_offset) {
{ startup_fixup fixup(data_offset, code_offset);
startup_fixup fixup(data_offset,code_offset); startup_code_block_updater updater(this, fixup);
startup_code_block_updater updater(this,fixup); code->allocator->iterate(updater, fixup);
code->allocator->iterate(updater,fixup);
} }
bool factor_vm::read_embedded_image_footer(FILE *file, embedded_image_footer *footer) bool factor_vm::read_embedded_image_footer(FILE* file,
{ embedded_image_footer* footer) {
safe_fseek(file, -(off_t)sizeof(embedded_image_footer), SEEK_END); safe_fseek(file, -(off_t) sizeof(embedded_image_footer), SEEK_END);
safe_fread(footer, (off_t)sizeof(embedded_image_footer), 1, file); safe_fread(footer, (off_t) sizeof(embedded_image_footer), 1, file);
return footer->magic == image_magic; return footer->magic == image_magic;
} }
FILE* factor_vm::open_image(vm_parameters *p) FILE* factor_vm::open_image(vm_parameters* p) {
{ if (p->embedded_image) {
if (p->embedded_image) FILE* file = OPEN_READ(p->executable_path);
{ if (file == NULL) {
FILE *file = OPEN_READ(p->executable_path); std::cout << "Cannot open embedded image" << std::endl;
if (file == NULL) std::cout << strerror(errno) << std::endl;
{ exit(1);
std::cout << "Cannot open embedded image" << std::endl; }
std::cout << strerror(errno) << std::endl; embedded_image_footer footer;
exit(1); if (!read_embedded_image_footer(file, &footer)) {
} std::cout << "No embedded image" << std::endl;
embedded_image_footer footer; exit(1);
if (!read_embedded_image_footer(file, &footer)) }
{ safe_fseek(file, (off_t) footer.image_offset, SEEK_SET);
std::cout << "No embedded image" << std::endl; return file;
exit(1); } else
} return OPEN_READ(p->image_path);
safe_fseek(file, (off_t)footer.image_offset, SEEK_SET);
return file;
}
else
return OPEN_READ(p->image_path);
} }
/* Read an image file from disk, only done once during startup */ /* Read an image file from disk, only done once during startup */
/* This function also initializes the data and code heaps */ /* This function also initializes the data and code heaps */
void factor_vm::load_image(vm_parameters *p) void factor_vm::load_image(vm_parameters* p) {
{ FILE* file = open_image(p);
FILE *file = open_image(p); if (file == NULL) {
if(file == NULL) std::cout << "Cannot open image file: " << p->image_path << std::endl;
{ std::cout << strerror(errno) << std::endl;
std::cout << "Cannot open image file: " << p->image_path << std::endl; exit(1);
std::cout << strerror(errno) << std::endl; }
exit(1);
}
image_header h; image_header h;
if(safe_fread(&h,sizeof(image_header),1,file) != 1) if (safe_fread(&h, sizeof(image_header), 1, file) != 1)
fatal_error("Cannot read image header",0); fatal_error("Cannot read image header", 0);
if(h.magic != image_magic) if (h.magic != image_magic)
fatal_error("Bad image: magic number check failed",h.magic); fatal_error("Bad image: magic number check failed", h.magic);
if(h.version != image_version) if (h.version != image_version)
fatal_error("Bad image: version number check failed",h.version); fatal_error("Bad image: version number check failed", h.version);
load_data_heap(file,&h,p); load_data_heap(file, &h, p);
load_code_heap(file,&h,p); load_code_heap(file, &h, p);
safe_fclose(file); safe_fclose(file);
init_objects(&h); init_objects(&h);
cell data_offset = data->tenured->start - h.data_relocation_base; cell data_offset = data->tenured->start - h.data_relocation_base;
cell code_offset = code->allocator->start - h.code_relocation_base; cell code_offset = code->allocator->start - h.code_relocation_base;
fixup_data(data_offset,code_offset); fixup_data(data_offset, code_offset);
fixup_code(data_offset,code_offset); fixup_code(data_offset, code_offset);
/* Store image path name */ /* Store image path name */
special_objects[OBJ_IMAGE] = allot_alien(false_object,(cell)p->image_path); special_objects[OBJ_IMAGE] = allot_alien(false_object, (cell) p->image_path);
} }
/* Save the current image to disk */ /* Save the current image to disk */
bool factor_vm::save_image(const vm_char *saving_filename, const vm_char *filename) bool factor_vm::save_image(const vm_char* saving_filename,
{ const vm_char* filename) {
FILE* file; FILE* file;
image_header h; image_header h;
file = OPEN_WRITE(saving_filename); file = OPEN_WRITE(saving_filename);
if(file == NULL) if (file == NULL) {
{ std::cout << "Cannot open image file: " << saving_filename << std::endl;
std::cout << "Cannot open image file: " << saving_filename << std::endl; std::cout << strerror(errno) << std::endl;
std::cout << strerror(errno) << std::endl; return false;
return false; }
}
h.magic = image_magic; h.magic = image_magic;
h.version = image_version; h.version = image_version;
h.data_relocation_base = data->tenured->start; h.data_relocation_base = data->tenured->start;
h.data_size = data->tenured->occupied_space(); h.data_size = data->tenured->occupied_space();
h.code_relocation_base = code->allocator->start; h.code_relocation_base = code->allocator->start;
h.code_size = code->allocator->occupied_space(); h.code_size = code->allocator->occupied_space();
h.true_object = true_object; h.true_object = true_object;
h.bignum_zero = bignum_zero; h.bignum_zero = bignum_zero;
h.bignum_pos_one = bignum_pos_one; h.bignum_pos_one = bignum_pos_one;
h.bignum_neg_one = bignum_neg_one; h.bignum_neg_one = bignum_neg_one;
for(cell i = 0; i < special_object_count; i++) for (cell i = 0; i < special_object_count; i++)
h.special_objects[i] = (save_special_p(i) ? special_objects[i] : false_object); h.special_objects[i] =
(save_special_p(i) ? special_objects[i] : false_object);
bool ok = true; bool ok = true;
if(safe_fwrite(&h,sizeof(image_header),1,file) != 1) ok = false; if (safe_fwrite(&h, sizeof(image_header), 1, file) != 1)
if(safe_fwrite((void*)data->tenured->start,h.data_size,1,file) != 1) ok = false; ok = false;
if(safe_fwrite(code->allocator->first_block(),h.code_size,1,file) != 1) ok = false; if (safe_fwrite((void*)data->tenured->start, h.data_size, 1, file) != 1)
safe_fclose(file); ok = false;
if (safe_fwrite(code->allocator->first_block(), h.code_size, 1, file) != 1)
ok = false;
safe_fclose(file);
if(!ok) if (!ok)
std::cout << "save-image failed: " << strerror(errno) << std::endl; std::cout << "save-image failed: " << strerror(errno) << std::endl;
else else
move_file(saving_filename,filename); move_file(saving_filename, filename);
return ok; return ok;
} }
void factor_vm::primitive_save_image() void factor_vm::primitive_save_image() {
{ /* do a full GC to push everything into tenured space */
/* do a full GC to push everything into tenured space */ primitive_compact_gc();
primitive_compact_gc();
data_root<byte_array> path2(ctx->pop(),this); data_root<byte_array> path2(ctx->pop(), this);
path2.untag_check(this); path2.untag_check(this);
data_root<byte_array> path1(ctx->pop(),this); data_root<byte_array> path1(ctx->pop(), this);
path1.untag_check(this); path1.untag_check(this);
save_image((vm_char *)(path1.untagged() + 1 ),(vm_char *)(path2.untagged() + 1)); save_image((vm_char*)(path1.untagged() + 1),
(vm_char*)(path2.untagged() + 1));
} }
void factor_vm::primitive_save_image_and_exit() void factor_vm::primitive_save_image_and_exit() {
{ /* We unbox this before doing anything else. This is the only point
/* We unbox this before doing anything else. This is the only point where we might throw an error, so we have to throw an error here since
where we might throw an error, so we have to throw an error here since later steps destroy the current image. */
later steps destroy the current image. */ data_root<byte_array> path2(ctx->pop(), this);
data_root<byte_array> path2(ctx->pop(),this); path2.untag_check(this);
path2.untag_check(this); data_root<byte_array> path1(ctx->pop(), this);
data_root<byte_array> path1(ctx->pop(),this); path1.untag_check(this);
path1.untag_check(this);
/* strip out special_objects data which is set on startup anyway */ /* strip out special_objects data which is set on startup anyway */
for(cell i = 0; i < special_object_count; i++) for (cell i = 0; i < special_object_count; i++)
if(!save_special_p(i)) special_objects[i] = false_object; if (!save_special_p(i))
special_objects[i] = false_object;
gc(collect_compact_op, gc(collect_compact_op, 0, /* requested size */
0, /* requested size */ false /* discard objects only reachable from stacks */);
false /* discard objects only reachable from stacks */);
/* Save the image */ /* Save the image */
if(save_image((vm_char *)(path1.untagged() + 1), (vm_char *)(path2.untagged() + 1))) if (save_image((vm_char*)(path1.untagged() + 1),
exit(0); (vm_char*)(path2.untagged() + 1)))
else exit(0);
exit(1); else
exit(1);
} }
bool factor_vm::embedded_image_p() bool factor_vm::embedded_image_p() {
{ const vm_char* vm_path = vm_executable_path();
const vm_char *vm_path = vm_executable_path(); if (!vm_path)
if (!vm_path) return false;
return false; FILE* file = OPEN_READ(vm_path);
FILE *file = OPEN_READ(vm_path); if (!file)
if (!file) return false;
return false; embedded_image_footer footer;
embedded_image_footer footer; bool embedded_p = read_embedded_image_footer(file, &footer);
bool embedded_p = read_embedded_image_footer(file, &footer); fclose(file);
fclose(file); return embedded_p;
return embedded_p;
} }
} }

View File

@ -1,49 +1,48 @@
namespace factor namespace factor {
{
static const cell image_magic = 0x0f0e0d0c; static const cell image_magic = 0x0f0e0d0c;
static const cell image_version = 4; static const cell image_version = 4;
struct embedded_image_footer { struct embedded_image_footer {
cell magic; cell magic;
cell image_offset; cell image_offset;
}; };
struct image_header { struct image_header {
cell magic; cell magic;
cell version; cell version;
/* base address of data heap when image was saved */ /* base address of data heap when image was saved */
cell data_relocation_base; cell data_relocation_base;
/* size of heap */ /* size of heap */
cell data_size; cell data_size;
/* base address of code heap when image was saved */ /* base address of code heap when image was saved */
cell code_relocation_base; cell code_relocation_base;
/* size of code heap */ /* size of code heap */
cell code_size; cell code_size;
/* tagged pointer to t singleton */ /* tagged pointer to t singleton */
cell true_object; cell true_object;
/* tagged pointer to bignum 0 */ /* tagged pointer to bignum 0 */
cell bignum_zero; cell bignum_zero;
/* tagged pointer to bignum 1 */ /* tagged pointer to bignum 1 */
cell bignum_pos_one; cell bignum_pos_one;
/* tagged pointer to bignum -1 */ /* tagged pointer to bignum -1 */
cell bignum_neg_one; cell bignum_neg_one;
/* Initial user environment */ /* Initial user environment */
cell special_objects[special_object_count]; cell special_objects[special_object_count];
}; };
struct vm_parameters { struct vm_parameters {
bool embedded_image; bool embedded_image;
const vm_char *image_path; const vm_char* image_path;
const vm_char *executable_path; const vm_char* executable_path;
cell datastack_size, retainstack_size, callstack_size; cell datastack_size, retainstack_size, callstack_size;
cell young_size, aging_size, tenured_size; cell young_size, aging_size, tenured_size;
cell code_size; cell code_size;
bool fep; bool fep;
bool console; bool console;
bool signals; bool signals;
cell max_pic_size; cell max_pic_size;
cell callback_size; cell callback_size;
}; };
} }