[Openmcl-devel] more openmcl foreign ptr access issues

Gary Byers gb at clozure.com
Mon Sep 13 17:50:49 PDT 2004



On Mon, 13 Sep 2004, Cyrus Harmon wrote:

> Ok, hot on the heels of figuring out how to get the MOP stuff to DWIM,
> now I'm trying (unsuccessfully, of course) to get access to foreign
> data using pref.
>
> Everything works fine if I do:
>
> 	(pref (foreign-ptr instance) :v<I>mage_<B>uffer.height))
>
> But if I try to do:
>
> 	(pref (foreign-ptr instance) (slot-definition-foreign-field slotd))
>
> (where the slot-def call is doing the right thing), I fail miserably.
> This sounds like the allocate-record I had a couple weeks back and is
> most likely a symptom of the same misunderstanding of how to properly
> use the interface database. But, in any event, I still feel like this
> is a reasonable thing to do. Anyway to have a call to pref determine
> the field name at runtime or am I out of luck here?
>
> Thanks,
>
> Cyrus
>

PREF is a macro; it tries to generate a lisp form that, when compiled
and executed, does some sort of memory access.  Most of the work is
currently done in a function called CCL::%FOREIGN-ACCESS-FORM.  To
allow for following a chain of field accessors (x.y.z),
%FOREIGN-ACCESS-FORM, takes a BIT-OFFSET argument that gets incremented
whenever a type is found to denote a record (struct/union) type and
an accessor denotes a field in that record type.

When it reaches a primitive type (or, more accurately, runs out of
accessors ...), it asks the foreign type to produce a lisp form that
can be used to access an instance of that foreign type, given the
original (usually ...) first arg to PREF and the accumulated bit
offset.  (Using a bit offset here is supposed to enable access to
bitfields which may not be byte-aligned.)

The idiom that's used (stolen/borrowed/watered-down from CMUCL's
ALIEN system) is

(invoke-foreign-type-method :extract-gen type base-form bit-offset)

In a simple case - something like

(pref int-ptr :int)

- where there are no record types or accessors involved - this devolves
into asking the foreign INTEGER type how to access a signed integer
of width 32 at bit-offset 0 from INT-PTR (or, more accurately, how
to generate a form that will do so when compiled and executed).  The
expansion will be something like:

(ccl:%get-signed-long INT-PTR (/ 0 8))

and the compiler will generate a LOAD instruction (and possibly some
hysterical boxing ...)

There aren't that many primitive foreign types (signed and unsigned
integers, two flavors of floats, pointers, not much else that I can
think of.)  You -could- write functions that were analogous to
the primitive foreign type's :EXTRACT-GEN "methods":

(defun dereference-integer-at-runtime (foreign-integer-type pointer bit-offset)
  (cond ((foreign-integer-type-signed foreign-integer-type)
         (case (foreign-type-bits foreign-integer-type)
           (8 (%get-signed-byte pointer (/ bit-offset 8)))
           (16 (%get-signed-word pointer (/ bit-offset 8)))
           ...))))

and do the same for for FLOAT and POINTER types, and define a SETF function
for each of the primitive types.  That would work (at least in theory),
but you'd be doing an amazing amount of type parsing to get at what's
usually a LOAD or STORE instruction, every time that you wanted to access
a slot in a foreign instance.  Note that if we add up the number of
actual primitive %get/%set functions that are involved in this, we'd
probably find around 10 of each.  Interpreting all of this type information
at runtime to discover which of those 10 accessors or setters to use
doesn't seem like much bang for the buck.

I don't want to try to solve the problem for you, but I do want to try
to scare you out of this approach, and to note that other solutions
are possible.  (There are existence proofs that other solutions are
possible.)



More information about the Openmcl-devel mailing list