source: branches/lispworks/persistent-clos.lisp@ 27

Last change on this file since 27 was 7, checked in by Gail Zacharias, 17 years ago

Credit for Anvita

  • Property svn:eol-style set to native
File size: 34.4 KB
Line 
1;;;-*- Mode: Lisp; Package: (WOOD) -*-
2
3;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
4;;
5;; persistent-clos.lisp
6;; Support for saving/restoring CLOS instances to/from Wood persistent heaps.
7;;
8;; Portions Copyright © 2006 Clozure Associates and Anvita eReference (www.Anvita.info)
9;; Copyright © 1996 Digitool, Inc.
10;; Copyright © 1992-1995 Apple Computer, Inc.
11;; All rights reserved.
12;; Permission is given to use, copy, and modify this software provided
13;; that Digitool is given credit in all derivative works.
14;; This software is provided "as is". Digitool makes no warranty or
15;; representation, either express or implied, with respect to this software,
16;; its quality, accuracy, merchantability, or fitness for a particular
17;; purpose.
18;;
19
20;;;;;;;;;;;;;;;;;;;;;;;;;;
21;;
22;; Modification History
23;;
24;; 02/01/06 gz LispWorks port
25;; 08/28/98 akh add dc-shared-initialize - fixes case of change class in memory, then write a slot-value to pheap
26;; left us with the class updated on disk but not the instance-slots with initforms
27;; ------------- 0.96
28;; ------------- 0.95
29;; ------------- 0.94
30;; ------------- 0.93
31;; ------------- 0.9
32;; 11/02/94 bill (method %p-store-object (t standard-object t)) no longer
33;; handles p-make-load-function-using-pheap. It has moved
34;; into %p-store-internal now.
35;; 10/28/94 Moon Change without-interrupts to with-databases-locked
36;; 10/25/94 bill p-load-instance calls wood-disk-resident-slot-names,
37;; a new GF that users can specialize.
38;; define-disk-resident-slot-names macro to aid generation
39;; of wood-disk-resident-slot-names methods and accessor
40;; methods that will swap disk resident slots in when
41;; necessary.
42;; 09/21/94 bill without-interrupts as necessary for interlocking
43;; -------------- 0.8
44;; 10/25/93 bill initialize-persistent-instance
45;; -------------- 0.6
46;; 02/16/93 bill p-load-instance now calls shared-initialize to initialize
47;; any new slots (slots that have been added since the instance
48;; was saved to the pheap file).
49;; 11/16/92 bill pheap-class-hash, p-class-instance-slot-names
50;; 11/09/92 bill Make it work correctly to create two instances, p-store them,
51;; redefine the class adding a slot, p-store the first instance,
52;; close and reopen the pheap, then p-load the second instance.
53;; chung@ils.nwu.edu found that this used to result in an instance all
54;; of whose slots were unbound.
55;; 08/27/92 bill in %p-store-object: call p-make-load-function
56;; 08/13/92 bill (setf p-slot-value) now does the right thing if instance
57;; is not a PPTR.
58;; -------------- 0.5
59;; 06/23/92 bill New file
60;;
61
62(in-package :wood)
63
64(defun pheap-class-hash (pheap)
65 (let ((hash (dc-class-hash (pheap-disk-cache pheap))))
66 (when hash
67 (pptr pheap hash))))
68
69(defun dc-class-hash (disk-cache &optional create?)
70 (with-databases-locked
71 (let ((res (dc-%svref disk-cache $root-vector $pheap.class-hash)))
72 (if (eql res $pheap-nil)
73 (if create?
74 (setf (dc-%svref disk-cache $root-vector $pheap.class-hash)
75 (dc-make-hash-table disk-cache)))
76 res))))
77
78(defun p-find-class (pheap name &optional (errorp t))
79 (multiple-value-bind (pointer imm?) (%p-store-hash-key pheap name)
80 (when pointer
81 (let ((res (dc-find-class (pheap-disk-cache pheap) pointer imm? errorp)))
82 (when res (pptr pheap res))))))
83
84(defun dc-find-class (disk-cache pointer immediate? &optional (errorp t))
85 (let ((hash (dc-class-hash disk-cache)))
86 (or (and hash
87 (dc-gethash disk-cache pointer immediate? hash))
88 (when errorp
89 (error "Class named ~s not found."
90 (dc-pointer-load disk-cache pointer immediate?))))))
91
92; Will overwrite an existing class
93(defun p-make-class (pheap name slots)
94 (unless (and (vectorp slots) (every 'symbolp slots))
95 (error "~s is not a vector of slot names"))
96 (multiple-value-bind (pointer imm?) (%p-store pheap name)
97 (pptr pheap
98 (dc-make-class (pheap-disk-cache pheap)
99 pointer
100 (%p-store pheap slots)
101 imm?
102 slots
103 pheap))))
104
105(defun dc-make-class (disk-cache name slots &optional name-imm? slots-object pheap)
106 (let* ((class (dc-make-uvector disk-cache $class-size $v_class))
107 (hash (dc-class-hash disk-cache t))
108 (wrapper (dc-make-class-wrapper disk-cache class slots slots-object pheap)))
109 (dc-%svfill disk-cache class
110 ($class.name name-imm?) name
111 $class.own-wrapper wrapper)
112 (dc-puthash disk-cache name name-imm? hash class)))
113
114(defun dc-make-class-wrapper (disk-cache class slots &optional slots-object pheap)
115 (let ((wrapper (dc-make-vector disk-cache $wrapper-size)))
116 (dc-%svfill disk-cache wrapper
117 $wrapper.class class
118 $wrapper.slots slots)
119 (when slots-object
120 (setf (gethash slots-object
121 (wrapper-hash (or pheap (disk-cache-pheap disk-cache))))
122 wrapper))
123 wrapper))
124
125; Access a (disk) class'es wrapper. Update it to agree with the
126; class in memory, if there is one.
127; Returns 2 value:
128; 1) the (possibly new) wrapper
129; 2) the in-memory class, or NIL if there isn't one.
130; 3) the vector of slot names for the in-memory class, or NIL
131; 4) true if the class'es was obsolete.
132(defun dc-update-class-wrapper (disk-cache class &optional pheap memory-class dont-update)
133 (unless pheap (setq pheap (disk-cache-pheap disk-cache)))
134 (if (eq memory-class :none)
135 (setq memory-class nil)
136 (let* ((name (pointer-load pheap (dc-%svref disk-cache class $class.name) :default disk-cache)))
137 (setq memory-class (find-class name nil))))
138 (with-databases-locked
139 (let ((wrapper (dc-%svref disk-cache class $class.own-wrapper))
140 (obsolete? nil)
141 slot-names)
142 (when memory-class
143 (let ((wrapper-hash (wrapper-hash pheap)))
144 (setq slot-names (wood-slot-names-vector (class-prototype memory-class)))
145 (unless (eql wrapper (gethash slot-names wrapper-hash))
146 (let ((old-slot-names (pointer-load pheap (dc-%svref disk-cache wrapper $wrapper.slots)
147 :default disk-cache)))
148 (if (equalp old-slot-names slot-names)
149 (setf (gethash slot-names wrapper-hash) wrapper)
150 (progn
151 (setq obsolete? t)
152 (unless dont-update
153 (setf wrapper (dc-make-class-wrapper
154 disk-cache class
155 (%p-store pheap slot-names) slot-names pheap)
156 (dc-%svref disk-cache class $class.own-wrapper) wrapper))))))))
157 (values wrapper memory-class slot-names obsolete?))))
158
159
160#+LispWorks
161(defparameter $wrapper-names-index
162 (or (loop with wrapper = (progn
163 (make-instance 'simple-error)
164 (clos::class-wrapper (find-class 'simple-error)))
165 for i in '(0 1 2 -1 -2 -3)
166 as val = (%svref wrapper i)
167 when (and (consp val)
168 (consp (cdr val))
169 (null (cddr val))
170 (equal val '(conditions::format-string conditions::format-arguments)))
171 return i)
172 (error "Couldn't find wrapper names index")))
173
174
175
176
177;; In lispworks, the names are in a list not a vector, but seems to work ok.
178(defun-inline %wrapper-instance-slots (wrapper)
179 #+ccl (ccl::%wrapper-instance-slots wrapper)
180 #-ccl (%svref wrapper $wrapper-names-index))
181
182#+LispWorks
183(defun class-own-wrapper (class)
184 (clos::class-wrapper class))
185
186; This knows internals of MCL's CLOS implementation
187(defun class-slots-vector (class)
188 (%wrapper-instance-slots #+ccl (or (ccl::%class-own-wrapper class)
189 (ccl::initialize-class-and-wrapper class))
190 #+LispWorks (clos::class-wrapper class)))
191
192
193(defun dc-make-class-slots-vector (disk-cache class &optional
194 (pheap (disk-cache-pheap disk-cache)))
195 (%p-store pheap (wood-slot-names-vector (class-prototype class))))
196
197(def-predicate classp (p disk-cache pointer)
198 (dc-vector-subtype-p disk-cache pointer $v_class))
199
200(def-accessor class-name (p) (disk-cache pointer)
201 (require-satisfies dc-classp disk-cache pointer)
202 (dc-%svref disk-cache pointer $class.name))
203
204(defun (setf dc-class-name) (value disk-cache class &optional value-imm?)
205 (require-satisfies dc-classp disk-cache class)
206 (setf (dc-%svref disk-cache class $class.name value-imm?) value)
207 (values value value-imm?))
208
209(def-accessor class-own-wrapper (p) (disk-cache pointer)
210 (require-satisfies dc-classp disk-cache pointer)
211 (dc-%svref disk-cache pointer $class.own-wrapper))
212
213(defun (setf dc-class-own-wrapper) (value disk-cache class &optional value-imm?)
214 (require-satisfies dc-classp disk-cache class)
215 (setf (dc-%svref disk-cache class $class.own-wrapper value-imm?) value)
216 (values value value-imm?))
217
218(defmacro dc-wrapper-class (disk-cache wrapper)
219 `(dc-uvref ,disk-cache ,wrapper $wrapper.class))
220
221(defmacro dc-wrapper-slots (disk-cache wrapper)
222 `(dc-uvref ,disk-cache ,wrapper $wrapper.slots))
223
224(def-accessor class-instance-slot-names (p) (disk-cache pointer)
225 (require-satisfies dc-classp disk-cache pointer)
226 (dc-wrapper-slots disk-cache (dc-class-own-wrapper disk-cache pointer)))
227
228(defun class-instance-slot-names (class)
229 (let ((wrapper (class-own-wrapper class)))
230 (unless wrapper
231 (class-prototype class)
232 (setq wrapper (class-own-wrapper class))
233 (unless wrapper (error "Can't find class-own-wrapper for ~s" class)))
234 (%wrapper-instance-slots wrapper)))
235
236(defun p-instance-class (instance)
237 (if (pptr-p instance)
238 (let* ((pheap (pptr-pheap instance))
239 (disk-cache (pheap-disk-cache pheap))
240 (pointer (pptr-pointer instance)))
241 (pointer-load
242 pheap
243 (dc-wrapper-class disk-cache (dc-instance-class-wrapper disk-cache pointer))))
244 (class-of instance)))
245
246(defmethod %p-store-object (pheap (object standard-class) descend)
247 (let* ((disk-cache (pheap-disk-cache pheap))
248 (descend (eq descend t))
249 name imm?
250 (address (maybe-cached-address pheap object
251 (multiple-value-setq (name imm?)
252 (%p-store pheap (class-name object)))
253 (or (dc-find-class disk-cache name imm? nil)
254 (progn
255 (setq descend nil)
256 (dc-make-class disk-cache
257 name
258 (dc-make-class-slots-vector
259 disk-cache object pheap)
260 imm?))))))
261 (when descend
262 (unless name
263 (multiple-value-setq (name imm?) (%p-store pheap (class-name object))))
264 (setf (dc-class-name disk-cache address imm?) name)
265 (setf (dc-wrapper-slots disk-cache (dc-class-own-wrapper disk-cache address))
266 (dc-make-class-slots-vector disk-cache object pheap)))
267 address))
268
269(defun p-load-class (pheap disk-cache pointer depth subtype)
270 (declare (ignore depth subtype))
271 (maybe-cached-value pheap pointer
272 (multiple-value-bind (name-pointer imm?) (dc-class-name disk-cache pointer)
273 (let ((name (dc-pointer-load disk-cache name-pointer imm? pheap)))
274 (or (find-class name nil)
275 (let ((slots (pointer-load pheap
276 (dc-wrapper-slots
277 disk-cache
278 (dc-class-own-wrapper disk-cache pointer))
279 :default
280 disk-cache)))
281 ;; this is wrong - lose initargs, initforms
282 (eval `(defclass ,name () ,(coerce slots 'list)))))))))
283
284(defmethod p-allocate-instance (pheap (class symbol))
285 (p-allocate-instance pheap (or (p-find-class pheap class nil)
286 (p-store pheap (find-class class)))))
287
288(defmethod p-allocate-instance (pheap (class standard-class))
289 (p-%allocate-instance pheap (p-store pheap class) class))
290
291(defmethod p-allocate-instance (pheap (class pptr))
292 (require-satisfies p-classp class)
293 (p-%allocate-instance pheap class nil))
294
295(defun p-%allocate-instance (pheap class memory-class)
296 (pptr pheap (dc-%allocate-instance (pheap-disk-cache pheap) (pptr-pointer class) memory-class)))
297
298(defun dc-%allocate-instance (disk-cache class &optional memory-class)
299 (let* ((wrapper (dc-update-class-wrapper disk-cache class nil memory-class))
300 (slots (dc-make-vector
301 disk-cache
302 (dc-length disk-cache (dc-wrapper-slots disk-cache wrapper))
303 nil (%unbound-marker) t))
304 (res (dc-make-uvector disk-cache $instance-size $v_instance)))
305 (dc-%svfill disk-cache res
306 $instance.wrapper wrapper
307 $instance.slots slots)
308 res))
309
310(def-accessor instance-class-wrapper (p) (disk-cache pointer)
311 (require-satisfies dc-standard-instance-p disk-cache pointer)
312 (dc-%svref disk-cache pointer $instance.wrapper))
313
314; This is the wrong name. Check the MOP
315(def-accessor instance-access (p index) (disk-cache pointer)
316 (require-satisfies dc-standard-instance-p disk-cache pointer)
317 (dc-uvref disk-cache (dc-%svref disk-cache pointer $instance.slots) index))
318
319(defun (setf p-instance-access) (value p index)
320 (setq index (require-type index 'fixnum))
321 (if (pptr-p p)
322 (let ((pheap (pptr-pheap p)))
323 (multiple-value-bind (v imm?) (%p-store pheap value)
324 (setf (dc-instance-access
325 (pheap-disk-cache pheap) (pptr-pointer p) index imm?)
326 v)
327 (if imm? v (pptr pheap v))))
328 (error "~s is defined only for Wood instances" '(setf p-instance-access))))
329
330(defun (setf dc-instance-access) (value disk-cache pointer index value-imm?)
331 (require-satisfies dc-standard-instance-p disk-cache pointer)
332 (setf (dc-uvref disk-cache (dc-%svref disk-cache pointer $instance.slots)
333 index value-imm?)
334 value))
335
336(defun instance-access (thing index)
337 (declare (ignore thing index))
338 (error "~s is defined only for Wood instances" 'instance-access))
339
340; Instance is an on-disk address.
341; class is an in-memory class or NIL.
342; Returns three values:
343; 1) The slots vector on disk
344; 2) The slot names vector in memory.
345; 3) slot-names vector if the instance was obsolete.
346; This will be different from the second value if the
347; dont-update arg is true.
348;
349; This is hairy because it has to deal with a lot of possibilities:
350;
351; 1) Class exists in memory, but hasn't been associated with PHEAP yet.
352; 2) Class exists in memeory and has been associated with PHEAP.
353; 3) Class does not exist in memory.
354; 4) 1 or 2 and the class has been redefined since the instance was stored in the PHEAP.
355(defun dc-updated-instance-slots (disk-cache instance memory-class pheap &optional
356 dont-update)
357 ;(assert (dc-vector-subtype-p disk-cache instance $v_instance))
358 (with-databases-locked
359 (let ((old-wrapper (dc-%svref disk-cache instance $instance.wrapper))
360 (instance-slots (dc-%svref disk-cache instance $instance.slots))
361 class wrapper slot-names old-slot-names obsolete?)
362 (if memory-class
363 (progn
364 (setq slot-names (wood-slot-names-vector (class-prototype memory-class)))
365 (setq wrapper (gethash slot-names (wrapper-hash pheap))))
366 (progn
367 (setq class (dc-%svref disk-cache old-wrapper $wrapper.class))
368 (multiple-value-setq (wrapper memory-class slot-names obsolete?)
369 (dc-update-class-wrapper disk-cache class pheap nil dont-update))
370 (unless slot-names
371 (setq slot-names (pointer-load pheap (dc-%svref disk-cache old-wrapper $wrapper.slots)
372 :default disk-cache)
373 wrapper old-wrapper))))
374 (if (if (and wrapper (not obsolete?))
375 (eql wrapper old-wrapper)
376 (when (equalp slot-names
377 (setq old-slot-names
378 (pointer-load pheap (dc-%svref disk-cache old-wrapper $wrapper.slots)
379 :default disk-cache)))
380 (setq wrapper (setf (gethash slot-names (wrapper-hash pheap)) old-wrapper))))
381 ; Wrapper is current
382 (values instance-slots slot-names)
383 ; Wrapper needs updating.
384 (progn
385 (unless old-slot-names
386 (setq old-slot-names (pointer-load
387 pheap
388 (dc-%svref disk-cache old-wrapper $wrapper.slots)
389 :default disk-cache)))
390 (if dont-update
391 (values instance-slots old-slot-names slot-names)
392 (let* ((slot-count (length slot-names))
393 (slot-values (make-array slot-count))
394 (slot-imms (make-array slot-count)))
395 (declare (fixnum slot-count))
396 ;(dynamic-extent slot-values slot-imms))
397 (unless wrapper
398 (let ((class (dc-%svref disk-cache old-wrapper $wrapper.class)))
399 (setq wrapper (dc-update-class-wrapper disk-cache class pheap memory-class dont-update))))
400 (dotimes (i slot-count)
401 (let ((index (position (svref slot-names i) old-slot-names :test 'eq)))
402 (if index
403 (multiple-value-bind (value imm?) (dc-uvref disk-cache instance-slots index)
404 (setf (svref slot-values i) value
405 (svref slot-imms i) imm?))
406 (setf (svref slot-values i) (%unbound-marker)
407 (svref slot-imms i) t))))
408 (let* ((old-instance-length (dc-length disk-cache instance-slots))
409 (new-instance-slots (if (>= old-instance-length slot-count)
410 (let ((index slot-count))
411 (dotimes (i (- old-instance-length slot-count))
412 (setf (dc-uvref disk-cache instance-slots index t)
413 (%unbound-marker)))
414 instance-slots)
415 (dc-make-vector
416 disk-cache slot-count
417 (dc-area disk-cache instance-slots)
418 (%unbound-marker) t))))
419 (dotimes (i slot-count)
420 (let ((value (svref slot-values i))
421 (imm? (svref slot-imms i)))
422 (unless (and imm? (eq value (%unbound-marker)))
423 (setf (dc-%svref disk-cache new-instance-slots i imm?) value))))
424 (dc-shared-initialize disk-cache pheap slot-values new-instance-slots memory-class)
425 (setf (dc-%svref disk-cache instance $instance.wrapper) wrapper
426 (dc-%svref disk-cache instance $instance.slots) new-instance-slots)
427 (values new-instance-slots slot-names)))))))))
428
429
430;;; *** TODO: Need Lispworks version.
431#+CCL
432(defun dc-shared-initialize (disk-cache pheap slot-values new-instance-slots class &optional (slot-names t))
433 ;; I don't know how to find all this stuff in the disk version - I don't think it's there.
434 ;; copied from %shared-initialize
435 (when class
436 (dotimes (i (uvsize (ccl::%class-instance-slotds class)))
437 (declare (fixnum i))
438 (let* ((slotd (svref (ccl::%class-instance-slotds class) i))
439 (index i)
440 (initform (ccl::%slotd-initform slotd)))
441 (when (and initform
442 (eq (svref slot-values index) (%unbound-marker))
443 (or (eq slot-names t) (memq (ccl::%slotd-name slotd) slot-names)))
444 (let ((value
445 (if (listp initform) ;(value)
446 (car initform)
447 (funcall initform))))
448 (multiple-value-bind (v imm?) (%p-store pheap value)
449 (setf (dc-%svref disk-cache new-instance-slots index imm?) v))))))))
450
451
452
453(def-predicate standard-instance-p (p disk-cache pointer)
454 (and (dc-uvectorp disk-cache pointer)
455 (dc-vector-subtype-p disk-cache pointer $v_instance)))
456
457(def-accessor slot-value (p slot-name) (disk-cache pointer)
458 (require-satisfies dc-standard-instance-p disk-cache pointer)
459 (multiple-value-bind (value imm?)
460 (dc-%slot-value disk-cache pointer slot-name)
461 (if (and imm? (eq value (%unbound-marker)))
462 (dc-slot-unbound disk-cache pointer slot-name)
463 (values value imm?))))
464
465(defun dc-%slot-value (disk-cache pointer slot-name)
466 (multiple-value-bind (slots index)
467 (dc-%slot-vector-and-index disk-cache pointer slot-name t)
468 (if slots
469 (if (eq slots (%unbound-marker))
470 (values slots t)
471 (dc-%svref disk-cache slots index))
472 (dc-slot-missing disk-cache pointer slot-name 'slot-value))))
473
474(defun dc-slot-missing (disk-cache pointer slot-name operation &optional new-value)
475 (declare (ignore operation new-value))
476 (error "~s has no slot named ~s"
477 (pptr (disk-cache-pheap disk-cache) pointer) slot-name))
478
479(defun dc-slot-unbound (disk-cache pointer slot-name)
480 (error "Slot ~s is unbound in ~s"
481 slot-name (pptr (disk-cache-pheap disk-cache) pointer)))
482
483; Returns two values:
484; 1) disk-cache vector of slots
485; 2) index in the vector
486;
487; If the slot doesn't exist, returns NIL.
488; If the slot exists, but only after the instance is updated and dont-update
489; is true, returns (%unbound-marker).
490(defun dc-%slot-vector-and-index (disk-cache pointer slot-name &optional dont-update)
491 (let* ((pheap (disk-cache-pheap disk-cache))
492 (wrapper (dc-%svref disk-cache pointer $instance.wrapper))
493 (memory-class (pointer-load
494 pheap
495 (dc-%svref disk-cache
496 (dc-%svref disk-cache wrapper $wrapper.class)
497 $class.name)
498 :default disk-cache)))
499 (multiple-value-bind (slots slot-names real-slot-names)
500 (dc-updated-instance-slots
501 disk-cache pointer
502 (find-class
503 memory-class
504 nil)
505 pheap
506 dont-update)
507 (let ((index (position slot-name slot-names :test 'eq))
508 (real-index (and dont-update
509 real-slot-names
510 (position slot-name real-slot-names))))
511 (if (and index (or (not dont-update) (not real-slot-names) real-index))
512 (values slots index)
513 (if real-index
514 (%unbound-marker)
515 nil))))))
516
517(defun (setf p-slot-value) (value p slot-name)
518 (if (pptr-p p)
519 (let* ((pheap (pptr-pheap p))
520 (disk-cache (pheap-disk-cache pheap))
521 (pointer (pptr-pointer p)))
522 (multiple-value-bind (slots index)
523 (dc-%slot-vector-and-index disk-cache pointer slot-name)
524 (unless slots
525 (dc-slot-missing disk-cache pointer slot-name '(setf p-slot-value)))
526 (multiple-value-bind (v imm?) (%p-store pheap value)
527 (setf (dc-%svref disk-cache slots index imm?) v)
528 (if imm?
529 v
530 (pptr pheap v)))))
531 (setf (slot-value p slot-name) value)))
532
533(def-accessor slot-boundp (p slot-name) (disk-cache pointer)
534 (values (not (eq (dc-%slot-value disk-cache pointer slot-name)
535 (%unbound-marker)))
536 t))
537
538(def-accessor slot-makunbound (p slot-name) (disk-cache pointer)
539 (multiple-value-bind (slots index)
540 (dc-%slot-vector-and-index disk-cache pointer slot-name t)
541 (unless slots
542 (dc-slot-missing disk-cache pointer slot-name 'p-slot-makunbound))
543 (unless (eq slots (%unbound-marker))
544 (setf (dc-%svref disk-cache slots index t) (%unbound-marker)))
545 pointer))
546
547#+CCL
548(defmethod %p-store-object (pheap (object ccl::funcallable-standard-object) descend)
549 (declare (ignore pheap descend))
550 (error "Can't save generic functions yet. Maybe never."))
551
552; this will do the wrong thing if anyone redefines the class
553; of the object while it is running.
554(defmethod %p-store-object (pheap (object standard-object) descend)
555 (let* ((class (class-of object))
556 (consed? nil))
557 (%p-store-object-body (pheap object descend disk-cache address)
558 (progn
559 (setq consed? t)
560 (dc-%allocate-instance disk-cache (%p-store pheap class)))
561 (progn
562 (unless consed?
563 ; Ensure that p-make-load-function-using-pheap method didn't change too much to handle
564 (require-satisfies dc-vector-subtype-p disk-cache address $v_instance))
565 (multiple-value-bind (slots slot-names)
566 (dc-updated-instance-slots disk-cache address class pheap)
567 (dotimes (i (length slot-names))
568 (let ((slot-name (elt slot-names i)))
569 (multiple-value-bind (value imm?)
570 (if (slot-boundp object slot-name)
571 (%p-store pheap (wood-slot-value object slot-name) descend)
572 (values (%unbound-marker) t))
573 (setf (dc-uvref disk-cache slots i imm?) value)))))))))
574
575; New functions
576; Allows a p-make-load-function-using-pheap method to save slots for an object
577; and do something else as well.
578
579(defmethod instance-slot-names ((instance structure-object))
580 #+ccl
581 (let ((sd (gethash (car (%svref instance 0)) ccl::%defstructs%))
582 (res nil))
583 (dolist (slot (%svref sd 1)) ;; sd-slots
584 (let ((name (car slot)))
585 (when (symbolp name)
586 (push name res))))
587 (nreverse res))
588 #+LispWorks
589 (structure:structure-class-slot-names (class-of instance)))
590
591(defmethod instance-slot-names ((instance standard-object))
592 (mapcar 'slot-definition-name (class-instance-slots (class-of instance))))
593
594(defmethod p-make-load-function-saving-slots ((object standard-object) &optional (slots nil slots-p))
595 (%p-make-load-function-saving-slots object slots slots-p))
596
597(defmethod p-make-load-function-saving-slots ((object structure-object) &optional (slots nil slots-p))
598 (%p-make-load-function-saving-slots object slots slots-p))
599
600(defun %p-make-load-function-saving-slots (object slots slots-p)
601 (let* ((slot-names (if slots-p slots (instance-slot-names object)))
602 (mapper #'(lambda (slot)
603 (if (slot-boundp object slot)
604 (slot-value object slot)
605 (%unbound-marker))))
606 (slot-values (mapcar mapper slot-names)))
607 (declare (dynamic-extent mapper))
608 (values `(allocate-instance-of-class ,(class-name (class-of object)))
609 (when slot-names
610 `(%set-slot-values ,object ,slot-names ,slot-values)))))
611
612(defun allocate-instance-of-class (class-name)
613 (allocate-instance (find-class class-name)))
614
615(defun progn-load-functions (&rest load-functions)
616 (declare (dynamic-extent load-functions))
617 (when load-functions
618 (do* ((this load-functions next)
619 (next (cdr this) (cdr this)))
620 ((null next) (apply 'funcall (car this)))
621 (apply 'funcall (car this)))))
622
623(defun progn-init-functions (object &rest init-functions)
624 (declare (dynamic-extent init-functions))
625 (dolist (f.args init-functions)
626 (apply (car f.args) object (cdr f.args))))
627
628(defun p-load-instance (pheap disk-cache pointer depth subtype)
629 (declare (ignore subtype))
630 (let* ((cached? t)
631 class
632 (instance (maybe-cached-value pheap pointer
633 (setq cached? nil)
634 (if (null depth)
635 (return-from p-load-instance (pptr pheap pointer)))
636 (setq class (pointer-load pheap
637 (dc-%svref disk-cache
638 (dc-instance-class-wrapper
639 disk-cache pointer)
640 $wrapper.class)
641 :default
642 disk-cache))
643 (allocate-instance class))))
644 (when (or (not cached?)
645 (and (eq depth t)
646 (let ((p-load-hash (p-load-hash pheap)))
647 (unless (gethash instance p-load-hash)
648 (setf (gethash instance p-load-hash) instance)))))
649 (let ((next-level-depth (cond ((or (eq depth :single) (fixnump depth)) nil)
650 (t depth)))
651 (disk-resident-slots (wood-disk-resident-slot-names instance)))
652 (multiple-value-bind (slot-vector slot-names real-slot-names)
653 (dc-updated-instance-slots
654 disk-cache pointer class pheap t)
655 (dotimes (i (length slot-names))
656 (let ((slot-name (elt slot-names i)))
657 (when (or (null real-slot-names) (position slot-name real-slot-names))
658 (multiple-value-bind (pointer immediate?)
659 (dc-%svref disk-cache slot-vector i)
660 (if immediate?
661 (if (eq pointer (%unbound-marker))
662 (slot-makunbound instance slot-name)
663 (setf (wood-slot-value instance slot-name) pointer))
664 (setf (wood-slot-value instance slot-name)
665 (if (member slot-name disk-resident-slots :test #'eq)
666 (pptr pheap pointer)
667 (pointer-load pheap pointer next-level-depth disk-cache))))))))
668 (when real-slot-names
669 (let (new-slot-names)
670 (dotimes (i (length real-slot-names))
671 (let ((slot-name (svref real-slot-names i)))
672 (unless (position slot-name slot-names)
673 (push slot-name new-slot-names))))
674 (when new-slot-names
675 (shared-initialize instance new-slot-names))))))
676 (unless cached?
677 (initialize-persistent-instance instance)))
678 instance))
679
680
681; These methods allow users to specialize the way that CLOS instances are saved.
682
683; Return a vector of the names of the slots to be saved for an instance.
684; The instance saving code assumes that multiple calls to this
685; method will return the same (EQ) vector unless the class has been redefined.
686; May be called with a CLASS-PROTOTYPE, so don't expect any of the slots
687; to contain useful information.
688(defmethod wood-slot-names-vector ((object standard-object))
689 (class-slots-vector (class-of object)))
690
691; These allow specialization of slot-value.
692; Some slots may want to be saved in a different format,
693; or interned on the way back in.
694(defmethod wood-slot-value ((object standard-object) slot-name)
695 (slot-value object slot-name))
696
697(defmethod (setf wood-slot-value) (value (object standard-object) slot-name)
698 (setf (slot-value object slot-name) value))
699
700
701; This generic function is called on a newly loaded CLOS instance
702(defmethod initialize-persistent-instance (instance)
703 (declare (ignore instance))
704 nil)
705
706
707; This generic function is called when an instance is p-load'ed to
708; determine which slots should remain disk resident and have pptr's
709; put in the instance.
710(defgeneric wood-disk-resident-slot-names (instance)
711 (:method ((instance t))
712 nil))
713
714(declaim (inline default-slot-value-processor))
715
716(defun default-slot-value-processor (instance slot-name value sticky p-loader pass-instance-to-p-loader)
717 (if (pptr-p value)
718 (let ((loaded-value
719 (if pass-instance-to-p-loader
720 (funcall p-loader instance value)
721 (funcall p-loader value))))
722 (when sticky
723 (setf (slot-value instance slot-name) loaded-value))
724 loaded-value)
725 value))
726
727; An easy way to define a wood-disk-resident-slot-names method
728; and some :around methods on slot accessors to swap the slots
729; in on demand.
730(defmacro define-disk-resident-slots ((class-name &key
731 sticky
732 (p-loader ''p-load)
733 pass-instance-to-p-loader
734 (slot-value-processor '#'default-slot-value-processor))
735 &body slots-and-accessors)
736 (let* ((sticky-p #'(lambda (slot-and-accessor)
737 (let ((cell (and (listp slot-and-accessor) (cddr slot-and-accessor))))
738 (if cell (car cell) sticky))))
739 (slots (mapcar #'(lambda (x) (if (listp x) (first x) x)) slots-and-accessors))
740 (accessors (mapcar #'(lambda (x) (if (listp x) (second x) x)) slots-and-accessors))
741 (stickies (mapcar sticky-p slots-and-accessors))
742 (class (find-class class-name nil))
743 (instance (make-symbol (symbol-name class-name))))
744 (declare (dynamic-extent sticky-p))
745 (flet ((require-symbol (x) (require-type x 'symbol)))
746 (mapc #'require-symbol slots)
747 (mapc #'require-symbol accessors))
748 (when class
749 (let* ((class-slots (mapcar 'slot-definition-name (class-instance-slots class))))
750 (flet ((require-slot (slot)
751 (unless (member slot class-slots :test 'eq)
752 (warn "~s is not an instance slot of ~s" slot class))))
753 (declare (dynamic-extent #'require-slot))
754 (mapc #'require-slot slots))))
755 `(progn
756 ,@(loop for slot in slots
757 for accessor in accessors
758 for sticky in stickies
759 collect
760 `(defmethod ,accessor :around ((,instance ,class-name))
761 (funcall ,slot-value-processor
762 ,instance
763 ',slot
764 (call-next-method)
765 ,(not (null sticky))
766 ,p-loader
767 ,(not (null pass-instance-to-p-loader)))))
768 (defmethod wood-disk-resident-slot-names ((,class-name ,class-name))
769 ',slots)
770 (record-source-file ',class-name :disk-resident-slots)
771 ',class-name)))
772
773
774
775;;; 1 3/10/94 bill 1.8d247
776;;; 2 7/26/94 Derek 1.9d027
777;;; 3 10/04/94 bill 1.9d071
778;;; 4 11/01/94 Derek 1.9d085 Bill's Saving Library Task
779;;; 5 11/03/94 Moon 1.9d086
780;;; 6 11/05/94 kab 1.9d087
781;;; 2 3/23/95 bill 1.11d010
Note: See TracBrowser for help on using the repository browser.