July 2005
These details were kindly provided by Duane Rettig of Franz.

Regarding the following snippet of the macro expansion of
FF:DEF-FOREIGN-CALL:

  (SYSTEM::FF-FUNCALL
    (LOAD-TIME-VALUE (EXCL::DETERMINE-FOREIGN-ADDRESS
                      '("foo" :LANGUAGE :C)  2 NIL))
    '(:INT (INTEGER * *)) ARG1
    '(:DOUBLE (DOUBLE-FLOAT * *)) ARG2
    '(:INT (INTEGER * *)))

"
... in Allegro CL, if you define a foreign call FOO with C entry point
"foo" and with :call-direct t in the arguments, and if other things are
satisfied, then if a lisp function BAR is compiled which has a call to
FOO, that call will not go through ff-funcall (and thus a large amount
of argument manipulation and processing) but will instead set up its
arguments directly on the stack, and will then perform the "call" more
or less directly, through the "entry vec" (a small structure which
keeps track of a foreign entry's address and status)."

This is the code that generates what the compiler expects to see:

(setq call-direct-form
      (if* call-direct
       then `(setf (get ',lispname 'sys::direct-ff-call)
             (list ',external-name
                   ,callback
                   ,convention
                   ',returning
                   ',arg-types
                   ,arg-checking
                   ,entry-vec-flags))
       else `(remprop ',lispname 'sys::direct-ff-call)))

Thus generating something like:

        (EVAL-WHEN (COMPILE LOAD EVAL)
          (SETF (GET 'FOO 'SYSTEM::DIRECT-FF-CALL)
                (LIST '("foo" :LANGUAGE :C) T :C
                      '(:INT (INTEGER * *))
                      '((:INT (INTEGER * *))
                        (:FLOAT (SINGLE-FLOAT * *)))
                      T
                      2 ; this magic value is explained later
                      )))

"
(defun determine-foreign-address (name &optional (flags 0) method-index)
  ;; return an entry-vec struct suitable for the foreign-call of name.
  ;;
  ;; name is either a string, which is taken without conversion, or
  ;; a list consisting of a string to convert or a conversion function
  ;; call.
  ;; flags is an integer representing the flags to place into the entry-vec.
  ;; method-index, if non-nil, is a word-index into a vtbl (virtual table).
  ;; If method-index is true, then the name must be a string uniquely
  ;; represented by the index and by the flags field.

Note that not all architectures implement the :method-index argument
to def-foreign-call, but your interface likely won't support it
anyway, so just leave it nil.  As for the flags, they are constants
stored into the entry-vec returned by d-f-a and are given here:

(defconstant ep-flag-call-semidirect 1) ; Real address stored in alt-address slot
(defconstant ep-flag-never-release 2)   ; Never release the heap
(defconstant ep-flag-always-release 4)  ; Always release the heap
(defconstant ep-flag-release-when-ok 8) ; Release the heap unless without-interrupts

(defconstant ep-flag-tramp-calls #x70) ; Make calls through special trampolines
(defconstant ep-flag-tramp-shift 4)

(defconstant ep-flag-variable-address #x100) ; Entry-point contains address of C var
(defconstant ep-flag-strings-convert #x200)	 ; Convert strings automatically

(defconstant ep-flag-get-errno #x1000)      ;; [rfe5060]: Get errno value after call
(defconstant ep-flag-get-last-error #x2000) ;; [rfe5060]: call GetLastError after call
;; Leave #x4000 and #x8000 open for expansion

Mostly, you'll give the value 2 (never release the heap), but if you
give 4 or 8, then d-f-a will automatically set the 1 bit as well,
which takes the call through a heap-release/reacquire process.

Some docs for entry-vec are:

;; -- entry vec --
;;  An entry-vec is an entry-point descriptor, usually a pointer into
;; a shared-library.  It is represented as a 5-element struct of type
;; foreign-vector.  The reason for this represntation is
;; that it allows the entry point to be stored in a table, called
;; the .saved-entry-points. table, and to be used by a foreign
;; function.  When the location of the foreign function to which the entry
;; point refers changes, it is simply a matter of changing the value in entry
;; point vector and the foreign call code sees it immediately.  There is
;; even an address that can be put in the entry point vector that denotes
;; a missing foreign function, thus lookup can happen dynamically.

(defstruct (entry-vec
	    (:type (vector excl::foreign (*)))
	    (:constructor make-entry-vec-boa ()))
  name               ; entry point name
  (address 0)        ; jump address for foreign code
  (handle 0)         ; shared-lib handle
  (flags 0)          ; ep-* flags
  (alt-address 0)    ; sometimes holds the real func addr
  )

[...]
"

Regarding the arguments to SYSTEM::FF-FUNCALL:
  '(:int (integer * *)) argN

"The type-spec is as it is given in the def-foreign-call
syntax, with a C type optionally followed by a lisp type,
followed optionally by a user-conversion function name[...]"


Getting the alignment:

CL-USER(2): (ff:get-foreign-type :int)
#S(FOREIGN-FUNCTIONS::IFOREIGN-TYPE
   :ATTRIBUTES NIL
   :SFTYPE
    #S(FOREIGN-FUNCTIONS::SIZED-FTYPE-PRIM
       :KIND :INT
       :WIDTH 4
       :OFFSET 0
       :ALIGN 4)
   ...)
