vm: resumably handle signals from leaf procedures
parent
1386212d23
commit
402e1155a5
|
@ -29,6 +29,7 @@ CONSTANT: deck-bits 18
|
||||||
: callstack-top-offset ( -- n ) 2 \ callstack type-number slot-offset ; inline
|
: callstack-top-offset ( -- n ) 2 \ callstack type-number slot-offset ; inline
|
||||||
: vm-context-offset ( -- n ) 0 bootstrap-cells ; inline
|
: vm-context-offset ( -- n ) 0 bootstrap-cells ; inline
|
||||||
: vm-spare-context-offset ( -- n ) 1 bootstrap-cells ; inline
|
: vm-spare-context-offset ( -- n ) 1 bootstrap-cells ; inline
|
||||||
|
: vm-signal-handler-addr-offset ( -- n ) 8 bootstrap-cells ; inline
|
||||||
: context-callstack-top-offset ( -- n ) 0 bootstrap-cells ; inline
|
: context-callstack-top-offset ( -- n ) 0 bootstrap-cells ; inline
|
||||||
: context-callstack-bottom-offset ( -- n ) 1 bootstrap-cells ; inline
|
: context-callstack-bottom-offset ( -- n ) 1 bootstrap-cells ; inline
|
||||||
: context-datastack-offset ( -- n ) 2 bootstrap-cells ; inline
|
: context-datastack-offset ( -- n ) 2 bootstrap-cells ; inline
|
||||||
|
|
|
@ -93,58 +93,47 @@ IN: bootstrap.x86
|
||||||
|
|
||||||
USE: locals
|
USE: locals
|
||||||
|
|
||||||
: jit-save-volatile-regs ( -- )
|
:: jit-save-volatile-regs ( -- save-size )
|
||||||
! do we also need to save XMM?
|
! do we also need to save XMM?
|
||||||
RSP volatile-regs length bootstrap-cell * SUB
|
volatile-regs length bootstrap-cell * 16 align :> save-size
|
||||||
|
RSP 2 bootstrap-cells [+] save-size ADD ! bump up stack frame size
|
||||||
|
RSP save-size SUB
|
||||||
volatile-regs
|
volatile-regs
|
||||||
[| r i | RSP i bootstrap-cell * [+] r MOV ] each-index ;
|
[| r i | RSP i bootstrap-cell * [+] r MOV ] each-index
|
||||||
|
save-size ;
|
||||||
|
|
||||||
:: jit-restore-volatile-regs ( additional-pop -- )
|
:: jit-restore-volatile-regs ( save-size -- )
|
||||||
volatile-regs
|
volatile-regs
|
||||||
[| r i | r RSP i bootstrap-cell * [+] MOV ] each-index
|
[| r i | r RSP i bootstrap-cell * [+] MOV ] each-index
|
||||||
RSP volatile-regs length bootstrap-cell * additional-pop + ADD ;
|
RSP save-size ADD ;
|
||||||
|
|
||||||
[
|
[| |
|
||||||
! Stack at this point has the signal handler pointer followed by
|
jit-save-volatile-regs :> save-size
|
||||||
! the return address back into normal execution, then the 24 bytes
|
|
||||||
! of stack frame + alignment inserted by the prolog.
|
|
||||||
! After registers are saved, the stack looks like:
|
|
||||||
! RSP saved volatile regs (`volatile-regs length` cells)
|
|
||||||
! + subprimitive stack frame alignment (3 cells)
|
|
||||||
! . signal handler address (1 cell)
|
|
||||||
! . resume address (1 cell)
|
|
||||||
jit-save-volatile-regs
|
|
||||||
jit-save-context
|
jit-save-context
|
||||||
RAX RSP volatile-regs length 3 + bootstrap-cell * [+] MOV
|
RAX vm-reg vm-signal-handler-addr-offset [+] MOV
|
||||||
RAX CALL
|
RAX CALL
|
||||||
bootstrap-cell jit-restore-volatile-regs
|
save-size jit-restore-volatile-regs
|
||||||
] \ signal-handler define-sub-primitive
|
] \ signal-handler define-sub-primitive
|
||||||
|
|
||||||
! :: jit-push-leaf-stack-frame ( -- )
|
[| |
|
||||||
! ;
|
jit-save-volatile-regs :> save-size
|
||||||
!
|
jit-save-context
|
||||||
! :: jit-pop-leaf-stack-frame ( -- )
|
RAX vm-reg vm-signal-handler-addr-offset [+] MOV
|
||||||
! ;
|
RAX CALL
|
||||||
!
|
! Stack at this point has a fake stack frame set up to represent the
|
||||||
! [
|
! leaf procedure we interrupted. We must tear down that frame in
|
||||||
! ! Stack at this point has the signal handler pointer followed by
|
! addition to our own before resuming.
|
||||||
! ! the word pointer and the return address back into normal execution,
|
! Grab our resume address and place it just underneath the leaf proc's
|
||||||
! ! then the 24 bytes of stack frame + alignment inserted by the prolog
|
! return address, since we can't touch any registers once they've been
|
||||||
! ! After registers are saved and the leaf stack frame is constructed,
|
! restored. If we got this far there should be no faults here and we
|
||||||
! ! the stack looks like:
|
! can get away with corrupting the stack frame.
|
||||||
! ! RSP fake leaf stack frame (4 cells)
|
RAX RSP save-size 3 bootstrap-cells + [+] MOV
|
||||||
! ! + saved volatile regs (`volatile-regs length` cells)
|
RSP save-size 6 bootstrap-cells + [+] RAX MOV
|
||||||
! ! . subprimitive stack frame alignment (3 cells)
|
|
||||||
! ! . leaf word (1 cell)
|
! Popping 3 extra cells here plus the 3 cells the epilogue pops leaves
|
||||||
! ! . signal handler address (1 cell)
|
! the resume address at the top of the stack for when the epilogue RETs.
|
||||||
! ! resume address (1 cell)
|
save-size 3 bootstrap-cells + jit-restore-volatile-regs
|
||||||
! jit-save-volatile-regs
|
] \ leaf-signal-handler define-sub-primitive
|
||||||
! jit-push-leaf-stack-frame
|
|
||||||
! jit-save-context
|
|
||||||
! "memory_signal_handler_impl" jit-call
|
|
||||||
! jit-pop-leaf-stack-frame
|
|
||||||
! bootstrap-cell jit-restore-volatile-regs
|
|
||||||
! ] \ leaf-signal-handler define-sub-primitive
|
|
||||||
|
|
||||||
[
|
[
|
||||||
arg1 ds-reg [] MOV
|
arg1 ds-reg [] MOV
|
||||||
|
|
|
@ -30,6 +30,7 @@ STRUCT: vm
|
||||||
{ nursery zone }
|
{ nursery zone }
|
||||||
{ cards-offset cell }
|
{ cards-offset cell }
|
||||||
{ decks-offset cell }
|
{ decks-offset cell }
|
||||||
|
{ signal-handler-addr cell }
|
||||||
{ special-objects cell[80] } ;
|
{ special-objects cell[80] } ;
|
||||||
|
|
||||||
: vm-field-offset ( field -- offset ) vm offset-of ; inline
|
: vm-field-offset ( field -- offset ) vm offset-of ; inline
|
||||||
|
|
|
@ -18,23 +18,70 @@ callstack *factor_vm::allot_callstack(cell size)
|
||||||
return stack;
|
return stack;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct word_finder {
|
||||||
|
cell address;
|
||||||
|
cell found_word;
|
||||||
|
|
||||||
|
word_finder(cell address) : address(address), found_word(0) {}
|
||||||
|
|
||||||
|
// XXX keep a map of word names in the code heap so we don't need this
|
||||||
|
void operator()(object *obj)
|
||||||
|
{
|
||||||
|
if (obj->type() == WORD_TYPE)
|
||||||
|
{
|
||||||
|
word *w = static_cast<word*>(obj);
|
||||||
|
if ((cell)w->code->entry_point() <= address
|
||||||
|
&& address - (cell)w->code->entry_point() < w->code->size()) {
|
||||||
|
assert(found_word == 0);
|
||||||
|
found_word = (cell)w->code->entry_point();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static cell find_word_for_address(factor_vm *vm, cell pc)
|
||||||
|
{
|
||||||
|
word_finder finder(pc);
|
||||||
|
vm->each_object(finder);
|
||||||
|
assert(finder.found_word != 0);
|
||||||
|
return finder.found_word;
|
||||||
|
}
|
||||||
|
|
||||||
void factor_vm::dispatch_signal_handler(cell *sp, cell *pc, cell handler)
|
void factor_vm::dispatch_signal_handler(cell *sp, cell *pc, cell handler)
|
||||||
{
|
{
|
||||||
/* True stack frames are always 16-byte aligned. Leaf procedures
|
/* 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)
|
that don't create a stack frame will be out of alignment by sizeof(cell)
|
||||||
bytes. */
|
bytes. */
|
||||||
/* XXX horribly x86-centric */
|
/* XXX horribly x86-centric */
|
||||||
|
/* XXX check if exception came from C code */
|
||||||
|
/* XXX handle callstack overflow */
|
||||||
|
|
||||||
cell offset = *sp % 16;
|
cell offset = *sp % 16;
|
||||||
|
|
||||||
|
signal_handler_addr = handler;
|
||||||
tagged<word> handler_word = tagged<word>(special_objects[SIGNAL_HANDLER_WORD]);
|
tagged<word> handler_word = tagged<word>(special_objects[SIGNAL_HANDLER_WORD]);
|
||||||
if (offset == 0)
|
if (offset == 0)
|
||||||
{
|
{
|
||||||
|
// should use FRAME_RETURN_ADDRESS here to be platform-agnostic
|
||||||
signal_from_leaf = false;
|
signal_from_leaf = false;
|
||||||
|
cell newsp = *sp - sizeof(cell);
|
||||||
|
*sp = newsp;
|
||||||
|
*(cell*)newsp = *pc;
|
||||||
}
|
}
|
||||||
|
// should check the PC since leaf procs on RISC architectures won't touch the
|
||||||
|
// stack at all
|
||||||
else if (offset == 16 - sizeof(cell))
|
else if (offset == 16 - sizeof(cell))
|
||||||
{
|
{
|
||||||
signal_from_leaf = true;
|
signal_from_leaf = true;
|
||||||
|
|
||||||
|
// Make a fake frame for the leaf procedure
|
||||||
|
cell leaf_word = find_word_for_address(this, *pc);
|
||||||
|
|
||||||
|
cell newsp = *sp + 4 * sizeof(cell); // XXX platform-appropriate stack size
|
||||||
|
*(cell*)(newsp + 3*sizeof(cell)) = 4*sizeof(cell);
|
||||||
|
*(cell*)(newsp + 2*sizeof(cell)) = leaf_word;
|
||||||
|
*(cell*) newsp = *pc;
|
||||||
|
*sp = newsp;
|
||||||
handler_word = tagged<word>(special_objects[LEAF_SIGNAL_HANDLER_WORD]);
|
handler_word = tagged<word>(special_objects[LEAF_SIGNAL_HANDLER_WORD]);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -42,12 +89,6 @@ void factor_vm::dispatch_signal_handler(cell *sp, cell *pc, cell handler)
|
||||||
fatal_error("Invalid stack frame during signal handler", *sp);
|
fatal_error("Invalid stack frame during signal handler", *sp);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Push the original PC as a return address and the C handler function
|
|
||||||
* pointer as an argument to the signal handler stub. */
|
|
||||||
cell newsp = *sp - 2*sizeof(cell);
|
|
||||||
*sp = newsp;
|
|
||||||
*(cell*)(newsp + sizeof(cell)) = *pc;
|
|
||||||
*(cell*)newsp = handler;
|
|
||||||
*pc = (cell)handler_word->code->entry_point();
|
*pc = (cell)handler_word->code->entry_point();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
13
vm/vm.hpp
13
vm/vm.hpp
|
@ -6,7 +6,11 @@ struct code_root;
|
||||||
|
|
||||||
struct factor_vm
|
struct factor_vm
|
||||||
{
|
{
|
||||||
// First 5 fields accessed directly by compiler. See basis/vm/vm.factor
|
//
|
||||||
|
// vvvvvv
|
||||||
|
// THESE FIELDS ARE ACCESSED DIRECTLY FROM FACTOR. See:
|
||||||
|
// basis/vm/vm.factor
|
||||||
|
// basis/compiler/constants/constants.factor
|
||||||
|
|
||||||
/* Current context */
|
/* Current context */
|
||||||
context *ctx;
|
context *ctx;
|
||||||
|
@ -21,10 +25,17 @@ struct factor_vm
|
||||||
cell cards_offset;
|
cell cards_offset;
|
||||||
cell decks_offset;
|
cell decks_offset;
|
||||||
|
|
||||||
|
/* cdecl signal handler address, used by signal handler subprimitives */
|
||||||
|
cell signal_handler_addr;
|
||||||
|
|
||||||
/* Various special objects, accessed by special-object and
|
/* Various special objects, accessed by special-object and
|
||||||
set-special-object primitives */
|
set-special-object primitives */
|
||||||
cell special_objects[special_object_count];
|
cell special_objects[special_object_count];
|
||||||
|
|
||||||
|
// THESE FIELDS ARE ACCESSED DIRECTLY FROM FACTOR.
|
||||||
|
// ^^^^^^
|
||||||
|
//
|
||||||
|
|
||||||
/* Data stack and retain stack sizes */
|
/* Data stack and retain stack sizes */
|
||||||
cell datastack_size, retainstack_size, callstack_size;
|
cell datastack_size, retainstack_size, callstack_size;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue