vm: dispatch signal handlers through subprimitive

We also need to save C ABI volatile registers before calling the signal handler in order to be able to reliably resume. Add signal-handler and leaf-signal-handler subprimitives to preserve volatile registers before invoking the signal handler C function.
db4
Joe Groff 2011-10-24 14:26:58 -07:00
parent dca0fd3487
commit 1386212d23
14 changed files with 142 additions and 71 deletions

View File

@ -92,7 +92,7 @@ CONSTANT: image-version 4
CONSTANT: data-base 1024 CONSTANT: data-base 1024
CONSTANT: special-objects-size 70 CONSTANT: special-objects-size 80
CONSTANT: header-size 10 CONSTANT: header-size 10
@ -184,26 +184,28 @@ SPECIAL-OBJECT: lazy-jit-compile-word 43
SPECIAL-OBJECT: unwind-native-frames-word 44 SPECIAL-OBJECT: unwind-native-frames-word 44
SPECIAL-OBJECT: fpu-state-word 45 SPECIAL-OBJECT: fpu-state-word 45
SPECIAL-OBJECT: set-fpu-state-word 46 SPECIAL-OBJECT: set-fpu-state-word 46
SPECIAL-OBJECT: signal-handler-word 47
SPECIAL-OBJECT: leaf-signal-handler-word 48
SPECIAL-OBJECT: callback-stub 48 SPECIAL-OBJECT: callback-stub 50
! PIC stubs ! PIC stubs
SPECIAL-OBJECT: pic-load 49 SPECIAL-OBJECT: pic-load 51
SPECIAL-OBJECT: pic-tag 50 SPECIAL-OBJECT: pic-tag 52
SPECIAL-OBJECT: pic-tuple 51 SPECIAL-OBJECT: pic-tuple 53
SPECIAL-OBJECT: pic-check-tag 52 SPECIAL-OBJECT: pic-check-tag 54
SPECIAL-OBJECT: pic-check-tuple 53 SPECIAL-OBJECT: pic-check-tuple 55
SPECIAL-OBJECT: pic-hit 54 SPECIAL-OBJECT: pic-hit 56
SPECIAL-OBJECT: pic-miss-word 55 SPECIAL-OBJECT: pic-miss-word 57
SPECIAL-OBJECT: pic-miss-tail-word 56 SPECIAL-OBJECT: pic-miss-tail-word 58
! Megamorphic dispatch ! Megamorphic dispatch
SPECIAL-OBJECT: mega-lookup 57 SPECIAL-OBJECT: mega-lookup 59
SPECIAL-OBJECT: mega-lookup-word 58 SPECIAL-OBJECT: mega-lookup-word 60
SPECIAL-OBJECT: mega-miss-word 59 SPECIAL-OBJECT: mega-miss-word 61
! Default definition for undefined words ! Default definition for undefined words
SPECIAL-OBJECT: undefined-quot 60 SPECIAL-OBJECT: undefined-quot 62
: special-object-offset ( symbol -- n ) : special-object-offset ( symbol -- n )
special-objects get at header-size + ; special-objects get at header-size + ;
@ -525,6 +527,8 @@ M: quotation '
\ unwind-native-frames unwind-native-frames-word set \ unwind-native-frames unwind-native-frames-word set
\ fpu-state fpu-state-word set \ fpu-state fpu-state-word set
\ set-fpu-state set-fpu-state-word set \ set-fpu-state set-fpu-state-word set
\ signal-handler signal-handler-word set
\ leaf-signal-handler leaf-signal-handler-word set
undefined-def undefined-quot set ; undefined-def undefined-quot set ;
: emit-special-objects ( -- ) : emit-special-objects ( -- )

View File

