0.9.2.26: refactoring internals of foreign linkage
[sbcl.git] / src / compiler / ppc / c-call.lisp
index 1942ef5..a8fedc8 100644 (file)
 
 #!+darwin
 (deftransform %alien-funcall ((function type &rest args))
-  (assert (sb!c::constant-lvar-p type))
+  (aver (sb!c::constant-lvar-p type))
   (let* ((type (sb!c::lvar-value type))
         (arg-types (alien-fun-type-arg-types type))
         (result-type (alien-fun-type-result-type type)))
-    (assert (= (length arg-types) (length args)))
+    (aver (= (length arg-types) (length args)))
     ;; We need to do something special for 64-bit integer arguments
     ;; and results.
     (if (or (some #'(lambda (type)
                           ,@(new-args))))))
        (sb!c::give-up-ir1-transform))))
 
-(define-vop (foreign-symbol-address)
-  (:translate foreign-symbol-address)
+(define-vop (foreign-symbol-sap)
+  (:translate foreign-symbol-sap)
   (:policy :fast-safe)
   (:args)
   (:arg-types (:constant simple-string))
   (:results (res :scs (sap-reg)))
   (:result-types system-area-pointer)
   (:generator 2
-    (inst lr res  (make-fixup (extern-alien-name foreign-symbol) :foreign))))
+    (inst lr res  (make-fixup foreign-symbol :foreign))))
 
 #!+linkage-table
-(define-vop (foreign-symbol-dataref-address)
-  (:translate foreign-symbol-dataref-address)
+(define-vop (foreign-symbol-dataref-sap)
+  (:translate foreign-symbol-dataref-sap)
   (:policy :fast-safe)
   (:args)
   (:arg-types (:constant simple-string))
   (:result-types system-area-pointer)
   (:temporary (:scs (non-descriptor-reg)) addr)
   (:generator 2
-    (inst lr addr (make-fixup (extern-alien-name foreign-symbol)
-                              :foreign-dataref))
+    (inst lr addr (make-fixup foreign-symbol :foreign-dataref))
     (loadw res addr)))
 
 (define-vop (call-out)
     (let ((cur-nfp (current-nfp-tn vop)))
       (when cur-nfp
        (store-stack-tn nfp-save cur-nfp))
-      (inst lr temp (make-fixup (extern-alien-name "call_into_c") :foreign))
+      (inst lr temp (make-fixup "call_into_c" :foreign))
       (inst mtctr temp)
       (move cfunc function)
       (inst bctrl)
               (inst addi nsp-tn nsp-tn delta))
              (t
               (inst lwz nsp-tn nsp-tn 0)))))))
+
+#-sb-xc-host
+(progn
+  (defun alien-callback-accessor-form (type sap offset)
+    ;; Unaligned access is slower, but possible, so this is nice and simple.
+    `(deref (sap-alien (sap+ ,sap ,offset) (* ,type))))
+
+  ;;; The "Mach-O Runtime Conventions" document for OS X almost specifies
+  ;;; the calling convention (it neglects to mention that the linkage
+  ;;; area is 24 bytes).
+  (defconstant n-foreign-linkage-area-bytes 24)
+
+  ;;; Returns a vector in static space containing machine code for the
+  ;;; callback wrapper
+  (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.
+         (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 ((out-of-registers-error ()
+                      (error "Too many arguments in callback"))
+                    (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
+                               (loop repeat words
+                                  for gpr = (pop gprs)
+                                  do 
+                                    (if gpr
+                                        (inst stw gpr stack-pointer offset)
+                                        (out-of-registers-error))
+                                    (incf words-processed)))
+                            ;; 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)))
+                                 (if fpr
+                                     (inst stfs fpr stack-pointer offset)
+                                     (out-of-registers-error)))
+                               (incf words-processed))
+                              ((alien-double-float-type-p type)
+                               (setf gprs (cddr gprs))
+                               (let ((fpr (pop fprs)))
+                                 (if fpr
+                                     (inst stfd fpr stack-pointer offset)
+                                     (out-of-registers-error)))
+                               (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 
+                 (+ n-foreign-linkage-area-bytes n-return-area-bytes args-size)))
+           (destructuring-bind (sp r0 arg1 arg2 arg3 arg4)
+               (mapcar #'make-gpr '(1 0 3 4 5 6))
+             (flet ((load-address-into (reg addr)
+                      (let ((high (ldb (byte 16 16) addr))
+                            (low (ldb (byte 16 0) addr)))
+                        (inst li reg high)
+                        (inst slwi reg reg 16)
+                        (inst ori reg reg low))))
+               ;; Setup the args
+               (load-address-into 
+                arg1 (get-lisp-obj-address #'enter-alien-callback))
+               (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)
+             (loop with gprs = (mapcar #'make-gpr '(3 4))
+                repeat n-return-area-words
+                for gpr = (pop gprs)
+                for offset downfrom (- 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)))
+         (make-static-vector (length buffer)
+                             :element-type '(unsigned-byte 8)
+                             :initial-contents buffer))))))
+  
\ No newline at end of file