1 ;;;; various extensions (including SB-INT "internal extensions")
2 ;;;; available both in the cross-compilation host Lisp and in the
3 ;;;; target SBCL, but which can't be defined on the target until until
4 ;;;; some significant amount of machinery (e.g. error-handling) is
7 ;;;; This software is part of the SBCL system. See the README file for
10 ;;;; This software is derived from the CMU CL system, which was
11 ;;;; written at Carnegie Mellon University and released into the
12 ;;;; public domain. The software is in the public domain and is
13 ;;;; provided with absolutely no warranty. See the COPYING and CREDITS
14 ;;;; files for more information.
16 (in-package "SB!IMPL")
18 ;;; Is X a list for which LENGTH is meaningful, i.e. a list which is
19 ;;; not improper and which is not circular?
20 (defun list-with-length-p (x)
21 (values (ignore-errors (list-length x))))
23 ;;; not used in 0.7.8, but possibly useful for defensive programming
24 ;;; in e.g. (COERCE ... 'VECTOR)
25 ;;;(defun list-length-or-die (x)
26 ;;; (or (list-length x)
27 ;;; ;; not clear how to do this best:
28 ;;; ;; * Should this be a TYPE-ERROR? Colloquially that'd make
29 ;;; ;; lots of sense, but since I'm not sure how to express
30 ;;; ;; "noncircular list" as a Lisp type expression, coding
31 ;;; ;; it seems awkward.
32 ;;; ;; * Should the ERROR object include the offending value?
33 ;;; ;; Ordinarily that's helpful, but if the user doesn't have
34 ;;; ;; his printer set up to deal with cyclicity, we might not
35 ;;; ;; be doing him a favor by printing the object here.
36 ;;; ;; -- WHN 2002-10-19
37 ;;; (error "can't calculate length of cyclic list")))
39 ;;; This is used in constructing arg lists for debugger printing,
40 ;;; and when needing to print unbound slots in PCL.
41 (defstruct (unprintable-object
42 (:constructor make-unprintable-object (string))
43 (:print-object (lambda (x s)
44 (print-unreadable-object (x s)
45 (write-string (unprintable-object-string x) s))))
49 ;;; Used internally, but it would be nice to provide something
50 ;;; like this for users as well.
52 ;;; FIXME / IMPORTANT: If the slot is raw, the address is correct only for
53 ;;; instances of the specified class, not its subclasses!
55 (defmacro define-structure-slot-addressor (name &key structure slot)
56 (let* ((dd (find-defstruct-description structure t))
57 (slotd (when dd (find slot (dd-slots dd) :key #'dsd-name)))
58 (index (when slotd (dsd-index slotd)))
59 (raw-type (dsd-raw-type slotd)))
61 (error "Slot ~S not found in ~S." slot structure))
63 (declaim (inline ,name))
64 (defun ,name (instance)
65 (declare (type ,structure instance) (optimize speed))
68 (+ (sb!kernel:get-lisp-obj-address instance)
69 (- (* ,(if (eq t raw-type)
70 (+ sb!vm:instance-slots-offset index)
71 (- (1+ (sb!kernel::dd-instance-length dd)) sb!vm:instance-slots-offset index
72 (1- (sb!kernel::raw-slot-words raw-type))))
74 sb!vm:instance-pointer-lowtag)))))))
76 (defmacro compare-and-swap (place old new &environment env)
77 "Atomically stores NEW in PLACE if OLD matches the current value of PLACE.
78 Two values are considered to match if they are EQ. Returns the previous value
79 of PLACE: if the returned value is EQ to OLD, the swap was carried out.
81 PLACE must be an accessor form whose CAR is one of the following:
83 CAR, CDR, FIRST, REST, SYMBOL-PLIST, SYMBOL-VALUE, SVREF
85 or the name of a DEFSTRUCT created accessor for a slot whose declared type is
86 either FIXNUM or T. Results are unspecified if the slot has a declared type
87 other then FIXNUM or T.
89 EXPERIMENTAL: Interface subject to change."
90 (flet ((invalid-place ()
91 (error "Invalid first argument to COMPARE-AND-SWAP: ~S" place)))
94 ;; FIXME: Not the nicest way to do this...
95 (destructuring-bind (op &rest args) place
98 `(%compare-and-swap-car (the cons ,@args) ,old ,new))
100 `(%compare-and-swap-cdr (the cons ,@args) ,old ,new))
102 `(%compare-and-swap-symbol-plist (the symbol ,@args) ,old (the list ,new)))
104 (destructuring-bind (name) args
105 (flet ((slow (symbol)
106 (with-unique-names (n-symbol n-old n-new)
107 `(let ((,n-symbol ,symbol)
110 (declare (symbol ,n-symbol))
111 (about-to-modify-symbol-value ,n-symbol 'compare-and-swap ,n-new)
112 (%compare-and-swap-symbol-value ,n-symbol ,n-old ,n-new)))))
113 (if (sb!xc:constantp name env)
114 (let ((cname (constant-form-value name env)))
115 (if (eq :special (info :variable :kind cname))
116 ;; Since we know the symbol is a special, we can just generate
118 `(%compare-and-swap-symbol-value
119 ',cname ,old (the ,(info :variable :type cname) ,new))
120 (slow (list 'quote cname))))
123 (let ((vector (car args))
125 (unless (and vector index (not (cddr args)))
127 (with-unique-names (v)
129 (declare (simple-vector ,v))
130 (%compare-and-swap-svref ,v (%check-bound ,v (length ,v) ,index) ,old ,new)))))
132 (let ((dd (info :function :structure-accessor op)))
134 (let* ((structure (dd-name dd))
135 (slotd (find op (dd-slots dd) :key #'dsd-accessor-name))
136 (index (dsd-index slotd))
137 (type (dsd-type slotd)))
138 (unless (eq t (dsd-raw-type slotd))
139 (error "Cannot use COMPARE-AND-SWAP with structure accessor for a typed slot: ~S"
141 (when (dsd-read-only slotd)
142 (error "Cannot use COMPARE-AND-SWAP with structure accessor for a read-only slot: ~S"
144 `(truly-the (values ,type &optional)
145 (%compare-and-swap-instance-ref (the ,structure ,@args)
147 (the ,type ,old) (the ,type ,new))))
148 (error "Invalid first argument to COMPARE-AND-SWAP: ~S" place))))))))
150 (macrolet ((def (name lambda-list ref &optional set)
151 #!+compare-and-swap-vops
152 (declare (ignore ref set))
153 `(defun ,name (,@lambda-list old new)
154 #!+compare-and-swap-vops
155 (,name ,@lambda-list old new)
156 #!-compare-and-swap-vops
157 (let ((current (,ref ,@lambda-list)))
158 (when (eq current old)
160 `(,set ,@lambda-list new)
161 `(setf (,ref ,@lambda-list) new)))
163 (def %compare-and-swap-car (cons) car)
164 (def %compare-and-swap-cdr (cons) cdr)
165 (def %compare-and-swap-instance-ref (instance index) %instance-ref %instance-set)
166 (def %compare-and-swap-symbol-plist (symbol) symbol-plist)
167 (def %compare-and-swap-symbol-value (symbol) symbol-value)
168 (def %compare-and-swap-svref (vector index) svref))
170 (defun expand-atomic-frob (name place diff)
171 (flet ((invalid-place ()
172 (error "Invalid first argument to ~S: ~S" name place)))
173 (unless (consp place)
175 (destructuring-bind (op &rest args) place
178 (let ((dd (info :function :structure-accessor op)))
180 (let* ((structure (dd-name dd))
181 (slotd (find op (dd-slots dd) :key #'dsd-accessor-name))
182 (index (dsd-index slotd))
183 (type (dsd-type slotd)))
184 (declare (ignorable structure index))
185 (unless (and (eq 'sb!vm:word (dsd-raw-type slotd))
186 (type= (specifier-type type) (specifier-type 'sb!vm:word)))
187 (error "~S requires a slot of type (UNSIGNED-BYTE ~S), not ~S: ~S"
188 name sb!vm:n-word-bits type place))
189 (when (dsd-read-only slotd)
190 (error "Cannot use ~S with structure accessor for a read-only slot: ~S"
192 #!+(or x86 x86-64 ppc)
193 `(truly-the sb!vm:word
194 (%raw-instance-atomic-incf/word
195 (the ,structure ,@args) ,index
196 (logand #.(1- (ash 1 sb!vm:n-word-bits))
199 `(the sb!vm:signed-word ,diff))
201 `(- (the sb!vm:signed-word ,diff)))))))
202 ;; No threads outside x86 and x86-64 for now, so this is easy...
203 #!-(or x86 x86-64 ppc)
204 (with-unique-names (structure old)
205 `(sb!sys:without-interrupts
206 (let* ((,structure ,@args)
207 (,old (,op ,structure)))
208 (setf (,op ,structure)
209 (logand #.(1- (ash 1 sb!vm:n-word-bits))
212 `(+ ,old (the sb!vm:signed-word ,diff)))
214 `(- ,old (the sb!vm:signed-word ,diff))))))
218 (defmacro atomic-incf (place &optional (diff 1))
220 "Atomically increments PLACE by DIFF, and returns the value of PLACE before
223 The incrementation is done using word-size modular arithmetic: on 32 bit
224 platforms ATOMIC-INCF of #xFFFFFFFF by one results in #x0 being stored in
227 PLACE must be an accessor form whose CAR is the name of a DEFSTRUCT accessor
228 whose declared type is (UNSIGNED-BYTE 32) on 32 bit platforms,
229 and (UNSIGNED-BYTE 64) on 64 bit platforms.
231 DIFF defaults to 1, and must be a (SIGNED-BYTE 32) on 32 bit platforms,
232 and (SIGNED-BYTE 64) on 64 bit platforms.
234 EXPERIMENTAL: Interface subject to change."
235 (expand-atomic-frob 'atomic-incf place diff))
237 (defmacro atomic-decf (place &optional (diff 1))
239 "Atomically decrements PLACE by DIFF, and returns the value of PLACE before
242 The decrementation is done using word-size modular arithmetic: on 32 bit
243 platforms ATOMIC-DECF of #x0 by one results in #xFFFFFFFF being stored in
246 PLACE must be an accessor form whose CAR is the name of a DEFSTRUCT accessor
247 whose declared type is (UNSIGNED-BYTE 32) on 32 bit platforms,
248 and (UNSIGNED-BYTE 64) on 64 bit platforms.
250 DIFF defaults to 1, and must be a (SIGNED-BYTE 32) on 32 bit platforms,
251 and (SIGNED-BYTE 64) on 64 bit platforms.
253 EXPERIMENTAL: Interface subject to change."
254 (expand-atomic-frob 'atomic-decf place diff))
256 (defun call-hooks (kind hooks &key (on-error :error))
260 (serious-condition (c)
261 (if (eq :warn on-error)
262 (warn "Problem running ~A hook ~S:~% ~A" kind hook c)
263 (with-simple-restart (continue "Skip this ~A hook." kind)
264 (error "Problem running ~A hook ~S:~% ~A" kind hook c)))))))
268 (defmacro-mundanely defglobal (name value &optional (doc nil docp))
270 "Defines NAME as a global variable that is always bound. VALUE is evaluated
271 and assigned to NAME both at compile- and load-time, but only if NAME is not
274 Global variables share their values between all threads, and cannot be
275 locally bound, declared special, defined as constants, and neither bound
276 nor defined as symbol macros.
278 See also the declarations SB-EXT:GLOBAL and SB-EXT:ALWAYS-BOUND."
280 (eval-when (:compile-toplevel)
281 (let ((boundp (boundp ',name)))
282 (%compiler-defglobal ',name (unless boundp ,value) boundp)))
283 (eval-when (:load-toplevel :execute)
284 (let ((boundp (boundp ',name)))
285 (%defglobal ',name (unless boundp ,value) boundp ',doc ,docp
286 (sb!c:source-location))))))
288 (defun %compiler-defglobal (name value boundp)
289 (sb!xc:proclaim `(global ,name))
292 (set-symbol-global-value name value)
295 (sb!xc:proclaim `(always-bound ,name)))
297 (defun %defglobal (name value boundp doc docp source-location)
298 (%compiler-defglobal name value boundp)
300 (setf (fdocumentation name 'variable) doc))
301 (sb!c:with-source-location (source-location)
302 (setf (info :source-location :variable name) source-location))