| 
									
										
										
										
											2009-05-02 05:04:19 -04:00
										 |  |  | #include "master.hpp"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-11 22:05:00 -04:00
										 |  |  | namespace factor { | 
					
						
							| 
									
										
										
										
											2009-05-04 02:46:13 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-05-02 05:04:19 -04:00
										 |  |  | /* Certain special objects in the image are known to the runtime */ | 
					
						
							| 
									
										
										
										
											2013-05-11 22:05:00 -04:00
										 |  |  | void factor_vm::init_objects(image_header* h) { | 
					
						
							|  |  |  |   memcpy(special_objects, h->special_objects, sizeof(special_objects)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   true_object = h->true_object; | 
					
						
							|  |  |  |   bignum_zero = h->bignum_zero; | 
					
						
							|  |  |  |   bignum_pos_one = h->bignum_pos_one; | 
					
						
							|  |  |  |   bignum_neg_one = h->bignum_neg_one; | 
					
						
							| 
									
										
										
										
											2009-05-02 05:04:19 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-11 22:05:00 -04:00
										 |  |  | void factor_vm::load_data_heap(FILE* file, image_header* h, vm_parameters* p) { | 
					
						
							|  |  |  |   p->tenured_size = std::max((h->data_size * 3) / 2, p->tenured_size); | 
					
						
							| 
									
										
										
										
											2009-05-02 05:04:19 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-11 22:05:00 -04:00
										 |  |  |   init_data_heap(p->young_size, p->aging_size, p->tenured_size); | 
					
						
							| 
									
										
										
										
											2009-05-02 05:04:19 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-11 22:05:00 -04:00
										 |  |  |   fixnum bytes_read = | 
					
						
							|  |  |  |       safe_fread((void*)data->tenured->start, 1, h->data_size, file); | 
					
						
							| 
									
										
										
										
											2009-05-02 05:04:19 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-13 00:53:47 -04:00
										 |  |  |   if ((cell)bytes_read != h->data_size) { | 
					
						
							| 
									
										
										
										
											2013-05-11 22:05:00 -04:00
										 |  |  |     std::cout << "truncated image: " << bytes_read << " bytes read, "; | 
					
						
							|  |  |  |     std::cout << h->data_size << " bytes expected\n"; | 
					
						
							|  |  |  |     fatal_error("load_data_heap failed", 0); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2009-05-02 05:04:19 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-11 22:05:00 -04:00
										 |  |  |   data->tenured->initial_free_list(h->data_size); | 
					
						
							| 
									
										
										
										
											2009-05-02 05:04:19 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-11 22:05:00 -04:00
										 |  |  | void factor_vm::load_code_heap(FILE* file, image_header* h, vm_parameters* p) { | 
					
						
							|  |  |  |   if (h->code_size > p->code_size) | 
					
						
							|  |  |  |     fatal_error("Code heap too small to fit image", h->code_size); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   init_code_heap(p->code_size); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (h->code_size != 0) { | 
					
						
							|  |  |  |     size_t bytes_read = | 
					
						
							|  |  |  |         safe_fread(code->allocator->first_block(), 1, h->code_size, file); | 
					
						
							|  |  |  |     if (bytes_read != h->code_size) { | 
					
						
							|  |  |  |       std::cout << "truncated image: " << bytes_read << " bytes read, "; | 
					
						
							|  |  |  |       std::cout << h->code_size << " bytes expected\n"; | 
					
						
							|  |  |  |       fatal_error("load_code_heap failed", 0); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   code->allocator->initial_free_list(h->code_size); | 
					
						
							|  |  |  |   code->initialize_all_blocks_set(); | 
					
						
							| 
									
										
										
										
											2009-05-02 05:04:19 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-06-11 20:06:00 -04:00
										 |  |  | struct startup_fixup { | 
					
						
							| 
									
										
										
										
											2013-05-11 22:05:00 -04:00
										 |  |  |   static const bool translated_code_block_map = true; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   cell data_offset; | 
					
						
							|  |  |  |   cell code_offset; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-12 23:20:43 -04:00
										 |  |  |   startup_fixup(cell data_offset, cell code_offset) | 
					
						
							|  |  |  |       : data_offset(data_offset), code_offset(code_offset) {} | 
					
						
							| 
									
										
										
										
											2013-05-11 22:05:00 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |   object* fixup_data(object* obj) { | 
					
						
							| 
									
										
										
										
											2013-05-13 00:53:47 -04:00
										 |  |  |     return (object*)((cell)obj + data_offset); | 
					
						
							| 
									
										
										
										
											2013-05-11 22:05:00 -04:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   code_block* fixup_code(code_block* obj) { | 
					
						
							| 
									
										
										
										
											2013-05-13 00:53:47 -04:00
										 |  |  |     return (code_block*)((cell)obj + code_offset); | 
					
						
							| 
									
										
										
										
											2013-05-11 22:05:00 -04:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   object* translate_data(const object* obj) { return fixup_data((object*)obj); } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   code_block* translate_code(const code_block* compiled) { | 
					
						
							|  |  |  |     return fixup_code((code_block*)compiled); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   cell size(const object* obj) { return obj->size(*this); } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   cell size(code_block* compiled) { return compiled->size(*this); } | 
					
						
							| 
									
										
										
										
											2009-10-03 09:47:05 -04:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2009-08-17 16:37:08 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-06-11 20:06:00 -04:00
										 |  |  | struct start_object_updater { | 
					
						
							| 
									
										
										
										
											2013-05-11 22:05:00 -04:00
										 |  |  |   factor_vm* parent; | 
					
						
							|  |  |  |   startup_fixup fixup; | 
					
						
							|  |  |  |   slot_visitor<startup_fixup> data_visitor; | 
					
						
							|  |  |  |   code_block_visitor<startup_fixup> code_visitor; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-12 23:20:43 -04:00
										 |  |  |   start_object_updater(factor_vm* parent, startup_fixup fixup) | 
					
						
							|  |  |  |       : parent(parent), | 
					
						
							|  |  |  |         fixup(fixup), | 
					
						
							|  |  |  |         data_visitor(slot_visitor<startup_fixup>(parent, fixup)), | 
					
						
							|  |  |  |         code_visitor(code_block_visitor<startup_fixup>(parent, fixup)) {} | 
					
						
							| 
									
										
										
										
											2013-05-11 22:05:00 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |   void operator()(object* obj, cell size) { | 
					
						
							|  |  |  |     parent->data->tenured->starts.record_object_start_offset(obj); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     data_visitor.visit_slots(obj); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     switch (obj->type()) { | 
					
						
							|  |  |  |       case ALIEN_TYPE: { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         alien* ptr = (alien*)obj; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (to_boolean(ptr->base)) | 
					
						
							|  |  |  |           ptr->update_address(); | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |           ptr->expired = parent->true_object; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       case DLL_TYPE: { | 
					
						
							|  |  |  |         parent->ffi_dlopen((dll*)obj); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       default: { | 
					
						
							|  |  |  |         code_visitor.visit_object_code_block(obj); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2009-10-03 09:47:05 -04:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-11 22:05:00 -04:00
										 |  |  | void factor_vm::fixup_data(cell data_offset, cell code_offset) { | 
					
						
							|  |  |  |   startup_fixup fixup(data_offset, code_offset); | 
					
						
							|  |  |  |   slot_visitor<startup_fixup> data_workhorse(this, fixup); | 
					
						
							|  |  |  |   data_workhorse.visit_roots(); | 
					
						
							| 
									
										
										
										
											2009-05-02 05:04:19 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-11 22:05:00 -04:00
										 |  |  |   start_object_updater updater(this, fixup); | 
					
						
							|  |  |  |   data->tenured->iterate(updater, fixup); | 
					
						
							| 
									
										
										
										
											2009-11-27 18:05:08 -05:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2009-05-02 05:04:19 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-06-11 20:06:00 -04:00
										 |  |  | struct startup_code_block_relocation_visitor { | 
					
						
							| 
									
										
										
										
											2013-05-11 22:05:00 -04:00
										 |  |  |   factor_vm* parent; | 
					
						
							|  |  |  |   startup_fixup fixup; | 
					
						
							|  |  |  |   slot_visitor<startup_fixup> data_visitor; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-12 23:20:43 -04:00
										 |  |  |   startup_code_block_relocation_visitor(factor_vm* parent, | 
					
						
							|  |  |  |                                         startup_fixup fixup) | 
					
						
							|  |  |  |       : parent(parent), | 
					
						
							|  |  |  |         fixup(fixup), | 
					
						
							|  |  |  |         data_visitor(slot_visitor<startup_fixup>(parent, fixup)) {} | 
					
						
							| 
									
										
										
										
											2013-05-11 22:05:00 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |   void operator()(instruction_operand op) { | 
					
						
							|  |  |  |     code_block* compiled = op.compiled; | 
					
						
							|  |  |  |     cell old_offset = | 
					
						
							| 
									
										
										
										
											2013-05-13 00:53:47 -04:00
										 |  |  |         op.rel_offset() + (cell)compiled->entry_point() - fixup.code_offset; | 
					
						
							| 
									
										
										
										
											2013-05-11 22:05:00 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |     switch (op.rel_type()) { | 
					
						
							|  |  |  |       case RT_LITERAL: { | 
					
						
							|  |  |  |         cell value = op.load_value(old_offset); | 
					
						
							|  |  |  |         if (immediate_p(value)) | 
					
						
							|  |  |  |           op.store_value(value); | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |           op.store_value( | 
					
						
							|  |  |  |               RETAG(fixup.fixup_data(untag<object>(value)), TAG(value))); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       case RT_ENTRY_POINT: | 
					
						
							|  |  |  |       case RT_ENTRY_POINT_PIC: | 
					
						
							|  |  |  |       case RT_ENTRY_POINT_PIC_TAIL: | 
					
						
							|  |  |  |       case RT_HERE: { | 
					
						
							|  |  |  |         cell value = op.load_value(old_offset); | 
					
						
							|  |  |  |         cell offset = TAG(value); | 
					
						
							|  |  |  |         code_block* compiled = (code_block*)UNTAG(value); | 
					
						
							| 
									
										
										
										
											2013-05-13 00:53:47 -04:00
										 |  |  |         op.store_value((cell)fixup.fixup_code(compiled) + offset); | 
					
						
							| 
									
										
										
										
											2013-05-11 22:05:00 -04:00
										 |  |  |         break; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       case RT_UNTAGGED: | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |       default: | 
					
						
							|  |  |  |         parent->store_external_address(op); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2009-11-27 18:05:08 -05:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2009-05-02 05:04:19 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-06-11 20:06:00 -04:00
										 |  |  | struct startup_code_block_updater { | 
					
						
							| 
									
										
										
										
											2013-05-11 22:05:00 -04:00
										 |  |  |   factor_vm* parent; | 
					
						
							|  |  |  |   startup_fixup fixup; | 
					
						
							| 
									
										
										
										
											2009-10-03 09:47:05 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-12 23:20:43 -04:00
										 |  |  |   startup_code_block_updater(factor_vm* parent, startup_fixup fixup) | 
					
						
							|  |  |  |       : parent(parent), fixup(fixup) {} | 
					
						
							| 
									
										
										
										
											2009-10-03 09:47:05 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-11 22:05:00 -04:00
										 |  |  |   void operator()(code_block* compiled, cell size) { | 
					
						
							|  |  |  |     slot_visitor<startup_fixup> data_visitor(parent, fixup); | 
					
						
							|  |  |  |     data_visitor.visit_code_block_objects(compiled); | 
					
						
							| 
									
										
										
										
											2009-11-27 18:05:08 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-11 22:05:00 -04:00
										 |  |  |     startup_code_block_relocation_visitor code_visitor(parent, fixup); | 
					
						
							|  |  |  |     compiled->each_instruction_operand(code_visitor); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2009-10-03 09:47:05 -04:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2009-08-17 16:37:08 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-11 22:05:00 -04:00
										 |  |  | void factor_vm::fixup_code(cell data_offset, cell code_offset) { | 
					
						
							|  |  |  |   startup_fixup fixup(data_offset, code_offset); | 
					
						
							|  |  |  |   startup_code_block_updater updater(this, fixup); | 
					
						
							|  |  |  |   code->allocator->iterate(updater, fixup); | 
					
						
							| 
									
										
										
										
											2009-08-17 16:37:08 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-11 22:05:00 -04:00
										 |  |  | bool factor_vm::read_embedded_image_footer(FILE* file, | 
					
						
							|  |  |  |                                            embedded_image_footer* footer) { | 
					
						
							| 
									
										
										
										
											2013-05-13 00:53:47 -04:00
										 |  |  |   safe_fseek(file, -(off_t)sizeof(embedded_image_footer), SEEK_END); | 
					
						
							|  |  |  |   safe_fread(footer, (off_t)sizeof(embedded_image_footer), 1, file); | 
					
						
							| 
									
										
										
										
											2013-05-11 22:05:00 -04:00
										 |  |  |   return footer->magic == image_magic; | 
					
						
							| 
									
										
										
										
											2011-11-27 17:39:21 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-11 22:05:00 -04:00
										 |  |  | FILE* factor_vm::open_image(vm_parameters* p) { | 
					
						
							|  |  |  |   if (p->embedded_image) { | 
					
						
							|  |  |  |     FILE* file = OPEN_READ(p->executable_path); | 
					
						
							|  |  |  |     if (file == NULL) { | 
					
						
							|  |  |  |       std::cout << "Cannot open embedded image" << std::endl; | 
					
						
							|  |  |  |       std::cout << strerror(errno) << std::endl; | 
					
						
							|  |  |  |       exit(1); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     embedded_image_footer footer; | 
					
						
							|  |  |  |     if (!read_embedded_image_footer(file, &footer)) { | 
					
						
							|  |  |  |       std::cout << "No embedded image" << std::endl; | 
					
						
							|  |  |  |       exit(1); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2013-05-13 00:53:47 -04:00
										 |  |  |     safe_fseek(file, (off_t)footer.image_offset, SEEK_SET); | 
					
						
							| 
									
										
										
										
											2013-05-11 22:05:00 -04:00
										 |  |  |     return file; | 
					
						
							|  |  |  |   } else | 
					
						
							|  |  |  |     return OPEN_READ(p->image_path); | 
					
						
							| 
									
										
										
										
											2011-11-18 21:05:23 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-05-02 05:04:19 -04:00
										 |  |  | /* Read an image file from disk, only done once during startup */ | 
					
						
							|  |  |  | /* This function also initializes the data and code heaps */ | 
					
						
							| 
									
										
										
										
											2013-05-11 22:05:00 -04:00
										 |  |  | void factor_vm::load_image(vm_parameters* p) { | 
					
						
							|  |  |  |   FILE* file = open_image(p); | 
					
						
							|  |  |  |   if (file == NULL) { | 
					
						
							|  |  |  |     std::cout << "Cannot open image file: " << p->image_path << std::endl; | 
					
						
							|  |  |  |     std::cout << strerror(errno) << std::endl; | 
					
						
							|  |  |  |     exit(1); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   image_header h; | 
					
						
							|  |  |  |   if (safe_fread(&h, sizeof(image_header), 1, file) != 1) | 
					
						
							|  |  |  |     fatal_error("Cannot read image header", 0); | 
					
						
							| 
									
										
										
										
											2009-05-02 05:04:19 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-11 22:05:00 -04:00
										 |  |  |   if (h.magic != image_magic) | 
					
						
							|  |  |  |     fatal_error("Bad image: magic number check failed", h.magic); | 
					
						
							| 
									
										
										
										
											2009-05-02 05:04:19 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-11 22:05:00 -04:00
										 |  |  |   if (h.version != image_version) | 
					
						
							|  |  |  |     fatal_error("Bad image: version number check failed", h.version); | 
					
						
							| 
									
										
										
										
											2009-05-02 05:04:19 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-11 22:05:00 -04:00
										 |  |  |   load_data_heap(file, &h, p); | 
					
						
							|  |  |  |   load_code_heap(file, &h, p); | 
					
						
							| 
									
										
										
										
											2009-05-02 05:04:19 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-11 22:05:00 -04:00
										 |  |  |   safe_fclose(file); | 
					
						
							| 
									
										
										
										
											2009-05-02 05:04:19 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-11 22:05:00 -04:00
										 |  |  |   init_objects(&h); | 
					
						
							| 
									
										
										
										
											2009-05-02 05:04:19 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-11 22:05:00 -04:00
										 |  |  |   cell data_offset = data->tenured->start - h.data_relocation_base; | 
					
						
							|  |  |  |   cell code_offset = code->allocator->start - h.code_relocation_base; | 
					
						
							| 
									
										
										
										
											2009-11-27 18:05:08 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-11 22:05:00 -04:00
										 |  |  |   fixup_data(data_offset, code_offset); | 
					
						
							|  |  |  |   fixup_code(data_offset, code_offset); | 
					
						
							| 
									
										
										
										
											2009-05-02 05:04:19 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-11 22:05:00 -04:00
										 |  |  |   /* Store image path name */ | 
					
						
							| 
									
										
										
										
											2013-05-13 00:53:47 -04:00
										 |  |  |   special_objects[OBJ_IMAGE] = allot_alien(false_object, (cell)p->image_path); | 
					
						
							| 
									
										
										
										
											2009-05-02 05:04:19 -04:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2009-05-04 02:46:13 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-10-16 15:41:40 -04:00
										 |  |  | /* Save the current image to disk */ | 
					
						
							| 
									
										
										
										
											2013-05-11 22:05:00 -04:00
										 |  |  | bool factor_vm::save_image(const vm_char* saving_filename, | 
					
						
							|  |  |  |                            const vm_char* filename) { | 
					
						
							|  |  |  |   FILE* file; | 
					
						
							|  |  |  |   image_header h; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   file = OPEN_WRITE(saving_filename); | 
					
						
							|  |  |  |   if (file == NULL) { | 
					
						
							|  |  |  |     std::cout << "Cannot open image file: " << saving_filename << std::endl; | 
					
						
							|  |  |  |     std::cout << strerror(errno) << std::endl; | 
					
						
							|  |  |  |     return false; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   h.magic = image_magic; | 
					
						
							|  |  |  |   h.version = image_version; | 
					
						
							|  |  |  |   h.data_relocation_base = data->tenured->start; | 
					
						
							|  |  |  |   h.data_size = data->tenured->occupied_space(); | 
					
						
							|  |  |  |   h.code_relocation_base = code->allocator->start; | 
					
						
							|  |  |  |   h.code_size = code->allocator->occupied_space(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   h.true_object = true_object; | 
					
						
							|  |  |  |   h.bignum_zero = bignum_zero; | 
					
						
							|  |  |  |   h.bignum_pos_one = bignum_pos_one; | 
					
						
							|  |  |  |   h.bignum_neg_one = bignum_neg_one; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   for (cell i = 0; i < special_object_count; i++) | 
					
						
							|  |  |  |     h.special_objects[i] = | 
					
						
							|  |  |  |         (save_special_p(i) ? special_objects[i] : false_object); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   bool ok = true; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (safe_fwrite(&h, sizeof(image_header), 1, file) != 1) | 
					
						
							|  |  |  |     ok = false; | 
					
						
							|  |  |  |   if (safe_fwrite((void*)data->tenured->start, h.data_size, 1, file) != 1) | 
					
						
							|  |  |  |     ok = false; | 
					
						
							|  |  |  |   if (safe_fwrite(code->allocator->first_block(), h.code_size, 1, file) != 1) | 
					
						
							|  |  |  |     ok = false; | 
					
						
							|  |  |  |   safe_fclose(file); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (!ok) | 
					
						
							|  |  |  |     std::cout << "save-image failed: " << strerror(errno) << std::endl; | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |     move_file(saving_filename, filename); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return ok; | 
					
						
							| 
									
										
										
										
											2009-10-16 15:41:40 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-11 22:05:00 -04:00
										 |  |  | void factor_vm::primitive_save_image() { | 
					
						
							|  |  |  |   /* do a full GC to push everything into tenured space */ | 
					
						
							|  |  |  |   primitive_compact_gc(); | 
					
						
							| 
									
										
										
										
											2009-10-16 15:41:40 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-11 22:05:00 -04:00
										 |  |  |   data_root<byte_array> path2(ctx->pop(), this); | 
					
						
							|  |  |  |   path2.untag_check(this); | 
					
						
							|  |  |  |   data_root<byte_array> path1(ctx->pop(), this); | 
					
						
							|  |  |  |   path1.untag_check(this); | 
					
						
							|  |  |  |   save_image((vm_char*)(path1.untagged() + 1), | 
					
						
							|  |  |  |              (vm_char*)(path2.untagged() + 1)); | 
					
						
							| 
									
										
										
										
											2009-10-16 15:41:40 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-11 22:05:00 -04:00
										 |  |  | void factor_vm::primitive_save_image_and_exit() { | 
					
						
							|  |  |  |   /* We unbox this before doing anything else. This is the only point
 | 
					
						
							|  |  |  |      where we might throw an error, so we have to throw an error here since | 
					
						
							|  |  |  |      later steps destroy the current image. */ | 
					
						
							|  |  |  |   data_root<byte_array> path2(ctx->pop(), this); | 
					
						
							|  |  |  |   path2.untag_check(this); | 
					
						
							|  |  |  |   data_root<byte_array> path1(ctx->pop(), this); | 
					
						
							|  |  |  |   path1.untag_check(this); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* strip out special_objects data which is set on startup anyway */ | 
					
						
							|  |  |  |   for (cell i = 0; i < special_object_count; i++) | 
					
						
							|  |  |  |     if (!save_special_p(i)) | 
					
						
							|  |  |  |       special_objects[i] = false_object; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   gc(collect_compact_op, 0, /* requested size */ | 
					
						
							|  |  |  |      false /* discard objects only reachable from stacks */); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* Save the image */ | 
					
						
							|  |  |  |   if (save_image((vm_char*)(path1.untagged() + 1), | 
					
						
							|  |  |  |                  (vm_char*)(path2.untagged() + 1))) | 
					
						
							|  |  |  |     exit(0); | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |     exit(1); | 
					
						
							| 
									
										
										
										
											2009-10-16 15:41:40 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-11 22:05:00 -04:00
										 |  |  | bool factor_vm::embedded_image_p() { | 
					
						
							|  |  |  |   const vm_char* vm_path = vm_executable_path(); | 
					
						
							|  |  |  |   if (!vm_path) | 
					
						
							|  |  |  |     return false; | 
					
						
							|  |  |  |   FILE* file = OPEN_READ(vm_path); | 
					
						
							|  |  |  |   if (!file) | 
					
						
							|  |  |  |     return false; | 
					
						
							|  |  |  |   embedded_image_footer footer; | 
					
						
							|  |  |  |   bool embedded_p = read_embedded_image_footer(file, &footer); | 
					
						
							|  |  |  |   fclose(file); | 
					
						
							|  |  |  |   return embedded_p; | 
					
						
							| 
									
										
										
										
											2011-11-18 21:05:23 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-05-04 02:46:13 -04:00
										 |  |  | } |