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 data_fixupper {
61 explicit data_fixupper(cell offset_) : offset(offset_) {}
63 object *operator()(object *obj)
65 return (object *)((char *)obj + offset);
69 struct code_fixupper {
72 explicit code_fixupper(cell offset_) : offset(offset_) {}
74 code_block *operator()(code_block *compiled)
76 return (code_block *)((char *)compiled + offset);
80 static inline cell tuple_size_with_fixup(cell offset, object *obj)
82 tuple_layout *layout = (tuple_layout *)((char *)UNTAG(((tuple *)obj)->layout) + offset);
83 return tuple_size(layout);
89 explicit fixup_sizer(cell offset_) : offset(offset_) {}
91 cell operator()(object *obj)
93 if(obj->type() == TUPLE_TYPE)
94 return align(tuple_size_with_fixup(offset,obj),data_alignment);
100 struct object_fixupper {
103 slot_visitor<data_fixupper> data_visitor;
104 code_block_visitor<code_fixupper> code_visitor;
106 object_fixupper(factor_vm *parent_, cell data_offset_, cell code_offset_) :
108 data_offset(data_offset_),
109 data_visitor(slot_visitor<data_fixupper>(parent_,data_fixupper(data_offset_))),
110 code_visitor(code_block_visitor<code_fixupper>(parent_,code_fixupper(code_offset_))) {}
112 void operator()(object *obj, cell size)
114 parent->data->tenured->starts.record_object_start_offset(obj);
120 cell payload_start = obj->binary_payload_start();
121 data_visitor.visit_slots(obj,payload_start);
123 alien *ptr = (alien *)obj;
125 if(to_boolean(ptr->base))
126 ptr->update_address();
128 ptr->expired = parent->true_object;
133 cell payload_start = obj->binary_payload_start();
134 data_visitor.visit_slots(obj,payload_start);
136 parent->ffi_dlopen((dll *)obj);
141 cell payload_start = tuple_size_with_fixup(data_offset,obj);
142 data_visitor.visit_slots(obj,payload_start);
147 cell payload_start = obj->binary_payload_start();
148 data_visitor.visit_slots(obj,payload_start);
149 code_visitor.visit_object_code_block(obj);
156 void factor_vm::fixup_data(cell data_offset, cell code_offset)
158 slot_visitor<data_fixupper> data_workhorse(this,data_fixupper(data_offset));
159 data_workhorse.visit_roots();
161 object_fixupper fixupper(this,data_offset,code_offset);
162 fixup_sizer sizer(data_offset);
163 data->tenured->iterate(fixupper,sizer);
166 struct code_block_fixup_relocation_visitor {
169 slot_visitor<data_fixupper> data_visitor;
170 code_fixupper code_visitor;
172 code_block_fixup_relocation_visitor(factor_vm *parent_, cell data_offset_, cell code_offset_) :
174 code_offset(code_offset_),
175 data_visitor(slot_visitor<data_fixupper>(parent_,data_fixupper(data_offset_))),
176 code_visitor(code_fixupper(code_offset_)) {}
178 void operator()(instruction_operand op)
180 code_block *compiled = op.parent_code_block();
181 cell old_offset = op.rel_offset() + (cell)compiled->entry_point() - code_offset;
183 switch(op.rel_type())
186 op.store_value(data_visitor.visit_pointer(op.load_value(old_offset)));
189 case RT_ENTRY_POINT_PIC:
190 case RT_ENTRY_POINT_PIC_TAIL:
191 op.store_code_block(code_visitor(op.load_code_block(old_offset)));
194 op.store_value(op.load_value(old_offset) + code_offset);
199 parent->store_external_address(op);
205 struct code_block_fixupper {
210 code_block_fixupper(factor_vm *parent_, cell data_offset_, cell code_offset_) :
212 data_offset(data_offset_),
213 code_offset(code_offset_) {}
215 void operator()(code_block *compiled, cell size)
217 slot_visitor<data_fixupper> data_visitor(parent,data_fixupper(data_offset));
218 data_visitor.visit_code_block_objects(compiled);
220 code_block_fixup_relocation_visitor code_visitor(parent,data_offset,code_offset);
221 compiled->each_instruction_operand(code_visitor);
225 void factor_vm::fixup_code(cell data_offset, cell code_offset)
227 code_block_fixupper fixupper(this,data_offset,code_offset);
228 code->allocator->iterate(fixupper);
231 /* Read an image file from disk, only done once during startup */
232 /* This function also initializes the data and code heaps */
233 void factor_vm::load_image(vm_parameters *p)
235 FILE *file = OPEN_READ(p->image_path);
238 std::cout << "Cannot open image file: " << p->image_path << std::endl;
239 std::cout << strerror(errno) << std::endl;
244 if(safe_fread(&h,sizeof(image_header),1,file) != 1)
245 fatal_error("Cannot read image header",0);
247 if(h.magic != image_magic)
248 fatal_error("Bad image: magic number check failed",h.magic);
250 if(h.version != image_version)
251 fatal_error("Bad image: version number check failed",h.version);
253 load_data_heap(file,&h,p);
254 load_code_heap(file,&h,p);
260 cell data_offset = data->tenured->start - h.data_relocation_base;
261 cell code_offset = code->allocator->start - h.code_relocation_base;
263 fixup_data(data_offset,code_offset);
264 fixup_code(data_offset,code_offset);
266 /* Store image path name */
267 special_objects[OBJ_IMAGE] = allot_alien(false_object,(cell)p->image_path);
270 /* Save the current image to disk */
271 bool factor_vm::save_image(const vm_char *saving_filename, const vm_char *filename)
276 file = OPEN_WRITE(saving_filename);
279 std::cout << "Cannot open image file: " << saving_filename << std::endl;
280 std::cout << strerror(errno) << std::endl;
284 h.magic = image_magic;
285 h.version = image_version;
286 h.data_relocation_base = data->tenured->start;
287 h.data_size = data->tenured->occupied_space();
288 h.code_relocation_base = code->allocator->start;
289 h.code_size = code->allocator->occupied_space();
291 h.true_object = true_object;
292 h.bignum_zero = bignum_zero;
293 h.bignum_pos_one = bignum_pos_one;
294 h.bignum_neg_one = bignum_neg_one;
296 for(cell i = 0; i < special_object_count; i++)
297 h.special_objects[i] = (save_special_p(i) ? special_objects[i] : false_object);
301 if(safe_fwrite(&h,sizeof(image_header),1,file) != 1) ok = false;
302 if(safe_fwrite((void*)data->tenured->start,h.data_size,1,file) != 1) ok = false;
303 if(safe_fwrite(code->allocator->first_block(),h.code_size,1,file) != 1) ok = false;
307 std::cout << "save-image failed: " << strerror(errno) << std::endl;
309 move_file(saving_filename,filename);
314 void factor_vm::primitive_save_image()
316 /* do a full GC to push everything into tenured space */
317 primitive_compact_gc();
319 data_root<byte_array> path2(ctx->pop(),this);
320 path2.untag_check(this);
321 data_root<byte_array> path1(ctx->pop(),this);
322 path1.untag_check(this);
323 save_image((vm_char *)(path1.untagged() + 1 ),(vm_char *)(path2.untagged() + 1));
326 void factor_vm::primitive_save_image_and_exit()
328 /* We unbox this before doing anything else. This is the only point
329 where we might throw an error, so we have to throw an error here since
330 later steps destroy the current image. */
331 data_root<byte_array> path2(ctx->pop(),this);
332 path2.untag_check(this);
333 data_root<byte_array> path1(ctx->pop(),this);
334 path1.untag_check(this);
336 /* strip out special_objects data which is set on startup anyway */
337 for(cell i = 0; i < special_object_count; i++)
338 if(!save_special_p(i)) special_objects[i] = false_object;
340 gc(collect_compact_op,
341 0, /* requested size */
342 false /* discard objects only reachable from stacks */);
345 if(save_image((vm_char *)(path1.untagged() + 1), (vm_char *)(path2.untagged() + 1)))