| 
									
										
										
										
											2007-09-20 18:09:08 -04:00
										 |  |  | #include "master.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Certain special objects in the image are known to the runtime */ | 
					
						
							|  |  |  | void init_objects(F_HEADER *h) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	memcpy(userenv,h->userenv,sizeof(userenv)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	T = h->t; | 
					
						
							|  |  |  | 	bignum_zero = h->bignum_zero; | 
					
						
							|  |  |  | 	bignum_pos_one = h->bignum_pos_one; | 
					
						
							|  |  |  | 	bignum_neg_one = h->bignum_neg_one; | 
					
						
							| 
									
										
										
										
											2007-12-26 02:33:49 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	stage2 = (userenv[STAGE2_ENV] != F); | 
					
						
							| 
									
										
										
										
											2007-09-20 18:09:08 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | INLINE void load_data_heap(FILE *file, F_HEADER *h, F_PARAMETERS *p) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	CELL good_size = h->data_size + (1 << 20); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if(good_size > p->aging_size) | 
					
						
							|  |  |  | 		p->aging_size = good_size; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	init_data_heap(p->gen_count,p->young_size,p->aging_size,p->secure_gc); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	F_ZONE *tenured = &data_heap->generations[TENURED]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if(fread((void*)tenured->start,h->data_size,1,file) != 1) | 
					
						
							|  |  |  | 		fatal_error("load_data_heap failed",0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	tenured->here = tenured->start + h->data_size; | 
					
						
							|  |  |  | 	data_relocation_base = h->data_relocation_base; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | INLINE void load_code_heap(FILE *file, F_HEADER *h, F_PARAMETERS *p) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	CELL good_size = h->code_size + (1 << 19); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if(good_size > p->code_size) | 
					
						
							|  |  |  | 		p->code_size = good_size; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	init_code_heap(p->code_size); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if(h->code_size != 0 | 
					
						
							|  |  |  | 		&& fread(first_block(&code_heap),h->code_size,1,file) != 1) | 
					
						
							|  |  |  | 		fatal_error("load_code_heap failed",0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	code_relocation_base = h->code_relocation_base; | 
					
						
							|  |  |  | 	build_free_list(&code_heap,h->code_size); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Read an image file from disk, only done once during startup */ | 
					
						
							|  |  |  | /* This function also initializes the data and code heaps */ | 
					
						
							|  |  |  | void load_image(F_PARAMETERS *p) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	FILE *file = OPEN_READ(p->image); | 
					
						
							|  |  |  | 	if(file == NULL) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		FPRINTF(stderr,"Cannot open image file: %s\n",p->image); | 
					
						
							|  |  |  | 		fprintf(stderr,"%s\n",strerror(errno)); | 
					
						
							|  |  |  | 		exit(1); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	F_HEADER h; | 
					
						
							|  |  |  | 	fread(&h,sizeof(F_HEADER),1,file); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if(h.magic != IMAGE_MAGIC) | 
					
						
							|  |  |  | 		fatal_error("Bad image: magic number check failed",h.magic); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if(h.version != IMAGE_VERSION) | 
					
						
							|  |  |  | 		fatal_error("Bad image: version number check failed",h.version); | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	load_data_heap(file,&h,p); | 
					
						
							|  |  |  | 	load_code_heap(file,&h,p); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	fclose(file); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	init_objects(&h); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	relocate_data(); | 
					
						
							|  |  |  | 	relocate_code(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Store image path name */ | 
					
						
							|  |  |  | 	userenv[IMAGE_ENV] = tag_object(from_native_string(p->image)); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Save the current image to disk */ | 
					
						
							| 
									
										
										
										
											2007-10-21 15:18:31 -04:00
										 |  |  | void save_image(const F_CHAR *filename) | 
					
						
							| 
									
										
										
										
											2007-09-20 18:09:08 -04:00
										 |  |  | { | 
					
						
							|  |  |  | 	FILE* file; | 
					
						
							|  |  |  | 	F_HEADER h; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	FPRINTF(stderr,"*** Saving %s...\n",filename); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	file = OPEN_WRITE(filename); | 
					
						
							|  |  |  | 	if(file == NULL) | 
					
						
							| 
									
										
										
										
											2007-10-21 15:18:31 -04:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2007-11-05 13:39:20 -05:00
										 |  |  | 		fprintf(stderr,"Cannot open image file: %s\n",strerror(errno)); | 
					
						
							| 
									
										
										
										
											2007-10-21 15:18:31 -04:00
										 |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2007-09-20 18:09:08 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	F_ZONE *tenured = &data_heap->generations[TENURED]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	h.magic = IMAGE_MAGIC; | 
					
						
							|  |  |  | 	h.version = IMAGE_VERSION; | 
					
						
							|  |  |  | 	h.data_relocation_base = tenured->start; | 
					
						
							|  |  |  | 	h.data_size = tenured->here - tenured->start; | 
					
						
							|  |  |  | 	h.code_relocation_base = code_heap.segment->start; | 
					
						
							|  |  |  | 	h.code_size = heap_size(&code_heap); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	h.t = T; | 
					
						
							|  |  |  | 	h.bignum_zero = bignum_zero; | 
					
						
							|  |  |  | 	h.bignum_pos_one = bignum_pos_one; | 
					
						
							|  |  |  | 	h.bignum_neg_one = bignum_neg_one; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	CELL i; | 
					
						
							|  |  |  | 	for(i = 0; i < USER_ENV; i++) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		if(i < FIRST_SAVE_ENV) | 
					
						
							|  |  |  | 			h.userenv[i] = F; | 
					
						
							|  |  |  | 		else | 
					
						
							|  |  |  | 			h.userenv[i] = userenv[i]; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	fwrite(&h,sizeof(F_HEADER),1,file); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-05 13:39:20 -05:00
										 |  |  | 	if(fwrite((void*)tenured->start,h.data_size,1,file) != 1) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		fprintf(stderr,"Save data heap failed: %s\n",strerror(errno)); | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2007-09-20 18:09:08 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-05 13:39:20 -05:00
										 |  |  | 	if(fwrite(first_block(&code_heap),h.code_size,1,file) != 1) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		fprintf(stderr,"Save code heap failed: %s\n",strerror(errno)); | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if(fclose(file)) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		fprintf(stderr,"Failed to close image file: %s\n",strerror(errno)); | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2007-09-20 18:09:08 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | DEFINE_PRIMITIVE(save_image) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	/* do a full GC to push everything into tenured space */ | 
					
						
							|  |  |  | 	code_gc(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	save_image(unbox_native_string()); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | DEFINE_PRIMITIVE(save_image_and_exit) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2007-12-16 18:42:56 -05:00
										 |  |  | 	F_CHAR *path = unbox_native_string(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	REGISTER_C_STRING(path); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-09-20 18:09:08 -04:00
										 |  |  | 	/* strip out userenv data which is set on startup anyway */ | 
					
						
							|  |  |  | 	CELL i; | 
					
						
							|  |  |  | 	for(i = 0; i < FIRST_SAVE_ENV; i++) | 
					
						
							|  |  |  | 		userenv[i] = F; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-28 02:22:53 -05:00
										 |  |  | 	for(i = LAST_SAVE_ENV + 1; i < USER_ENV; i++) | 
					
						
							|  |  |  | 		userenv[i] = F; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-09-20 18:09:08 -04:00
										 |  |  | 	/* do a full GC + code heap compaction */ | 
					
						
							| 
									
										
										
										
											2007-10-29 01:12:27 -04:00
										 |  |  | 	compact_code_heap(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-12-16 18:42:56 -05:00
										 |  |  | 	UNREGISTER_C_STRING(path); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-10-29 01:12:27 -04:00
										 |  |  | 	/* Save the image */ | 
					
						
							| 
									
										
										
										
											2007-12-16 18:42:56 -05:00
										 |  |  | 	save_image(path); | 
					
						
							| 
									
										
										
										
											2007-09-20 18:09:08 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* now exit; we cannot continue executing like this */ | 
					
						
							|  |  |  | 	exit(0); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void fixup_word(F_WORD *word) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2008-01-02 19:36:36 -05:00
										 |  |  | 	if(stage2) | 
					
						
							| 
									
										
										
										
											2007-10-28 04:33:36 -04:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2008-01-02 19:36:36 -05:00
										 |  |  | 		code_fixup((CELL)&word->code); | 
					
						
							|  |  |  | 		if(word->profiling) code_fixup((CELL)&word->profiling); | 
					
						
							| 
									
										
										
										
											2008-01-16 15:45:04 -05:00
										 |  |  | 		code_fixup((CELL)&word->xt); | 
					
						
							| 
									
										
										
										
											2007-10-28 04:33:36 -04:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2007-09-20 18:09:08 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void fixup_quotation(F_QUOTATION *quot) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2007-10-28 04:33:36 -04:00
										 |  |  | 	if(quot->compiledp == F) | 
					
						
							| 
									
										
										
										
											2007-09-25 21:23:20 -04:00
										 |  |  | 		quot->xt = lazy_jit_compile; | 
					
						
							| 
									
										
										
										
											2007-09-26 00:26:19 -04:00
										 |  |  | 	else | 
					
						
							| 
									
										
										
										
											2007-10-28 04:33:36 -04:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2007-10-29 01:12:27 -04:00
										 |  |  | 		code_fixup((CELL)"->xt); | 
					
						
							|  |  |  | 		code_fixup((CELL)"->code); | 
					
						
							| 
									
										
										
										
											2007-10-28 04:33:36 -04:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2007-09-20 18:09:08 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void fixup_alien(F_ALIEN *d) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	d->expired = T; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void fixup_stack_frame(F_STACK_FRAME *frame) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2007-10-29 01:12:27 -04:00
										 |  |  | 	code_fixup((CELL)&frame->xt); | 
					
						
							|  |  |  | 	code_fixup((CELL)&FRAME_RETURN_ADDRESS(frame)); | 
					
						
							| 
									
										
										
										
											2007-09-20 18:09:08 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-09-22 18:56:27 -04:00
										 |  |  | void fixup_callstack_object(F_CALLSTACK *stack) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	iterate_callstack_object(stack,fixup_stack_frame); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-09-20 18:09:08 -04:00
										 |  |  | /* Initialize an object in a newly-loaded image */ | 
					
						
							|  |  |  | void relocate_object(CELL relocating) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	do_slots(relocating,data_fixup); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	switch(untag_header(get(relocating))) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 	case WORD_TYPE: | 
					
						
							|  |  |  | 		fixup_word((F_WORD *)relocating); | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case QUOTATION_TYPE: | 
					
						
							|  |  |  | 		fixup_quotation((F_QUOTATION *)relocating); | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case DLL_TYPE: | 
					
						
							| 
									
										
										
										
											2008-02-16 01:54:54 -05:00
										 |  |  | 		ffi_dlopen((F_DLL *)relocating); | 
					
						
							| 
									
										
										
										
											2007-09-20 18:09:08 -04:00
										 |  |  | 		break; | 
					
						
							|  |  |  | 	case ALIEN_TYPE: | 
					
						
							|  |  |  | 		fixup_alien((F_ALIEN *)relocating); | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case CALLSTACK_TYPE: | 
					
						
							| 
									
										
										
										
											2007-09-22 18:56:27 -04:00
										 |  |  | 		fixup_callstack_object((F_CALLSTACK *)relocating); | 
					
						
							| 
									
										
										
										
											2007-09-20 18:09:08 -04:00
										 |  |  | 		break; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Since the image might have been saved with a different base address than
 | 
					
						
							|  |  |  | where it is loaded, we need to fix up pointers in the image. */ | 
					
						
							|  |  |  | void relocate_data() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	CELL relocating; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	CELL i; | 
					
						
							|  |  |  | 	for(i = 0; i < USER_ENV; i++) | 
					
						
							|  |  |  | 		data_fixup(&userenv[i]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	data_fixup(&T); | 
					
						
							|  |  |  | 	data_fixup(&bignum_zero); | 
					
						
							|  |  |  | 	data_fixup(&bignum_pos_one); | 
					
						
							|  |  |  | 	data_fixup(&bignum_neg_one); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	F_ZONE *tenured = &data_heap->generations[TENURED]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for(relocating = tenured->start; | 
					
						
							|  |  |  | 		relocating < tenured->here; | 
					
						
							|  |  |  | 		relocating += untagged_object_size(relocating)) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		allot_barrier(relocating); | 
					
						
							|  |  |  | 		relocate_object(relocating); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void fixup_code_block(F_COMPILED *relocating, CELL code_start, | 
					
						
							| 
									
										
										
										
											2008-01-16 15:45:04 -05:00
										 |  |  | 	CELL reloc_start, CELL literals_start) | 
					
						
							| 
									
										
										
										
											2007-09-20 18:09:08 -04:00
										 |  |  | { | 
					
						
							|  |  |  | 	/* relocate literal table data */ | 
					
						
							|  |  |  | 	CELL scan; | 
					
						
							|  |  |  | 	CELL literal_end = literals_start + relocating->literals_length; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for(scan = literals_start; scan < literal_end; scan += CELLS) | 
					
						
							|  |  |  | 		data_fixup((CELL*)scan); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-10-28 04:33:36 -04:00
										 |  |  | 	if(reloc_start != literals_start) | 
					
						
							| 
									
										
										
										
											2008-01-16 15:45:04 -05:00
										 |  |  | 		relocate_code_block(relocating,code_start,reloc_start,literals_start); | 
					
						
							| 
									
										
										
										
											2007-09-20 18:09:08 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void relocate_code() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	iterate_code_heap(fixup_code_block); | 
					
						
							|  |  |  | } |