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 raw_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 raw_fread((void*)code->allocator->start, 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> visitor;
85 start_object_updater(factor_vm* parent, startup_fixup fixup)
88 visitor(slot_visitor<startup_fixup>(parent, fixup)) { }
90 void operator()(object* obj, cell size) {
91 parent->data->tenured->starts.record_object_start_offset(obj);
93 visitor.visit_slots(obj);
95 switch (obj->type()) {
98 alien* ptr = (alien*)obj;
100 if (to_boolean(ptr->base))
101 ptr->update_address();
103 ptr->expired = parent->true_object;
107 parent->ffi_dlopen((dll*)obj);
111 visitor.visit_object_code_block(obj);
118 void factor_vm::fixup_data(cell data_offset, cell code_offset) {
119 startup_fixup fixup(data_offset, code_offset);
120 slot_visitor<startup_fixup> visitor(this, fixup);
121 visitor.visit_all_roots();
123 start_object_updater updater(this, fixup);
124 data->tenured->iterate(updater, fixup);
127 struct startup_code_block_relocation_visitor {
130 slot_visitor<startup_fixup> visitor;
132 startup_code_block_relocation_visitor(factor_vm* parent,
136 visitor(slot_visitor<startup_fixup>(parent, fixup)) {}
138 void operator()(instruction_operand op) {
139 code_block* compiled = op.compiled;
141 op.rel_offset() + compiled->entry_point() - fixup.code_offset;
143 switch (op.rel_type()) {
145 cell value = op.load_value(old_offset);
146 if (immediate_p(value))
147 op.store_value(value);
150 RETAG(fixup.fixup_data(untag<object>(value)), TAG(value)));
154 case RT_ENTRY_POINT_PIC:
155 case RT_ENTRY_POINT_PIC_TAIL:
157 cell value = op.load_value(old_offset);
158 cell offset = TAG(value);
159 code_block* compiled = (code_block*)UNTAG(value);
160 op.store_value((cell)fixup.fixup_code(compiled) + offset);
166 parent->store_external_address(op);
172 struct startup_code_block_updater {
176 startup_code_block_updater(factor_vm* parent, startup_fixup fixup)
177 : parent(parent), fixup(fixup) {}
179 void operator()(code_block* compiled, cell size) {
180 slot_visitor<startup_fixup> visitor(parent, fixup);
181 visitor.visit_code_block_objects(compiled);
183 startup_code_block_relocation_visitor code_visitor(parent, fixup);
184 compiled->each_instruction_operand(code_visitor);
188 void factor_vm::fixup_code(cell data_offset, cell code_offset) {
189 startup_fixup fixup(data_offset, code_offset);
190 startup_code_block_updater updater(this, fixup);
191 code->allocator->iterate(updater, fixup);
194 bool factor_vm::read_embedded_image_footer(FILE* file,
195 embedded_image_footer* footer) {
196 safe_fseek(file, -(off_t)sizeof(embedded_image_footer), SEEK_END);
197 safe_fread(footer, (off_t)sizeof(embedded_image_footer), 1, file);
198 return footer->magic == image_magic;
201 char *threadsafe_strerror(int errnum) {
202 char *buf = (char *) malloc(STRERROR_BUFFER_SIZE);
204 fatal_error("Out of memory in threadsafe_strerror, errno", errnum);
206 THREADSAFE_STRERROR(errnum, buf, STRERROR_BUFFER_SIZE);
210 FILE* factor_vm::open_image(vm_parameters* p) {
211 if (p->embedded_image) {
212 FILE* file = OPEN_READ(p->executable_path);
214 std::cout << "Cannot open embedded image" << std::endl;
215 char *msg = threadsafe_strerror(errno);
216 std::cout << "strerror:1: " << msg << std::endl;
220 embedded_image_footer footer;
221 if (!read_embedded_image_footer(file, &footer)) {
222 std::cout << "No embedded image" << std::endl;
225 safe_fseek(file, (off_t)footer.image_offset, SEEK_SET);
228 return OPEN_READ(p->image_path);
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) {
234 FILE* file = open_image(p);
236 std::cout << "Cannot open image file: " << p->image_path << std::endl;
237 char *msg = threadsafe_strerror(errno);
238 std::cout << "strerror:2: " << msg << std::endl;
243 if (raw_fread(&h, sizeof(image_header), 1, file) != 1)
244 fatal_error("Cannot read image header", 0);
246 if (h.magic != image_magic)
247 fatal_error("Bad image: magic number check failed", h.magic);
249 if (h.version != image_version)
250 fatal_error("Bad image: version number check failed", h.version);
252 load_data_heap(file, &h, p);
253 load_code_heap(file, &h, p);
259 cell data_offset = data->tenured->start - h.data_relocation_base;
260 cell code_offset = code->allocator->start - h.code_relocation_base;
262 fixup_data(data_offset, code_offset);
263 fixup_code(data_offset, code_offset);
265 /* Store image path name */
266 special_objects[OBJ_IMAGE] = allot_alien(false_object, (cell)p->image_path);
269 /* Save the current image to disk */
270 bool factor_vm::save_image(const vm_char* saving_filename,
271 const vm_char* filename) {
275 file = OPEN_WRITE(saving_filename);
277 std::cout << "Cannot open image file for writing: " << saving_filename << std::endl;
278 char *msg = threadsafe_strerror(errno);
279 std::cout << "strerror:3: " << msg << 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] =
298 (save_special_p(i) ? special_objects[i] : false_object);
302 if (safe_fwrite(&h, sizeof(image_header), 1, file) != 1)
304 if (safe_fwrite((void*)data->tenured->start, h.data_size, 1, file) != 1)
306 if (safe_fwrite((void*)code->allocator->start, h.code_size, 1, file) != 1)
311 std::cout << "save-image failed." << std::endl;
312 char *msg = threadsafe_strerror(errno);
313 std::cout << "strerror:4: " << msg << std::endl;
317 move_file(saving_filename, filename);
322 void factor_vm::primitive_save_image() {
323 /* do a full GC to push everything into tenured space */
324 primitive_compact_gc();
326 data_root<byte_array> path2(ctx->pop(), this);
327 path2.untag_check(this);
328 data_root<byte_array> path1(ctx->pop(), this);
329 path1.untag_check(this);
330 save_image((vm_char*)(path1.untagged() + 1),
331 (vm_char*)(path2.untagged() + 1));
334 /* Allocates memory */
335 void factor_vm::primitive_save_image_and_exit() {
336 /* We unbox this before doing anything else. This is the only point
337 where we might throw an error, so we have to throw an error here since
338 later steps destroy the current image. */
339 data_root<byte_array> path2(ctx->pop(), this);
340 path2.untag_check(this);
341 data_root<byte_array> path1(ctx->pop(), this);
342 path1.untag_check(this);
344 /* strip out special_objects data which is set on startup anyway */
345 for (cell i = 0; i < special_object_count; i++)
346 if (!save_special_p(i))
347 special_objects[i] = false_object;
349 /* dont trace objects only reachable from context stacks so we don't
350 get volatile data saved in the image. */
351 active_contexts.clear();
352 code->uninitialized_blocks.clear();
354 gc(collect_compact_op, 0 /* requested size */);
357 if (save_image((vm_char*)(path1.untagged() + 1),
358 (vm_char*)(path2.untagged() + 1)))
364 bool factor_vm::embedded_image_p() {
365 const vm_char* vm_path = vm_executable_path();
368 FILE* file = OPEN_READ(vm_path);
371 embedded_image_footer footer;
372 bool embedded_p = read_embedded_image_footer(file, &footer);