1 | |
---|
2 | ;; Raw outlines of a graphViz tool to visualize the instruction graph of ABCL generated code. |
---|
3 | ;; and the associated stack depths. |
---|
4 | |
---|
5 | (defvar *graph* nil) |
---|
6 | |
---|
7 | (declaim (ftype (function (t) t) branch-opcode-p)) |
---|
8 | (declaim (inline branch-opcode-p)) |
---|
9 | (defun branch-opcode-p (opcode) |
---|
10 | (declare (optimize speed)) |
---|
11 | (declare (type '(integer 0 255) opcode)) |
---|
12 | (or (<= 153 opcode 168) |
---|
13 | (= opcode 198))) |
---|
14 | |
---|
15 | (declaim (ftype (function (t t t) t) walk-code)) |
---|
16 | (defun walk-code (code start-index depth last-instruction) |
---|
17 | (declare (optimize speed)) |
---|
18 | (declare (type fixnum start-index depth)) |
---|
19 | (do* ((i start-index (1+ i)) |
---|
20 | (limit (length code))) |
---|
21 | ((>= i limit)) |
---|
22 | (declare (type fixnum i limit)) |
---|
23 | (let* ((instruction (aref code i)) |
---|
24 | (instruction-depth (jvm::instruction-depth instruction)) |
---|
25 | (instruction-stack (jvm::instruction-stack instruction)) |
---|
26 | (this-instruction (format nil "i~A" i))) |
---|
27 | (declare (type fixnum instruction-stack)) |
---|
28 | (format t "~A ~A~%" last-instruction this-instruction) |
---|
29 | (push (list last-instruction this-instruction depth) *graph*) |
---|
30 | (setf last-instruction this-instruction) |
---|
31 | (when instruction-depth |
---|
32 | (unless (= (the fixnum instruction-depth) |
---|
33 | (the fixnum (+ depth instruction-stack))) |
---|
34 | (internal-compiler-error |
---|
35 | "Stack inconsistency detected in ~A at index ~D: found ~S, expected ~S." |
---|
36 | (compiland-name *current-compiland*) |
---|
37 | i instruction-depth (+ depth instruction-stack)) |
---|
38 | (return-from walk-code))) |
---|
39 | (let ((opcode (jvm::instruction-opcode instruction))) |
---|
40 | (setf depth (+ depth instruction-stack)) |
---|
41 | (setf (jvm::instruction-depth instruction) depth) |
---|
42 | (when (branch-opcode-p opcode) |
---|
43 | (let ((label (car (jvm::instruction-args instruction)))) |
---|
44 | (declare (type symbol label)) |
---|
45 | (walk-code code (symbol-value label) depth this-instruction))) |
---|
46 | (when (member opcode '(167 176 191)) ; GOTO ARETURN ATHROW |
---|
47 | ;; Current path ends. |
---|
48 | (return-from walk-code)))))) |
---|
49 | |
---|
50 | (declaim (ftype (function () t) analyze-stack)) |
---|
51 | (defun analyze-stack () |
---|
52 | (declare (optimize speed)) |
---|
53 | (let* ((code *code*) |
---|
54 | (code-length (length code))) |
---|
55 | (declare (type vector code)) |
---|
56 | (dotimes (i code-length) |
---|
57 | (declare (type (unsigned-byte 16) i)) |
---|
58 | (let* ((instruction (aref code i)) |
---|
59 | (opcode (jvm::instruction-opcode instruction))) |
---|
60 | (when (eql opcode 202) ; LABEL |
---|
61 | (let ((label (car (jvm::instruction-args instruction)))) |
---|
62 | (set label i))) |
---|
63 | (if (jvm::instruction-stack instruction) |
---|
64 | (when (jvm::opcode-stack-effect opcode) |
---|
65 | (unless (eql (jvm::instruction-stack instruction) |
---|
66 | (jvm::opcode-stack-effect opcode)) |
---|
67 | (sys::%format t "instruction-stack = ~S opcode-stack-effect = ~S~%" |
---|
68 | (jvm::instruction-stack instruction) |
---|
69 | (jvm::opcode-stack-effect opcode)) |
---|
70 | (sys::%format t "index = ~D instruction = ~A~%" i |
---|
71 | (jvm::print-instruction instruction)))) |
---|
72 | (setf (jvm::instruction-stack instruction) |
---|
73 | (jvm::opcode-stack-effect opcode))) |
---|
74 | (unless (jvm::instruction-stack instruction) |
---|
75 | (sys::%format t "no stack information for instruction ~D~%" |
---|
76 | (jvm::instruction-opcode instruction)) |
---|
77 | (aver nil)))) |
---|
78 | (walk-code code 0 0 (gensym)) |
---|
79 | (dolist (handler *handlers*) |
---|
80 | ;; Stack depth is always 1 when handler is called. |
---|
81 | (walk-code code (symbol-value (jvm::handler-code handler)) 1 (gensym))) |
---|
82 | (let ((max-stack 0)) |
---|
83 | (declare (type fixnum max-stack)) |
---|
84 | (dotimes (i code-length) |
---|
85 | (declare (type (unsigned-byte 16) i)) |
---|
86 | (let* ((instruction (aref code i)) |
---|
87 | (instruction-depth (jvm::instruction-depth instruction))) |
---|
88 | (when instruction-depth |
---|
89 | (setf max-stack (max max-stack (the fixnum instruction-depth)))))) |
---|
90 | ;; (when *compiler-debug* |
---|
91 | ;; (sys::%format t "compiland name = ~S~%" (compiland-name *current-compiland*)) |
---|
92 | ;; (sys::%format t "max-stack = ~D~%" max-stack) |
---|
93 | ;; (sys::%format t "----- after stack analysis -----~%") |
---|
94 | ;; (print-code)) |
---|
95 | max-stack))) |
---|
96 | |
---|
97 | |
---|
98 | (defvar *code*) |
---|
99 | (defvar *handlers*) |
---|
100 | (compile nil '(lambda () nil)) |
---|
101 | (setq *handlers* nil) |
---|
102 | (setq *code* nil) |
---|
103 | (setq jvm::*saved-code* nil) |
---|
104 | (setq jvm::*compiler-debug* t) |
---|
105 | (defun f () |
---|
106 | (let ((stream (make-string-input-stream "f" 0))) |
---|
107 | (read-line stream) |
---|
108 | (lambda () |
---|
109 | (return-from f)))) |
---|
110 | (ignore-errors (compile 'f)) |
---|
111 | |
---|
112 | (setq *graph* nil) |
---|
113 | (let ((*code* (coerce (car jvm::*saved-code*) 'vector)) |
---|
114 | (*handlers* (car jvm::*saved-handlers*))) |
---|
115 | (analyze-stack)) |
---|
116 | (with-open-file (f #p"g.gvz" :direction :output :if-exists :supersede) |
---|
117 | (format f "digraph main {~%") |
---|
118 | (dolist (e *graph*) |
---|
119 | (format f "~A -> ~A [label=\"~A\"];~%" |
---|
120 | (first e) (second e) (third e))) |
---|
121 | (let ((*code* (coerce (car jvm::*saved-code*) 'vector))) |
---|
122 | (dotimes (i (length *code*)) |
---|
123 | (format f "i~A [label=\"~A:~A\"]~%" i i |
---|
124 | (jvm::opcode-name (jvm::instruction-opcode (aref *code* i)))))) |
---|
125 | (format f "}~%")) |
---|
126 | |
---|