[Openmcl-devel] more openmcl foreign ptr access issues

Cyrus Harmon ch-openmcl at bobobeach.com
Mon Sep 13 23:28:50 PDT 2004


Following up on my own problem, the following does what I was looking 
for:

(defmethod initialize-instance
     ((slotd mac-foreign-standard-direct-slot-definition) &rest all-keys 
&key direct-superclasses)
   (call-next-method)
   (if (and (slot-boundp slotd 'foreignp)
	   (car (slot-value slotd 'foreignp)))
       (let* ((field (slot-value slotd 'foreign-field))
	     (reader (compile nil `(lambda (r)
				     (pref r ,(car field)))))
	     (writer (compile nil `(lambda (r v)
				     (setf (pref r ,(car field)) v)))))
	(setf (slot-value slotd 'foreign-reader) reader)
	(setf (slot-value slotd 'foreign-writer) writer)))
   )

(There's probably a way to get both the reader and writer to play nice 
as an accessor that can be setf'ed, but I haven't gotten to that.)

In summary, the trick was to compile the function. Should have been 
obvious, I guess, and I wonder if a similar resolution might apply to a 
similar problem I mentioned a few weeks ago, which I managed to resolve 
via the allocate-record stuff Gary Byers posted to the list a few weeks 
ago.

So, in summary, if you know the keywords ahead of time, pref is fine, 
if not and you want to pass a variable containing a keyword to pref at 
runtime, one solution is to compile the function and funcall/apply it 
later. Works for what I need, at least so far so good.

I've been working on wrapping the vImage framework (well, one measly 
structure so far) but now that I've got this done, it should go a bit 
faster. If anyone's interested in seeing what I've got, drop me an 
email. Might also be useful for the documentation pages for an example 
of a fairly involved usage of a user(developer)-built interface 
database and use of the MOP to attempt to hide some of the details from 
the user(developer) so that they can just treat foreign fields as 
slots.

Cyrus

On Sep 13, 2004, at 6:14 PM, Cyrus Harmon wrote:

> Ok, I'm suitably scared. Now to consider other approaches and 
> hopefully find one that is less scary... I'm open to suggestions if 
> anyone's got any.
>
> The (perhaps misguided) idea behind this whole thing was that one 
> could build some of the ffi machinery into some MOP machinery and be 
> able to get access to these facilities using a metaclass and some 
> appropriate initargs to the slot specs in the defclass. Of course it's 
> proving to be far more complex than I imagined when I started. The MOP 
> stuff was inspired by Kevin Rosenberg's use of MOP in clsql and seemed 
> like a good idea at the time. The FFI stuff was going swimmingly using 
> the interface database and the reader macros until I decided to put 
> yet another layer of indirection around all that stuff, at which point 
> things got messy in a hurry.
>
> Thanks again,
>
> Cyrus
>
>
> On Sep 13, 2004, at 5:50 PM, Gary Byers wrote:
>
>>
>>
>> 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.)
>
> _______________________________________________
> Openmcl-devel mailing list
> Openmcl-devel at clozure.com
> http://clozure.com/mailman/listinfo/openmcl-devel




More information about the Openmcl-devel mailing list