From: Gabor Melis Date: Tue, 21 Apr 2009 11:25:51 +0000 (+0000) Subject: 1.0.27.14: bias x86oid frame pointer X-Git-Url: http://repo.macrolet.net/gitweb/?a=commitdiff_plain;h=952d16ab5880823c1864eb9105bb269e2e00760d;p=sbcl.git 1.0.27.14: bias x86oid frame pointer Forward port of Alastair Bridgewater's patch. Duplicate it on x86-64. Make it so that fp points to ocfp just as if the call had been made by CALL to a function with the standard prologue "PUSH EBP; MOV ESP, EBP". Fix the debugger. --- diff --git a/NEWS b/NEWS index fe81cbb..6f89262 100644 --- a/NEWS +++ b/NEWS @@ -5,6 +5,8 @@ changes in sbcl-1.0.28 relative to 1.0.27: * bug fix: RESTART-FRAME and RETURN-FROM-FRAME stack corruption * bug fix: the discriminating function for PRINT-OBJECT no longer preserves potentially-invalid effective methods in its cache. + * improvement: on x86/x86-64 Lisp call frames now have the same layout as C + frames, allowing for instance more reliable backtraces. changes in sbcl-1.0.27 relative to 1.0.26: * new port: support added for x86-64 OpenBSD. (thanks to Josh Elsasser) diff --git a/doc/internals/calling-convention.texinfo b/doc/internals/calling-convention.texinfo index bf5b2f3..5fcb529 100644 --- a/doc/internals/calling-convention.texinfo +++ b/doc/internals/calling-convention.texinfo @@ -119,7 +119,39 @@ frame to include sufficient space for its local variables, after possibly converting any @code{&rest} arguments to a proper list. The above scheme was changed in 1.0.27 on x86 and x86-64 by swapping -the old frame pointer and the return address. +the old frame pointer with the return address and making EBP point two +words later: + +On x86/x86-64 the stack now looks like this (stack grows downwards): + +@verbatim +---------- +RETURN PC +---------- +OLD FP +---------- <- FP points here +EMPTY SLOT +---------- +FIRST ARG +---------- +@end verbatim + +just as if the function had been CALLed and upon entry executed the +standard prologue: PUSH EBP; MOV EBP, ESP. On other architectures the +stack looks like this (stack grows upwards): + +@verbatim +---------- +FIRST ARG +---------- +EMPTY SLOT +---------- +RETURN PC +---------- +OLD FP +---------- <- FP points here +@end verbatim + @node Unknown-Values Returns @comment node-name, next, previous, up diff --git a/src/assembly/x86-64/arith.lisp b/src/assembly/x86-64/arith.lisp index b6a1934..fc05cbe 100644 --- a/src/assembly/x86-64/arith.lisp +++ b/src/assembly/x86-64/arith.lisp @@ -40,12 +40,12 @@ (inst ret) DO-STATIC-FUN + ;; Same as: (inst enter (fixnumize 1)) (inst push rbp-tn) - (inst lea rbp-tn (make-ea :qword - :base rsp-tn - :disp (* 2 n-word-bytes))) + (inst mov rbp-tn rsp-tn) (inst sub rsp-tn (fixnumize 1)) - (inst push (make-ea :qword :base rbp-tn :disp (- n-word-bytes))) + (inst push (make-ea :qword :base rbp-tn + :disp (frame-byte-offset return-pc-save-offset))) (inst mov rcx (fixnumize 2)) ; arg count (inst jmp (make-ea :qword @@ -127,9 +127,10 @@ (inst jmp :z FIXNUM) (inst push rbp-tn) - (inst lea rbp-tn (make-ea :qword :base rsp-tn :disp (* 2 n-word-bytes))) + (inst mov rbp-tn rsp-tn) (inst sub rsp-tn (fixnumize 1)) - (inst push (make-ea :qword :base rbp-tn :disp (- n-word-bytes))) + (inst push (make-ea :qword :base rbp-tn + :disp (frame-byte-offset return-pc-save-offset))) (inst mov rcx (fixnumize 1)) ; arg count (inst jmp (make-ea :qword :disp (+ nil-value (static-fun-offset '%negate)))) @@ -167,13 +168,18 @@ (inst ret) DO-STATIC-FUN - (move rcx rsp-tn) (inst sub rsp-tn (fixnumize 3)) - (inst mov (make-ea :qword - :base rcx - :disp (frame-byte-offset ocfp-save-offset)) + (inst mov (make-ea :qword :base rsp-tn + :disp (frame-byte-offset + (+ sp->fp-offset + -3 + ocfp-save-offset))) rbp-tn) - (move rbp-tn rcx) + (inst lea rbp-tn (make-ea :qword :base rsp-tn + :disp (frame-byte-offset + (+ sp->fp-offset + -3 + ocfp-save-offset)))) (inst mov rcx (fixnumize 2)) (inst call (make-ea :qword :disp (+ nil-value @@ -232,13 +238,18 @@ (inst ret) DO-STATIC-FUN - (move rcx rsp-tn) (inst sub rsp-tn (fixnumize 3)) - (inst mov (make-ea :qword - :base rcx - :disp (frame-byte-offset ocfp-save-offset)) + (inst mov (make-ea :qword :base rsp-tn + :disp (frame-byte-offset + (+ sp->fp-offset + -3 + ocfp-save-offset))) rbp-tn) - (move rbp-tn rcx) + (inst lea rbp-tn (make-ea :qword :base rsp-tn + :disp (frame-byte-offset + (+ sp->fp-offset + -3 + ocfp-save-offset)))) (inst mov rcx (fixnumize 2)) (inst call (make-ea :qword :disp (+ nil-value (static-fun-offset 'eql)))) @@ -289,13 +300,19 @@ (inst ret) DO-STATIC-FUN - (move rcx rsp-tn) (inst sub rsp-tn (fixnumize 3)) - (inst mov (make-ea :qword - :base rcx - :disp (frame-byte-offset ocfp-save-offset)) + (inst mov (make-ea :qword :base rsp-tn + :disp (frame-byte-offset + (+ sp->fp-offset + -3 + ocfp-save-offset))) rbp-tn) - (move rbp-tn rcx) + (inst lea rbp-tn (make-ea :qword :base rsp-tn + :disp (frame-byte-offset + (+ sp->fp-offset + -3 + ocfp-save-offset)))) + (inst mov rcx (fixnumize 2)) (inst call (make-ea :qword :disp (+ nil-value (static-fun-offset 'two-arg-=)))) diff --git a/src/assembly/x86-64/assem-rtns.lisp b/src/assembly/x86-64/assem-rtns.lisp index 5b51eef..28b0c1c 100644 --- a/src/assembly/x86-64/assem-rtns.lisp +++ b/src/assembly/x86-64/assem-rtns.lisp @@ -39,8 +39,13 @@ (inst cmp ecx (fixnumize 3)) (inst jmp :e THREE-VALUES) - (inst mov ebx rbp-tn) - ;; Save the count, because the loop is going to destroy it. + ;; As per the calling convention EBX is expected to point at the SP + ;; before the stack frame. + (inst lea ebx (make-ea :qword :base rbp-tn + :disp (* sp->fp-offset n-word-bytes))) + + ;; Save the count, the return address and restore the frame pointer, + ;; because the loop is going to destroy them. (inst mov edx ecx) (inst mov eax (make-ea :qword :base rbp-tn :disp (frame-byte-offset return-pc-save-offset))) @@ -78,13 +83,12 @@ ;; Handle the register arg cases. ZERO-VALUES - (inst mov ebx rbp-tn) + (inst lea ebx (make-ea :qword :base rbp-tn + :disp (* sp->fp-offset n-word-bytes))) (inst mov edx nil-value) (inst mov edi edx) (inst mov esi edx) - (inst lea rsp-tn - (make-ea :qword :base ebx - :disp (frame-byte-offset ocfp-save-offset))) + (inst mov rsp-tn rbp-tn) (inst stc) (inst pop rbp-tn) (inst ret) @@ -93,33 +97,29 @@ ;; check for this case when size > speed. ONE-VALUE (loadw edx esi -1) - (inst lea rsp-tn - (make-ea :qword :base rbp-tn - :disp (frame-byte-offset ocfp-save-offset))) + (inst mov rsp-tn rbp-tn) (inst clc) (inst pop rbp-tn) (inst ret) TWO-VALUES - (inst mov ebx rbp-tn) + (inst lea ebx (make-ea :qword :base rbp-tn + :disp (* sp->fp-offset n-word-bytes))) (loadw edx esi -1) (loadw edi esi -2) (inst mov esi nil-value) - (inst lea rsp-tn - (make-ea :qword :base ebx - :disp (frame-byte-offset ocfp-save-offset))) + (inst mov rsp-tn rbp-tn) (inst stc) (inst pop rbp-tn) (inst ret) THREE-VALUES - (inst mov ebx rbp-tn) + (inst lea ebx (make-ea :qword :base rbp-tn + :disp (* sp->fp-offset n-word-bytes))) (loadw edx esi -1) (loadw edi esi -2) (loadw esi esi -3) - (inst lea rsp-tn - (make-ea :qword :base ebx - :disp (frame-byte-offset ocfp-save-offset))) + (inst mov rsp-tn rbp-tn) (inst stc) (inst pop rbp-tn) (inst ret)) @@ -207,7 +207,7 @@ ;; Clear most of the stack. (inst lea rsp-tn - (make-ea :qword :base rbp-tn :disp (* -3 n-word-bytes))) + (make-ea :qword :base rbp-tn :disp (* (- sp->fp-offset 3) n-word-bytes))) ;; Push the return-pc so it looks like we just called. (pushw rbp-tn (frame-word-offset return-pc-save-offset)) diff --git a/src/assembly/x86/arith.lisp b/src/assembly/x86/arith.lisp index 28d510f..54f9489 100644 --- a/src/assembly/x86/arith.lisp +++ b/src/assembly/x86/arith.lisp @@ -40,12 +40,12 @@ (inst ret) DO-STATIC-FUN + ;; Same as: (inst enter (fixnumize 1)) (inst push ebp-tn) - (inst lea ebp-tn (make-ea :dword - :base esp-tn - :disp (* 2 n-word-bytes))) + (inst mov ebp-tn esp-tn) (inst sub esp-tn (fixnumize 1)) - (inst push (make-ea :dword :base ebp-tn :disp (- n-word-bytes))) + (inst push (make-ea :dword :base ebp-tn + :disp (frame-byte-offset return-pc-save-offset))) (inst mov ecx (fixnumize 2)) ; arg count (inst jmp (make-ea :dword @@ -130,9 +130,10 @@ (inst jmp :z FIXNUM) (inst push ebp-tn) - (inst lea ebp-tn (make-ea :dword :base esp-tn :disp (* 2 n-word-bytes))) + (inst mov ebp-tn esp-tn) (inst sub esp-tn (fixnumize 1)) - (inst push (make-ea :dword :base ebp-tn :disp (- n-word-bytes))) + (inst push (make-ea :dword :base ebp-tn + :disp (frame-byte-offset return-pc-save-offset))) (inst mov ecx (fixnumize 1)) ; arg count (inst jmp (make-ea :dword :disp (+ nil-value (static-fun-offset '%negate)))) @@ -169,13 +170,18 @@ (inst ret) DO-STATIC-FUN - (move ecx esp-tn) (inst sub esp-tn (fixnumize 3)) - (inst mov (make-ea :dword - :base ecx - :disp (frame-byte-offset ocfp-save-offset)) + (inst mov (make-ea :dword :base esp-tn + :disp (frame-byte-offset + (+ sp->fp-offset + -3 + ocfp-save-offset))) ebp-tn) - (move ebp-tn ecx) + (inst lea ebp-tn (make-ea :dword :base esp-tn + :disp (frame-byte-offset + (+ sp->fp-offset + -3 + ocfp-save-offset)))) (inst mov ecx (fixnumize 2)) (inst call (make-ea :dword :disp (+ nil-value @@ -229,7 +235,7 @@ (inst cmp ecx other-pointer-lowtag) (inst jmp :e DO-STATIC-FUN) - ;; Not both other pointers + ;; At least one fixnum (inst cmp x y) RET (inst ret) @@ -239,13 +245,18 @@ (inst cmp x y) (inst jmp :e RET) - (move ecx esp-tn) (inst sub esp-tn (fixnumize 3)) - (inst mov (make-ea :dword - :base ecx - :disp (frame-byte-offset ocfp-save-offset)) + (inst mov (make-ea :dword :base esp-tn + :disp (frame-byte-offset + (+ sp->fp-offset + -3 + ocfp-save-offset))) ebp-tn) - (move ebp-tn ecx) + (inst lea ebp-tn (make-ea :dword :base esp-tn + :disp (frame-byte-offset + (+ sp->fp-offset + -3 + ocfp-save-offset)))) (inst mov ecx (fixnumize 2)) (inst call (make-ea :dword :disp (+ nil-value (static-fun-offset 'eql)))) @@ -296,13 +307,18 @@ (inst ret) DO-STATIC-FUN - (move ecx esp-tn) (inst sub esp-tn (fixnumize 3)) - (inst mov (make-ea :dword - :base ecx - :disp (frame-byte-offset ocfp-save-offset)) + (inst mov (make-ea :dword :base esp-tn + :disp (frame-byte-offset + (+ sp->fp-offset + -3 + ocfp-save-offset))) ebp-tn) - (move ebp-tn ecx) + (inst lea ebp-tn (make-ea :dword :base esp-tn + :disp (frame-byte-offset + (+ sp->fp-offset + -3 + ocfp-save-offset)))) (inst mov ecx (fixnumize 2)) (inst call (make-ea :dword :disp (+ nil-value (static-fun-offset 'two-arg-=)))) diff --git a/src/assembly/x86/assem-rtns.lisp b/src/assembly/x86/assem-rtns.lisp index ee8a506..cce719e 100644 --- a/src/assembly/x86/assem-rtns.lisp +++ b/src/assembly/x86/assem-rtns.lisp @@ -39,8 +39,13 @@ (inst cmp ecx (fixnumize 3)) (inst jmp :e THREE-VALUES) - (inst mov ebx ebp-tn) - ;; Save the count, because the loop is going to destroy it. + ;; As per the calling convention EBX is expected to point at the SP + ;; before the stack frame. + (inst lea ebx (make-ea :dword :base ebp-tn + :disp (* sp->fp-offset n-word-bytes))) + + ;; Save the count, the return address and restore the frame pointer, + ;; because the loop is going to destroy them. (inst mov edx ecx) (inst mov eax (make-ea :dword :base ebp-tn :disp (frame-byte-offset return-pc-save-offset))) @@ -78,13 +83,12 @@ ;; Handle the register arg cases. ZERO-VALUES - (inst mov ebx ebp-tn) + (inst lea ebx (make-ea :dword :base ebp-tn + :disp (* sp->fp-offset n-word-bytes))) (inst mov edx nil-value) (inst mov edi edx) (inst mov esi edx) - (inst lea esp-tn - (make-ea :dword :base ebx - :disp (frame-byte-offset ocfp-save-offset))) + (inst mov esp-tn ebp-tn) (inst stc) (inst pop ebp-tn) (inst ret) @@ -93,33 +97,29 @@ ;; check for this case when size > speed. ONE-VALUE (loadw edx esi -1) - (inst lea esp-tn - (make-ea :dword :base ebp-tn - :disp (frame-byte-offset ocfp-save-offset))) + (inst mov esp-tn ebp-tn) (inst clc) (inst pop ebp-tn) (inst ret) TWO-VALUES - (inst mov ebx ebp-tn) + (inst lea ebx (make-ea :dword :base ebp-tn + :disp (* sp->fp-offset n-word-bytes))) (loadw edx esi -1) (loadw edi esi -2) (inst mov esi nil-value) - (inst lea esp-tn - (make-ea :dword :base ebx - :disp (frame-byte-offset ocfp-save-offset))) + (inst mov esp-tn ebp-tn) (inst stc) (inst pop ebp-tn) (inst ret) THREE-VALUES - (inst mov ebx ebp-tn) + (inst lea ebx (make-ea :dword :base ebp-tn + :disp (* sp->fp-offset n-word-bytes))) (loadw edx esi -1) (loadw edi esi -2) (loadw esi esi -3) - (inst lea esp-tn - (make-ea :dword :base ebx - :disp (frame-byte-offset ocfp-save-offset))) + (inst mov esp-tn ebp-tn) (inst stc) (inst pop ebp-tn) (inst ret)) @@ -204,7 +204,7 @@ ;; Clear most of the stack. (inst lea esp-tn - (make-ea :dword :base ebp-tn :disp (* -3 n-word-bytes))) + (make-ea :dword :base ebp-tn :disp (* (- sp->fp-offset 3) n-word-bytes))) ;; Push the return-pc so it looks like we just called. (pushw ebp-tn (frame-word-offset return-pc-save-offset)) diff --git a/src/code/debug-int.lisp b/src/code/debug-int.lisp index e5dfe62..d003425 100644 --- a/src/code/debug-int.lisp +++ b/src/code/debug-int.lisp @@ -558,7 +558,7 @@ (- (get-lisp-obj-address code) sb!vm:other-pointer-lowtag) code-header-len))) -; (format t "c-lra-fpc ~A ~A ~A~%" pc code pc-offset) + ;;(format t "c-lra-fpc ~A ~A ~A~%" pc code pc-offset) (values pc-offset code))))) #!+(or x86 x86-64) @@ -594,61 +594,14 @@ (declaim (maybe-inline x86-call-context)) (defun x86-call-context (fp) (declare (type system-area-pointer fp)) - (labels ((fail () - (values nil - (int-sap 0) - (int-sap 0))) - (handle (fp) - (cond - ((not (control-stack-pointer-valid-p fp)) - (fail)) - (t - ;; Check the two possible frame pointers. - (let ((lisp-ocfp (sap-ref-sap fp (- (* (1+ ocfp-save-offset) - sb!vm::n-word-bytes)))) - (lisp-ra (sap-ref-sap fp (- (* (1+ return-pc-save-offset) - sb!vm::n-word-bytes)))) - (c-ocfp (sap-ref-sap fp (* 0 sb!vm:n-word-bytes))) - (c-ra (sap-ref-sap fp (* 1 sb!vm:n-word-bytes)))) - (cond ((and (sap> lisp-ocfp fp) - (control-stack-pointer-valid-p lisp-ocfp) - (ra-pointer-valid-p lisp-ra) - (sap> c-ocfp fp) - (control-stack-pointer-valid-p c-ocfp) - (ra-pointer-valid-p c-ra)) - ;; Look forward another step to check their validity. - (let ((lisp-ok (handle lisp-ocfp)) - (c-ok (handle c-ocfp))) - (cond ((and lisp-ok c-ok) - ;; Both still seem valid - choose the lisp frame. - #!+freebsd - (if (sap> lisp-ocfp c-ocfp) - (values t lisp-ra lisp-ocfp) - (values t c-ra c-ocfp)) - #!-freebsd - (values t lisp-ra lisp-ocfp)) - (lisp-ok - ;; The lisp convention is looking good. - (values t lisp-ra lisp-ocfp)) - (c-ok - ;; The C convention is looking good. - (values t c-ra c-ocfp)) - (t - ;; Neither seems right? - (fail))))) - ((and (sap> lisp-ocfp fp) - (control-stack-pointer-valid-p lisp-ocfp) - (ra-pointer-valid-p lisp-ra)) - ;; The lisp convention is looking good. - (values t lisp-ra lisp-ocfp)) - ((and (sap> c-ocfp fp) - (control-stack-pointer-valid-p c-ocfp) - #!-linux (ra-pointer-valid-p c-ra)) - ;; The C convention is looking good. - (values t c-ra c-ocfp)) - (t - (fail)))))))) - (handle fp))) + (let ((ocfp (sap-ref-sap fp (sb!vm::frame-byte-offset ocfp-save-offset))) + (ra (sap-ref-sap fp (sb!vm::frame-byte-offset return-pc-save-offset)))) + (if (and (control-stack-pointer-valid-p fp) + (sap> ocfp fp) + (control-stack-pointer-valid-p ocfp) + (ra-pointer-valid-p ra)) + (values t ra ocfp) + (values nil (int-sap 0) (int-sap 0))))) ) ; #+x86 PROGN @@ -746,8 +699,7 @@ (#.ocfp-save-offset (stack-ref pointer stack-slot)) (#.lra-save-offset - (sap-ref-sap pointer (- (* (1+ stack-slot) - sb!vm::n-word-bytes)))))))) + (sap-ref-sap pointer (sb!vm::frame-byte-offset stack-slot))))))) (defun (setf get-context-value) (value frame stack-slot loc) (declare (type compiled-frame frame) (type unsigned-byte stack-slot) @@ -763,8 +715,8 @@ (#.ocfp-save-offset (setf (stack-ref pointer stack-slot) value)) (#.lra-save-offset - (setf (sap-ref-sap pointer (- (* (1+ stack-slot) - sb!vm::n-word-bytes))) value)))))) + (setf (sap-ref-sap pointer (sb!vm::frame-byte-offset stack-slot)) + value)))))) (defun foreign-function-backtrace-name (sap) (let ((name (sap-foreign-symbol sap))) @@ -2102,8 +2054,9 @@ register." ,@body)) (stack-frame-offset (data-width offset) #!+(or x86 x86-64) - `(- (* (+ (sb!c:sc-offset-offset sc-offset) ,data-width ,offset) - sb!vm:n-word-bytes)) + `(sb!vm::frame-byte-offset (+ (sb!c:sc-offset-offset sc-offset) + (1- ,data-width) + ,offset)) #!-(or x86 x86-64) (declare (ignore data-width)) #!-(or x86 x86-64) @@ -2289,8 +2242,9 @@ register." ,@body)) (stack-frame-offset (data-width offset) #!+(or x86 x86-64) - `(- (* (+ (sb!c:sc-offset-offset sc-offset) ,data-width ,offset) - sb!vm:n-word-bytes)) + `(sb!vm::frame-byte-offset (+ (sb!c:sc-offset-offset sc-offset) + (1- ,data-width) + ,offset)) #!-(or x86 x86-64) (declare (ignore data-width)) #!-(or x86 x86-64) diff --git a/src/compiler/x86-64/call.lisp b/src/compiler/x86-64/call.lisp index 13a4511..2e07954 100644 --- a/src/compiler/x86-64/call.lisp +++ b/src/compiler/x86-64/call.lisp @@ -143,7 +143,8 @@ (inst lea rsp-tn (make-ea :qword :base rbp-tn :disp (- (* n-word-bytes - (max 3 (sb-allocated-size 'stack))))))) + (- (max 3 (sb-allocated-size 'stack)) + sp->fp-offset)))))) (trace-table-entry trace-table-normal))) @@ -151,12 +152,13 @@ ;;; or a multiple-call-local. All it does is allocate stack space for the ;;; callee (who has the same size stack as us). (define-vop (allocate-frame) - (:results (res :scs (any-reg control-stack)) + (:results (res :scs (any-reg)) (nfp)) (:info callee) (:ignore nfp callee) (:generator 2 - (move res rsp-tn) + (inst lea res (make-ea :qword :base rsp-tn + :disp (- (* sp->fp-offset n-word-bytes)))) (inst sub rsp-tn (* n-word-bytes (sb-allocated-size 'stack))))) ;;; Allocate a partial frame for passing stack arguments in a full @@ -165,9 +167,10 @@ ;;; before it can extend the stack. (define-vop (allocate-full-call-frame) (:info nargs) - (:results (res :scs (any-reg control-stack))) + (:results (res :scs (any-reg))) (:generator 2 - (move res rsp-tn) + (inst lea res (make-ea :qword :base rsp-tn + :disp (- (* sp->fp-offset n-word-bytes)))) (inst sub rsp-tn (* (max nargs 3) n-word-bytes)))) ;;; Emit code needed at the return-point from an unknown-values call @@ -256,12 +259,12 @@ (when first-stack-arg-p ;; There are stack args so the frame of the callee is ;; still there, save RDX in its first slot temporalily. - (storew rdx-tn rbx-tn -1)) - (loadw rdx-tn rbx-tn (frame-word-offset i)) + (storew rdx-tn rbx-tn (frame-word-offset sp->fp-offset))) + (loadw rdx-tn rbx-tn (frame-word-offset (+ sp->fp-offset i))) (inst mov tn rdx-tn))) (emit-label defaulting-done) - (loadw rdx-tn rbx-tn -1) + (loadw rdx-tn rbx-tn (frame-word-offset sp->fp-offset)) (move rsp-tn rbx-tn) (let ((defaults (defaults))) @@ -315,7 +318,7 @@ ;; and then default the remaining stack arguments. (emit-label regs-defaulted) ;; Save EDI. - (storew rdi-tn rbx-tn (frame-word-offset 1)) + (storew rdi-tn rbx-tn (frame-word-offset (+ sp->fp-offset 1))) ;; Compute the number of stack arguments, and if it's zero or ;; less, don't copy any stack arguments. (inst sub rcx-tn (fixnumize register-arg-count)) @@ -333,17 +336,18 @@ (make-ea :qword :base rbp-tn :disp (frame-byte-offset register-arg-count))) ;; Save ESI, and compute a pointer to where the args come from. - (storew rsi-tn rbx-tn (frame-word-offset 2)) + (storew rsi-tn rbx-tn (frame-word-offset (+ sp->fp-offset 2))) (inst lea rsi-tn (make-ea :qword :base rbx-tn - :disp (frame-byte-offset register-arg-count))) + :disp (frame-byte-offset + (+ sp->fp-offset register-arg-count)))) ;; Do the copy. (inst shr rcx-tn word-shift) ; make word count (inst std) (inst rep) (inst movs :qword) ;; Restore RSI. - (loadw rsi-tn rbx-tn (frame-word-offset 2)) + (loadw rsi-tn rbx-tn (frame-word-offset (+ sp->fp-offset 2))) ;; Now we have to default the remaining args. Find out how many. (inst sub rax-tn (fixnumize (- nvals register-arg-count))) (inst neg rax-tn) @@ -359,7 +363,7 @@ (inst stos rax-tn) ;; Restore EDI, and reset the stack. (emit-label restore-edi) - (loadw rdi-tn rbx-tn (frame-word-offset 1)) + (loadw rdi-tn rbx-tn (frame-word-offset (+ sp->fp-offset 1))) (inst mov rsp-tn rbx-tn) (inst cld)))) (values)) @@ -611,9 +615,7 @@ (check-ocfp-and-return-pc old-fp return-pc) (trace-table-entry trace-table-fun-epilogue) ;; Zot all of the stack except for the old-fp and return-pc. - (inst lea rsp-tn - (make-ea :qword :base rbp-tn - :disp (frame-byte-offset ocfp-save-offset))) + (inst mov rsp-tn rbp-tn) (inst pop rbp-tn) (inst ret) (trace-table-entry trace-table-normal))) @@ -815,6 +817,10 @@ ,(if variable '(inst sub rsp-tn (fixnumize 3))) + ;; Bias the new-fp for use as an fp + ,(if variable + '(inst sub new-fp (fixnumize sp->fp-offset))) + ;; Save the fp (storew rbp-tn new-fp (frame-word-offset ocfp-save-offset)) @@ -899,8 +905,7 @@ (check-ocfp-and-return-pc old-fp return-pc) (trace-table-entry trace-table-fun-epilogue) ;; Drop stack above old-fp - (inst lea rsp-tn (make-ea :qword :base rbp-tn - :disp (frame-byte-offset (tn-offset old-fp)))) + (inst mov rsp-tn rbp-tn) ;; Clear the multiple-value return flag (inst clc) ;; Restore the old frame pointer @@ -942,18 +947,11 @@ (error "nvalues is 1")) (trace-table-entry trace-table-fun-epilogue) ;; Establish the values pointer and values count. - (move rbx rbp-tn) + (inst lea rbx (make-ea :qword :base rbp-tn + :disp (* sp->fp-offset n-word-bytes))) (if (zerop nvals) (zeroize rcx) ; smaller (inst mov rcx (fixnumize nvals))) - ;; Clear as much of the stack as possible, but not past the old - ;; frame address. - (inst lea rsp-tn - (make-ea :qword :base rbx - :disp (frame-byte-offset - (if (< register-arg-count nvals) - (1- nvals) - ocfp-save-offset)))) ;; Pre-default any argument register that need it. (when (< nvals register-arg-count) (let* ((arg-tns (nthcdr nvals (list a0 a1 a2))) @@ -967,15 +965,24 @@ ;; stack and we've changed the stack pointer. So we have to ;; tell it to index off of RBX instead of RBP. (cond ((<= nvals register-arg-count) + (inst mov rsp-tn rbp-tn) (inst pop rbp-tn) (inst ret)) (t ;; Some values are on the stack after RETURN-PC and OLD-FP, ;; can't return normally and some slots of the frame will ;; be used as temporaries by the receiver. + ;; + ;; Clear as much of the stack as possible, but not past the + ;; old frame address. + (inst lea rsp-tn + (make-ea :qword :base rbp-tn + :disp (frame-byte-offset (1- nvals)))) (move rbp-tn old-fp) (inst push (make-ea :qword :base rbx - :disp (frame-byte-offset (tn-offset return-pc)))) + :disp (frame-byte-offset + (+ sp->fp-offset + (tn-offset return-pc))))) (inst ret))) (trace-table-entry trace-table-normal))) @@ -987,8 +994,6 @@ ;;; assembly-routine. ;;; ;;; The assembly routine takes the following args: -;;; RAX -- the return-pc to finally jump to. -;;; RBX -- pointer to where to put the values. ;;; RCX -- number of values to find there. ;;; RSI -- pointer to where to find the values. (define-vop (return-multiple) @@ -1012,8 +1017,8 @@ (inst jmp :ne not-single) ;; Return with one value. (loadw a0 vals -1) - (inst lea rsp-tn (make-ea :qword :base rbp-tn - :disp (frame-byte-offset ocfp-save-offset))) + ;; Clear the stack until ocfp. + (inst mov rsp-tn rbp-tn) ;; clear the multiple-value return flag (inst clc) ;; Out of here. @@ -1064,11 +1069,11 @@ (inst jmp :be JUST-ALLOC-FRAME))) ;; Allocate the space on the stack. - ;; stack = rbp - (max 3 frame-size) - (nargs - fixed) + ;; stack = rbp + sp->fp-offset - (max 3 frame-size) - (nargs - fixed) (inst lea rbx-tn (make-ea :qword :base rbp-tn - :disp (- (fixnumize fixed) - (* n-word-bytes + :disp (* n-word-bytes + (- (+ sp->fp-offset fixed) (max 3 (sb-allocated-size 'stack)))))) (inst sub rbx-tn rcx-tn) ; Got the new stack in rbx (inst mov rsp-tn rbx-tn) @@ -1090,7 +1095,8 @@ (inst sub rcx-tn (fixnumize fixed)))) ;; Initialize R8 to be the end of args. - (inst mov source rbp-tn) + (inst lea source (make-ea :qword :base rbp-tn + :disp (* sp->fp-offset n-word-bytes))) (inst sub source rbx-tn) ;; We need to copy from downwards up to avoid overwriting some of @@ -1120,9 +1126,12 @@ ( nil ) ;; Store it relative to rbp (inst mov (make-ea :qword :base rbp-tn - :disp (- (* n-word-bytes - (+ 1 (- i fixed) - (max 3 (sb-allocated-size 'stack)))))) + :disp (* n-word-bytes + (- sp->fp-offset + (+ 1 + (- i fixed) + (max 3 (sb-allocated-size + 'stack)))))) (nth i *register-arg-tns*)) (incf i) @@ -1140,7 +1149,8 @@ JUST-ALLOC-FRAME (inst lea rsp-tn (make-ea :qword :base rbp-tn - :disp (- (* n-word-bytes + :disp (* n-word-bytes + (- sp->fp-offset (max 3 (sb-allocated-size 'stack)))))) DONE)) diff --git a/src/compiler/x86-64/char.lisp b/src/compiler/x86-64/char.lisp index 8e92290..b70458c 100644 --- a/src/compiler/x86-64/char.lisp +++ b/src/compiler/x86-64/char.lisp @@ -110,14 +110,14 @@ (character-stack #!-sb-unicode (inst mov - ;; FIXME: naked 8 (should be... what? n-register-bytes? - ;; n-word-bytes? Dunno. - (make-ea :byte :base fp :disp (- (* (1+ (tn-offset y)) 8))) + ;; XXX: If the sb-unicode case needs to handle c-call, + ;; why does the non-unicode case not need to? + (make-ea :byte :base fp :disp (frame-byte-offset (tn-offset y))) x) #!+sb-unicode (if (= (tn-offset fp) esp-offset) - (storew x fp (tn-offset y)) ; c-call - (storew x fp (- (1+ (tn-offset y))))))))) + (storew x fp (tn-offset y)) ; c-call + (storew x fp (frame-word-offset (tn-offset y)))))))) (define-move-vop move-character-arg :move-arg (any-reg character-reg) (character-reg)) diff --git a/src/compiler/x86-64/debug.lisp b/src/compiler/x86-64/debug.lisp index 5ab67c6..5f720fe 100644 --- a/src/compiler/x86-64/debug.lisp +++ b/src/compiler/x86-64/debug.lisp @@ -43,7 +43,7 @@ (move temp offset) (inst neg temp) (inst mov result - (make-ea :qword :base sap :disp (- n-word-bytes) :index temp)))) + (make-ea :qword :base sap :disp (frame-byte-offset 0) :index temp)))) (define-vop (read-control-stack-c) (:translate stack-ref) @@ -55,7 +55,7 @@ (:result-types *) (:generator 5 (inst mov result (make-ea :qword :base sap - :disp (- (* (1+ index) n-word-bytes)))))) + :disp (frame-byte-offset index))))) (define-vop (write-control-stack) (:translate %set-stack-ref) @@ -71,7 +71,8 @@ (move temp offset) (inst neg temp) (inst mov - (make-ea :qword :base sap :disp (- n-word-bytes) :index temp) value) + (make-ea :qword :base sap :disp (frame-byte-offset 0) :index temp) + value) (move result value))) (define-vop (write-control-stack-c) @@ -84,8 +85,7 @@ (:results (result :scs (descriptor-reg))) (:result-types *) (:generator 5 - (inst mov (make-ea :qword :base sap - :disp (- (* (1+ index) n-word-bytes))) + (inst mov (make-ea :qword :base sap :disp (frame-byte-offset index)) value) (move result value))) diff --git a/src/compiler/x86-64/float.lisp b/src/compiler/x86-64/float.lisp index b642b5c..23eef99 100644 --- a/src/compiler/x86-64/float.lisp +++ b/src/compiler/x86-64/float.lisp @@ -32,8 +32,7 @@ (declare (ignore kind)) `(make-ea :qword :base rbp-tn - :disp (- (* (+ (tn-offset ,tn) 1) - n-word-bytes))))) + :disp (frame-byte-offset (tn-offset ,tn))))) (defun ea-for-sf-stack (tn) (ea-for-xf-stack tn :single)) (defun ea-for-df-stack (tn) @@ -44,9 +43,14 @@ (declare (ignore kind)) `(make-ea :qword :base ,base - :disp (- (* (+ (tn-offset ,tn) - (* 1 (ecase ,slot (:real 1) (:imag 2)))) - n-word-bytes))))) + :disp (frame-byte-offset + (+ (tn-offset ,tn) + (cond ((= (tn-offset ,base) rsp-offset) + sp->fp-offset) + ((= (tn-offset ,base) rbp-offset) + 0) + (t (error "Unexpected offset."))) + (ecase ,slot (:real 0) (:imag 1))))))) (defun ea-for-csf-real-stack (tn &optional (base rbp-tn)) (ea-for-cxf-stack tn :single :real base)) (defun ea-for-csf-imag-stack (tn &optional (base rbp-tn)) @@ -326,8 +330,7 @@ (:double '((inst movsd ea x))))) (let ((ea (make-ea :dword :base fp - :disp (- (* (1+ (tn-offset y)) - n-word-bytes))))) + :disp (frame-byte-offset (tn-offset y))))) ,@(ecase format (:single '((inst movss ea x))) (:double '((inst movsd ea x)))))))))) @@ -728,7 +731,7 @@ (inst movsd temp float) (move hi-bits temp)) (double-stack - (loadw hi-bits ebp-tn (- (1+ (tn-offset float))))) + (loadw hi-bits ebp-tn (frame-word-offset (tn-offset float)))) (descriptor-reg (loadw hi-bits float double-float-value-slot other-pointer-lowtag))) @@ -750,7 +753,7 @@ (inst movsd temp float) (move lo-bits temp)) (double-stack - (loadw lo-bits ebp-tn (- (1+ (tn-offset float))))) + (loadw lo-bits ebp-tn (frame-word-offset (tn-offset float)))) (descriptor-reg (loadw lo-bits float double-float-value-slot other-pointer-lowtag))) diff --git a/src/compiler/x86-64/insts.lisp b/src/compiler/x86-64/insts.lisp index fdf8ad7..ae0f2b8 100644 --- a/src/compiler/x86-64/insts.lisp +++ b/src/compiler/x86-64/insts.lisp @@ -1234,7 +1234,7 @@ (emit-mod-reg-r/m-byte segment #b11 reg (reg-tn-encoding thing))) (stack ;; Convert stack tns into an index off RBP. - (let ((disp (- (* (1+ (tn-offset thing)) n-word-bytes)))) + (let ((disp (frame-byte-offset (tn-offset thing)))) (cond ((<= -128 disp 127) (emit-mod-reg-r/m-byte segment #b01 reg #b101) (emit-byte segment disp)) diff --git a/src/compiler/x86-64/move.lisp b/src/compiler/x86-64/move.lisp index 4f37f5a..cd6642b 100644 --- a/src/compiler/x86-64/move.lisp +++ b/src/compiler/x86-64/move.lisp @@ -187,19 +187,19 @@ ;; Lisp stack (etypecase val (integer - (storew (fixnumize val) fp (- (1+ (tn-offset y))))) + (storew (fixnumize val) fp (frame-word-offset (tn-offset y)))) (symbol (storew (+ nil-value (static-symbol-offset val)) - fp (- (1+ (tn-offset y))))) + fp (frame-word-offset (tn-offset y)))) (character (storew (logior (ash (char-code val) n-widetag-bits) character-widetag) - fp (- (1+ (tn-offset y)))))))) + fp (frame-word-offset (tn-offset y))))))) (if (= (tn-offset fp) esp-offset) ;; C-call (storew x fp (tn-offset y)) ;; Lisp stack - (storew x fp (- (1+ (tn-offset y)))))))))) + (storew x fp (frame-word-offset (tn-offset y))))))))) (define-move-vop move-arg :move-arg (any-reg descriptor-reg) @@ -405,7 +405,7 @@ ((signed-stack unsigned-stack) (if (= (tn-offset fp) esp-offset) (storew x fp (tn-offset y)) ; c-call - (storew x fp (- (1+ (tn-offset y))))))))) + (storew x fp (frame-word-offset (tn-offset y)))))))) (define-move-vop move-word-arg :move-arg (descriptor-reg any-reg signed-reg unsigned-reg) (signed-reg unsigned-reg)) diff --git a/src/compiler/x86-64/nlx.lisp b/src/compiler/x86-64/nlx.lisp index dd31d2a..4cc02fd 100644 --- a/src/compiler/x86-64/nlx.lisp +++ b/src/compiler/x86-64/nlx.lisp @@ -24,7 +24,7 @@ (defun catch-block-ea (tn) (aver (sc-is tn catch-block)) (make-ea :qword :base rbp-tn - :disp (- (* (+ (tn-offset tn) catch-block-size) n-word-bytes)))) + :disp (frame-byte-offset (+ -1 (tn-offset tn) catch-block-size)))) ;;;; Save and restore dynamic environment. @@ -168,9 +168,10 @@ (storew rdx-tn rbx-tn -1)) (sc-case tn ((descriptor-reg any-reg) - (loadw tn start (frame-word-offset i))) + (loadw tn start (frame-word-offset (+ sp->fp-offset i)))) ((control-stack) - (loadw move-temp start (frame-word-offset i)) + (loadw move-temp start + (frame-word-offset (+ sp->fp-offset i))) (inst mov tn move-temp))))) (let ((defaulting-done (gen-label))) (emit-label defaulting-done) @@ -277,7 +278,8 @@ ;; Clear the stack (inst lea rsp-tn - (make-ea :qword :base rbp-tn :disp (* -3 n-word-bytes))) + (make-ea :qword :base rbp-tn + :disp (* (- sp->fp-offset 3) n-word-bytes))) ;; Push the return-pc so it looks like we just called. (pushw rbp-tn (frame-word-offset return-pc-save-offset)) diff --git a/src/compiler/x86-64/sap.lisp b/src/compiler/x86-64/sap.lisp index 9177094..02aba44 100644 --- a/src/compiler/x86-64/sap.lisp +++ b/src/compiler/x86-64/sap.lisp @@ -65,7 +65,7 @@ (sap-stack (if (= (tn-offset fp) esp-offset) (storew x fp (tn-offset y)) ; c-call - (storew x fp (- (1+ (tn-offset y))))))))) + (storew x fp (frame-word-offset (tn-offset y)))))))) (define-move-vop move-sap-arg :move-arg (descriptor-reg sap-reg) (sap-reg)) diff --git a/src/compiler/x86-64/static-fn.lisp b/src/compiler/x86-64/static-fn.lisp index ee2baea..e0b76ca 100644 --- a/src/compiler/x86-64/static-fn.lisp +++ b/src/compiler/x86-64/static-fn.lisp @@ -16,9 +16,6 @@ (:policy :safe) (:variant-vars function) (:vop-var vop) - ;;(:node-var node) - (:temporary (:sc unsigned-reg :offset ebx-offset - :from (:eval 0) :to (:eval 2)) ebx) (:temporary (:sc unsigned-reg :offset ecx-offset :from (:eval 0) :to (:eval 2)) ecx)) @@ -41,7 +38,8 @@ (<= num-results register-arg-count)) (error "either too many args (~W) or too many results (~W); max = ~W" num-args num-results register-arg-count)) - (let ((num-temps (max num-args num-results))) + (let ((num-temps (max num-args num-results)) + (node (gensym "NODE-"))) (collect ((temp-names) (temps) (arg-names) (args) (result-names) (results)) (dotimes (i num-results) (let ((result-name (intern (format nil "RESULT-~D" i)))) @@ -73,28 +71,30 @@ ,@(temps) (:temporary (:sc unsigned-reg) call-target) (:results ,@(results)) + (:node-var ,node) (:generator ,(+ 50 num-args num-results) ,@(moves (temp-names) (arg-names)) - ;; If speed not more important than size, duplicate the + ;; If speed is at least as important as size, duplicate the ;; effect of the ENTER with discrete instructions. Takes - ;; 2+1+3+2=8 bytes as opposed to 4+3=7 bytes. - (cond (t ;(policy node (>= speed space)) - (inst mov ebx rsp-tn) - ;; Dummy for return address + ;; 3+4+4=11 bytes as opposed to 1+4=5 bytes. + (cond ((policy ,node (>= speed space)) + (inst sub rsp-tn (fixnumize 3)) + (inst mov (make-ea :qword :base rsp-tn + :disp (frame-byte-offset + (+ sp->fp-offset + -3 + ocfp-save-offset))) + rbp-tn) + (inst lea rbp-tn (make-ea :qword :base rsp-tn + :disp (frame-byte-offset + (+ sp->fp-offset + -3 + ocfp-save-offset))))) + (t + ;; Dummy for return address. (inst push rbp-tn) - ;; Save the old-fp - (inst push rbp-tn) - ;; Ensure that at least three slots are available; one - ;; above, two more needed. - (inst sub rsp-tn (fixnumize 1)) - (inst mov rbp-tn ebx)) - #+(or) (t - (inst enter (fixnumize 2)) - ;; The enter instruction pushes EBP and then copies - ;; ESP into EBP. We want the new EBP to be the - ;; original ESP, so we fix it up afterwards. - (inst add rbp-tn (fixnumize 1)))) + (inst enter (fixnumize 1)))) ,(if (zerop num-args) '(inst xor ecx ecx) diff --git a/src/compiler/x86-64/type-vops.lisp b/src/compiler/x86-64/type-vops.lisp index 491444e..1298a5e 100644 --- a/src/compiler/x86-64/type-vops.lisp +++ b/src/compiler/x86-64/type-vops.lisp @@ -20,7 +20,7 @@ (make-byte-tn value)) ((sc-is value control-stack) (make-ea :byte :base rbp-tn - :disp (- (* (1+ (tn-offset value)) n-word-bytes)))) + :disp (frame-byte-offset (tn-offset value)))) (t value)) sb!vm::fixnum-tag-mask)) diff --git a/src/compiler/x86-64/vm.lisp b/src/compiler/x86-64/vm.lisp index 405ca67..c946adb 100644 --- a/src/compiler/x86-64/vm.lisp +++ b/src/compiler/x86-64/vm.lisp @@ -445,14 +445,23 @@ ;;;; miscellaneous function call parameters -;;; offsets of special stack frame locations -(def!constant ocfp-save-offset 1) +;;; Offsets of special stack frame locations relative to RBP. +;;; +;;; Consider the standard prologue PUSH RBP; MOV RBP, RSP: the return +;;; address is at RBP+8, the old control stack frame pointer is at +;;; RBP, the magic 3rd slot is at RBP-8. Then come the locals from +;;; RBP-16 on. (def!constant return-pc-save-offset 0) +(def!constant ocfp-save-offset 1) (def!constant code-save-offset 2) +;;; Let SP be the stack pointer before CALLing, and FP is the frame +;;; pointer after the standard prologue. SP + +;;; FRAME-WORD-OFFSET(SP->FP-OFFSET + I) = FP + FRAME-WORD-OFFSET(I). +(def!constant sp->fp-offset 2) (declaim (inline frame-word-offset)) (defun frame-word-offset (index) - (- (1+ index))) + (- (1- index))) (declaim (inline frame-byte-offset)) (defun frame-byte-offset (index) diff --git a/src/compiler/x86/call.lisp b/src/compiler/x86/call.lisp index 7fcbed2..4d54c91 100644 --- a/src/compiler/x86/call.lisp +++ b/src/compiler/x86/call.lisp @@ -143,7 +143,8 @@ (inst lea esp-tn (make-ea :dword :base ebp-tn :disp (- (* n-word-bytes - (max 3 (sb-allocated-size 'stack))))))) + (- (max 3 (sb-allocated-size 'stack)) + sp->fp-offset)))))) (trace-table-entry trace-table-normal))) @@ -151,12 +152,13 @@ ;;; or a multiple-call-local. All it does is allocate stack space for the ;;; callee (who has the same size stack as us). (define-vop (allocate-frame) - (:results (res :scs (any-reg control-stack)) + (:results (res :scs (any-reg)) (nfp)) (:info callee) (:ignore nfp callee) (:generator 2 - (move res esp-tn) + (inst lea res (make-ea :dword :base esp-tn + :disp (- (* sp->fp-offset n-word-bytes)))) (inst sub esp-tn (* n-word-bytes (sb-allocated-size 'stack))))) ;;; Allocate a partial frame for passing stack arguments in a full @@ -165,9 +167,10 @@ ;;; before it can extend the stack. (define-vop (allocate-full-call-frame) (:info nargs) - (:results (res :scs (any-reg control-stack))) + (:results (res :scs (any-reg))) (:generator 2 - (move res esp-tn) + (inst lea res (make-ea :dword :base esp-tn + :disp (- (* sp->fp-offset n-word-bytes)))) (inst sub esp-tn (* (max nargs 3) n-word-bytes)))) ;;; Emit code needed at the return-point from an unknown-values call @@ -263,12 +266,12 @@ (when first-stack-arg-p ;; There are stack args so the frame of the callee is ;; still there, save EDX in its first slot temporalily. - (storew edx-tn ebx-tn -1)) - (loadw edx-tn ebx-tn (frame-word-offset i)) + (storew edx-tn ebx-tn (frame-word-offset sp->fp-offset))) + (loadw edx-tn ebx-tn (frame-word-offset (+ sp->fp-offset i))) (inst mov tn edx-tn))) (emit-label defaulting-done) - (loadw edx-tn ebx-tn -1) + (loadw edx-tn ebx-tn (frame-word-offset sp->fp-offset)) (move esp-tn ebx-tn) (let ((defaults (defaults))) @@ -323,7 +326,7 @@ ;; and then default the remaining stack arguments. (emit-label regs-defaulted) ;; Save EDI. - (storew edi-tn ebx-tn (frame-word-offset 1)) + (storew edi-tn ebx-tn (frame-word-offset (+ sp->fp-offset 1))) ;; Compute the number of stack arguments, and if it's zero or ;; less, don't copy any stack arguments. (inst sub ecx-tn (fixnumize register-arg-count)) @@ -341,17 +344,18 @@ (make-ea :dword :base ebp-tn :disp (frame-byte-offset register-arg-count))) ;; Save ESI, and compute a pointer to where the args come from. - (storew esi-tn ebx-tn (frame-word-offset 2)) + (storew esi-tn ebx-tn (frame-word-offset (+ sp->fp-offset 2))) (inst lea esi-tn (make-ea :dword :base ebx-tn - :disp (frame-byte-offset register-arg-count))) + :disp (frame-byte-offset + (+ sp->fp-offset register-arg-count)))) ;; Do the copy. (inst shr ecx-tn word-shift) ; make word count (inst std) (inst rep) (inst movs :dword) ;; Restore ESI. - (loadw esi-tn ebx-tn (frame-word-offset 2)) + (loadw esi-tn ebx-tn (frame-word-offset (+ sp->fp-offset 2))) ;; Now we have to default the remaining args. Find out how many. (inst sub eax-tn (fixnumize (- nvals register-arg-count))) (inst neg eax-tn) @@ -367,7 +371,7 @@ (inst stos eax-tn) ;; Restore EDI, and reset the stack. (emit-label restore-edi) - (loadw edi-tn ebx-tn (frame-word-offset 1)) + (loadw edi-tn ebx-tn (frame-word-offset (+ sp->fp-offset 1))) (inst mov esp-tn ebx-tn) (inst cld)))) (values)) @@ -616,9 +620,7 @@ (check-ocfp-and-return-pc old-fp return-pc) (trace-table-entry trace-table-fun-epilogue) ;; Zot all of the stack except for the old-fp and return-pc. - (inst lea esp-tn - (make-ea :dword :base ebp-tn - :disp (frame-byte-offset ocfp-save-offset))) + (inst mov esp-tn ebp-tn) (inst pop ebp-tn) (inst ret) (trace-table-entry trace-table-normal))) @@ -820,6 +822,10 @@ ,(if variable '(inst sub esp-tn (fixnumize 3))) + ;; Bias the new-fp for use as an fp + ,(if variable + '(inst sub new-fp (fixnumize sp->fp-offset))) + ;; Save the fp (storew ebp-tn new-fp (frame-word-offset ocfp-save-offset)) @@ -898,8 +904,7 @@ (check-ocfp-and-return-pc old-fp return-pc) (trace-table-entry trace-table-fun-epilogue) ;; Drop stack above old-fp - (inst lea esp-tn (make-ea :dword :base ebp-tn - :disp (frame-byte-offset (tn-offset old-fp)))) + (inst mov esp-tn ebp-tn) ;; Clear the multiple-value return flag (inst clc) ;; Restore the old frame pointer @@ -941,18 +946,11 @@ (error "nvalues is 1")) (trace-table-entry trace-table-fun-epilogue) ;; Establish the values pointer and values count. - (move ebx ebp-tn) + (inst lea ebx (make-ea :dword :base ebp-tn + :disp (* sp->fp-offset n-word-bytes))) (if (zerop nvals) (inst xor ecx ecx) ; smaller (inst mov ecx (fixnumize nvals))) - ;; Clear as much of the stack as possible, but not past the old - ;; frame address. - (inst lea esp-tn - (make-ea :dword :base ebx - :disp (frame-byte-offset - (if (< register-arg-count nvals) - (1- nvals) - ocfp-save-offset)))) ;; Pre-default any argument register that need it. (when (< nvals register-arg-count) (let* ((arg-tns (nthcdr nvals (list a0 a1 a2))) @@ -966,15 +964,24 @@ ;; stack and we've changed the stack pointer. So we have to ;; tell it to index off of EBX instead of EBP. (cond ((<= nvals register-arg-count) + (inst mov esp-tn ebp-tn) (inst pop ebp-tn) (inst ret)) (t ;; Some values are on the stack after RETURN-PC and OLD-FP, ;; can't return normally and some slots of the frame will ;; be used as temporaries by the receiver. + ;; + ;; Clear as much of the stack as possible, but not past the + ;; old frame address. + (inst lea esp-tn + (make-ea :dword :base ebp-tn + :disp (frame-byte-offset (1- nvals)))) (move ebp-tn old-fp) (inst push (make-ea :dword :base ebx - :disp (frame-byte-offset (tn-offset return-pc)))) + :disp (frame-byte-offset + (+ sp->fp-offset + (tn-offset return-pc))))) (inst ret))) (trace-table-entry trace-table-normal))) @@ -986,8 +993,6 @@ ;;; assembly-routine. ;;; ;;; The assembly routine takes the following args: -;;; EAX -- the return-pc to finally jump to. -;;; EBX -- pointer to where to put the values. ;;; ECX -- number of values to find there. ;;; ESI -- pointer to where to find the values. (define-vop (return-multiple) @@ -1010,8 +1015,8 @@ (inst jmp :ne not-single) ;; Return with one value. (loadw a0 vals -1) - (inst lea esp-tn (make-ea :dword :base ebp-tn - :disp (frame-byte-offset ocfp-save-offset))) + ;; Clear the stack until ocfp. + (inst mov esp-tn ebp-tn) ;; clear the multiple-value return flag (inst clc) ;; Out of here. @@ -1074,11 +1079,11 @@ (inst jmp :be JUST-ALLOC-FRAME))) ;; Allocate the space on the stack. - ;; stack = ebp - (max 3 frame-size) - (nargs - fixed) + ;; stack = ebp + sp->fp-offset - (max 3 frame-size) - (nargs - fixed) (inst lea ebx-tn (make-ea :dword :base ebp-tn - :disp (- (fixnumize fixed) - (* n-word-bytes + :disp (* n-word-bytes + (- (+ sp->fp-offset fixed) (max 3 (sb-allocated-size 'stack)))))) (inst sub ebx-tn ecx-tn) ; Got the new stack in ebx (inst mov esp-tn ebx-tn) @@ -1107,7 +1112,8 @@ ;; now. ;; Initialize src to be end of args. - (inst mov esi-tn ebp-tn) + (inst lea esi-tn (make-ea :dword :base ebp-tn + :disp (* sp->fp-offset n-word-bytes))) (inst sub esi-tn ebx-tn) ;; We need to copy from downwards up to avoid overwriting some of @@ -1139,33 +1145,37 @@ ;; Here: nargs>=1 && nargs>fixed (when (< fixed register-arg-count) - ;; Now we have to deposit any more args that showed up in - ;; registers. - (do ((i fixed)) - ( nil ) - ;; Store it relative to ebp - (inst mov (make-ea :dword :base ebp-tn - :disp (- (* n-word-bytes - (+ 1 (- i fixed) - (max 3 (sb-allocated-size 'stack)))))) - (nth i *register-arg-tns*)) - - (incf i) - (when (>= i register-arg-count) - (return)) - - ;; Don't deposit any more than there are. - (if (zerop i) - (inst test ecx-tn ecx-tn) - (inst cmp ecx-tn (fixnumize i))) - (inst jmp :eq DONE))) + ;; Now we have to deposit any more args that showed up in + ;; registers. + (do ((i fixed)) + ( nil ) + ;; Store it relative to ebp + (inst mov (make-ea :dword :base ebp-tn + :disp (* n-word-bytes + (- sp->fp-offset + (+ 1 + (- i fixed) + (max 3 (sb-allocated-size + 'stack)))))) + (nth i *register-arg-tns*)) + + (incf i) + (when (>= i register-arg-count) + (return)) + + ;; Don't deposit any more than there are. + (if (zerop i) + (inst test ecx-tn ecx-tn) + (inst cmp ecx-tn (fixnumize i))) + (inst jmp :eq DONE))) (inst jmp DONE) JUST-ALLOC-FRAME (inst lea esp-tn (make-ea :dword :base ebp-tn - :disp (- (* n-word-bytes + :disp (* n-word-bytes + (- sp->fp-offset (max 3 (sb-allocated-size 'stack)))))) DONE)) diff --git a/src/compiler/x86/debug.lisp b/src/compiler/x86/debug.lisp index 5bb80e1..823ee8f 100644 --- a/src/compiler/x86/debug.lisp +++ b/src/compiler/x86/debug.lisp @@ -71,7 +71,8 @@ (move temp offset) (inst neg temp) (inst mov - (make-ea :dword :base sap :disp (frame-byte-offset 0) :index temp) value) + (make-ea :dword :base sap :disp (frame-byte-offset 0) :index temp) + value) (move result value))) (define-vop (write-control-stack-c) @@ -84,8 +85,7 @@ (:results (result :scs (descriptor-reg))) (:result-types *) (:generator 5 - (inst mov (make-ea :dword :base sap - :disp (frame-byte-offset index)) + (inst mov (make-ea :dword :base sap :disp (frame-byte-offset index)) value) (move result value))) diff --git a/src/compiler/x86/nlx.lisp b/src/compiler/x86/nlx.lisp index 07d4032..96d2ca4 100644 --- a/src/compiler/x86/nlx.lisp +++ b/src/compiler/x86/nlx.lisp @@ -189,9 +189,10 @@ (storew edx-tn ebx-tn -1)) (sc-case tn ((descriptor-reg any-reg) - (loadw tn start (frame-word-offset i))) + (loadw tn start (frame-word-offset (+ sp->fp-offset i)))) ((control-stack) - (loadw move-temp start (frame-word-offset i)) + (loadw move-temp start + (frame-word-offset (+ sp->fp-offset i))) (inst mov tn move-temp))))) (let ((defaulting-done (gen-label))) (emit-label defaulting-done) @@ -296,7 +297,8 @@ ;; Clear the stack (inst lea esp-tn - (make-ea :dword :base ebp-tn :disp (* -3 n-word-bytes))) + (make-ea :dword :base ebp-tn + :disp (* (- sp->fp-offset 3) n-word-bytes))) ;; Push the return-pc so it looks like we just called. (pushw ebp-tn (frame-word-offset return-pc-save-offset)) diff --git a/src/compiler/x86/static-fn.lisp b/src/compiler/x86/static-fn.lisp index 675d204..6b9f03c 100644 --- a/src/compiler/x86/static-fn.lisp +++ b/src/compiler/x86/static-fn.lisp @@ -16,9 +16,6 @@ (:policy :safe) (:variant-vars function) (:vop-var vop) - ;;(:node-var node) - (:temporary (:sc unsigned-reg :offset ebx-offset - :from (:eval 0) :to (:eval 2)) ebx) (:temporary (:sc unsigned-reg :offset ecx-offset :from (:eval 0) :to (:eval 2)) ecx)) @@ -41,7 +38,8 @@ (<= num-results register-arg-count)) (error "either too many args (~W) or too many results (~W); max = ~W" num-args num-results register-arg-count)) - (let ((num-temps (max num-args num-results))) + (let ((num-temps (max num-args num-results)) + (node (gensym "NODE-"))) (collect ((temp-names) (temps) (arg-names) (args) (result-names) (results)) (dotimes (i num-results) (let ((result-name (intern (format nil "RESULT-~D" i)))) @@ -72,28 +70,30 @@ (:args ,@(args)) ,@(temps) (:results ,@(results)) + (:node-var ,node) (:generator ,(+ 50 num-args num-results) ,@(moves (temp-names) (arg-names)) - ;; If speed not more important than size, duplicate the + ;; If speed is at least as important as size, duplicate the ;; effect of the ENTER with discrete instructions. Takes - ;; 2+1+3+2=8 bytes as opposed to 4+3=7 bytes. - (cond (t ;(policy node (>= speed space)) - (inst mov ebx esp-tn) - ;; Dummy for return address + ;; 3+4+4=11 bytes as opposed to 1+4=5 bytes. + (cond ((policy ,node (>= speed space)) + (inst sub esp-tn (fixnumize 3)) + (inst mov (make-ea :dword :base esp-tn + :disp (frame-byte-offset + (+ sp->fp-offset + -3 + ocfp-save-offset))) + ebp-tn) + (inst lea ebp-tn (make-ea :dword :base esp-tn + :disp (frame-byte-offset + (+ sp->fp-offset + -3 + ocfp-save-offset))))) + (t + ;; Dummy for return address. (inst push ebp-tn) - ;; Save the old-fp - (inst push ebp-tn) - ;; Ensure that at least three slots are available; one - ;; above, two more needed. - (inst sub esp-tn (fixnumize 1)) - (inst mov ebp-tn ebx)) - #+(or) (t - (inst enter (fixnumize 2)) - ;; The enter instruction pushes EBP and then copies - ;; ESP into EBP. We want the new EBP to be the - ;; original ESP, so we fix it up afterwards. - (inst add ebp-tn (fixnumize 1)))) + (inst enter (fixnumize 1)))) ,(if (zerop num-args) '(inst xor ecx ecx) diff --git a/src/compiler/x86/vm.lisp b/src/compiler/x86/vm.lisp index 7b1f486..5313dc3 100644 --- a/src/compiler/x86/vm.lisp +++ b/src/compiler/x86/vm.lisp @@ -421,13 +421,22 @@ ;;;; miscellaneous function call parameters -;;; offsets of special stack frame locations -(def!constant ocfp-save-offset 1) +;;; Offsets of special stack frame locations relative to EBP. +;;; +;;; Consider the standard prologue PUSH EBP; MOV EBP, ESP: the return +;;; address is at EBP+4, the old control stack frame pointer is at +;;; EBP, the magic 3rd slot is at EBP-4. Then come the locals from +;;; EBP-8 on. (def!constant return-pc-save-offset 0) +(def!constant ocfp-save-offset 1) +;;; Let SP be the stack pointer before CALLing, and FP is the frame +;;; pointer after the standard prologue. SP + +;;; FRAME-WORD-OFFSET(SP->FP-OFFSET + I) = FP + FRAME-WORD-OFFSET(I). +(def!constant sp->fp-offset 2) (declaim (inline frame-word-offset)) (defun frame-word-offset (index) - (- (1+ index))) + (- (1- index))) (declaim (inline frame-byte-offset)) (defun frame-byte-offset (index) diff --git a/src/runtime/backtrace.c b/src/runtime/backtrace.c index ea53069..348d204 100644 --- a/src/runtime/backtrace.c +++ b/src/runtime/backtrace.c @@ -324,55 +324,21 @@ ra_pointer_p (void *ra) static int x86_call_context (void *fp, void **ra, void **ocfp) { - void *lisp_ocfp; - void *lisp_ra; void *c_ocfp; void *c_ra; - int lisp_valid_p, c_valid_p; + int c_valid_p; if (!stack_pointer_p(fp)) return 0; c_ocfp = *((void **) fp); c_ra = *((void **) fp + 1); - lisp_ocfp = *((void **) fp - 2); - lisp_ra = *((void **) fp - 1); - lisp_valid_p = (lisp_ocfp > fp - && stack_pointer_p(lisp_ocfp) - && ra_pointer_p(lisp_ra)); c_valid_p = (c_ocfp > fp && stack_pointer_p(c_ocfp) && ra_pointer_p(c_ra)); - if (lisp_valid_p && c_valid_p) { - void *lisp_path_fp; - void *c_path_fp; - void *dummy; - - int lisp_path_p = x86_call_context(lisp_ocfp, &lisp_path_fp, &dummy); - int c_path_p = x86_call_context(c_ocfp, &c_path_fp, &dummy); - - if (lisp_path_p && c_path_p) { -#if defined __FreeBSD__ && __FreeBSD_version > 400000 - if (lisp_ocfp > c_ocfp) - *ra = lisp_ra, *ocfp = lisp_ocfp; - else - *ra = c_ra, *ocfp = c_ocfp; -#else - *ra = lisp_ra, *ocfp = lisp_ocfp; -#endif - } - else if (lisp_path_p) - *ra = lisp_ra, *ocfp = lisp_ocfp; - else if (c_path_p) - *ra = c_ra, *ocfp = c_ocfp; - else - return 0; - } - else if (lisp_valid_p) - *ra = lisp_ra, *ocfp = lisp_ocfp; - else if (c_valid_p) + if (c_valid_p) *ra = c_ra, *ocfp = c_ocfp; else return 0; diff --git a/src/runtime/x86-64-assem.S b/src/runtime/x86-64-assem.S index 64f04ee..79140e0 100644 --- a/src/runtime/x86-64-assem.S +++ b/src/runtime/x86-64-assem.S @@ -209,11 +209,10 @@ Ldone: xor %rbx,%rbx # available /* Alloc new frame. */ - mov %rsp,%rbx # The current sp marks start of new frame. - push %rbp # dummy for return address - push %rbp # fp in save location S0 + push %rbp # Dummy for return address + push %rbp # fp in save location S1 + mov %rsp,%rbp # The current sp marks start of new frame. sub $8,%rsp # Ensure 3 slots are allocated, two above. - mov %rbx,%rbp # Switch to new frame. Lcall: call *CLOSURE_FUN_OFFSET(%rax) diff --git a/src/runtime/x86-assem.S b/src/runtime/x86-assem.S index 04c6031..37fcafa 100644 --- a/src/runtime/x86-assem.S +++ b/src/runtime/x86-assem.S @@ -272,11 +272,10 @@ Ldone: #endif /* Alloc new frame. */ - mov %esp,%ebx # The current sp marks start of new frame. - push %ebp # dummy for return address + push %ebp # Dummy for return address push %ebp # fp in save location S1 + mov %esp,%ebp # The current sp marks start of new frame. sub $4,%esp # Ensure 3 slots are allocated, two above. - mov %ebx,%ebp # Switch to new frame. call *CLOSURE_FUN_OFFSET(%eax) diff --git a/version.lisp-expr b/version.lisp-expr index c670ede..629910d 100644 --- a/version.lisp-expr +++ b/version.lisp-expr @@ -17,4 +17,4 @@ ;;; checkins which aren't released. (And occasionally for internal ;;; versions, especially for internal versions off the main CVS ;;; branch, it gets hairier, e.g. "0.pre7.14.flaky4.13".) -"1.0.27.13" +"1.0.27.14"