0.8.5.14:
[sbcl.git] / src / compiler / target-disassem.lisp
index d7e60e7..6e07407 100644 (file)
@@ -44,8 +44,9 @@
   (sort insts #'> :key #'specializer-rank))
 
 (defun specialization-error (insts)
-  (error "~@<internal disassembler error: ~2I~_Instructions either aren't related or conflict in some way: ~4I~_~S~:>"
-        insts))
+  (bug
+   "~@<Instructions either aren't related or conflict in some way: ~4I~_~S~:>"
+   insts))
 
 ;;; Given a list of instructions INSTS, Sees if one of these instructions is a
 ;;; more general form of all the others, in which case they are put into its
 ;;;    <padding to dual-word boundary>
 ;;;    start of instructions
 ;;;    ...
-;;;    function-headers and lra's buried in here randomly
+;;;    fun-headers and lra's buried in here randomly
 ;;;    ...
 ;;;    start of trace-table
 ;;;    <padding to dual-word boundary>
 \f
 (defstruct (offs-hook (:copier nil))
   (offset 0 :type offset)
-  (function (required-argument) :type function)
+  (fun (missing-arg) :type function)
   (before-address nil :type (member t nil)))
 
 (defstruct (segment (:conc-name seg-)
                    (:constructor %make-segment)
                    (:copier nil))
-  (sap-maker (required-argument)
+  (sap-maker (missing-arg)
             :type (function () sb!sys:system-area-pointer))
-  (length 0 :type length)
+  (length 0 :type disassem-length)
   (virtual-location 0 :type address)
   (storage-info nil :type (or null storage-info))
   (code nil :type (or null sb!kernel:code-component))
 (def!method print-object ((seg segment) stream)
   (print-unreadable-object (seg stream :type t)
     (let ((addr (sb!sys:sap-int (funcall (seg-sap-maker seg)))))
-      (format stream "#X~X[~D]~:[ (#X~X)~;~*~]~@[ in ~S~]"
+      (format stream "#X~X[~W]~:[ (#X~X)~;~*~]~@[ in ~S~]"
              addr
              (seg-length seg)
              (= (seg-virtual-location seg) addr)
              (seg-virtual-location seg)
              (seg-code seg)))))
 \f
-;;; All state during disassembly. We store some seemingly redundant
-;;; information so that we can allow garbage collect during disassembly and
-;;; not get tripped up by a code block being moved...
-(defstruct (disassem-state (:conc-name dstate-)
-                          (:constructor %make-dstate)
-                          (:copier nil))
-  (cur-offs 0 :type offset)            ; offset of current pos in segment
-  (next-offs 0 :type offset)           ; offset of next position
-
-  (segment-sap (required-argument) :type sb!sys:system-area-pointer)
-                                       ; a sap pointing to our segment
-  (segment nil :type (or null segment))        ; the current segment
-
-  (alignment sb!vm:word-bytes :type alignment) ; what to align to in most cases
-  (byte-order :little-endian
-             :type (member :big-endian :little-endian))
-
-  (properties nil :type list)          ; for user code to hang stuff off of
-  (filtered-values (make-array max-filtered-value-index)
-                  :type filtered-value-vector)
-
-  (addr-print-len nil :type            ; used for prettifying printing
-                 (or null (integer 0 20)))
-  (argument-column 0 :type column)
-  (output-state :beginning             ; to make output look nicer
-               :type (member :beginning
-                             :block-boundary
-                             nil))
-
-  (labels nil :type list)              ; alist of (address . label-number)
-  (label-hash (make-hash-table)                ; same thing in a different form
-             :type hash-table)
-
-  (fun-hooks nil :type list)           ; list of function
-
-  ;; these next two are popped as they are used
-  (cur-labels nil :type list)          ; alist of (address . label-number)
-  (cur-offs-hooks nil :type list)      ; list of offs-hook
-
-  (notes nil :type list)               ; for the current location
-
-  (current-valid-locations nil         ; currently active source variables
-                          :type (or null (vector bit))))
-(def!method print-object ((dstate disassem-state) stream)
-  (print-unreadable-object (dstate stream :type t)
-    (format stream
-           "+~D~@[ in ~S~]"
-           (dstate-cur-offs dstate)
-           (dstate-segment dstate))))
-
-;;; Return the absolute address of the current instruction in DSTATE.
-(defun dstate-cur-addr (dstate)
-  (the address (+ (seg-virtual-location (dstate-segment dstate))
-                 (dstate-cur-offs dstate))))
-
-;;; Return the absolute address of the next instruction in DSTATE.
-(defun dstate-next-addr (dstate)
-  (the address (+ (seg-virtual-location (dstate-segment dstate))
-                 (dstate-next-offs dstate))))
-\f
 ;;;; function ops
 
 (defun fun-self (fun)
   (declare (type compiled-function fun))
   (sb!kernel:%simple-fun-next fun))
 
-(defun fun-address (function)
-  (declare (type compiled-function function))
-  (- (sb!kernel:get-lisp-obj-address function) sb!vm:fun-pointer-lowtag))
+(defun fun-address (fun)
+  (declare (type compiled-function fun))
+  (ecase (sb!kernel:widetag-of fun)
+    (#.sb!vm:simple-fun-header-widetag
+     (- (sb!kernel:get-lisp-obj-address fun) sb!vm:fun-pointer-lowtag))
+    (#.sb!vm:closure-header-widetag
+     (fun-address (sb!kernel:%closure-fun fun)))
+    (#.sb!vm:funcallable-instance-header-widetag
+     (fun-address (sb!kernel:funcallable-instance-fun fun)))))
 
 ;;; the offset of FUNCTION from the start of its code-component's
 ;;; instruction area
   (declare (type sb!kernel:code-component code-component))
   (sb!sys:sap-int (sb!kernel:code-instructions code-component)))
 
+;;; unused as of sbcl-0.pre7.129
+#|
 ;;; Return the first function in CODE-COMPONENT.
 (defun code-first-function (code-component)
   (declare (type sb!kernel:code-component code-component))
   (sb!kernel:code-header-ref code-component
                             sb!vm:code-trace-table-offset-slot))
+|#
 
 (defun segment-offs-to-code-offs (offset segment)
   (sb!sys:without-gcing
           (type disassem-state dstate))
   (when (and (aligned-p (+ (seg-virtual-location (dstate-segment dstate))
                           (dstate-cur-offs dstate))
-                       (* 2 sb!vm:word-bytes))
+                       (* 2 sb!vm:n-word-bytes))
             ;; Check type.
             (= (sb!sys:sap-ref-8 (dstate-segment-sap dstate)
                                  (if (eq (dstate-byte-order dstate)
                                      (dstate-cur-offs dstate)
                                      (+ (dstate-cur-offs dstate)
                                         (1- lra-size))))
-               sb!vm:return-pc-header-type))
+               sb!vm:return-pc-header-widetag))
     (unless (null stream)
-      (princ '.lra stream))
-    (incf (dstate-next-offs dstate) lra-size))
+      (note "possible LRA header" dstate)))
   nil)
 
