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 void factor_vm::fixup_data(cell data_offset, cell code_offset) {
81 startup_fixup fixup(data_offset, code_offset);
82 slot_visitor<startup_fixup> visitor(this, fixup);
83 visitor.visit_all_roots();
85 auto start_object_updater = [&](object *obj, cell size) {
86 data->tenured->starts.record_object_start_offset(obj);
87 visitor.visit_slots(obj);
88 switch (obj->type()) {
91 alien* ptr = (alien*)obj;
93 if (to_boolean(ptr->base))
94 ptr->update_address();
96 ptr->expired = true_object;
100 ffi_dlopen((dll*)obj);
104 visitor.visit_object_code_block(obj);
109 data->tenured->iterate(start_object_updater, fixup);
112 struct startup_code_block_relocation_visitor {
115 slot_visitor<startup_fixup> visitor;
117 startup_code_block_relocation_visitor(factor_vm* parent,
121 visitor(slot_visitor<startup_fixup>(parent, fixup)) {}
123 void operator()(instruction_operand op) {
124 code_block* compiled = op.compiled;
126 op.rel_offset() + compiled->entry_point() - fixup.code_offset;
128 switch (op.rel_type()) {
130 cell value = op.load_value(old_offset);
131 if (immediate_p(value))
132 op.store_value(value);
135 RETAG(fixup.fixup_data(untag<object>(value)), TAG(value)));
139 case RT_ENTRY_POINT_PIC:
140 case RT_ENTRY_POINT_PIC_TAIL:
142 cell value = op.load_value(old_offset);
143 cell offset = TAG(value);
144 code_block* compiled = (code_block*)UNTAG(value);
145 op.store_value((cell)fixup.fixup_code(compiled) + offset);
151 parent->store_external_address(op);
157 void factor_vm::fixup_code(cell data_offset, cell code_offset) {
158 startup_fixup fixup(data_offset, code_offset);
159 auto updater = [&](code_block* compiled, cell size) {
160 slot_visitor<startup_fixup> visitor(this, fixup);
161 visitor.visit_code_block_objects(compiled);
163 startup_code_block_relocation_visitor code_visitor(this, fixup);
164 compiled->each_instruction_operand(code_visitor);
166 code->allocator->iterate(updater, fixup);
169 bool factor_vm::read_embedded_image_footer(FILE* file,
170 embedded_image_footer* footer) {
171 safe_fseek(file, -(off_t)sizeof(embedded_image_footer), SEEK_END);
172 safe_fread(footer, (off_t)sizeof(embedded_image_footer), 1, file);
173 return footer->magic == image_magic;
176 char *threadsafe_strerror(int errnum) {
177 char *buf = (char *) malloc(STRERROR_BUFFER_SIZE);
179 fatal_error("Out of memory in threadsafe_strerror, errno", errnum);
181 THREADSAFE_STRERROR(errnum, buf, STRERROR_BUFFER_SIZE);
185 FILE* factor_vm::open_image(vm_parameters* p) {
186 if (p->embedded_image) {
187 FILE* file = OPEN_READ(p->executable_path);
189 std::cout << "Cannot open embedded image" << std::endl;
190 char *msg = threadsafe_strerror(errno);
191 std::cout << "strerror:1: " << msg << std::endl;
195 embedded_image_footer footer;
196 if (!read_embedded_image_footer(file, &footer)) {
197 std::cout << "No embedded image" << std::endl;
200 safe_fseek(file, (off_t)footer.image_offset, SEEK_SET);
203 return OPEN_READ(p->image_path);
206 /* Read an image file from disk, only done once during startup */
207 /* This function also initializes the data and code heaps */
208 void factor_vm::load_image(vm_parameters* p) {
209 FILE* file = open_image(p);
211 std::cout << "Cannot open image file: " << p->image_path << std::endl;
212 char *msg = threadsafe_strerror(errno);
213 std::cout << "strerror:2: " << msg << std::endl;
218 if (raw_fread(&h, sizeof(image_header), 1, file) != 1)
219 fatal_error("Cannot read image header", 0);
221 if (h.magic != image_magic)
222 fatal_error("Bad image: magic number check failed", h.magic);
224 if (h.version != image_version)
225 fatal_error("Bad image: version number check failed", h.version);
227 load_data_heap(file, &h, p);
228 load_code_heap(file, &h, p);
234 cell data_offset = data->tenured->start - h.data_relocation_base;
235 cell code_offset = code->allocator->start - h.code_relocation_base;
237 fixup_data(data_offset, code_offset);
238 fixup_code(data_offset, code_offset);
240 /* Store image path name */
241 special_objects[OBJ_IMAGE] = allot_alien(false_object, (cell)p->image_path);
244 /* Save the current image to disk */
245 bool factor_vm::save_image(const vm_char* saving_filename,
246 const vm_char* filename) {
250 file = OPEN_WRITE(saving_filename);
252 std::cout << "Cannot open image file for writing: " << saving_filename << std::endl;
253 char *msg = threadsafe_strerror(errno);
254 std::cout << "strerror:3: " << msg << std::endl;
259 h.magic = image_magic;
260 h.version = image_version;
261 h.data_relocation_base = data->tenured->start;
262 h.data_size = data->tenured->occupied_space();
263 h.code_relocation_base = code->allocator->start;
264 h.code_size = code->allocator->occupied_space();
266 h.true_object = true_object;
267 h.bignum_zero = bignum_zero;
268 h.bignum_pos_one = bignum_pos_one;
269 h.bignum_neg_one = bignum_neg_one;
271 for (cell i = 0; i < special_object_count; i++)
272 h.special_objects[i] =
273 (save_special_p(i) ? special_objects[i] : false_object);
277 if (safe_fwrite(&h, sizeof(image_header), 1, file) != 1)
279 if (safe_fwrite((void*)data->tenured->start, h.data_size, 1, file) != 1)
281 if (safe_fwrite((void*)code->allocator->start, h.code_size, 1, file) != 1)
286 std::cout << "save-image failed." << std::endl;
287 char *msg = threadsafe_strerror(errno);
288 std::cout << "strerror:4: " << msg << std::endl;
292 move_file(saving_filename, filename);
297 /* Allocates memory */
298 void factor_vm::primitive_save_image() {
299 /* We unbox this before doing anything else. This is the only point
300 where we might throw an error, so we have to throw an error here since
301 later steps destroy the current image. */
302 bool then_die = to_boolean(ctx->pop());
303 byte_array* path2 = untag_check<byte_array>(ctx->pop());
304 byte_array* path1 = untag_check<byte_array>(ctx->pop());
306 /* Copy the paths to non-gc memory to avoid them hanging around in
308 vm_char* path1_saved = safe_strdup(path1->data<vm_char>());
309 vm_char* path2_saved = safe_strdup(path2->data<vm_char>());
312 /* strip out special_objects data which is set on startup anyway */
313 for (cell i = 0; i < special_object_count; i++)
314 if (!save_special_p(i))
315 special_objects[i] = false_object;
317 /* dont trace objects only reachable from context stacks so we don't
318 get volatile data saved in the image. */
319 active_contexts.clear();
320 code->uninitialized_blocks.clear();
323 /* do a full GC to push everything remaining into tenured space */
324 primitive_compact_gc();
327 bool ret = save_image(path1_saved, path2_saved);
335 bool factor_vm::embedded_image_p() {
336 const vm_char* vm_path = vm_executable_path();
339 FILE* file = OPEN_READ(vm_path);
342 embedded_image_footer footer;
343 bool embedded_p = read_embedded_image_footer(file, &footer);