allegro-internals.txt - clic - Clic is an command line interactive client for gopher written in Common LISP
 (HTM) git clone git://bitreich.org/clic/ git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65d7roiv6bfj7d652fid.onion/clic/
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) Tags
 (DIR) README
 (DIR) LICENSE
       ---
       allegro-internals.txt (5245B)
       ---
            1 July 2005
            2 These details were kindly provided by Duane Rettig of Franz.
            3 
            4 Regarding the following snippet of the macro expansion of
            5 FF:DEF-FOREIGN-CALL:
            6 
            7   (SYSTEM::FF-FUNCALL
            8     (LOAD-TIME-VALUE (EXCL::DETERMINE-FOREIGN-ADDRESS
            9                       '("foo" :LANGUAGE :C)  2 NIL))
           10     '(:INT (INTEGER * *)) ARG1
           11     '(:DOUBLE (DOUBLE-FLOAT * *)) ARG2
           12     '(:INT (INTEGER * *)))
           13 
           14 "
           15 ... in Allegro CL, if you define a foreign call FOO with C entry point
           16 "foo" and with :call-direct t in the arguments, and if other things are
           17 satisfied, then if a lisp function BAR is compiled which has a call to
           18 FOO, that call will not go through ff-funcall (and thus a large amount
           19 of argument manipulation and processing) but will instead set up its
           20 arguments directly on the stack, and will then perform the "call" more
           21 or less directly, through the "entry vec" (a small structure which
           22 keeps track of a foreign entry's address and status)."
           23 
           24 This is the code that generates what the compiler expects to see:
           25 
           26 (setq call-direct-form
           27       (if* call-direct
           28        then `(setf (get ',lispname 'sys::direct-ff-call)
           29              (list ',external-name
           30                    ,callback
           31                    ,convention
           32                    ',returning
           33                    ',arg-types
           34                    ,arg-checking
           35                    ,entry-vec-flags))
           36        else `(remprop ',lispname 'sys::direct-ff-call)))
           37 
           38 Thus generating something like:
           39 
           40         (EVAL-WHEN (COMPILE LOAD EVAL)
           41           (SETF (GET 'FOO 'SYSTEM::DIRECT-FF-CALL)
           42                 (LIST '("foo" :LANGUAGE :C) T :C
           43                       '(:INT (INTEGER * *))
           44                       '((:INT (INTEGER * *))
           45                         (:FLOAT (SINGLE-FLOAT * *)))
           46                       T
           47                       2 ; this magic value is explained later
           48                       )))
           49 
           50 "
           51 (defun determine-foreign-address (name &optional (flags 0) method-index)
           52   ;; return an entry-vec struct suitable for the foreign-call of name.
           53   ;;
           54   ;; name is either a string, which is taken without conversion, or
           55   ;; a list consisting of a string to convert or a conversion function
           56   ;; call.
           57   ;; flags is an integer representing the flags to place into the entry-vec.
           58   ;; method-index, if non-nil, is a word-index into a vtbl (virtual table).
           59   ;; If method-index is true, then the name must be a string uniquely
           60   ;; represented by the index and by the flags field.
           61 
           62 Note that not all architectures implement the :method-index argument
           63 to def-foreign-call, but your interface likely won't support it
           64 anyway, so just leave it nil.  As for the flags, they are constants
           65 stored into the entry-vec returned by d-f-a and are given here:
           66 
           67 (defconstant ep-flag-call-semidirect 1) ; Real address stored in alt-address slot
           68 (defconstant ep-flag-never-release 2)   ; Never release the heap
           69 (defconstant ep-flag-always-release 4)  ; Always release the heap
           70 (defconstant ep-flag-release-when-ok 8) ; Release the heap unless without-interrupts
           71 
           72 (defconstant ep-flag-tramp-calls #x70) ; Make calls through special trampolines
           73 (defconstant ep-flag-tramp-shift 4)
           74 
           75 (defconstant ep-flag-variable-address #x100) ; Entry-point contains address of C var
           76 (defconstant ep-flag-strings-convert #x200)         ; Convert strings automatically
           77 
           78 (defconstant ep-flag-get-errno #x1000)      ;; [rfe5060]: Get errno value after call
           79 (defconstant ep-flag-get-last-error #x2000) ;; [rfe5060]: call GetLastError after call
           80 ;; Leave #x4000 and #x8000 open for expansion
           81 
           82 Mostly, you'll give the value 2 (never release the heap), but if you
           83 give 4 or 8, then d-f-a will automatically set the 1 bit as well,
           84 which takes the call through a heap-release/reacquire process.
           85 
           86 Some docs for entry-vec are:
           87 
           88 ;; -- entry vec --
           89 ;;  An entry-vec is an entry-point descriptor, usually a pointer into
           90 ;; a shared-library.  It is represented as a 5-element struct of type
           91 ;; foreign-vector.  The reason for this represntation is
           92 ;; that it allows the entry point to be stored in a table, called
           93 ;; the .saved-entry-points. table, and to be used by a foreign
           94 ;; function.  When the location of the foreign function to which the entry
           95 ;; point refers changes, it is simply a matter of changing the value in entry
           96 ;; point vector and the foreign call code sees it immediately.  There is
           97 ;; even an address that can be put in the entry point vector that denotes
           98 ;; a missing foreign function, thus lookup can happen dynamically.
           99 
          100 (defstruct (entry-vec
          101             (:type (vector excl::foreign (*)))
          102             (:constructor make-entry-vec-boa ()))
          103   name               ; entry point name
          104   (address 0)        ; jump address for foreign code
          105   (handle 0)         ; shared-lib handle
          106   (flags 0)          ; ep-* flags
          107   (alt-address 0)    ; sometimes holds the real func addr
          108   )
          109 
          110 [...]
          111 "
          112 
          113 Regarding the arguments to SYSTEM::FF-FUNCALL:
          114   '(:int (integer * *)) argN
          115 
          116 "The type-spec is as it is given in the def-foreign-call
          117 syntax, with a C type optionally followed by a lisp type,
          118 followed optionally by a user-conversion function name[...]"
          119 
          120 
          121 Getting the alignment:
          122 
          123 CL-USER(2): (ff:get-foreign-type :int)
          124 #S(FOREIGN-FUNCTIONS::IFOREIGN-TYPE
          125    :ATTRIBUTES NIL
          126    :SFTYPE
          127     #S(FOREIGN-FUNCTIONS::SIZED-FTYPE-PRIM
          128        :KIND :INT
          129        :WIDTH 4
          130        :OFFSET 0
          131        :ALIGN 4)
          132    ...)