-;;; Print the function-header (entry-point) pseudo-instruction at the
+;;; Print the fun-header (entry-point) pseudo-instruction at the
 ;;; current location in DSTATE to STREAM.
 (defun fun-header-hook (stream dstate)
   (declare (type (or null stream) stream)
        (alignment (dstate-alignment dstate)))
     (unless (aligned-p location alignment)
       (when stream
-       (format stream "~A~Vt~D~%" '.align
+       (format stream "~A~Vt~W~%" '.align
                (dstate-argument-column dstate)
                alignment))
       (incf(dstate-next-offs dstate)
   (setf (dstate-cur-offs dstate) 0)
   (setf (dstate-cur-labels dstate) (dstate-labels dstate)))
 
-(defun do-offs-hooks (before-address stream dstate)
+(defun call-offs-hooks (before-address stream dstate)
   (declare (type (or null stream) stream)
           (type disassem-state dstate))
   (let ((cur-offs (dstate-cur-offs dstate)))
                         (not (offs-hook-before-address next-hook))))
            (return))
          (unless (< hook-offs cur-offs)
-           (funcall (offs-hook-function next-hook) stream dstate))
+           (funcall (offs-hook-fun next-hook) stream dstate))
          (pop (dstate-cur-offs-hooks dstate))
          (unless (= (dstate-next-offs dstate) cur-offs)
            (return)))))))
 
