1 ;;;; This software is part of the SBCL system. See the README file for
4 ;;;; This software is derived from software originally released by Xerox
5 ;;;; Corporation. Copyright and release statements follow. Later modifications
6 ;;;; to the software are in the public domain and are provided with
7 ;;;; absolutely no warranty. See the COPYING and CREDITS files for more
10 ;;;; copyright information from original PCL sources:
12 ;;;; Copyright (c) 1985, 1986, 1987, 1988, 1989, 1990 Xerox Corporation.
13 ;;;; All rights reserved.
15 ;;;; Use and copying of this software and preparation of derivative works based
16 ;;;; upon this software are permitted. Any distribution of this software or
17 ;;;; derivative works must comply with all applicable United States export
20 ;;;; This software is made available AS IS, and Xerox Corporation makes no
21 ;;;; warranty about the software, its performance or its conformity to any
26 ;;; This file is (almost) functionally equivalent to dlap.lisp, but
29 ;;; Might generate faster code, too, depending on the compiler and
30 ;;; whether an implementation-specific lap assembler was used.
32 (defun emit-one-class-reader (class-slot-p)
33 (emit-reader/writer
:reader
1 class-slot-p
))
35 (defun emit-one-class-boundp (class-slot-p)
36 (emit-reader/writer
:boundp
1 class-slot-p
))
38 (defun emit-one-class-writer (class-slot-p)
39 (emit-reader/writer
:writer
1 class-slot-p
))
41 (defun emit-two-class-reader (class-slot-p)
42 (emit-reader/writer
:reader
2 class-slot-p
))
44 (defun emit-two-class-boundp (class-slot-p)
45 (emit-reader/writer
:boundp
2 class-slot-p
))
47 (defun emit-two-class-writer (class-slot-p)
48 (emit-reader/writer
:writer
2 class-slot-p
))
50 ;;; --------------------------------
52 (defun emit-one-index-readers (class-slot-p)
53 (emit-one-or-n-index-reader/writer
:reader nil class-slot-p
))
55 (defun emit-one-index-boundps (class-slot-p)
56 (emit-one-or-n-index-reader/writer
:boundp nil class-slot-p
))
58 (defun emit-one-index-writers (class-slot-p)
59 (emit-one-or-n-index-reader/writer
:writer nil class-slot-p
))
61 (defun emit-n-n-readers ()
62 (emit-one-or-n-index-reader/writer
:reader t nil
))
64 (defun emit-n-n-boundps ()
65 (emit-one-or-n-index-reader/writer
:boundp t nil
))
67 (defun emit-n-n-writers ()
68 (emit-one-or-n-index-reader/writer
:writer t nil
))
70 ;;; --------------------------------
72 (defun emit-checking (metatypes applyp
)
73 (emit-checking-or-caching nil nil metatypes applyp
))
75 (defun emit-caching (metatypes applyp
)
76 (emit-checking-or-caching t nil metatypes applyp
))
78 (defun emit-in-checking-cache-p (metatypes)
79 (emit-checking-or-caching nil t metatypes nil
))
81 (defun emit-constant-value (metatypes)
82 (emit-checking-or-caching t t metatypes nil
))
84 ;;; --------------------------------
86 ;;; FIXME: What do these variables mean?
87 (defvar *precompiling-lap
* nil
)
88 (defvar *emit-function-p
* t
)
90 ;;; FIXME: This variable is motivated by Gerd Moellman's observation,
91 ;;; in <867kga1wra.fsf@gerd.free-bsd.org> on cmucl-imp 2002-10-22,
92 ;;; that the functions returned from EMIT-xxx-FUNCTION can cause an
93 ;;; order-of-magnitude slowdown. We include this variable for now,
94 ;;; but maybe its effect should rather be controlled by compilation
95 ;;; policy if there is a noticeable space difference between the
96 ;;; branches, or else maybe the EMIT-xxx-FUNCTION branches should be
97 ;;; deleted. It's not clear to me how all of this works, though, so
98 ;;; until proper benchmarks are done it's probably safest simply to
99 ;;; have this pseudo-constant to hide code. -- CSR, 2003-02-14
100 (defvar *optimize-cache-functions-p
* t
)
102 (defun emit-default-only (metatypes applyp
)
103 (unless *optimize-cache-functions-p
*
104 (when (and (null *precompiling-lap
*) *emit-function-p
*)
105 (return-from emit-default-only
106 (emit-default-only-function metatypes applyp
))))
107 (multiple-value-bind (lambda-list args rest-arg more-arg
)
108 (make-dlap-lambda-list metatypes applyp
)
109 (generating-lisp '(emf)
111 `(invoke-effective-method-function emf
115 :rest-arg
,rest-arg
))))
117 ;;; --------------------------------
119 (defun generating-lisp (closure-variables args form
)
120 (let ((lambda `(lambda ,closure-variables
121 ,@(when (member 'miss-fn closure-variables
)
122 `((declare (type function miss-fn
))))
125 (declare #.
*optimize-speed
*)
127 (values (if *precompiling-lap
*
129 (compile nil lambda
))
132 ;;; note on implementation for CMU 17 and later (including SBCL):
133 ;;; Since STD-INSTANCE-P is weakened, that branch may run on non-PCL
134 ;;; instances (structures). The result will be the non-wrapper layout
135 ;;; for the structure, which will cause a miss. The "slots" will be
136 ;;; whatever the first slot is, but will be ignored. Similarly,
137 ;;; FSC-INSTANCE-P returns true on funcallable structures as well as
139 (defun emit-reader/writer
(reader/writer
1-or-2-class class-slot-p
)
140 (unless *optimize-cache-functions-p
*
141 (when (and (null *precompiling-lap
*) *emit-function-p
*)
142 (return-from emit-reader
/writer
143 (emit-reader/writer-function
144 reader
/writer
1-or-2-class class-slot-p
))))
147 (closure-variables ())
148 (field +first-wrapper-cache-number-index
+)
149 (read-form (emit-slot-read-form class-slot-p
'index
'slots
)))
150 ;;we need some field to do the fast obsolete check
153 (setq instance
(dfun-arg-symbol 0)
154 arglist
(list instance
)))
155 (:writer
(setq instance
(dfun-arg-symbol 1)
156 arglist
(list (dfun-arg-symbol 0) instance
))))
158 (1 (setq closure-variables
'(wrapper-0 index miss-fn
)))
159 (2 (setq closure-variables
'(wrapper-0 wrapper-1 index miss-fn
))))
163 `(let* (,@(unless class-slot-p
`((slots nil
)))
164 (wrapper (cond ((std-instance-p ,instance
)
165 ,@(unless class-slot-p
167 (std-instance-slots ,instance
))))
168 (std-instance-wrapper ,instance
))
169 ((fsc-instance-p ,instance
)
170 ,@(unless class-slot-p
172 (fsc-instance-slots ,instance
))))
173 (fsc-instance-wrapper ,instance
)))))
176 (/= (wrapper-cache-number-vector-ref wrapper
,field
) 0)
177 ,@(if (eql 1 1-or-2-class
)
178 `((eq wrapper wrapper-0
))
179 `((or (eq wrapper wrapper-0
)
180 (eq wrapper wrapper-1
)))))
181 ,@(ecase reader
/writer
183 `((let ((value ,read-form
))
184 (unless (eq value
+slot-unbound
+)
185 (return-from access value
)))))
187 `((let ((value ,read-form
))
188 (return-from access
(not (eq value
+slot-unbound
+))))))
190 `((return-from access
(setf ,read-form
,(car arglist
)))))))
191 (funcall miss-fn
,@arglist
))))))
193 (defun emit-slot-read-form (class-slot-p index slots
)
196 `(clos-slots-ref ,slots
,index
)))
198 (defun emit-boundp-check (value-form miss-fn arglist
)
199 `(let ((value ,value-form
))
200 (if (eq value
+slot-unbound
+)
201 (funcall ,miss-fn
,@arglist
)
204 (defun emit-slot-access (reader/writer class-slot-p slots
205 index miss-fn arglist
)
206 (let ((read-form (emit-slot-read-form class-slot-p index slots
)))
208 (:reader
(emit-boundp-check read-form miss-fn arglist
))
209 (:boundp
`(not (eq ,read-form
+slot-unbound
+)))
210 (:writer
`(setf ,read-form
,(car arglist
))))))
212 (defmacro emit-reader
/writer-macro
(reader/writer
1-or-2-class class-slot-p
)
213 (let ((*emit-function-p
* nil
)
214 (*precompiling-lap
* t
))
216 (emit-reader/writer reader
/writer
1-or-2-class class-slot-p
))))
218 (defun emit-one-or-n-index-reader/writer
(reader/writer
221 (unless *optimize-cache-functions-p
*
222 (when (and (null *precompiling-lap
*) *emit-function-p
*)
223 (return-from emit-one-or-n-index-reader
/writer
224 (emit-one-or-n-index-reader/writer-function
225 reader
/writer cached-index-p class-slot-p
))))
226 (multiple-value-bind (arglist metatypes
)
229 (values (list (dfun-arg-symbol 0))
230 '(standard-instance)))
231 (:writer
(values (list (dfun-arg-symbol 0) (dfun-arg-symbol 1))
232 '(t standard-instance
))))
234 `(cache ,@(unless cached-index-p
'(index)) miss-fn
)
236 `(let (,@(unless class-slot-p
'(slots))
237 ,@(when cached-index-p
'(index)))
238 ,(emit-dlap arglist metatypes
239 (emit-slot-access reader
/writer class-slot-p
240 'slots
'index
'miss-fn arglist
)
241 `(funcall miss-fn
,@arglist
)
242 (when cached-index-p
'index
)
243 (unless class-slot-p
'(slots)))))))
245 (defmacro emit-one-or-n-index-reader
/writer-macro
246 (reader/writer cached-index-p class-slot-p
)
247 (let ((*emit-function-p
* nil
)
248 (*precompiling-lap
* t
))
250 (emit-one-or-n-index-reader/writer reader
/writer
254 (defun emit-miss (miss-fn args applyp
)
256 `(multiple-value-call ,miss-fn
,@args
257 (sb-c::%more-arg-values .more-context.
260 `(funcall ,miss-fn
,@args
)))
262 (defun emit-checking-or-caching (cached-emf-p return-value-p metatypes applyp
)
263 (unless *optimize-cache-functions-p
*
264 (when (and (null *precompiling-lap
*) *emit-function-p
*)
265 (return-from emit-checking-or-caching
266 (emit-checking-or-caching-function
267 cached-emf-p return-value-p metatypes applyp
))))
268 (multiple-value-bind (lambda-list args rest-arg more-arg
)
269 (make-dlap-lambda-list metatypes applyp
)
271 `(cache ,@(unless cached-emf-p
'(emf)) miss-fn
)
273 `(let (,@(when cached-emf-p
'(emf)))
277 (if cached-emf-p
'emf t
)
278 `(invoke-effective-method-function
282 :rest-arg
,rest-arg
))
283 (emit-miss 'miss-fn args applyp
)
284 (when cached-emf-p
'emf
))))))
286 (defmacro emit-checking-or-caching-macro
(cached-emf-p
290 (let ((*emit-function-p
* nil
)
291 (*precompiling-lap
* t
))
293 (emit-checking-or-caching cached-emf-p return-value-p metatypes applyp
))))
295 (defun emit-dlap (args metatypes hit miss value-reg
&optional slot-regs
)
297 (wrapper-bindings (mapcan (lambda (arg mt
)
300 `((,(format-symbol *pcl-package
*
304 mt arg
'miss
(pop slot-regs
))))))
306 (wrappers (mapcar #'car wrapper-bindings
)))
307 (declare (fixnum index
))
308 (unless wrappers
(error "Every metatype is T."))
311 (let ((field (cache-field cache
))
312 (cache-vector (cache-vector cache
))
313 (mask (cache-mask cache
))
314 (size (cache-size cache
))
315 (overflow (cache-overflow cache
))
317 (declare (fixnum size field mask
))
318 ,(cond ((cdr wrappers
)
319 (emit-greater-than-1-dlap wrappers
'miss value-reg
))
321 (emit-1-t-dlap (car wrappers
) 'miss value-reg
))
323 (emit-1-nil-dlap (car wrappers
) 'miss
)))
324 (return-from dfun
,hit
))
326 (return-from dfun
,miss
)))))
328 (defun emit-1-nil-dlap (wrapper miss-label
)
329 `(let* ((primary ,(emit-1-wrapper-compute-primary-cache-location wrapper
332 (declare (fixnum primary location
))
334 (loop (when (eq ,wrapper
(cache-vector-ref cache-vector location
))
335 (return-from search nil
))
336 (setq location
(the fixnum
(+ location
1)))
337 (when (= location size
)
339 (when (= location primary
)
340 (dolist (entry overflow
)
341 (when (eq (car entry
) ,wrapper
)
342 (return-from search nil
)))
343 (go ,miss-label
))))))
345 (defmacro get-cache-vector-lock-count
(cache-vector)
346 `(let ((lock-count (cache-vector-lock-count ,cache-vector
)))
347 (unless (typep lock-count
'fixnum
)
348 (error "My cache got freed somehow."))
349 (the fixnum lock-count
)))
351 (defun emit-1-t-dlap (wrapper miss-label value
)
352 `(let ((primary ,(emit-1-wrapper-compute-primary-cache-location wrapper
354 (initial-lock-count (get-cache-vector-lock-count cache-vector
)))
355 (declare (fixnum primary initial-lock-count
))
356 (let ((location primary
))
357 (declare (fixnum location
))
359 (loop (when (eq ,wrapper
(cache-vector-ref cache-vector location
))
360 (setq ,value
(cache-vector-ref cache-vector
(1+ location
)))
361 (return-from search nil
))
362 (setq location
(the fixnum
(+ location
2)))
363 (when (= location size
)
365 (when (= location primary
)
366 (dolist (entry overflow
)
367 (when (eq (car entry
) ,wrapper
)
368 (setq ,value
(cdr entry
))
369 (return-from search nil
)))
371 (unless (= initial-lock-count
372 (get-cache-vector-lock-count cache-vector
))
375 (defun emit-greater-than-1-dlap (wrappers miss-label value
)
376 (declare (type list wrappers
))
377 (let ((cache-line-size (compute-line-size (+ (length wrappers
)
380 (size-1 (the fixnum
(- size
1))))
381 (declare (fixnum primary size-1
))
382 ,(emit-n-wrapper-compute-primary-cache-location wrappers miss-label
)
383 (let ((initial-lock-count (get-cache-vector-lock-count cache-vector
)))
384 (declare (fixnum initial-lock-count
))
385 (let ((location primary
)
387 (declare (fixnum location next-location
))
389 (loop (setq next-location
390 (the fixnum
(+ location
,cache-line-size
)))
397 (the fixnum
(+ location
1))))))
400 `((setq location
(the fixnum
(+ location
1)))
401 (setq ,value
(cache-vector-ref cache-vector
403 (return-from search nil
))
404 (setq location next-location
)
405 (when (= location size-1
)
407 (when (= location primary
)
408 (dolist (entry overflow
)
409 (let ((entry-wrappers (car entry
)))
410 (when (and ,@(mapcar (lambda (wrapper)
412 (pop entry-wrappers
)))
415 `((setq ,value
(cdr entry
))))
416 (return-from search nil
))))
418 (unless (= initial-lock-count
419 (get-cache-vector-lock-count cache-vector
))
420 (go ,miss-label
)))))))
422 (defun emit-1-wrapper-compute-primary-cache-location (wrapper miss-label
)
423 `(let ((wrapper-cache-no (wrapper-cache-number-vector-ref ,wrapper field
)))
424 (declare (fixnum wrapper-cache-no
))
425 (when (zerop wrapper-cache-no
) (go ,miss-label
))
426 ,(let ((form `(logand mask wrapper-cache-no
)))
427 `(the fixnum
,form
))))
429 (defun emit-n-wrapper-compute-primary-cache-location (wrappers miss-label
)
430 (declare (type list wrappers
))
431 ;; This returns 1 less that the actual location.
433 ,@(let ((adds 0) (len (length wrappers
)))
434 (declare (fixnum adds len
))
435 (mapcar (lambda (wrapper)
436 `(let ((wrapper-cache-no (wrapper-cache-number-vector-ref
438 (declare (fixnum wrapper-cache-no
))
439 (when (zerop wrapper-cache-no
) (go ,miss-label
))
440 (setq primary
(the fixnum
(+ primary wrapper-cache-no
)))
443 (when (or (zerop (mod adds
444 wrapper-cache-number-adds-ok
))
447 ,(let ((form `(logand primary mask
)))
448 `(the fixnum
,form
))))))))
451 ;;; CMU17 (and SBCL) note: Since STD-INSTANCE-P is weakened in the
452 ;;; CMU/SBCL approach of using funcallable instances, that branch may
453 ;;; run on non-pcl instances (structures). The result will be the
454 ;;; non-wrapper layout for the structure, which will cause a miss. The
455 ;;; "slots" will be whatever the first slot is, but will be ignored.
456 ;;; Similarly, FSC-INSTANCE-P returns true on funcallable structures
457 ;;; as well as PCL fins.
458 (defun emit-fetch-wrapper (metatype argument miss-label
&optional slot
)
461 `(cond ((std-instance-p ,argument
)
462 ,@(when slot
`((setq ,slot
(std-instance-slots ,argument
))))
463 (std-instance-wrapper ,argument
))
464 ((fsc-instance-p ,argument
)
465 ,@(when slot
`((setq ,slot
(fsc-instance-slots ,argument
))))
466 (fsc-instance-wrapper ,argument
))
470 (when slot
(error "can't do a slot reg for this metatype"))
471 `(wrapper-of ,argument
))
472 ((built-in-instance structure-instance
)
473 (when slot
(error "can't do a slot reg for this metatype"))
474 `(built-in-or-structure-wrapper