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)
197 (+ (* vector-data-offset n-word-bytes)
199 (ash (+ len (1- (ash 1 (- shift))))
203 ;;; Access to the GENCGC page table for better precision in
204 ;;; MAP-ALLOCATED-OBJECTS
207 (define-alien-type (struct page)
210 (bytes-used (unsigned 16))
213 (declaim (inline find-page-index))
214 (define-alien-routine "find_page_index" long (index long))
215 (define-alien-variable "page_table" (* (struct page))))
217 ;;; Iterate over all the objects allocated in SPACE, calling FUN with
218 ;;; the object, the object's type code, and the object's total size in
219 ;;; bytes, including any header and padding.
220 #!-sb-fluid (declaim (maybe-inline map-allocated-objects))
221 (defun map-allocated-objects (fun space)
222 (declare (type function fun) (type spaces space))
224 (multiple-value-bind (start end) (space-bounds space)
225 (declare (type system-area-pointer start end))
226 (declare (optimize (speed 3)))
227 (let ((current start)
228 #!+gencgc (skip-tests-until-addr 0))
229 (labels ((maybe-finish-mapping ()
230 (unless (sap< current end)
231 (aver (sap= current end))
232 (return-from map-allocated-objects)))
233 ;; GENCGC doesn't allocate linearly, which means that the
234 ;; dynamic space can contain large blocks zeros that get
235 ;; accounted as conses in ROOM (and slow down other
236 ;; applications of MAP-ALLOCATED-OBJECTS). To fix this
237 ;; check the GC page structure for the current address.
238 ;; If the page is free or the address is beyond the page-
239 ;; internal allocation offset (bytes-used) skip to the
240 ;; next page immediately.
243 (when (eq space :dynamic)
244 (loop with page-mask = #.(1- sb!vm:gencgc-page-size)
245 for addr of-type sb!vm:word = (sap-int current)
246 while (>= addr skip-tests-until-addr)
248 ;; For some reason binding PAGE with LET
249 ;; conses like mad (but gives no compiler notes...)
250 ;; Work around the problem with SYMBOL-MACROLET
251 ;; instead of trying to figure out the real
252 ;; issue. -- JES, 2005-05-17
254 ((page (deref page-table
255 (find-page-index addr))))
256 ;; Don't we have any nicer way to access C struct
258 (let ((alloc-flag (ldb (byte 3 2)
260 (bytes-used (slot page 'bytes-used)))
261 ;; If the page is not free and the current
262 ;; pointer is still below the allocation offset
264 (when (and (not (zerop alloc-flag))
265 (<= (logand page-mask addr)
267 ;; Don't bother testing again until we
268 ;; get past that allocation offset
269 (setf skip-tests-until-addr
270 (+ (logandc2 addr page-mask)
271 (the fixnum bytes-used)))
272 ;; And then continue with the scheduled
274 (return-from maybe-skip-page))
275 ;; Move CURRENT to start of next page
276 (setf current (int-sap (+ (logandc2 addr page-mask)
277 sb!vm:gencgc-page-size)))
278 (maybe-finish-mapping)))))))
279 (declare (inline maybe-finish-mapping maybe-skip-page))
281 (maybe-finish-mapping)
283 (let* ((header (sap-ref-word current 0))
284 (header-widetag (logand header #xFF))
285 (info (svref *room-info* header-widetag)))
288 (eq (room-info-kind info) :lowtag))
289 (let ((size (* cons-size n-word-bytes)))
291 (make-lisp-obj (logior (sap-int current)
292 list-pointer-lowtag))
295 (setq current (sap+ current size))))
296 ((eql header-widetag closure-header-widetag)
297 (let* ((obj (make-lisp-obj (logior (sap-int current)
298 fun-pointer-lowtag)))
299 (size (round-to-dualword
300 (* (the fixnum (1+ (get-closure-length obj)))
302 (funcall fun obj header-widetag size)
303 (setq current (sap+ current size))))
304 ((eq (room-info-kind info) :instance)
305 (let* ((obj (make-lisp-obj
306 (logior (sap-int current) instance-pointer-lowtag)))
307 (size (round-to-dualword
308 (* (+ (%instance-length obj) 1) n-word-bytes))))
309 (declare (fixnum size))
310 (funcall fun obj header-widetag size)
311 (aver (zerop (logand size lowtag-mask)))
312 (setq current (sap+ current size))))
314 (let* ((obj (make-lisp-obj
315 (logior (sap-int current) other-pointer-lowtag)))
316 (size (ecase (room-info-kind info)
318 (aver (or (eql (room-info-length info)
319 (1+ (get-header-data obj)))
321 (simple-array-nil-p obj)))
323 (* (room-info-length info) n-word-bytes)))
325 (vector-total-size obj info))
328 (* (1+ (get-header-data obj)) n-word-bytes)))
331 (* (get-header-data obj) n-word-bytes))
333 (* (the fixnum (%code-code-size obj))
335 (declare (fixnum size))
336 (funcall fun obj header-widetag size)
337 (aver (zerop (logand size lowtag-mask)))
338 (setq current (sap+ current size))))))))))))
343 ;;; Return a list of 3-lists (bytes object type-name) for the objects
344 ;;; allocated in Space.
345 (defun type-breakdown (space)
346 (let ((sizes (make-array 256 :initial-element 0 :element-type 'fixnum))
347 (counts (make-array 256 :initial-element 0 :element-type 'fixnum)))
348 (map-allocated-objects
349 (lambda (obj type size)
350 (declare (fixnum size) (optimize (speed 3)) (ignore obj))
351 (incf (aref sizes type) size)
352 (incf (aref counts type)))
355 (let ((totals (make-hash-table :test 'eq)))
357 (let ((total-count (aref counts i)))
358 (unless (zerop total-count)
359 (let* ((total-size (aref sizes i))
360 (name (room-info-name (aref *room-info* i)))
361 (found (gethash name totals)))
363 (incf (first found) total-size)
364 (incf (second found) total-count))
366 (setf (gethash name totals)
367 (list total-size total-count name))))))))
369 (collect ((totals-list))
370 (maphash (lambda (k v)
374 (sort (totals-list) #'> :key #'first)))))
376 ;;; Handle the summary printing for MEMORY-USAGE. Totals is a list of lists
377 ;;; (space-name . totals-for-space), where totals-for-space is the list
378 ;;; returned by TYPE-BREAKDOWN.
379 (defun print-summary (spaces totals)
380 (let ((summary (make-hash-table :test 'eq)))
381 (dolist (space-total totals)
382 (dolist (total (cdr space-total))
383 (push (cons (car space-total) total)
384 (gethash (third total) summary))))
386 (collect ((summary-totals))
387 (maphash (lambda (k v)
390 (declare (fixnum sum))
391 (dolist (space-total v)
392 (incf sum (first (cdr space-total))))
393 (summary-totals (cons sum v))))
396 (format t "~2&Summary of spaces: ~(~{~A ~}~)~%" spaces)
397 (let ((summary-total-bytes 0)
398 (summary-total-objects 0))
399 (declare (fixnum summary-total-bytes summary-total-objects))
400 (dolist (space-totals
401 (mapcar #'cdr (sort (summary-totals) #'> :key #'car)))
402 (let ((total-objects 0)
405 (declare (fixnum total-objects total-bytes))
407 (dolist (space-total space-totals)
408 (let ((total (cdr space-total)))
409 (setq name (third total))
410 (incf total-bytes (first total))
411 (incf total-objects (second total))
412 (spaces (cons (car space-total) (first total)))))
413 (format t "~%~A:~% ~:D bytes, ~:D object~:P"
414 name total-bytes total-objects)
415 (dolist (space (spaces))
416 (format t ", ~W% ~(~A~)"
417 (round (* (cdr space) 100) total-bytes)
420 (incf summary-total-bytes total-bytes)
421 (incf summary-total-objects total-objects))))
422 (format t "~%Summary total:~% ~:D bytes, ~:D objects.~%"
423 summary-total-bytes summary-total-objects)))))
425 ;;; Report object usage for a single space.
426 (defun report-space-total (space-total cutoff)
427 (declare (list space-total) (type (or single-float null) cutoff))
428 (format t "~2&Breakdown for ~(~A~) space:~%" (car space-total))
429 (let* ((types (cdr space-total))
430 (total-bytes (reduce #'+ (mapcar #'first types)))
431 (total-objects (reduce #'+ (mapcar #'second types)))
432 (cutoff-point (if cutoff
433 (truncate (* (float total-bytes) cutoff))
436 (reported-objects 0))
437 (declare (fixnum total-objects total-bytes cutoff-point reported-objects
439 (loop for (bytes objects name) in types do
440 (when (<= bytes cutoff-point)
441 (format t " ~10:D bytes for ~9:D other object~2:*~P.~%"
442 (- total-bytes reported-bytes)
443 (- total-objects reported-objects))
445 (incf reported-bytes bytes)
446 (incf reported-objects objects)
447 (format t " ~10:D bytes for ~9:D ~(~A~) object~2:*~P.~%"
449 (format t " ~10:D bytes for ~9:D ~(~A~) object~2:*~P (space total.)~%"
450 total-bytes total-objects (car space-total))))
452 ;;; Print information about the heap memory in use. PRINT-SPACES is a
453 ;;; list of the spaces to print detailed information for.
454 ;;; COUNT-SPACES is a list of the spaces to scan. For either one, T
455 ;;; means all spaces (i.e. :STATIC, :DYNAMIC and :READ-ONLY.) If
456 ;;; PRINT-SUMMARY is true, then summary information will be printed.
457 ;;; The defaults print only summary information for dynamic space. If
458 ;;; true, CUTOFF is a fraction of the usage in a report below which
459 ;;; types will be combined as OTHER.
460 (defun memory-usage (&key print-spaces (count-spaces '(:dynamic))
461 (print-summary t) cutoff)
462 (declare (type (or single-float null) cutoff))
463 (let* ((spaces (if (eq count-spaces t)
464 '(:static :dynamic :read-only)
466 (totals (mapcar (lambda (space)
467 (cons space (type-breakdown space)))
470 (dolist (space-total totals)
471 (when (or (eq print-spaces t)
472 (member (car space-total) print-spaces))
473 (report-space-total space-total cutoff)))
475 (when print-summary (print-summary spaces totals)))
479 ;;; Print info about how much code and no-ops there are in SPACE.
480 (defun count-no-ops (space)
481 (declare (type spaces space))
485 (declare (fixnum code-words no-ops)
486 (type unsigned-byte total-bytes))
487 (map-allocated-objects
488 (lambda (obj type size)
489 (declare (fixnum size))
490 (when (eql type code-header-widetag)
491 (incf total-bytes size)
492 (let ((words (truly-the fixnum (%code-code-size obj)))
493 (sap (truly-the system-area-pointer
494 (%primitive code-instructions obj))))
495 (incf code-words words)
497 (when (zerop (sap-ref-word sap (* i n-word-bytes)))
502 "~:D code-object bytes, ~:D code words, with ~:D no-ops (~D%).~%"
503 total-bytes code-words no-ops
504 (round (* no-ops 100) code-words)))
508 (defun descriptor-vs-non-descriptor-storage (&rest spaces)
509 (let ((descriptor-words 0)
510 (non-descriptor-headers 0)
511 (non-descriptor-bytes 0))
512 (declare (type unsigned-byte descriptor-words non-descriptor-headers
513 non-descriptor-bytes))
514 (dolist (space (or spaces '(:read-only :static :dynamic)))
515 (declare (inline map-allocated-objects))
516 (map-allocated-objects
517 (lambda (obj type size)
518 (declare (fixnum size))
520 (#.code-header-widetag
521 (let ((inst-words (truly-the fixnum (%code-code-size obj))))
522 (declare (type fixnum inst-words))
523 (incf non-descriptor-bytes (* inst-words n-word-bytes))
524 (incf descriptor-words
525 (- (truncate size n-word-bytes) inst-words))))
527 #.single-float-widetag
528 #.double-float-widetag
529 #.simple-base-string-widetag
530 #!+sb-unicode #.simple-character-string-widetag
531 #.simple-array-nil-widetag
532 #.simple-bit-vector-widetag
533 #.simple-array-unsigned-byte-2-widetag
534 #.simple-array-unsigned-byte-4-widetag
535 #.simple-array-unsigned-byte-8-widetag
536 #.simple-array-unsigned-byte-16-widetag
537 #.simple-array-unsigned-byte-32-widetag
538 #.simple-array-signed-byte-8-widetag
539 #.simple-array-signed-byte-16-widetag
540 ; #.simple-array-signed-byte-30-widetag
541 #.simple-array-signed-byte-32-widetag
542 #.simple-array-single-float-widetag
543 #.simple-array-double-float-widetag
544 #.simple-array-complex-single-float-widetag
545 #.simple-array-complex-double-float-widetag)
546 (incf non-descriptor-headers)
547 (incf non-descriptor-bytes (- size n-word-bytes)))
548 ((#.list-pointer-lowtag
549 #.instance-pointer-lowtag
552 #.simple-array-widetag
553 #.simple-vector-widetag
554 #.complex-base-string-widetag
555 #.complex-vector-nil-widetag
556 #.complex-bit-vector-widetag
557 #.complex-vector-widetag
558 #.complex-array-widetag
559 #.closure-header-widetag
560 #.funcallable-instance-header-widetag
561 #.value-cell-header-widetag
562 #.symbol-header-widetag
564 #.weak-pointer-widetag
565 #.instance-header-widetag)
566 (incf descriptor-words (truncate size n-word-bytes)))
568 (error "bogus widetag: ~W" type))))
570 (format t "~:D words allocated for descriptor objects.~%"
572 (format t "~:D bytes data/~:D words header for non-descriptor objects.~%"
573 non-descriptor-bytes non-descriptor-headers)
576 ;;; Print a breakdown by instance type of all the instances allocated
577 ;;; in SPACE. If TOP-N is true, print only information for the
578 ;;; TOP-N types with largest usage.
579 (defun instance-usage (space &key (top-n 15))
580 (declare (type spaces space) (type (or fixnum null) top-n))
581 (format t "~2&~@[Top ~W ~]~(~A~) instance types:~%" top-n space)
582 (let ((totals (make-hash-table :test 'eq))
585 (declare (fixnum total-objects total-bytes))
586 (map-allocated-objects
587 (lambda (obj type size)
588 (declare (fixnum size) (optimize (speed 3)))
589 (when (eql type instance-header-widetag)
591 (incf total-bytes size)
592 (let* ((classoid (layout-classoid (%instance-ref obj 0)))
593 (found (gethash classoid totals)))
595 (incf (the fixnum (car found)))
596 (incf (the fixnum (cdr found)) size))
598 (setf (gethash classoid totals) (cons 1 size)))))))
601 (collect ((totals-list))
602 (maphash (lambda (classoid what)
603 (totals-list (cons (prin1-to-string
604 (classoid-proper-name classoid))
607 (let ((sorted (sort (totals-list) #'> :key #'cddr))
610 (declare (fixnum printed-bytes printed-objects))
611 (dolist (what (if top-n
612 (subseq sorted 0 (min (length sorted) top-n))
614 (let ((bytes (cddr what))
615 (objects (cadr what)))
616 (incf printed-bytes bytes)
617 (incf printed-objects objects)
618 (format t " ~A: ~:D bytes, ~:D object~:P.~%" (car what)
621 (let ((residual-objects (- total-objects printed-objects))
622 (residual-bytes (- total-bytes printed-bytes)))
623 (unless (zerop residual-objects)
624 (format t " Other types: ~:D bytes, ~:D object~:P.~%"
625 residual-bytes residual-objects))))
627 (format t " ~:(~A~) instance total: ~:D bytes, ~:D object~:P.~%"
628 space total-bytes total-objects)))
632 ;;;; PRINT-ALLOCATED-OBJECTS
634 (defun print-allocated-objects (space &key (percent 0) (pages 5)
635 type larger smaller count
636 (stream *standard-output*))
637 (declare (type (integer 0 99) percent) (type index pages)
638 (type stream stream) (type spaces space)
639 (type (or index null) type larger smaller count))
640 (multiple-value-bind (start-sap end-sap) (space-bounds space)
641 (let* ((space-start (sap-int start-sap))
642 (space-end (sap-int end-sap))
643 (space-size (- space-end space-start))
644 (pagesize (sb!sys:get-page-size))
645 (start (+ space-start (round (* space-size percent) 100)))
646 (printed-conses (make-hash-table :test 'eq))
650 (declare (type (unsigned-byte 32) last-page start)
651 (fixnum pages-so-far count-so-far pagesize))
652 (labels ((note-conses (x)
653 (unless (or (atom x) (gethash x printed-conses))
654 (setf (gethash x printed-conses) t)
655 (note-conses (car x))
656 (note-conses (cdr x)))))
657 (map-allocated-objects
658 (lambda (obj obj-type size)
659 (let ((addr (get-lisp-obj-address obj)))
660 (when (>= addr start)
662 (> count-so-far count)
663 (> pages-so-far pages))
664 (return-from print-allocated-objects (values)))
667 (let ((this-page (* (the (values (unsigned-byte 32) t)
668 (truncate addr pagesize))
670 (declare (type (unsigned-byte 32) this-page))
671 (when (/= this-page last-page)
672 (when (< pages-so-far pages)
673 ;; FIXME: What is this? (ERROR "Argh..")? or
674 ;; a warning? or code that can be removed
675 ;; once the system is stable? or what?
676 (format stream "~2&**** Page ~W, address ~X:~%"
678 (setq last-page this-page)
679 (incf pages-so-far))))
681 (when (and (or (not type) (eql obj-type type))
682 (or (not smaller) (<= size smaller))
683 (or (not larger) (>= size larger)))
686 (#.code-header-widetag
687 (let ((dinfo (%code-debug-info obj)))
688 (format stream "~&Code object: ~S~%"
690 (sb!c::compiled-debug-info-name dinfo)
692 (#.symbol-header-widetag
693 (format stream "~&~S~%" obj))
694 (#.list-pointer-lowtag
695 (unless (gethash obj printed-conses)
697 (let ((*print-circle* t)
700 (format stream "~&~S~%" obj))))
703 (let ((str (write-to-string obj :level 5 :length 10
705 (unless (eql type instance-header-widetag)
706 (format stream "~S: " (type-of obj)))
707 (format stream "~A~%"
708 (subseq str 0 (min (length str) 60))))))))))
712 ;;;; LIST-ALLOCATED-OBJECTS, LIST-REFERENCING-OBJECTS
714 (defvar *ignore-after* nil)
716 (defun valid-obj (space x)
717 (or (not (eq space :dynamic))
718 ;; this test looks bogus if the allocator doesn't work linearly,
719 ;; which I suspect is the case for GENCGC. -- CSR, 2004-06-29
720 (< (get-lisp-obj-address x) (get-lisp-obj-address *ignore-after*))))
722 (defun maybe-cons (space x stuff)
723 (if (valid-obj space x)
727 (defun list-allocated-objects (space &key type larger smaller count
729 (declare (type spaces space)
730 (type (or index null) larger smaller type count)
731 (type (or function null) test)
732 (inline map-allocated-objects))
733 (unless *ignore-after*
734 (setq *ignore-after* (cons 1 2)))
735 (collect ((counted 0 1+))
737 (map-allocated-objects
738 (lambda (obj obj-type size)
739 (when (and (or (not type) (eql obj-type type))
740 (or (not smaller) (<= size smaller))
741 (or (not larger) (>= size larger))
742 (or (not test) (funcall test obj)))
743 (setq res (maybe-cons space obj res))
744 (when (and count (>= (counted) count))
745 (return-from list-allocated-objects res))))
749 (defun map-referencing-objects (fun space object)
750 (declare (type spaces space) (inline map-allocated-objects))
751 (unless *ignore-after*
752 (setq *ignore-after* (cons 1 2)))
753 (flet ((maybe-call (fun obj)
754 (when (valid-obj space obj)
756 (map-allocated-objects
757 (lambda (obj obj-type size)
758 (declare (ignore obj-type size))
761 (when (or (eq (car obj) object)
762 (eq (cdr obj) object))
763 (maybe-call fun obj)))
765 (dotimes (i (%instance-length obj))
766 (when (eq (%instance-ref obj i) object)
770 (let ((length (get-header-data obj)))
771 (do ((i code-constants-offset (1+ i)))
773 (when (eq (code-header-ref obj i) object)
777 (dotimes (i (length obj))
778 (when (eq (svref obj i) object)
782 (when (or (eq (symbol-name obj) object)
783 (eq (symbol-package obj) object)
784 (eq (symbol-plist obj) object)
785 (eq (symbol-value obj) object))
786 (maybe-call fun obj)))))
789 (defun list-referencing-objects (space object)
791 (map-referencing-objects
792 (lambda (obj) (res obj)) space object)