-(defun do-fun-hooks (chunk stream dstate)
+(defun call-fun-hooks (chunk stream dstate)
   (let ((hooks (dstate-fun-hooks dstate))
        (cur-offs (dstate-cur-offs dstate)))
     (setf (dstate-next-offs dstate) cur-offs)
   (let ((alignment (dstate-alignment dstate)))
     (unless (null stream)
       (multiple-value-bind (words bytes)
-         (truncate alignment sb!vm:word-bytes)
+         (truncate alignment sb!vm:n-word-bytes)
        (when (> words 0)
          (print-words words stream dstate))
        (when (> bytes 0)
 
       (setf (dstate-next-offs dstate) (dstate-cur-offs dstate))
 
-      (do-offs-hooks t stream dstate)
+      (call-offs-hooks t stream dstate)
       (unless (or prefix-p (null stream))
        (print-current-address stream dstate))
-      (do-offs-hooks nil stream dstate)
+      (call-offs-hooks nil stream dstate)
 
       (unless (> (dstate-next-offs dstate) (dstate-cur-offs dstate))
        (sb!sys:without-gcing
                (sap-ref-dchunk (dstate-segment-sap dstate)
                                (dstate-cur-offs dstate)
                                (dstate-byte-order dstate))))
-          (let ((fun-prefix-p (do-fun-hooks chunk stream dstate)))
+          (let ((fun-prefix-p (call-fun-hooks chunk stream dstate)))
             (if (> (dstate-next-offs dstate) (dstate-cur-offs dstate))
                 (setf prefix-p fun-prefix-p)
                 (let ((inst (find-inst chunk ispace)))
            (incf max)
            (setf (cdr label) max)
            (setf (gethash (car label) label-hash)
-                 (format nil "L~D" max)))))
+                 (format nil "L~W" max)))))
       (setf (dstate-labels dstate) labels))))
 \f
 ;;; Get the instruction-space, creating it if necessary.
        (when (or (null label-location) (> label-location location))
          (return))
        (unless (< label-location location)
-         (format stream " L~D:" (cdr next-label)))
+         (format stream " L~W:" (cdr next-label)))
        (pop (dstate-cur-labels dstate))))
 
     ;; move to the instruction column
       (unless (zerop word-offs)
        (write-string ", " stream))
       (let ((word 0) (bit-shift 0))
-       (dotimes (byte-offs sb!vm:word-bytes)
+       (dotimes (byte-offs sb!vm:n-word-bytes)
          (let ((byte
                 (sb!sys:sap-ref-8
                        sap
                        (+ start-offs
-                          (* word-offs sb!vm:word-bytes)
+                          (* word-offs sb!vm:n-word-bytes)
                           byte-offs))))
            (setf word
                  (if (eq byte-order :big-endian)
-                     (+ (ash word sb!vm:byte-bits) byte)
+                     (+ (ash word sb!vm:n-byte-bits) byte)
                      (+ word (ash byte bit-shift))))
-           (incf bit-shift sb!vm:byte-bits)))
-       (format stream "#X~V,'0X" (ash sb!vm:word-bits -2) word)))))
+           (incf bit-shift sb!vm:n-byte-bits)))
+       (format stream "#X~V,'0X" (ash sb!vm:n-word-bits -2) word)))))
 \f
 (defvar *default-dstate-hooks* (list #'lra-hook))
 
       ((null fun))
     (let ((offset (code-offs-to-segment-offs (fun-offset fun) segment)))
       (when (<= 0 offset length)
-       (push (make-offs-hook :offset offset :function #'fun-header-hook)
+       (push (make-offs-hook :offset offset :fun #'fun-header-hook)
              (seg-hooks segment))))))
 \f
 ;;; A SAP-MAKER is a no-argument function that returns a SAP.
                     debug-fun source-form-cache
                     hooks)
   (declare (type (function () sb!sys:system-area-pointer) sap-maker)
-          (type length length)
+          (type disassem-length length)
           (type (or null address) virtual-location)
           (type (or null sb!di:debug-fun) debug-fun)
           (type (or null source-form-cache) source-form-cache))
       (let ((fun-offset (sb!kernel:get-closure-length fun)))
        ;; There is function header fun-offset words from the
        ;; code header.
-       (format t "Fun-header ~S at offset ~D (words): ~S~A => ~S~%"
+       (format t "Fun-header ~S at offset ~W (words): ~S~A => ~S~%"
                fun
                fun-offset
                (sb!kernel:code-header-ref
 (defstruct (source-form-cache (:conc-name sfcache-)
                              (:copier nil))
   (debug-source nil :type (or null sb!di:debug-source))
-  (top-level-form-index -1 :type fixnum)
-  (top-level-form nil :type list)
+  (toplevel-form-index -1 :type fixnum)
+  (toplevel-form nil :type list)
   (form-number-mapping-table nil :type (or null (vector list)))
   (last-location-retrieved nil :type (or null sb!di:code-location))
   (last-form-retrieved -1 :type fixnum))
 
-(defun get-top-level-form (debug-source tlf-index)
+(defun get-toplevel-form (debug-source tlf-index)
   (let ((name (sb!di:debug-source-name debug-source)))
     (ecase (sb!di:debug-source-from debug-source)
       (:file
                                  (file-position f char-offset))
                                 (t
                                  (warn "Source file ~S has been modified; ~@
-                                        using form offset instead of file index."
+                                        using form offset instead of ~
+                                         file index."
                                        name)
                                  (let ((*read-suppress* t))
                                    (dotimes (i local-tlf-index) (read f)))))
   (and cache
        (and (eq (sb!di:code-location-debug-source loc)
                (sfcache-debug-source cache))
-           (eq (sb!di:code-location-top-level-form-offset loc)
-               (sfcache-top-level-form-index cache)))))
+           (eq (sb!di:code-location-toplevel-form-offset loc)
+               (sfcache-toplevel-form-index cache)))))
 
 (defun get-source-form (loc context &optional cache)
   (let* ((cache-valid (cache-valid loc cache))
-        (tlf-index (sb!di:code-location-top-level-form-offset loc))
+        (tlf-index (sb!di:code-location-toplevel-form-offset loc))
         (form-number (sb!di:code-location-form-number loc))
-        (top-level-form
+        (toplevel-form
          (if cache-valid
-             (sfcache-top-level-form cache)
-             (get-top-level-form (sb!di:code-location-debug-source loc)
+             (sfcache-toplevel-form cache)
+             (get-toplevel-form (sb!di:code-location-debug-source loc)
                                  tlf-index)))
         (mapping-table
          (if cache-valid
              (sfcache-form-number-mapping-table cache)
-             (sb!di:form-number-translations top-level-form tlf-index))))
+             (sb!di:form-number-translations toplevel-form tlf-index))))
     (when (and (not cache-valid) cache)
       (setf (sfcache-debug-source cache) (sb!di:code-location-debug-source loc)
-           (sfcache-top-level-form-index cache) tlf-index
-           (sfcache-top-level-form cache) top-level-form
+           (sfcache-toplevel-form-index cache) tlf-index
+           (sfcache-toplevel-form cache) toplevel-form
            (sfcache-form-number-mapping-table cache) mapping-table))
-    (cond ((null top-level-form)
+    (cond ((null toplevel-form)
           nil)
          ((> form-number (length mapping-table))
           (warn "bogus form-number in form!  The source file has probably ~@
                  been changed too much to cope with.")
           (when cache
             ;; Disable future warnings.
-            (setf (sfcache-top-level-form cache) nil))
+            (setf (sfcache-toplevel-form cache) nil))
           nil)
          (t
           (when cache
             (setf (sfcache-last-location-retrieved cache) loc)
             (setf (sfcache-last-form-retrieved cache) form-number))
-          (sb!di:source-path-context top-level-form
+          (sb!di:source-path-context toplevel-form
                                      (aref mapping-table form-number)
                                      context)))))
 
       (values nil nil)
       (values (get-source-form loc context cache) t)))
 \f
-;;;; stuff to use debugging-info to augment the disassembly
+;;;; stuff to use debugging info to augment the disassembly
 
 (defun code-fun-map (code)
   (declare (type sb!kernel:code-component code))
-  (sb!di::get-debug-info-fun-map (sb!kernel:%code-debug-info code)))
+  (sb!c::compiled-debug-info-fun-map (sb!kernel:%code-debug-info code)))
 
 (defstruct (location-group (:copier nil))
   (locations #() :type (vector (or list fixnum))))
                                      :debug-vars debug-vars))
           (let ((debug-var (aref debug-vars debug-var-offset)))
             #+nil
-            (format t ";;; At offset ~D: ~S~%" debug-var-offset debug-var)
+            (format t ";;; At offset ~W: ~S~%" debug-var-offset debug-var)
             (let* ((sc-offset
                     (sb!di::compiled-debug-var-sc-offset debug-var))
                    (sb-name
                      (sb!c:sc-sb (aref sc-vec
                                        (sb!c:sc-offset-scn sc-offset))))))
               #+nil
-              (format t ";;; SET: ~S[~D]~%"
+              (format t ";;; SET: ~S[~W]~%"
                       sb-name (sb!c:sc-offset-offset sc-offset))
               (unless (null sb-name)
                 (let ((group (cdr (assoc sb-name groups))))
   (let ((last-block-pc -1))
     (flet ((add-hook (pc fun &optional before-address)
             (push (make-offs-hook
-                   :offset pc ;; ##### FIX to account for non-zero offs in code
-                   :function fun
+                   :offset pc ;; ### FIX to account for non-zero offs in code
+                   :fun fun
                    :before-address before-address)
                   (seg-hooks segment))))
       (handler-case
                              (when stream
                                (unless at-block-begin
                                  (terpri stream))
-                               (format stream ";;; [~D] "
+                               (format stream ";;; [~W] "
                                        (sb!di:code-location-form-number
                                         loc))
                                (prin1-short form stream)
          (storage-info-for-debug-fun debug-fun))
     (add-source-tracking-hooks segment debug-fun sfcache)
     (let ((kind (sb!di:debug-fun-kind debug-fun)))
-      (flet ((anh (n)
+      (flet ((add-new-hook (n)
               (push (make-offs-hook
                      :offset 0
-                     :function (lambda (stream dstate)
-                                 (declare (ignore stream))
-                                 (note n dstate)))
+                     :fun (lambda (stream dstate)
+                            (declare (ignore stream))
+                            (note n dstate)))
                     (seg-hooks segment))))
        (case kind
          (:external)
          ((nil)
-          (anh "no-arg-parsing entry point"))
+          (add-new-hook "no-arg-parsing entry point"))
          (t
-          (anh (lambda (stream)
-                 (format stream "~S entry point" kind)))))))))
+          (add-new-hook (lambda (stream)
+                          (format stream "~S entry point" kind)))))))))
 \f
 ;;; Return a list of the segments of memory containing machine code
 ;;; instructions for FUNCTION.
-(defun get-function-segments (function)
+(defun get-fun-segments (function)
   (declare (type compiled-function function))
   (let* ((code (fun-code function))
         (fun-map (code-fun-map code))
               (let ((name (sb!c::compiled-debug-fun-name fmap-entry))
                     (kind (sb!c::compiled-debug-fun-kind fmap-entry)))
                 #+nil
-                (format t ";;; SAW ~S ~S ~S,~S ~D,~D~%"
+                (format t ";;; SAW ~S ~S ~S,~S ~W,~W~%"
                         name kind first-block-seen-p nil-block-seen-p
                         last-offset
                         (sb!c::compiled-debug-fun-start-pc fmap-entry))
                        (when first-block-seen-p
                          (setf nil-block-seen-p t))))
                 (setf last-debug-fun
-                      (sb!di::make-compiled-debug-fun fmap-entry code))
-                )))))
+                      (sb!di::make-compiled-debug-fun fmap-entry code)))))))
        (let ((max-offset (code-inst-area-length code)))
          (when (and first-block-seen-p last-debug-fun)
            (add-seg last-offset
                     last-debug-fun))
          (if (null segments)
              (let ((offs (fun-insts-offset function)))
-               (make-code-segment code offs (- max-offset offs)))
+               (list 
+                (make-code-segment code offs (- max-offset offs))))
              (nreverse segments)))))))
 
 ;;; Return a list of the segments of memory containing machine code
                          (length (code-inst-area-length code)))
   (declare (type sb!kernel:code-component code)
           (type offset start-offset)
-          (type length length))
+          (type disassem-length length))
   (let ((segments nil))
     (when code
       (let ((fun-map (code-fun-map code))
       (dolist (seg segments)
        (disassemble-segment seg stream dstate)))))
 \f
-;;;; top-level functions
+;;;; top level functions
 
 ;;; Disassemble the machine code instructions for FUNCTION.
-(defun disassemble-function (function &key
-                                     (stream *standard-output*)
-                                     (use-labels t))
-  (declare (type compiled-function function)
+(defun disassemble-fun (fun &key
+                           (stream *standard-output*)
+                           (use-labels t))
+  (declare (type compiled-function fun)
           (type stream stream)
           (type (member t nil) use-labels))
   (let* ((dstate (make-dstate))
-        (segments (get-function-segments function)))
+        (segments (get-fun-segments fun)))
     (when use-labels
       (label-segments segments dstate))
     (disassemble-segments segments stream dstate)))
 
+;;; FIXME: We probably don't need this any more now that there are
+;;; no interpreted functions, only compiled ones.
 (defun compile-function-lambda-expr (function)
   (declare (type function function))
   (multiple-value-bind (lambda closurep name)
       (error "can't compile a lexical closure"))
     (compile nil lambda)))
 
-(defun compiled-function-or-lose (thing &optional (name thing))
-  (cond ((or (symbolp thing)
-            (and (listp thing)
-                 (eq (car thing) 'setf)))
-        (compiled-function-or-lose (fdefinition thing) thing))
+(defun compiled-fun-or-lose (thing &optional (name thing))
+  (cond ((legal-fun-name-p thing)
+        (compiled-fun-or-lose (fdefinition thing) thing))
        ((functionp thing)
         thing)
        ((and (listp thing)
           (type (or (member t) stream) stream)
           (type (member t nil) use-labels))
   (pprint-logical-block (*standard-output* nil :per-line-prefix "; ")
-    (disassemble-function (compiled-function-or-lose object)
-                         :stream stream
-                         :use-labels use-labels)
+    (disassemble-fun (compiled-fun-or-lose object)
+                    :stream stream
+                    :use-labels use-labels)
     nil))
 
 ;;; Disassembles the given area of memory starting at ADDRESS and
                           code-component
                           (use-labels t))
   (declare (type (or address sb!sys:system-area-pointer) address)
-          (type length length)
+          (type disassem-length length)
           (type stream stream)
           (type (or null sb!kernel:code-component) code-component)
           (type (member t nil) use-labels))
 \f
 ;;; routines to find things in the Lisp environment
 
-;;; an alist of (SYMBOL-SLOT-OFFSET . ACCESS-FUNCTION-NAME) for slots
+;;; an alist of (SYMBOL-SLOT-OFFSET . ACCESS-FUN-NAME) for slots
 ;;; in a symbol object that we know about
 (defparameter *grokked-symbol-slots*
   (sort `((,sb!vm:symbol-value-slot . symbol-value)
 ;;; access function of the slot.
 (defun grok-symbol-slot-ref (address)
   (declare (type address address))
-  (if (not (aligned-p address sb!vm:word-bytes))
+  (if (not (aligned-p address sb!vm:n-word-bytes))
       (values nil nil)
       (do ((slots-tail *grokked-symbol-slots* (cdr slots-tail)))
          ((null slots-tail)
                      assoc-with
                      (sb!di:debug-var-symbol
                       (aref (dstate-debug-vars dstate)
-                            storage-location))
-                     stream))
+                            storage-location))))
            dstate)
       t)))
 \f