1 ;;;; heap-grovelling memory usage stuff
3 ;;;; This software is part of the SBCL system. See the README file for
6 ;;;; This software is derived from the CMU CL system, which was
7 ;;;; written at Carnegie Mellon University and released into the
8 ;;;; public domain. The software is in the public domain and is
9 ;;;; provided with absolutely no warranty. See the COPYING and CREDITS
10 ;;;; files for more information.
14 ;;;; type format database
16 (eval-when (:compile-toplevel :load-toplevel :execute)
17 (def!struct (room-info (:make-load-form-fun just-dump-it-normally))
18 ;; the name of this type
19 (name nil :type symbol)
20 ;; kind of type (how we determine length)
22 :type (member :lowtag :fixed :header :vector
23 :string :code :closure :instance))
24 ;; length if fixed-length, shift amount for element size if :VECTOR
25 (length nil :type (or fixnum null))))
27 (eval-when (:compile-toplevel :execute)
29 (defvar *meta-room-info* (make-array 256 :initial-element nil))
31 (dolist (obj *primitive-objects*)
32 (let ((widetag (primitive-object-widetag obj))
33 (lowtag (primitive-object-lowtag obj))
34 (name (primitive-object-name obj))
35 (variable (primitive-object-variable-length-p obj))
36 (size (primitive-object-size obj)))
39 (;; KLUDGE described in dan_b message "Another one for the
40 ;; collection [bug 108]" (sbcl-devel 2004-01-22)
42 ;; In a freshly started SBCL 0.8.7.20ish, (TIME (ROOM T)) causes
43 ;; debugger invoked on a SB-INT:BUG in thread 5911:
44 ;; failed AVER: "(SAP= CURRENT END)"
45 ;; [WHN: Similar things happened on one but not the other of my
46 ;; machines when I just run ROOM a lot in a loop.]
48 ;; This appears to be due to my [DB] abuse of the primitive
49 ;; object macros to define a thread object that shares a lowtag
50 ;; with fixnums and has no widetag: it looks like the code that
51 ;; generates *META-ROOM-INFO* infers from this that even fixnums
52 ;; are thread-sized - probably undesirable.
54 ;; This [the fix; the EQL NAME 'THREAD clause here] is more in the
55 ;; nature of a workaround than a really good fix. I'm not sure
56 ;; what a really good fix is: I /think/ it's probably to remove
57 ;; the :LOWTAG option in DEFINE-PRIMITIVE-OBJECT THREAD, then teach
58 ;; genesis to generate the necessary OBJECT_SLOT_OFFSET macros
59 ;; for assembly source in the runtime/genesis/*.h files.
62 (let ((info (make-room-info :name name
64 (lowtag (symbol-value lowtag)))
65 (declare (fixnum lowtag))
67 (setf (svref *meta-room-info* (logior lowtag (ash i 3))) info))))
70 (setf (svref *meta-room-info* (symbol-value widetag))
71 (make-room-info :name name
75 (dolist (code (list #!+sb-unicode complex-character-string-widetag
76 complex-base-string-widetag simple-array-widetag
77 complex-bit-vector-widetag complex-vector-widetag
78 complex-array-widetag complex-vector-nil-widetag))
79 (setf (svref *meta-room-info* code)
80 (make-room-info :name 'array-header
83 (setf (svref *meta-room-info* bignum-widetag)
84 (make-room-info :name 'bignum
87 (setf (svref *meta-room-info* closure-header-widetag)
88 (make-room-info :name 'closure
91 (dolist (stuff '((simple-bit-vector-widetag . -3)
92 (simple-vector-widetag . 2)
93 (simple-array-unsigned-byte-2-widetag . -2)
94 (simple-array-unsigned-byte-4-widetag . -1)
95 (simple-array-unsigned-byte-7-widetag . 0)
96 (simple-array-unsigned-byte-8-widetag . 0)
97 (simple-array-unsigned-byte-15-widetag . 1)
98 (simple-array-unsigned-byte-16-widetag . 1)
99 (simple-array-unsigned-byte-31-widetag . 2)
100 (simple-array-unsigned-byte-32-widetag . 2)
101 (simple-array-unsigned-byte-60-widetag . 3)
102 (simple-array-unsigned-byte-63-widetag . 3)
103 (simple-array-unsigned-byte-64-widetag . 3)
104 (simple-array-signed-byte-8-widetag . 0)
105 (simple-array-signed-byte-16-widetag . 1)
106 (simple-array-unsigned-byte-29-widetag . 2)
107 (simple-array-signed-byte-30-widetag . 2)
108 (simple-array-signed-byte-32-widetag . 2)
109 (simple-array-signed-byte-61-widetag . 3)
110 (simple-array-signed-byte-64-widetag . 3)
111 (simple-array-single-float-widetag . 2)
112 (simple-array-double-float-widetag . 3)
113 (simple-array-complex-single-float-widetag . 3)
114 (simple-array-complex-double-float-widetag . 4)))
115 (let* ((name (car stuff))
117 (sname (string name)))
119 (setf (svref *meta-room-info* (symbol-value name))
120 (make-room-info :name (intern (subseq sname
122 (mismatch sname "-WIDETAG"
127 (setf (svref *meta-room-info* simple-base-string-widetag)
128 (make-room-info :name 'simple-base-string
133 (setf (svref *meta-room-info* simple-character-string-widetag)
134 (make-room-info :name 'simple-character-string
138 (setf (svref *meta-room-info* simple-array-nil-widetag)
139 (make-room-info :name 'simple-array-nil
143 (setf (svref *meta-room-info* code-header-widetag)
144 (make-room-info :name 'code
147 (setf (svref *meta-room-info* instance-header-widetag)
148 (make-room-info :name 'instance
153 (defparameter *room-info* '#.*meta-room-info*)
154 (deftype spaces () '(member :static :dynamic :read-only))
156 ;;;; MAP-ALLOCATED-OBJECTS
158 ;;; Since they're represented as counts of words, we should never
159 ;;; need bignums to represent these:
160 (declaim (type fixnum
161 *static-space-free-pointer*
162 *read-only-space-free-pointer*))
164 (defun space-bounds (space)
165 (declare (type spaces space))
168 (values (int-sap static-space-start)
169 (int-sap (* *static-space-free-pointer* n-word-bytes))))
171 (values (int-sap read-only-space-start)
172 (int-sap (* *read-only-space-free-pointer* n-word-bytes))))
174 (values (int-sap (current-dynamic-space-start))
175 (dynamic-space-free-pointer)))))
177 ;;; Return the total number of bytes used in SPACE.
178 (defun space-bytes (space)
179 (multiple-value-bind (start end) (space-bounds space)
180 (- (sap-int end) (sap-int start))))
182 ;;; Round SIZE (in bytes) up to the next dualword (eight byte) boundary.
183 #!-sb-fluid (declaim (inline round-to-dualword))
184 (defun round-to-dualword (size)
185 (declare (fixnum size))
186 (logand (the fixnum (+ size lowtag-mask)) (lognot lowtag-mask)))
188 ;;; Return the total size of a vector in bytes, including any pad.
189 #!-sb-fluid (declaim (inline vector-total-size))
190 (defun vector-total-size (obj info)
191 (let ((shift (room-info-length info))
192 (len (+ (length (the (simple-array * (*)) obj))
193 (ecase (room-info-kind info)
196 (declare (type (integer -3 3) shift))
198 (+ (* vector-data-offset n-word-bytes)
203 (1- (the fixnum (ash 1 (- shift)))))))
205 (ash len shift)))))))
207 ;;; Access to the GENCGC page table for better precision in
208 ;;; MAP-ALLOCATED-OBJECTS
211 (define-alien-type (struct page)
214 (bytes-used (unsigned 16))
217 (declaim (inline find-page-index))
218 (define-alien-routine "find_page_index" long (index long))
219 (define-alien-variable "page_table"
221 #.(truncate (- dynamic-space-end
223 sb!vm:gencgc-page-size))))
225 ;;; Iterate over all the objects allocated in SPACE, calling FUN with
226 ;;; the object, the object's type code, and the object's total size in
227 ;;; bytes, including any header and padding.
228 #!-sb-fluid (declaim (maybe-inline map-allocated-objects))
229 (defun map-allocated-objects (fun space)
230 (declare (type function fun) (type spaces space))
232 (multiple-value-bind (start end) (space-bounds space)
233 (declare (type system-area-pointer start end))
234 (declare (optimize (speed 3) (safety 0)))
235 (let ((current start)
236 #!+gencgc (skip-tests-until-addr 0))
237 (labels ((maybe-finish-mapping ()
238 (unless (sap< current end)
239 (aver (sap= current end))
240 (return-from map-allocated-objects)))
241 ;; GENCGC doesn't allocate linearly, which means that the
242 ;; dynamic space can contain large blocks zeros that get
243 ;; accounted as conses in ROOM (and slow down other
244 ;; applications of MAP-ALLOCATED-OBJECTS). To fix this
245 ;; check the GC page structure for the current address.
246 ;; If the page is free or the address is beyond the page-
247 ;; internal allocation offset (bytes-used) skip to the
248 ;; next page immediately.
251 (when (eq space :dynamic)
252 (loop with page-mask = #.(1- sb!vm:gencgc-page-size)
253 for addr of-type sb!vm:word = (sap-int current)
254 while (>= addr skip-tests-until-addr)
256 ;; For some reason binding PAGE with LET
257 ;; conses like mad (but gives no compiler notes...)
258 ;; Work around the problem with SYMBOL-MACROLET
259 ;; instead of trying to figure out the real
260 ;; issue. -- JES, 2005-05-17
262 ((page (deref page-table
263 (find-page-index addr))))
264 ;; Don't we have any nicer way to access C struct
266 (let ((alloc-flag (ldb (byte 3 2)
268 (bytes-used (slot page 'bytes-used)))
269 ;; If the page is not free and the current
270 ;; pointer is still below the allocation offset
272 (when (and (not (zerop alloc-flag))
273 (<= (logand page-mask addr)
275 ;; Don't bother testing again until we
276 ;; get past that allocation offset
277 (setf skip-tests-until-addr
278 (+ (logandc2 addr page-mask)
279 (the fixnum bytes-used)))
280 ;; And then continue with the scheduled
282 (return-from maybe-skip-page))
283 ;; Move CURRENT to start of next page
284 (setf current (int-sap (+ (logandc2 addr page-mask)
285 sb!vm:gencgc-page-size)))
286 (maybe-finish-mapping)))))))
287 (declare (inline maybe-finish-mapping maybe-skip-page))
289 (maybe-finish-mapping)
291 (let* ((header (sap-ref-word current 0))
292 (header-widetag (logand header #xFF))
293 (info (svref *room-info* header-widetag)))
296 (eq (room-info-kind info) :lowtag))
297 (let ((size (* cons-size n-word-bytes)))
299 (make-lisp-obj (logior (sap-int current)
300 list-pointer-lowtag))
303 (setq current (sap+ current size))))
304 ((eql header-widetag closure-header-widetag)
305 (let* ((obj (make-lisp-obj (logior (sap-int current)
306 fun-pointer-lowtag)))
307 (size (round-to-dualword
308 (* (the fixnum (1+ (get-closure-length obj)))
310 (funcall fun obj header-widetag size)
311 (setq current (sap+ current size))))
312 ((eq (room-info-kind info) :instance)
313 (let* ((obj (make-lisp-obj
314 (logior (sap-int current) instance-pointer-lowtag)))
315 (size (round-to-dualword
316 (* (+ (%instance-length obj) 1) n-word-bytes))))
317 (declare (fixnum size))
318 (funcall fun obj header-widetag size)
319 (aver (zerop (logand size lowtag-mask)))
320 (setq current (sap+ current size))))
322 (let* ((obj (make-lisp-obj
323 (logior (sap-int current) other-pointer-lowtag)))
324 (size (ecase (room-info-kind info)
326 (aver (or (eql (room-info-length info)
327 (1+ (get-header-data obj)))
329 (simple-array-nil-p obj)))
331 (* (room-info-length info) n-word-bytes)))
333 (vector-total-size obj info))
336 (* (1+ (get-header-data obj)) n-word-bytes)))
339 (* (get-header-data obj) n-word-bytes))
341 (* (the fixnum (%code-code-size obj))
343 (declare (fixnum size))
344 (funcall fun obj header-widetag size)
345 (aver (zerop (logand size lowtag-mask)))
346 (setq current (sap+ current size))))))))))))
351 ;;; Return a list of 3-lists (bytes object type-name) for the objects
352 ;;; allocated in Space.
353 (defun type-breakdown (space)
354 (let ((sizes (make-array 256 :initial-element 0 :element-type 'fixnum))
355 (counts (make-array 256 :initial-element 0 :element-type 'fixnum)))
356 (map-allocated-objects
357 (lambda (obj type size)
358 (declare (fixnum size) (optimize (speed 3) (safety 0)) (ignore obj))
359 (incf (aref sizes type) size)
360 (incf (aref counts type)))
363 (let ((totals (make-hash-table :test 'eq)))
365 (let ((total-count (aref counts i)))
366 (unless (zerop total-count)
367 (let* ((total-size (aref sizes i))
368 (name (room-info-name (aref *room-info* i)))
369 (found (gethash name totals)))
371 (incf (first found) total-size)
372 (incf (second found) total-count))
374 (setf (gethash name totals)
375 (list total-size total-count name))))))))
377 (collect ((totals-list))
378 (maphash (lambda (k v)
382 (sort (totals-list) #'> :key #'first)))))
384 ;;; Handle the summary printing for MEMORY-USAGE. Totals is a list of lists
385 ;;; (space-name . totals-for-space), where totals-for-space is the list
386 ;;; returned by TYPE-BREAKDOWN.
387 (defun print-summary (spaces totals)
388 (let ((summary (make-hash-table :test 'eq)))
389 (dolist (space-total totals)
390 (dolist (total (cdr space-total))
391 (push (cons (car space-total) total)
392 (gethash (third total) summary))))
394 (collect ((summary-totals))
395 (maphash (lambda (k v)
398 (declare (fixnum sum))
399 (dolist (space-total v)
400 (incf sum (first (cdr space-total))))
401 (summary-totals (cons sum v))))
404 (format t "~2&Summary of spaces: ~(~{~A ~}~)~%" spaces)
405 (let ((summary-total-bytes 0)
406 (summary-total-objects 0))
407 (declare (fixnum summary-total-bytes summary-total-objects))
408 (dolist (space-totals
409 (mapcar #'cdr (sort (summary-totals) #'> :key #'car)))
410 (let ((total-objects 0)
413 (declare (fixnum total-objects total-bytes))
415 (dolist (space-total space-totals)
416 (let ((total (cdr space-total)))
417 (setq name (third total))
418 (incf total-bytes (first total))
419 (incf total-objects (second total))
420 (spaces (cons (car space-total) (first total)))))
421 (format t "~%~A:~% ~:D bytes, ~:D object~:P"
422 name total-bytes total-objects)
423 (dolist (space (spaces))
424 (format t ", ~W% ~(~A~)"
425 (round (* (cdr space) 100) total-bytes)
428 (incf summary-total-bytes total-bytes)
429 (incf summary-total-objects total-objects))))
430 (format t "~%Summary total:~% ~:D bytes, ~:D objects.~%"
431 summary-total-bytes summary-total-objects)))))
433 ;;; Report object usage for a single space.
434 (defun report-space-total (space-total cutoff)
435 (declare (list space-total) (type (or single-float null) cutoff))
436 (format t "~2&Breakdown for ~(~A~) space:~%" (car space-total))
437 (let* ((types (cdr space-total))
438 (total-bytes (reduce #'+ (mapcar #'first types)))
439 (total-objects (reduce #'+ (mapcar #'second types)))
440 (cutoff-point (if cutoff
441 (truncate (* (float total-bytes) cutoff))
444 (reported-objects 0))
445 (declare (fixnum total-objects total-bytes cutoff-point reported-objects
447 (loop for (bytes objects name) in types do
448 (when (<= bytes cutoff-point)
449 (format t " ~10:D bytes for ~9:D other object~2:*~P.~%"
450 (- total-bytes reported-bytes)
451 (- total-objects reported-objects))
453 (incf reported-bytes bytes)
454 (incf reported-objects objects)
455 (format t " ~10:D bytes for ~9:D ~(~A~) object~2:*~P.~%"
457 (format t " ~10:D bytes for ~9:D ~(~A~) object~2:*~P (space total.)~%"
458 total-bytes total-objects (car space-total))))
460 ;;; Print information about the heap memory in use. PRINT-SPACES is a
461 ;;; list of the spaces to print detailed information for.
462 ;;; COUNT-SPACES is a list of the spaces to scan. For either one, T
463 ;;; means all spaces (i.e. :STATIC, :DYNAMIC and :READ-ONLY.) If
464 ;;; PRINT-SUMMARY is true, then summary information will be printed.
465 ;;; The defaults print only summary information for dynamic space. If
466 ;;; true, CUTOFF is a fraction of the usage in a report below which
467 ;;; types will be combined as OTHER.
468 (defun memory-usage (&key print-spaces (count-spaces '(:dynamic))
469 (print-summary t) cutoff)
470 (declare (type (or single-float null) cutoff))
471 (let* ((spaces (if (eq count-spaces t)
472 '(:static :dynamic :read-only)
474 (totals (mapcar (lambda (space)
475 (cons space (type-breakdown space)))
478 (dolist (space-total totals)
479 (when (or (eq print-spaces t)
480 (member (car space-total) print-spaces))
481 (report-space-total space-total cutoff)))
483 (when print-summary (print-summary spaces totals)))
487 ;;; Print info about how much code and no-ops there are in SPACE.
488 (defun count-no-ops (space)
489 (declare (type spaces space))
493 (declare (fixnum code-words no-ops)
494 (type unsigned-byte total-bytes))
495 (map-allocated-objects
496 (lambda (obj type size)
497 (declare (fixnum size) (optimize (safety 0)))
498 (when (eql type code-header-widetag)
499 (incf total-bytes size)
500 (let ((words (truly-the fixnum (%code-code-size obj)))
501 (sap (truly-the system-area-pointer
502 (%primitive code-instructions obj))))
503 (incf code-words words)
505 (when (zerop (sap-ref-word sap (* i n-word-bytes)))
510 "~:D code-object bytes, ~:D code words, with ~:D no-ops (~D%).~%"
511 total-bytes code-words no-ops
512 (round (* no-ops 100) code-words)))
516 (defun descriptor-vs-non-descriptor-storage (&rest spaces)
517 (let ((descriptor-words 0)
518 (non-descriptor-headers 0)
519 (non-descriptor-bytes 0))
520 (declare (type unsigned-byte descriptor-words non-descriptor-headers
521 non-descriptor-bytes))
522 (dolist (space (or spaces '(:read-only :static :dynamic)))
523 (declare (inline map-allocated-objects))
524 (map-allocated-objects
525 (lambda (obj type size)
526 (declare (fixnum size) (optimize (safety 0)))
528 (#.code-header-widetag
529 (let ((inst-words (truly-the fixnum (%code-code-size obj))))
530 (declare (type fixnum inst-words))
531 (incf non-descriptor-bytes (* inst-words n-word-bytes))
532 (incf descriptor-words
533 (- (truncate size n-word-bytes) inst-words))))
535 #.single-float-widetag
536 #.double-float-widetag
537 #.simple-base-string-widetag
538 #!+sb-unicode #.simple-character-string-widetag
539 #.simple-array-nil-widetag
540 #.simple-bit-vector-widetag
541 #.simple-array-unsigned-byte-2-widetag
542 #.simple-array-unsigned-byte-4-widetag
543 #.simple-array-unsigned-byte-8-widetag
544 #.simple-array-unsigned-byte-16-widetag
545 #.simple-array-unsigned-byte-32-widetag
546 #.simple-array-signed-byte-8-widetag
547 #.simple-array-signed-byte-16-widetag
548 ; #.simple-array-signed-byte-30-widetag
549 #.simple-array-signed-byte-32-widetag
550 #.simple-array-single-float-widetag
551 #.simple-array-double-float-widetag
552 #.simple-array-complex-single-float-widetag
553 #.simple-array-complex-double-float-widetag)
554 (incf non-descriptor-headers)
555 (incf non-descriptor-bytes (- size n-word-bytes)))
556 ((#.list-pointer-lowtag
557 #.instance-pointer-lowtag
560 #.simple-array-widetag
561 #.simple-vector-widetag
562 #.complex-base-string-widetag
563 #.complex-vector-nil-widetag
564 #.complex-bit-vector-widetag
565 #.complex-vector-widetag
566 #.complex-array-widetag
567 #.closure-header-widetag
568 #.funcallable-instance-header-widetag
569 #.value-cell-header-widetag
570 #.symbol-header-widetag
572 #.weak-pointer-widetag
573 #.instance-header-widetag)
574 (incf descriptor-words (truncate size n-word-bytes)))
576 (error "bogus widetag: ~W" type))))
578 (format t "~:D words allocated for descriptor objects.~%"
580 (format t "~:D bytes data/~:D words header for non-descriptor objects.~%"
581 non-descriptor-bytes non-descriptor-headers)
584 ;;; Print a breakdown by instance type of all the instances allocated
585 ;;; in SPACE. If TOP-N is true, print only information for the
586 ;;; TOP-N types with largest usage.
587 (defun instance-usage (space &key (top-n 15))
588 (declare (type spaces space) (type (or fixnum null) top-n))
589 (format t "~2&~@[Top ~W ~]~(~A~) instance types:~%" top-n space)
590 (let ((totals (make-hash-table :test 'eq))
593 (declare (fixnum total-objects total-bytes))
594 (map-allocated-objects
595 (lambda (obj type size)
596 (declare (fixnum size) (optimize (speed 3) (safety 0)))
597 (when (eql type instance-header-widetag)
599 (incf total-bytes size)
600 (let* ((classoid (layout-classoid (%instance-ref obj 0)))
601 (found (gethash classoid totals)))
603 (incf (the fixnum (car found)))
604 (incf (the fixnum (cdr found)) size))
606 (setf (gethash classoid totals) (cons 1 size)))))))
609 (collect ((totals-list))
610 (maphash (lambda (classoid what)
611 (totals-list (cons (prin1-to-string
612 (classoid-proper-name classoid))
615 (let ((sorted (sort (totals-list) #'> :key #'cddr))
618 (declare (fixnum printed-bytes printed-objects))
619 (dolist (what (if top-n
620 (subseq sorted 0 (min (length sorted) top-n))
622 (let ((bytes (cddr what))
623 (objects (cadr what)))
624 (incf printed-bytes bytes)
625 (incf printed-objects objects)
626 (format t " ~A: ~:D bytes, ~:D object~:P.~%" (car what)
629 (let ((residual-objects (- total-objects printed-objects))
630 (residual-bytes (- total-bytes printed-bytes)))
631 (unless (zerop residual-objects)
632 (format t " Other types: ~:D bytes, ~:D object~:P.~%"
633 residual-bytes residual-objects))))
635 (format t " ~:(~A~) instance total: ~:D bytes, ~:D object~:P.~%"
636 space total-bytes total-objects)))
640 ;;;; PRINT-ALLOCATED-OBJECTS
642 (defun print-allocated-objects (space &key (percent 0) (pages 5)
643 type larger smaller count
644 (stream *standard-output*))
645 (declare (type (integer 0 99) percent) (type index pages)
646 (type stream stream) (type spaces space)
647 (type (or index null) type larger smaller count))
648 (multiple-value-bind (start-sap end-sap) (space-bounds space)
649 (let* ((space-start (sap-int start-sap))
650 (space-end (sap-int end-sap))
651 (space-size (- space-end space-start))
652 (pagesize (sb!sys:get-page-size))
653 (start (+ space-start (round (* space-size percent) 100)))
654 (printed-conses (make-hash-table :test 'eq))
658 (declare (type (unsigned-byte 32) last-page start)
659 (fixnum pages-so-far count-so-far pagesize))
660 (labels ((note-conses (x)
661 (unless (or (atom x) (gethash x printed-conses))
662 (setf (gethash x printed-conses) t)
663 (note-conses (car x))
664 (note-conses (cdr x)))))
665 (map-allocated-objects
666 (lambda (obj obj-type size)
667 (declare (optimize (safety 0)))
668 (let ((addr (get-lisp-obj-address obj)))
669 (when (>= addr start)
671 (> count-so-far count)
672 (> pages-so-far pages))
673 (return-from print-allocated-objects (values)))
676 (let ((this-page (* (the (values (unsigned-byte 32) t)
677 (truncate addr pagesize))
679 (declare (type (unsigned-byte 32) this-page))
680 (when (/= this-page last-page)
681 (when (< pages-so-far pages)
682 ;; FIXME: What is this? (ERROR "Argh..")? or
683 ;; a warning? or code that can be removed
684 ;; once the system is stable? or what?
685 (format stream "~2&**** Page ~W, address ~X:~%"
687 (setq last-page this-page)
688 (incf pages-so-far))))
690 (when (and (or (not type) (eql obj-type type))
691 (or (not smaller) (<= size smaller))
692 (or (not larger) (>= size larger)))
695 (#.code-header-widetag
696 (let ((dinfo (%code-debug-info obj)))
697 (format stream "~&Code object: ~S~%"
699 (sb!c::compiled-debug-info-name dinfo)
701 (#.symbol-header-widetag
702 (format stream "~&~S~%" obj))
703 (#.list-pointer-lowtag
704 (unless (gethash obj printed-conses)
706 (let ((*print-circle* t)
709 (format stream "~&~S~%" obj))))
712 (let ((str (write-to-string obj :level 5 :length 10
714 (unless (eql type instance-header-widetag)
715 (format stream "~S: " (type-of obj)))
716 (format stream "~A~%"
717 (subseq str 0 (min (length str) 60))))))))))
721 ;;;; LIST-ALLOCATED-OBJECTS, LIST-REFERENCING-OBJECTS
723 (defvar *ignore-after* nil)
725 (defun valid-obj (space x)
726 (or (not (eq space :dynamic))
727 ;; this test looks bogus if the allocator doesn't work linearly,
728 ;; which I suspect is the case for GENCGC. -- CSR, 2004-06-29
729 (< (get-lisp-obj-address x) (get-lisp-obj-address *ignore-after*))))
731 (defun maybe-cons (space x stuff)
732 (if (valid-obj space x)
736 (defun list-allocated-objects (space &key type larger smaller count
738 (declare (type spaces space)
739 (type (or index null) larger smaller type count)
740 (type (or function null) test)
741 (inline map-allocated-objects))
742 (unless *ignore-after*
743 (setq *ignore-after* (cons 1 2)))
744 (collect ((counted 0 1+))
746 (map-allocated-objects
747 (lambda (obj obj-type size)
748 (declare (optimize (safety 0)))
749 (when (and (or (not type) (eql obj-type type))
750 (or (not smaller) (<= size smaller))
751 (or (not larger) (>= size larger))
752 (or (not test) (funcall test obj)))
753 (setq res (maybe-cons space obj res))
754 (when (and count (>= (counted) count))
755 (return-from list-allocated-objects res))))
759 (defun map-referencing-objects (fun space object)
760 (declare (type spaces space) (inline map-allocated-objects))
761 (unless *ignore-after*
762 (setq *ignore-after* (cons 1 2)))
763 (flet ((maybe-call (fun obj)
764 (when (valid-obj space obj)
766 (map-allocated-objects
767 (lambda (obj obj-type size)
768 (declare (optimize (safety 0)) (ignore obj-type size))
771 (when (or (eq (car obj) object)
772 (eq (cdr obj) object))
773 (maybe-call fun obj)))
775 (dotimes (i (%instance-length obj))
776 (when (eq (%instance-ref obj i) object)
780 (let ((length (get-header-data obj)))
781 (do ((i code-constants-offset (1+ i)))
783 (when (eq (code-header-ref obj i) object)
787 (dotimes (i (length obj))
788 (when (eq (svref obj i) object)
792 (when (or (eq (symbol-name obj) object)
793 (eq (symbol-package obj) object)
794 (eq (symbol-plist obj) object)
795 (eq (symbol-value obj) object))
796 (maybe-call fun obj)))))
799 (defun list-referencing-objects (space object)
801 (map-referencing-objects
802 (lambda (obj) (res obj)) space object)