code-grapher.lisp 5.13 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126

;; Raw outlines of a graphViz tool to visualize the instruction graph of ABCL generated code.
;;  and the associated stack depths.

(defvar *graph* nil)

(declaim (ftype (function (t) t) branch-opcode-p))
(declaim (inline branch-opcode-p))
(defun branch-opcode-p (opcode)
  (declare (optimize speed))
  (declare (type '(integer 0 255) opcode))
  (or (<= 153 opcode 168)
      (= opcode 198)))

(declaim (ftype (function (t t t) t) walk-code))
(defun walk-code (code start-index depth last-instruction)
  (declare (optimize speed))
  (declare (type fixnum start-index depth))
  (do* ((i start-index (1+ i))
        (limit (length code)))
       ((>= i limit))
    (declare (type fixnum i limit))
    (let* ((instruction (aref code i))
           (instruction-depth (jvm::instruction-depth instruction))
           (instruction-stack (jvm::instruction-stack instruction))
           (this-instruction (format nil "i~A" i)))
      (declare (type fixnum instruction-stack))
      (format t "~A ~A~%" last-instruction this-instruction)
      (push (list last-instruction  this-instruction depth) *graph*)
      (setf last-instruction this-instruction)
      (when instruction-depth
        (unless (= (the fixnum instruction-depth)
                   (the fixnum (+ depth instruction-stack)))
          (internal-compiler-error 
           "Stack inconsistency detected in ~A at index ~D: found ~S, expected ~S." 
           (compiland-name *current-compiland*)
           i instruction-depth (+ depth instruction-stack))
          (return-from walk-code)))
      (let ((opcode (jvm::instruction-opcode instruction)))
        (setf depth (+ depth instruction-stack))
        (setf (jvm::instruction-depth instruction) depth)
        (when (branch-opcode-p opcode)
          (let ((label (car (jvm::instruction-args instruction))))
            (declare (type symbol label))
            (walk-code code (symbol-value label) depth this-instruction)))
        (when (member opcode '(167 176 191)) ; GOTO ARETURN ATHROW
          ;; Current path ends.
          (return-from walk-code))))))

(declaim (ftype (function () t) analyze-stack))
(defun analyze-stack ()
  (declare (optimize speed))
  (let* ((code *code*)
         (code-length (length code)))
    (declare (type vector code))
    (dotimes (i code-length)
      (declare (type (unsigned-byte 16) i))
      (let* ((instruction (aref code i))
             (opcode (jvm::instruction-opcode instruction)))
        (when (eql opcode 202) ; LABEL
          (let ((label (car (jvm::instruction-args instruction))))
            (set label i)))
        (if (jvm::instruction-stack instruction)
            (when (jvm::opcode-stack-effect opcode)
              (unless (eql (jvm::instruction-stack instruction)
                           (jvm::opcode-stack-effect opcode))
                (sys::%format t "instruction-stack = ~S opcode-stack-effect = ~S~%"
                         (jvm::instruction-stack instruction)
                         (jvm::opcode-stack-effect opcode))
                (sys::%format t "index = ~D instruction = ~A~%" i
                              (jvm::print-instruction instruction))))
            (setf (jvm::instruction-stack instruction)
                  (jvm::opcode-stack-effect opcode)))
        (unless (jvm::instruction-stack instruction)
          (sys::%format t "no stack information for instruction ~D~%"
                        (jvm::instruction-opcode instruction))
          (aver nil))))
    (walk-code code 0 0 (gensym))
    (dolist (handler *handlers*)
      ;; Stack depth is always 1 when handler is called.
      (walk-code code (symbol-value (jvm::handler-code handler)) 1 (gensym)))
    (let ((max-stack 0))
      (declare (type fixnum max-stack))
      (dotimes (i code-length)
        (declare (type (unsigned-byte 16) i))
        (let* ((instruction (aref code i))
               (instruction-depth (jvm::instruction-depth instruction)))
          (when instruction-depth
            (setf max-stack (max max-stack (the fixnum instruction-depth))))))
;;       (when *compiler-debug*
;;         (sys::%format t "compiland name = ~S~%" (compiland-name *current-compiland*))
;;         (sys::%format t "max-stack = ~D~%" max-stack)
;;         (sys::%format t "----- after stack analysis -----~%")
;;         (print-code))
      max-stack)))


(defvar *code*)
(defvar *handlers*)
(compile nil '(lambda () nil))
(setq *handlers* nil)
(setq *code* nil)
(setq jvm::*saved-code* nil)
(setq jvm::*compiler-debug* t)
(defun f ()
  (let ((stream (make-string-input-stream "f" 0)))
    (read-line stream)
    (lambda () 
      (return-from f))))
(ignore-errors  (compile 'f))

(setq *graph* nil)
(let ((*code* (coerce (car jvm::*saved-code*) 'vector))
      (*handlers* (car jvm::*saved-handlers*)))
  (analyze-stack))
(with-open-file (f #p"g.gvz" :direction :output :if-exists :supersede)
  (format f "digraph main {~%")
  (dolist (e *graph*)
    (format f "~A -> ~A [label=\"~A\"];~%"
            (first e) (second e) (third e)))
  (let ((*code* (coerce (car jvm::*saved-code*) 'vector)))
    (dotimes (i (length *code*))
      (format f "i~A [label=\"~A:~A\"]~%" i i
              (jvm::opcode-name (jvm::instruction-opcode (aref *code* i))))))
  (format f "}~%"))