5 bool factor_arg(const vm_char* str, const vm_char* arg, cell* value) {
7 if (SSCANF(str, arg, &val) > 0) {
14 vm_parameters::vm_parameters() {
15 embedded_image = false;
18 datastack_size = 32 * sizeof(cell);
19 retainstack_size = 32 * sizeof(cell);
21 #if defined(FACTOR_PPC)
22 callstack_size = 256 * sizeof(cell);
24 callstack_size = 128 * sizeof(cell);
28 young_size = sizeof(cell) / 4;
29 aging_size = sizeof(cell) / 2;
30 tenured_size = 24 * sizeof(cell);
38 console = GetConsoleWindow() != NULL;
46 void vm_parameters::init_from_args(int argc, vm_char** argv) {
47 executable_path = argv[0];
51 for (i = 1; i < argc; i++) {
52 vm_char* arg = argv[i];
53 if (STRCMP(arg, STRING_LITERAL("--")) == 0)
55 else if (factor_arg(arg, STRING_LITERAL("-datastack=%d"),
58 else if (factor_arg(arg, STRING_LITERAL("-retainstack=%d"),
61 else if (factor_arg(arg, STRING_LITERAL("-callstack=%d"),
64 else if (factor_arg(arg, STRING_LITERAL("-young=%d"), &young_size))
66 else if (factor_arg(arg, STRING_LITERAL("-aging=%d"), &aging_size))
68 else if (factor_arg(arg, STRING_LITERAL("-tenured=%d"), &tenured_size))
70 else if (factor_arg(arg, STRING_LITERAL("-codeheap=%d"), &code_size))
72 else if (factor_arg(arg, STRING_LITERAL("-pic=%d"), &max_pic_size))
74 else if (factor_arg(arg, STRING_LITERAL("-callbacks=%d"), &callback_size))
76 else if (STRNCMP(arg, STRING_LITERAL("-i="), 3) == 0)
78 else if (STRCMP(arg, STRING_LITERAL("-fep")) == 0)
80 else if (STRCMP(arg, STRING_LITERAL("-nosignals")) == 0)
82 else if (STRCMP(arg, STRING_LITERAL("-console")) == 0)
87 void factor_vm::load_data_heap(FILE* file, image_header* h, vm_parameters* p) {
88 p->tenured_size = std::max((h->data_size * 3) / 2, p->tenured_size);
90 init_data_heap(p->young_size, p->aging_size, p->tenured_size);
93 raw_fread((void*)data->tenured->start, 1, h->data_size, file);
95 if ((cell)bytes_read != h->data_size) {
96 std::cout << "truncated image: " << bytes_read << " bytes read, ";
97 std::cout << h->data_size << " bytes expected\n";
98 fatal_error("load_data_heap failed", 0);
101 data->tenured->initial_free_list(h->data_size);
104 void factor_vm::load_code_heap(FILE* file, image_header* h, vm_parameters* p) {
105 if (h->code_size > p->code_size)
106 fatal_error("Code heap too small to fit image", h->code_size);
108 code = new code_heap(p->code_size);
110 if (h->code_size != 0) {
112 raw_fread((void*)code->allocator->start, 1, h->code_size, file);
113 if (bytes_read != h->code_size) {
114 std::cout << "truncated image: " << bytes_read << " bytes read, ";
115 std::cout << h->code_size << " bytes expected\n";
116 fatal_error("load_code_heap failed", 0);
120 code->allocator->initial_free_list(h->code_size);
121 code->initialize_all_blocks_set();
124 struct startup_fixup {
125 static const bool translated_code_block_map = true;
130 startup_fixup(cell data_offset, cell code_offset)
131 : data_offset(data_offset), code_offset(code_offset) {}
133 object* fixup_data(object* obj) {
134 return (object*)((cell)obj + data_offset);
137 code_block* fixup_code(code_block* obj) {
138 return (code_block*)((cell)obj + code_offset);
141 object* translate_data(const object* obj) { return fixup_data((object*)obj); }
143 code_block* translate_code(const code_block* compiled) {
144 return fixup_code((code_block*)compiled);
147 cell size(const object* obj) { return obj->size(*this); }
149 cell size(code_block* compiled) { return compiled->size(*this); }
152 void factor_vm::fixup_heaps(cell data_offset, cell code_offset) {
153 startup_fixup fixup(data_offset, code_offset);
154 slot_visitor<startup_fixup> visitor(this, fixup);
155 visitor.visit_all_roots();
157 auto start_object_updater = [&](object *obj, cell size) {
158 data->tenured->starts.record_object_start_offset(obj);
159 visitor.visit_slots(obj);
160 switch (obj->type()) {
162 alien* ptr = (alien*)obj;
163 if (to_boolean(ptr->base))
164 ptr->update_address();
166 ptr->expired = special_objects[OBJ_CANONICAL_TRUE];
170 ffi_dlopen((dll*)obj);
174 visitor.visit_object_code_block(obj);
179 data->tenured->iterate(start_object_updater, fixup);
181 auto updater = [&](code_block* compiled, cell size) {
182 visitor.visit_code_block_objects(compiled);
183 cell rel_base = compiled->entry_point() - fixup.code_offset;
184 visitor.visit_instruction_operands(compiled, rel_base);
186 code->allocator->iterate(updater, fixup);
189 bool factor_vm::read_embedded_image_footer(FILE* file,
190 embedded_image_footer* footer) {
191 safe_fseek(file, -(off_t)sizeof(embedded_image_footer), SEEK_END);
192 safe_fread(footer, (off_t)sizeof(embedded_image_footer), 1, file);
193 return footer->magic == image_magic;
196 char *threadsafe_strerror(int errnum) {
197 char *buf = (char *) malloc(STRERROR_BUFFER_SIZE);
199 fatal_error("Out of memory in threadsafe_strerror, errno", errnum);
201 THREADSAFE_STRERROR(errnum, buf, STRERROR_BUFFER_SIZE);
205 FILE* factor_vm::open_image(vm_parameters* p) {
206 if (!p->embedded_image)
207 return OPEN_READ(p->image_path);
209 FILE* file = OPEN_READ(p->executable_path);
211 std::cout << "Cannot open embedded image" << std::endl;
212 char *msg = threadsafe_strerror(errno);
213 std::cout << "strerror:1: " << msg << std::endl;
217 embedded_image_footer footer;
218 if (!read_embedded_image_footer(file, &footer)) {
219 std::cout << "No embedded image" << std::endl;
222 safe_fseek(file, (off_t)footer.image_offset, SEEK_SET);
226 /* Read an image file from disk, only done once during startup */
227 /* This function also initializes the data and code heaps */
228 void factor_vm::load_image(vm_parameters* p) {
229 FILE* file = open_image(p);
231 std::cout << "Cannot open image file: " << p->image_path << std::endl;
232 char *msg = threadsafe_strerror(errno);
233 std::cout << "strerror:2: " << msg << std::endl;
238 if (raw_fread(&h, sizeof(image_header), 1, file) != 1)
239 fatal_error("Cannot read image header", 0);
241 if (h.magic != image_magic)
242 fatal_error("Bad image: magic number check failed", h.magic);
244 if (h.version != image_version)
245 fatal_error("Bad image: version number check failed", h.version);
247 load_data_heap(file, &h, p);
248 load_code_heap(file, &h, p);
252 /* Certain special objects in the image are known to the runtime */
253 memcpy(special_objects, h.special_objects, sizeof(special_objects));
255 cell data_offset = data->tenured->start - h.data_relocation_base;
256 cell code_offset = code->allocator->start - h.code_relocation_base;
257 fixup_heaps(data_offset, code_offset);
259 /* Store image path name */
260 special_objects[OBJ_IMAGE] = allot_alien(false_object, (cell)p->image_path);
263 /* Save the current image to disk. We don't throw any exceptions here
264 because if the 'then-die' argument is t it is not safe to do
265 so. Instead we signal failure by returning false. */
266 bool factor_vm::save_image(const vm_char* saving_filename,
267 const vm_char* filename) {
270 h.magic = image_magic;
271 h.version = image_version;
272 h.data_relocation_base = data->tenured->start;
273 h.data_size = data->tenured->occupied_space();
274 h.code_relocation_base = code->allocator->start;
275 h.code_size = code->allocator->occupied_space();
277 for (cell i = 0; i < special_object_count; i++)
278 h.special_objects[i] =
279 (save_special_p(i) ? special_objects[i] : false_object);
281 FILE* file = OPEN_WRITE(saving_filename);
284 if (safe_fwrite(&h, sizeof(image_header), 1, file) != 1)
286 if (h.data_size > 0 &&
287 safe_fwrite((void*)data->tenured->start, h.data_size, 1, file) != 1)
289 if (h.code_size > 0 &&
290 safe_fwrite((void*)code->allocator->start, h.code_size, 1, file) != 1)
292 if (raw_fclose(file) == -1)
294 if (!move_file(saving_filename, filename))
299 /* Allocates memory */
300 void factor_vm::primitive_save_image() {
301 /* We unbox this before doing anything else. This is the only point
302 where we might throw an error, so we have to throw an error here since
303 later steps destroy the current image. */
304 bool then_die = to_boolean(ctx->pop());
305 byte_array* path2 = untag_check<byte_array>(ctx->pop());
306 byte_array* path1 = untag_check<byte_array>(ctx->pop());
308 /* Copy the paths to non-gc memory to avoid them hanging around in
310 vm_char* path1_saved = safe_strdup(path1->data<vm_char>());
311 vm_char* path2_saved = safe_strdup(path2->data<vm_char>());
314 /* strip out special_objects data which is set on startup anyway */
315 for (cell i = 0; i < special_object_count; i++)
316 if (!save_special_p(i))
317 special_objects[i] = false_object;
319 /* dont trace objects only reachable from context stacks so we don't
320 get volatile data saved in the image. */
321 active_contexts.clear();
322 code->uninitialized_blocks.clear();
324 /* I think clearing the callback heap should be fine too. */
325 callbacks->allocator->initial_free_list(0);
328 /* do a full GC to push everything remaining into tenured space */
329 primitive_compact_gc();
332 bool ret = save_image(path1_saved, path2_saved);
340 general_error(ERROR_IO, tag_fixnum(errno), false_object);
344 bool factor_vm::embedded_image_p() {
345 const vm_char* vm_path = vm_executable_path();
348 FILE* file = OPEN_READ(vm_path);
351 embedded_image_footer footer;
352 bool embedded_p = read_embedded_image_footer(file, &footer);