~ubuntu-branches/ubuntu/quantal/gclcvs/quantal

« back to all changes in this revision

Viewing changes to pcl/pcl_cache.lisp

  • Committer: Bazaar Package Importer
  • Author(s): Camm Maguire
  • Date: 2004-06-24 15:13:46 UTC
  • Revision ID: james.westby@ubuntu.com-20040624151346-xh0xaaktyyp7aorc
Tags: 2.7.0-26
C_GC_OFFSET is 2 on m68k-linux

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
;;;-*-Mode:LISP; Package:(PCL LISP 1000); Base:10; Syntax:Common-lisp -*-
 
2
;;;
 
3
;;; *************************************************************************
 
4
;;; Copyright (c) 1985, 1986, 1987, 1988, 1989, 1990 Xerox Corporation.
 
5
;;; All rights reserved.
 
6
;;;
 
7
;;; Use and copying of this software and preparation of derivative works
 
8
;;; based upon this software are permitted.  Any distribution of this
 
9
;;; software or derivative works must comply with all applicable United
 
10
;;; States export control laws.
 
11
;;; 
 
12
;;; This software is made available AS IS, and Xerox Corporation makes no
 
13
;;; warranty about the software, its performance or its conformity to any
 
14
;;; specification.
 
15
;;; 
 
16
;;; Any person obtaining a copy of this software is requested to send their
 
17
;;; name and post office or electronic mail address to:
 
18
;;;   CommonLoops Coordinator
 
19
;;;   Xerox PARC
 
20
;;;   3333 Coyote Hill Rd.
 
21
;;;   Palo Alto, CA 94304
 
22
;;; (or send Arpanet mail to CommonLoops-Coordinator.pa@Xerox.arpa)
 
23
;;;
 
24
;;; Suggestions, comments and requests for improvements are also welcome.
 
25
;;; *************************************************************************
 
26
;;;
 
27
;;; The basics of the PCL wrapper cache mechanism.
 
28
;;;
 
29
 
 
30
(in-package :pcl)
 
31
;;;
 
32
;;; The caching algorithm implemented:
 
33
;;;
 
34
;;; << put a paper here >>
 
35
;;;
 
36
;;; For now, understand that as far as most of this code goes, a cache has
 
37
;;; two important properties.  The first is the number of wrappers used as
 
38
;;; keys in each cache line.  Throughout this code, this value is always
 
39
;;; called NKEYS.  The second is whether or not the cache lines of a cache
 
40
;;; store a value.  Throughout this code, this always called VALUEP.
 
41
;;;
 
42
;;; Depending on these values, there are three kinds of caches.
 
43
;;;
 
44
;;; NKEYS = 1, VALUEP = NIL
 
45
;;;
 
46
;;; In this kind of cache, each line is 1 word long.  No cache locking is
 
47
;;; needed since all read's in the cache are a single value.  Nevertheless
 
48
;;; line 0 (location 0) is reserved, to ensure that invalid wrappers will
 
49
;;; not get a first probe hit.
 
50
;;;
 
51
;;; To keep the code simpler, a cache lock count does appear in location 0
 
52
;;; of these caches, that count is incremented whenever data is written to
 
53
;;; the cache.  But, the actual lookup code (see make-dlap) doesn't need to
 
54
;;; do locking when reading the cache.
 
55
;;; 
 
56
;;;
 
57
;;; NKEYS = 1, VALUEP = T
 
58
;;;
 
59
;;; In this kind of cache, each line is 2 words long.  Cache locking must
 
60
;;; be done to ensure the synchronization of cache reads.  Line 0 of the
 
61
;;; cache (location 0) is reserved for the cache lock count.  Location 1
 
62
;;; of the cache is unused (in effect wasted).
 
63
;;; 
 
64
;;; NKEYS > 1
 
65
;;;
 
66
;;; In this kind of cache, the 0 word of the cache holds the lock count.
 
67
;;; The 1 word of the cache is line 0.  Line 0 of these caches is not
 
68
;;; reserved.
 
69
;;;
 
70
;;; This is done because in this sort of cache, the overhead of doing the
 
71
;;; cache probe is high enough that the 1+ required to offset the location
 
72
;;; is not a significant cost.  In addition, because of the larger line
 
73
;;; sizes, the space that would be wasted by reserving line 0 to hold the
 
74
;;; lock count is more significant.
 
75
;;;
 
76
 
 
77
;;;
 
78
;;; Caches
 
79
;;;
 
