📄 c-call.lisp
字号:
;; broken. (if (/= 0 (rem in-words-processed words)) (progn (incf in-words-processed) (incf in-offset n-word-bytes))) (dotimes (k words) ;; Copy from memory to memory. (inst lwz r0 stack-pointer in-offset) (inst stw r0 stack-pointer out-offset) (incf out-words-processed) (incf out-offset n-word-bytes) (incf in-words-processed) (incf in-offset n-word-bytes))))) ;; The handling of floats is a little ugly ;; because we hard-code the number of words ;; for single- and double-floats. ((alien-single-float-type-p type) (let ((fpr (pop fprs))) (if fpr (inst stfs fpr stack-pointer out-offset) (progn ;; The ABI says that floats ;; stored on the stack are ;; promoted to doubles. gcc ;; stores them as floats. ;; Follow gcc here. ;; => no alignment needed either. (inst lfs f0 stack-pointer in-offset) (inst stfs f0 stack-pointer out-offset) (incf in-words-processed)))) (incf out-words-processed)) ((alien-double-float-type-p type) (let ((fpr (pop fprs))) (if fpr (inst stfd fpr stack-pointer out-offset) (progn ;; Ensure alignment. (if (oddp in-words-processed) (progn (incf in-words-processed) (incf in-offset n-word-bytes))) (inst lfd f0 stack-pointer in-offset) (inst stfd f0 stack-pointer out-offset) (incf in-words-processed 2)))) (incf out-words-processed 2)) (t (bug "Unknown alien floating point type: ~S" type)))))) (mapc #'save-arg argument-types (mapcar (lambda (arg) (ceiling (alien-type-bits arg) n-word-bits)) argument-types)) ;; Arranged the args, allocated the return area. Now ;; actuall call funcall3: funcall3 (call-alien-function, ;; index, args, return-area) (destructuring-bind (arg1 arg2 arg3 arg4) (mapcar #'make-gpr '(3 4 5 6)) (load-address-into arg1 (+ nil-value (static-symbol-offset 'sb!alien::*enter-alien-callback*))) (loadw arg1 arg1 symbol-value-slot other-pointer-lowtag) (inst li arg2 (fixnumize index)) (inst addi arg3 stack-pointer (- arg-store-pos)) (inst addi arg4 stack-pointer (- return-area-pos))) ;; Setup everything. Now save sp, setup the frame. (inst mflr r0) (inst stw r0 stack-pointer (* 2 n-word-bytes)) ; FIXME: magic ; constant, copied from Darwin. (inst stwu stack-pointer stack-pointer (- frame-size)) ;; And make the call. (load-address-into r0 (foreign-symbol-address "funcall3")) (inst mtlr r0) (inst blrl) ;; We're back! Restore sp and lr, load the ;; return value from just under sp, and return. (inst lwz stack-pointer stack-pointer 0) (inst lwz r0 stack-pointer (* 2 n-word-bytes)) (inst mtlr r0) (cond ((sb!alien::alien-single-float-type-p result-type) (let ((f1 (make-fpr 1))) (inst lfs f1 stack-pointer (- return-area-pos)))) ((sb!alien::alien-double-float-type-p result-type) (let ((f1 (make-fpr 1))) (inst lfd f1 stack-pointer (- return-area-pos)))) ((sb!alien::alien-void-type-p result-type) ;; Nothing to do ) (t (loop with gprs = (mapcar #'make-gpr '(3 4)) repeat n-return-area-words for gpr = (pop gprs) for offset from (- return-area-pos) by n-word-bytes do (unless gpr (bug "Out of return registers in alien-callback trampoline.")) (inst lwz gpr stack-pointer offset)))) (inst blr)))) (finalize-segment segment) ;; Now that the segment is done, convert it to a static ;; vector we can point foreign code to. (let* ((buffer (sb!assem::segment-buffer segment)) (vector (make-static-vector (length buffer) :element-type '(unsigned-byte 8) :initial-contents buffer)) (sap (sb!sys:vector-sap vector))) (sb!alien:alien-funcall (sb!alien:extern-alien "ppc_flush_icache" (function void system-area-pointer unsigned-long)) sap (length buffer)) vector)))) ;;; Returns a vector in static space containing machine code for the ;;; callback wrapper #!+darwin (defun alien-callback-assembler-wrapper (index result-type argument-types) (flet ((make-gpr (n) (make-random-tn :kind :normal :sc (sc-or-lose 'any-reg) :offset n)) (make-fpr (n) (make-random-tn :kind :normal :sc (sc-or-lose 'double-reg) :offset n))) (let* ((segment (make-segment))) (assemble (segment) ;; To save our arguments, we follow the algorithm sketched in the ;; "PowerPC Calling Conventions" section of that document. ;; ;; CLH: There are a couple problems here. First, we bail if ;; we run out of registers. AIUI, we can just ignore the extra ;; args here and we will be ok... (let ((words-processed 0) (gprs (mapcar #'make-gpr '(3 4 5 6 7 8 9 10))) (fprs (mapcar #'make-fpr '(1 2 3 4 5 6 7 8 9 10 11 12 13))) (stack-pointer (make-gpr 1))) (labels ((save-arg (type words) (let ((integerp (not (alien-float-type-p type))) (offset (+ (* words-processed n-word-bytes) n-foreign-linkage-area-bytes))) (cond (integerp (dotimes (k words) (let ((gpr (pop gprs))) (when gpr (inst stw gpr stack-pointer offset)) (incf words-processed) (incf offset n-word-bytes)))) ;; The handling of floats is a little ugly ;; because we hard-code the number of words ;; for single- and double-floats. ((alien-single-float-type-p type) (pop gprs) (let ((fpr (pop fprs))) (when fpr (inst stfs fpr stack-pointer offset))) (incf words-processed)) ((alien-double-float-type-p type) (setf gprs (cddr gprs)) (let ((fpr (pop fprs))) (when fpr (inst stfd fpr stack-pointer offset))) (incf words-processed 2)) (t (bug "Unknown alien floating point type: ~S" type)))))) (mapc #'save-arg argument-types (mapcar (lambda (arg) (ceiling (alien-type-bits arg) n-word-bits)) argument-types)))) ;; Set aside room for the return area just below sp, then ;; actually call funcall3: funcall3 (call-alien-function, ;; index, args, return-area) ;; ;; INDEX is fixnumized, ARGS and RETURN-AREA don't need to be ;; because they're word-aligned. Kinda gross, but hey ... (let* ((n-return-area-words (ceiling (or (alien-type-bits result-type) 0) n-word-bits)) (n-return-area-bytes (* n-return-area-words n-word-bytes)) ;; FIXME: magic constant, and probably n-args-bytes (args-size (* 3 n-word-bytes)) ;; FIXME: n-frame-bytes? (frame-size (logandc2 (+ n-foreign-linkage-area-bytes n-return-area-bytes args-size +stack-alignment-bytes+) +stack-alignment-bytes+))) (destructuring-bind (sp r0 arg1 arg2 arg3 arg4) (mapcar #'make-gpr '(1 0 3 4 5 6)) ;; FIXME: This is essentially the same code as LR in ;; insts.lisp, but attempting to use (INST LR ...) instead ;; of this function results in callbacks not working. Why? ;; --njf, 2006-01-04 (flet ((load-address-into (reg addr) (let ((high (ldb (byte 16 16) addr)) (low (ldb (byte 16 0) addr))) (inst lis reg high) (inst ori reg reg low)))) ;; Setup the args ;; CLH 2006/02/10 -Following JES' logic in ;; x86-64/c-call.lisp, we need to access ;; ENTER-ALIEN-CALLBACK through the symbol-value slot ;; of SB-ALIEN::*ENTER-ALIEN-CALLBACK* to ensure that ;; it works if GC moves ENTER-ALIEN-CALLBACK. ;; ;; old way: ;; (load-address-into arg1 (get-lisp-obj-address #'enter-alien-callback)) ;; new way: ;; (load-symbol arg1 'sb!alien::*enter-alien-callback*) ;; ;; whoops: can't use load-symbol here as null-tn might ;; not be loaded with the proper value as we are ;; coming in from C code. Use nil-value constant ;; instead, following the logic in x86-64/c-call.lisp. (load-address-into arg1 (+ nil-value (static-symbol-offset 'sb!alien::*enter-alien-callback*))) (loadw arg1 arg1 symbol-value-slot other-pointer-lowtag) (inst li arg2 (fixnumize index)) (inst addi arg3 sp n-foreign-linkage-area-bytes) ;; FIXME: This was (- (* RETURN-AREA-SIZE N-WORD-BYTES)), while ;; RETURN-AREA-SIZE was (* N-RETURN-AREA-WORDS N-WORD-BYTES): ;; I assume the intention was (- N-RETURN-AREA-BYTES), but who knows? ;; --NS 2005-06-11 (inst addi arg4 sp (- n-return-area-bytes)) ;; FIXME! FIXME FIXME: What does this FIXME refer to? ;; Save sp, setup the frame (inst mflr r0) (inst stw r0 sp (* 2 n-word-bytes)) ; FIXME: magic constant (inst stwu sp sp (- frame-size)) ;; Make the call (load-address-into r0 (foreign-symbol-address "funcall3")) (inst mtlr r0) (inst blrl)) ;; We're back! Restore sp and lr, load the return value from just ;; under sp, and return. (inst lwz sp sp 0) (inst lwz r0 sp (* 2 n-word-bytes)) (inst mtlr r0) (cond ((sb!alien::alien-single-float-type-p result-type) (let ((f1 (make-fpr 1))) (inst lfs f1 sp (- (* n-return-area-words n-word-bytes))))) ((sb!alien::alien-double-float-type-p result-type) (let ((f1 (make-fpr 1))) (inst lfd f1 sp (- (* n-return-area-words n-word-bytes))))) ((sb!alien::alien-void-type-p result-type) ;; Nothing to do ) (t (loop with gprs = (mapcar #'make-gpr '(3 4)) repeat n-return-area-words for gpr = (pop gprs) for offset from (- (* n-return-area-words n-word-bytes)) by n-word-bytes do (unless gpr (bug "Out of return registers in alien-callback trampoline.")) (inst lwz gpr sp offset)))) (inst blr)))) (finalize-segment segment) ;; Now that the segment is done, convert it to a static ;; vector we can point foreign code to. (let* ((buffer (sb!assem::segment-buffer segment)) (vector (make-static-vector (length buffer) :element-type '(unsigned-byte 8) :initial-contents buffer)) (sap (sb!sys:vector-sap vector))) (sb!alien:alien-funcall (sb!alien:extern-alien "ppc_flush_icache" (function void system-area-pointer unsigned-long)) sap (length buffer)) vector)))))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -