]> gitweb.factorcode.org Git - factor.git/blob - vm/cpu-x86.cpp
VM: simplifies the dispatch_resumable_signal() method
[factor.git] / vm / cpu-x86.cpp
1 #include "master.hpp"
2
3 namespace factor {
4
5 void factor_vm::dispatch_non_resumable_signal(cell* sp, cell* pc,
6                                               cell handler,
7                                               cell limit) {
8
9   /* Fault came from the VM or foreign code. We don't try to fix the
10      call stack from *sp and instead use the last saved "good value"
11      which we get from ctx->callstack_top. Then launch the handler
12      without going through the resumable subprimitive. */
13   signal_resumable = false;
14
15   cell frame_top = ctx->callstack_top;
16   cell seg_start = ctx->callstack_seg->start;
17
18   if (frame_top < seg_start) {
19     /* The saved callstack pointer is outside the callstack
20        segment. That means that we need to carefully cut off one frame
21        first which hopefully should put the pointer within the
22        callstack's bounds. */
23     code_block *block = code->code_block_for_address(*pc);
24     cell frame_size = block->stack_frame_size_for_address(*pc);
25     frame_top += frame_size;
26   }
27
28   /* Cut the callstack down to the shallowest Factor stack
29      frame that leaves room for the signal handler to do its thing,
30      and launch the handler without going through the resumable
31      subprimitive. */
32   FACTOR_ASSERT(seg_start <= frame_top);
33   while (frame_top < ctx->callstack_bottom && frame_top < limit) {
34     frame_top = code->frame_predecessor(frame_top);
35   }
36   ctx->callstack_top = frame_top;
37   *sp = frame_top;
38   *pc = handler;
39 }
40
41 void factor_vm::dispatch_resumable_signal(cell* sp, cell* pc, cell handler) {
42
43   signal_resumable = true;
44
45   /* Fault came from Factor, and we've got a good callstack. Route the
46      signal handler through the resumable signal handler
47      subprimitive. */
48
49   cell offset = *sp % 16;
50
51   signal_handler_addr = handler;
52
53   /* True stack frames are always 16-byte aligned. Leaf procedures
54      that don't create a stack frame will be out of alignment by
55      sizeof(cell) bytes. */
56   /* On architectures with a link register we would have to check for
57      leafness by matching the PC to a word. We should also use
58      FRAME_RETURN_ADDRESS instead of assuming the stack pointer is the
59      right place to put the resume address. */
60   cell index = 0;
61   cell delta = 0;
62   if (offset == 0) {
63     delta = sizeof(cell);
64     index = SIGNAL_HANDLER_WORD;
65   } else if (offset == 16 - sizeof(cell)) {
66     /* Make a fake frame for the leaf procedure */
67     FACTOR_ASSERT(code->code_block_for_address(*pc) != NULL);
68     delta = LEAF_FRAME_SIZE;
69     index = LEAF_SIGNAL_HANDLER_WORD;
70   } else {
71     FACTOR_ASSERT(false);
72   }
73   cell new_sp = *sp - delta;
74   *sp = new_sp;
75   *(cell*)new_sp = *pc;
76   tagged<word> handler_word = tagged<word>(special_objects[index]);
77   *pc = (cell)handler_word->entry_point;
78 }
79
80 void factor_vm::dispatch_signal_handler(cell* sp, cell* pc, cell handler) {
81
82   bool in_code_seg = code->seg->in_segment_p(*pc);
83   cell cs_limit = ctx->callstack_seg->start + stack_reserved;
84   bool resumable_p = in_code_seg && *sp >= cs_limit;
85   if (resumable_p) {
86     dispatch_resumable_signal(sp, pc, handler);
87   } else {
88     dispatch_non_resumable_signal(sp, pc, handler, cs_limit);
89   }
90
91   /* Poking with the stack pointer, which the above code does, means
92      that pointers to stack-allocated objects will become
93      corrupted. Therefore the root vectors needs to be cleared because
94      their pointers to stack variables are now garbage. */
95   data_roots.clear();
96   code_roots.clear();
97 }
98
99 }