X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~mdw/git/clg/blobdiff_plain/4e968638bb6018ba57fccf3543985b6c95b783fa..8f49b7a10a9717890ca98dff2b01799b80ce2761:/gffi/proxy.lisp diff --git a/gffi/proxy.lisp b/gffi/proxy.lisp index 8e83f47..7ce9f05 100644 --- a/gffi/proxy.lisp +++ b/gffi/proxy.lisp @@ -20,7 +20,7 @@ ;; TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE ;; SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -;; $Id: proxy.lisp,v 1.1 2006-04-25 20:49:16 espen Exp $ +;; $Id: proxy.lisp,v 1.10 2007-12-11 14:26:11 espen Exp $ (in-package "GFFI") @@ -83,13 +83,14 @@ (defun list-invalidated-instances () ;;;; Proxy for alien instances -#+clisp -(defvar *foreign-instance-locations* (make-hash-table :weak :key)) +#?(or (sbcl>= 0 9 17) (featurep :clisp)) +(defvar *foreign-instance-locations* + (make-hash-table #+clisp :weak #+sbcl :weakness :key)) + -;; TODO: add a ref-counted-proxy subclass (eval-when (:compile-toplevel :load-toplevel :execute) (defclass proxy (virtual-slots-object) - (#-clisp(location :special t :type pointer)) + (#?-(or (sbcl>= 0 9 17) (featurep :clisp))(%location :special t :type pointer)) (:metaclass virtual-slots-class))) (defgeneric instance-finalizer (instance)) @@ -98,17 +99,28 @@ (defgeneric unreference-function (class)) (defgeneric invalidate-instance (instance &optional finalize-p)) (defgeneric allocate-foreign (object &key &allow-other-keys)) -(defun foreign-location (instance) - #-clisp(slot-value instance 'location) - #+clisp(gethash instance *foreign-instance-locations*)) +#?-(or (sbcl>= 0 9 17) (featurep :clisp)) +(progn + (defun foreign-location (instance) + (slot-value instance '%location)) + + (defun (setf foreign-location) (location instance) + (setf (slot-value instance '%location) location)) + + (defun proxy-valid-p (instance) + (slot-boundp instance '%location))) + +#?(or (sbcl>= 0 9 17) (featurep :clisp)) +(progn + (defun foreign-location (instance) + (gethash instance *foreign-instance-locations*)) + + (defun (setf foreign-location) (location instance) + (setf (gethash instance *foreign-instance-locations*) location)) -(defun (setf foreign-location) (location instance) - #-clisp(setf (slot-value instance 'location) location) - #+clisp(setf (gethash instance *foreign-instance-locations*) location)) + (defun proxy-valid-p (instance) + (and (gethash instance *foreign-instance-locations*) t))) -(defun proxy-valid-p (instance) - #-clisp(slot-boundp instance 'location) - #+clisp(and (gethash instance *foreign-instance-locations*) t)) (defmethod reference-function ((name symbol)) (reference-function (find-class name))) @@ -151,18 +163,20 @@ (defmethod instance-finalizer ((instance proxy)) #'(lambda () (funcall unref location)))) -;; FINALIZE-P should always be given the same value as the keyword -;; argument :FINALZIE given to MAKE-PROXY-INSTANCE or non NIL if the -;; proxy was created with MAKE-INSTANCE +;; FINALIZE-P should always be the same as the keyword argument +;; :FINALZIE given to MAKE-PROXY-INSTANCE or non NIL if the proxy was +;; created with MAKE-INSTANCE (defmethod invalidate-instance ((instance proxy) &optional finalize-p) + #+clisp(declare (ignore finalize-p)) (remove-cached-instance (foreign-location instance)) #+(or sbcl cmu) (progn (when finalize-p (funcall (instance-finalizer instance))) - (slot-makunbound instance 'location) + #?-(sbcl>= 0 9 17)(slot-makunbound instance '%location) + #?(sbcl>= 0 9 17)(remhash instance *foreign-instance-locations*) (cancel-finalization instance)) - ;; We can't cached invalidated instances in CLISP beacuse it is + ;; We can't cache invalidated instances in CLISP beacuse it is ;; not possible to cancel finalization #-clisp(cache-invalidated-instance instance)) @@ -241,14 +255,22 @@ (defmethod compute-effective-slot-definition-initargs ((class proxy-class) dir (call-next-method)) (call-next-method))) + (defmethod slot-readable-p ((slotd effective-alien-slot-definition)) + (declare (ignore slotd)) + t) - (defmethod compute-slot-reader-function ((slotd effective-alien-slot-definition)) + (defmethod compute-slot-reader-function ((slotd effective-alien-slot-definition) &optional signal-unbound-p) + (declare (ignore signal-unbound-p)) (let* ((type (slot-definition-type slotd)) (offset (slot-definition-offset slotd)) (reader (reader-function type))) #'(lambda (object) (funcall reader (foreign-location object) offset)))) + (defmethod slot-writable-p ((slotd effective-alien-slot-definition)) + (declare (ignore slotd)) + t) + (defmethod compute-slot-writer-function ((slotd effective-alien-slot-definition)) (let* ((type (slot-definition-type slotd)) (offset (slot-definition-offset slotd)) @@ -260,7 +282,8 @@ (defmethod compute-slot-writer-function ((slotd effective-alien-slot-definitio (funcall writer value location offset)) value))) - (defmethod compute-slot-reader-function ((slotd effective-virtual-alien-slot-definition)) + (defmethod compute-slot-reader-function ((slotd effective-virtual-alien-slot-definition) &optional signal-unbound-p) + (declare (ignore signal-unbound-p)) (if (and (slot-boundp slotd 'getter) (stringp (slot-definition-getter slotd))) (let ((getter (slot-definition-getter slotd)) (type (slot-definition-type slotd)) @@ -279,15 +302,16 @@ (defmethod compute-slot-writer-function ((slotd effective-virtual-alien-slot-d #'(lambda (value object) (unless writer (setq writer (mkbinding setter nil 'pointer type))) + ;; First argument in foreign setters is the object and second + ;; is value (funcall writer (foreign-location object) value))) (call-next-method))) - (defconstant +struct-alignmen+ (size-of 'pointer)) - - (defun align-offset (size &optional packed-p) - (if (or packed-p (zerop (mod size +struct-alignmen+))) - size - (+ size (- +struct-alignmen+ (mod size +struct-alignmen+))))) + (defun adjust-offset (offset type &optional packed-p) + (let ((alignment (type-alignment type))) + (if (or packed-p (zerop (mod offset alignment))) + offset + (+ offset (- alignment (mod offset alignment)))))) (defmethod compute-slots ((class proxy-class)) (let ((alien-slots (remove-if-not @@ -297,17 +321,16 @@ (defmethod compute-slots ((class proxy-class)) (when alien-slots (loop with packed-p = (foreign-slots-packed-p class) - as offset = (align-offset + for slotd in alien-slots + as offset = (adjust-offset (foreign-size (most-specific-proxy-superclass class)) + (slot-definition-type slotd) packed-p) - then (align-offset - (+ - (slot-definition-offset slotd) - (size-of (slot-definition-type slotd))) - packed-p) - for slotd in alien-slots - unless (slot-boundp slotd 'offset) - do (setf (slot-value slotd 'offset) offset)))) + then (adjust-offset offset (slot-definition-type slotd) packed-p) + do (if (slot-boundp slotd 'offset) + (setf offset (slot-value slotd 'offset)) + (setf (slot-value slotd 'offset) offset)) + (incf offset (size-of (slot-definition-type slotd)))))) (call-next-method)) (defmethod validate-superclass ((class proxy-class) (super standard-class)) @@ -327,6 +350,10 @@ (define-type-method size-of ((type proxy) &key inlined) (assert-not-inlined type inlined) (size-of 'pointer)) +(define-type-method type-alignment ((type proxy) &key inlined) + (assert-not-inlined type inlined) + (type-alignment 'pointer)) + (define-type-method from-alien-form ((type proxy) form &key (ref :free)) (let ((class (type-expand type))) (ecase ref @@ -365,10 +392,6 @@ (define-type-method to-alien-function ((type proxy) &optional copy-p) (funcall ref (foreign-location instance)))) #'foreign-location)) -(define-type-method size-of ((type proxy) &key inlined) - (assert-not-inlined type inlined) - (size-of 'pointer)) - (define-type-method writer-function ((type proxy) &key temp inlined) (assert-not-inlined type inlined) (if temp @@ -479,6 +502,20 @@ (defmethod make-proxy-instance ((class proxy-class) location (cache-instance instance) instance)) +;;;; Superclass for ref-counted objects + +(defclass ref-counted-object (proxy) + () + (:metaclass proxy-class)) + +(define-type-method from-alien-form ((type ref-counted-object) form + &key (ref :copy)) + (call-next-method type form :ref ref)) + +(define-type-method from-alien-function ((type ref-counted-object) + &key (ref :copy)) + (call-next-method type :ref ref)) + ;;;; Superclasses for wrapping of C structures @@ -549,20 +586,20 @@ (defmethod compute-slots :around ((class struct-class)) (when (and #?-(or (sbcl>= 0 9 8) (featurep :clisp))(class-finalized-p class) (not (slot-boundp class 'size))) - (let ((size (or - (loop - for slotd in slots - when (eq (slot-definition-allocation slotd) :alien) - maximize (+ - (slot-definition-offset slotd) - (size-of (slot-definition-type slotd)))) - 0))) - (setf (slot-value class 'size) (+ size (mod size +struct-alignmen+))))) + (setf (slot-value class 'size) + (or + (loop + for slotd in slots + when (eq (slot-definition-allocation slotd) :alien) + maximize (+ + (slot-definition-offset slotd) + (size-of (slot-definition-type slotd)))) + 0))) slots)) (define-type-method callback-wrapper ((type struct) var arg form) (let ((class (type-expand type))) - `(let ((,var (ensure-proxy-instance ',class ,arg :finalize nil))) + `(let ((,var (ensure-proxy-instance ',class ,arg :reference nil :finalize nil))) (unwind-protect ,form (invalidate-instance ,var))))) @@ -572,6 +609,15 @@ (define-type-method size-of ((type struct) &key inlined) (foreign-size type) (size-of 'pointer))) +(define-type-method type-alignment ((type struct) &key inlined) + (if inlined + (let ((slot1 (find-if + #'(lambda (slotd) + (eq (slot-definition-allocation slotd) :alien)) + (class-slots (find-class type))))) + (type-alignment (slot-definition-type slot1))) + (type-alignment 'pointer))) + (define-type-method writer-function ((type struct) &key temp inlined) (if inlined (if temp