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);
58 struct startup_fixup {
62 explicit startup_fixup(cell data_offset_, cell code_offset_) :
63 data_offset(data_offset_), code_offset(code_offset_) {}
65 object *fixup_data(object *obj)
67 return (object *)((cell)obj + data_offset);
70 code_block *fixup_code(code_block *obj)
72 return (code_block *)((cell)obj + code_offset);
75 object *translate_data(const object *obj)
77 return fixup_data((object *)obj);
80 code_block *translate_code(const code_block *compiled)
82 return fixup_code((code_block *)compiled);
85 cell size(const object *obj)
87 return obj->size(*this);
90 cell size(code_block *compiled)
92 return compiled->size(*this);
96 struct start_object_updater {
99 slot_visitor<startup_fixup> data_visitor;
100 code_block_visitor<startup_fixup> code_visitor;
102 start_object_updater(factor_vm *parent_, startup_fixup fixup_) :
105 data_visitor(slot_visitor<startup_fixup>(parent_,fixup_)),
106 code_visitor(code_block_visitor<startup_fixup>(parent_,fixup_)) {}
108 void operator()(object *obj, cell size)
110 parent->data->tenured->starts.record_object_start_offset(obj);
112 data_visitor.visit_slots(obj);
119 alien *ptr = (alien *)obj;
121 if(to_boolean(ptr->base))
122 ptr->update_address();
124 ptr->expired = parent->true_object;
129 parent->ffi_dlopen((dll *)obj);
134 code_visitor.visit_object_code_block(obj);
141 void factor_vm::fixup_data(cell data_offset, cell code_offset)
143 startup_fixup fixup(data_offset,code_offset);
144 slot_visitor<startup_fixup> data_workhorse(this,fixup);
145 data_workhorse.visit_roots();
147 start_object_updater updater(this,fixup);
148 data->tenured->iterate(updater,fixup);
151 struct startup_code_block_relocation_visitor {
154 slot_visitor<startup_fixup> data_visitor;
156 startup_code_block_relocation_visitor(factor_vm *parent_, startup_fixup fixup_) :
159 data_visitor(slot_visitor<startup_fixup>(parent_,fixup_)) {}
161 void operator()(instruction_operand op)
163 code_block *compiled = op.parent_code_block();
164 cell old_offset = op.rel_offset() + (cell)compiled->entry_point() - fixup.code_offset;
166 switch(op.rel_type())
170 cell value = op.load_value(old_offset);
171 if(immediate_p(value))
172 op.store_value(value);
174 op.store_value(RETAG(fixup.fixup_data(untag<object>(value)),TAG(value)));
178 case RT_ENTRY_POINT_PIC:
179 case RT_ENTRY_POINT_PIC_TAIL:
182 cell value = op.load_value(old_offset);
183 cell offset = value & (data_alignment - 1);
184 op.store_value((cell)fixup.fixup_code((code_block *)value) + offset);
190 parent->store_external_address(op);
196 struct startup_code_block_updater {
200 startup_code_block_updater(factor_vm *parent_, startup_fixup fixup_) :
201 parent(parent_), fixup(fixup_) {}
203 void operator()(code_block *compiled, cell size)
205 slot_visitor<startup_fixup> data_visitor(parent,fixup);
206 data_visitor.visit_code_block_objects(compiled);
208 startup_code_block_relocation_visitor code_visitor(parent,fixup);
209 compiled->each_instruction_operand(code_visitor);
213 void factor_vm::fixup_code(cell data_offset, cell code_offset)
215 startup_fixup fixup(data_offset,code_offset);
216 startup_code_block_updater updater(this,fixup);
217 code->allocator->iterate(updater,fixup);
220 /* Read an image file from disk, only done once during startup */
221 /* This function also initializes the data and code heaps */
222 void factor_vm::load_image(vm_parameters *p)
224 FILE *file = OPEN_READ(p->image_path);
227 std::cout << "Cannot open image file: " << p->image_path << std::endl;
228 std::cout << strerror(errno) << std::endl;
233 if(safe_fread(&h,sizeof(image_header),1,file) != 1)
234 fatal_error("Cannot read image header",0);
236 if(h.magic != image_magic)
237 fatal_error("Bad image: magic number check failed",h.magic);
239 if(h.version != image_version)
240 fatal_error("Bad image: version number check failed",h.version);
242 load_data_heap(file,&h,p);
243 load_code_heap(file,&h,p);
249 cell data_offset = data->tenured->start - h.data_relocation_base;
250 cell code_offset = code->allocator->start - h.code_relocation_base;
252 fixup_data(data_offset,code_offset);
253 fixup_code(data_offset,code_offset);
255 /* Store image path name */
256 special_objects[OBJ_IMAGE] = allot_alien(false_object,(cell)p->image_path);
259 /* Save the current image to disk */
260 bool factor_vm::save_image(const vm_char *saving_filename, const vm_char *filename)
265 file = OPEN_WRITE(saving_filename);
268 std::cout << "Cannot open image file: " << saving_filename << std::endl;
269 std::cout << strerror(errno) << std::endl;
273 h.magic = image_magic;
274 h.version = image_version;
275 h.data_relocation_base = data->tenured->start;
276 h.data_size = data->tenured->occupied_space();
277 h.code_relocation_base = code->allocator->start;
278 h.code_size = code->allocator->occupied_space();
280 h.true_object = true_object;
281 h.bignum_zero = bignum_zero;
282 h.bignum_pos_one = bignum_pos_one;
283 h.bignum_neg_one = bignum_neg_one;
285 for(cell i = 0; i < special_object_count; i++)
286 h.special_objects[i] = (save_special_p(i) ? special_objects[i] : false_object);
290 if(safe_fwrite(&h,sizeof(image_header),1,file) != 1) ok = false;
291 if(safe_fwrite((void*)data->tenured->start,h.data_size,1,file) != 1) ok = false;
292 if(safe_fwrite(code->allocator->first_block(),h.code_size,1,file) != 1) ok = false;
296 std::cout << "save-image failed: " << strerror(errno) << std::endl;
298 move_file(saving_filename,filename);
303 void factor_vm::primitive_save_image()
305 /* do a full GC to push everything into tenured space */
306 primitive_compact_gc();
308 data_root<byte_array> path2(ctx->pop(),this);
309 path2.untag_check(this);
310 data_root<byte_array> path1(ctx->pop(),this);
311 path1.untag_check(this);
312 save_image((vm_char *)(path1.untagged() + 1 ),(vm_char *)(path2.untagged() + 1));
315 void factor_vm::primitive_save_image_and_exit()
317 /* We unbox this before doing anything else. This is the only point
318 where we might throw an error, so we have to throw an error here since
319 later steps destroy the current image. */
320 data_root<byte_array> path2(ctx->pop(),this);
321 path2.untag_check(this);
322 data_root<byte_array> path1(ctx->pop(),this);
323 path1.untag_check(this);
325 /* strip out special_objects data which is set on startup anyway */
326 for(cell i = 0; i < special_object_count; i++)
327 if(!save_special_p(i)) special_objects[i] = false_object;
329 gc(collect_compact_op,
330 0, /* requested size */
331 false /* discard objects only reachable from stacks */);
334 if(save_image((vm_char *)(path1.untagged() + 1), (vm_char *)(path2.untagged() + 1)))