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 FILE* factor_vm::open_image(vm_parameters* p) {
204 if (p->embedded_image) {
205 FILE* file = OPEN_READ(p->executable_path);
207 std::cout << "Cannot open embedded image" << std::endl;
208 std::cout << strerror(errno) << std::endl;
211 embedded_image_footer footer;
212 if (!read_embedded_image_footer(file, &footer)) {
213 std::cout << "No embedded image" << std::endl;
216 safe_fseek(file, (off_t)footer.image_offset, SEEK_SET);
219 return OPEN_READ(p->image_path);
222 /* Read an image file from disk, only done once during startup */
223 /* This function also initializes the data and code heaps */
224 void factor_vm::load_image(vm_parameters* p) {
225 FILE* file = open_image(p);
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,
261 const vm_char* filename) {
265 file = OPEN_WRITE(saving_filename);
267 std::cout << "Cannot open image file: " << saving_filename << std::endl;
268 std::cout << strerror(errno) << std::endl;
272 h.magic = image_magic;
273 h.version = image_version;
274 h.data_relocation_base = data->tenured->start;
275 h.data_size = data->tenured->occupied_space();
276 h.code_relocation_base = code->allocator->start;
277 h.code_size = code->allocator->occupied_space();
279 h.true_object = true_object;
280 h.bignum_zero = bignum_zero;
281 h.bignum_pos_one = bignum_pos_one;
282 h.bignum_neg_one = bignum_neg_one;
284 for (cell i = 0; i < special_object_count; i++)
285 h.special_objects[i] =
286 (save_special_p(i) ? special_objects[i] : false_object);
290 if (safe_fwrite(&h, sizeof(image_header), 1, file) != 1)
292 if (safe_fwrite((void*)data->tenured->start, h.data_size, 1, file) != 1)
294 if (safe_fwrite(code->allocator->first_block(), h.code_size, 1, file) != 1)
299 std::cout << "save-image failed: " << strerror(errno) << std::endl;
301 move_file(saving_filename, filename);
306 void factor_vm::primitive_save_image() {
307 /* do a full GC to push everything into tenured space */
308 primitive_compact_gc();
310 data_root<byte_array> path2(ctx->pop(), this);
311 path2.untag_check(this);
312 data_root<byte_array> path1(ctx->pop(), this);
313 path1.untag_check(this);
314 save_image((vm_char*)(path1.untagged() + 1),
315 (vm_char*)(path2.untagged() + 1));
318 void factor_vm::primitive_save_image_and_exit() {
319 /* We unbox this before doing anything else. This is the only point
320 where we might throw an error, so we have to throw an error here since
321 later steps destroy the current image. */
322 data_root<byte_array> path2(ctx->pop(), this);
323 path2.untag_check(this);
324 data_root<byte_array> path1(ctx->pop(), this);
325 path1.untag_check(this);
327 /* strip out special_objects data which is set on startup anyway */
328 for (cell i = 0; i < special_object_count; i++)
329 if (!save_special_p(i))
330 special_objects[i] = false_object;
332 gc(collect_compact_op, 0, /* requested size */
333 false /* discard objects only reachable from stacks */);
336 if (save_image((vm_char*)(path1.untagged() + 1),
337 (vm_char*)(path2.untagged() + 1)))
343 bool factor_vm::embedded_image_p() {
344 const vm_char* vm_path = vm_executable_path();
347 FILE* file = OPEN_READ(vm_path);
350 embedded_image_footer footer;
351 bool embedded_p = read_embedded_image_footer(file, &footer);