VM: Refactor image.cpp/hpp to Factor style
parent
4ea2e9ed06
commit
cae6a5e855
179
vm/image.cpp
179
vm/image.cpp
|
@ -1,11 +1,9 @@
|
|||
#include "master.hpp"
|
||||
|
||||
namespace factor
|
||||
{
|
||||
namespace factor {
|
||||
|
||||
/* 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));
|
||||
|
||||
true_object = h->true_object;
|
||||
|
@ -14,18 +12,15 @@ void factor_vm::init_objects(image_header *h)
|
|||
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);
|
||||
|
||||
init_data_heap(p->young_size,
|
||||
p->aging_size,
|
||||
p->tenured_size);
|
||||
init_data_heap(p->young_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 << h->data_size << " bytes expected\n";
|
||||
fatal_error("load_data_heap failed", 0);
|
||||
|
@ -34,18 +29,16 @@ void factor_vm::load_data_heap(FILE *file, image_header *h, vm_parameters *p)
|
|||
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)
|
||||
fatal_error("Code heap too small to fit image", h->code_size);
|
||||
|
||||
init_code_heap(p->code_size);
|
||||
|
||||
if(h->code_size != 0)
|
||||
{
|
||||
size_t bytes_read = safe_fread(code->allocator->first_block(),1,h->code_size,file);
|
||||
if(bytes_read != h->code_size)
|
||||
{
|
||||
if (h->code_size != 0) {
|
||||
size_t bytes_read =
|
||||
safe_fread(code->allocator->first_block(), 1, h->code_size, file);
|
||||
if (bytes_read != h->code_size) {
|
||||
std::cout << "truncated image: " << bytes_read << " bytes read, ";
|
||||
std::cout << h->code_size << " bytes expected\n";
|
||||
fatal_error("load_code_heap failed", 0);
|
||||
|
@ -62,38 +55,26 @@ struct 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_) {}
|
||||
explicit startup_fixup(cell data_offset_, cell 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);
|
||||
}
|
||||
|
||||
code_block *fixup_code(code_block *obj)
|
||||
{
|
||||
code_block* fixup_code(code_block* obj) {
|
||||
return (code_block*)((cell) obj + code_offset);
|
||||
}
|
||||
|
||||
object *translate_data(const object *obj)
|
||||
{
|
||||
return fixup_data((object *)obj);
|
||||
}
|
||||
object* translate_data(const 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);
|
||||
}
|
||||
|
||||
cell size(const object *obj)
|
||||
{
|
||||
return obj->size(*this);
|
||||
}
|
||||
cell size(const object* obj) { return obj->size(*this); }
|
||||
|
||||
cell size(code_block *compiled)
|
||||
{
|
||||
return compiled->size(*this);
|
||||
}
|
||||
cell size(code_block* compiled) { return compiled->size(*this); }
|
||||
};
|
||||
|
||||
struct start_object_updater {
|
||||
|
@ -102,22 +83,19 @@ struct start_object_updater {
|
|||
slot_visitor<startup_fixup> data_visitor;
|
||||
code_block_visitor<startup_fixup> code_visitor;
|
||||
|
||||
start_object_updater(factor_vm *parent_, startup_fixup fixup_) :
|
||||
parent(parent_),
|
||||
start_object_updater(factor_vm* parent_, startup_fixup fixup_)
|
||||
: parent(parent_),
|
||||
fixup(fixup_),
|
||||
data_visitor(slot_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);
|
||||
|
||||
data_visitor.visit_slots(obj);
|
||||
|
||||
switch(obj->type())
|
||||
{
|
||||
case ALIEN_TYPE:
|
||||
{
|
||||
switch (obj->type()) {
|
||||
case ALIEN_TYPE: {
|
||||
|
||||
alien* ptr = (alien*)obj;
|
||||
|
||||
|
@ -127,13 +105,11 @@ struct start_object_updater {
|
|||
ptr->expired = parent->true_object;
|
||||
break;
|
||||
}
|
||||
case DLL_TYPE:
|
||||
{
|
||||
case DLL_TYPE: {
|
||||
parent->ffi_dlopen((dll*)obj);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
default: {
|
||||
code_visitor.visit_object_code_block(obj);
|
||||
break;
|
||||
}
|
||||
|
@ -141,8 +117,7 @@ struct start_object_updater {
|
|||
}
|
||||
};
|
||||
|
||||
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);
|
||||
slot_visitor<startup_fixup> data_workhorse(this, fixup);
|
||||
data_workhorse.visit_roots();
|
||||
|
@ -156,32 +131,31 @@ struct startup_code_block_relocation_visitor {
|
|||
startup_fixup fixup;
|
||||
slot_visitor<startup_fixup> data_visitor;
|
||||
|
||||
startup_code_block_relocation_visitor(factor_vm *parent_, startup_fixup fixup_) :
|
||||
parent(parent_),
|
||||
startup_code_block_relocation_visitor(factor_vm* parent_,
|
||||
startup_fixup fixup_)
|
||||
: parent(parent_),
|
||||
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;
|
||||
cell old_offset = op.rel_offset() + (cell)compiled->entry_point() - fixup.code_offset;
|
||||
cell old_offset =
|
||||
op.rel_offset() + (cell) compiled->entry_point() - fixup.code_offset;
|
||||
|
||||
switch(op.rel_type())
|
||||
{
|
||||
case RT_LITERAL:
|
||||
{
|
||||
switch (op.rel_type()) {
|
||||
case RT_LITERAL: {
|
||||
cell value = op.load_value(old_offset);
|
||||
if (immediate_p(value))
|
||||
op.store_value(value);
|
||||
else
|
||||
op.store_value(RETAG(fixup.fixup_data(untag<object>(value)),TAG(value)));
|
||||
op.store_value(
|
||||
RETAG(fixup.fixup_data(untag<object>(value)), TAG(value)));
|
||||
break;
|
||||
}
|
||||
case RT_ENTRY_POINT:
|
||||
case RT_ENTRY_POINT_PIC:
|
||||
case RT_ENTRY_POINT_PIC_TAIL:
|
||||
case RT_HERE:
|
||||
{
|
||||
case RT_HERE: {
|
||||
cell value = op.load_value(old_offset);
|
||||
cell offset = TAG(value);
|
||||
code_block* compiled = (code_block*)UNTAG(value);
|
||||
|
@ -201,11 +175,10 @@ struct startup_code_block_updater {
|
|||
factor_vm* parent;
|
||||
startup_fixup fixup;
|
||||
|
||||
startup_code_block_updater(factor_vm *parent_, startup_fixup fixup_) :
|
||||
parent(parent_), fixup(fixup_) {}
|
||||
startup_code_block_updater(factor_vm* parent_, startup_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);
|
||||
data_visitor.visit_code_block_objects(compiled);
|
||||
|
||||
|
@ -214,51 +187,43 @@ struct startup_code_block_updater {
|
|||
}
|
||||
};
|
||||
|
||||
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_code_block_updater updater(this, 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_fread(footer, (off_t) sizeof(embedded_image_footer), 1, file);
|
||||
return footer->magic == image_magic;
|
||||
}
|
||||
|
||||
FILE* factor_vm::open_image(vm_parameters *p)
|
||||
{
|
||||
if (p->embedded_image)
|
||||
{
|
||||
FILE* factor_vm::open_image(vm_parameters* p) {
|
||||
if (p->embedded_image) {
|
||||
FILE* file = OPEN_READ(p->executable_path);
|
||||
if (file == NULL)
|
||||
{
|
||||
if (file == NULL) {
|
||||
std::cout << "Cannot open embedded image" << std::endl;
|
||||
std::cout << strerror(errno) << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
embedded_image_footer footer;
|
||||
if (!read_embedded_image_footer(file, &footer))
|
||||
{
|
||||
if (!read_embedded_image_footer(file, &footer)) {
|
||||
std::cout << "No embedded image" << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
safe_fseek(file, (off_t) footer.image_offset, SEEK_SET);
|
||||
return file;
|
||||
}
|
||||
else
|
||||
} else
|
||||
return OPEN_READ(p->image_path);
|
||||
}
|
||||
|
||||
/* Read an image file from disk, only done once during startup */
|
||||
/* 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);
|
||||
if(file == NULL)
|
||||
{
|
||||
if (file == NULL) {
|
||||
std::cout << "Cannot open image file: " << p->image_path << std::endl;
|
||||
std::cout << strerror(errno) << std::endl;
|
||||
exit(1);
|
||||
|
@ -292,14 +257,13 @@ void factor_vm::load_image(vm_parameters *p)
|
|||
}
|
||||
|
||||
/* 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;
|
||||
image_header h;
|
||||
|
||||
file = OPEN_WRITE(saving_filename);
|
||||
if(file == NULL)
|
||||
{
|
||||
if (file == NULL) {
|
||||
std::cout << "Cannot open image file: " << saving_filename << std::endl;
|
||||
std::cout << strerror(errno) << std::endl;
|
||||
return false;
|
||||
|
@ -318,13 +282,17 @@ bool factor_vm::save_image(const vm_char *saving_filename, const vm_char *filena
|
|||
h.bignum_neg_one = bignum_neg_one;
|
||||
|
||||
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;
|
||||
|
||||
if(safe_fwrite(&h,sizeof(image_header),1,file) != 1) ok = false;
|
||||
if(safe_fwrite((void*)data->tenured->start,h.data_size,1,file) != 1) ok = false;
|
||||
if(safe_fwrite(code->allocator->first_block(),h.code_size,1,file) != 1) ok = false;
|
||||
if (safe_fwrite(&h, sizeof(image_header), 1, file) != 1)
|
||||
ok = false;
|
||||
if (safe_fwrite((void*)data->tenured->start, h.data_size, 1, file) != 1)
|
||||
ok = false;
|
||||
if (safe_fwrite(code->allocator->first_block(), h.code_size, 1, file) != 1)
|
||||
ok = false;
|
||||
safe_fclose(file);
|
||||
|
||||
if (!ok)
|
||||
|
@ -335,8 +303,7 @@ bool factor_vm::save_image(const vm_char *saving_filename, const vm_char *filena
|
|||
return ok;
|
||||
}
|
||||
|
||||
void factor_vm::primitive_save_image()
|
||||
{
|
||||
void factor_vm::primitive_save_image() {
|
||||
/* do a full GC to push everything into tenured space */
|
||||
primitive_compact_gc();
|
||||
|
||||
|
@ -344,11 +311,11 @@ void factor_vm::primitive_save_image()
|
|||
path2.untag_check(this);
|
||||
data_root<byte_array> path1(ctx->pop(), 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
|
||||
where we might throw an error, so we have to throw an error here since
|
||||
later steps destroy the current image. */
|
||||
|
@ -359,21 +326,21 @@ void factor_vm::primitive_save_image_and_exit()
|
|||
|
||||
/* strip out special_objects data which is set on startup anyway */
|
||||
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,
|
||||
0, /* requested size */
|
||||
gc(collect_compact_op, 0, /* requested size */
|
||||
false /* discard objects only reachable from stacks */);
|
||||
|
||||
/* Save the image */
|
||||
if(save_image((vm_char *)(path1.untagged() + 1), (vm_char *)(path2.untagged() + 1)))
|
||||
if (save_image((vm_char*)(path1.untagged() + 1),
|
||||
(vm_char*)(path2.untagged() + 1)))
|
||||
exit(0);
|
||||
else
|
||||
exit(1);
|
||||
}
|
||||
|
||||
bool factor_vm::embedded_image_p()
|
||||
{
|
||||
bool factor_vm::embedded_image_p() {
|
||||
const vm_char* vm_path = vm_executable_path();
|
||||
if (!vm_path)
|
||||
return false;
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
namespace factor
|
||||
{
|
||||
namespace factor {
|
||||
|
||||
static const cell image_magic = 0x0f0e0d0c;
|
||||
static const cell image_version = 4;
|
||||
|
|
Loading…
Reference in New Issue