0.7.13.21:
[sbcl.git] / src / code / room.lisp
1 ;;;; heap-grovelling memory usage stuff
2
3 ;;;; This software is part of the SBCL system. See the README file for
4 ;;;; more information.
5 ;;;;
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.
11
12 (in-package "SB!VM")
13 \f
14 ;;;; type format database
15
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)
21     (kind (missing-arg)
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))))
26
27 (eval-when (:compile-toplevel :execute)
28
29 (defvar *meta-room-info* (make-array 256 :initial-element nil))
30
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)))
37     (cond
38      ((not lowtag))
39      ((not widetag)
40       (let ((info (make-room-info :name name
41                                   :kind :lowtag))
42             (lowtag (symbol-value lowtag)))
43         (declare (fixnum lowtag))
44         (dotimes (i 32)
45           (setf (svref *meta-room-info* (logior lowtag (ash i 3))) info))))
46      (variable)
47      (t
48       (setf (svref *meta-room-info* (symbol-value widetag))
49             (make-room-info :name name
50                             :kind :fixed
51                             :length size))))))
52
53 (dolist (code (list complex-string-widetag simple-array-widetag
54                     complex-bit-vector-widetag complex-vector-widetag
55                     complex-array-widetag))
56   (setf (svref *meta-room-info* code)
57         (make-room-info :name 'array-header
58                         :kind :header)))
59
60 (setf (svref *meta-room-info* bignum-widetag)
61       (make-room-info :name 'bignum
62                       :kind :header))
63
64 (setf (svref *meta-room-info* closure-header-widetag)
65       (make-room-info :name 'closure
66                       :kind :closure))
67
68 (dolist (stuff '((simple-bit-vector-widetag . -3)
69                  (simple-vector-widetag . 2)
70                  (simple-array-unsigned-byte-2-widetag . -2)
71                  (simple-array-unsigned-byte-4-widetag . -1)
72                  (simple-array-unsigned-byte-8-widetag . 0)
73                  (simple-array-unsigned-byte-16-widetag . 1)
74                  (simple-array-unsigned-byte-32-widetag . 2)
75                  (simple-array-signed-byte-8-widetag . 0)
76                  (simple-array-signed-byte-16-widetag . 1)
77                  (simple-array-signed-byte-30-widetag . 2)
78                  (simple-array-signed-byte-32-widetag . 2)
79                  (simple-array-single-float-widetag . 2)
80                  (simple-array-double-float-widetag . 3)
81                  (simple-array-complex-single-float-widetag . 3)
82                  (simple-array-complex-double-float-widetag . 4)))
83   (let* ((name (car stuff))
84          (size (cdr stuff))
85          (sname (string name)))
86     (setf (svref *meta-room-info* (symbol-value name))
87           (make-room-info :name (intern (subseq sname
88                                                 0
89                                                 (mismatch sname "-WIDETAG"
90                                                           :from-end t)))
91                           :kind :vector
92                           :length size))))
93
94 (setf (svref *meta-room-info* simple-string-widetag)
95       (make-room-info :name 'simple-string
96                       :kind :string
97                       :length 0))
98
99 (setf (svref *meta-room-info* simple-array-nil-widetag)
100       (make-room-info :name 'simple-array-nil
101                       :kind :fixed
102                       :length 2))
103
104 (setf (svref *meta-room-info* code-header-widetag)
105       (make-room-info :name 'code
106                       :kind :code))
107
108 (setf (svref *meta-room-info* instance-header-widetag)
109       (make-room-info :name 'instance
110                       :kind :instance))
111
112 ) ; EVAL-WHEN
113
114 (defparameter *room-info* '#.*meta-room-info*)
115 (deftype spaces () '(member :static :dynamic :read-only))
116 \f
117 ;;;; MAP-ALLOCATED-OBJECTS
118
119 ;;; Since they're represented as counts of words, we should never
120 ;;; need bignums to represent these:
121 (declaim (type fixnum
122                *static-space-free-pointer*
123                *read-only-space-free-pointer*))
124
125 (defun space-bounds (space)
126   (declare (type spaces space))
127   (ecase space
128     (:static
129      (values (int-sap static-space-start)
130              (int-sap (* *static-space-free-pointer* n-word-bytes))))
131     (:read-only
132      (values (int-sap read-only-space-start)
133              (int-sap (* *read-only-space-free-pointer* n-word-bytes))))
134     (:dynamic
135      (values (int-sap dynamic-space-start)
136              (dynamic-space-free-pointer)))))
137
138 ;;; Return the total number of bytes used in SPACE.
139 (defun space-bytes (space)
140   (multiple-value-bind (start end) (space-bounds space)
141     (- (sap-int end) (sap-int start))))
142
143 ;;; Round SIZE (in bytes) up to the next dualword (eight byte) boundary.
144 #!-sb-fluid (declaim (inline round-to-dualword))
145 (defun round-to-dualword (size)
146   (declare (fixnum size))
147   (logand (the fixnum (+ size lowtag-mask)) (lognot lowtag-mask)))
148
149 ;;; Return the total size of a vector in bytes, including any pad.
150 #!-sb-fluid (declaim (inline vector-total-size))
151 (defun vector-total-size (obj info)
152   (let ((shift (room-info-length info))
153         (len (+ (length (the (simple-array * (*)) obj))
154                 (ecase (room-info-kind info)
155                   (:vector 0)
156                   (:string 1)))))
157     (declare (type (integer -3 3) shift))
158     (round-to-dualword
159      (+ (* vector-data-offset n-word-bytes)
160         (the fixnum
161              (if (minusp shift)
162                  (ash (the fixnum
163                            (+ len (the fixnum
164                                        (1- (the fixnum (ash 1 (- shift)))))))
165                       shift)
166                  (ash len shift)))))))
167
168 ;;; Iterate over all the objects allocated in SPACE, calling FUN with
169 ;;; the object, the object's type code, and the objects total size in
170 ;;; bytes, including any header and padding.
171 #!-sb-fluid (declaim (maybe-inline map-allocated-objects))
172 (defun map-allocated-objects (fun space)
173   (declare (type function fun) (type spaces space))
174   (without-gcing
175     (multiple-value-bind (start end) (space-bounds space)
176       (declare (type system-area-pointer start end))
177       (declare (optimize (speed 3) (safety 0)))
178       (let ((current start)
179             #+nil
180             (prev nil))
181         (loop
182           (let* ((header (sap-ref-32 current 0))
183                  (header-widetag (logand header #xFF))
184                  (info (svref *room-info* header-widetag)))
185             (cond
186              ((or (not info)
187                   (eq (room-info-kind info) :lowtag))
188               (let ((size (* cons-size n-word-bytes)))
189                 (funcall fun
190                          (make-lisp-obj (logior (sap-int current)
191                                                 list-pointer-lowtag))
192                          list-pointer-lowtag
193                          size)
194                 (setq current (sap+ current size))))
195              ((eql header-widetag closure-header-widetag)
196               (let* ((obj (make-lisp-obj (logior (sap-int current)
197                                                  fun-pointer-lowtag)))
198                      (size (round-to-dualword
199                             (* (the fixnum (1+ (get-closure-length obj)))
200                                n-word-bytes))))
201                 (funcall fun obj header-widetag size)
202                 (setq current (sap+ current size))))
203              ((eq (room-info-kind info) :instance)
204               (let* ((obj (make-lisp-obj
205                            (logior (sap-int current) instance-pointer-lowtag)))
206                      (size (round-to-dualword
207                             (* (+ (%instance-length obj) 1) n-word-bytes))))
208                 (declare (fixnum size))
209                 (funcall fun obj header-widetag size)
210                 (aver (zerop (logand size lowtag-mask)))
211                 #+nil
212                 (when (> size 200000) (break "implausible size, prev ~S" prev))
213                 #+nil
214                 (setq prev current)
215                 (setq current (sap+ current size))))
216              (t
217               (let* ((obj (make-lisp-obj
218                            (logior (sap-int current) other-pointer-lowtag)))
219                      (size (ecase (room-info-kind info)
220                              (:fixed
221                               (aver (or (eql (room-info-length info)
222                                                (1+ (get-header-data obj)))
223                                         (floatp obj)
224                                         (simple-array-nil-p obj)))
225                               (round-to-dualword
226                                (* (room-info-length info) n-word-bytes)))
227                              ((:vector :string)
228                               (vector-total-size obj info))
229                              (:header
230                               (round-to-dualword
231                                (* (1+ (get-header-data obj)) n-word-bytes)))
232                              (:code
233                               (+ (the fixnum
234                                       (* (get-header-data obj) n-word-bytes))
235                                  (round-to-dualword
236                                   (* (the fixnum (%code-code-size obj))
237                                      n-word-bytes)))))))
238                 (declare (fixnum size))
239                 (funcall fun obj header-widetag size)
240                 (aver (zerop (logand size lowtag-mask)))
241                 #+nil
242                 (when (> size 200000)
243                   (break "Implausible size, prev ~S" prev))
244                 #+nil
245                 (setq prev current)
246                 (setq current (sap+ current size))))))
247           (unless (sap< current end)
248             (aver (sap= current end))
249             (return)))
250
251         #+nil
252         prev))))
253 \f
254 ;;;; MEMORY-USAGE
255
256 ;;; Return a list of 3-lists (bytes object type-name) for the objects
257 ;;; allocated in Space.
258 (defun type-breakdown (space)
259   (let ((sizes (make-array 256 :initial-element 0 :element-type 'fixnum))
260         (counts (make-array 256 :initial-element 0 :element-type 'fixnum)))
261     (map-allocated-objects
262      (lambda (obj type size)
263        (declare (fixnum size) (optimize (speed 3) (safety 0)) (ignore obj))
264        (incf (aref sizes type) size)
265        (incf (aref counts type)))
266      space)
267
268     (let ((totals (make-hash-table :test 'eq)))
269       (dotimes (i 256)
270         (let ((total-count (aref counts i)))
271           (unless (zerop total-count)
272             (let* ((total-size (aref sizes i))
273                    (name (room-info-name (aref *room-info* i)))
274                    (found (gethash name totals)))
275               (cond (found
276                      (incf (first found) total-size)
277                      (incf (second found) total-count))
278                     (t
279                      (setf (gethash name totals)
280                            (list total-size total-count name))))))))
281
282       (collect ((totals-list))
283         (maphash (lambda (k v)
284                    (declare (ignore k))
285                    (totals-list v))
286                  totals)
287         (sort (totals-list) #'> :key #'first)))))
288
289 ;;; Handle the summary printing for MEMORY-USAGE. Totals is a list of lists
290 ;;; (space-name . totals-for-space), where totals-for-space is the list
291 ;;; returned by TYPE-BREAKDOWN.
292 (defun print-summary (spaces totals)
293   (let ((summary (make-hash-table :test 'eq)))
294     (dolist (space-total totals)
295       (dolist (total (cdr space-total))
296         (push (cons (car space-total) total)
297               (gethash (third total) summary))))
298
299     (collect ((summary-totals))
300       (maphash (lambda (k v)
301                  (declare (ignore k))
302                  (let ((sum 0))
303                    (declare (fixnum sum))
304                    (dolist (space-total v)
305                      (incf sum (first (cdr space-total))))
306                    (summary-totals (cons sum v))))
307                summary)
308
309       (format t "~2&Summary of spaces: ~(~{~A ~}~)~%" spaces)
310       (let ((summary-total-bytes 0)
311             (summary-total-objects 0))
312         (declare (fixnum summary-total-bytes summary-total-objects))
313         (dolist (space-totals
314                  (mapcar #'cdr (sort (summary-totals) #'> :key #'car)))
315           (let ((total-objects 0)
316                 (total-bytes 0)
317                 name)
318             (declare (fixnum total-objects total-bytes))
319             (collect ((spaces))
320               (dolist (space-total space-totals)
321                 (let ((total (cdr space-total)))
322                   (setq name (third total))
323                   (incf total-bytes (first total))
324                   (incf total-objects (second total))
325                   (spaces (cons (car space-total) (first total)))))
326               (format t "~%~A:~%    ~:D bytes, ~:D object~:P"
327                       name total-bytes total-objects)
328               (dolist (space (spaces))
329                 (format t ", ~W% ~(~A~)"
330                         (round (* (cdr space) 100) total-bytes)
331                         (car space)))
332               (format t ".~%")
333               (incf summary-total-bytes total-bytes)
334               (incf summary-total-objects total-objects))))
335         (format t "~%Summary total:~%    ~:D bytes, ~:D objects.~%"
336                 summary-total-bytes summary-total-objects)))))
337
338 ;;; Report object usage for a single space.
339 (defun report-space-total (space-total cutoff)
340   (declare (list space-total) (type (or single-float null) cutoff))
341   (format t "~2&Breakdown for ~(~A~) space:~%" (car space-total))
342   (let* ((types (cdr space-total))
343          (total-bytes (reduce #'+ (mapcar #'first types)))
344          (total-objects (reduce #'+ (mapcar #'second types)))
345          (cutoff-point (if cutoff
346                            (truncate (* (float total-bytes) cutoff))
347                            0))
348          (reported-bytes 0)
349          (reported-objects 0))
350     (declare (fixnum total-objects total-bytes cutoff-point reported-objects
351                      reported-bytes))
352     (loop for (bytes objects name) in types do
353       (when (<= bytes cutoff-point)
354         (format t "  ~10:D bytes for ~9:D other object~2:*~P.~%"
355                 (- total-bytes reported-bytes)
356                 (- total-objects reported-objects))
357         (return))
358       (incf reported-bytes bytes)
359       (incf reported-objects objects)
360       (format t "  ~10:D bytes for ~9:D ~(~A~) object~2:*~P.~%"
361               bytes objects name))
362     (format t "  ~10:D bytes for ~9:D ~(~A~) object~2:*~P (space total.)~%"
363             total-bytes total-objects (car space-total))))
364
365 ;;; Print information about the heap memory in use. PRINT-SPACES is a
366 ;;; list of the spaces to print detailed information for.
367 ;;; COUNT-SPACES is a list of the spaces to scan. For either one, T
368 ;;; means all spaces (i.e. :STATIC, :DYNAMIC and :READ-ONLY.) If
369 ;;; PRINT-SUMMARY is true, then summary information will be printed.
370 ;;; The defaults print only summary information for dynamic space. If
371 ;;; true, CUTOFF is a fraction of the usage in a report below which
372 ;;; types will be combined as OTHER.
373 (defun memory-usage (&key print-spaces (count-spaces '(:dynamic))
374                           (print-summary t) cutoff)
375   (declare (type (or single-float null) cutoff))
376   (let* ((spaces (if (eq count-spaces t)
377                      '(:static :dynamic :read-only)
378                      count-spaces))
379          (totals (mapcar (lambda (space)
380                            (cons space (type-breakdown space)))
381                          spaces)))
382
383     (dolist (space-total totals)
384       (when (or (eq print-spaces t)
385                 (member (car space-total) print-spaces))
386         (report-space-total space-total cutoff)))
387
388     (when print-summary (print-summary spaces totals)))
389
390   (values))
391 \f
392 ;;; Print info about how much code and no-ops there are in SPACE.
393 (defun count-no-ops (space)
394   (declare (type spaces space))
395   (let ((code-words 0)
396         (no-ops 0)
397         (total-bytes 0))
398     (declare (fixnum code-words no-ops)
399              (type unsigned-byte total-bytes))
400     (map-allocated-objects
401      (lambda (obj type size)
402        (declare (fixnum size) (optimize (safety 0)))
403        (when (eql type code-header-widetag)
404          (incf total-bytes size)
405          (let ((words (truly-the fixnum (%code-code-size obj)))
406                (sap (truly-the system-area-pointer
407                                (%primitive code-instructions obj))))
408            (incf code-words words)
409            (dotimes (i words)
410              (when (zerop (sap-ref-32 sap (* i n-word-bytes)))
411                (incf no-ops))))))
412      space)
413
414     (format t
415             "~:D code-object bytes, ~:D code words, with ~:D no-ops (~D%).~%"
416             total-bytes code-words no-ops
417             (round (* no-ops 100) code-words)))
418
419   (values))
420 \f
421 (defun descriptor-vs-non-descriptor-storage (&rest spaces)
422   (let ((descriptor-words 0)
423         (non-descriptor-headers 0)
424         (non-descriptor-bytes 0))
425     (declare (type unsigned-byte descriptor-words non-descriptor-headers
426                    non-descriptor-bytes))
427     (dolist (space (or spaces '(:read-only :static :dynamic)))
428       (declare (inline map-allocated-objects))
429       (map-allocated-objects
430        (lambda (obj type size)
431          (declare (fixnum size) (optimize (safety 0)))
432          (case type
433            (#.code-header-widetag
434             (let ((inst-words (truly-the fixnum (%code-code-size obj))))
435               (declare (type fixnum inst-words))
436               (incf non-descriptor-bytes (* inst-words n-word-bytes))
437               (incf descriptor-words
438                     (- (truncate size n-word-bytes) inst-words))))
439            ((#.bignum-widetag
440              #.single-float-widetag
441              #.double-float-widetag
442              #.simple-string-widetag
443              #.simple-bit-vector-widetag
444              #.simple-array-unsigned-byte-2-widetag
445              #.simple-array-unsigned-byte-4-widetag
446              #.simple-array-unsigned-byte-8-widetag
447              #.simple-array-unsigned-byte-16-widetag
448              #.simple-array-unsigned-byte-32-widetag
449              #.simple-array-signed-byte-8-widetag
450              #.simple-array-signed-byte-16-widetag
451              #.simple-array-signed-byte-30-widetag
452              #.simple-array-signed-byte-32-widetag
453              #.simple-array-single-float-widetag
454              #.simple-array-double-float-widetag
455              #.simple-array-complex-single-float-widetag
456              #.simple-array-complex-double-float-widetag)
457             (incf non-descriptor-headers)
458             (incf non-descriptor-bytes (- size n-word-bytes)))
459            ((#.list-pointer-lowtag
460              #.instance-pointer-lowtag
461              #.ratio-widetag
462              #.complex-widetag
463              #.simple-array-widetag
464              #.simple-vector-widetag
465              #.complex-string-widetag
466              #.complex-bit-vector-widetag
467              #.complex-vector-widetag
468              #.complex-array-widetag
469              #.closure-header-widetag
470              #.funcallable-instance-header-widetag
471              #.value-cell-header-widetag
472              #.symbol-header-widetag
473              #.sap-widetag
474              #.weak-pointer-widetag
475              #.instance-header-widetag)
476             (incf descriptor-words (truncate size n-word-bytes)))
477            (t
478             (error "bogus widetag: ~W" type))))
479        space))
480     (format t "~:D words allocated for descriptor objects.~%"
481             descriptor-words)
482     (format t "~:D bytes data/~:D words header for non-descriptor objects.~%"
483             non-descriptor-bytes non-descriptor-headers)
484     (values)))
485 \f
486 ;;; Print a breakdown by instance type of all the instances allocated
487 ;;; in SPACE. If TOP-N is true, print only information for the the
488 ;;; TOP-N types with largest usage.
489 (defun instance-usage (space &key (top-n 15))
490   (declare (type spaces space) (type (or fixnum null) top-n))
491   (format t "~2&~@[Top ~W ~]~(~A~) instance types:~%" top-n space)
492   (let ((totals (make-hash-table :test 'eq))
493         (total-objects 0)
494         (total-bytes 0))
495     (declare (fixnum total-objects total-bytes))
496     (map-allocated-objects
497      (lambda (obj type size)
498        (declare (fixnum size) (optimize (speed 3) (safety 0)))
499        (when (eql type instance-header-widetag)
500          (incf total-objects)
501          (incf total-bytes size)
502          (let* ((class (layout-class (%instance-ref obj 0)))
503                 (found (gethash class totals)))
504            (cond (found
505                   (incf (the fixnum (car found)))
506                   (incf (the fixnum (cdr found)) size))
507                  (t
508                   (setf (gethash class totals) (cons 1 size)))))))
509      space)
510
511     (collect ((totals-list))
512       (maphash (lambda (class what)
513                  (totals-list (cons (prin1-to-string
514                                      (class-proper-name class))
515                                     what)))
516                totals)
517       (let ((sorted (sort (totals-list) #'> :key #'cddr))
518             (printed-bytes 0)
519             (printed-objects 0))
520         (declare (fixnum printed-bytes printed-objects))
521         (dolist (what (if top-n
522                           (subseq sorted 0 (min (length sorted) top-n))
523                           sorted))
524           (let ((bytes (cddr what))
525                 (objects (cadr what)))
526             (incf printed-bytes bytes)
527             (incf printed-objects objects)
528             (format t "  ~A: ~:D bytes, ~:D object~:P.~%" (car what)
529                     bytes objects)))
530
531         (let ((residual-objects (- total-objects printed-objects))
532               (residual-bytes (- total-bytes printed-bytes)))
533           (unless (zerop residual-objects)
534             (format t "  Other types: ~:D bytes, ~:D object~:P.~%"
535                     residual-bytes residual-objects))))
536
537       (format t "  ~:(~A~) instance total: ~:D bytes, ~:D object~:P.~%"
538               space total-bytes total-objects)))
539
540   (values))
541 \f
542 (defun find-holes (&rest spaces)
543   (dolist (space (or spaces '(:read-only :static :dynamic)))
544     (format t "In ~A space:~%" space)
545     (let ((start-addr nil)
546           (total-bytes 0))
547       (declare (type (or null (unsigned-byte 32)) start-addr)
548                (type (unsigned-byte 32) total-bytes))
549       (map-allocated-objects
550        (lambda (object typecode bytes)
551          (declare (ignore typecode)
552                   (type (unsigned-byte 32) bytes))
553          (if (and (consp object)
554                   (eql (car object) 0)
555                   (eql (cdr object) 0))
556              (if start-addr
557                  (incf total-bytes bytes)
558                  (setf start-addr (sb!di::get-lisp-obj-address object)
559                        total-bytes bytes))
560              (when start-addr
561                (format t "~:D bytes at #X~X~%" total-bytes start-addr)
562                (setf start-addr nil))))
563        space)
564       (when start-addr
565         (format t "~:D bytes at #X~X~%" total-bytes start-addr))))
566   (values))
567 \f
568 ;;;; PRINT-ALLOCATED-OBJECTS
569
570 (defun print-allocated-objects (space &key (percent 0) (pages 5)
571                                       type larger smaller count
572                                       (stream *standard-output*))
573   (declare (type (integer 0 99) percent) (type index pages)
574            (type stream stream) (type spaces space)
575            (type (or index null) type larger smaller count))
576   (multiple-value-bind (start-sap end-sap) (space-bounds space)
577     (let* ((space-start (sap-int start-sap))
578            (space-end (sap-int end-sap))
579            (space-size (- space-end space-start))
580            (pagesize (sb!sys:get-page-size))
581            (start (+ space-start (round (* space-size percent) 100)))
582            (printed-conses (make-hash-table :test 'eq))
583            (pages-so-far 0)
584            (count-so-far 0)
585            (last-page 0))
586       (declare (type (unsigned-byte 32) last-page start)
587                (fixnum pages-so-far count-so-far pagesize))
588       (labels ((note-conses (x)
589                  (unless (or (atom x) (gethash x printed-conses))
590                    (setf (gethash x printed-conses) t)
591                    (note-conses (car x))
592                    (note-conses (cdr x)))))
593         (map-allocated-objects
594          (lambda (obj obj-type size)
595            (declare (optimize (safety 0)))
596            (let ((addr (get-lisp-obj-address obj)))
597              (when (>= addr start)
598                (when (if count
599                          (> count-so-far count)
600                          (> pages-so-far pages))
601                  (return-from print-allocated-objects (values)))
602
603                (unless count
604                  (let ((this-page (* (the (values (unsigned-byte 32) t)
605                                        (truncate addr pagesize))
606                                      pagesize)))
607                    (declare (type (unsigned-byte 32) this-page))
608                    (when (/= this-page last-page)
609                      (when (< pages-so-far pages)
610                        ;; FIXME: What is this? (ERROR "Argh..")? or
611                        ;; a warning? or code that can be removed
612                        ;; once the system is stable? or what?
613                        (format stream "~2&**** Page ~W, address ~X:~%"
614                                pages-so-far addr))
615                      (setq last-page this-page)
616                      (incf pages-so-far))))
617
618                (when (and (or (not type) (eql obj-type type))
619                           (or (not smaller) (<= size smaller))
620                           (or (not larger) (>= size larger)))
621                  (incf count-so-far)
622                  (case type
623                    (#.code-header-widetag
624                     (let ((dinfo (%code-debug-info obj)))
625                       (format stream "~&Code object: ~S~%"
626                               (if dinfo
627                                   (sb!c::compiled-debug-info-name dinfo)
628                                   "No debug info."))))
629                    (#.symbol-header-widetag
630                     (format stream "~&~S~%" obj))
631                    (#.list-pointer-lowtag
632                     (unless (gethash obj printed-conses)
633                       (note-conses obj)
634                       (let ((*print-circle* t)
635                             (*print-level* 5)
636                             (*print-length* 10))
637                         (format stream "~&~S~%" obj))))
638                    (t
639                     (fresh-line stream)
640                     (let ((str (write-to-string obj :level 5 :length 10
641                                                 :pretty nil)))
642                       (unless (eql type instance-header-widetag)
643                         (format stream "~S: " (type-of obj)))
644                       (format stream "~A~%"
645                               (subseq str 0 (min (length str) 60))))))))))
646          space))))
647   (values))
648 \f
649 ;;;; LIST-ALLOCATED-OBJECTS, LIST-REFERENCING-OBJECTS
650
651 (defvar *ignore-after* nil)
652
653 (defun maybe-cons (space x stuff)
654   (if (or (not (eq space :dynamic))
655           (< (get-lisp-obj-address x) (get-lisp-obj-address *ignore-after*)))
656       (cons x stuff)
657       stuff))
658
659 (defun list-allocated-objects (space &key type larger smaller count
660                                      test)
661   (declare (type spaces space)
662            (type (or index null) larger smaller type count)
663            (type (or function null) test)
664            (inline map-allocated-objects))
665   (unless *ignore-after* (setq *ignore-after* (cons 1 2)))
666   (collect ((counted 0 1+))
667     (let ((res ()))
668       (map-allocated-objects
669        (lambda (obj obj-type size)
670          (declare (optimize (safety 0)))
671          (when (and (or (not type) (eql obj-type type))
672                     (or (not smaller) (<= size smaller))
673                     (or (not larger) (>= size larger))
674                     (or (not test) (funcall test obj)))
675            (setq res (maybe-cons space obj res))
676            (when (and count (>= (counted) count))
677              (return-from list-allocated-objects res))))
678        space)
679       res)))
680
681 (defun list-referencing-objects (space object)
682   (declare (type spaces space) (inline map-allocated-objects))
683   (unless *ignore-after* (setq *ignore-after* (cons 1 2)))
684   (let ((res ()))
685     (flet ((res (x)
686              (setq res (maybe-cons space x res))))
687       (map-allocated-objects
688        (lambda (obj obj-type size)
689          (declare (optimize (safety 0)) (ignore obj-type size))
690          (typecase obj
691            (cons
692             (when (or (eq (car obj) object) (eq (cdr obj) object))
693               (res obj)))
694            (instance
695             (dotimes (i (%instance-length obj))
696               (when (eq (%instance-ref obj i) object)
697                 (res obj)
698                 (return))))
699            (simple-vector
700             (dotimes (i (length obj))
701               (when (eq (svref obj i) object)
702                 (res obj)
703                 (return))))
704            (symbol
705             (when (or (eq (symbol-name obj) object)
706                       (eq (symbol-package obj) object)
707                       (eq (symbol-plist obj) object)
708                       (eq (symbol-value obj) object))
709               (res obj)))))
710        space))
711     res))