]> gitweb.factorcode.org Git - factor.git/commitdiff
vm: resumably handle signals from leaf procedures
authorJoe Groff <arcata@gmail.com>
Tue, 25 Oct 2011 06:46:34 +0000 (23:46 -0700)
committerJoe Groff <arcata@gmail.com>
Fri, 28 Oct 2011 04:18:18 +0000 (21:18 -0700)
basis/compiler/constants/constants.factor
basis/cpu/x86/64/bootstrap.factor
basis/vm/vm.factor
vm/callstack.cpp
vm/vm.hpp

index fe12925e7f75c8be3e1744164214a1bdeb285517..e285952461cc4798a980d4424450c81e28d7307b 100644 (file)
@@ -29,6 +29,7 @@ CONSTANT: deck-bits 18
 : callstack-top-offset ( -- n ) 2 \ callstack type-number slot-offset ; inline
 : vm-context-offset ( -- n ) 0 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-bottom-offset ( -- n ) 1 bootstrap-cells ; inline
 : context-datastack-offset ( -- n ) 2 bootstrap-cells ; inline
index e201a1d3243f37ffcb4db9dcc62c84e70994c079..47d6a59895420c25cf7a450c55c2429663f8e77b 100755 (executable)
@@ -93,58 +93,47 @@ IN: bootstrap.x86
 
 USE: locals
 
-: jit-save-volatile-regs ( -- )
+:: jit-save-volatile-regs ( -- save-size )
     ! 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
-    [| 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
     [| 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
-    ! 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-volatile-regs :> save-size
     jit-save-context
-    RAX RSP volatile-regs length 3 + bootstrap-cell * [+] MOV
+    RAX vm-reg vm-signal-handler-addr-offset [+] MOV
     RAX CALL
-    bootstrap-cell jit-restore-volatile-regs
+    save-size 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
+[| |
+    jit-save-volatile-regs :> save-size
+    jit-save-context
+    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
+    ! addition to our own before resuming.
+    ! Grab our resume address and place it just underneath the leaf proc's
+    ! return address, since we can't touch any registers once they've been
+    ! restored. If we got this far there should be no faults here and we
+    ! can get away with corrupting the stack frame.
+    RAX RSP save-size 3 bootstrap-cells + [+] MOV
+    RSP save-size 6 bootstrap-cells + [+] RAX MOV
+
+    ! Popping 3 extra cells here plus the 3 cells the epilogue pops leaves
+    ! the resume address at the top of the stack for when the epilogue RETs.
+    save-size 3 bootstrap-cells + jit-restore-volatile-regs
+] \ leaf-signal-handler define-sub-primitive
 
 [
     arg1 ds-reg [] MOV
index 84a70cbc71c9bcc08314f8d971df1c5f8253dad0..c22b739f08d1fcf21741e20378c23cf26c524873 100644 (file)
@@ -30,6 +30,7 @@ STRUCT: vm
 { nursery zone }
 { cards-offset cell }
 { decks-offset cell }
+{ signal-handler-addr cell }
 { special-objects cell[80] } ;
 
 : vm-field-offset ( field -- offset ) vm offset-of ; inline
index 683c7aa7f673a650f4ca5bf57c7d913746dfffa4..8b16cccef4e1ec91ebfe01f544dbd750e96eaee0 100755 (executable)
@@ -18,23 +18,70 @@ callstack *factor_vm::allot_callstack(cell size)
        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)
 {
        /* 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. */
        /* XXX horribly x86-centric */
+       /* XXX check if exception came from C code */
+       /* XXX handle callstack overflow */
 
        cell offset = *sp % 16;
 
+       signal_handler_addr = handler;
        tagged<word> handler_word = tagged<word>(special_objects[SIGNAL_HANDLER_WORD]);
        if (offset == 0)
        {
+               // should use FRAME_RETURN_ADDRESS here to be platform-agnostic
                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))
        {
                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]);
        }
        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);
        }
 
-       /* 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();
 }
 
index 180b92b3c556b4b48d42fc02e683cf1329de2dd5..04946bea1d6d6e8aa5522f1e4333254cee74c2a5 100755 (executable)
--- a/vm/vm.hpp
+++ b/vm/vm.hpp
@@ -6,7 +6,11 @@ struct code_root;
 
 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 */
        context *ctx;
@@ -21,10 +25,17 @@ struct factor_vm
        cell cards_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
        set-special-object primitives */
        cell special_objects[special_object_count];
 
+       // THESE FIELDS ARE ACCESSED DIRECTLY FROM FACTOR.
+       // ^^^^^^
+       //
+
        /* Data stack and retain stack sizes */
        cell datastack_size, retainstack_size, callstack_size;