chiark / gitweb /
Added caching of invalidated proxy instances
[clg] / glib / proxy.lisp
CommitLineData
55212af1 1;; Common Lisp bindings for GTK+ v2.x
2;; Copyright 2000-2005 Espen S. Johnsen <espen@users.sf.net>
b44caf77 3;;
55212af1 4;; Permission is hereby granted, free of charge, to any person obtaining
5;; a copy of this software and associated documentation files (the
6;; "Software"), to deal in the Software without restriction, including
7;; without limitation the rights to use, copy, modify, merge, publish,
8;; distribute, sublicense, and/or sell copies of the Software, and to
9;; permit persons to whom the Software is furnished to do so, subject to
10;; the following conditions:
b44caf77 11;;
55212af1 12;; The above copyright notice and this permission notice shall be
13;; included in all copies or substantial portions of the Software.
b44caf77 14;;
55212af1 15;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16;; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17;; MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18;; IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19;; CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20;; TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21;; SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
b44caf77 22
2a9afe6f 23;; $Id: proxy.lisp,v 1.29 2006/02/07 13:20:39 espen Exp $
b44caf77 24
25(in-package "GLIB")
26
b44caf77 27;;;; Superclass for all metaclasses implementing some sort of virtual slots
28
29(eval-when (:compile-toplevel :load-toplevel :execute)
6baf860c 30 (defclass virtual-slots-class (standard-class)
935a783c 31 ())
b44caf77 32
33 (defclass direct-virtual-slot-definition (standard-direct-slot-definition)
ba25fa44 34 ((setter :reader slot-definition-setter :initarg :setter)
935a783c 35 (getter :reader slot-definition-getter :initarg :getter)
64bce834 36 (unbound :reader slot-definition-unbound :initarg :unbound)
935a783c 37 (boundp :reader slot-definition-boundp :initarg :boundp)))
b44caf77 38
935a783c 39 (defclass effective-virtual-slot-definition (standard-effective-slot-definition)
40 ((setter :reader slot-definition-setter :initarg :setter)
41 (getter :reader slot-definition-getter :initarg :getter)
64bce834 42 (unbound :reader slot-definition-unbound :initarg :unbound)
82defe4d 43 (boundp :reader slot-definition-boundp :initarg :boundp)))
935a783c 44
82defe4d 45 (defclass direct-special-slot-definition (standard-direct-slot-definition)
46 ())
b44caf77 47
82defe4d 48 (defclass effective-special-slot-definition (standard-effective-slot-definition)
49 ()))
50
51(defvar *unbound-marker* (gensym "UNBOUND-MARKER-"))
52
53(defun most-specific-slot-value (instances slot &optional (default *unbound-marker*))
54 (let ((object (find-if
55 #'(lambda (ob)
56 (and (slot-exists-p ob slot) (slot-boundp ob slot)))
57 instances)))
58 (if object
59 (slot-value object slot)
60 default)))
61
62(defmethod initialize-instance ((slotd effective-special-slot-definition) &rest initargs)
63 (declare (ignore initargs))
64 (call-next-method)
65 (setf (slot-value slotd 'allocation) :instance))
66
b44caf77 67
6baf860c 68(defmethod direct-slot-definition-class ((class virtual-slots-class) &rest initargs)
82defe4d 69 (case (getf initargs :allocation)
70 (:virtual (find-class 'direct-virtual-slot-definition))
71 (:special (find-class 'direct-special-slot-definition))
72 (t (call-next-method))))
b44caf77 73
6baf860c 74(defmethod effective-slot-definition-class ((class virtual-slots-class) &rest initargs)
82defe4d 75 (case (getf initargs :allocation)
76 (:virtual (find-class 'effective-virtual-slot-definition))
77 (:special (find-class 'effective-special-slot-definition))
78 (t (call-next-method))))
b44caf77 79
935a783c 80
81(defmethod initialize-internal-slot-functions ((slotd effective-virtual-slot-definition))
64bce834 82 (if (not (slot-boundp slotd 'getter))
83 (setf
935a783c 84 (slot-value slotd 'reader-function)
64bce834 85 #'(lambda (object)
86 (declare (ignore object))
87 (error "Can't read slot: ~A" (slot-definition-name slotd)))
88 (slot-value slotd 'boundp-function)
89 #'(lambda (object) (declare (ignore object)) nil))
90
91 (let ((getter-function
92 (let ((getter (slot-value slotd 'getter)))
93 (etypecase getter
94 (function getter)
95 (symbol
96 #'(lambda (object)
97 (funcall getter object)))
98 (string
99 (let ((reader nil))
100 (setf (slot-value slotd 'reader-function)
101 #'(lambda (object)
102 (unless reader
b6bf802c 103 (setq reader
104 (mkbinding getter
105 (slot-definition-type slotd) 'pointer)))
7ce0497d 106 (funcall reader (foreign-location object))))))))))
64bce834 107
935a783c 108 (setf
64bce834 109 (slot-value slotd 'boundp-function)
110 (cond
64bce834 111 ((slot-boundp slotd 'unbound)
112 (let ((unbound-value (slot-value slotd 'unbound)))
b6bf802c 113 #'(lambda (object)
114 (not (eq (funcall getter-function object) unbound-value)))))
115 ((slot-boundp slotd 'boundp)
116 (let ((boundp (slot-value slotd 'boundp)))
64bce834 117 (etypecase boundp
118 (function boundp)
119 (symbol #'(lambda (object)
120 (funcall boundp object)))
121 (string (let ((reader ()))
122 #'(lambda (object)
123 (unless reader
124 (setq reader
125 (mkbinding boundp
126 (slot-definition-type slotd) 'pointer)))
7ce0497d 127 (funcall reader (foreign-location object))))))))
b6bf802c 128 ((multiple-value-bind (unbound-p unbound-value)
129 (unbound-value (slot-definition-type slotd))
130 (when unbound-p
131 #'(lambda (object)
132 (not (eq (funcall getter-function object) unbound-value))))))
133 (#'(lambda (object) (declare (ignore object)) t))))
64bce834 134
135 (setf
136 (slot-value slotd 'reader-function)
137 (cond
138 ((slot-boundp slotd 'unbound)
139 (let ((unbound (slot-value slotd 'unbound))
140 (slot-name (slot-definition-name slotd)))
b6bf802c 141 #'(lambda (object)
142 (let ((value (funcall getter-function object)))
143 (if (eq value unbound)
144 (slot-unbound (class-of object) object slot-name)
145 value)))))
64bce834 146 ((slot-boundp slotd 'boundp)
147 (let ((boundp-function (slot-value slotd 'boundp-function)))
b6bf802c 148 #'(lambda (object)
149 (and
150 (funcall boundp-function object)
151 (funcall getter-function object)))))
152 ((multiple-value-bind (unbound-p unbound-value)
153 (unbound-value (slot-definition-type slotd))
154 (let ((slot-name (slot-definition-name slotd)))
155 (when unbound-p
156 #'(lambda (object)
157 (let ((value (funcall getter-function object)))
158 (if (eq value unbound-value)
159 (slot-unbound (class-of object) object slot-name)
160 value)))))))
64bce834 161 (getter-function)))))
162
163 (setf
164 (slot-value slotd 'writer-function)
165 (if (not (slot-boundp slotd 'setter))
166 #'(lambda (object)
167 (declare (ignore object))
168 (error "Can't set slot: ~A" (slot-definition-name slotd)))
169 (with-slots (setter) slotd
935a783c 170 (etypecase setter
171 (function setter)
64bce834 172 ((or symbol cons)
173 #'(lambda (value object)
174 (funcall (fdefinition setter) value object)))
0466f75e 175 (string
64bce834 176 (let ((writer ()))
177 (setf
178 (slot-value slotd 'writer-function)
179 #'(lambda (value object)
180 (unless writer
181 (setq writer
182 (mkbinding setter 'nil 'pointer
183 (slot-definition-type slotd))))
7ce0497d 184 (funcall writer (foreign-location object) value)))))))))
64bce834 185
935a783c 186 (initialize-internal-slot-gfs (slot-definition-name slotd)))
187
188
189
64bce834 190(defmethod compute-slot-accessor-info ((slotd effective-virtual-slot-definition) type gf)
935a783c 191 nil)
192
6baf860c 193(defmethod compute-effective-slot-definition-initargs ((class virtual-slots-class) direct-slotds)
64bce834 194 (if (typep (first direct-slotds) 'direct-virtual-slot-definition)
195 (let ((initargs ()))
196 (let ((getter (most-specific-slot-value direct-slotds 'getter)))
197 (unless (eq getter *unbound-marker*)
198 (setf (getf initargs :getter) getter)))
199 (let ((setter (most-specific-slot-value direct-slotds 'setter)))
200 (unless (eq setter *unbound-marker*)
201 (setf (getf initargs :setter) setter)))
202 (let ((unbound (most-specific-slot-value direct-slotds 'unbound)))
203 (unless (eq unbound *unbound-marker*)
204 (setf (getf initargs :unbound) unbound)))
205 (let ((boundp (most-specific-slot-value direct-slotds 'boundp)))
206 (unless (eq boundp *unbound-marker*)
207 (setf (getf initargs :boundp) boundp)))
208 (nconc initargs (call-next-method)))
935a783c 209 (call-next-method)))
210
b44caf77 211
b44caf77 212(defmethod slot-value-using-class
6baf860c 213 ((class virtual-slots-class) (object standard-object)
b44caf77 214 (slotd effective-virtual-slot-definition))
935a783c 215 (if (funcall (slot-value slotd 'boundp-function) object)
216 (funcall (slot-value slotd 'reader-function) object)
217 (slot-unbound class object (slot-definition-name slotd))))
b44caf77 218
b44caf77 219(defmethod slot-boundp-using-class
6baf860c 220 ((class virtual-slots-class) (object standard-object)
b44caf77 221 (slotd effective-virtual-slot-definition))
935a783c 222 (funcall (slot-value slotd 'boundp-function) object))
223
224(defmethod (setf slot-value-using-class)
6baf860c 225 (value (class virtual-slots-class) (object standard-object)
b44caf77 226 (slotd effective-virtual-slot-definition))
935a783c 227 (funcall (slot-value slotd 'writer-function) value object))
228
229
b44caf77 230(defmethod validate-superclass
6baf860c 231 ((class virtual-slots-class) (super standard-class))
b44caf77 232 t)
233
234
235;;;; Proxy cache
236
b44caf77 237(defvar *instance-cache* (make-hash-table :test #'eql))
238
a2bc0f3a 239(defun cache-instance (instance &optional (weak-ref t))
b44caf77 240 (setf
7ce0497d 241 (gethash (sap-int (foreign-location instance)) *instance-cache*)
a2bc0f3a 242 (if weak-ref
243 (make-weak-pointer instance)
244 instance)))
b44caf77 245
246(defun find-cached-instance (location)
3d36c5d6 247 (let ((ref (gethash (sap-int location) *instance-cache*)))
b44caf77 248 (when ref
a2bc0f3a 249 (if (weak-pointer-p ref)
250 (weak-pointer-value ref)
251 ref))))
b44caf77 252
a5c3a597 253(defun instance-cached-p (location)
3d36c5d6 254 (gethash (sap-int location) *instance-cache*))
a5c3a597 255
b44caf77 256(defun remove-cached-instance (location)
3d36c5d6 257 (remhash (sap-int location) *instance-cache*))
b44caf77 258
6baf860c 259;; For debuging
a2bc0f3a 260(defun list-cached-instances ()
6baf860c 261 (let ((instances ()))
262 (maphash #'(lambda (location ref)
263 (declare (ignore location))
a2bc0f3a 264 (push ref instances))
6baf860c 265 *instance-cache*)
266 instances))
267
2a9afe6f 268;; Instances that gets invalidated tend to be short lived, but created
269;; in large numbers. So we're keeping them in a hash table to be able
270;; to reuse them (and thus reduce consing)
271(defvar *invalidated-instance-cache* (make-hash-table :test #'eql))
272
273(defun cache-invalidated-instance (instance)
274 (push instance
275 (gethash (class-of instance) *invalidated-instance-cache*)))
276
277(defun find-invalidated-instance (class)
278 (when (gethash class *invalidated-instance-cache*)
279 (pop (gethash class *invalidated-instance-cache*))))
280
281(defun list-invalidated-instances ()
282 (let ((instances ()))
283 (maphash #'(lambda (location ref)
284 (declare (ignore location))
285 (push ref instances))
286 *invalidated-instance-cache*)
287 instances))
288
b44caf77 289
290
291;;;; Proxy for alien instances
292
253c1339 293;; TODO: add a ref-counted-proxy subclass
6baf860c 294(defclass proxy ()
7ce0497d 295 ((location :allocation :special :reader foreign-location :type pointer))
82defe4d 296 (:metaclass virtual-slots-class))
b44caf77 297
6baf860c 298(defgeneric instance-finalizer (object))
299(defgeneric reference-foreign (class location))
300(defgeneric unreference-foreign (class location))
253c1339 301(defgeneric invalidate-instance (object))
6baf860c 302
c55abd76 303(defmethod reference-foreign ((name symbol) location)
304 (reference-foreign (find-class name) location))
305
306(defmethod unreference-foreign ((name symbol) location)
307 (unreference-foreign (find-class name) location))
308
6baf860c 309(defmethod unreference-foreign :around ((class class) location)
310 (unless (null-pointer-p location)
7ce0497d 311 (call-next-method)))
b44caf77 312
a5c3a597 313(defmethod print-object ((instance proxy) stream)
314 (print-unreadable-object (instance stream :type t :identity nil)
7ce0497d 315 (if (slot-boundp instance 'location)
316 (format stream "at 0x~X" (sap-int (foreign-location instance)))
317 (write-string "at \"unbound\"" stream))))
b44caf77 318
1d06a422 319(defmethod initialize-instance :around ((instance proxy) &rest initargs)
320 (declare (ignore initargs))
321 (prog1
322 (call-next-method)
323 (cache-instance instance)
324 (finalize instance (instance-finalizer instance))))
b44caf77 325
326(defmethod instance-finalizer ((instance proxy))
7ce0497d 327 (let ((location (foreign-location instance))
6baf860c 328 (class (class-of instance)))
329;; (unless (find-method #'unreference-foreign nil (list (class-of class) t) nil)
330;; (error "No matching method for UNREFERENCE-INSTANCE when called with class ~A" class))
331 #'(lambda ()
29933e83 332 (remove-cached-instance location)
6baf860c 333 (unreference-foreign class location))))
ba25fa44 334
2a9afe6f 335;; Any reference to the foreign object the instance may have held
336;; should be released before this method is invoked
253c1339 337(defmethod invalidate-instance ((instance proxy))
338 (remove-cached-instance (foreign-location instance))
2a9afe6f 339 (slot-makunbound instance 'location)
340 (cancel-finalization instance)
341 (cache-invalidated-instance instance))
253c1339 342
b44caf77 343
344;;;; Metaclass used for subclasses of proxy
345
3d36c5d6 346(defgeneric most-specific-proxy-superclass (class))
347(defgeneric direct-proxy-superclass (class))
7ce0497d 348(defgeneric compute-foreign-size (class))
3d36c5d6 349
350
b44caf77 351(eval-when (:compile-toplevel :load-toplevel :execute)
6baf860c 352 (defclass proxy-class (virtual-slots-class)
7ce0497d 353 ((size :reader foreign-size)))
b44caf77 354
355 (defclass direct-alien-slot-definition (direct-virtual-slot-definition)
ba25fa44 356 ((allocation :initform :alien)
357 (offset :reader slot-definition-offset :initarg :offset)))
b44caf77 358
359 (defclass effective-alien-slot-definition (effective-virtual-slot-definition)
935a783c 360 ((offset :reader slot-definition-offset :initarg :offset)))
ba25fa44 361
b44caf77 362 (defmethod most-specific-proxy-superclass ((class proxy-class))
363 (find-if
364 #'(lambda (class)
365 (subtypep (class-name class) 'proxy))
935a783c 366 (cdr (compute-class-precedence-list class))))
3d36c5d6 367
ba25fa44 368 (defmethod direct-proxy-superclass ((class proxy-class))
369 (find-if
370 #'(lambda (class)
371 (subtypep (class-name class) 'proxy))
935a783c 372 (class-direct-superclasses class)))
373
64bce834 374 (defmethod shared-initialize ((class proxy-class) names &key size)
b44caf77 375 (call-next-method)
ba25fa44 376 (cond
935a783c 377 (size (setf (slot-value class 'size) (first size)))
6baf860c 378 ((slot-boundp class 'size) (slot-makunbound class 'size))))
7ce0497d 379
935a783c 380 (defmethod direct-slot-definition-class ((class proxy-class) &rest initargs)
b44caf77 381 (case (getf initargs :allocation)
82defe4d 382 (:alien (find-class 'direct-alien-slot-definition))
b44caf77 383 (t (call-next-method))))
935a783c 384
385 (defmethod effective-slot-definition-class ((class proxy-class) &rest initargs)
b44caf77 386 (case (getf initargs :allocation)
387 (:alien (find-class 'effective-alien-slot-definition))
b44caf77 388 (t (call-next-method))))
389
935a783c 390
391 (defmethod compute-effective-slot-definition-initargs ((class proxy-class) direct-slotds)
392 (if (eq (most-specific-slot-value direct-slotds 'allocation) :alien)
393 (nconc
394 (list :offset (most-specific-slot-value direct-slotds 'offset))
395 (call-next-method))
396 (call-next-method)))
397
398
399 (defmethod initialize-internal-slot-functions ((slotd effective-alien-slot-definition))
400 (with-slots (offset) slotd
6baf860c 401 (let ((type (slot-definition-type slotd)))
64bce834 402 (unless (slot-boundp slotd 'getter)
6baf860c 403 (let ((reader (reader-function type)))
404 (setf
64bce834 405 (slot-value slotd 'getter)
6baf860c 406 #'(lambda (object)
7ce0497d 407 (funcall reader (foreign-location object) offset)))))
935a783c 408
64bce834 409 (unless (slot-boundp slotd 'setter)
6baf860c 410 (let ((writer (writer-function type))
411 (destroy (destroy-function type)))
412 (setf
64bce834 413 (slot-value slotd 'setter)
6baf860c 414 #'(lambda (value object)
7ce0497d 415 (let ((location (foreign-location object)))
6baf860c 416 (funcall destroy location offset) ; destroy old value
64bce834 417 (funcall writer value location offset))))))))
418
935a783c 419 (call-next-method))
420
7ce0497d 421 (defmethod compute-foreign-size ((class proxy-class))
422 nil)
935a783c 423
935a783c 424 ;; TODO: call some C code to detect this a compile time
425 (defconstant +struct-alignmen+ 4)
b44caf77 426
7ce0497d 427 (defun align-offset (size)
428 (if (zerop (mod size +struct-alignmen+))
429 size
430 (+ size (- +struct-alignmen+ (mod size +struct-alignmen+)))))
431
b44caf77 432 (defmethod compute-slots ((class proxy-class))
7ce0497d 433 (let ((alien-slots
434 (remove-if-not
435 #'(lambda (slotd)
436 (eq (slot-definition-allocation slotd) :alien))
437 (class-direct-slots class))))
438 (when alien-slots
439 (loop
440 as offset = (align-offset (foreign-size
441 (most-specific-proxy-superclass class)))
442 then (align-offset
443 (+
444 (slot-definition-offset slotd)
445 (size-of (slot-definition-type slotd))))
446 for slotd in alien-slots
447 unless (slot-boundp slotd 'offset)
448 do (setf (slot-value slotd 'offset) offset))))
b44caf77 449 (call-next-method))
8ae7ddc2 450
7ce0497d 451 (defmethod compute-slots :after ((class proxy-class))
452 (when (and (class-finalized-p class) (not (slot-boundp class 'size)))
453 (let ((size (compute-foreign-size class)))
454 (when size
455 (setf (slot-value class 'size) size)))))
935a783c 456
457 (defmethod validate-superclass ((class proxy-class) (super standard-class))
458 (subtypep (class-name super) 'proxy))
459
7ce0497d 460 (defmethod foreign-size ((class-name symbol))
461 (foreign-size (find-class class-name))))
556b4a05 462
7ce0497d 463(defmethod foreign-size ((object proxy))
464 (foreign-size (class-of object)))
935a783c 465
7ce0497d 466
6baf860c 467(defmethod alien-type ((class proxy-class) &rest args)
468 (declare (ignore class args))
469 (alien-type 'pointer))
470
471(defmethod size-of ((class proxy-class) &rest args)
472 (declare (ignore class args))
473 (size-of 'pointer))
474
475(defmethod from-alien-form (location (class proxy-class) &rest args)
476 (declare (ignore args))
477 `(ensure-proxy-instance ',(class-name class) ,location))
478
479(defmethod from-alien-function ((class proxy-class) &rest args)
480 (declare (ignore args))
481 #'(lambda (location)
482 (ensure-proxy-instance class location)))
b44caf77 483
6baf860c 484(defmethod to-alien-form (instance (class proxy-class) &rest args)
485 (declare (ignore class args))
7ce0497d 486 `(foreign-location ,instance))
b44caf77 487
6baf860c 488(defmethod to-alien-function ((class proxy-class) &rest args)
489 (declare (ignore class args))
7ce0497d 490 #'foreign-location)
6baf860c 491
508d13a7 492(defmethod copy-from-alien-form (location (class proxy-class) &rest args)
493 (declare (ignore args))
494 (let ((class-name (class-name class)))
495 `(ensure-proxy-instance ',class-name
496 (reference-foreign ',class-name ,location))))
497
498(defmethod copy-from-alien-function ((class proxy-class) &rest args)
499 (declare (ignore args))
500 #'(lambda (location)
501 (ensure-proxy-instance class (reference-foreign class location))))
502
503(defmethod copy-to-alien-form (instance (class proxy-class) &rest args)
504 (declare (ignore args))
7ce0497d 505 `(reference-foreign ',(class-name class) (foreign-location ,instance)))
508d13a7 506
507(defmethod copy-to-alien-function ((class proxy-class) &rest args)
3d36c5d6 508 (declare (ignore args))
508d13a7 509 #'(lambda (instance)
7ce0497d 510 (reference-foreign class (foreign-location instance))))
508d13a7 511
6baf860c 512(defmethod writer-function ((class proxy-class) &rest args)
513 (declare (ignore args))
514 #'(lambda (instance location &optional (offset 0))
515 (assert (null-pointer-p (sap-ref-sap location offset)))
516 (setf
517 (sap-ref-sap location offset)
7ce0497d 518 (reference-foreign class (foreign-location instance)))))
b44caf77 519
6baf860c 520(defmethod reader-function ((class proxy-class) &rest args)
521 (declare (ignore args))
0739b019 522 #'(lambda (location &optional (offset 0) weak-p)
523 (declare (ignore weak-p))
508d13a7 524 (let ((instance (sap-ref-sap location offset)))
525 (unless (null-pointer-p instance)
526 (ensure-proxy-instance class (reference-foreign class instance))))))
b44caf77 527
6baf860c 528(defmethod destroy-function ((class proxy-class) &rest args)
529 (declare (ignore args))
530 #'(lambda (location &optional (offset 0))
531 (unreference-foreign class (sap-ref-sap location offset))))
532
b6bf802c 533(defmethod unbound-value ((class proxy-class) &rest args)
556b4a05 534 (declare (ignore args))
b6bf802c 535 (values t nil))
6baf860c 536
1d06a422 537(defun ensure-proxy-instance (class location &rest initargs)
538 "Returns a proxy object representing the foreign object at the give
539location. If an existing object is not found in the cache
540MAKE-PROXY-INSTANCE is called to create one."
6baf860c 541 (unless (null-pointer-p location)
542 (or
e4a48e09 543 #-debug-ref-counting(find-cached-instance location)
544 #+debug-ref-counting
253c1339 545 (let ((instance (find-cached-instance location)))
546 (when instance
547 (format t "Object found in cache: ~A~%" instance)
548 instance))
1d06a422 549 (let ((instance (apply #'make-proxy-instance class location initargs)))
550 (cache-instance instance)
551 instance))))
552
553(defgeneric make-proxy-instance (class location &key weak)
554 (:documentation "Creates a new proxy object representing the foreign
555object at the give location. If WEAK is non NIL the foreign memory
556will not be released when the proxy is garbage collected."))
557
253c1339 558(defmethod make-proxy-instance ((class symbol) location &rest initargs)
559 (apply #'make-proxy-instance (find-class class) location initargs))
1d06a422 560
561(defmethod make-proxy-instance ((class proxy-class) location &key weak)
2a9afe6f 562 (let ((instance
563 (or
564 (find-invalidated-instance class)
565 (allocate-instance class))))
1d06a422 566 (setf (slot-value instance 'location) location)
567 (unless weak
568 (finalize instance (instance-finalizer instance)))
569 instance))
b44caf77 570
ba25fa44 571
572;;;; Superclasses for wrapping of C structures
b44caf77 573
6baf860c 574(defclass struct (proxy)
575 ()
7ce0497d 576 (:metaclass proxy-class)
577 (:size 0))
b44caf77 578
6baf860c 579(defmethod initialize-instance ((struct struct) &rest initargs)
b44caf77 580 (declare (ignore initargs))
9da5a342 581 (unless (slot-boundp struct 'location)
7ce0497d 582 (let ((size (foreign-size (class-of struct))))
9da5a342 583 (if (zerop size)
584 (error "~A has zero size" (class-of struct))
556b4a05 585 (setf (slot-value struct 'location) (allocate-memory size)))))
b44caf77 586 (call-next-method))
587
588
6baf860c 589;;;; Metaclasses used for subclasses of struct
590
591(defclass struct-class (proxy-class)
592 ())
b44caf77 593
82defe4d 594(defmethod direct-slot-definition-class ((class struct-class) &rest initargs)
595 (if (not (getf initargs :allocation))
596 (find-class 'direct-alien-slot-definition)
597 (call-next-method)))
598
6baf860c 599(defmethod reference-foreign ((class struct-class) location)
7ce0497d 600 (copy-memory location (foreign-size class)))
6baf860c 601
602(defmethod unreference-foreign ((class struct-class) location)
ba25fa44 603 (deallocate-memory location))
b44caf77 604
7ce0497d 605(defmethod compute-foreign-size ((class struct-class))
606 (let ((size (loop
607 for slotd in (class-slots class)
608 when (eq (slot-definition-allocation slotd) :alien)
609 maximize (+
610 (slot-definition-offset slotd)
611 (size-of (slot-definition-type slotd))))))
612 (+ size (mod size +struct-alignmen+))))
613
0739b019 614(defmethod reader-function ((class struct-class) &rest args)
253c1339 615 (declare (ignore args))
0739b019 616 #'(lambda (location &optional (offset 0) weak-p)
253c1339 617 (let ((instance (sap-ref-sap location offset)))
618 (unless (null-pointer-p instance)
0739b019 619 (if weak-p
620 (ensure-proxy-instance class instance :weak t)
621 (ensure-proxy-instance class (reference-foreign class instance)))))))
253c1339 622
b44caf77 623
6baf860c 624(defclass static-struct-class (struct-class)
625 ())
b44caf77 626
6baf860c 627(defmethod reference-foreign ((class static-struct-class) location)
628 (declare (ignore class))
ba25fa44 629 location)
b44caf77 630
6baf860c 631(defmethod unreference-foreign ((class static-struct-class) location)
632 (declare (ignore class location))
ba25fa44 633 nil)
b4edcbf0 634
0739b019 635(defmethod reader-function ((class struct-class) &rest args)
636 (declare (ignore args))
637 #'(lambda (location &optional (offset 0) weak-p)
638 (declare (ignore weak-p))
639 (let ((instance (sap-ref-sap location offset)))
640 (unless (null-pointer-p instance)
641 (ensure-proxy-instance class instance :weak t)))))
642
b4edcbf0 643
644;;; Pseudo type for structs which are inlined in other objects
645
646(defmethod size-of ((type (eql 'inlined)) &rest args)
647 (declare (ignore type))
7ce0497d 648 (foreign-size (first args)))
b4edcbf0 649
650(defmethod reader-function ((type (eql 'inlined)) &rest args)
651 (declare (ignore type))
652 (destructuring-bind (class) args
0739b019 653 #'(lambda (location &optional (offset 0) weak-p)
654 (declare (ignore weak-p))
b4edcbf0 655 (ensure-proxy-instance class
656 (reference-foreign class (sap+ location offset))))))
657
253c1339 658(defmethod writer-function ((type (eql 'inlined)) &rest args)
659 (declare (ignore type))
660 (destructuring-bind (class) args
661 #'(lambda (instance location &optional (offset 0))
662 (copy-memory (foreign-location instance) (foreign-size class) (sap+ location offset)))))
663
b4edcbf0 664(defmethod destroy-function ((type (eql 'inlined)) &rest args)
665 (declare (ignore args))
666 #'(lambda (location &optional (offset 0))
667 (declare (ignore location offset))))
668
669(export 'inlined)