Some support for platforms whose libraries do not maintain a frame pointer
authorDavid Lichteblau <david@lichteblau.com>
Mon, 12 Nov 2012 19:13:09 +0000 (20:13 +0100)
committerDavid Lichteblau <david@lichteblau.com>
Wed, 5 Dec 2012 16:34:28 +0000 (17:34 +0100)
For platforms on which system libraries are built with the
equivalent of -fomit-frame-pointer, i.e. do not maintain EBP, save
it in the thread structure upon entry to an exception handler, and
restore the register during call_into_lisp.

Currently for Windows on x86-64 only, where it is required.
Analogous changes had been implemented for x86, but are not included
here.

Thanks to Anton Kovalenko.

src/compiler/generic/objdef.lisp
src/runtime/safepoint.c
src/runtime/thread.c
src/runtime/win32-os.c
src/runtime/x86-64-assem.S

index d3bd635..fda2758 100644 (file)
   (mach-port-name :c-type "mach_port_name_t")
   (nonpointer-data :c-type "struct nonpointer_thread_data *" :length #!+alpha 2 #!-alpha 1)
   #!+(and sb-safepoint x86) (selfptr :c-type "struct thread *")
+  ;; Context base pointer for running on top of system libraries built using
+  ;; -fomit-frame-pointer.  Currently truly required and implemented only
+  ;; for (and win32 x86-64), but could be generalized to other platforms if
+  ;; needed:
+  #!+win32 (carried-base-pointer :c-type "os_context_register_t")
   #!+sb-safepoint (csp-around-foreign-call :c-type "lispobj *")
   #!+sb-safepoint (pc-around-foreign-call :c-type "lispobj *")
   #!+win32 (synchronous-io-handle-and-flag :c-type "HANDLE" :length 1)
index 3faabe5..8a34a08 100644 (file)
@@ -983,6 +983,11 @@ callback_wrapper_trampoline(
     if (!th)
         lose("callback invoked in non-lisp thread.  Sorry, that is not supported yet.");
 
+#ifdef LISP_FEATURE_WIN32
+    /* arg2 is the pointer to a return value, which sits on the stack */
+    th->carried_base_pointer = (os_context_register_t) *(((void**)arg2)-1);
+#endif
+
     WITH_GC_AT_SAFEPOINTS_ONLY()
         funcall3(SymbolValue(ENTER_ALIEN_CALLBACK, 0), arg0, arg1, arg2);
 }
index 926009c..838a187 100644 (file)
@@ -568,7 +568,12 @@ create_thread_struct(lispobj initial_function) {
     th->os_thread=0;
 
 #ifdef LISP_FEATURE_SB_SAFEPOINT
+# ifdef LISP_FEATURE_WIN32
+    th->carried_base_pointer = 0;
+# endif
+# ifdef LISP_FEATURE_C_STACK_IS_CONTROL_STACK
     th->pc_around_foreign_call = 0;
+# endif
     th->csp_around_foreign_call = csp_page;
 #endif
 
index dc502b0..49358a1 100644 (file)
@@ -1373,6 +1373,13 @@ handle_exception(EXCEPTION_RECORD *exception_record,
     context.sigmask = self ? self->os_thread->blocked_signal_set : 0;
 #endif
 
+    os_context_register_t oldbp = NULL;
+    if (self) {
+        oldbp = self ? self->carried_base_pointer : 0;
+        self->carried_base_pointer
+            = (os_context_register_t) voidreg(win32_context, bp);
+    }
+
     /* For EXCEPTION_ACCESS_VIOLATION only. */
     void *fault_address = (void *)exception_record->ExceptionInformation[1];
 
@@ -1415,6 +1422,9 @@ handle_exception(EXCEPTION_RECORD *exception_record,
         /* All else failed, drop through to the lisp-side exception handler. */
         signal_internal_error_or_lose(ctx, exception_record, fault_address);
 
+    if (self)
+        self->carried_base_pointer = oldbp;
+
     errno = lastErrno;
     SetLastError(lastError);
     return ExceptionContinueExecution;
@@ -1451,6 +1461,14 @@ veh(EXCEPTION_POINTERS *ep)
 }
 #endif
 
+os_context_register_t
+carry_frame_pointer(os_context_register_t default_value)
+{
+    struct thread* self = arch_os_get_current_thread();
+    os_context_register_t bp = self->carried_base_pointer;
+    return bp ? bp : default_value;
+}
+
 void
 wos_install_interrupt_handlers(struct lisp_exception_frame *handler)
 {
index 7c91ef0..b85639e 100644 (file)
@@ -156,12 +156,23 @@ GNAME(call_into_lisp_first_time):
  * return values in rax rdx
  * callee saves rbp rbx r12-15 if it uses them
  */
-       
+#ifdef LISP_FEATURE_WIN32
+# define SUPPORT_FOMIT_FRAME_POINTER
+#endif
        .align  align_16byte,0x90
 GNAME(call_into_lisp):
+#ifdef SUPPORT_FOMIT_FRAME_POINTER
+       mov     %rbp,%rax
+#endif
        push    %rbp            # Save old frame pointer.
        mov     %rsp,%rbp       # Establish new frame.
 Lstack:
+#ifdef SUPPORT_FOMIT_FRAME_POINTER
+       /* If called through call_into_lisp_first_time, %r15 becomes invalid
+        * here, but we will not return in that case. */
+       push    %r15
+       mov     %rax,%r15
+#endif
        /* FIXME x86 saves FPU state here */
        push    %rbx    # these regs are callee-saved according to C
        push    %r12    # so must be preserved and restored when 
@@ -176,6 +187,13 @@ Lstack:
        push    %rsi    #
        push    %rdx    #
 #ifdef LISP_FEATURE_SB_THREAD
+# ifdef SUPPORT_FOMIT_FRAME_POINTER
+       mov     (%rbp),%rcx
+       sub     $32,%rsp
+       call    GNAME(carry_frame_pointer)
+       add     $32,%rsp
+       mov     %rax,(%rbp)
+# endif
 #ifdef LISP_FEATURE_GCC_TLS
        movq    %fs:0, %rax
        movq    GNAME(current_thread)@TPOFF(%rax), %r12
@@ -238,7 +256,13 @@ LsingleValue:
 /* FIXME Restore the NPX state. */
 
        mov     %rdx,%rax       # c-val
+#ifdef SUPPORT_FOMIT_FRAME_POINTER
+       mov     %r15,%rbp       # orig rbp
+       pop     %r15            # orig r15
+       add     $8,%rsp         # no need for saved (overridden) rbp
+#else
        leave
+#endif
        ret
        SIZE(GNAME(call_into_lisp))
 \f