| 
									
										
										
										
											2009-05-04 02:00:30 -04:00
										 |  |  | #include "master.hpp"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-05-04 05:50:24 -04:00
										 |  |  | factor::context *stack_chain; | 
					
						
							| 
									
										
										
										
											2009-05-04 02:46:13 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | namespace factor | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-05-04 05:50:24 -04:00
										 |  |  | cell ds_size, rs_size; | 
					
						
							|  |  |  | context *unused_contexts; | 
					
						
							| 
									
										
										
										
											2009-05-04 02:00:30 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-05-05 12:33:35 -04:00
										 |  |  | void reset_datastack() | 
					
						
							| 
									
										
										
										
											2009-05-04 02:00:30 -04:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2009-05-04 05:50:24 -04:00
										 |  |  | 	ds = ds_bot - sizeof(cell); | 
					
						
							| 
									
										
										
										
											2009-05-04 02:00:30 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-05-05 12:33:35 -04:00
										 |  |  | void reset_retainstack() | 
					
						
							| 
									
										
										
										
											2009-05-04 02:00:30 -04:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2009-05-04 05:50:24 -04:00
										 |  |  | 	rs = rs_bot - sizeof(cell); | 
					
						
							| 
									
										
										
										
											2009-05-04 02:00:30 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-05-08 16:05:55 -04:00
										 |  |  | static const cell stack_reserved = (64 * sizeof(cell)); | 
					
						
							| 
									
										
										
										
											2009-05-04 02:00:30 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-05-05 12:33:35 -04:00
										 |  |  | void fix_stacks() | 
					
						
							| 
									
										
										
										
											2009-05-04 02:00:30 -04:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2009-05-08 16:05:55 -04:00
										 |  |  | 	if(ds + sizeof(cell) < ds_bot || ds + stack_reserved >= ds_top) reset_datastack(); | 
					
						
							|  |  |  | 	if(rs + sizeof(cell) < rs_bot || rs + stack_reserved >= rs_top) reset_retainstack(); | 
					
						
							| 
									
										
										
										
											2009-05-04 02:00:30 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* called before entry into foreign C code. Note that ds and rs might
 | 
					
						
							|  |  |  | be stored in registers, so callbacks must save and restore the correct values */ | 
					
						
							| 
									
										
										
										
											2009-05-05 12:33:35 -04:00
										 |  |  | void save_stacks() | 
					
						
							| 
									
										
										
										
											2009-05-04 02:00:30 -04:00
										 |  |  | { | 
					
						
							|  |  |  | 	if(stack_chain) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		stack_chain->datastack = ds; | 
					
						
							|  |  |  | 		stack_chain->retainstack = rs; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-05-05 12:33:35 -04:00
										 |  |  | context *alloc_context() | 
					
						
							| 
									
										
										
										
											2009-05-04 02:00:30 -04:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2009-05-04 05:50:24 -04:00
										 |  |  | 	context *new_context; | 
					
						
							| 
									
										
										
										
											2009-05-04 02:00:30 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if(unused_contexts) | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2009-05-04 05:50:24 -04:00
										 |  |  | 		new_context = unused_contexts; | 
					
						
							| 
									
										
										
										
											2009-05-04 02:00:30 -04:00
										 |  |  | 		unused_contexts = unused_contexts->next; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2009-05-04 05:50:24 -04:00
										 |  |  | 		new_context = (context *)safe_malloc(sizeof(context)); | 
					
						
							|  |  |  | 		new_context->datastack_region = alloc_segment(ds_size); | 
					
						
							|  |  |  | 		new_context->retainstack_region = alloc_segment(rs_size); | 
					
						
							| 
									
										
										
										
											2009-05-04 02:00:30 -04:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-05-04 05:50:24 -04:00
										 |  |  | 	return new_context; | 
					
						
							| 
									
										
										
										
											2009-05-04 02:00:30 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-05-04 05:50:24 -04:00
										 |  |  | void dealloc_context(context *old_context) | 
					
						
							| 
									
										
										
										
											2009-05-04 02:00:30 -04:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2009-05-04 05:50:24 -04:00
										 |  |  | 	old_context->next = unused_contexts; | 
					
						
							|  |  |  | 	unused_contexts = old_context; | 
					
						
							| 
									
										
										
										
											2009-05-04 02:00:30 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* called on entry into a compiled callback */ | 
					
						
							| 
									
										
										
										
											2009-05-05 12:33:35 -04:00
										 |  |  | void nest_stacks() | 
					
						
							| 
									
										
										
										
											2009-05-04 02:00:30 -04:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2009-05-04 05:50:24 -04:00
										 |  |  | 	context *new_context = alloc_context(); | 
					
						
							| 
									
										
										
										
											2009-05-04 02:00:30 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-05-04 05:50:24 -04:00
										 |  |  | 	new_context->callstack_bottom = (stack_frame *)-1; | 
					
						
							|  |  |  | 	new_context->callstack_top = (stack_frame *)-1; | 
					
						
							| 
									
										
										
										
											2009-05-04 02:00:30 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* note that these register values are not necessarily valid stack
 | 
					
						
							|  |  |  | 	pointers. they are merely saved non-volatile registers, and are | 
					
						
							|  |  |  | 	restored in unnest_stacks(). consider this scenario: | 
					
						
							|  |  |  | 	- factor code calls C function | 
					
						
							|  |  |  | 	- C function saves ds/cs registers (since they're non-volatile) | 
					
						
							|  |  |  | 	- C function clobbers them | 
					
						
							|  |  |  | 	- C function calls Factor callback | 
					
						
							|  |  |  | 	- Factor callback returns | 
					
						
							|  |  |  | 	- C function restores registers | 
					
						
							|  |  |  | 	- C function returns to Factor code */ | 
					
						
							| 
									
										
										
										
											2009-05-04 05:50:24 -04:00
										 |  |  | 	new_context->datastack_save = ds; | 
					
						
							|  |  |  | 	new_context->retainstack_save = rs; | 
					
						
							| 
									
										
										
										
											2009-05-04 02:00:30 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* save per-callback userenv */ | 
					
						
							| 
									
										
										
										
											2009-05-04 05:50:24 -04:00
										 |  |  | 	new_context->current_callback_save = userenv[CURRENT_CALLBACK_ENV]; | 
					
						
							|  |  |  | 	new_context->catchstack_save = userenv[CATCHSTACK_ENV]; | 
					
						
							| 
									
										
										
										
											2009-05-04 02:00:30 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-05-04 05:50:24 -04:00
										 |  |  | 	new_context->next = stack_chain; | 
					
						
							|  |  |  | 	stack_chain = new_context; | 
					
						
							| 
									
										
										
										
											2009-05-04 02:00:30 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	reset_datastack(); | 
					
						
							|  |  |  | 	reset_retainstack(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* called when leaving a compiled callback */ | 
					
						
							| 
									
										
										
										
											2009-05-05 12:33:35 -04:00
										 |  |  | void unnest_stacks() | 
					
						
							| 
									
										
										
										
											2009-05-04 02:00:30 -04:00
										 |  |  | { | 
					
						
							|  |  |  | 	ds = stack_chain->datastack_save; | 
					
						
							|  |  |  | 	rs = stack_chain->retainstack_save; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* restore per-callback userenv */ | 
					
						
							|  |  |  | 	userenv[CURRENT_CALLBACK_ENV] = stack_chain->current_callback_save; | 
					
						
							|  |  |  | 	userenv[CATCHSTACK_ENV] = stack_chain->catchstack_save; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-05-04 05:50:24 -04:00
										 |  |  | 	context *old_stacks = stack_chain; | 
					
						
							| 
									
										
										
										
											2009-05-04 02:00:30 -04:00
										 |  |  | 	stack_chain = old_stacks->next; | 
					
						
							|  |  |  | 	dealloc_context(old_stacks); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* called on startup */ | 
					
						
							| 
									
										
										
										
											2009-05-04 05:50:24 -04:00
										 |  |  | void init_stacks(cell ds_size_, cell rs_size_) | 
					
						
							| 
									
										
										
										
											2009-05-04 02:00:30 -04:00
										 |  |  | { | 
					
						
							|  |  |  | 	ds_size = ds_size_; | 
					
						
							|  |  |  | 	rs_size = rs_size_; | 
					
						
							|  |  |  | 	stack_chain = NULL; | 
					
						
							|  |  |  | 	unused_contexts = NULL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-05-04 05:50:24 -04:00
										 |  |  | bool stack_to_array(cell bottom, cell top) | 
					
						
							| 
									
										
										
										
											2009-05-04 02:00:30 -04:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2009-05-04 05:50:24 -04:00
										 |  |  | 	fixnum depth = (fixnum)(top - bottom + sizeof(cell)); | 
					
						
							| 
									
										
										
										
											2009-05-04 02:00:30 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if(depth < 0) | 
					
						
							|  |  |  | 		return false; | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2009-05-04 05:50:24 -04:00
										 |  |  | 		array *a = allot_array_internal<array>(depth / sizeof(cell)); | 
					
						
							| 
									
										
										
										
											2009-05-04 02:00:30 -04:00
										 |  |  | 		memcpy(a + 1,(void*)bottom,depth); | 
					
						
							| 
									
										
										
										
											2009-05-04 05:50:24 -04:00
										 |  |  | 		dpush(tag<array>(a)); | 
					
						
							| 
									
										
										
										
											2009-05-04 02:00:30 -04:00
										 |  |  | 		return true; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | PRIMITIVE(datastack) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if(!stack_to_array(ds_bot,ds)) | 
					
						
							|  |  |  | 		general_error(ERROR_DS_UNDERFLOW,F,F,NULL); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | PRIMITIVE(retainstack) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if(!stack_to_array(rs_bot,rs)) | 
					
						
							|  |  |  | 		general_error(ERROR_RS_UNDERFLOW,F,F,NULL); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* returns pointer to top of stack */ | 
					
						
							| 
									
										
										
										
											2009-05-04 05:50:24 -04:00
										 |  |  | cell array_to_stack(array *array, cell bottom) | 
					
						
							| 
									
										
										
										
											2009-05-04 02:00:30 -04:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2009-05-04 05:50:24 -04:00
										 |  |  | 	cell depth = array_capacity(array) * sizeof(cell); | 
					
						
							| 
									
										
										
										
											2009-05-04 02:00:30 -04:00
										 |  |  | 	memcpy((void*)bottom,array + 1,depth); | 
					
						
							| 
									
										
										
										
											2009-05-04 05:50:24 -04:00
										 |  |  | 	return bottom + depth - sizeof(cell); | 
					
						
							| 
									
										
										
										
											2009-05-04 02:00:30 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | PRIMITIVE(set_datastack) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2009-05-04 05:50:24 -04:00
										 |  |  | 	ds = array_to_stack(untag_check<array>(dpop()),ds_bot); | 
					
						
							| 
									
										
										
										
											2009-05-04 02:00:30 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | PRIMITIVE(set_retainstack) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2009-05-04 05:50:24 -04:00
										 |  |  | 	rs = array_to_stack(untag_check<array>(dpop()),rs_bot); | 
					
						
							| 
									
										
										
										
											2009-05-04 02:00:30 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Used to implement call( */ | 
					
						
							|  |  |  | PRIMITIVE(check_datastack) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2009-05-04 05:50:24 -04:00
										 |  |  | 	fixnum out = to_fixnum(dpop()); | 
					
						
							|  |  |  | 	fixnum in = to_fixnum(dpop()); | 
					
						
							|  |  |  | 	fixnum height = out - in; | 
					
						
							|  |  |  | 	array *saved_datastack = untag_check<array>(dpop()); | 
					
						
							|  |  |  | 	fixnum saved_height = array_capacity(saved_datastack); | 
					
						
							|  |  |  | 	fixnum current_height = (ds - ds_bot + sizeof(cell)) / sizeof(cell); | 
					
						
							|  |  |  | 	if(current_height - height != saved_height) | 
					
						
							| 
									
										
										
										
											2009-05-04 02:00:30 -04:00
										 |  |  | 		dpush(F); | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2009-05-04 05:50:24 -04:00
										 |  |  | 		fixnum i; | 
					
						
							|  |  |  | 		for(i = 0; i < saved_height - in; i++) | 
					
						
							| 
									
										
										
										
											2009-05-04 02:00:30 -04:00
										 |  |  | 		{ | 
					
						
							| 
									
										
										
										
											2009-05-04 05:50:24 -04:00
										 |  |  | 			if(((cell *)ds_bot)[i] != array_nth(saved_datastack,i)) | 
					
						
							| 
									
										
										
										
											2009-05-04 02:00:30 -04:00
										 |  |  | 			{ | 
					
						
							|  |  |  | 				dpush(F); | 
					
						
							|  |  |  | 				return; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		dpush(T); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2009-05-04 02:46:13 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | } |