factor/vm/cpu-x86.cpp

97 lines
3.3 KiB
C++
Raw Normal View History

#include "master.hpp"
2013-05-11 21:55:50 -04:00
namespace factor {
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.
cell frame_top = ctx->callstack_top;
cell seg_start = ctx->callstack_seg->start;
if (frame_top < seg_start) {
// 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.
FACTOR_ASSERT(seg_start <= frame_top);
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) {
// 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.
cell index = 0;
cell delta = 0;
if (offset == 0) {
delta = sizeof(cell);
index = SIGNAL_HANDLER_WORD;
} else if (offset == 16 - sizeof(cell)) {
// Make a fake frame for the leaf procedure
FACTOR_ASSERT(code->code_block_for_address(*pc) != NULL);
delta = LEAF_FRAME_SIZE;
index = LEAF_SIGNAL_HANDLER_WORD;
} else {
FACTOR_ASSERT(false);
}
cell new_sp = *sp - delta;
*sp = new_sp;
*(cell*)new_sp = *pc;
*pc = untag<word>(special_objects[index])->entry_point;
}
2013-05-11 21:55:50 -04:00
void factor_vm::dispatch_signal_handler(cell* sp, cell* pc, cell handler) {
bool in_code_seg = code->seg->in_segment_p(*pc);
cell cs_limit = ctx->callstack_seg->start + stack_reserved;
2015-08-26 14:15:42 -04:00
signal_resumable = in_code_seg && *sp >= cs_limit;
if (signal_resumable) {
dispatch_resumable_signal(sp, pc, handler);
2013-05-11 21:55:50 -04:00
} else {
dispatch_non_resumable_signal(sp, pc, handler, cs_limit);
2013-05-11 21:55:50 -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();
}
}