[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: FFI Questions



I see that Andrew already answered half your question; I can
answer the other half:

   Date: Thu, 21 Jun 90 17:55:03 -0700
   From: Paul Snively <chewy@apple.com>

   Hi there... I'm sitting here with David Kosbie, looking at
   page 330 of the MACL 1.3 manual, where it says:

   "Only floating-point values and strings may be passed by
   reference..."

   David is trying to use the FFI to gain access to the
   functionality of some pre-existing MPW .o files, some of which
   take Pascal VAR args of type INTEGER or LONGINT, or of a
   record type.  Is there any mechanism at all for accomplishing
   this?  Or can we perhaps work a mechanism in (e.g. hacking at
   the FFI source?) :-)

To pass a VAR argument to a pascal function means to pass a
pointer to the actual argument value.  The easiest and fastest
way I know of to do this using MACL is to put the value on the
stack and pass its address (as outlined in the 1.3 reference
manual on page 201).  So suppose I want to call the function PFUN
defined as

procedure pfun (var iParam : integer, var lParam : longint);

Then from MACL I do

(defun call-pfun (int-arg long-arg)
  (%stack-block ((pascal-int 2)
         	 (pascal-long 4))
    (%put-word pascal-int int-arg)
    (%put-long pascal-long long-arg)	;only puts low 31 bits, see below
    (ff-call <address-of-pfun> :ptr pascal-int :ptr pascal-long :novalue)
    (values (%get-word pascal-int)
	    (%get-word pascal-long))))

Notes:

1) pascal-int and pascal-long hold pointers to the stack
space allocated by the %stack-block, so that using them as :ptr
args calls the pascal function with pointers to the actual
values, as desired.

2) %get-long and %put-long do boxing and unboxing of their args
(they only use the low 31 bits) so if you really need all 32 bits
you will have to arrange to transfer the info on and off the
stack 16 bits at a time and use bignum arithmetic to do the
splitting and rejoining of the two halves.

3) If you want to pass a Mac record as a var, you just pass the
lisp variable containing the record as a :ptr arg.  It doesn't
matter if you allocated the record with _NewPointer or rlet.

4) If you are using the deffpfun interface, use an argspec of
(t :ptr) regardless of whether you are passing integers, longs,
or records, and pass in the stack-pointing or heap-pointing
variable (pascal-int or pascal-long in this example).

5) If you use ff-call directly on a c function, be sure to
reverse the order of the args (C pushes them last-to-first).

   Better still, _why_ does this restriction exist in the first
   place?

Sorry, I'm not an MACL implementor, so I can't say for sure.  I
don't see any technical reason why :by-reference couldn't be done
automatically for immediate data as I have outlined it here
(given the appropriate warnings about 32nd-bit truncation).  I
suspect it simply wasn't a high priority (given how easy it is
for users to do it themselves).  Perhaps someone in Cambridge can
tell us.


Hope this helps,
    dan

Daniel Brotsky (Internet: brotsky@parc.xerox.com)
Xerox Palo Alto Research Center (PARC)
3333 Coyote Hill Road; Palo Alto, CA, USA  94304
TEL: 415-494-4709; FAX: 415-494-4334