chiark / gitweb /
FOREIGN
[clg] / glib / proxy.lisp
index 52e329d529fa1b127261191f7a212cff58e641ca..53d35babc44990d2602cf78a30d56f81eee5d0ea 100644 (file)
@@ -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.28 2006-02-06 18:12:19 espen Exp $
+;; $Id: proxy.lisp,v 1.31 2006-02-08 22:10:47 espen Exp $
 
 (in-package "GLIB")
 
@@ -183,7 +183,7 @@ (defmethod initialize-internal-slot-functions ((slotd effective-virtual-slot-def
                     (slot-definition-type slotd))))
                 (funcall writer (foreign-location object) value)))))))))
 
-  (initialize-internal-slot-gfs (slot-definition-name slotd)))
+  #-sbcl>=0.9.8(initialize-internal-slot-gfs (slot-definition-name slotd)))
 
 
 
@@ -234,7 +234,6 @@ (defmethod validate-superclass
 
 ;;;; Proxy cache
 
-(internal *instance-cache*)
 (defvar *instance-cache* (make-hash-table :test #'eql))
 
 (defun cache-instance (instance &optional (weak-ref t))
@@ -266,13 +265,34 @@ (defun list-cached-instances ()
             *instance-cache*)
     instances))
                        
+;; Instances that gets invalidated tend to be short lived, but created
+;; in large numbers. So we're keeping them in a hash table to be able
+;; to reuse them (and thus reduce consing)
+(defvar *invalidated-instance-cache* (make-hash-table :test #'eql))
+
+(defun cache-invalidated-instance (instance)
+  (push instance
+   (gethash (class-of instance) *invalidated-instance-cache*)))
+
+(defun find-invalidated-instance (class)
+  (when (gethash class *invalidated-instance-cache*)
+    (pop (gethash class *invalidated-instance-cache*))))
+
+(defun list-invalidated-instances ()
+  (let ((instances ()))
+    (maphash #'(lambda (location ref)
+                (declare (ignore location))
+                (push ref instances))
+            *invalidated-instance-cache*)
+    instances))
+
 
 
 ;;;; Proxy for alien instances
 
 ;; TODO: add a ref-counted-proxy subclass
 (defclass proxy ()
-  ((location :allocation :special :reader foreign-location :type pointer))
+  ((location :allocation :special :type pointer))
   (:metaclass virtual-slots-class))
 
 (defgeneric instance-finalizer (object))
@@ -280,6 +300,15 @@ (defgeneric reference-foreign (class location))
 (defgeneric unreference-foreign (class location))
 (defgeneric invalidate-instance (object))
 
+(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))
+
 (defmethod reference-foreign ((name symbol) location)
   (reference-foreign (find-class name) location))
 
@@ -312,16 +341,19 @@ (defmethod instance-finalizer ((instance proxy))
        (remove-cached-instance location)
        (unreference-foreign class location))))
 
+;; Any reference to the foreign object the instance may have held
+;; should be released before this method is invoked
 (defmethod invalidate-instance ((instance proxy))
   (remove-cached-instance (foreign-location instance))
-  (slot-makunbound instance 'location))
+  (slot-makunbound instance 'location)
+  (cancel-finalization instance)
+  (cache-invalidated-instance instance))
 
 
 ;;;; Metaclass used for subclasses of proxy
 
 (defgeneric most-specific-proxy-superclass (class))
 (defgeneric direct-proxy-superclass (class))
-(defgeneric compute-foreign-size (class))
   
 
 (eval-when (:compile-toplevel :load-toplevel :execute)
@@ -394,9 +426,6 @@   (defmethod initialize-internal-slot-functions ((slotd effective-alien-slot-def
 
     (call-next-method))
   
-  (defmethod compute-foreign-size ((class proxy-class))
-    nil)
-
   ;; TODO: call some C code to detect this a compile time
   (defconstant +struct-alignmen+ 4)
 
@@ -424,12 +453,6 @@   (defmethod compute-slots ((class proxy-class))
        do (setf (slot-value slotd 'offset) offset))))
     (call-next-method))
 
-  (defmethod compute-slots :after ((class proxy-class))
-    (when (and (class-finalized-p class) (not (slot-boundp class 'size)))
-      (let ((size (compute-foreign-size class)))
-       (when size 
-         (setf (slot-value class 'size) size)))))
-  
   (defmethod validate-superclass ((class proxy-class) (super standard-class))
     (subtypep (class-name super) 'proxy))
   
@@ -535,8 +558,11 @@ (defmethod make-proxy-instance ((class symbol) location &rest initargs)
   (apply #'make-proxy-instance (find-class class) location initargs))
 
 (defmethod make-proxy-instance ((class proxy-class) location &key weak)
-  (let ((instance (allocate-instance class)))
-    (setf (slot-value instance 'location) location)
+  (let ((instance
+        (or
+         (find-invalidated-instance class)
+         (allocate-instance class))))
+    (setf (foreign-location instance) location)
     (unless weak
       (finalize instance (instance-finalizer instance)))
     instance))
@@ -575,14 +601,19 @@ (defmethod reference-foreign ((class struct-class) location)
 (defmethod unreference-foreign ((class struct-class) location)
   (deallocate-memory location))
 
-(defmethod compute-foreign-size ((class struct-class))
-  (let ((size (loop
-              for slotd in (class-slots class)
-              when (eq (slot-definition-allocation slotd) :alien)
-              maximize (+ 
-                        (slot-definition-offset slotd)
-                        (size-of (slot-definition-type slotd))))))
-    (+ size (mod size +struct-alignmen+))))
+(defmethod compute-slots :around ((class struct-class))
+    (let ((slots (call-next-method)))
+      (when (and 
+            #-sbcl>=0.9.8(class-finalized-p class) #+sbc098 t
+            (not (slot-boundp class 'size)))
+        (let ((size (loop
+                    for slotd in slots
+                    when (eq (slot-definition-allocation slotd) :alien)
+                    maximize (+ 
+                              (slot-definition-offset slotd)
+                              (size-of (slot-definition-type slotd))))))
+         (setf (slot-value class 'size) (+ size (mod size +struct-alignmen+)))))
+      slots))
 
 (defmethod reader-function ((class struct-class) &rest args)
   (declare (ignore args))