| 
									
										
										
										
											2011-10-26 19:22:42 -04:00
										 |  |  | #include "master.hpp"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-11 21:55:50 -04:00
										 |  |  | namespace factor { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-12 22:59:14 -04:00
										 |  |  | void factor_vm::dispatch_non_resumable_signal(cell* sp, cell* pc, | 
					
						
							|  |  |  |                                               cell handler, | 
					
						
							|  |  |  |                                               cell limit) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* Fault came from the VM or foreign code. We don't try to fix the
 | 
					
						
							|  |  |  |      call stack from *sp and instead use the last saved "good value" | 
					
						
							|  |  |  |      which we get from ctx->callstack_top. Then launch the handler | 
					
						
							|  |  |  |      without going through the resumable subprimitive. */ | 
					
						
							|  |  |  |   signal_resumable = false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   cell frame_top = ctx->callstack_top; | 
					
						
							| 
									
										
										
										
											2015-08-14 18:08:42 -04:00
										 |  |  |   cell seg_start = ctx->callstack_seg->start; | 
					
						
							| 
									
										
										
										
											2015-08-12 22:59:14 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-14 18:08:42 -04:00
										 |  |  |   if (frame_top < seg_start) { | 
					
						
							| 
									
										
										
										
											2015-08-12 22:59:14 -04:00
										 |  |  |     /* The saved callstack pointer is outside the callstack
 | 
					
						
							|  |  |  |        segment. That means that we need to carefully cut off one frame | 
					
						
							|  |  |  |        first which hopefully should put the pointer within the | 
					
						
							|  |  |  |        callstack's bounds. */ | 
					
						
							|  |  |  |     code_block *block = code->code_block_for_address(*pc); | 
					
						
							|  |  |  |     cell frame_size = block->stack_frame_size_for_address(*pc); | 
					
						
							|  |  |  |     frame_top += frame_size; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* Cut the callstack down to the shallowest Factor stack
 | 
					
						
							|  |  |  |      frame that leaves room for the signal handler to do its thing, | 
					
						
							|  |  |  |      and launch the handler without going through the resumable | 
					
						
							|  |  |  |      subprimitive. */ | 
					
						
							| 
									
										
										
										
											2015-08-14 18:08:42 -04:00
										 |  |  |   FACTOR_ASSERT(seg_start <= frame_top); | 
					
						
							| 
									
										
										
										
											2015-08-12 22:59:14 -04:00
										 |  |  |   while (frame_top < ctx->callstack_bottom && frame_top < limit) { | 
					
						
							|  |  |  |     frame_top = code->frame_predecessor(frame_top); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   ctx->callstack_top = frame_top; | 
					
						
							|  |  |  |   *sp = frame_top; | 
					
						
							|  |  |  |   *pc = handler; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void factor_vm::dispatch_resumable_signal(cell* sp, cell* pc, cell handler) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   signal_resumable = true; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* Fault came from Factor, and we've got a good callstack. Route the
 | 
					
						
							|  |  |  |      signal handler through the resumable signal handler | 
					
						
							|  |  |  |      subprimitive. */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   cell offset = *sp % 16; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   signal_handler_addr = handler; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* True stack frames are always 16-byte aligned. Leaf procedures
 | 
					
						
							|  |  |  |      that don't create a stack frame will be out of alignment by | 
					
						
							|  |  |  |      sizeof(cell) bytes. */ | 
					
						
							|  |  |  |   /* On architectures with a link register we would have to check for
 | 
					
						
							|  |  |  |      leafness by matching the PC to a word. We should also use | 
					
						
							|  |  |  |      FRAME_RETURN_ADDRESS instead of assuming the stack pointer is the | 
					
						
							|  |  |  |      right place to put the resume address. */ | 
					
						
							| 
									
										
										
										
											2015-08-14 18:08:42 -04:00
										 |  |  |   cell index = 0; | 
					
						
							|  |  |  |   cell delta = 0; | 
					
						
							| 
									
										
										
										
											2015-08-12 22:59:14 -04:00
										 |  |  |   if (offset == 0) { | 
					
						
							| 
									
										
										
										
											2015-08-14 18:08:42 -04:00
										 |  |  |     delta = sizeof(cell); | 
					
						
							|  |  |  |     index = SIGNAL_HANDLER_WORD; | 
					
						
							| 
									
										
										
										
											2015-08-12 22:59:14 -04:00
										 |  |  |   } else if (offset == 16 - sizeof(cell)) { | 
					
						
							|  |  |  |     /* Make a fake frame for the leaf procedure */ | 
					
						
							|  |  |  |     FACTOR_ASSERT(code->code_block_for_address(*pc) != NULL); | 
					
						
							| 
									
										
										
										
											2015-08-14 18:08:42 -04:00
										 |  |  |     delta = LEAF_FRAME_SIZE; | 
					
						
							|  |  |  |     index = LEAF_SIGNAL_HANDLER_WORD; | 
					
						
							| 
									
										
										
										
											2015-08-12 22:59:14 -04:00
										 |  |  |   } else { | 
					
						
							|  |  |  |     FACTOR_ASSERT(false); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2015-08-14 18:08:42 -04:00
										 |  |  |   cell new_sp = *sp - delta; | 
					
						
							|  |  |  |   *sp = new_sp; | 
					
						
							|  |  |  |   *(cell*)new_sp = *pc; | 
					
						
							|  |  |  |   tagged<word> handler_word = tagged<word>(special_objects[index]); | 
					
						
							| 
									
										
										
										
											2015-08-12 22:59:14 -04:00
										 |  |  |   *pc = (cell)handler_word->entry_point; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-11 21:55:50 -04:00
										 |  |  | void factor_vm::dispatch_signal_handler(cell* sp, cell* pc, cell handler) { | 
					
						
							| 
									
										
										
										
											2015-08-04 08:27:14 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-12 22:59:14 -04:00
										 |  |  |   bool in_code_seg = code->seg->in_segment_p(*pc); | 
					
						
							|  |  |  |   cell cs_limit = ctx->callstack_seg->start + stack_reserved; | 
					
						
							|  |  |  |   bool resumable_p = in_code_seg && *sp >= cs_limit; | 
					
						
							|  |  |  |   if (resumable_p) { | 
					
						
							|  |  |  |     dispatch_resumable_signal(sp, pc, handler); | 
					
						
							| 
									
										
										
										
											2013-05-11 21:55:50 -04:00
										 |  |  |   } else { | 
					
						
							| 
									
										
										
										
											2015-08-12 22:59:14 -04:00
										 |  |  |     dispatch_non_resumable_signal(sp, pc, handler, cs_limit); | 
					
						
							| 
									
										
										
										
											2013-05-11 21:55:50 -04:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2014-07-23 05:07:49 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |   /* Poking with the stack pointer, which the above code does, means
 | 
					
						
							|  |  |  |      that pointers to stack-allocated objects will become | 
					
						
							|  |  |  |      corrupted. Therefore the root vectors needs to be cleared because | 
					
						
							|  |  |  |      their pointers to stack variables are now garbage. */ | 
					
						
							|  |  |  |   data_roots.clear(); | 
					
						
							|  |  |  |   code_roots.clear(); | 
					
						
							| 
									
										
										
										
											2011-10-26 19:22:42 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } |