1 ;;;; This file contains stuff that was split out from 'globaldb.lisp'
2 ;;;; to satisfy build-order constraints.
4 ;;;; This software is part of the SBCL system. See the README file for
7 ;;;; This software is derived from the CMU CL system, which was
8 ;;;; written at Carnegie Mellon University and released into the
9 ;;;; public domain. The software is in the public domain and is
10 ;;;; provided with absolutely no warranty. See the COPYING and CREDITS
11 ;;;; files for more information.
13 ;;; Given the presence of docstrings and source locations,
14 ;;; this logic arguably belongs to the runtime kernel, not the compiler,
15 ;;; but such nuance isn't hugely important.
18 ;;; Similar to FUNCTION, but the result type is "exactly" specified:
19 ;;; if it is an object type, then the function returns exactly one
20 ;;; value, if it is a short form of VALUES, then this short form
21 ;;; specifies the exact number of values.
22 (def!type sfunction
(args &optional result
)
23 (let ((result (cond ((eq result
'*) '*)
25 (not (eq (car result
) 'values
)))
26 `(values ,result
&optional
))
27 ((intersection (cdr result
) sb
!xc
:lambda-list-keywords
)
29 (t `(values ,@(cdr result
) &optional
)))))
30 `(function ,args
,result
)))
32 (declaim (ftype (sfunction (t t t
) (values t t
)) info
)
33 (ftype (sfunction (t t t
) t
) clear-info
)
34 (ftype (sfunction (t t t t
) t
) (setf info
)))
36 ;;; (:FUNCTION :TYPE) information is extracted through a wrapper.
37 ;;; The globaldb representation is not necessarily literally a CTYPE.
39 (declaim (ftype (sfunction (t) (values ctype boolean
)) proclaimed-ftype
))
41 ;;; At run time, we represent the type of a piece of INFO in the globaldb
42 ;;; by a small integer between 1 and 63. [0 is reserved for internal use.]
43 ;;; CLISP, and maybe others, need EVAL-WHEN because without it, the constant
44 ;;; is not seen by the "#." expression a few lines down.
45 (eval-when (:compile-toplevel
:load-toplevel
:execute
)
46 (defconstant info-number-bits
6))
47 (def!type info-number
() `(unsigned-byte ,info-number-bits
))
49 ;;; A map from info-number to its META-INFO object.
50 ;;; The reverse mapping is obtained by reading the META-INFO.
51 (declaim (type (simple-vector #.
(ash 1 info-number-bits
)) *info-types
*))
52 (!defglobal
*info-types
*
53 ;; Must be dumped as a literal for cold-load.
54 #.
(make-array (ash 1 info-number-bits
) :initial-element nil
))
58 !make-meta-info
(number category kind type-spec
59 type-checker validate-function default
))
61 ;; a number that uniquely identifies this object
62 (number nil
:type info-number
:read-only t
)
63 ;; 2-part key to this piece of metainfo
64 (category nil
:type keyword
:read-only t
)
65 (kind nil
:type keyword
:read-only t
)
66 ;; a type specifier which info of this type must satisfy
67 (type-spec nil
:type t
:read-only t
)
68 ;; Two functions called by (SETF INFO) before calling SET-INFO-VALUE.
69 ;; 1. A function that type-checks its argument and returns it,
70 ;; or signals an error.
71 ;; Some Lisps trip over their shoelaces trying to assert that
72 ;; a function is (function (t) t). Our code is fine though.
73 (type-checker nil
:type
#+sb-xc-host function
#-sb-xc-host
(sfunction (t) t
)
75 ;; 2. a function of two arguments, a name and new-value, which performs
76 ;; any other checks and/or side-effects including signaling an error.
77 (validate-function nil
:type
(or function null
) :read-only t
)
78 ;; If FUNCTIONP, then a function called when there is no information of
79 ;; this type. If not FUNCTIONP, then any object serving as a default.
80 (default nil
:read-only t
))
82 (declaim (freeze-type meta-info
))
84 (defconstant +info-metainfo-type-num
+ 0)
86 ;; Refer to info-vector.lisp for the meaning of this constant.
87 (defconstant +no-auxilliary-key
+ 0)
89 ;; Return the globaldb info for SYMBOL. With respect to the state diagram
90 ;; presented at the definition of SYMBOL-PLIST, if the object in SYMBOL's
91 ;; info slot is LISTP, it is in state 1 or 3. Either way, take the CDR.
92 ;; Otherwise, it is in state 2 so return the value as-is.
93 ;; In terms of this function being named "-vector", implying always a vector,
94 ;; it is understood that NIL is a proxy for +NIL-PACKED-INFOS+, a vector.
98 #!-symbol-info-vops
(declaim (inline symbol-info-vector
))
99 (defun symbol-info-vector (symbol)
100 (let ((info-holder (symbol-info symbol
)))
101 (truly-the (or null simple-vector
)
102 (if (listp info-holder
) (cdr info-holder
) info-holder
)))))
104 ;;; SYMBOL-INFO is a primitive object accessor defined in 'objdef.lisp'
105 ;;; But in the host Lisp, there is no such thing as a symbol-info slot.
106 ;;; Instead, symbol-info is kept in the host symbol's plist.
108 (defmacro symbol-info-vector
(symbol) `(get ,symbol
:sb-xc-globaldb-info
))
110 ;; Perform the equivalent of (GET-INFO-VALUE KIND +INFO-METAINFO-TYPE-NUM+)
111 ;; but skipping the defaulting logic.
112 ;; Return zero or more META-INFOs that match on KIND, which is usually
113 ;; - though not always - a unique identifier for the (:TYPE :KIND) pair.
114 ;; Note that bypassing of defaults is critical for bootstrapping,
115 ;; since INFO is used to retrieve its own META-INFO at system-build time.
116 (defmacro !get-meta-infos
(kind)
117 `(let* ((info-vector (symbol-info-vector ,kind
))
118 (index (if info-vector
119 (packed-info-value-index info-vector
+no-auxilliary-key
+
120 +info-metainfo-type-num
+))))
121 (if index
(svref info-vector index
))))
123 ;; (UNSIGNED-BYTE 16) is an arbitrarily generous limit on the number of
124 ;; cells in an info-vector. Most vectors have a fewer than a handful of things,
125 ;; and performance would need to be re-thought if more than about a dozen
126 ;; cells were in use. (It would want to become hash-based probably)
127 (declaim (ftype (function (simple-vector (or (eql 0) symbol
) info-number
)
128 (or null
(unsigned-byte 16)))
129 packed-info-value-index
))
131 ;; Return the META-INFO object for CATEGORY and KIND, signaling an error
132 ;; if not found and ERRORP is non-nil. Note that the two-level logical hierarchy
133 ;; of CATEGORY + KIND is physically grouped by KIND first, then CATEGORY.
134 ;; e.g. Searching for (:SETF :EXPANDER) searches for :EXPANDER and finds
135 ;; (#<:CAS :EXPANDER, 44> #<:SETF :EXPANDER, 43> #<:TYPE :EXPANDER, 25>)
136 ;; from which one is picked. This is slightly faster than searching first by
137 ;; CATEGORY, because in the case of :FUNCTION there would be ~11 things to sift
138 ;; through, whereas typically no more than 3 or 4 items have the same KIND.
140 (defun meta-info (category kind
&optional
(errorp t
))
141 (or (let ((metadata (!get-meta-infos kind
)))
142 (cond ((listp metadata
) ; conveniently handles NIL
143 (dolist (info metadata nil
) ; FIND is slower :-(
144 (when (eq (meta-info-category (truly-the meta-info info
))
147 ((eq (meta-info-category (truly-the meta-info metadata
)) category
)
149 ;; !GET-META-INFOS enforces that KIND is a symbol, therefore
150 ;; if a metaobject was found, CATEGORY was necessarily a symbol too.
151 ;; Otherwise, if the caller wants no error to be signaled on missing info,
152 ;; we must nevertheless enforce that CATEGORY was actually a symbol.
154 (error "(~S ~S) is not a defined info type." category kind
)
155 (progn (the symbol category
) nil
)))) ; THE is for type-safety
157 ;;; Compiler macros for INFO functions.
159 ;;; These are defined ASAP so that when building the cross-compiler, all calls
160 ;;; occurring after compilation of "globaldb" (for known constant meta-info)
161 ;;; are transformed; and when executing the cross-compiler, *all* inlineable
162 ;;; calls for known constant meta-info are transformed;
163 ;;; and when running target code, calls with legal constants for the first two
164 ;;; arguments are transformed.
165 (macrolet ((def (name lambda-list form
)
166 (assert (and (member 'category lambda-list
)
167 (member 'kind lambda-list
)))
168 `(define-compiler-macro ,name
,(append '(&whole .whole.
) lambda-list
)
169 (if (and (keywordp category
) (keywordp kind
))
170 ;; In the target Lisp, it's a STYLE-WARNING if this macro
171 ;; defers to a full call to #'INFO.
172 ;; If the cross-compilation host, if any info-type is
173 ;; defined, then it's an error not to find the meta-info.
174 ;; If no info-types are defined, silently defer.
176 (and #+sb-xc-host
(find-if #'identity
*info-types
*)
177 (meta-info category kind
#-sb-xc-host nil
))))
182 (style-warn "(~S ~S) is not a defined info type."
187 (def info
(category kind name
)
188 `(truly-the (values ,(meta-info-type-spec meta-info
) boolean
)
189 (get-info-value ,name
,(meta-info-number meta-info
))))
191 (def (setf info
) (new-value category kind name
)
192 (let* (#+sb-xc-host
(sb!xc
:*gensym-counter
* sb
!xc
:*gensym-counter
*)
193 (tin (meta-info-number meta-info
)) ; info-type id number
194 (type-spec (meta-info-type-spec meta-info
))
195 (new (make-symbol "NEW"))
197 (when (meta-info-validate-function meta-info
)
198 ;; is (or ... null), but non-null at macroexpansion time
199 ;; implies non-null at runtime.
201 (meta-info-validate-function
202 (truly-the meta-info
(svref *info-types
* ,tin
)))))))
203 `(let ((,new
,new-value
))
204 ;; enforce type-correctness regardless of enclosing policy
205 (let ((,new
(locally (declare (optimize (safety 3)))
206 (the ,type-spec
,new
))))
208 `((funcall ,check
,name
,new
)))
209 (set-info-value ,name
,tin
,new
)))))
211 (def clear-info
(category kind name
)
212 `(clear-info-values ,name
'(,(meta-info-number meta-info
)))))
214 ;; interface to %ATOMIC-SET-INFO-VALUE
215 ;; GET-INFO-VALUE-INITIALIZING is a restricted case of this,
216 ;; and perhaps could be implemented as such.
217 ;; Atomic update will be important for making the fasloader threadsafe
218 ;; using a predominantly lock-free design, and other nice things.
219 (defmacro atomic-set-info-value
(category kind name lambda
)
220 (with-unique-names (info-number proc
)
222 ,(if (and (keywordp category
) (keywordp kind
))
223 (meta-info-number (meta-info category kind
))
224 `(meta-info-number (meta-info ,category
,kind
)))))
225 ,(if (and (listp lambda
) (eq (car lambda
) 'lambda
))
226 ;; rewrite as FLET because the compiler is unable to dxify
227 ;; (DX-LET ((x (LAMBDA <whatever>))) (F x))
228 (destructuring-bind (lambda-list . body
) (cdr lambda
)
229 `(dx-flet ((,proc
,lambda-list
,@body
))
230 (%atomic-set-info-value
,name
,info-number
#',proc
)))
231 `(%atomic-set-info-value
,name
,info-number
,lambda
)))))
233 ;; Perform the approximate equivalent operations of retrieving
234 ;; (INFO :CATEGORY :KIND NAME), but if no info is found, invoke CREATION-FORM
235 ;; to produce an object that becomes the value for that piece of info, storing
236 ;; and returning it. The entire sequence behaves atomically but with a proviso:
237 ;; the creation form's result may be discarded, and another object returned
238 ;; instead (presumably) from another thread's execution of the creation form.
239 ;; If constructing the object has either non-trivial cost, or deleterious
240 ;; side-effects from making and discarding its result, do NOT use this macro.
241 ;; A mutex-guarded table would probably be more appropriate in such cases.
243 (defmacro get-info-value-initializing
(category kind name creation-form
)
244 (let ((proc (make-symbol "THUNK")))
245 `(dx-flet ((,proc
() ,creation-form
))
246 (%get-info-value-initializing
247 ,(if (and (keywordp category
) (keywordp kind
))
248 (meta-info-number (meta-info category kind
))
249 `(meta-info-number (meta-info ,category
,kind
)))
252 ;;;; boolean attribute utilities
254 ;;;; We need to maintain various sets of boolean attributes for known
255 ;;;; functions and VOPs. To save space and allow for quick set
256 ;;;; operations, we represent the attributes as bits in a fixnum.
258 (deftype attributes
() 'fixnum
)
260 ;;; Given a list of attribute names and an alist that translates them
261 ;;; to masks, return the OR of the masks.
262 (defun encode-attribute-mask (names universe
)
263 (loop for name in names
264 for pos
= (position name universe
)
265 sum
(if pos
(ash 1 pos
) (error "unknown attribute name: ~S" name
))))
267 (defun decode-attribute-mask (bits universe
)
268 (loop for name across universe
269 for mask
= 1 then
(ash mask
1)
270 when
(logtest mask bits
) collect name
))
272 ;;; Define a new class of boolean attributes, with the attributes
273 ;;; having the specified ATTRIBUTE-NAMES. NAME is the name of the
274 ;;; class, which is used to generate some macros to manipulate sets of
277 ;;; NAME-attributep attributes attribute-name*
278 ;;; Return true if one of the named attributes is present, false
279 ;;; otherwise. When set with SETF, updates the place Attributes
280 ;;; setting or clearing the specified attributes.
282 ;;; NAME-attributes attribute-name*
283 ;;; Return a set of the named attributes.
284 (defmacro !def-boolean-attribute
(name &rest attribute-names
)
285 (let ((vector (coerce attribute-names
'vector
))
286 (constructor (symbolicate name
"-ATTRIBUTES"))
287 (test-name (symbolicate name
"-ATTRIBUTEP")))
289 (defmacro ,constructor
(&rest attribute-names
)
290 "Automagically generated boolean attribute creation function.
291 See !DEF-BOOLEAN-ATTRIBUTE."
292 (encode-attribute-mask attribute-names
,vector
))
293 (defun ,(symbolicate "DECODE-" name
"-ATTRIBUTES") (attributes)
294 (decode-attribute-mask attributes
,vector
))
295 (defmacro ,test-name
(attributes &rest attribute-names
)
296 "Automagically generated boolean attribute test function.
297 See !DEF-BOOLEAN-ATTRIBUTE."
298 `(logtest (the attributes
,attributes
)
299 (,',constructor
,@attribute-names
)))
300 (define-setf-expander ,test-name
(place &rest attributes
302 "Automagically generated boolean attribute setter. See
303 !DEF-BOOLEAN-ATTRIBUTE."
304 (multiple-value-bind (temps values stores setter getter
)
305 (#+sb-xc-host get-setf-expansion
306 #-sb-xc-host sb
!xc
:get-setf-expansion place env
)
308 (error "multiple store variables for ~S" place
))
309 (let ((newval (sb!xc
:gensym
))
310 (n-place (sb!xc
:gensym
))
311 (mask (encode-attribute-mask attributes
,vector
)))
312 (values `(,@temps
,n-place
)
315 `(let ((,(first stores
)
317 (logior ,n-place
,mask
)
318 (logandc2 ,n-place
,mask
))))
321 `(,',test-name
,n-place
,@attributes
))))))))
323 ;;; And now for some gratuitous pseudo-abstraction...
326 ;;; Return the union of all the sets of boolean attributes which are its
328 ;;; ATTRIBUTES-INTERSECTION
329 ;;; Return the intersection of all the sets of boolean attributes which
330 ;;; are its arguments.
332 ;;; True if the attributes present in ATTR1 are identical to
334 (defmacro attributes-union
(&rest attributes
)
336 (logior ,@(mapcar (lambda (x) `(the attributes
,x
)) attributes
))))
337 (defmacro attributes-intersection
(&rest attributes
)
339 (logand ,@(mapcar (lambda (x) `(the attributes
,x
)) attributes
))))
340 (declaim (ftype (function (attributes attributes
) boolean
) attributes
=))
341 #!-sb-fluid
(declaim (inline attributes
=))
342 (defun attributes= (attr1 attr2
)