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((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> data_workhorse(this, fixup);
121 data_workhorse.visit_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> data_visitor;
132 startup_code_block_relocation_visitor(factor_vm* parent,
136 data_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> data_visitor(parent, fixup);
181 data_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: " << 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: " << msg << 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,
272 const vm_char* filename) {
276 file = OPEN_WRITE(saving_filename);
278 std::cout << "Cannot open image file for writing: " << saving_filename << std::endl;
279 char *msg = threadsafe_strerror(errno);
280 std::cout << "strerror: " << msg << std::endl;
285 h.magic = image_magic;
286 h.version = image_version;
287 h.data_relocation_base = data->tenured->start;
288 h.data_size = data->tenured->occupied_space();
289 h.code_relocation_base = code->allocator->start;
290 h.code_size = code->allocator->occupied_space();
292 h.true_object = true_object;
293 h.bignum_zero = bignum_zero;
294 h.bignum_pos_one = bignum_pos_one;
295 h.bignum_neg_one = bignum_neg_one;
297 for (cell i = 0; i < special_object_count; i++)
298 h.special_objects[i] =
299 (save_special_p(i) ? special_objects[i] : false_object);
303 if (safe_fwrite(&h, sizeof(image_header), 1, file) != 1)
305 if (safe_fwrite((void*)data->tenured->start, h.data_size, 1, file) != 1)
307 if (safe_fwrite((void*)code->allocator->start, h.code_size, 1, file) != 1)
312 std::cout << "save-image failed." << std::endl;
313 char *msg = threadsafe_strerror(errno);
314 std::cout << "strerror: " << msg << std::endl;
318 move_file(saving_filename, filename);
323 void factor_vm::primitive_save_image() {
324 /* do a full GC to push everything into tenured space */
325 primitive_compact_gc();
327 data_root<byte_array> path2(ctx->pop(), this);
328 path2.untag_check(this);
329 data_root<byte_array> path1(ctx->pop(), this);
330 path1.untag_check(this);
331 save_image((vm_char*)(path1.untagged() + 1),
332 (vm_char*)(path2.untagged() + 1));
335 /* Allocates memory */
336 void factor_vm::primitive_save_image_and_exit() {
337 /* We unbox this before doing anything else. This is the only point
338 where we might throw an error, so we have to throw an error here since
339 later steps destroy the current image. */
340 data_root<byte_array> path2(ctx->pop(), this);
341 path2.untag_check(this);
342 data_root<byte_array> path1(ctx->pop(), this);
343 path1.untag_check(this);
345 /* strip out special_objects data which is set on startup anyway */
346 for (cell i = 0; i < special_object_count; i++)
347 if (!save_special_p(i))
348 special_objects[i] = false_object;
350 gc(collect_compact_op, 0, /* requested size */
351 false /* discard objects only reachable from stacks */);
354 if (save_image((vm_char*)(path1.untagged() + 1),
355 (vm_char*)(path2.untagged() + 1)))
361 bool factor_vm::embedded_image_p() {
362 const vm_char* vm_path = vm_executable_path();
365 FILE* file = OPEN_READ(vm_path);
368 embedded_image_footer footer;
369 bool embedded_p = read_embedded_image_footer(file, &footer);