Eliminate style-warning about undefined type GLOBAL-VAR
[sbcl.git] / src / compiler / info-vector.lisp
blobcdb491a927585dd566913b6fdfe554fac0d4f88a
1 ;;;; This software is part of the SBCL system. See the README file for
2 ;;;; more information.
3 ;;;;
4 ;;;; This software is derived from the CMU CL system, which was
5 ;;;; written at Carnegie Mellon University and released into the
6 ;;;; public domain. The software is in the public domain and is
7 ;;;; provided with absolutely no warranty. See the COPYING and CREDITS
8 ;;;; files for more information.
10 (in-package "SB!C")
12 ;;;; This file implements abstract types which map globaldb Info-Number/Name
13 ;;;; pairs to data values. The database itself is defined in 'globaldb'.
15 ;;; Quasi-lockfree concurrent hashtable
16 ;;; ===================================
18 ;; References:
19 ;; http://trac.clozure.com/ccl/wiki/Internals/LockFreeHashTables
20 ;; https://github.com/boundary/high-scale-lib/blob/master/src/main/java/org/cliffc/high_scale_lib/NonBlockingHashMap.java
22 ;; The basic hashable is a lightweight one using prime number sizing strategy,
23 ;; and a secondary hash for re-probing that is not necessarily co-prime with
24 ;; the table size (as it would be, ideally), and no support for deletion.
26 ;; The lock-free logic differs from each of the preceding reference algorithms.
27 ;; The Java algorithm is truly lock-free: death of any thread will never impede
28 ;; progress in other threads. The CCL algorithm is only quasi-lock-free, as is
29 ;; ours. Were a rehashing thread to terminate abnormally while holding the
30 ;; rehash mutex, all other threads will likely starve at some point.
32 ;; Unlike the CCL algorithm, we allow reading/writing concurrently with rehash.
33 ;; Most operations will never notice that the rehasher has acquired a mutex,
34 ;; because the only case where writers compete for the mutex is in trying
35 ;; to claim a new cell in a storage vector that is being transported, and where
36 ;; the rehasher has already visited the desired cell. Since the rehasher will
37 ;; never re-visit a cell, it disallows updates that it could not perceive.
38 ;; The Java algorithm has additional complexity imposed upon it by the
39 ;; feature that rehashing work is parceling out fairly to threads,
40 ;; whereas we avoid that by having one rehasher transport all cells.
42 ;; A marker for cells that may be claimed by a writer
43 (defconstant +empty-key+ 0)
44 ;; A marker for cells that may NOT be claimed by a writer.
45 (defconstant +unavailable-key+ -1)
47 ;; We have a 24-bit cell index. This is generous,
48 ;; allowing for ~5 million Names assuming 60% load factor.
49 (deftype info-cell-index () `(unsigned-byte 24))
51 ;; An INFO-STORAGE is a vector of a 3-element header followed by all keys
52 ;; and then all values. This way we can simply use FILL to set all keys to 0
53 ;; and all values to NIL.
54 (defconstant +info-keys-offset+ 3)
55 (defstruct (info-storage (:type vector) (:constructor nil) (:copier nil))
56 ;; Capacity refers to pairs of vector elements. The lower bound is to
57 ;; try (in vain) to elide a check for division by 0 in the secondary hash.
58 ;; The upper bound is harmlessly wrong by a factor of 2 because
59 ;; INFO-CELL-INDEX should be the max physical cell that can be addressed.
60 ;; No problem - you'll run out of memory before hitting the edge anyway.
61 (capacity 0 :type (and (integer 3 *) info-cell-index)) ; immutable
62 ;; Make a new storage if count exceeds this
63 (threshold 0 :type info-cell-index) ; immutable
64 (next nil :type simple-vector) ; Pending INFO-STORAGE during rehash
65 ;; keys ... data ...
68 (declaim (ftype (sfunction (unsigned-byte)
69 (unsigned-byte #.sb!vm:n-positive-fixnum-bits))
70 primify))
71 (defun make-info-storage (n-cells-min &optional (load-factor .7))
72 ;; If you ask for 40 entries at 50% load, you get (PRIMIFY 80) entries.
73 (let* ((n-cells (primify (ceiling n-cells-min load-factor)))
74 (a (make-array (+ +info-keys-offset+ (* 2 n-cells))))
75 (end (+ +info-keys-offset+ n-cells)))
76 (setf (info-storage-capacity a) n-cells
77 ;; The threshold should be approximately the same as
78 ;; the number you asked for in the first place.
79 (info-storage-threshold a) (floor (* n-cells load-factor))
80 (info-storage-next a) #()) ; type-correct initial value
81 (fill a +empty-key+ :start +info-keys-offset+ :end end)
82 (fill a nil :start end)
83 a))
85 (declaim (ftype (sfunction (t) (unsigned-byte #.sb!vm:n-positive-fixnum-bits))
86 globaldb-sxhashoid))
87 (defstruct (info-hashtable (:conc-name info-env-))
88 (storage (make-info-storage 30) :type simple-vector)
89 (comparator #'equal :type function)
90 (hash-function #'globaldb-sxhashoid :type function)
91 (mutex (sb!thread:make-mutex))
92 ;; COUNT is always at *least* as large as the key count.
93 ;; If no insertions are in progress, it is exactly right.
94 (count 0 :type word))
96 (def!method print-object ((self info-hashtable) stream)
97 (declare (stream stream))
98 (print-unreadable-object (self stream :type t :identity t)
99 (format stream "~D/~D entr~:@P" (info-env-count self)
100 (info-storage-capacity (info-env-storage self)))))
102 ;; We can't assume that the host lisp supports a CAS operation for info-gethash
103 ;; or info-puthash, but that's fine because there's only one thread.
104 (defmacro info-cas (storage index oldval newval)
105 #+sb-xc-host
106 `(xc-compare-and-swap-svref ,storage ,index ,oldval ,newval)
107 #-sb-xc-host
108 `(cas (svref ,storage ,index) ,oldval ,newval))
110 ;; Similarly we need a way to atomically adjust the hashtable count.
111 (declaim (inline info-env-adjust-count))
112 (defun info-env-adjust-count (table delta)
113 #+sb-xc-host
114 (prog1 (info-env-count table) (incf (info-env-count table) delta))
115 #-sb-xc-host
116 ;; Inform the compiler that this is not possibly a bignum,
117 ;; since it's true upper bound is the info storage threshold.
118 (truly-the info-cell-index (atomic-incf (info-env-count table) delta)))
120 (declaim (inline make-info-forwarding-pointer
121 info-forwarding-pointer-target
122 info-value-moved-p)
123 (ftype (sfunction (t) simple-vector) info-env-rehash)
124 (ftype (sfunction (t t) simple-vector) %wait-for-rehash))
126 ;; Concurrent access relies on a forwarding pointer being placed into
127 ;; transported value cells. Since this is not a fully general hashtable,
128 ;; we can use fixnums as forwarding pointers, as they're otherwise
129 ;; never present as a value.
130 #+sb-xc-host
131 (progn
132 (defun xc-compare-and-swap-svref (vector index old new)
133 (let ((actual-old (svref vector index)))
134 (if (eq old actual-old)
135 (progn (setf (svref vector index) new) old)
136 (error "xc bug. CAS expected ~S got ~S" old actual-old))))
137 (defun make-info-forwarding-pointer (index) index)
138 (defun info-forwarding-pointer-target (pointer) pointer)
139 (defun info-value-moved-p (val) (fixnump val)))
141 ;; However, here is a forwarding-pointer representation that allows fixnums
142 ;; as legal values in the table, so, since it's more general, ... why not?
143 #-sb-xc-host
144 (progn
145 (defun make-info-forwarding-pointer (index)
146 (declare (type info-cell-index index) (optimize (safety 0)))
147 (%make-lisp-obj (+ (ash index 8) sb!vm:unbound-marker-widetag)))
148 (defun info-forwarding-pointer-target (marker)
149 (ash (get-lisp-obj-address marker) -8))
150 (defun info-value-moved-p (x)
151 (eq (logand (get-lisp-obj-address x) #xff)
152 sb!vm:unbound-marker-widetag)))
154 ;; The common skeleton of {Get, Put, Rehash} operations. Probe key cells until
155 ;; either a hit occurs, in which case the :HIT form is executed and looping
156 ;; stops; or an empty slot is seen in which case the :MISS code is executed.
157 ;; :MISS should contain a GO or RETURN on success, otherwise probing continues.
158 ;; No precaution exists against probing forever, such as could happen if the
159 ;; probing strategy fails to visit all candidate free cells.
161 ;; Stepping is done by subtracting a secondary hash rather than adding,
162 ;; as this allows testing for wraparound by comparison to a constant
163 ;; instead of against storage capacity. Nonlinear probing jumps around in
164 ;; the L1 cache regardless, as they key space is a ring so the "direction"
165 ;; of probing is irrelevant. [In contrast, linear probing usually benefits
166 ;; from scanning physically forward, preferably within a cache line,
167 ;; but for practical purposes linear probing is worse.]
169 (defmacro !do-probe-sequence ((storage key table &optional hash)
170 &key probe hit miss)
171 (with-unique-names (test miss-fn len key-index step)
172 (once-only ((storage storage) (key key) (table table)
173 (hashval
174 `(the fixnum
175 ,(or hash
176 `(funcall (info-env-hash-function ,table) ,key)))))
177 `(macrolet ((key-index () ; expose key+value indices to invoking code
178 ',key-index)
179 (value-index ()
180 '(+ (info-storage-capacity ,storage) ,key-index))
181 (,test ()
182 `(let ((probed-key (svref ,',storage ,',key-index)))
183 ,',probe ; could keep a tally of the probes
184 ;; Optimistically test for hit first, then markers
185 (cond ((funcall (info-env-comparator ,',table)
186 probed-key ,',key)
187 (go :hit))
188 ((or (eql probed-key +unavailable-key+)
189 (eql probed-key +empty-key+))
190 (,',miss-fn))))))
191 (let* ((,len (info-storage-capacity ,storage))
192 (,key-index (+ (rem ,hashval ,len) +info-keys-offset+))
193 (,step 0))
194 (declare (type info-cell-index ,key-index ,step))
195 (dx-flet ((,miss-fn () ,miss))
196 (tagbody
197 (,test)
198 ;; only need the second hash if didn't hit on first try
199 (setq ,step (1+ (rem ,hashval (- ,len 2))))
200 :loop
201 (setq ,key-index (let ((next (- ,key-index ,step)))
202 (if (< next +info-keys-offset+)
203 (+ next ,len)
204 next)))
205 (,test)
206 (go :loop)
207 :HIT))
208 ,hit)))))
210 ;; Wait for ENV's storage to change to something other than STORAGE, and
211 ;; return the new one. As long as rehash finishes in finite time, every thread
212 ;; makes progess. We don't protect against untimely death of the thread
213 ;; that holds the lock.
215 (defun %wait-for-rehash (env storage)
216 ;; kinda spin, except not quite that bad
217 (loop (sb!thread:thread-yield) ; relinquish time slice, supposing it helps
218 (if (eq (info-env-storage env) storage)
219 ;; Grab and release the mutex for no other reason than to
220 ;; observe that a rehasher doesn't (for the moment) have it.
221 (sb!thread:with-mutex ((info-env-mutex env))) ; do nothing, retry
222 (return (info-env-storage env)))))
224 ;; Look in info-environment ENV for the name KEY. Arguments are like GETHASH.
226 ;; Invariant: any KEY's value is present in at most 1 storage.
227 ;; Uniqueness of the location ensures that when writing with CAS, the place is
228 ;; either current, or CAS fails in a way that informs the writer of a new place.
229 ;; At most one probing sequence occurs, in that hitting a key might entail
230 ;; more than one forwarding but never a re-probing.
231 ;; The same is not true on insert, for which probing restart is quite common.
232 ;; When chasing values, INFO-STORAGE-NEXT may or may not be EQ to what is in
233 ;; INFO-ENV-STORAGE, depending whether rehash is still running, has completed,
234 ;; or started all over again before the reader got a chance to chase one time.
236 (defun info-gethash (key env &aux (storage (info-env-storage env)))
237 (!do-probe-sequence (storage key env)
238 :miss (return-from info-gethash nil)
239 ;; With 99% certainty the :READ barrier is needed for non-x86, and if not,
240 ;; it can't hurt. 'info-storage-next' can be empty until at least one cell
241 ;; has been forwarded, but in general an unsynchronized read might be
242 ;; perceived as executing before a conditional that guards whether the
243 ;; read should happen at all. 'storage-next' has the deceptive look of a
244 ;; data dependency but it's not - it's a control dependency which as per
245 ;; the 'memory-barriers.txt' document at kernel.org, demands a barrier.
246 ;; The subsequent ref to storage (if the loop iterates) has a
247 ;; data-dependency, and will never be reordered except on an Alpha :-(
248 ;; so we _don't_ need a barrier after resetting 'storage' and 'index'.
249 :hit (let ((index (value-index)))
250 (loop (let ((value
251 (sb!thread:barrier (:read) (svref storage index))))
252 (if (info-value-moved-p value)
253 (setq storage (info-storage-next storage)
254 index (info-forwarding-pointer-target value))
255 (return value)))))))
257 ;; ENV and KEY are as above. UPDATE-PROC is invoked with the old value stored
258 ;; for KEY and it should return the possibly-unchanged new value to put.
260 ;; Note a tiny problem of semantics on 'miss' - for an instant after winning
261 ;; CAS of a new key, that key appears to exist with the default value NIL,
262 ;; causing readers to think "FOUND-P" = T which might have a different sense
263 ;; from "not found". If a Name is transiently "found" despite having no data,
264 ;; nobody cares, at least for globaldb. Remedies, if desired, involve either:
265 ;; 1. Making a "no value" marker that is distinct from NIL.
266 ;; 2. Placing keys/value pairs in adjacent cells and using double-wide CAS.
267 ;; The reason we don't care about this anomaly is that we have to
268 ;; look in an Info-Vector [q.v.] anyway to get the whole picture.
270 (defun info-puthash (env key update-proc)
271 (aver (not (member key '(0 -1))))
272 (labels ((follow/update (array value-index)
273 (let ((value ; see INFO-GETHASH for this barrier's rationale
274 (sb!thread:barrier (:read) (svref array value-index))))
275 (if (info-value-moved-p value)
276 (follow/update (info-storage-next array)
277 (info-forwarding-pointer-target value))
278 (update array value-index value))))
279 (update (array index oldval)
280 ;; invariant: OLDVAL is not a forwarding pointer.
281 (let ((newval (funcall update-proc oldval)))
282 (if (eq newval oldval)
283 oldval ; forgo update
284 (named-let put ((array array) (index index))
285 (let ((actual-old (info-cas array index oldval newval)))
286 ;; Unlike above, this read of storage-next can not
287 ;; be perceived as having occurred prior to CAS.
288 ;; x86 synchronizes at every locked instruction, and our
289 ;; PPC CAS vops sync as a nececessity of performing CAS.
290 (cond ((eq oldval actual-old) newval) ; win
291 ((info-value-moved-p actual-old) ; forwarded
292 (put (info-storage-next array)
293 (info-forwarding-pointer-target actual-old)))
294 (t ; collision with another writer
295 (update array index actual-old)))))))))
296 (named-let probe ((hashval (funcall (info-env-hash-function env) key))
297 (storage (info-env-storage env)))
298 (!do-probe-sequence (storage key env hashval)
299 :hit (follow/update storage (value-index))
300 :miss
301 (progn
302 (let ((old-count (info-env-adjust-count env 1)))
303 (declare (type info-cell-index old-count))
304 (when (>= old-count (info-storage-threshold storage))
305 (sb!thread:with-mutex ((info-env-mutex env))
306 ;; any thread could have beaten us to rehashing
307 (when (eq (info-env-storage env) storage)
308 (info-env-rehash env)))
309 (info-env-adjust-count env -1) ; prepare to retry
310 (return-from probe (probe hashval (info-env-storage env)))))
311 ;; Attempt to claim KEY-INDEX
312 (let ((oldkey (info-cas storage (key-index) +empty-key+ key)))
313 (when (eql oldkey +empty-key+) ; successful claim
314 ;; Optimistically assume that nobody else rewrote the value
315 (return-from probe (update storage (value-index) nil)))
316 (info-env-adjust-count env -1) ; failed
317 ;; The fallthrough branch of this COND is ordinary CAS failure where
318 ;; somebody else wanted this slot, and won. Looping tries again.
319 (cond ((funcall (info-env-comparator env) oldkey key) ; coincidence
320 (return-from probe (follow/update storage (value-index))))
321 ((eql oldkey +unavailable-key+) ; Highly unlikely
322 ;; as preemptive check up above ensured no rehash needed.
323 (return-from probe
324 (probe hashval (%wait-for-rehash env storage)))))))))))
326 ;; Rehash ENV to a larger storage. When writing a key into new storage,
327 ;; key cells are uniquely owned by this thread without contention.
328 ;; Other threads may not look in new storage without first observing that
329 ;; a key's value was definitely moved.
330 ;; The rehasher marks empty cells as unusable so that writers can't insert
331 ;; into the subsequence of storage already visited. The rehasher must of
332 ;; course vie for the cell it is trying to mark as unusable.
334 (defun info-env-rehash (env)
335 (let* ((old-count (info-env-count env))
336 (old-storage (info-env-storage env))
337 ;; the new storage begins life at ~50% capacity
338 (new-storage (make-info-storage (ceiling old-count .5)))
339 (old-capacity (info-storage-capacity old-storage))
340 (new-capacity (info-storage-capacity new-storage)))
342 (sb!thread:barrier (:write) ; Publish NEW-STORAGE before scanning keys.
343 (setf (info-storage-next old-storage) new-storage))
345 (loop for old-key-index of-type info-cell-index
346 from +info-keys-offset+ below (+ +info-keys-offset+ old-capacity)
347 ;; If the indexed cell is not in use, try once to prevent subsequent
348 ;; writes by changing the empty marker to 'unavailable'. The outcome
349 ;; determines whether to continue transporting the cell's value.
350 for key = (let ((key (svref old-storage old-key-index)))
351 (if (eql key +empty-key+)
352 (info-cas old-storage old-key-index
353 +empty-key+ +unavailable-key+)
354 key))
355 unless (eql key +empty-key+)
356 do (let* ((new-key-index
357 (block nil
358 (!do-probe-sequence (new-storage key env)
359 :hit (bug "Globaldb rehash failure. Mutated key?")
360 :miss (return (key-index)))))
361 (old-value-index (+ old-key-index old-capacity))
362 (new-value-index (+ new-key-index new-capacity))
363 (value (svref old-storage old-value-index)))
364 (setf (svref new-storage new-key-index) key) ; Q: barrier needed?
365 ;; Copy the current value into the new storage,
366 ;; and CAS in a forwarding pointer. Repeat until successful.
367 (loop
368 ;; Force VALUE to memory before publishing relocated status
369 (sb!thread:barrier (:write)
370 (setf (svref new-storage new-value-index) value))
371 (let ((actual-old
372 (info-cas
373 old-storage old-value-index value
374 (make-info-forwarding-pointer new-value-index))))
375 (if (eq value actual-old)
376 (return)
377 (setq value actual-old))))))
379 ;; Typical of most lockfree algorithms, we've no idea when
380 ;; the old storage can be freed. GC will figure it out.
381 ;; No write barrier needed. Threads still looking at old storage
382 ;; will eventually find all cells unavailable or forwarded.
383 (setf (info-env-storage env) new-storage)))
385 ;; This maphash implementation is not threadsafe.
386 ;; It can be made threadsafe by following forwarded values
387 ;; and skipping over unavailable keys.
389 (defmacro info-maphash (fun env) ; map FUN over each key/value
390 (with-unique-names (f storage capacity i key)
391 `(let* ((,f ,fun)
392 (,storage (info-env-storage ,env))
393 (,capacity (info-storage-capacity ,storage)))
394 (loop for ,i below ,capacity
395 for ,key = (svref ,storage (+ ,i +info-keys-offset+))
396 unless (eql ,key +empty-key+)
397 do (funcall ,f ,key
398 (svref ,storage
399 (+ ,i +info-keys-offset+ ,capacity)))))))
401 ;; CAS is the primitive operation on an info hashtable,
402 ;; and SETF is implemented in terms of CAS. For the most part it is
403 ;; inadvisable to use this for anything other than tinkering at the REPL.
405 (defun (setf info-gethash) (newval key env)
406 (dx-flet ((update (old) (declare (ignore old)) newval))
407 (info-puthash env key #'update)))
409 (defun show-info-env (env)
410 (info-maphash (lambda (k v) (format t "~S -> ~S~%" k v)) env))
412 ;;;; Info-Vectors
413 ;;;; ============
415 ;;; Info for a Name (an arbitrary object) is stored in an Info-Vector,
416 ;;; which is like is a 2-level association list. Info-Vectors are stored in
417 ;;; symbols for most names, or in the global hashtable for "complicated" names.
419 ;;; Such vectors exists in two variations: packed and unpacked.
420 ;;; The representations are nearly equivalent for lookup, but the packed format
421 ;;; is more space-efficient, though difficult to manipulate except by unpacking.
423 ;;; Consider a family of Names whose "root" is SB-MOP:STANDARD-INSTANCE-ACCESS.
424 ;;; 1. SB-MOP:STANDARD-INSTANCE-ACCESS
425 ;;; 2. (SETF SB-MOP:STANDARD-INSTANCE-ACCESS)
426 ;;; 3. (CAS SB-MOP:STANDARD-INSTANCE-ACCESS)
428 ;;; Those three names share one Info-Vector. Conceptually the outer alist key
429 ;;; is NIL for the first of those names, and SETF/CAS for the latter two.
430 ;;; The inner alist key is a number identifying a type of info.
431 ;;; If it were actually an alist, it would look like this:
433 ;;; ((nil (63 . #<fdefn SB-MOP:STANDARD-INSTANCE-ACCESS>) (1 . :FUNCTION) ...)
434 ;;; (SETF (63 . #<fdefn (SETF SB-MOP:STANDARD-INSTANCE-ACCESS)>) ...)
435 ;;; (CAS (63 . #<fdefn (CAS SB-MOP:STANDARD-INSTANCE-ACCESS)>) ...)
436 ;;; ...)
438 ;;; Note:
439 ;;; * The root name is exogenous to the vector - it is not stored.
440 ;;; * The info-number for (:FUNCTION :DEFINITION) is 63, :KIND is 1, etc.
441 ;;; * Names which are lists of length other than 2, or improper lists,
442 ;;; or whose elements are not both symbols, are disqualified.
444 ;;; Packed vector layout
445 ;;; --------------------
446 ;;; Because the keys to the inner lists are integers in the range 0 to 63,
447 ;;; either 5 or 10 keys will fit into a fixnum depending on word size.
448 ;;; This permits one memory read to retrieve a collection of keys. In packed
449 ;;; format, an ordered set of keys ("fields") is called a "descriptor".
451 ;;; Descriptors are stored from element 0 upward in the packed vector,
452 ;;; and data are indexed downward from the last element of the vector.
454 ;;; #(descriptor0 descriptor1 ... descriptorN valueN ... value1 value0)
456 ;;; e.g. The field at absolute index 3 - vector element 0, bit position 18 -
457 ;;; will find its data at index (- END 3). In this manner, it doesn't matter
458 ;;; how many more descriptors exist.
460 ;;; A "group" comprises all the info for a particular Name, and its list
461 ;;; of types may may span descriptors, though rarely.
462 ;;; An "auxilliary key" is the first element of a 2-list Name. It is interposed
463 ;;; within the data portion of the vector after the preceding info group.
464 ;;; Descriptors are self-delimiting in that the first field in a group
465 ;;; indicates the number of additional fields in the group.
467 ;;; Unpacked vector layout
468 ;;; ----------------------
469 ;;; This representation is used transiently during insertion/deletion.
470 ;;; It is a concatenation of plists as a vector, interposing at the splice
471 ;;; points the auxilliary key for the group, except for the root name which
472 ;;; does not store an auxilliary key.
474 ;;; Unpacked vector format looks like:
476 ;;; /- next group starts here
477 ;;; v
478 ;;; #(length type val type val ... KEY length type val ... KEY length ...)
479 ;;; ^
480 ;;; info group for the primary Name, a/k/a "root symbol", starts here
482 ;;; One can envision that the first info group stores its auxilliary key
483 ;;; at vector index -1 when thinking about the correctness of algorithms
484 ;;; that process unpacked info-vectors.
485 ;;; See !TEST-PACKIFY-INFOS for examples of each format.
487 ;;;;; Some stuff moved from 'globaldb.lisp':
489 (defconstant info-num-mask (ldb (byte info-number-bits 0) -1)) ; #b111111
491 ;; Using 6 bits per packed field, 5 infos can be described in a 30-bit fixnum,
492 ;; or 10 in a fixnum on 64-bit machines (regardless of n-fixnum-tag-bits).
493 ;; The eval-when seems to be necessary for building with CCL as host.
494 (eval-when (:compile-toplevel :load-toplevel :execute)
495 (defconstant +infos-per-word+ (floor sb!vm:n-fixnum-bits info-number-bits)))
497 ;; Descriptors are target fixnums
498 (deftype info-descriptor () `(signed-byte ,sb!vm:n-fixnum-bits))
500 ;; An empty info-vector. Its 0th field describes that there are no more fields.
501 (defconstant-eqx +nil-packed-infos+ #(0) #'equalp)
503 ;; FDEFINITIONs have an info-number that admits slightly clever logic
504 ;; for INFO-VECTOR-FDEFN. Do not change this constant without
505 ;; careful examination of that function.
506 (defconstant +fdefn-info-num+ info-num-mask)
508 ;; Extract a field from a packed info descriptor.
509 ;; A field is either a count of info-numbers, or an info-number.
510 (declaim (inline packed-info-field))
511 (defun packed-info-field (vector desc-index field-index)
512 (ldb (byte info-number-bits
513 (* (the (mod #.+infos-per-word+) field-index) info-number-bits))
514 (the info-descriptor (svref vector desc-index))))
516 ;; Compute the number of elements needed to hold unpacked VECTOR after packing.
517 ;; This is not "compute-packed-info-size" since that could be misconstrued
518 ;; and wanting the vector to be already packed.
520 (defun compute-packified-info-size (vector &optional (end (length vector)))
521 (declare (simple-vector vector)) ; unpacked format
522 (let ((index 0) ; index into the unpacked input vector
523 (n-fields 0)) ; will be the total number of packed fields
524 (declare (type index index end n-fields))
525 (loop
526 ;; 'length' is the number of vector elements in this info group,
527 ;; including itself but not including its auxilliary key.
528 (let ((length (the index (svref vector index))))
529 ;; Divide by 2 because we only count one field for the entry, but the
530 ;; input vector had 2 cells per entry. Add 1 because the group's field
531 ;; count is accounted for in the total packed field count.
532 (incf n-fields (1+ (ash length -1)))
533 (incf index (1+ length)) ; jump over the entries, +1 for aux-key
534 (when (>= index end)
535 ;; The first info group lacks an aux-key, making n-fields 1 too high
536 ;; in terms of data cells used, but correct for packed fields.
537 (return (+ (ceiling n-fields +infos-per-word+) (1- n-fields))))))))
539 ;; MAKE-INFO-DESCRIPTOR is basically ASH-LEFT-MODFX, shifting VAL by SHIFT.
540 ;; It is important that info descriptors be target fixnums, but 'cross-modular'
541 ;; isn't loaded early enough to use 'mask-signed-field'.
542 ;; It's not needed on 64-bit host/target combination because 10 fields (60 bits)
543 ;; never touch the sign bit.
544 ;; FIXME: figure out why the definition of ash-left-modfx is
545 ;; conditionalized out for platforms other than x86[-64].
546 ;; It looks like it ought to work whether or not there are vops.
547 (defmacro make-info-descriptor (val shift)
548 (if (> sb!vm:n-fixnum-bits 30)
549 `(ash ,val ,shift)
550 `(logior (if (logbitp (- 29 ,shift) ,val) sb!xc:most-negative-fixnum 0)
551 (ash ,val ,shift))))
553 ;; Convert unpacked vector to packed vector.
554 ;; 'pack-infos' would be a hypothetical accessor for the 'infos' of a 'pack'
555 ;; (whatever that is ...) so verbifying as such makes it more mnemonic to me.
557 (defun packify-infos (input &optional (end (length input)))
558 (declare (simple-vector input))
559 (let* ((output (make-array (compute-packified-info-size input end)))
560 (i -1) ; input index: pre-increment to read the next datum
561 (j -1) ; descriptor index: pre-increment to write
562 (k (length output)) ; data index: pre-decrement to write
563 (field-shift 0)
564 (word 0))
565 (declare (type index-or-minus-1 i j k end)
566 (type (mod #.(1+ (* (1- +infos-per-word+) info-number-bits)))
567 field-shift)
568 (type info-descriptor word))
569 (flet ((put-field (val) ; insert VAL into the current packed descriptor
570 (declare (type info-number val))
571 (setq word (logior (make-info-descriptor val field-shift) word))
572 (if (< field-shift (* (1- +infos-per-word+) info-number-bits))
573 (incf field-shift info-number-bits)
574 (setf (svref output (incf j)) word field-shift 0 word 0))))
575 ;; Truncating divide by 2: count = n-elements in the group @ 2 per entry,
576 ;; +1 for count itself but not including its aux-key.
577 (loop (let ((count (ash (the index (svref input (incf i))) -1)))
578 (put-field count) ; how many infos to follow
579 (dotimes (iter count)
580 (put-field (svref input (incf i))) ; an info-number
581 (setf (svref output (decf k)) (svref input (incf i)))) ; value
582 (when (>= (incf i) end)
583 (return))
584 (setf (svref output (decf k)) (svref input i))))) ; an aux-key
585 (unless (zerop field-shift) ; store the final descriptor word
586 (setf (svref output (incf j)) word))
587 (aver (eql (1+ j) k)) ; last descriptor must be adjacent final data cell
588 output))
590 ;; Within the scope of BODY, bind GENERATOR to a local function which
591 ;; returns the next field from a descriptor in INPUT-VAR, a packed vector.
592 ;; The generator uses DESCRIPTOR-INDEX and updates it as a side-effect.
594 (defmacro !with-packed-info-iterator ((generator input-var
595 &key descriptor-index)
596 &body body)
597 (with-unique-names (input word count)
598 `(let* ((,input (the simple-vector ,input-var))
599 (,descriptor-index -1)
600 (,count 0)
601 (,word 0))
602 (declare (type info-descriptor ,word)
603 (fixnum ,count)
604 (type index-or-minus-1 ,descriptor-index))
605 (flet ((,generator ()
606 (when (zerop ,count)
607 (incf ,descriptor-index)
608 (setq ,word (svref ,input ,descriptor-index)
609 ,count +infos-per-word+))
610 (prog1 (logand ,word info-num-mask)
611 (setq ,word (ash ,word (- info-number-bits)))
612 (decf ,count))))
613 ,@body))))
615 ;; Iterate over VECTOR, binding DATA-INDEX to the index of each aux-key in turn.
616 ;; TOTAL-N-FIELDS is deliberately exposed to invoking code.
618 (defmacro !do-packed-info-vector-aux-key ((vector &optional (data-index (gensym)))
619 step-form &optional result-form)
620 (with-unique-names (descriptor-idx field-idx)
621 (once-only ((vector vector))
622 `(let ((,data-index (length ,vector))
623 (,descriptor-idx 0)
624 (,field-idx 0)
625 (total-n-fields 0))
626 (declare (type index ,data-index ,descriptor-idx total-n-fields)
627 (type (mod #.+infos-per-word+) ,field-idx))
628 ;; Loop through the descriptors in random-access fashion.
629 ;; Skip 1+ n-infos each time, because the 'n-infos' is itself a field
630 ;; that is not accounted for in its own value.
631 (loop (let ((n (1+ (packed-info-field ,vector
632 ,descriptor-idx ,field-idx))))
633 (incf total-n-fields n)
634 (multiple-value-setq (,descriptor-idx ,field-idx)
635 (floor total-n-fields +infos-per-word+))
636 (decf ,data-index n))
637 ;; Done when the ascending index and descending index meet
638 (unless (< ,descriptor-idx ,data-index)
639 (return ,result-form))
640 ,@(if step-form (list step-form)))))))
642 ;; Return all function names that are stored in SYMBOL's info-vector.
643 ;; As an example, (INFO-VECTOR-NAME-LIST 'SB-PCL::DIRECT-SUPERCLASSES) =>
644 ;; ((SB-PCL::SLOT-ACCESSOR :GLOBAL SB-PCL::DIRECT-SUPERCLASSES SB-PCL::READER)
645 ;; (SB-PCL::SLOT-ACCESSOR :GLOBAL SB-PCL::DIRECT-SUPERCLASSES BOUNDP)
646 ;; (SB-PCL::SLOT-ACCESSOR :GLOBAL SB-PCL::DIRECT-SUPERCLASSES SB-PCL::WRITER))
647 (defun info-vector-name-list (symbol)
648 (let ((vector (symbol-info-vector symbol))
649 (list))
650 (when vector
651 (!do-packed-info-vector-aux-key (vector key-index)
652 (push (construct-globaldb-name (svref vector key-index) symbol)
653 list))
654 (nconc (and (plusp (packed-info-field vector 0 0)) (list symbol))
655 (nreverse list)))))
657 ;; Compute the number of elements needed to hold packed VECTOR after unpacking.
658 ;; The unpacked size is the number of auxilliary keys plus the number of entries
659 ;; @ 2 cells per entry, plus the number of length cells which indicate the
660 ;; number of data cells used (including length cells but not aux key cells).
661 ;; Equivalently, it's the number of packed fields times 2 minus 1.
663 (defun compute-unpackified-info-size (vector)
664 (declare (simple-vector vector))
665 (!do-packed-info-vector-aux-key (vector) ()
666 ;; off-by-one: the first info group's auxilliary key is imaginary
667 (1- (truly-the fixnum (ash total-n-fields 1)))))
669 ;; Convert packed INPUT vector to unpacked.
670 ;; If optional OUTPUT is supplied, it is used, otherwise output is allocated.
671 ;; For efficiency the OUTPUT should be provided as a dynamic-extent array.
673 (defun unpackify-infos (input &optional (output nil output-supplied-p))
674 (declare (simple-vector input))
675 (unless output-supplied-p
676 (setq output (make-array (compute-unpackified-info-size input))))
677 (let ((i (length input)) (j -1)) ; input index and output index respectively
678 (declare (type index-or-minus-1 i j))
679 (!with-packed-info-iterator (next-field input :descriptor-index desc-idx)
680 (loop ; over name
681 (let ((n-infos (next-field)))
682 ;; store the info group length, including the length cell in the length
683 (setf (svref output (incf j)) (1+ (ash n-infos 1)))
684 (dotimes (iter n-infos) ; over info-types
685 (setf (svref output (incf j)) (next-field) ; type-num
686 (svref output (incf j)) (svref input (decf i))))) ; value
687 (if (< desc-idx (decf i)) ; as long as the indices haven't met
688 (setf (svref output (incf j)) (svref input i)) ; copy next aux-key
689 (return (if output-supplied-p nil output))))))) ; else done
691 ;; Return the index of the 'length' item for an info group having
692 ;; auxilliary-key KEY in unpacked VECTOR bounded by END (exclusive),
693 ;; or NIL if not found.
695 (defun info-find-aux-key/unpacked (key vector end)
696 (declare (type index end))
697 (if (eql key +no-auxilliary-key+)
698 0 ; the first group's length (= end) is stored here always
699 (let ((index 0))
700 (declare (type index index))
701 (loop
702 ;; skip 'length' cells plus the next aux-key
703 (incf index (1+ (the index (svref vector index))))
704 (cond ((>= index end)
705 (return nil))
706 ;; backward a cell is where the aux-key resides.
707 ((eq (svref vector (1- index)) key)
708 (return index)))))))
710 ;; In packed info VECTOR try to find the auxilliary key SYMBOL.
711 ;; If found, return indices of its data, info descriptor word, and field.
712 ;; If not found, the first value is NIL and the descriptor indices
713 ;; arbitrarily point to the next available descriptor field.
715 (defun info-find-aux-key/packed (vector symbol)
716 ;; explicit bounds checking is done by the code below
717 (declare (optimize (safety 0)))
718 (aver (simple-vector-p vector))
719 (let ((descriptor-idx 0) ; physical index to vector
720 (field-idx 0) ; relative index within current descriptor
721 ;; On each iteration DATA-IDX points to an aux-key cell
722 ;; The first group's imaginary aux-key cell is past the end.
723 (data-idx (length (the simple-vector vector))))
724 (declare (type index descriptor-idx data-idx)
725 (fixnum field-idx)) ; can briefly exceed +infos-per-word+
726 ;; Efficiently skip past N-INFOS infos. If decrementing the data index
727 ;; hits the descriptor index, we're done. Otherwise increment the field
728 ;; index and maybe descriptor index and check again for loop termination.
729 (flet ((skip (n-infos &aux (n-fields (1+ n-infos))) ; return T on success
730 (cond ((<= (decf data-idx n-fields) descriptor-idx) nil)
731 ;; descriptor-idx < data-idx, so potentially more data.
732 ;; If current descriptor has another field, continue.
733 ((< (incf field-idx n-fields) +infos-per-word+) t)
734 (t ; The descriptor index advances.
735 (loop (incf descriptor-idx)
736 (when (< (decf field-idx +infos-per-word+)
737 +infos-per-word+)
738 (return (< descriptor-idx data-idx))))))))
739 (declare (inline skip))
740 ;; While this could compare aux-keys with #'EQUAL, it is not obvious how
741 ;; in general one would pick a symbol from the name as that which
742 ;; is delegated as the one to hold the info-vector.
743 (values (cond ((not (skip (packed-info-field vector 0 0))) nil)
744 ;; At least one aux key is present.
745 ((eq (aref vector data-idx) symbol) data-idx) ; yay
746 ;; aux-key order invariant allows early fail on SETF
747 ((eq symbol 'setf) nil)
749 (loop
750 (cond ((not (skip (packed-info-field vector descriptor-idx
751 field-idx)))
752 (return nil))
753 ((eq (aref vector data-idx) symbol)
754 (return data-idx))))))
755 descriptor-idx field-idx)))) ; can be ignored if 1st val is nil
757 ;; Take a packed info-vector INPUT and insert (AUX-KEY,INFO-NUMBER,VALUE).
758 ;; Packed info-vectors are immutable. Any alteration must create a copy.
759 ;; This is done by unpacking/repacking - it's easy enough and fairly
760 ;; efficient since the temporary vector is stack-allocated.
762 (defun %packed-info-insert (input aux-key info-number value)
763 (declare (simple-vector input) (type info-number info-number))
764 (let* ((n-extra-elts
765 ;; Test if the aux-key has been seen before or needs to be added.
766 (if (and (not (eql aux-key +no-auxilliary-key+))
767 (not (info-find-aux-key/packed input aux-key)))
768 4 ; need space for [aux-key, length, type-num, value]
769 2)) ; only space for [type-num, value]
770 (old-size (compute-unpackified-info-size input))
771 (new-size (+ old-size n-extra-elts))
772 (new (make-array new-size)))
773 (declare (type index old-size new-size)
774 (truly-dynamic-extent new))
775 (unpackify-infos input new)
776 (flet ((insert-at (point v0 v1)
777 (unless (eql point old-size) ; slide right
778 (replace new new :start1 (+ point n-extra-elts) :start2 point))
779 (setf (svref new point) v0
780 (svref new (+ point 1)) v1)))
781 (cond ((= n-extra-elts 4)
782 ;; creating a new aux key. SETF immediately follows the data
783 ;; for the primary Name. All other aux-keys go to the end.
784 (let ((point (if (eq aux-key 'setf) (svref new 0) old-size)))
785 (insert-at point aux-key 3) ; = add 3 data cells not incl. aux-key
786 (setf (svref new (+ point 2)) info-number
787 (svref new (+ point 3)) value)))
789 (let ((data-start (info-find-aux-key/unpacked
790 aux-key new old-size)))
791 ;; it had better be found - it was in the packed vector
792 (aver data-start)
793 ;; fdefn must be the first piece of info for any name.
794 ;; This facilitates implementing SYMBOL-FUNCTION without
795 ;; without completely decoding the vector.
796 (insert-at (+ data-start (if (eql info-number +fdefn-info-num+)
797 1 (svref new data-start)))
798 info-number value)
799 ;; add 2 cells, and verify that re-packing won't
800 ;; overflow the 'count' for this info group.
801 (aver (typep (ash (incf (svref new data-start) 2) -1)
802 'info-number))))))
803 (packify-infos new)))
805 ;; Return T if INFO-VECTOR admits quicker insertion logic - it must have
806 ;; exactly one descriptor for the root name, space for >= 1 more field,
807 ;; and no aux-keys.
808 (declaim (inline info-quickly-insertable-p))
809 (defun info-quickly-insertable-p (input)
810 (let ((n-infos (packed-info-field input 0 0)))
811 ;; We can easily determine if the no-aux-keys constraint is satisfied,
812 ;; because a secondary name's info occupies at least two cells,
813 ;; one for its aux-key and >= 1 for info values.
814 (and (< n-infos (1- +infos-per-word+))
815 (eql n-infos (1- (length input))))))
817 ;; Take a packed info-vector INPUT and return a new one with INFO-NUMBER/VALUE
818 ;; added for the root name. The vector must satisfy INFO-QUICKLY-INSERTABLE-P.
819 ;; This code is separate from PACKED-INFO-INSERT to facilitate writing
820 ;; a unit test of this logic against the complete logic.
822 (defun quick-packed-info-insert (input info-number value)
823 ;; Because INPUT contains 1 descriptor and its corresponding values,
824 ;; the current length is exactly NEW-N, the new number of fields.
825 (let* ((descriptor (svref input 0))
826 (new-n (truly-the info-number (length input)))
827 (new-vect (make-array (1+ new-n))))
828 ;; Two cases: we're either inserting info for the fdefn, or not.
829 (cond ((eq info-number +fdefn-info-num+)
830 ;; fdefn, if present, must remain the first packed field.
831 ;; Replace the lowest field (the count) with +fdefn-info-num+,
832 ;; shift everything left 6 bits, then OR in the new count.
833 (setf (svref new-vect 0)
834 (logior (make-info-descriptor
835 (dpb +fdefn-info-num+ (byte info-number-bits 0)
836 descriptor) info-number-bits) new-n)
837 ;; Packed vectors are indexed "backwards". The first
838 ;; field's info is in the highest numbered cell.
839 (svref new-vect new-n) value)
840 (loop for i from 1 below new-n
841 do (setf (svref new-vect i) (svref input i))))
843 ;; Add a field on the high end and increment the count.
844 (setf (svref new-vect 0)
845 (logior (make-info-descriptor
846 info-number (* info-number-bits new-n))
847 (1+ descriptor))
848 (svref new-vect 1) value)
849 ;; Slide the old data up 1 cell.
850 (loop for i from 2 to new-n
851 do (setf (svref new-vect i) (svref input (1- i))))))
852 new-vect))
854 (declaim (maybe-inline packed-info-insert))
855 (defun packed-info-insert (vector aux-key info-number newval)
856 (if (and (eql aux-key +no-auxilliary-key+)
857 (info-quickly-insertable-p vector))
858 (quick-packed-info-insert vector info-number newval)
859 (%packed-info-insert vector aux-key info-number newval)))
861 ;; Search packed VECTOR for AUX-KEY and INFO-NUMBER, returning
862 ;; the index of the data if found, or NIL if not found.
864 (defun packed-info-value-index (vector aux-key type-num)
865 (declare (optimize (safety 0))) ; vector bounds are AVERed
866 (let ((data-idx (length vector)) (descriptor-idx 0) (field-idx 0))
867 (declare (type index descriptor-idx)
868 (type (mod #.+infos-per-word+) field-idx))
869 (unless (eql aux-key +no-auxilliary-key+)
870 (multiple-value-setq (data-idx descriptor-idx field-idx)
871 (info-find-aux-key/packed vector aux-key))
872 (unless data-idx
873 (return-from packed-info-value-index nil)))
874 ;; Fetch a descriptor and shift out trailing bits that won't be scanned.
875 (let* ((descriptor (ash (the info-descriptor (aref vector descriptor-idx))
876 (* (- info-number-bits) field-idx)))
877 (n-infos (logand descriptor info-num-mask))
878 ;; Compute n things in this descriptor after extracting one field. e.g.
879 ;; if starting index = 2, there's space for 7 more fields in 60 bits.
880 (swath (min (- +infos-per-word+ field-idx 1) n-infos)))
881 ;; Type inference on n-infos deems it to have no lower bound due to DECF.
882 (declare (type info-descriptor descriptor)
883 (type (unsigned-byte #.info-number-bits) n-infos)
884 (type index data-idx))
885 ;; Repeatedly shift and mask, which is quicker than extracting a field at
886 ;; varying positions. Start by shifting out the n-infos field.
887 (setq descriptor (ash descriptor (- info-number-bits)))
888 (loop
889 (dotimes (j swath)
890 (when (eql type-num (logand descriptor info-num-mask))
891 (return-from packed-info-value-index
892 (the index (- data-idx j 1))))
893 (setq descriptor (ash descriptor (- info-number-bits))))
894 (when (zerop (decf n-infos swath))
895 (return nil))
896 (incf descriptor-idx)
897 (decf data-idx swath)
898 (aver (< descriptor-idx data-idx))
899 (setq descriptor (svref vector descriptor-idx)
900 swath (min n-infos +infos-per-word+))))))
902 ;; Helper for CLEAR-INFO-VALUES when Name has the efficient form.
903 ;; Given packed info-vector INPUT and auxilliary key KEY2
904 ;; return a new vector in which TYPE-NUMS are absent.
905 ;; When none of TYPE-NUMs were present to begin with, return NIL.
907 ;; While this could determine whether it would do anything before unpacking,
908 ;; clearing does not happen often enough to warrant the pre-check.
910 (defun packed-info-remove (input key2 type-nums)
911 (declare (simple-vector input))
912 (when (or (eql (length input) (length +nil-packed-infos+))
913 (and (not (eql key2 +no-auxilliary-key+))
914 (not (info-find-aux-key/packed input key2))))
915 (return-from packed-info-remove nil)) ; do nothing
916 (let* ((end (compute-unpackified-info-size input))
917 (new (make-array end))
918 (data-start 0))
919 (declare (truly-dynamic-extent new) (type index end data-start))
920 (unpackify-infos input new)
921 (let ((start (info-find-aux-key/unpacked key2 new end)))
922 (aver start) ; must be found - it was in the packed vector
923 (setq data-start start)) ; point to the group's length cell
924 (dolist (type-num type-nums)
925 (declare (type info-number type-num))
926 (let ((i (loop for probe from (1+ data-start) by 2
927 repeat (ash (svref new data-start) -1) ; =n-entries
928 when (eql (svref new probe) type-num)
929 return probe)))
930 ;; N.B. the early termination checks aren't just optimizations,
931 ;; they're requirements, because otherwise the loop could smash
932 ;; data that does not belong to this auxilliary key.
933 (cond ((not i)) ; not found - ignore
934 ;; Squash out 2 cells if deleting an info for primary name,
935 ;; or for secondary name with at least one more entry.
936 ((or (eql data-start 0) (> (svref new data-start) 3))
937 (replace new new :start1 i :start2 (+ i 2))
938 (decf end 2)
939 (when (= (decf (svref new data-start) 2) 1)
940 ;; the group is now comprised solely of its length cell
941 (return))) ; so bail out
943 ;; Delete the sole entry for a secondary name
944 ;; by removing aux-key, length, and one entry (a cell pair).
945 (replace new new :start1 (- i 2) :start2 (+ i 2))
946 (decf end 4) ; shorten by 4 cells, and stop now
947 (return)))))
948 (let ((delta (- (length new) end)))
949 (cond ((zerop delta) nil)
950 ;; All empty info-vectors are equivalent, so if
951 ;; unpacked vector has no data, return a constant.
952 ((eql end 1) +nil-packed-infos+)
953 (t (packify-infos new end)))))) ; otherwise repack
955 ;; We need a few magic constants to be shared between the next two functions.
956 (defconstant-eqx !+pcl-reader-name+ (make-symbol "READER") (constantly t))
957 (defconstant-eqx !+pcl-writer-name+ (make-symbol "WRITER") (constantly t))
958 (defconstant-eqx !+pcl-boundp-name+ (make-symbol "BOUNDP") (constantly t))
960 ;; PCL names are physically 4-lists (see "pcl/slot-name")
961 ;; that get treated as 2-component names for globaldb's purposes.
962 ;; Return the kind of PCL slot accessor name that NAME is, if it is one.
963 ;; i.e. it matches (SLOT-ACCESSOR :GLOBAL <sym> READER|WRITER|BOUNDP)
964 ;; When called, NAME is already known to start with 'SLOT-ACCESSOR.
965 ;; This has to be defined before building PCL.
966 (defun pcl-global-accessor-name-p (name)
967 (let* ((cdr (cdr name)) (tail (cdr cdr)) last
968 kind)
969 (if (and (eq (car cdr) :global)
970 (listp tail)
971 (symbolp (car tail))
972 (listp (setq last (cdr tail)))
973 (not (cdr last))
974 ;; Return symbols that can't conflict, in case somebody
975 ;; legitimates (BOUNDP <f>) via DEFINE-FUNCTION-NAME-SYNTAX.
976 ;; Especially important since BOUNDP is an external of CL.
977 (setq kind (case (car last)
978 (sb!pcl::reader !+pcl-reader-name+)
979 (sb!pcl::writer !+pcl-writer-name+)
980 (sb!pcl::boundp !+pcl-boundp-name+))))
981 ;; The first return value is what matters to WITH-GLOBALDB-NAME
982 ;; for deciding whether the name is "simple".
983 ;; Return the KIND first, just in case somehow we end up with
984 ;; (SLOT-ACCESSOR :GLOBAL NIL WRITER) as a name.
985 ;; [It "can't happen" since NIL is a constant though]
986 (values kind (car tail))
987 (values nil nil))))
989 ;; Construct a name from its parts.
990 ;; For PCL global accessors, produce the real name, not the 2-part name.
991 ;; This operation is not invoked in normal use of globaldb.
992 ;; It is only for mapping over all names.
993 (defun construct-globaldb-name (aux-symbol stem)
994 (cond ((eq aux-symbol !+pcl-reader-name+) (sb!pcl::slot-reader-name stem))
995 ((eq aux-symbol !+pcl-writer-name+) (sb!pcl::slot-writer-name stem))
996 ((eq aux-symbol !+pcl-boundp-name+) (sb!pcl::slot-boundp-name stem))
997 (t (list aux-symbol stem)))) ; something like (SETF frob)
999 ;; Call FUNCTION with each piece of info in packed VECT using ROOT-SYMBOL
1000 ;; as the primary name. FUNCTION must accept 3 values (NAME INFO-NUMBER VALUE).
1001 (defun %call-with-each-info (function vect root-symbol)
1002 (let ((name root-symbol)
1003 (data-idx (length vect)))
1004 (declare (type index data-idx))
1005 (!with-packed-info-iterator (next-field vect :descriptor-index desc-idx)
1006 (loop ; over name
1007 (dotimes (i (next-field)) ; number of infos for this name
1008 (funcall function name (next-field) (svref vect (decf data-idx))))
1009 (if (< desc-idx (decf data-idx))
1010 (setq name
1011 (construct-globaldb-name (svref vect data-idx) root-symbol))
1012 (return))))))
1015 Info packing example. This example has 2 auxilliary-keys: SETF and CAS.
1017 (!test-packify-infos '(13 :XYZ 18 "nine" 28 :BAR 7 T)
1018 '(SETF 8 NIL 17 :FGX)
1019 '(CAS 6 :MUMBLE 2 :BAZ 47 :FOO))
1021 #(109006134805865284 3010 :FOO :BAZ :MUMBLE CAS :FGX NIL SETF T :BAR "nine" :XYZ)
1023 (format nil "~4,'0o ~20,'0o" 3010 109006134805865284)
1024 => "5702 06032110020734221504"
1025 Reading from right-to-left, converting each 2-digit octal number to decimal:
1026 4, 13, 18, 28, 7, 2, 8, 17, 3, 6, 2, 47
1027 Which is interpreted as:
1028 4 infos for the root name. type numbers: 13, 18, 28, 7
1029 2 infos for SETF auxilliary-key. type numbers: 8, 17
1030 3 infos for CAS auxilliary-key. type numbers: 6, 2, 47
1032 (unpackify-infos (!test-packify-infos ...)) ; same input
1033 => #(9 13 :XYZ 18 "nine" 28 :BAR 7 T
1034 SETF 5 8 NIL 17 :FGX
1035 CAS 7 6 :MUMBLE 2 :BAZ 47 :FOO)
1036 This is interpreted as
1037 root name, 9 cells: {13->:XYZ, 18->"nine", 28->:BAR, 7->T}
1038 SETF, 5 cells: {8->NIL, 17->:FGX}
1039 CAS, 7 cells: {6->:MUMBLE, 2->:BAZ, 47->:FOO}
1042 ;; Reshape inputs per the above commented example to a packed vector.
1043 ;; The info for a symbol's fdefn must precede other info-numbers.
1044 ;; and SETF must be the first aux key if other aux keys are present.
1045 ;; The test function does not enforce these invariants.
1046 ;; N.B. As this function starts with "!", is is omitted from the target image.
1047 (defun !test-packify-infos (&rest lists)
1048 (flet ((check (plist)
1049 (and (evenp (length plist))
1050 (loop for (indicator value) on plist by #'cddr
1051 always (typep indicator 'info-number))))
1052 (add-length-prefix (list) ; computers count better than people
1053 (cons (1+ (length list)) list)))
1054 (unless (and (check (first lists))
1055 (every (lambda (list)
1056 (and (symbolp (car list)) (check (cdr list))))
1057 (rest lists)))
1058 (error "Malformed info entries"))
1059 (packify-infos
1060 (coerce (apply #'append
1061 (cons (add-length-prefix (first lists))
1062 (mapcar (lambda (more)
1063 (cons (car more)
1064 (add-length-prefix (cdr more))))
1065 (rest lists))))
1066 'vector))))
1068 ;; Given a NAME naming a globaldb object, decide whether the NAME has
1069 ;; an efficient or "simple" form, versus a general or "hairy" form.
1070 ;; The efficient form is either a symbol, a (CONS SYMBOL (CONS SYMBOL NULL)),
1071 ;; or a PCL global slot {reader, writer, boundp} function name.
1073 ;; If NAME is "simple", bind KEY2 and KEY1 to the elements
1074 ;; in that order, and execute the SIMPLE code, otherwise execute the HAIRY code.
1075 ;; If ALLOW-ATOM is T - the default - then NAME can be just a symbol
1076 ;; in which case its second component is +NO-AUXILLIARY-KEY+.
1078 (defmacro with-globaldb-name ((key1 key2 &optional (allow-atom t))
1079 name &key simple hairy)
1080 (with-unique-names (rest)
1081 `(let ((,key1 ,name) (,key2 +NO-AUXILLIARY-KEY+))
1082 (if (or ,@(if allow-atom `((symbolp ,key1)))
1083 (if (listp ,key1)
1084 (let ((,rest (cdr ,key1)))
1085 (when (listp ,rest)
1086 (cond ((not (cdr ,rest))
1087 (setq ,key2 (car ,key1) ,key1 (car ,rest))
1088 (and (symbolp ,key1) (symbolp ,key2) ,rest))
1089 ((eq (car ,key1) 'sb!pcl::slot-accessor)
1090 (multiple-value-setq (,key2 ,key1)
1091 (pcl-global-accessor-name-p ,key1))))))))
1092 ,simple
1093 ;; The KEYs remain bound, but they should not be used for anything.
1094 ,hairy))))
1096 ;; Given Info-Vector VECT, return the fdefn that it contains for its root name,
1097 ;; or nil if there is no value. NIL input is acceptable and will return NIL.
1098 (declaim (inline info-vector-fdefn))
1099 (defun info-vector-fdefn (vect)
1100 (when vect
1101 ;; This is safe: Info-Vector invariant requires that it have length >= 1.
1102 (let ((word (the fixnum (svref vect 0))))
1103 ;; Test that the first info-number is +fdefn-info-num+ and its n-infos
1104 ;; field is nonzero. These conditions can be tested simultaneously
1105 ;; using a SIMD-in-a-register idea. The low 6 bits must be nonzero
1106 ;; and the next 6 must be exactly #b111111, so considered together
1107 ;; as a 12-bit unsigned integer it must be >= #b111111000001
1108 (when (>= (ldb (byte (* info-number-bits 2) 0) word)
1109 (1+ (ash +fdefn-info-num+ info-number-bits)))
1110 ;; DATA-REF-WITH-OFFSET doesn't know the info-vector length invariant,
1111 ;; so depite (safety 0) eliding bounds check, FOLD-INDEX-ADDRESSING
1112 ;; wasn't kicking in without (TRULY-THE (INTEGER 1 *)).
1113 (aref vect (1- (truly-the (integer 1 *) (length vect))))))))
1115 ;;; Some of this stuff might belong in 'symbol.lisp', but can't be,
1116 ;;; because 'symbol.lisp' is :NOT-HOST in build-order.
1118 ;; In the target, UPDATE-SYMBOL-INFO is defined in 'symbol.lisp'.
1119 #+sb-xc-host
1120 (defun update-symbol-info (symbol update-fn)
1121 ;; Never pass NIL to an update-fn. Pass the minimal info-vector instead,
1122 ;; a vector describing 0 infos and 0 auxilliary keys.
1123 (let ((newval (funcall update-fn (or (symbol-info-vector symbol)
1124 +nil-packed-infos+))))
1125 (when newval
1126 (setf (symbol-info-vector symbol) newval))
1127 (values)))
1129 ;; Return the globaldb info for SYMBOL. With respect to the state diagram
1130 ;; presented at the definition of SYMBOL-PLIST, if the object in SYMBOL's
1131 ;; info slot is LISTP, it is in state 1 or 3. Either way, take the CDR.
1132 ;; Otherwise, it is in state 2 so return the value as-is.
1133 ;; In terms of this function being named "-vector", implying always a vector,
1134 ;; it is understood that NIL is a proxy for +NIL-PACKED-INFOS+, a vector.
1136 #-sb-xc-host
1137 (progn
1138 #!-symbol-info-vops (declaim (inline symbol-info-vector))
1139 (defun symbol-info-vector (symbol)
1140 (let ((info-holder (symbol-info symbol)))
1141 (truly-the (or null simple-vector)
1142 (if (listp info-holder) (cdr info-holder) info-holder)))))
1144 ;;; The current *INFO-ENVIRONMENT*, a structure of type INFO-HASHTABLE.
1145 ;;; Cheat by setting to nil before the type is proclaimed
1146 ;;; so that we can then also proclaim ALWAYS-BOUND.
1147 (defvar *info-environment* nil)
1148 #-sb-xc-host
1149 (declaim (type info-hashtable *info-environment*)
1150 (always-bound *info-environment*))
1152 ;;; Update the INFO-NUMBER for NAME in the global environment,
1153 ;;; setting it to NEW-VALUE. This is thread-safe in the presence
1154 ;;; of multiple readers/writers. Threads simultaneously writing data
1155 ;;; for the same NAME will succeed if the info type numbers differ,
1156 ;;; and the winner is indeterminate if the type numbers are the same.
1158 ;;; It is not usually a good idea to think of globaldb as an arbitrary
1159 ;;; key-to-value map supporting rapid or frequent update for a key.
1160 ;;; This is because each update must shallow-copy any data that existed
1161 ;;; for NAME, as a consequence of the very minimal lockfree protocol.
1163 ;;; If, for example, you wanted to track how many times a full-call to
1164 ;;; each global function was emitted during compilation, you could create
1165 ;;; an info-type (:function :full-calls) and the value of that info-type
1166 ;;; could be a cons cell holding an integer. In this way incrementing
1167 ;;; the cell contents does not affecting the globaldb. In contrast,
1168 ;;; (INCF (INFO :function :full-calls myname)) would perform poorly.
1170 ;;; See also ATOMIC-SET-INFO-VALUE and GET-INFO-VALUE-INITIALIZING
1171 ;;; for atomic read/modify/write operations.
1173 ;;; Return the new value so that this can be conveniently used in a
1174 ;;; SETF function.
1175 (defun set-info-value (name info-number new-value)
1176 (when (typep name 'fixnum)
1177 (error "~D is not a legal INFO name." name))
1179 ;; Storage of FAST-METHOD and SLOW-METHOD compiler info is largely pointless.
1180 ;; Why? Because the compiler can't even resolve the "name" of the function in
1181 ;; many cases. If there are EQL specializers involved, it's clearly impossible
1182 ;; because the form X in (EQL x) needs to be evaluated. So most of the data
1183 ;; can't be computed until the file defining the method is loaded. At that
1184 ;; point, you know that the :KIND is :FUNCTION, and :WHERE-FROM is :DEFINED
1185 ;; - they can't be anything else. And you also pretty much know the signature,
1186 ;; since it is based on the specializers, so storing again is a total waste.
1188 ;; FIXME: figure out a way not to store these, or else have globaldb ignore
1189 ;; the calls to set-info-value, and mock any calls to get-info-value
1190 ;; so that it looks like the data were stored, if someone tries to read it.
1191 ;: Or store the data in the method object somehow so that at least dropping
1192 ;; a method can drop the data. This would work because as mentioned above,
1193 ;; there is mostly no such thing as purely compile-time info for methods.
1194 #+nil ; So I can easily re-enable this to figure out what's going on.
1195 (when (and (consp name)
1196 (memq (car name) '(sb!pcl::slow-method sb!pcl::fast-method))
1197 (some #'consp (car (last name))))
1198 (let ((i (aref sb!c::*info-types* info-number)))
1199 (warn "Globaldb storing info for ~S~% ~S ~S~% -> ~S"
1200 name (meta-info-category i) (meta-info-kind i) new-value)))
1202 (let ((name (uncross name)))
1203 ;; If the INFO-NUMBER already exists in VECT, then copy it and
1204 ;; alter one cell; otherwise unpack it, grow the vector, and repack.
1205 (dx-flet ((augment (vect aux-key) ; VECT is a packed vector, never NIL
1206 (declare (simple-vector vect))
1207 (let ((index
1208 (packed-info-value-index vect aux-key info-number)))
1209 (if (not index)
1210 (packed-info-insert vect aux-key info-number new-value)
1211 (let ((copy (copy-seq vect)))
1212 (setf (svref copy index) new-value)
1213 copy)))))
1214 (with-globaldb-name (key1 key2) name
1215 :simple
1216 ;; UPDATE-SYMBOL-INFO never supplies OLD-INFO as NIL.
1217 (dx-flet ((simple-name (old-info) (augment old-info key2)))
1218 (update-symbol-info key1 #'simple-name))
1219 :hairy
1220 ;; INFO-PUTHASH supplies NIL for OLD-INFO if NAME was absent.
1221 (dx-flet ((hairy-name (old-info)
1222 (augment (or old-info +nil-packed-infos+)
1223 +no-auxilliary-key+)))
1224 (info-puthash *info-environment* name #'hairy-name)))))
1225 new-value)
1227 ;; Instead of accepting a new-value, call NEW-VALUE-FUN to compute it
1228 ;; from the existing value. The function receives two arguments:
1229 ;; if there was already a value, that value and T; otherwise two NILs.
1230 ;; Return the newly-computed value. If NEW-VALUE-FUN returns the old value
1231 ;; (compared by EQ) when there was one, then no globaldb update is made.
1232 (defun %atomic-set-info-value (name info-number new-value-fun)
1233 (declare (function new-value-fun))
1234 (when (typep name 'fixnum)
1235 (error "~D is not a legal INFO name." name))
1236 (let ((name (uncross name)) new-value)
1237 (dx-flet ((augment (vect aux-key) ; VECT is a packed vector, never NIL
1238 (declare (simple-vector vect))
1239 (let ((index
1240 (packed-info-value-index vect aux-key info-number)))
1241 (if (not index)
1242 (packed-info-insert
1243 vect aux-key info-number
1244 (setq new-value (funcall new-value-fun nil nil)))
1245 (let ((oldval (svref vect index)))
1246 (setq new-value (funcall new-value-fun oldval t))
1247 (if (eq new-value oldval)
1248 vect ; return the old vector
1249 (let ((copy (copy-seq vect)))
1250 (setf (svref copy index) new-value)
1251 copy)))))))
1252 (with-globaldb-name (key1 key2) name
1253 :simple
1254 ;; UPDATE-SYMBOL-INFO never supplies OLD-INFO as NIL.
1255 (dx-flet ((simple-name (old-info) (augment old-info key2)))
1256 (update-symbol-info key1 #'simple-name))
1257 :hairy
1258 ;; INFO-PUTHASH supplies NIL for OLD-INFO if NAME was absent.
1259 (dx-flet ((hairy-name (old-info)
1260 (augment (or old-info +nil-packed-infos+)
1261 +no-auxilliary-key+)))
1262 (info-puthash *info-environment* name #'hairy-name))))
1263 new-value))
1265 ;; %GET-INFO-VALUE-INITIALIZING is provided as a low-level operation similar
1266 ;; to the above because it does not require info metadata for defaulting,
1267 ;; nor deal with the keyword-based info type designators at all.
1268 ;; In contrast, GET-INFO-VALUE requires metadata.
1269 ;; For this operation to make sense, the objects produced should be permanently
1270 ;; assigned to their name, such as are fdefns and classoid-cells.
1271 ;; Note also that we do not do an initial attempt to read once with INFO,
1272 ;; followed up by a double-checking get-or-set operation. It is assumed that
1273 ;; the user of this already did an initial check, if such is warranted.
1274 (defun %get-info-value-initializing (name info-number creation-thunk)
1275 (when (typep name 'fixnum)
1276 (error "~D is not a legal INFO name." name))
1277 (let ((name (uncross name))
1278 result)
1279 (dx-flet ((get-or-set (info-vect aux-key)
1280 (let ((index
1281 (packed-info-value-index info-vect aux-key info-number)))
1282 (cond (index
1283 (setq result (svref info-vect index))
1284 nil) ; no update to info-vector
1286 ;; Update conflicts possibly for unrelated info-number
1287 ;; can force re-execution. (UNLESS result ...) tries
1288 ;; to avoid calling the thunk more than once.
1289 (unless result
1290 (setq result (funcall creation-thunk)))
1291 (packed-info-insert info-vect aux-key info-number
1292 result))))))
1293 (with-globaldb-name (key1 key2) name
1294 :simple
1295 ;; UPDATE-SYMBOL-INFO never supplies OLD-INFO as NIL.
1296 (dx-flet ((simple-name (old-info) (get-or-set old-info key2)))
1297 (update-symbol-info key1 #'simple-name))
1298 :hairy
1299 ;; INFO-PUTHASH supplies NIL for OLD-INFO if NAME was absent.
1300 (dx-flet ((hairy-name (old-info)
1301 (or (get-or-set (or old-info +nil-packed-infos+)
1302 +no-auxilliary-key+)
1303 ;; Return OLD-INFO to elide writeback. Unlike for
1304 ;; UPDATE-SYMBOL-INFO, NIL is not a no-op marker.
1305 old-info)))
1306 (info-puthash *info-environment* name #'hairy-name))))
1307 result))