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 = TAG(value);
184 code_block *compiled = (code_block *)UNTAG(value);
185 op.store_value((cell)fixup.fixup_code(compiled) + offset);
191 parent->store_external_address(op);
197 struct startup_code_block_updater {
201 startup_code_block_updater(factor_vm *parent_, startup_fixup fixup_) :
202 parent(parent_), fixup(fixup_) {}
204 void operator()(code_block *compiled, cell size)
206 slot_visitor<startup_fixup> data_visitor(parent,fixup);
207 data_visitor.visit_code_block_objects(compiled);
209 startup_code_block_relocation_visitor code_visitor(parent,fixup);
210 compiled->each_instruction_operand(code_visitor);
214 void factor_vm::fixup_code(cell data_offset, cell code_offset)
216 startup_fixup fixup(data_offset,code_offset);
217 startup_code_block_updater updater(this,fixup);
218 code->allocator->iterate(updater,fixup);
221 /* Read an image file from disk, only done once during startup */
222 /* This function also initializes the data and code heaps */
223 void factor_vm::load_image(vm_parameters *p)
225 FILE *file = OPEN_READ(p->image_path);
228 std::cout << "Cannot open image file: " << p->image_path << std::endl;
229 std::cout << strerror(errno) << std::endl;
234 if(safe_fread(&h,sizeof(image_header),1,file) != 1)
235 fatal_error("Cannot read image header",0);
237 if(h.magic != image_magic)
238 fatal_error("Bad image: magic number check failed",h.magic);
240 if(h.version != image_version)
241 fatal_error("Bad image: version number check failed",h.version);
243 load_data_heap(file,&h,p);
244 load_code_heap(file,&h,p);
250 cell data_offset = data->tenured->start - h.data_relocation_base;
251 cell code_offset = code->allocator->start - h.code_relocation_base;
253 fixup_data(data_offset,code_offset);
254 fixup_code(data_offset,code_offset);
256 /* Store image path name */
257 special_objects[OBJ_IMAGE] = allot_alien(false_object,(cell)p->image_path);
260 /* Save the current image to disk */
261 bool factor_vm::save_image(const vm_char *saving_filename, const vm_char *filename)
266 file = OPEN_WRITE(saving_filename);
269 std::cout << "Cannot open image file: " << saving_filename << std::endl;
270 std::cout << strerror(errno) << std::endl;
274 h.magic = image_magic;
275 h.version = image_version;
276 h.data_relocation_base = data->tenured->start;
277 h.data_size = data->tenured->occupied_space();
278 h.code_relocation_base = code->allocator->start;
279 h.code_size = code->allocator->occupied_space();
281 h.true_object = true_object;
282 h.bignum_zero = bignum_zero;
283 h.bignum_pos_one = bignum_pos_one;
284 h.bignum_neg_one = bignum_neg_one;
286 for(cell i = 0; i < special_object_count; i++)
287 h.special_objects[i] = (save_special_p(i) ? special_objects[i] : false_object);
291 if(safe_fwrite(&h,sizeof(image_header),1,file) != 1) ok = false;
292 if(safe_fwrite((void*)data->tenured->start,h.data_size,1,file) != 1) ok = false;
293 if(safe_fwrite(code->allocator->first_block(),h.code_size,1,file) != 1) ok = false;
297 std::cout << "save-image failed: " << strerror(errno) << std::endl;
299 move_file(saving_filename,filename);
304 void factor_vm::primitive_save_image()
306 /* do a full GC to push everything into tenured space */
307 primitive_compact_gc();
309 data_root<byte_array> path2(ctx->pop(),this);
310 path2.untag_check(this);
311 data_root<byte_array> path1(ctx->pop(),this);
312 path1.untag_check(this);
313 save_image((vm_char *)(path1.untagged() + 1 ),(vm_char *)(path2.untagged() + 1));
316 void factor_vm::primitive_save_image_and_exit()
318 /* We unbox this before doing anything else. This is the only point
319 where we might throw an error, so we have to throw an error here since
320 later steps destroy the current image. */
321 data_root<byte_array> path2(ctx->pop(),this);
322 path2.untag_check(this);
323 data_root<byte_array> path1(ctx->pop(),this);
324 path1.untag_check(this);
326 /* strip out special_objects data which is set on startup anyway */
327 for(cell i = 0; i < special_object_count; i++)
328 if(!save_special_p(i)) special_objects[i] = false_object;
330 gc(collect_compact_op,
331 0, /* requested size */
332 false /* discard objects only reachable from stacks */);
335 if(save_image((vm_char *)(path1.untagged() + 1), (vm_char *)(path2.untagged() + 1)))