80
;;; A cache is essentially just a vector.  The use of the individual `words'
 
81
;;; in the vector depends on particular properties of the cache as described
 
82
;;; above.
 
83
;;;
 
84
;;; This defines an abstraction for caches in terms of their most obvious
 
85
;;; implementation as simple vectors.  But, please notice that part of the
 
86
;;; implementation of this abstraction, is the function lap-out-cache-ref.
 
87
;;; This means that most port-specific modifications to the implementation
 
88
;;; of caches will require corresponding port-specific modifications to the
 
89
;;; lap code assembler.
 
90
;;;
 
91
(defmacro cache-vector-ref (cache-vector location)
 
92
  `(svref (the simple-vector ,cache-vector)
 
93
          (#-cmu the #+cmu ext:truly-the non-negative-fixnum ,location)))
 
94
 
 
95
(defmacro cache-vector-size (cache-vector)
 
96
  `(array-dimension (the simple-vector ,cache-vector) 0))
 
97
 
 
98
(defun allocate-cache-vector (size)
 
99
  (make-array size :adjustable nil))
 
100
 
 
101
(defmacro cache-vector-lock-count (cache-vector)
 
102
  `(cache-vector-ref ,cache-vector 0))
 
103
 
 
104
(defun flush-cache-vector-internal (cache-vector)
 
105
  (without-interrupts  
 
106
    (fill (the simple-vector cache-vector) nil)
 
107
    (setf (cache-vector-lock-count cache-vector) 0))
 
108
  cache-vector)
 
109
 
 
110
(defmacro modify-cache (cache-vector &body body)
 
111
  `(without-interrupts
 
112
     (multiple-value-prog1
 
113
       (progn ,@body)
 
114
       (let ((old-count (cache-vector-lock-count ,cache-vector)))
 
115
         (declare (type non-negative-fixnum old-count))
 
116
         (setf (cache-vector-lock-count ,cache-vector)
 
117
               (if (= old-count most-positive-fixnum)
 
118
                   1 (the non-negative-fixnum (1+ old-count))))))))
 
119
 
 
120
(deftype field-type ()
 
121
  '(integer 0    ;#.(position 'number wrapper-layout)
 
122
            7))  ;#.(position 'number wrapper-layout :from-end t)
 
123
 
 
124
(eval-when (compile load eval)
 
125
(defun power-of-two-ceiling (x)
 
126
  (declare (type (and fixnum (integer 1 *)) x))
 
127
  ;;(expt 2 (ceiling (log x 2)))
 
128
  (the non-negative-fixnum (ash 1 (integer-length (1- x)))))
 
129
 
 
130
(defconstant *nkeys-limit* 256)
 
131
)
 
132
 
 
133
(defstruct (cache
 
134
             (:print-function print-cache)
 
135
             (:constructor make-cache ())
 
136
             (:copier copy-cache-internal))
 
137
  (owner nil)
 
138
  (nkeys 1 :type (integer 1 #.*nkeys-limit*))
 
139
  (valuep nil :type (member nil t))
 
140
  (nlines 0 :type non-negative-fixnum)
 
141
  (field 0 :type field-type)
 
142
  (limit-fn #'default-limit-fn :type function)
 
143
  (mask 0 :type non-negative-fixnum)
 
144
  (size 0 :type non-negative-fixnum)
 
145
  (line-size 1 :type (integer 1 #.(power-of-two-ceiling (1+ *nkeys-limit*))))
 
146
  (max-location 0 :type non-negative-fixnum)
 
147
  (vector #() :type simple-vector)
 
148
  (overflow nil :type list))
 
149
 
 
150
#+cmu
 
151
(declaim (ext:freeze-type cache))
 
152
 
 
153
(defun print-cache (cache stream depth)
 
154
  (declare (ignore depth))
 
155
  (printing-random-thing (cache stream)
 
156
    (format stream "cache ~D ~S ~D" 
 
157
            (cache-nkeys cache) (cache-valuep cache) (cache-nlines cache))))
 
158
 
 
159
#+akcl
 
160
(si::freeze-defstruct 'cache)
 
161
 
 
162
(defmacro cache-lock-count (cache)
 
163
  `(cache-vector-lock-count (cache-vector ,cache)))
 
164
 
 
165
 
 
166
;;;
 
167
;;; Some facilities for allocation and freeing caches as they are needed.
 
168
;;; This is done on the assumption that a better port of PCL will arrange
 
169
;;; to cons these all the same static area.  Given that, the fact that
 
170
;;; PCL tries to reuse them should be a win.
 
171
;;; 
 
172
(defvar *free-cache-vectors* (make-hash-table :size 16 :test 'eql))
 
173
 
 
174
;;;
 
175
;;; Return a cache that has had flush-cache-vector-internal called on it.  This
 
176
;;; returns a cache of exactly the size requested, it won't ever return a
 
177
;;; larger cache.
 
178
;;; 
 
179
(defun get-cache-vector (size)
 
180
  (let ((entry (gethash size *free-cache-vectors*)))
 
181
    (without-interrupts
 
182
      (cond ((null entry)
 
183
             (setf (gethash size *free-cache-vectors*) (cons 0 nil))
 
184
             (get-cache-vector size))
 
185
            ((null (cdr entry))
 
186
             (incf (car entry))
 
187
             (flush-cache-vector-internal (allocate-cache-vector size)))
 
188
            (t
 
189
             (let ((cache (cdr entry)))
 
190
               (setf (cdr entry) (cache-vector-ref cache 0))
 
191
               (flush-cache-vector-internal cache)))))))
 
192
 
 
193
(defun free-cache-vector (cache-vector)
 
194
  (let ((entry (gethash (cache-vector-size cache-vector) *free-cache-vectors*)))
 
195
    (without-interrupts
 
196
      (if (null entry)
 
197
          (error "Attempt to free a cache-vector not allocated by GET-CACHE-VECTOR.")
 
198
          (let ((thread (cdr entry)))
 
199
            (loop (unless thread (return))
 
200
                  (when (eq thread cache-vector) (error "Freeing a cache twice."))
 
201
                  (setq thread (cache-vector-ref thread 0)))      
 
202
            (flush-cache-vector-internal cache-vector)          ;Help the GC
 
203
            (setf (cache-vector-ref cache-vector 0) (cdr entry))
 
204
            (setf (cdr entry) cache-vector)
 
205
            nil)))))
 
206
 
 
207
;;;
 
208
;;; This is just for debugging and analysis.  It shows the state of the free
 
209
;;; cache resource.
 
210
;;; 
 
211
(defun show-free-cache-vectors ()
 
212
  (let ((elements ()))
 
213
    (maphash #'(lambda (s e) (push (list s e) elements)) *free-cache-vectors*)
 
214
    (setq elements (sort elements #'< :key #'car))
 
215
    (dolist (e elements)
 
216
      (let* ((size (car e))
 
217
             (entry (cadr e))
 
218
             (allocated (car entry))
 
219
             (head (cdr entry))
 
220
             (free 0))
 
221
        (loop (when (null head) (return t))
 
222
              (setq head (cache-vector-ref head 0))
 
223
              (incf free))
 
224
        (format t
 
225
                "~&There  ~4D are caches of size ~4D. (~D free  ~3D%)"
 
226
                allocated
 
227
                size
 
228
                free
 
229
                (floor (* 100 (/ free (float allocated)))))))))
 
230
 
 
231
 
 
232
;;;
 
233
;;; Wrapper cache numbers
 
234
;;; 
 
235
 
 
236
;;;
 
237
;;; The constant WRAPPER-CACHE-NUMBER-ADDS-OK controls the number of non-zero
 
238
;;; bits wrapper cache numbers will have.
 
239
;;;
 
240
;;; The value of this constant is the number of wrapper cache numbers which
 
241
;;; can be added and still be certain the result will be a fixnum.  This is
 
242
;;; used by all the code that computes primary cache locations from multiple
 
243
;;; wrappers.
 
244
;;;
 
245
;;; The value of this constant is used to derive the next two which are the
 
246
;;; forms of this constant which it is more convenient for the runtime code
 
247
;;; to use.
 
248
;;; 
 
249
#-cmu17
 
250
(eval-when (compile load eval)
 
251
 
 
252
(defconstant wrapper-cache-number-adds-ok 4)
 
253
 
 
254
;;; Incorrect.  This actually allows 15 or 16 adds, depending on whether
 
255
;;; most-positive-fixnum is all-ones.  -- Ram
 
256
;;;
 
257
(defconstant wrapper-cache-number-length
 
258
             (- (integer-length most-positive-fixnum)
 
259
                wrapper-cache-number-adds-ok))
 
260
 
 
261
(defconstant wrapper-cache-number-mask
 
262
             (1- (expt 2 wrapper-cache-number-length)))
 
263
 
 
264
 
 
265
(defvar *get-wrapper-cache-number* (make-random-state))
 
266
 
 
267
(defun get-wrapper-cache-number ()
 
268
  (let ((n 0))
 
269
    (declare (type non-negative-fixnum n))
 
270
    (loop
 
271
      (setq n
 
272
            (logand wrapper-cache-number-mask
 
273
                    (random most-positive-fixnum *get-wrapper-cache-number*)))
 
274
      (unless (zerop n) (return n)))))
 
275
 
 
276
 
 
277
(unless (> wrapper-cache-number-length 8)
 
278
  (error "In this implementation of Common Lisp, fixnums are so small that~@
 
279
          wrapper cache numbers end up being only ~D bits long.  This does~@
 
280
          not actually keep PCL from running, but it may degrade cache~@
 
281
          performance.~@
 
282
          You may want to consider changing the value of the constant~@
 
283
          WRAPPER-CACHE-NUMBER-ADDS-OK.")))
 
284
 
 
285
#+cmu17
 
286
(progn
 
287
  (defconstant wrapper-cache-number-length
 
288
    (integer-length kernel:layout-hash-max))
 
289
  
 
290
  (defconstant wrapper-cache-number-mask kernel:layout-hash-max)
 
291
  
 
292
  (defconstant wrapper-cache-number-adds-ok
 
293
    (truncate most-positive-fixnum kernel:layout-hash-max)))
 
294
 
 
295
 
 
296
;;;
 
297
;;; wrappers themselves
 
298
;;;
 
299
;;; This caching algorithm requires that wrappers have more than one wrapper
 
300
;;; cache number.  You should think of these multiple numbers as being in
 
301
;;; columns.  That is, for a given cache, the same column of wrapper cache
 
302
;;; numbers will be used.
 
303
;;;
 
304
;;; If at some point the cache distribution of a cache gets bad, the cache
 
305
;;; can be rehashed by switching to a different column.
 
306
;;;
 
307
;;; The columns are referred to by field number which is that number which,
 
308
;;; when used as a second argument to wrapper-ref, will return that column
 
309
;;; of wrapper cache number.
 
310
;;;
 
311
;;; This code is written to allow flexibility as to how many wrapper cache
 
312
;;; numbers will be in each wrapper, and where they will be located.  It is
 
313
;;; also set up to allow port specific modifications to `pack' the wrapper
 
314
;;; cache numbers on machines where the addressing modes make that a good
 
315
;;; idea.
 
316
;;; 
 
317
#-structure-wrapper
 
318
(progn
 
319
(eval-when (compile load eval)
 
320
(defconstant wrapper-layout
 
321
             '(number
 
322
               number
 
323
               number
 
324
               number
 
325
               number
 
326
               number
 
327
               number
 
328
               number
 
329
               state
 
330
               instance-slots-layout
 
331
               class-slots
 
332
               class
 
333
               no-of-instance-slots))
 
334
)
 
335
 
 
336
(eval-when (compile load eval)
 
337
 
 
338
(defun wrapper-field (type)
 
339
  (posq type wrapper-layout))
 
340
 
 
341
(defun next-wrapper-field (field-number)
 
342
  (position (nth field-number wrapper-layout)
 
343
            wrapper-layout
 
344
            :start (1+ field-number)))
 
345
 
 
346
(defmacro first-wrapper-cache-number-index ()
 
347
  `(wrapper-field 'number))
 
348
 
 
349
(defmacro next-wrapper-cache-number-index (field-number)
 
350
  `(next-wrapper-field ,field-number))
 
351
 
 
352
);eval-when
 
353
 
 
354
(defmacro wrapper-cache-number-vector (wrapper)
 
355
  wrapper)
 
356
 
 
357
(defmacro cache-number-vector-ref (cnv n)
 
358
  `(svref ,cnv ,n))
 
359
 
 
360
 
 
361
(defmacro wrapper-ref (wrapper n)
 
362
  `(svref ,wrapper ,n))
 
363
 
 
364
(defmacro wrapper-state (wrapper)
 
365
  `(wrapper-ref ,wrapper ,(wrapper-field 'state)))
 
366
 
 
367
(defmacro wrapper-instance-slots-layout (wrapper)
 
368
  `(wrapper-ref ,wrapper ,(wrapper-field 'instance-slots-layout)))
 
369
 
 
370
(defmacro wrapper-class-slots (wrapper)
 
371
  `(wrapper-ref ,wrapper ,(wrapper-field 'class-slots)))
 
372
 
 
373
(defmacro wrapper-class (wrapper)
 
374
  `(wrapper-ref ,wrapper ,(wrapper-field 'class)))
 
375
 
 
376
(defmacro wrapper-no-of-instance-slots (wrapper)
 
377
  `(wrapper-ref ,wrapper ,(wrapper-field 'no-of-instance-slots)))
 
378
 
 
379
(defmacro make-wrapper-internal ()
 
380
  `(let ((wrapper (make-array ,(length wrapper-layout) :adjustable nil)))
 
381
     ,@(gathering1 (collecting)
 
382
         (iterate ((i (interval :from 0))
 
383
                   (desc (list-elements wrapper-layout)))
 
384
           (ecase desc
 
385
             (number
 
386
              (gather1 `(setf (wrapper-ref wrapper ,i)
 
387
                              (get-wrapper-cache-number))))
 
388
             ((state instance-slots-layout class-slots class no-of-instance-slots)))))
 
389
     (setf (wrapper-state wrapper) 't)     
 
390
     wrapper))
 
391
 
 
392
(defun make-wrapper (no-of-instance-slots &optional class)
 
393
  (let ((wrapper (make-wrapper-internal)))
 
394
    (setf (wrapper-no-of-instance-slots wrapper) no-of-instance-slots)
 
395
    (setf (wrapper-class wrapper) class)
 
396
    wrapper))
 
397
 
 
398
)
 
399
 
 
400
; In CMUCL we want to do type checking as early as possible; structures help this.
 
401
#+structure-wrapper
 
402
(eval-when (compile load eval)
 
403
 
 
404
(defconstant wrapper-cache-number-vector-length
 
405
  #+cmu17 kernel:layout-hash-length #-cmu17 8)
 
406
 
 
407
#-cmu17
 
408
(deftype cache-number-vector ()
 
409
  `(simple-array fixnum (,wrapper-cache-number-vector-length)))
 
410
 
 
411
(defconstant wrapper-layout (make-list wrapper-cache-number-vector-length
 
412
                                       :initial-element 'number))
 
413
 
 
414
)
 
415
 
 
416
#+structure-wrapper
 
417
(progn
 
418
 
 
419
#-(or new-kcl-wrapper cmu17)
 
420
(defun make-wrapper-cache-number-vector ()
 
421
  (let ((cnv (make-array #.wrapper-cache-number-vector-length
 
422
                         :element-type 'fixnum)))
 
423
    (dotimes (i #.wrapper-cache-number-vector-length)
 
424
      (setf (aref cnv i) (get-wrapper-cache-number)))
 
425
    cnv))
 
426
 
 
427
 
 
428
#-cmu17
 
429
(defstruct (wrapper
 
430
             #+new-kcl-wrapper (:include si::basic-wrapper)
 
431
             (:print-function print-wrapper)
 
432
             #-new-kcl-wrapper
 
433
             (:constructor make-wrapper (no-of-instance-slots &optional class))
 
434
             #+new-kcl-wrapper
 
435
             (:constructor make-wrapper-internal))
 
436
  #-new-kcl-wrapper
 
437
  (cache-number-vector (make-wrapper-cache-number-vector)
 
438
                       :type cache-number-vector)
 
439
  #-new-kcl-wrapper
 
440
  (state t :type (or (member t) cons)) 
 
441
  ;;  either t or a list (state-sym new-wrapper)
 
442
  ;;           where state-sym is either :flush or :obsolete
 
443
  (instance-slots-layout nil :type list)
 
444
  (class-slots nil :type list)
 
445
  #-new-kcl-wrapper
 
446
  (no-of-instance-slots 0 :type fixnum)
 
447
  #-new-kcl-wrapper
 
448
  (class *the-class-t* :type class))
 
449
 
 
450
 
 
451
(unless (boundp '*the-class-t*) (setq *the-class-t* nil))
 
452
 
 
453
#+new-kcl-wrapper
 
454
(defmacro wrapper-no-of-instance-slots (wrapper)
 
455
  `(si::s-data-length ,wrapper))
 
456
 
 
457
 
 
458
;;; Note that for CMU, the WRAPPER of a built-in or structure class will be
 
459
;;; some other kind of KERNEL:LAYOUT, but this shouldn't matter, since the only
 
460
;;; two slots that WRAPPER adds are meaningless in those cases.
 
461
;;;
 
462
#+cmu17
 
463
(progn
 
464
  (defstruct (wrapper
 
465
              (:include kernel:layout)
 
466
              (:conc-name %wrapper-)
 
467
              (:print-function print-wrapper)
 
468
              (:constructor make-wrapper-internal))
 
469
    (instance-slots-layout nil :type list)
 
470
    (class-slots nil :type list))
 
471
  (declaim (ext:freeze-type wrapper))
 
472
 
 
473
  (defmacro wrapper-class (wrapper)
 
474
    `(kernel:class-pcl-class (kernel:layout-class ,wrapper)))
 
475
  (defmacro wrapper-no-of-instance-slots (wrapper)
 
476
    `(kernel:layout-length ,wrapper))
 
477
  (declaim (inline wrapper-state (setf wrapper-state)))
 
478
 
 
479
  (defun wrapper-state (wrapper)
 
480
    (let ((invalid (kernel:layout-invalid wrapper)))
 
481
      (cond ((null invalid)
 
482
             t)
 
483
            ((atom invalid)
 
484
             ;; Some non-pcl object.  invalid is probably :INVALID
 
485
             ;; We should compute the new wrapper here instead
 
486
             ;; of returning nil, but why bother, since
 
487
             ;; obsolete-instance-trap can't use it.
 
488
             '(:obsolete nil))
 
489
            (t
 
490
             invalid))))
 
491
  
 
492
  (defun (setf wrapper-state) (new-value wrapper)
 
493
    (setf (kernel:layout-invalid wrapper)
 
494
          (if (eq new-value 't)
 
495
              nil
 
496
              new-value)))
 
497
 
 
498
  (defmacro wrapper-instance-slots-layout (wrapper)
 
499
    `(%wrapper-instance-slots-layout ,wrapper))
 
500
  (defmacro wrapper-class-slots (wrapper)
 
501
    `(%wrapper-class-slots ,wrapper))
 
502
  (defmacro wrapper-cache-number-vector (x) x))
 
503
 
 
504
 
 
505
#+new-kcl-wrapper
 
506
(defun make-wrapper (size &optional class)
 
507
  (multiple-value-bind (raw slot-positions)
 
508
      (if (< size 50)
 
509
          (values si::*all-t-s-type* si::*standard-slot-positions*)
 
510
          (values (make-array size :element-type 'unsigned-char)
 
511
                  (let ((array (make-array size :element-type 'unsigned-short)))
 
512
                    (dotimes (i size)
 
513
                      (declare (fixnum i))
 
514
                      (setf (aref array i) (* #.(si::size-of t) i))))))
 
515
    (make-wrapper-internal :length size
 
516
                           :raw raw
 
517
                           :print-function 'print-std-instance
 
518
                           :slot-position slot-positions
 
519
                           :size (* size #.(si::size-of t))
 
520
                           :class class)))
 
521
 
 
522
#+cmu17
 
523
;;; BOOT-MAKE-WRAPPER  --  Interface
 
524
;;;
 
525
;;;    Called in BRAID when we are making wrappers for classes whose slots are
 
526
;;; not initialized yet, and which may be built-in classes.  We pass in the
 
527
;;; class name in addition to the class.
 
528
;;;
 
529
(defun boot-make-wrapper (length name &optional class)
 
530
  (let ((found (lisp:find-class name nil)))
 
531
    (cond
 
532
     (found
 
533
      (unless (kernel:class-pcl-class found)
 
534
        (setf (kernel:class-pcl-class found) class))
 
535
      (assert (eq (kernel:class-pcl-class found) class))
 
536
      (let ((layout (kernel:class-layout found)))
 
537
        (assert layout)
 
538
        layout))
 
539
     (t
 
540
      (kernel:initialize-layout-hash
 
541
       (make-wrapper-internal
 
542
        :length length
 
543
        :class (kernel:make-standard-class :name name :pcl-class class)))))))
 
544
 
 
545
 
 
546
#+cmu17
 
547
;;; MAKE-WRAPPER  --  Interface
 
548
;;;
 
549
;;;    In CMU CL, the layouts (a.k.a wrappers) for built-in and structure
 
550
;;; classes already exist when PCL is initialized, so we don't necessarily
 
551
;;; always make a wrapper.  Also, we help maintain the mapping between
 
552
;;; lisp:class and pcl::class objects.
 
553
;;;
 
554
(defun make-wrapper (length class)
 
555
  (cond
 
556
   ((typep class 'std-class)
 
557
    (kernel:initialize-layout-hash
 
558
     (make-wrapper-internal
 
559
      :length length
 
560
      :class
 
561
      (let ((owrap (class-wrapper class)))
 
562
        (cond (owrap
 
563
               (kernel:layout-class owrap))
 
564
              ((*subtypep (class-of class)
 
565
                          *the-class-standard-class*)
 
566
               (kernel:make-standard-class :pcl-class class))
 
567
              (t
 
568
               (kernel:make-random-pcl-class :pcl-class class)))))))
 
569
   (t
 
570
    (let* ((found (lisp:find-class (slot-value class 'name)))
 
571
           (layout (kernel:class-layout found)))
 
572
      (unless (kernel:class-pcl-class found)
 
573
        (setf (kernel:class-pcl-class found) class))
 
574
      (assert (eq (kernel:class-pcl-class found) class))
 
575
      (assert layout)
 
576
      layout))))
 
577
 
 
578
(defun print-wrapper (wrapper stream depth)
 
579
  (declare (ignore depth))
 
580
  (printing-random-thing (wrapper stream)
 
581
    (format stream "Wrapper ~S" (wrapper-class wrapper))))
 
582
 
 
583
(defmacro first-wrapper-cache-number-index ()
 
584
  0)
 
585
 
 
586
(defmacro next-wrapper-cache-number-index (field-number)
 
587
  `(and (< (the field-type ,field-number)
 
588
           #.(1- wrapper-cache-number-vector-length))
 
589
        (the field-type (1+ (the field-type ,field-number)))))
 
590
 
 
591
#-cmu17
 
592
(defmacro cache-number-vector-ref (cnv n)
 
593
  `(#-kcl svref #+kcl aref ,cnv ,n))
 
594
 
 
595
#+cmu17
 
596
(defmacro cache-number-vector-ref (cnv n)
 
597
  `(wrapper-cache-number-vector-ref ,cnv ,n))
 
598
 
 
599
)
 
600
 
 
601
#-cmu17
 
602
(defmacro wrapper-cache-number-vector-ref (wrapper n)
 
603
  `(the fixnum
 
604
        (#-structure-wrapper svref #+structure-wrapper aref
 
605
          (wrapper-cache-number-vector ,wrapper) ,n)))
 
606
#+cmu17
 
607
(defmacro wrapper-cache-number-vector-ref (wrapper n)
 
608
  `(kernel:layout-hash ,wrapper ,n))
 
609
 
 
610
(defmacro class-no-of-instance-slots (class)
 
611
  `(wrapper-no-of-instance-slots (class-wrapper ,class)))
 
612
 
 
613
(defmacro wrapper-class* (wrapper)
 
614
  #-(or new-kcl-wrapper cmu17)
 
615
  `(wrapper-class ,wrapper)
 
616
  #+(or new-kcl-wrapper cmu17)
 
617
  `(let ((wrapper ,wrapper))
 
618
     (or (wrapper-class wrapper)
 
619
         (find-structure-class
 
620
          #+new-kcl-wrapper (si::s-data-name wrapper)
 
621
          #+cmu17 (lisp:class-name (kernel:layout-class wrapper))))))
 
622
 
 
623
;;;
 
624
;;; The wrapper cache machinery provides general mechanism for trapping on
 
625
;;; the next access to any instance of a given class.  This mechanism is
 
626
;;; used to implement the updating of instances when the class is redefined
 
627
;;; (make-instances-obsolete).  The same mechanism is also used to update
 
628
;;; generic function caches when there is a change to the supers of a class.
 
629
;;;
 
630
;;; Basically, a given wrapper can be valid or invalid.  If it is invalid,
 
631
;;; it means that any attempt to do a wrapper cache lookup using the wrapper
 
632
;;; should trap.  Also, methods on slot-value-using-class check the wrapper
 
633
;;; validity as well.  This is done by calling check-wrapper-validity.
 
634
;;; 
 
635
 
 
636
(defmacro invalid-wrapper-p (wrapper)
 
637
  `(neq (wrapper-state ,wrapper) 't))
 
638
 
 
639
(defvar *previous-nwrappers* (make-hash-table))
 
640
 
 
641
(defun invalidate-wrapper (owrapper state nwrapper)
 
642
  (ecase state
 
643
    ((:flush :obsolete)
 
644
     (let ((new-previous ()))
 
645
       ;;
 
646
       ;; First off, a previous call to invalidate-wrapper may have recorded
 
647
       ;; owrapper as an nwrapper to update to.  Since owrapper is about to
 
648
       ;; be invalid, it no longer makes sense to update to it.
 
649
       ;;
 
650
       ;; We go back and change the previously invalidated wrappers so that
 
651
       ;; they will now update directly to nwrapper.  This corresponds to a
 
652
       ;; kind of transitivity of wrapper updates.
 
653
       ;; 
 
654
       (dolist (previous (gethash owrapper *previous-nwrappers*))
 
655
         (when (eq state ':obsolete)
 
656
           (setf (car previous) ':obsolete))
 
657
         (setf (cadr previous) nwrapper)
 
658
         (push previous new-previous))
 
659
       
 
660
       (let ((ocnv (wrapper-cache-number-vector owrapper)))
 
661
         (iterate ((type (list-elements wrapper-layout))
 
662
                   (i (interval :from 0)))
 
663
           (when (eq type 'number) (setf (cache-number-vector-ref ocnv i) 0))))
 
664
       (push (setf (wrapper-state owrapper) (list state nwrapper))
 
665
             new-previous)
 
666
       
 
667
       (setf (gethash owrapper *previous-nwrappers*) ()
 
668
             (gethash nwrapper *previous-nwrappers*) new-previous)))))
 
669
 
 
670
(defun check-wrapper-validity (instance)
 
671
  (let* ((owrapper (wrapper-of instance))
 
672
         (state (wrapper-state owrapper)))
 
673
    (if (eq state  't)
 
674
        owrapper
 
675
        (let ((nwrapper
 
676
                (ecase (car state)
 
677
                  (:flush
 
678
                    (flush-cache-trap owrapper (cadr state) instance))
 
679
                  (:obsolete
 
680
                    (obsolete-instance-trap owrapper (cadr state) instance)))))
 
681
          ;;
 
682
          ;; This little bit of error checking is superfluous.  It only
 
683
          ;; checks to see whether the person who implemented the trap
 
684
          ;; handling screwed up.  Since that person is hacking internal
 
685
          ;; PCL code, and is not a user, this should be needless.  Also,
 
686
          ;; since this directly slows down instance update and generic
 
687
          ;; function cache refilling, feel free to take it out sometime
 
688
          ;; soon.
 
689
          ;; 
 
690
          (cond ((neq nwrapper (wrapper-of instance))
 
691
                 (error "Wrapper returned from trap not wrapper of instance."))
 
692
                ((invalid-wrapper-p nwrapper)
 
693
                 (error "Wrapper returned from trap invalid.")))
 
694
          nwrapper))))
 
695
 
 
696
#-cmu17
 
697
(defmacro check-wrapper-validity1 (object)
 
698
  (let ((owrapper (gensym)))
 
699
    `(let ((,owrapper (cond ((std-instance-p ,object)
 
700
                             (std-instance-wrapper ,object))
 
701
                            ((fsc-instance-p ,object)
 
702
                             (fsc-instance-wrapper ,object))
 
703
                            #+new-kcl-wrapper
 
704
                            (t (built-in-wrapper-of ,object))
 
705
                            #-new-kcl-wrapper
 
706
                            (t (wrapper-of ,object)))))
 
707
       (if (eq 't (wrapper-state ,owrapper))
 
708
           ,owrapper
 
709
           (check-wrapper-validity ,object)))))
 
710
 
 
711
#+cmu17
 
712
;;; semantically equivalent, but faster.
 
713
;;;
 
714
(defmacro check-wrapper-validity1 (object)
 
715
  (let ((owrapper (gensym)))
 
716
    `(let ((,owrapper (kernel:layout-of object)))
 
717
       (if (kernel:layout-invalid ,owrapper)
 
718
           (check-wrapper-validity ,object)
 
719
           ,owrapper))))
 
720
 
 
721
 
 
722
(defvar *free-caches* nil)
 
723
 
 
724
(defun get-cache (nkeys valuep limit-fn nlines)
 
725
  (declare (type non-negative-fixnum nlines))
 
726
  (let ((cache (or (without-interrupts (pop *free-caches*)) (make-cache))))
 
727
    (declare (type cache cache))
 
728
    (multiple-value-bind (cache-mask actual-size line-size nlines)
 
729
        (compute-cache-parameters nkeys valuep nlines)
 
730
      (declare (type non-negative-fixnum 
 
731
                     cache-mask actual-size line-size nlines))
 
732
      (setf (cache-nkeys cache) nkeys
 
733
            (cache-valuep cache) valuep
 
734
            (cache-nlines cache) nlines
 
735
            (cache-field cache) (first-wrapper-cache-number-index)
 
736
            (cache-limit-fn cache) limit-fn
 
737
            (cache-mask cache) cache-mask
 
738
            (cache-size cache) actual-size
 
739
            (cache-line-size cache) line-size
 
740
            (cache-max-location cache) 
 
741
              (let ((line (1- nlines)))
 
742
                (declare (type non-negative-fixnum line))
 
743
                (if (= nkeys 1)
 
744
                    (the fixnum (* line line-size))
 
745
                    (the fixnum (1+ (the fixnum (* line line-size))))))
 
746
            (cache-vector cache) (get-cache-vector actual-size)
 
747
            (cache-overflow cache) nil)
 
748
      cache)))
 
749
 
 
750
(defun get-cache-from-cache (old-cache new-nlines 
 
751
                             &optional (new-field (first-wrapper-cache-number-index)))
 
752
  (declare (type non-negative-fixnum new-nlines))
 
753
  (let ((nkeys (cache-nkeys old-cache))
 
754
        (valuep (cache-valuep old-cache))
 
755
        (cache (or (without-interrupts (pop *free-caches*)) (make-cache))))
 
756
    (declare (type cache cache))
 
757
    (multiple-value-bind (cache-mask actual-size line-size nlines)
 
758
        (if (= new-nlines (cache-nlines old-cache))
 
759
            (values (cache-mask old-cache) (cache-size old-cache) 
 
760
                    (cache-line-size old-cache) (cache-nlines old-cache))
 
761
            (compute-cache-parameters nkeys valuep new-nlines))
 
762
      (declare (type non-negative-fixnum 
 
763
                     cache-mask actual-size line-size nlines))
 
764
      (setf (cache-owner cache) (cache-owner old-cache)
 
765
            (cache-nkeys cache) nkeys
 
766
            (cache-valuep cache) valuep
 
767
            (cache-nlines cache) nlines
 
768
            (cache-field cache) new-field
 
769
            (cache-limit-fn cache) (cache-limit-fn old-cache)
 
770
            (cache-mask cache) cache-mask
 
771
            (cache-size cache) actual-size
 
772
            (cache-line-size cache) line-size
 
773
            (cache-max-location cache) 
 
774
              (let ((line (1- nlines)))
 
775
                (declare (type non-negative-fixnum line))
 
776
                (if (= nkeys 1)
 
777
                    (the fixnum (* line line-size))
 
778
                    (the fixnum (1+ (the fixnum (* line line-size))))))
 
779
            (cache-vector cache) (get-cache-vector actual-size)
 
780
            (cache-overflow cache) nil)
 
781
      cache)))
 
782
 
 
783
(defun copy-cache (old-cache)
 
784
  (let* ((new-cache (copy-cache-internal old-cache))
 
785
         (size (cache-size old-cache))
 
786
         (old-vector (cache-vector old-cache))
 
787
         (new-vector (get-cache-vector size)))
 
788
    (declare (simple-vector old-vector new-vector))
 
789
    (dotimes (i size)
 
790
      (setf (svref new-vector i) (svref old-vector i)))
 
791
    (setf (cache-vector new-cache) new-vector)
 
792
    new-cache))
 
793
 
 
794
(defun free-cache (cache)
 
795
  (free-cache-vector (cache-vector cache))
 
796
  (setf (cache-vector cache) #())
 
797
  (setf (cache-owner cache) nil)
 
798
  (push cache *free-caches*)
 
799
  nil)
 
800
 
 
801
(defun compute-line-size (x)
 
802
  (power-of-two-ceiling x))
 
803
 
 
804
(defun compute-cache-parameters (nkeys valuep nlines-or-cache-vector)
 
805
  ;;(declare (values cache-mask actual-size line-size nlines))
 
806
  (declare (type non-negative-fixnum nkeys))
 
807
  (if (= nkeys 1)
 
808
      (let* ((line-size (if valuep 2 1))
 
809
             (cache-size (if (typep nlines-or-cache-vector 'fixnum)
 
810
                             (the non-negative-fixnum 
 
811
                                  (* line-size
 
812
                                     (the non-negative-fixnum 
 
813
                                          (power-of-two-ceiling 
 
814
                                            nlines-or-cache-vector))))
 
815
                             (cache-vector-size nlines-or-cache-vector))))
 
816
        (declare (type non-negative-fixnum line-size cache-size))
 
817
        (values (logxor (the non-negative-fixnum (1- cache-size))
 
818
                        (the non-negative-fixnum (1- line-size)))
 
819
                cache-size
 
820
                line-size
 
821
                (the non-negative-fixnum (floor cache-size line-size))))
 
822
      (let* ((line-size (power-of-two-ceiling (if valuep (1+ nkeys) nkeys)))
 
823
             (cache-size (if (typep nlines-or-cache-vector 'fixnum)
 
824
                             (the non-negative-fixnum
 
825
                                  (* line-size
 
826
                                     (the non-negative-fixnum
 
827
                                          (power-of-two-ceiling 
 
828
                                            nlines-or-cache-vector))))
 
829
                             (1- (cache-vector-size nlines-or-cache-vector)))))
 
830
        (declare (type non-negative-fixnum line-size cache-size))
 
831
        (values (logxor (the non-negative-fixnum (1- cache-size))
 
832
                        (the non-negative-fixnum (1- line-size)))
 
833
                (the non-negative-fixnum (1+ cache-size))
 
834
                line-size
 
835
                (the non-negative-fixnum (floor cache-size line-size))))))
 
836
 
 
837
 
 
838
 
 
839
;;;
 
840
;;; The various implementations of computing a primary cache location from
 
841
;;; wrappers.  Because some implementations of this must run fast there are
 
842
;;; several implementations of the same algorithm.
 
843
;;;
 
844
;;; The algorithm is:
 
845
;;;
 
846
;;;  SUM       over the wrapper cache numbers,
 
847
;;;  ENSURING  that the result is a fixnum
 
848
;;;  MASK      the result against the mask argument.
 
849
;;;
 
850
;;;
 
851
 
 
852
;;;
 
853
;;; COMPUTE-PRIMARY-CACHE-LOCATION
 
854
;;; 
 
855
;;; The basic functional version.  This is used by the cache miss code to
 
856
;;; compute the primary location of an entry.  
 
857
;;;
 
858
(defun compute-primary-cache-location (field mask wrappers)
 
859
  (declare (type field-type field) (type non-negative-fixnum mask))
 
860
  (if (not (listp wrappers))
 
861
      (logand mask (the non-negative-fixnum 
 
862
                        (wrapper-cache-number-vector-ref wrappers field)))
 
863
      (let ((location 0) (i 0))
 
864
        (declare (type non-negative-fixnum location i))
 
865
        (dolist (wrapper wrappers)
 
866
          ;;
 
867
          ;; First add the cache number of this wrapper to location.
 
868
          ;; 
 
869
          (let ((wrapper-cache-number 
 
870
                 (wrapper-cache-number-vector-ref wrapper field)))
 
871
            (declare (type non-negative-fixnum wrapper-cache-number))
 
872
            (if (zerop wrapper-cache-number)
 
873
                (return-from compute-primary-cache-location 0)
 
874
                (setq location (the non-negative-fixnum 
 
875
                                    (+ location wrapper-cache-number)))))
 
876
          ;;
 
877
          ;; Then, if we are working with lots of wrappers, deal with
 
878
          ;; the wrapper-cache-number-mask stuff.
 
879
          ;; 
 
880
          (when (and (not (zerop i))
 
881
                     (zerop (mod i wrapper-cache-number-adds-ok)))
 
882
            (setq location
 
883
                  (logand location wrapper-cache-number-mask)))
 
884
          (incf i))
 
885
        (the non-negative-fixnum (1+ (logand mask location))))))
 
886
 
 
887
;;;
 
888
;;; COMPUTE-PRIMARY-CACHE-LOCATION-FROM-LOCATION
 
889
;;;
 
890
;;; This version is called on a cache line.  It fetches the wrappers from
 
891
;;; the cache line and determines the primary location.  Various parts of
 
892
;;; the cache filling code call this to determine whether it is appropriate
 
893
;;; to displace a given cache entry.
 
894
;;; 
 
895
;;; If this comes across a wrapper whose cache-no is 0, it returns the symbol
 
896
;;; invalid to suggest to its caller that it would be provident to blow away
 
897
;;; the cache line in question.
 
898
;;;
 
899
(defun compute-primary-cache-location-from-location (to-cache from-location 
 
900
                                                     &optional (from-cache to-cache))
 
901
  (declare (type cache to-cache from-cache)
 
902
           (type non-negative-fixnum from-location))
 
903
  (let ((result 0)
 
904
        (cache-vector (cache-vector from-cache))
 
905
        (field (cache-field to-cache))
 
906
        (mask (cache-mask to-cache))
 
907
        (nkeys (cache-nkeys to-cache)))
 
908
    (declare (type field-type field)
 
909
             (type non-negative-fixnum result mask nkeys)
 
910
             (simple-vector cache-vector))
 
911
    (dotimes (i nkeys)
 
912
      (let* ((wrapper (cache-vector-ref cache-vector (+ i from-location)))
 
913
             (wcn (wrapper-cache-number-vector-ref wrapper field)))
 
914
        (declare (type non-negative-fixnum wcn))
 
915
        (setq result (+ result wcn)))
 
916
      (when (and (not (zerop i))
 
917
                 (zerop (mod i wrapper-cache-number-adds-ok)))
 
918
        (setq result (logand result wrapper-cache-number-mask))))    
 
919
    (if (= nkeys 1)
 
920
        (logand mask result)
 
921
        (the non-negative-fixnum (1+ (logand mask result))))))
 
922
 
 
923
 
 
924
;;;
 
925
;;;  NIL              means nothing so far, no actual arg info has NILs
 
926
;;;                   in the metatype
 
927
;;;  CLASS            seen all sorts of metaclasses
 
928
;;;                   (specifically, more than one of the next 4 values)
 
929
;;;  T                means everything so far is the class T
 
930
;;;  STANDARD-CLASS   seen only standard classes
 
931
;;;  BUILT-IN-CLASS   seen only built in classes
 
932
;;;  STRUCTURE-CLASS  seen only structure classes
 
933
;;;  
 
934
(defun raise-metatype (metatype new-specializer)
 
935
  (let ((slot      (find-class 'slot-class))
 
936
        (standard  (find-class 'standard-class))
 
937
        (fsc       (find-class 'funcallable-standard-class))
 
938
        (structure (find-class 'structure-class))
 
939
        (built-in  (find-class 'built-in-class)))
 
940
    (flet ((specializer->metatype (x)
 
941
             (let ((meta-specializer 
 
942
                     (if (eq *boot-state* 'complete)
 
943
                         (class-of (specializer-class x))
 
944
                         (class-of x))))
 
945
               (cond ((eq x *the-class-t*) t)
 
946
                     ((*subtypep meta-specializer standard)  'standard-instance)
 
947
                     ((*subtypep meta-specializer fsc)       'standard-instance)
 
948
                     ((*subtypep meta-specializer structure) 'structure-instance)
 
949
                     ((*subtypep meta-specializer built-in)  'built-in-instance)
 
950
                     ((*subtypep meta-specializer slot)      'slot-instance)
 
951
                     (t (error "PCL can not handle the specializer ~S (meta-specializer ~S)."
 
952
                               new-specializer meta-specializer))))))
 
953
      ;;
 
954
      ;; We implement the following table.  The notation is
 
955
      ;; that X and Y are distinct meta specializer names.
 
956
      ;; 
 
957
      ;;   NIL    <anything>    ===>  <anything>
 
958
      ;;    X      X            ===>      X
 
959
      ;;    X      Y            ===>    CLASS
 
960
      ;;    
 
961
      (let ((new-metatype (specializer->metatype new-specializer)))
 
962
        (cond ((eq new-metatype 'slot-instance) 'class)
 
963
              ((null metatype) new-metatype)
 
964
              ((eq metatype new-metatype) new-metatype)
 
965
              (t 'class))))))
 
966
 
 
967
(defmacro with-dfun-wrappers ((args metatypes)
 
968
                              (dfun-wrappers invalid-wrapper-p 
 
969
                                             &optional wrappers classes types)
 
970
                              invalid-arguments-form
 
971
                              &body body)
 
972
  `(let* ((args-tail ,args) (,invalid-wrapper-p nil) (invalid-arguments-p nil)
 
973
          (,dfun-wrappers nil) (dfun-wrappers-tail nil)
 
974
          ,@(when wrappers
 
975
              `((wrappers-rev nil) (types-rev nil) (classes-rev nil))))
 
976
     (dolist (mt ,metatypes)
 
977
       (unless args-tail
 
978
         (setq invalid-arguments-p t)
 
979
         (return nil))
 
980
       (let* ((arg (pop args-tail))
 
981
              (wrapper nil)
 
982
              ,@(when wrappers
 
983
                  `((class *the-class-t*)
 
984
                    (type 't))))
 
985
         (unless (eq mt 't)
 
986
           (setq wrapper (wrapper-of arg))
 
987
           (when (invalid-wrapper-p wrapper)
 
988
             (setq ,invalid-wrapper-p t)
 
989
             (setq wrapper (check-wrapper-validity arg)))
 
990
           (cond ((null ,dfun-wrappers)
 
991
                  (setq ,dfun-wrappers wrapper))
 
992
                 ((not (consp ,dfun-wrappers))
 
993
                  (setq dfun-wrappers-tail (list wrapper))
 
994
                  (setq ,dfun-wrappers (cons ,dfun-wrappers dfun-wrappers-tail)))
 
995
                 (t
 
996
                  (let ((new-dfun-wrappers-tail (list wrapper)))
 
997
                    (setf (cdr dfun-wrappers-tail) new-dfun-wrappers-tail)
 
998
                    (setf dfun-wrappers-tail new-dfun-wrappers-tail))))
 
999
           ,@(when wrappers
 
1000
               `((setq class (wrapper-class* wrapper))
 
1001
                 (setq type `(class-eq ,class)))))
 
1002
         ,@(when wrappers
 
1003
             `((push wrapper wrappers-rev)
 
1004
               (push class classes-rev)
 
1005
               (push type types-rev)))))
 
1006
     (if invalid-arguments-p
 
1007
         ,invalid-arguments-form
 
1008
         (let* (,@(when wrappers
 
1009
                    `((,wrappers (nreverse wrappers-rev))
 
1010
                      (,classes (nreverse classes-rev))
 
1011
                      (,types (mapcar #'(lambda (class)
 
1012
                                          `(class-eq ,class))
 
1013
                                      ,classes)))))
 
1014
           ,@body))))
 
1015
 
 
1016
 
 
1017
;;;
 
1018
;;; Some support stuff for getting a hold of symbols that we need when
 
1019
;;; building the discriminator codes.  Its ok for these to be interned
 
1020
;;; symbols because we don't capture any user code in the scope in which
 
1021
;;; these symbols are bound.
 
1022
;;; 
 
1023
 
 
1024
(defvar *dfun-arg-symbols* '(.ARG0. .ARG1. .ARG2. .ARG3.))
 
1025
 
 
1026
(defun dfun-arg-symbol (arg-number)
 
1027
  (or (nth arg-number (the list *dfun-arg-symbols*))
 
1028
      (intern (format nil ".ARG~A." arg-number) *the-pcl-package*)))
 
1029
 
 
1030
(defvar *slot-vector-symbols* '(.SLOTS0. .SLOTS1. .SLOTS2. .SLOTS3.))
 
1031
 
 
1032
(defun slot-vector-symbol (arg-number)
 
1033
  (or (nth arg-number (the list *slot-vector-symbols*))
 
1034
      (intern (format nil ".SLOTS~A." arg-number) *the-pcl-package*)))
 
1035
 
 
1036
(defun make-dfun-lambda-list (metatypes applyp)
 
1037
  (gathering1 (collecting)
 
1038
    (iterate ((i (interval :from 0))
 
1039
              (s (list-elements metatypes)))
 
1040
      (progn s)
 
1041
      (gather1 (dfun-arg-symbol i)))
 
1042
    (when applyp
 
1043
      (gather1 '&rest)
 
1044
      (gather1 '.dfun-rest-arg.))))
 
1045
 
 
1046
(defun make-dlap-lambda-list (metatypes applyp)
 
1047
  (gathering1 (collecting)
 
1048
    (iterate ((i (interval :from 0))
 
1049
              (s (list-elements metatypes)))
 
1050
      (progn s)
 
1051
      (gather1 (dfun-arg-symbol i)))
 
1052
    (when applyp
 
1053
      (gather1 '&rest))))
 
1054
 
 
1055
(defun make-emf-call (metatypes applyp fn-variable &optional emf-type)
 
1056
  (let ((required
 
1057
         (gathering1 (collecting)
 
1058
            (iterate ((i (interval :from 0))
 
1059
                      (s (list-elements metatypes)))
 
1060
              (progn s)
 
1061
              (gather1 (dfun-arg-symbol i))))))
 
1062
    `(,(if (eq emf-type 'fast-method-call)
 
1063
           'invoke-effective-method-function-fast
 
1064
           'invoke-effective-method-function)
 
1065
      ,fn-variable ,applyp ,@required ,@(when applyp `(.dfun-rest-arg.)))))
 
1066
 
 
1067
(defun make-dfun-call (metatypes applyp fn-variable)
 
1068
  (let ((required
 
1069
          (gathering1 (collecting)
 
1070
            (iterate ((i (interval :from 0))
 
1071
                      (s (list-elements metatypes)))
 
1072
              (progn s)
 
1073
              (gather1 (dfun-arg-symbol i))))))
 
1074
    (if applyp
 
1075
        `(function-apply   ,fn-variable ,@required .dfun-rest-arg.)
 
1076
        `(function-funcall ,fn-variable ,@required))))
 
1077
 
 
1078
(defun make-dfun-arg-list (metatypes applyp)
 
1079
  (let ((required
 
1080
          (gathering1 (collecting)
 
1081
            (iterate ((i (interval :from 0))
 
1082
                      (s (list-elements metatypes)))
 
1083
              (progn s)
 
1084
              (gather1 (dfun-arg-symbol i))))))
 
1085
    (if applyp
 
1086
        `(list* ,@required .dfun-rest-arg.)
 
1087
        `(list ,@required))))
 
1088
 
 
1089
(defun make-fast-method-call-lambda-list (metatypes applyp)
 
1090
  (gathering1 (collecting)
 
1091
    (gather1 '.pv-cell.)
 
1092
    (gather1 '.next-method-call.)
 
1093
    (iterate ((i (interval :from 0))
 
1094
              (s (list-elements metatypes)))
 
1095
      (progn s)
 
1096
      (gather1 (dfun-arg-symbol i)))
 
1097
    (when applyp
 
1098
      (gather1 '.dfun-rest-arg.))))
 
1099
 
 
1100
(defmacro fin-lambda-fn (arglist &body body)
 
1101
  `#'(#+cmu kernel:instance-lambda #-cmu lambda 
 
1102
       ,arglist
 
1103
       ,@body))
 
1104
 
 
1105
(defun make-dispatch-lambda (function-p metatypes applyp body)
 
1106
  `(#+cmu ,(if function-p 'kernel:instance-lambda 'lambda) #-cmu lambda
 
1107
     ,(if function-p
 
1108
          (make-dfun-lambda-list metatypes applyp)
 
1109
          (make-fast-method-call-lambda-list metatypes applyp))
 
1110
     ,@(unless function-p
 
1111
         `((declare (ignore .pv-cell. .next-method-call.))))
 
1112
     #+cmu (declare (ignorable ,@(cddr (make-fast-method-call-lambda-list 
 
1113
                                        metatypes applyp))))
 
1114
     #+copy-&rest-arg
 
1115
     ,@(when (and applyp function-p)
 
1116
         `((setq .dfun-rest-arg. (copy-list .dfun-rest-arg.))))
 
1117
     ,@body))
 
1118
 
 
1119
 
 
1120
;;;
 
1121
;;; Its too bad Common Lisp compilers freak out when you have a defun with
 
1122
;;; a lot of LABELS in it.  If I could do that I could make this code much
 
1123
;;; easier to read and work with.
 
1124
;;;
 
1125
;;; Ahh Scheme...
 
1126
;;; 
 
1127
;;; In the absence of that, the following little macro makes the code that
 
1128
;;; follows a little bit more reasonable.  I would like to add that having
 
1129
;;; to practically write my own compiler in order to get just this simple
 
1130
;;; thing is something of a drag.
 
1131
;;;
 
1132
(eval-when (compile load eval)
 
1133
 
 
1134
(defvar *cache* nil)
 
1135
 
 
1136
(defconstant *local-cache-functions*
 
1137
  '((cache () .cache.)
 
1138
    (nkeys () (cache-nkeys .cache.))
 
1139
    (line-size () (cache-line-size .cache.))
 
1140
    (vector () (cache-vector .cache.))
 
1141
    (valuep () (cache-valuep .cache.))
 
1142
    (nlines () (cache-nlines .cache.))
 
1143
    (max-location () (cache-max-location .cache.))
 
1144
    (limit-fn () (cache-limit-fn .cache.))
 
1145
    (size () (cache-size .cache.))
 
1146
    (mask () (cache-mask .cache.))
 
1147
    (field () (cache-field .cache.))
 
1148
    (overflow () (cache-overflow .cache.))
 
1149
 
 
1150
    ;;
 
1151
    ;; Return T IFF this cache location is reserved.  The only time
 
1152
    ;; this is true is for line number 0 of an nkeys=1 cache.  
 
1153
    ;;
 
1154
    (line-reserved-p (line)
 
1155
      (declare (type non-negative-fixnum line))
 
1156
      (and (= (nkeys) 1)
 
1157
           (= line 0)))
 
1158
    ;;
 
1159
    (location-reserved-p (location)
 
1160
      (declare (type non-negative-fixnum location))
 
1161
      (and (= (nkeys) 1)
 
1162
           (= location 0)))
 
1163
    ;;
 
1164
    ;; Given a line number, return the cache location.  This is the
 
1165
    ;; value that is the second argument to cache-vector-ref.  Basically,
 
1166
    ;; this deals with the offset of nkeys>1 caches and multiplies
 
1167
    ;; by line size.  
 
1168
    ;;    
 
1169
    (line-location (line)
 
1170
      (declare (type non-negative-fixnum line))
 
1171
      (when (line-reserved-p line)
 
1172
        (error "line is reserved"))
 
1173
      (if (= (nkeys) 1)
 
1174
          (the non-negative-fixnum (* line (line-size)))
 
1175
          (the non-negative-fixnum 
 
1176
               (1+ (the non-negative-fixnum (* line (line-size)))))))
 
1177
    ;;
 
1178
    ;; Given a cache location, return the line.  This is the inverse
 
1179
    ;; of LINE-LOCATION.
 
1180
    ;;    
 
1181
    (location-line (location)
 
1182
      (declare (type non-negative-fixnum location))
 
1183
      (if (= (nkeys) 1)
 
1184
          (floor location (line-size))
 
1185
          (floor (the non-negative-fixnum (1- location)) (line-size))))
 
1186
    ;;
 
1187
    ;; Given a line number, return the wrappers stored at that line.
 
1188
    ;; As usual, if nkeys=1, this returns a single value.  Only when
 
1189
    ;; nkeys>1 does it return a list.  An error is signalled if the
 
1190
    ;; line is reserved.
 
1191
    ;;
 
1192
    (line-wrappers (line)
 
1193
      (declare (type non-negative-fixnum line))
 
1194
      (when (line-reserved-p line) (error "Line is reserved."))
 
1195
      (location-wrappers (line-location line)))
 
1196
    ;;
 
1197
    (location-wrappers (location) ; avoid multiplies caused by line-location
 
1198
      (declare (type non-negative-fixnum location))
 
1199
      (if (= (nkeys) 1)
 
1200
          (cache-vector-ref (vector) location)
 
1201
          (let ((list (make-list (nkeys)))
 
1202
                (vector (vector)))
 
1203
            (declare (simple-vector vector))
 
1204
            (dotimes (i (nkeys) list)
 
1205
              (setf (nth i list) (cache-vector-ref vector (+ location i)))))))
 
1206
    ;;
 
1207
    ;; Given a line number, return true IFF the line's
 
1208
    ;; wrappers are the same as wrappers.
 
1209
    ;;
 
1210
    (line-matches-wrappers-p (line wrappers)
 
1211
      (declare (type non-negative-fixnum line))
 
1212
      (and (not (line-reserved-p line))
 
1213
           (location-matches-wrappers-p (line-location line) wrappers)))
 
1214
    ;;
 
1215
    (location-matches-wrappers-p (loc wrappers) ; must not be reserved
 
1216
      (declare (type non-negative-fixnum loc))
 
1217
      (let ((cache-vector (vector)))
 
1218
        (declare (simple-vector cache-vector))
 
1219
        (if (= (nkeys) 1)
 
1220
            (eq wrappers (cache-vector-ref cache-vector loc))
 
1221
            (dotimes (i (nkeys) t)
 
1222
              (unless (eq (pop wrappers)
 
1223
                          (cache-vector-ref cache-vector (+ loc i)))
 
1224
                (return nil))))))
 
1225
    ;;
 
1226
    ;; Given a line number, return the value stored at that line.
 
1227
    ;; If valuep is NIL, this returns NIL.  As with line-wrappers,
 
1228
    ;; an error is signalled if the line is reserved.
 
1229
    ;; 
 
1230
    (line-value (line)
 
1231
      (declare (type non-negative-fixnum line))
 
1232
      (when (line-reserved-p line) (error "Line is reserved."))
 
1233
      (location-value (line-location line)))
 
1234
    ;;
 
1235
    (location-value (loc)
 
1236
      (declare (type non-negative-fixnum loc))
 
1237
      (and (valuep)
 
1238
           (cache-vector-ref (vector) (+ loc (nkeys)))))
 
1239
    ;;
 
1240
    ;; Given a line number, return true IFF that line has data in
 
1241
    ;; it.  The state of the wrappers stored in the line is not
 
1242
    ;; checked.  An error is signalled if line is reserved.
 
1243
    (line-full-p (line)
 
1244
      (when (line-reserved-p line) (error "Line is reserved."))
 
1245
      (not (null (cache-vector-ref (vector) (line-location line)))))
 
1246
    ;;
 
1247
    ;; Given a line number, return true IFF the line is full and
 
1248
    ;; there are no invalid wrappers in the line, and the line's
 
1249
    ;; wrappers are different from wrappers.
 
1250
    ;; An error is signalled if the line is reserved.
 
1251
    ;;
 
1252
    (line-valid-p (line wrappers)
 
1253
      (declare (type non-negative-fixnum line))
 
1254
      (when (line-reserved-p line) (error "Line is reserved."))
 
1255
      (location-valid-p (line-location line) wrappers))
 
1256
    ;;
 
1257
    (location-valid-p (loc wrappers)
 
1258
      (declare (type non-negative-fixnum loc))
 
1259
      (let ((cache-vector (vector))
 
1260
            (wrappers-mismatch-p (null wrappers)))
 
1261
        (declare (simple-vector cache-vector))
 
1262
        (dotimes (i (nkeys) wrappers-mismatch-p)
 
1263
          (let ((wrapper (cache-vector-ref cache-vector (+ loc i))))
 
1264
            (when (or (null wrapper)
 
1265
                      (invalid-wrapper-p wrapper))
 
1266
              (return nil))
 
1267
            (unless (and wrappers
 
1268
                         (eq wrapper
 
1269
                             (if (consp wrappers) (pop wrappers) wrappers)))
 
1270
              (setq wrappers-mismatch-p t))))))
 
1271
    ;;
 
1272
    ;; How many unreserved lines separate line-1 and line-2.
 
1273
    ;;
 
1274
    (line-separation (line-1 line-2)
 
1275
     (declare (type non-negative-fixnum line-1 line-2))
 
1276
     (let ((diff (the fixnum (- line-2 line-1))))
 
1277
       (declare (fixnum diff))
 
1278
       (when (minusp diff)
 
1279
         (setq diff (+ diff (nlines)))
 
1280
         (when (line-reserved-p 0)
 
1281
           (setq diff (1- diff))))
 
1282
       diff))
 
1283
    ;;
 
1284
    ;; Given a cache line, get the next cache line.  This will not
 
1285
    ;; return a reserved line.
 
1286
    ;; 
 
1287
    (next-line (line)
 
1288
     (declare (type non-negative-fixnum line))
 
1289
     (if (= line (the fixnum (1- (nlines))))
 
1290
         (if (line-reserved-p 0) 1 0)
 
1291
         (the non-negative-fixnum (1+ line))))
 
1292
    ;;
 
1293
    (next-location (loc)
 
1294
      (declare (type non-negative-fixnum loc))
 
1295
      (if (= loc (max-location))
 
1296
          (if (= (nkeys) 1)
 
1297
              (line-size)
 
1298
              1)
 
1299
          (the non-negative-fixnum (+ loc (line-size)))))
 
1300
    ;;
 
1301
    ;; Given a line which has a valid entry in it, this will return
 
1302
    ;; the primary cache line of the wrappers in that line.  We just
 
1303
    ;; call COMPUTE-PRIMARY-CACHE-LOCATION-FROM-LOCATION, this is an
 
1304
    ;; easier packaging up of the call to it.
 
1305
    ;; 
 
1306
    (line-primary (line)
 
1307
      (declare (type non-negative-fixnum line))
 
1308
      (location-line (line-primary-location line)))
 
1309
    ;;
 
1310
    (line-primary-location (line)
 
1311
     (declare (type non-negative-fixnum line))
 
1312
     (compute-primary-cache-location-from-location
 
1313
       (cache) (line-location line)))
 
1314
    ))
 
1315
 
 
1316
(defmacro with-local-cache-functions ((cache) &body body)
 
1317
  `(let ((.cache. ,cache))
 
1318
     (declare (type cache .cache.))
 
1319
     (macrolet ,(mapcar #'(lambda (fn)
 
1320
                            `(,(car fn) ,(cadr fn)
 
1321
                                `(let (,,@(mapcar #'(lambda (var)
 
1322
                                                      ``(,',var ,,var))
 
1323
                                                  (cadr fn)))
 
1324
                                    ,@',(cddr fn))))
 
1325
                        *local-cache-functions*)
 
1326
       ,@body)))
 
1327
 
 
1328
)
 
1329
 
 
1330
;;;
 
1331
;;; Here is where we actually fill, recache and expand caches.
 
1332
;;;
 
1333
;;; The functions FILL-CACHE and PROBE-CACHE are the ONLY external
 
1334
;;; entrypoints into this code.
 
1335
;;;
 
1336
;;; FILL-CACHE returns 1 value: a new cache
 
1337
;;;
 
1338
;;;   a wrapper field number
 
1339
;;;   a cache
 
1340
;;;   a mask
 
1341
;;;   an absolute cache size (the size of the actual vector)
 
1342
;;; It tries to re-adjust the cache every time it makes a new fill.  The
 
1343
;;; intuition here is that we want uniformity in the number of probes needed to
 
1344
;;; find an entry.  Furthermore, adjusting has the nice property of throwing out
 
1345
;;; any entries that are invalid.
 
1346
;;;
 
1347
(defvar *cache-expand-threshold* 1.25)
 
1348
 
 
1349
(defun fill-cache (cache wrappers value &optional free-cache-p)
 
1350
  ;;(declare (values cache))
 
1351
  (unless wrappers ; fill-cache won't return if wrappers is nil, might as well check.
 
1352
    (error "fill-cache: wrappers arg is NIL!"))
 
1353
  (or (fill-cache-p nil cache wrappers value)
 
1354
      (and (< (ceiling (* (cache-count cache) 1.25))
 
1355
              (if (= (cache-nkeys cache) 1)
 
1356
                  (1- (cache-nlines cache))
 
1357
                  (cache-nlines cache)))
 
1358
           (adjust-cache cache wrappers value free-cache-p))
 
1359
      (expand-cache cache wrappers value free-cache-p)))
 
1360
 
 
1361
(defvar *check-cache-p* nil)
 
1362
 
 
1363
(defmacro maybe-check-cache (cache)
 
1364
  `(progn
 
1365
     (when *check-cache-p*
 
1366
       (check-cache ,cache))
 
1367
     ,cache))
 
1368
 
 
1369
(defun check-cache (cache)
 
1370
  (with-local-cache-functions (cache)
 
1371
    (let ((location (if (= (nkeys) 1) 0 1))
 
1372
          (limit (funcall (limit-fn) (nlines))))
 
1373
      (dotimes (i (nlines) cache)
 
1374
        (when (and (not (location-reserved-p location))
 
1375
                   (line-full-p i))
 
1376
          (let* ((home-loc (compute-primary-cache-location-from-location 
 
1377
                            cache location))
 
1378
                 (home (location-line (if (location-reserved-p home-loc)
 
1379
                                          (next-location home-loc)
 
1380
                                          home-loc)))
 
1381
                 (sep (when home (line-separation home i))))
 
1382
            (when (and sep (> sep limit))
 
1383
              (error "bad cache ~S ~@
 
1384
                      value at location ~D is ~D lines from its home. limit is ~D."
 
1385
                     cache location sep limit))))
 
1386
        (setq location (next-location location))))))
 
1387
 
 
1388
(defun probe-cache (cache wrappers &optional default limit-fn)
 
1389
  ;;(declare (values value))
 
1390
  (unless wrappers (error "probe-cache: wrappers arg is NIL!"))
 
1391
  (with-local-cache-functions (cache)
 
1392
    (let* ((location (compute-primary-cache-location (field) (mask) wrappers))
 
1393
           (limit (funcall (or limit-fn (limit-fn)) (nlines))))
 
1394
      (declare (type non-negative-fixnum location limit))
 
1395
      (when (location-reserved-p location)
 
1396
        (setq location (next-location location)))
 
1397
      (dotimes (i (1+ limit))
 
1398
        (when (location-matches-wrappers-p location wrappers)
 
1399
          (return-from probe-cache (or (not (valuep))
 
1400
                                       (location-value location))))
 
1401
        (setq location (next-location location)))
 
1402
      (dolist (entry (overflow))
 
1403
        (when (equal (car entry) wrappers)
 
1404
          (return-from probe-cache (or (not (valuep))
 
1405
                                       (cdr entry)))))
 
1406
      default)))
 
1407
 
 
1408
(defun map-cache (function cache &optional set-p)
 
1409
  (with-local-cache-functions (cache)
 
1410
    (let ((set-p (and set-p (valuep))))
 
1411
      (dotimes (i (nlines) cache)
 
1412
        (unless (or (line-reserved-p i) (not (line-valid-p i nil)))
 
1413
          (let ((value (funcall function (line-wrappers i) (line-value i))))
 
1414
            (when set-p
 
1415
              (setf (cache-vector-ref (vector) (+ (line-location i) (nkeys)))
 
1416
                    value)))))
 
1417
      (dolist (entry (overflow))
 
1418
        (let ((value (funcall function (car entry) (cdr entry))))
 
1419
          (when set-p
 
1420
            (setf (cdr entry) value))))))
 
1421
  cache)
 
1422
 
 
1423
(defun cache-count (cache)
 
1424
  (with-local-cache-functions (cache)
 
1425
    (let ((count 0))
 
1426
      (declare (type non-negative-fixnum count))
 
1427
      (dotimes (i (nlines) count)
 
1428
        (unless (line-reserved-p i)
 
1429
          (when (line-full-p i)
 
1430
            (incf count)))))))
 
1431
 
 
1432
(defun entry-in-cache-p (cache wrappers value)
 
1433
  (declare (ignore value))
 
1434
  (with-local-cache-functions (cache)
 
1435
    (dotimes (i (nlines))
 
1436
      (unless (line-reserved-p i)
 
1437
        (when (equal (line-wrappers i) wrappers)
 
1438
          (return t))))))
 
1439
 
 
1440
;;;
 
1441
;;; returns T or NIL
 
1442
;;;
 
1443
(defun fill-cache-p (forcep cache wrappers value)
 
1444
  (with-local-cache-functions (cache)
 
1445
    (let* ((location (compute-primary-cache-location (field) (mask) wrappers))
 
1446
           (primary (location-line location)))
 
1447
      (declare (type non-negative-fixnum location primary))
 
1448
      (multiple-value-bind (free emptyp)
 
1449
          (find-free-cache-line primary cache wrappers)
 
1450
        (when (or forcep emptyp)
 
1451
          (when (not emptyp)
 
1452
            (push (cons (line-wrappers free) (line-value free)) 
 
1453
                  (cache-overflow cache)))
 
1454
          ;;(fill-line free wrappers value)
 
1455
          (let ((line free))
 
1456
            (declare (type non-negative-fixnum line))
 
1457
            (when (line-reserved-p line)
 
1458
              (error "Attempt to fill a reserved line."))
 
1459
            (let ((loc (line-location line))
 
1460
                  (cache-vector (vector)))
 
1461
              (declare (type non-negative-fixnum loc)
 
1462
                       (simple-vector cache-vector))
 
1463
              (cond ((= (nkeys) 1)
 
1464
                     (setf (cache-vector-ref cache-vector loc) wrappers)
 
1465
                     (when (valuep)
 
1466
                       (setf (cache-vector-ref cache-vector (1+ loc)) value)))
 
1467
                    (t
 
1468
                     (let ((i 0))
 
1469
                       (declare (type non-negative-fixnum i))
 
1470
                       (dolist (w wrappers)
 
1471
                         (setf (cache-vector-ref cache-vector (+ loc i)) w)
 
1472
                         (setq i (the non-negative-fixnum (1+ i)))))
 
1473
                     (when (valuep)
 
1474
                       (setf (cache-vector-ref cache-vector (+ loc (nkeys)))
 
1475
                             value))))
 
1476
              (maybe-check-cache cache))))))))
 
1477
 
 
1478
(defun fill-cache-from-cache-p (forcep cache from-cache from-line)
 
1479
  (declare (type non-negative-fixnum from-line))
 
1480
  (with-local-cache-functions (cache)
 
1481
    (let ((primary (location-line (compute-primary-cache-location-from-location
 
1482
                                   cache (line-location from-line) from-cache))))
 
1483
      (declare (type non-negative-fixnum primary))
 
1484
      (multiple-value-bind (free emptyp)
 
1485
          (find-free-cache-line primary cache)
 
1486
        (when (or forcep emptyp)
 
1487
          (when (not emptyp)
 
1488
            (push (cons (line-wrappers free) (line-value free))
 
1489
                  (cache-overflow cache)))
 
1490
          ;;(transfer-line from-cache-vector from-line cache-vector free)
 
1491
          (let ((from-cache-vector (cache-vector from-cache))
 
1492
                (to-cache-vector (vector))
 
1493
                (to-line free))
 
1494
            (declare (type non-negative-fixnum to-line))
 
1495
            (if (line-reserved-p to-line)
 
1496
                (error "transfering something into a reserved cache line.")
 
1497
                (let ((from-loc (line-location from-line))
 
1498
                      (to-loc (line-location to-line)))
 
1499
                  (declare (type non-negative-fixnum from-loc to-loc))
 
1500
                  (modify-cache to-cache-vector
 
1501
                                (dotimes (i (line-size))
 
1502
                                  (setf (cache-vector-ref to-cache-vector
 
1503
                                                          (+ to-loc i))
 
1504
                                        (cache-vector-ref from-cache-vector
 
1505
                                                          (+ from-loc i)))))))
 
1506
            (maybe-check-cache cache)))))))
 
1507
 
 
1508
;;;
 
1509
;;; Returns NIL or (values <field> <cache-vector>)
 
1510
;;; 
 
1511
;;; This is only called when it isn't possible to put the entry in the cache
 
1512
;;; the easy way.  That is, this function assumes that FILL-CACHE-P has been
 
1513
;;; called as returned NIL.
 
1514
;;;
 
1515
;;; If this returns NIL, it means that it wasn't possible to find a wrapper
 
1516
;;; field for which all of the entries could be put in the cache (within the
 
1517
;;; limit).  
 
1518
;;;
 
1519
(defun adjust-cache (cache wrappers value free-old-cache-p)
 
1520
  (with-local-cache-functions (cache)
 
1521
    (let ((ncache (get-cache-from-cache cache (nlines) (field))))
 
1522
      (do ((nfield (cache-field ncache)
 
1523
                   (next-wrapper-cache-number-index nfield)))
 
1524
          ((null nfield) (free-cache ncache) nil)
 
1525
        (let ((nfield nfield))
 
1526
          (declare (type field-type nfield))
 
1527
          (setf (cache-field ncache) nfield)
 
1528
          (labels ((try-one-fill-from-line (line)
 
1529
                     (fill-cache-from-cache-p nil ncache cache line))
 
1530
                   (try-one-fill (wrappers value)
 
1531
                     (fill-cache-p nil ncache wrappers value)))
 
1532
            (if (and (dotimes (i (nlines) t)
 
1533
                       (when (and (null (line-reserved-p i))
 
1534
                                  (line-valid-p i wrappers))
 
1535
                         (unless (try-one-fill-from-line i) (return nil))))
 
1536
                     (dolist (wrappers+value (cache-overflow cache) t)
 
1537
                       (unless (try-one-fill (car wrappers+value)
 
1538
                                             (cdr wrappers+value))
 
1539
                         (return nil)))
 
1540
                     (try-one-fill wrappers value))
 
1541
                (progn (when free-old-cache-p (free-cache cache))
 
1542
                       (return (maybe-check-cache ncache)))
 
1543
                (flush-cache-vector-internal (cache-vector ncache)))))))))
 
1544
 
 
1545
                       
 
1546
;;;
 
1547
;;; returns: (values <cache>)
 
1548
;;;
 
1549
(defun expand-cache (cache wrappers value free-old-cache-p)
 
1550
  ;;(declare (values cache))
 
1551
  (with-local-cache-functions (cache)
 
1552
    (let ((ncache (get-cache-from-cache cache (* (nlines) 2))))
 
1553
      (labels ((do-one-fill-from-line (line)
 
1554
                 (unless (fill-cache-from-cache-p nil ncache cache line)
 
1555
                   (do-one-fill (line-wrappers line) (line-value line))))
 
1556
               (do-one-fill (wrappers value)
 
1557
                 (setq ncache (or (adjust-cache ncache wrappers value t)
 
1558
                                  (fill-cache-p t ncache wrappers value))))
 
1559
               (try-one-fill (wrappers value)
 
1560
                 (fill-cache-p nil ncache wrappers value)))
 
1561
        (dotimes (i (nlines))
 
1562
          (when (and (null (line-reserved-p i))
 
1563
                     (line-valid-p i wrappers))
 
1564
            (do-one-fill-from-line i)))
 
1565
        (dolist (wrappers+value (cache-overflow cache))
 
1566
          (unless (try-one-fill (car wrappers+value) (cdr wrappers+value))
 
1567
            (do-one-fill (car wrappers+value) (cdr wrappers+value))))
 
1568
        (unless (try-one-fill wrappers value)
 
1569
          (do-one-fill wrappers value))
 
1570
        (when free-old-cache-p (free-cache cache))
 
1571
        (maybe-check-cache ncache)))))
 
1572
 
 
1573
 
 
1574
;;;
 
1575
;;; This is the heart of the cache filling mechanism.  It implements the decisions
 
1576
;;; about where entries are placed.
 
1577
;;; 
 
1578
;;; Find a line in the cache at which a new entry can be inserted.
 
1579
;;;
 
1580
;;;   <line>
 
1581
;;;   <empty?>           is <line> in fact empty?
 
1582
;;;
 
1583
(defun find-free-cache-line (primary cache &optional wrappers)
 
1584
  ;;(declare (values line empty?))
 
1585
  (declare (type non-negative-fixnum primary))
 
1586
  (with-local-cache-functions (cache)
 
1587
    (when (line-reserved-p primary) (setq primary (next-line primary)))
 
1588
    (let ((limit (funcall (limit-fn) (nlines)))
 
1589
          (wrappedp nil)
 
1590
          (lines nil)
 
1591
          (p primary) (s primary))
 
1592
      (declare (type non-negative-fixnum p s limit))
 
1593
      (block find-free
 
1594
        (loop
 
1595
         ;; Try to find a free line starting at <s>.  <p> is the
 
1596
         ;; primary line of the entry we are finding a free
 
1597
         ;; line for, it is used to compute the seperations.
 
1598
         (do* ((line s (next-line line))
 
1599
               (nsep (line-separation p s) (1+ nsep)))
 
1600
              (())
 
1601
           (declare (type non-negative-fixnum line nsep))
 
1602
           (when (null (line-valid-p line wrappers)) ;If this line is empty or
 
1603
             (push line lines)          ;invalid, just use it.
 
1604
             (return-from find-free))
 
1605
           (when (and wrappedp (>= line primary))
 
1606
             ;; have gone all the way around the cache, time to quit
 
1607
             (return-from find-free-cache-line (values primary nil)))
 
1608
           (let ((osep (line-separation (line-primary line) line)))
 
1609
             (when (>= osep limit)
 
1610
               (return-from find-free-cache-line (values primary nil)))
 
1611
             (when (cond ((= nsep limit) t)
 
1612
                         ((= nsep osep) (zerop (random 2)))
 
1613
                         ((> nsep osep) t)
 
1614
                         (t nil))
 
1615
               ;; See if we can displace what is in this line so that we
 
1616
               ;; can use the line.
 
1617
               (when (= line (the fixnum (1- (nlines)))) (setq wrappedp t))
 
1618
               (setq p (line-primary line))
 
1619
               (setq s (next-line line))
 
1620
               (push line lines)
 
1621
               (return nil)))
 
1622
           (when (= line (the fixnum (1- (nlines)))) (setq wrappedp t)))))
 
1623
      ;; Do all the displacing.
 
1624
      (loop 
 
1625
       (when (null (cdr lines)) (return nil))
 
1626
       (let ((dline (pop lines))
 
1627
             (line (car lines)))
 
1628
         (declare (type non-negative-fixnum dline line))
 
1629
         ;;Copy from line to dline (dline is known to be free).
 
1630
         (let ((from-loc (line-location line))
 
1631
               (to-loc (line-location dline))
 
1632
               (cache-vector (vector)))
 
1633
           (declare (type non-negative-fixnum from-loc to-loc)
 
1634
                    (simple-vector cache-vector))
 
1635
           (modify-cache cache-vector
 
1636
                         (dotimes (i (line-size))
 
1637
                           (setf (cache-vector-ref cache-vector (+ to-loc i))
 
1638
                                 (cache-vector-ref cache-vector (+ from-loc i)))
 
1639
                           (setf (cache-vector-ref cache-vector (+ from-loc i))
 
1640
                                 nil))))))
 
1641
      (values (car lines) t))))
 
1642
 
 
1643
(defun default-limit-fn (nlines)
 
1644
  (case nlines
 
1645
    ((1 2 4) 1)
 
1646
    ((8 16)  4)
 
1647
    (otherwise 6)))
 
1648
 
 
1649
(defvar *empty-cache* (make-cache)) ; for defstruct slot initial value forms
 
1650
 
 
1651
;;;
 
1652
;;; pre-allocate generic function caches.  The hope is that this will put
 
1653
;;; them nicely together in memory, and that that may be a win.  Of course
 
1654
;;; the first gc copy will probably blow that out, this really wants to be
 
1655
;;; wrapped in something that declares the area static.
 
1656
;;;
 
1657
;;; This preallocation only creates about 25% more caches than PCL itself
 
1658
;;; uses.  Some ports may want to preallocate some more of these.
 
1659
;;; 
 
1660
(eval-when (load)
 
1661
  (dolist (n-size '((1 513)(3 257)(3 129)(14 128)(6 65)(2 64)(7 33)(16 32)
 
1662
                    (16 17)(32 16)(64 9)(64 8)(6 5)(128 4)(35 2)))
 
1663
    (let ((n (car n-size))
 
1664
          (size (cadr n-size)))
 
1665
      (mapcar #'free-cache-vector
 
1666
              (mapcar #'get-cache-vector
 
1667
                      (make-list n :initial-element size))))))
 
1668
 
 
1669
(defun caches-to-allocate ()
 
1670
  (sort (let ((l nil))
 
1671
          (maphash #'(lambda (size entry)
 
1672
                       (push (list (car entry) size) l))
 
1673
                   pcl::*free-caches*)
 
1674
          l)
 
1675
        #'> :key #'cadr))
 
1676
 
 
1677