5 /* Certain special objects in the image are known to the runtime */
6 void factor_vm::init_objects(image_header* h) {
7 memcpy(special_objects, h->special_objects, sizeof(special_objects));
9 true_object = h->true_object;
10 bignum_zero = h->bignum_zero;
11 bignum_pos_one = h->bignum_pos_one;
12 bignum_neg_one = h->bignum_neg_one;
15 void factor_vm::load_data_heap(FILE* file, image_header* h, vm_parameters* p) {
16 p->tenured_size = std::max((h->data_size * 3) / 2, p->tenured_size);
18 init_data_heap(p->young_size, p->aging_size, p->tenured_size);
21 safe_fread((void*)data->tenured->start, 1, h->data_size, file);
23 if ((cell)bytes_read != h->data_size) {
24 std::cout << "truncated image: " << bytes_read << " bytes read, ";
25 std::cout << h->data_size << " bytes expected\n";
26 fatal_error("load_data_heap failed", 0);
29 data->tenured->initial_free_list(h->data_size);
32 void factor_vm::load_code_heap(FILE* file, image_header* h, vm_parameters* p) {
33 if (h->code_size > p->code_size)
34 fatal_error("Code heap too small to fit image", h->code_size);
36 init_code_heap(p->code_size);
38 if (h->code_size != 0) {
40 safe_fread(code->allocator->first_block(), 1, h->code_size, file);
41 if (bytes_read != h->code_size) {
42 std::cout << "truncated image: " << bytes_read << " bytes read, ";
43 std::cout << h->code_size << " bytes expected\n";
44 fatal_error("load_code_heap failed", 0);
48 code->allocator->initial_free_list(h->code_size);
49 code->initialize_all_blocks_set();
52 struct startup_fixup {
53 static const bool translated_code_block_map = true;
58 startup_fixup(cell data_offset, cell code_offset)
59 : data_offset(data_offset), code_offset(code_offset) {}
61 object* fixup_data(object* obj) {
62 return (object*)((cell)obj + data_offset);
65 code_block* fixup_code(code_block* obj) {
66 return (code_block*)((cell)obj + code_offset);
69 object* translate_data(const object* obj) { return fixup_data((object*)obj); }
71 code_block* translate_code(const code_block* compiled) {
72 return fixup_code((code_block*)compiled);
75 cell size(const object* obj) { return obj->size(*this); }
77 cell size(code_block* compiled) { return compiled->size(*this); }
80 struct start_object_updater {
83 slot_visitor<startup_fixup> data_visitor;
84 code_block_visitor<startup_fixup> code_visitor;
86 start_object_updater(factor_vm* parent, startup_fixup fixup)
89 data_visitor(slot_visitor<startup_fixup>(parent, fixup)),
90 code_visitor(code_block_visitor<startup_fixup>(parent, fixup)) {}
92 void operator()(object* obj, cell size) {
93 parent->data->tenured->starts.record_object_start_offset(obj);
95 data_visitor.visit_slots(obj);
97 switch (obj->type()) {
100 alien* ptr = (alien*)obj;
102 if (to_boolean(ptr->base))
103 ptr->update_address();
105 ptr->expired = parent->true_object;
109 parent->ffi_dlopen((dll*)obj);
113 code_visitor.visit_object_code_block(obj);
120 void factor_vm::fixup_data(cell data_offset, cell code_offset) {
121 startup_fixup fixup(data_offset, code_offset);
122 slot_visitor<startup_fixup> data_workhorse(this, fixup);
123 data_workhorse.visit_roots();
125 start_object_updater updater(this, fixup);
126 data->tenured->iterate(updater, fixup);
129 struct startup_code_block_relocation_visitor {
132 slot_visitor<startup_fixup> data_visitor;
134 startup_code_block_relocation_visitor(factor_vm* parent,
138 data_visitor(slot_visitor<startup_fixup>(parent, fixup)) {}
140 void operator()(instruction_operand op) {
141 code_block* compiled = op.compiled;
143 op.rel_offset() + (cell)compiled->entry_point() - fixup.code_offset;
145 switch (op.rel_type()) {
147 cell value = op.load_value(old_offset);
148 if (immediate_p(value))
149 op.store_value(value);
152 RETAG(fixup.fixup_data(untag<object>(value)), TAG(value)));
156 case RT_ENTRY_POINT_PIC:
157 case RT_ENTRY_POINT_PIC_TAIL:
159 cell value = op.load_value(old_offset);
160 cell offset = TAG(value);
161 code_block* compiled = (code_block*)UNTAG(value);
162 op.store_value((cell)fixup.fixup_code(compiled) + offset);
168 parent->store_external_address(op);
174 struct startup_code_block_updater {
178 startup_code_block_updater(factor_vm* parent, startup_fixup fixup)
179 : parent(parent), fixup(fixup) {}
181 void operator()(code_block* compiled, cell size) {
182 slot_visitor<startup_fixup> data_visitor(parent, fixup);
183 data_visitor.visit_code_block_objects(compiled);
185 startup_code_block_relocation_visitor code_visitor(parent, fixup);
186 compiled->each_instruction_operand(code_visitor);
190 void factor_vm::fixup_code(cell data_offset, cell code_offset) {
191 startup_fixup fixup(data_offset, code_offset);
192 startup_code_block_updater updater(this, fixup);
193 code->allocator->iterate(updater, fixup);
196 bool factor_vm::read_embedded_image_footer(FILE* file,
197 embedded_image_footer* footer) {
198 safe_fseek(file, -(off_t)sizeof(embedded_image_footer), SEEK_END);
199 safe_fread(footer, (off_t)sizeof(embedded_image_footer), 1, file);
200 return footer->magic == image_magic;
203 char *threadsafe_strerror(int errnum) {
204 char *buf = (char *) malloc(STRERROR_BUFFER_SIZE);
206 fatal_error("Out of memory in threadsafe_strerror, errno", errnum);
208 THREADSAFE_STRERROR(errnum, buf, STRERROR_BUFFER_SIZE);
212 FILE* factor_vm::open_image(vm_parameters* p) {
213 if (p->embedded_image) {
214 FILE* file = OPEN_READ(p->executable_path);
216 std::cout << "Cannot open embedded image" << std::endl;
217 char *msg = threadsafe_strerror(errno);
218 std::cout << "strerror: " << msg << std::endl;
222 embedded_image_footer footer;
223 if (!read_embedded_image_footer(file, &footer)) {
224 std::cout << "No embedded image" << std::endl;
227 safe_fseek(file, (off_t)footer.image_offset, SEEK_SET);
230 return OPEN_READ(p->image_path);
233 /* Read an image file from disk, only done once during startup */
234 /* This function also initializes the data and code heaps */
235 void factor_vm::load_image(vm_parameters* p) {
236 FILE* file = open_image(p);
238 std::cout << "Cannot open image file: " << p->image_path << std::endl;
239 char *msg = threadsafe_strerror(errno);
240 std::cout << "strerror: " << msg << std::endl;
246 if (safe_fread(&h, sizeof(image_header), 1, file) != 1)
247 fatal_error("Cannot read image header", 0);
249 if (h.magic != image_magic)
250 fatal_error("Bad image: magic number check failed", h.magic);
252 if (h.version != image_version)
253 fatal_error("Bad image: version number check failed", h.version);
255 load_data_heap(file, &h, p);
256 load_code_heap(file, &h, p);
262 cell data_offset = data->tenured->start - h.data_relocation_base;
263 cell code_offset = code->allocator->start - h.code_relocation_base;
265 fixup_data(data_offset, code_offset);
266 fixup_code(data_offset, code_offset);
268 /* Store image path name */
269 special_objects[OBJ_IMAGE] = allot_alien(false_object, (cell)p->image_path);
272 /* Save the current image to disk */
273 bool factor_vm::save_image(const vm_char* saving_filename,
274 const vm_char* filename) {
278 file = OPEN_WRITE(saving_filename);
280 std::cout << "Cannot open image file for writing: " << saving_filename << std::endl;
281 char *msg = threadsafe_strerror(errno);
282 std::cout << "strerror: " << msg << std::endl;
287 h.magic = image_magic;
288 h.version = image_version;
289 h.data_relocation_base = data->tenured->start;
290 h.data_size = data->tenured->occupied_space();
291 h.code_relocation_base = code->allocator->start;
292 h.code_size = code->allocator->occupied_space();
294 h.true_object = true_object;
295 h.bignum_zero = bignum_zero;
296 h.bignum_pos_one = bignum_pos_one;
297 h.bignum_neg_one = bignum_neg_one;
299 for (cell i = 0; i < special_object_count; i++)
300 h.special_objects[i] =
301 (save_special_p(i) ? special_objects[i] : false_object);
305 if (safe_fwrite(&h, sizeof(image_header), 1, file) != 1)
307 if (safe_fwrite((void*)data->tenured->start, h.data_size, 1, file) != 1)
309 if (safe_fwrite(code->allocator->first_block(), h.code_size, 1, file) != 1)
314 std::cout << "save-image failed." << std::endl;
315 char *msg = threadsafe_strerror(errno);
316 std::cout << "strerror: " << msg << std::endl;
320 move_file(saving_filename, filename);
325 void factor_vm::primitive_save_image() {
326 /* do a full GC to push everything into tenured space */
327 primitive_compact_gc();
329 data_root<byte_array> path2(ctx->pop(), this);
330 path2.untag_check(this);
331 data_root<byte_array> path1(ctx->pop(), this);
332 path1.untag_check(this);
333 save_image((vm_char*)(path1.untagged() + 1),
334 (vm_char*)(path2.untagged() + 1));
337 /* Allocates memory */
338 void factor_vm::primitive_save_image_and_exit() {
339 /* We unbox this before doing anything else. This is the only point
340 where we might throw an error, so we have to throw an error here since
341 later steps destroy the current image. */
342 data_root<byte_array> path2(ctx->pop(), this);
343 path2.untag_check(this);
344 data_root<byte_array> path1(ctx->pop(), this);
345 path1.untag_check(this);
347 /* strip out special_objects data which is set on startup anyway */
348 for (cell i = 0; i < special_object_count; i++)
349 if (!save_special_p(i))
350 special_objects[i] = false_object;
352 gc(collect_compact_op, 0, /* requested size */
353 false /* discard objects only reachable from stacks */);
356 if (save_image((vm_char*)(path1.untagged() + 1),
357 (vm_char*)(path2.untagged() + 1)))
363 bool factor_vm::embedded_image_p() {
364 const vm_char* vm_path = vm_executable_path();
367 FILE* file = OPEN_READ(vm_path);
370 embedded_image_footer footer;
371 bool embedded_p = read_embedded_image_footer(file, &footer);