6 /* Certain special objects in the image are known to the runtime */
7 void factor_vm::init_objects(image_header *h)
9 memcpy(special_objects,h->special_objects,sizeof(special_objects));
11 true_object = h->true_object;
12 bignum_zero = h->bignum_zero;
13 bignum_pos_one = h->bignum_pos_one;
14 bignum_neg_one = h->bignum_neg_one;
17 void factor_vm::load_data_heap(FILE *file, image_header *h, vm_parameters *p)
19 p->tenured_size = std::max((h->data_size * 3) / 2,p->tenured_size);
21 init_data_heap(p->young_size,
25 fixnum bytes_read = safe_fread((void*)data->tenured->start,1,h->data_size,file);
27 if((cell)bytes_read != h->data_size)
29 std::cout << "truncated image: " << bytes_read << " bytes read, ";
30 std::cout << h->data_size << " bytes expected\n";
31 fatal_error("load_data_heap failed",0);
34 data->tenured->initial_free_list(h->data_size);
37 void factor_vm::load_code_heap(FILE *file, image_header *h, vm_parameters *p)
39 if(h->code_size > p->code_size)
40 fatal_error("Code heap too small to fit image",h->code_size);
42 init_code_heap(p->code_size);
46 size_t bytes_read = safe_fread(code->allocator->first_block(),1,h->code_size,file);
47 if(bytes_read != h->code_size)
49 std::cout << "truncated image: " << bytes_read << " bytes read, ";
50 std::cout << h->code_size << " bytes expected\n";
51 fatal_error("load_code_heap failed",0);
55 code->allocator->initial_free_list(h->code_size);
56 code->initialize_all_blocks_set();
59 struct startup_fixup {
63 explicit startup_fixup(cell data_offset_, cell code_offset_) :
64 data_offset(data_offset_), code_offset(code_offset_) {}
66 object *fixup_data(object *obj)
68 return (object *)((cell)obj + data_offset);
71 code_block *fixup_code(code_block *obj)
73 return (code_block *)((cell)obj + code_offset);
76 object *translate_data(const object *obj)
78 return fixup_data((object *)obj);
81 code_block *translate_code(const code_block *compiled)
83 return fixup_code((code_block *)compiled);
86 cell size(const object *obj)
88 return obj->size(*this);
91 cell size(code_block *compiled)
93 return compiled->size(*this);
97 struct start_object_updater {
100 slot_visitor<startup_fixup> data_visitor;
101 code_block_visitor<startup_fixup> code_visitor;
103 start_object_updater(factor_vm *parent_, startup_fixup fixup_) :
106 data_visitor(slot_visitor<startup_fixup>(parent_,fixup_)),
107 code_visitor(code_block_visitor<startup_fixup>(parent_,fixup_)) {}
109 void operator()(object *obj, cell size)
111 parent->data->tenured->starts.record_object_start_offset(obj);
113 data_visitor.visit_slots(obj);
120 alien *ptr = (alien *)obj;
122 if(to_boolean(ptr->base))
123 ptr->update_address();
125 ptr->expired = parent->true_object;
130 parent->ffi_dlopen((dll *)obj);
135 code_visitor.visit_object_code_block(obj);
142 void factor_vm::fixup_data(cell data_offset, cell code_offset)
144 startup_fixup fixup(data_offset,code_offset);
145 slot_visitor<startup_fixup> data_workhorse(this,fixup);
146 data_workhorse.visit_roots();
148 start_object_updater updater(this,fixup);
149 data->tenured->iterate(updater,fixup);
152 struct startup_code_block_relocation_visitor {
155 slot_visitor<startup_fixup> data_visitor;
157 startup_code_block_relocation_visitor(factor_vm *parent_, startup_fixup fixup_) :
160 data_visitor(slot_visitor<startup_fixup>(parent_,fixup_)) {}
162 void operator()(instruction_operand op)
164 code_block *compiled = op.compiled;
165 cell old_offset = op.rel_offset() + (cell)compiled->entry_point() - fixup.code_offset;
167 switch(op.rel_type())
171 cell value = op.load_value(old_offset);
172 if(immediate_p(value))
173 op.store_value(value);
175 op.store_value(RETAG(fixup.fixup_data(untag<object>(value)),TAG(value)));
179 case RT_ENTRY_POINT_PIC:
180 case RT_ENTRY_POINT_PIC_TAIL:
183 cell value = op.load_value(old_offset);
184 cell offset = TAG(value);
185 code_block *compiled = (code_block *)UNTAG(value);
186 op.store_value((cell)fixup.fixup_code(compiled) + offset);
192 parent->store_external_address(op);
198 struct startup_code_block_updater {
202 startup_code_block_updater(factor_vm *parent_, startup_fixup fixup_) :
203 parent(parent_), fixup(fixup_) {}
205 void operator()(code_block *compiled, cell size)
207 slot_visitor<startup_fixup> data_visitor(parent,fixup);
208 data_visitor.visit_code_block_objects(compiled);
210 startup_code_block_relocation_visitor code_visitor(parent,fixup);
211 compiled->each_instruction_operand(code_visitor);
215 void factor_vm::fixup_code(cell data_offset, cell code_offset)
217 startup_fixup fixup(data_offset,code_offset);
218 startup_code_block_updater updater(this,fixup);
219 code->allocator->iterate(updater,fixup);
222 FILE* factor_vm::open_image(vm_parameters *p)
224 if (p->embedded_image)
226 FILE *file = OPEN_READ(p->executable_path);
229 std::cout << "Cannot open embedded image" << std::endl;
230 std::cout << strerror(errno) << std::endl;
233 safe_fseek(file, -sizeof(embedded_image_footer), SEEK_END);
234 embedded_image_footer footer;
235 safe_fread(&footer, sizeof(embedded_image_footer), 1, file);
236 if (footer.magic != image_magic)
238 std::cout << "No embedded image" << std::endl;
241 safe_fseek(file, footer.image_offset, SEEK_SET);
245 return OPEN_READ(p->image_path);
248 /* Read an image file from disk, only done once during startup */
249 /* This function also initializes the data and code heaps */
250 void factor_vm::load_image(vm_parameters *p)
252 FILE *file = open_image(p);
255 std::cout << "Cannot open image file: " << p->image_path << std::endl;
256 std::cout << strerror(errno) << std::endl;
261 if(safe_fread(&h,sizeof(image_header),1,file) != 1)
262 fatal_error("Cannot read image header",0);
264 if(h.magic != image_magic)
265 fatal_error("Bad image: magic number check failed",h.magic);
267 if(h.version != image_version)
268 fatal_error("Bad image: version number check failed",h.version);
270 load_data_heap(file,&h,p);
271 load_code_heap(file,&h,p);
277 cell data_offset = data->tenured->start - h.data_relocation_base;
278 cell code_offset = code->allocator->start - h.code_relocation_base;
280 fixup_data(data_offset,code_offset);
281 fixup_code(data_offset,code_offset);
283 /* Store image path name */
284 special_objects[OBJ_IMAGE] = allot_alien(false_object,(cell)p->image_path);
287 /* Save the current image to disk */
288 bool factor_vm::save_image(const vm_char *saving_filename, const vm_char *filename)
293 file = OPEN_WRITE(saving_filename);
296 std::cout << "Cannot open image file: " << saving_filename << std::endl;
297 std::cout << strerror(errno) << std::endl;
301 h.magic = image_magic;
302 h.version = image_version;
303 h.data_relocation_base = data->tenured->start;
304 h.data_size = data->tenured->occupied_space();
305 h.code_relocation_base = code->allocator->start;
306 h.code_size = code->allocator->occupied_space();
308 h.true_object = true_object;
309 h.bignum_zero = bignum_zero;
310 h.bignum_pos_one = bignum_pos_one;
311 h.bignum_neg_one = bignum_neg_one;
313 for(cell i = 0; i < special_object_count; i++)
314 h.special_objects[i] = (save_special_p(i) ? special_objects[i] : false_object);
318 if(safe_fwrite(&h,sizeof(image_header),1,file) != 1) ok = false;
319 if(safe_fwrite((void*)data->tenured->start,h.data_size,1,file) != 1) ok = false;
320 if(safe_fwrite(code->allocator->first_block(),h.code_size,1,file) != 1) ok = false;
324 std::cout << "save-image failed: " << strerror(errno) << std::endl;
326 move_file(saving_filename,filename);
331 void factor_vm::primitive_save_image()
333 /* do a full GC to push everything into tenured space */
334 primitive_compact_gc();
336 data_root<byte_array> path2(ctx->pop(),this);
337 path2.untag_check(this);
338 data_root<byte_array> path1(ctx->pop(),this);
339 path1.untag_check(this);
340 save_image((vm_char *)(path1.untagged() + 1 ),(vm_char *)(path2.untagged() + 1));
343 void factor_vm::primitive_save_image_and_exit()
345 /* We unbox this before doing anything else. This is the only point
346 where we might throw an error, so we have to throw an error here since
347 later steps destroy the current image. */
348 data_root<byte_array> path2(ctx->pop(),this);
349 path2.untag_check(this);
350 data_root<byte_array> path1(ctx->pop(),this);
351 path1.untag_check(this);
353 /* strip out special_objects data which is set on startup anyway */
354 for(cell i = 0; i < special_object_count; i++)
355 if(!save_special_p(i)) special_objects[i] = false_object;
357 gc(collect_compact_op,
358 0, /* requested size */
359 false /* discard objects only reachable from stacks */);
362 if(save_image((vm_char *)(path1.untagged() + 1), (vm_char *)(path2.untagged() + 1)))
368 bool factor_vm::embedded_image_p()
370 const vm_char *vm_path = vm_executable_path();
373 FILE *file = OPEN_READ(vm_path);
376 safe_fseek(file, -sizeof(embedded_image_footer), SEEK_END);
377 embedded_image_footer footer;
378 safe_fread(&footer, sizeof(embedded_image_footer), 1, file);
380 return footer.magic == image_magic;