@ -36,12 +36,12 @@ IN: bootstrap.x86
[ [
! load entry point ! load entry point
RAX 0 MOV rc-absolute-cell rel-this RAX 0 MOV rc-absolute-cell rel-this
! store entry point
RSP bootstrap-cell 2 * neg [+] RAX MOV
! store stack frame size
RSP bootstrap-cell neg [+] stack-frame-size MOV
! alignment ! alignment
RSP stack-frame-size bootstrap-cell - SUB RSP stack-frame-size bootstrap-cell - SUB
! store entry point
RSP stack-frame-size bootstrap-cell 3 * - [+] RAX MOV
! store stack frame size
RSP stack-frame-size bootstrap-cell 2 * - [+] stack-frame-size MOV
] jit-prolog jit-define ] jit-prolog jit-define
[ [
@ -91,6 +91,61 @@ IN: bootstrap.x86
"end_callback" jit-call "end_callback" jit-call
] \ c-to-factor define-sub-primitive ] \ c-to-factor define-sub-primitive
USE: locals
: jit-save-volatile-regs ( -- )
! do we also need to save XMM?
RSP volatile-regs length bootstrap-cell * SUB
volatile-regs
[| r i | RSP i bootstrap-cell * [+] r MOV ] each-index ;
:: jit-restore-volatile-regs ( additional-pop -- )
volatile-regs
[| r i | r RSP i bootstrap-cell * [+] MOV ] each-index
RSP volatile-regs length bootstrap-cell * additional-pop + ADD ;
[
! Stack at this point has the signal handler pointer followed by
! 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
RAX RSP volatile-regs length 3 + bootstrap-cell * [+] MOV
RAX CALL
bootstrap-cell jit-restore-volatile-regs
] \ signal-handler define-sub-primitive
! :: jit-push-leaf-stack-frame ( -- )
! ;
!
! :: jit-pop-leaf-stack-frame ( -- )
! ;
!
! [
! ! Stack at this point has the signal handler pointer followed by
! ! the word pointer and the return address back into normal execution,
! ! then the 24 bytes of stack frame + alignment inserted by the prolog
! ! After registers are saved and the leaf stack frame is constructed,
! ! the stack looks like:
! ! RSP fake leaf stack frame (4 cells)
! ! + saved volatile regs (`volatile-regs length` cells)
! ! . subprimitive stack frame alignment (3 cells)
! ! . leaf word (1 cell)
! ! . signal handler address (1 cell)
! ! resume address (1 cell)
! jit-save-volatile-regs
! 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
ds-reg bootstrap-cell SUB ds-reg bootstrap-cell SUB

View File

@ -7,6 +7,7 @@ IN: bootstrap.x86
: stack-frame-size ( -- n ) 4 bootstrap-cells ; : stack-frame-size ( -- n ) 4 bootstrap-cells ;
: nv-regs ( -- seq ) { RBX R12 R13 R14 R15 } ; : nv-regs ( -- seq ) { RBX R12 R13 R14 R15 } ;
: volatile-regs ( -- seq ) { RAX RCX RDX RSI RDI R8 R9 R10 R11 } ;
: arg1 ( -- reg ) RDI ; : arg1 ( -- reg ) RDI ;
: arg2 ( -- reg ) RSI ; : arg2 ( -- reg ) RSI ;
: arg3 ( -- reg ) RDX ; : arg3 ( -- reg ) RDX ;

View File

@ -9,6 +9,7 @@ DEFER: stack-reg
: stack-frame-size ( -- n ) 8 bootstrap-cells ; : stack-frame-size ( -- n ) 8 bootstrap-cells ;
: nv-regs ( -- seq ) { RBX RSI RDI R12 R13 R14 R15 } ; : nv-regs ( -- seq ) { RBX RSI RDI R12 R13 R14 R15 } ;
: volatile-regs ( -- seq ) { RAX RCX RDX R8 R9 R10 R11 } ;
: arg1 ( -- reg ) RCX ; : arg1 ( -- reg ) RCX ;
: arg2 ( -- reg ) RDX ; : arg2 ( -- reg ) RDX ;
: arg3 ( -- reg ) R8 ; : arg3 ( -- reg ) R8 ;

View File

@ -954,3 +954,7 @@ PRIVATE>
: HWNT ( -- ) HEX: 2e , ; ! Hint branch Weakly Not Taken : HWNT ( -- ) HEX: 2e , ; ! Hint branch Weakly Not Taken
: HST ( -- ) HEX: 3e , ; ! Hint branch Strongly Taken : HST ( -- ) HEX: 3e , ; ! Hint branch Strongly Taken
! interrupt instructions
: INT ( n -- ) dup 3 = [ drop HEX: cc , ] [ HEX: cd , 1, ] if ;

View File

@ -60,7 +60,7 @@ mailbox
sleep-entry ; sleep-entry ;
: self ( -- thread ) : self ( -- thread )
63 special-object { thread } declare ; inline 65 special-object { thread } declare ; inline
: thread-continuation ( thread -- continuation ) : thread-continuation ( thread -- continuation )
context>> check-box value>> continuation-for ; context>> check-box value>> continuation-for ;
@ -79,7 +79,7 @@ sleep-entry ;
[ tnamespace ] dip change-at ; inline [ tnamespace ] dip change-at ; inline
: threads ( -- assoc ) : threads ( -- assoc )
64 special-object { hashtable } declare ; inline 66 special-object { hashtable } declare ; inline
: thread-registered? ( thread -- ? ) : thread-registered? ( thread -- ? )
id>> threads key? ; id>> threads key? ;
@ -92,18 +92,18 @@ sleep-entry ;
: unregister-thread ( thread -- ) : unregister-thread ( thread -- )
id>> threads delete-at ; id>> threads delete-at ;
: set-self ( thread -- ) 63 set-special-object ; inline : set-self ( thread -- ) 65 set-special-object ; inline
PRIVATE> PRIVATE>
: run-queue ( -- dlist ) : run-queue ( -- dlist )
65 special-object { dlist } declare ; inline 67 special-object { dlist } declare ; inline
: sleep-queue ( -- heap ) : sleep-queue ( -- heap )
66 special-object { min-heap } declare ; inline 68 special-object { min-heap } declare ; inline
: waiting-callbacks ( -- assoc ) : waiting-callbacks ( -- assoc )
68 special-object { hashtable } declare ; inline 70 special-object { hashtable } declare ; inline
: new-thread ( quot name class -- thread ) : new-thread ( quot name class -- thread )
new new
@ -234,10 +234,10 @@ M: real sleep
<PRIVATE <PRIVATE
: init-thread-state ( -- ) : init-thread-state ( -- )
H{ } clone 64 set-special-object H{ } clone 66 set-special-object
<dlist> 65 set-special-object <dlist> 67 set-special-object
<min-heap> 66 set-special-object <min-heap> 68 set-special-object
H{ } clone 68 set-special-object ; H{ } clone 70 set-special-object ;
: init-initial-thread ( -- ) : init-initial-thread ( -- )
[ ] "Initial" <thread> [ ] "Initial" <thread>

View File

@ -30,7 +30,7 @@ STRUCT: vm
{ nursery zone } { nursery zone }
{ cards-offset cell } { cards-offset cell }
{ decks-offset cell } { decks-offset cell }
{ special-objects cell[70] } ; { special-objects cell[80] } ;
: vm-field-offset ( field -- offset ) vm offset-of ; inline : vm-field-offset ( field -- offset ) vm offset-of ; inline

View File

@ -67,5 +67,5 @@ M: array symbol>string [ (symbol>string) ] map ;
[ [
8 special-object utf8 alien>string string>cpu \ cpu set-global 8 special-object utf8 alien>string string>cpu \ cpu set-global
9 special-object utf8 alien>string string>os \ os set-global 9 special-object utf8 alien>string string>os \ os set-global
67 special-object utf8 alien>string \ vm-compiler set-global 69 special-object utf8 alien>string \ vm-compiler set-global
] "alien.strings" add-startup-hook ] "alien.strings" add-startup-hook

View File

@ -345,6 +345,8 @@ tuple
{ "(call)" "kernel.private" ( quot -- ) } { "(call)" "kernel.private" ( quot -- ) }
{ "fpu-state" "kernel.private" ( -- ) } { "fpu-state" "kernel.private" ( -- ) }
{ "set-fpu-state" "kernel.private" ( -- ) } { "set-fpu-state" "kernel.private" ( -- ) }
{ "signal-handler" "kernel.private" ( -- ) }
{ "leaf-signal-handler" "kernel.private" ( -- ) }
{ "unwind-native-frames" "kernel.private" ( -- ) } { "unwind-native-frames" "kernel.private" ( -- ) }
{ "set-callstack" "kernel.private" ( callstack -- * ) } { "set-callstack" "kernel.private" ( callstack -- * ) }
{ "lazy-jit-compile" "kernel.private" ( -- ) } { "lazy-jit-compile" "kernel.private" ( -- ) }

View File

@ -106,7 +106,7 @@ GENERIC: definitions-changed ( assoc obj -- )
! Incremented each time stack effects potentially changed, used ! Incremented each time stack effects potentially changed, used
! by compiler.tree.propagation.call-effect for call( and execute( ! by compiler.tree.propagation.call-effect for call( and execute(
! inline caching ! inline caching
: effect-counter ( -- n ) 47 special-object ; inline : effect-counter ( -- n ) 49 special-object ; inline
GENERIC: always-bump-effect-counter? ( defspec -- ? ) GENERIC: always-bump-effect-counter? ( defspec -- ? )
@ -141,9 +141,9 @@ M: object always-bump-effect-counter? drop f ;
: bump-effect-counter ( -- ) : bump-effect-counter ( -- )
bump-effect-counter? [ bump-effect-counter? [
47 special-object 0 or 49 special-object 0 or
1 + 1 +
47 set-special-object 49 set-special-object
] when ; ] when ;
: notify-observers ( -- ) : notify-observers ( -- )

View File

@ -124,7 +124,7 @@ callback-error-hook [ [ die ] ] initialize
catchstack* [ catchstack* [
in-callback? in-callback?
[ callback-error-hook get-global call( error -- * ) ] [ callback-error-hook get-global call( error -- * ) ]
[ 63 special-object error-in-thread ] [ 65 special-object error-in-thread ]
if if
] [ pop continue-with ] if-empty ; ] [ pop continue-with ] if-empty ;
@ -190,8 +190,8 @@ M: condition compute-restarts
init-catchstack init-catchstack
! VM calls on error ! VM calls on error
[ [
! 63 = self ! 65 = self
63 special-object error-thread set-global 65 special-object error-thread set-global
continuation error-continuation set-global continuation error-continuation set-global
[ original-error set-global ] [ rethrow ] bi [ original-error set-global ] [ rethrow ] bi
] 5 set-special-object ] 5 set-special-object

View File

@ -55,7 +55,7 @@ M: c-io-backend init-io ;
: stdin-handle ( -- alien ) 11 special-object ; : stdin-handle ( -- alien ) 11 special-object ;
: stdout-handle ( -- alien ) 12 special-object ; : stdout-handle ( -- alien ) 12 special-object ;
: stderr-handle ( -- alien ) 61 special-object ; : stderr-handle ( -- alien ) 63 special-object ;
: init-c-stdio ( -- ) : init-c-stdio ( -- )
stdin-handle <c-reader> stdin-handle <c-reader>

View File

@ -18,35 +18,37 @@ callstack *factor_vm::allot_callstack(cell size)
return stack; return stack;
} }
void factor_vm::dispatch_signal_handler(cell *sp, cell *pc, cell newpc) 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 */
cell offset = *sp % 16; cell offset = *sp % 16;
if (offset == 0) {
tagged<word> handler_word = tagged<word>(special_objects[SIGNAL_HANDLER_WORD]);
if (offset == 0)
{
signal_from_leaf = false; signal_from_leaf = false;
cell newsp = *sp - sizeof(cell); }
*sp = newsp; else if (offset == 16 - sizeof(cell))
*(cell*)newsp = *pc; {
*pc = newpc; signal_from_leaf = true;
ctx->callstack_top = (stack_frame*)newsp; handler_word = tagged<word>(special_objects[LEAF_SIGNAL_HANDLER_WORD]);
} else if (offset == 16 - sizeof(cell)) { }
dispatch_signal_handler_from_leaf(sp, pc, newpc); else
} else { {
fatal_error("Invalid stack frame during signal handler", *sp); fatal_error("Invalid stack frame during signal handler", *sp);
} }
}
void factor_vm::dispatch_signal_handler_from_leaf(cell *sp, cell *pc, cell newpc) /* Push the original PC as a return address and the C handler function
{ * pointer as an argument to the signal handler stub. */
/* We should try to conjure a stack frame here, but we may need to deal cell newsp = *sp - 2*sizeof(cell);
with callstack overflows or the GC moving code around. *sp = newsp;
For now leave the stack untouched so the signal handler returns into *(cell*)(newsp + sizeof(cell)) = *pc;
the parent procedure. This will cause things to blow up if the stack *(cell*)newsp = handler;
is left unbalanced. */ *pc = (cell)handler_word->code->entry_point();
signal_from_leaf = true;
*pc = newpc;
} }
/* We ignore the two topmost frames, the 'callstack' primitive /* We ignore the two topmost frames, the 'callstack' primitive

View File

@ -1,7 +1,7 @@
namespace factor namespace factor
{ {
static const cell special_object_count = 70; static const cell special_object_count = 80;
enum special_object { enum special_object {
OBJ_WALKER_HOOK = 3, /* non-local exit hook, used by library only */ OBJ_WALKER_HOOK = 3, /* non-local exit hook, used by library only */
@ -57,16 +57,18 @@ enum special_object {
UNWIND_NATIVE_FRAMES_WORD, UNWIND_NATIVE_FRAMES_WORD,
GET_FPU_STATE_WORD, GET_FPU_STATE_WORD,
SET_FPU_STATE_WORD, SET_FPU_STATE_WORD,
SIGNAL_HANDLER_WORD,
LEAF_SIGNAL_HANDLER_WORD,
/* Incremented on every modify-code-heap call; invalidates call( inline /* Incremented on every modify-code-heap call; invalidates call( inline
caching */ caching */
REDEFINITION_COUNTER = 47, REDEFINITION_COUNTER = 49,
/* Callback stub generation in callbacks.c */ /* Callback stub generation in callbacks.c */
CALLBACK_STUB = 48, CALLBACK_STUB = 50,
/* Polymorphic inline cache generation in inline_cache.c */ /* Polymorphic inline cache generation in inline_cache.c */
PIC_LOAD = 49, PIC_LOAD = 51,
PIC_TAG, PIC_TAG,
PIC_TUPLE, PIC_TUPLE,
PIC_CHECK_TAG, PIC_CHECK_TAG,
@ -76,25 +78,25 @@ enum special_object {
PIC_MISS_TAIL_WORD, PIC_MISS_TAIL_WORD,
/* Megamorphic cache generation in dispatch.c */ /* Megamorphic cache generation in dispatch.c */
MEGA_LOOKUP = 57, MEGA_LOOKUP = 59,
MEGA_LOOKUP_WORD, MEGA_LOOKUP_WORD,
MEGA_MISS_WORD, MEGA_MISS_WORD,
OBJ_UNDEFINED = 60, /* default quotation for undefined words */ OBJ_UNDEFINED = 62, /* default quotation for undefined words */
OBJ_STDERR = 61, /* stderr FILE* handle */ OBJ_STDERR = 63, /* stderr FILE* handle */
OBJ_STAGE2 = 62, /* have we bootstrapped? */ OBJ_STAGE2 = 64, /* have we bootstrapped? */
OBJ_CURRENT_THREAD = 63, OBJ_CURRENT_THREAD = 65,
OBJ_THREADS = 64, OBJ_THREADS = 66,
OBJ_RUN_QUEUE = 65, OBJ_RUN_QUEUE = 67,
OBJ_SLEEP_QUEUE = 66, OBJ_SLEEP_QUEUE = 68,
OBJ_VM_COMPILER = 67, /* version string of the compiler we were built with */ OBJ_VM_COMPILER = 69, /* version string of the compiler we were built with */
OBJ_WAITING_CALLBACKS = 68, OBJ_WAITING_CALLBACKS = 70,
}; };
/* save-image-and-exit discards special objects that are filled in on startup /* save-image-and-exit discards special objects that are filled in on startup