[cffi-devel] Re: Passing Lisp values into and back out of C?

Luis Oliveira luismbo at gmail.com
Wed Mar 14 17:03:11 UTC 2007


Peter Seibel <peter at gigamonkeys.com> writes:
> Other than keeping my own integer->object mapping and passing the
> integer to C and translating it back to the object when I get it back,
> is there some easier way to do this in CFFI?

AFAIK, that is the best way to do it.  You could also serialize Lisp
objects into a foreign array, though the situations where that would be
a better approach seem limited and you loose object identity.

SBCL and some other Lisps will let you get pointers to vectors of some
types.  With Allegro you apparently can get pointers to arbitrary Lisp
objects with EXCL:LISPVAL-TO-ADDRESS and then get it back with
SYS:MEMREF (though you have to get the offset right, and AFAICT handle
immediate values yourself); it seems easier to do your own mapping
instead.  You have to worry about the GC moving objects around too.

Hmm, since you're asking whether this is doable in *CFFI*, the answer is
no then. :-)  You can, however, make good use of CFFI's type system!

(use-package :cffi)

(define-foreign-type lisp-object-type ()
  ((weakp :initarg :weakp))
  (:actual-type :unsigned-int))

(define-parse-method lisp-object (&key weak-mapping)
  (make-instance 'lisp-object-type :weakp weak-mapping))

(defvar *regular-hashtable* (make-hash-table))

(defvar *weak-hashtable*
  (trivial-garbage:make-weak-hash-table :weakness :value))

(defvar *regular-counter* 0)
(defvar *weak-counter* 0)

(defun increment-counter (value)
  (mod (1+ value) (expt 2 (* 8 (foreign-type-size :unsigned-int)))))

(define-modify-macro incf-counter () increment-counter)

(defmethod translate-to-foreign (value (type lisp-object-type))
  (with-slots (weakp) type
    (let ((id (if weakp
                  (incf-counter *weak-counter*)
                  (incf-counter *regular-counter*)))
          (ht (if weakp *weak-hashtable* *regular-hashtable*)))
      (setf (gethash id ht) value)
      id)))

(defmethod translate-from-foreign (int (type lisp-object-type))
  (with-slots (weakp) type
    ;; If isn't a weak hashtable, we should probably remhash.
    (gethash int (if weakp *weak-hashtable* *regular-hashtable*))))

;;;; Silly example

CL-USER> (defctype weak-mapping (lisp-object :weak-mapping t))
WEAK-MAPPING

CL-USER> (foreign-funcall "abs" weak-mapping (lambda (x) x) weak-mapping)
#<FUNCTION (LAMBDA (X)) {11AB46F5}>
T


This type has obvious shortcomings.  In order to be generally useful it
should probably take different arguments such as an hashtable so that
different CFFI users don't share the same hashtable, have a smarter
(possibly user-provided) counter mechanism, etc...  I hope it's a useful
example nevertheless.

-- 
Luís Oliveira
http://student.dei.uc.pt/~lmoliv/




More information about the cffi-devel mailing list