source: branches/generic-class-file/abcl/src/org/armedbear/lisp/jvm-instructions.lisp @ 12877

Last change on this file since 12877 was 12877, checked in by ehuelsmann, 13 years ago

Optimization functions optimize in tight loops, optimize for speed.
Also, remove iterator variable type declarations: our inferencer
knows their type.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 34.0 KB
Line 
1;;; jvm-instructions.lisp
2;;;
3;;; Copyright (C) 2003-2006 Peter Graves
4;;; $Id: jvm-instructions.lisp 12877 2010-08-08 13:16:53Z ehuelsmann $
5;;;
6;;; This program is free software; you can redistribute it and/or
7;;; modify it under the terms of the GNU General Public License
8;;; as published by the Free Software Foundation; either version 2
9;;; of the License, or (at your option) any later version.
10;;;
11;;; This program is distributed in the hope that it will be useful,
12;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
13;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14;;; GNU General Public License for more details.
15;;;
16;;; You should have received a copy of the GNU General Public License
17;;; along with this program; if not, write to the Free Software
18;;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19;;;
20;;; As a special exception, the copyright holders of this library give you
21;;; permission to link this library with independent modules to produce an
22;;; executable, regardless of the license terms of these independent
23;;; modules, and to copy and distribute the resulting executable under
24;;; terms of your choice, provided that you also meet, for each linked
25;;; independent module, the terms and conditions of the license of that
26;;; module.  An independent module is a module which is not derived from
27;;; or based on this library.  If you modify this library, you may extend
28;;; this exception to your version of the library, but you are not
29;;; obligated to do so.  If you do not wish to do so, delete this
30;;; exception statement from your version.
31
32(in-package #:jvm)
33
34
35;;    OPCODES
36
37(defconst *opcode-table* (make-array 256))
38
39(defconst *opcodes* (make-hash-table :test 'equalp))
40
41(defstruct jvm-opcode name number size stack-effect)
42
43(defun %define-opcode (name number size stack-effect)
44  (declare (type fixnum number size))
45  (let* ((name (string name))
46         (opcode (make-jvm-opcode :name name
47                                  :number number
48                                  :size size
49                                  :stack-effect stack-effect)))
50     (setf (svref *opcode-table* number) opcode)
51     (setf (gethash name *opcodes*) opcode)
52     (setf (gethash number *opcodes*) opcode)))
53
54(defmacro define-opcode (name number size stack-effect)
55  `(%define-opcode ',name ,number ,size ,stack-effect))
56
57;; name number size stack-effect (nil if unknown)
58(define-opcode nop 0 1 0)
59(define-opcode aconst_null 1 1 1)
60(define-opcode iconst_m1 2 1 1)
61(define-opcode iconst_0 3 1 1)
62(define-opcode iconst_1 4 1 1)
63(define-opcode iconst_2 5 1 1)
64(define-opcode iconst_3 6 1 1)
65(define-opcode iconst_4 7 1 1)
66(define-opcode iconst_5 8 1 1)
67(define-opcode lconst_0 9 1 2)
68(define-opcode lconst_1 10 1 2)
69(define-opcode fconst_0 11 1 1)
70(define-opcode fconst_1 12 1 1)
71(define-opcode fconst_2 13 1 1)
72(define-opcode dconst_0 14 1 2)
73(define-opcode dconst_1 15 1 2)
74(define-opcode bipush 16 2 1)
75(define-opcode sipush 17 3 1)
76(define-opcode ldc 18 2 1)
77(define-opcode ldc_w 19 3 1)
78(define-opcode ldc2_w 20 3 2)
79(define-opcode iload 21 2 1)
80(define-opcode lload 22 2 2)
81(define-opcode fload 23 2 nil)
82(define-opcode dload 24 2 nil)
83(define-opcode aload 25 2 1)
84(define-opcode iload_0 26 1 1)
85(define-opcode iload_1 27 1 1)
86(define-opcode iload_2 28 1 1)
87(define-opcode iload_3 29 1 1)
88(define-opcode lload_0 30 1 2)
89(define-opcode lload_1 31 1 2)
90(define-opcode lload_2 32 1 2)
91(define-opcode lload_3 33 1 2)
92(define-opcode fload_0 34 1 nil)
93(define-opcode fload_1 35 1 nil)
94(define-opcode fload_2 36 1 nil)
95(define-opcode fload_3 37 1 nil)
96(define-opcode dload_0 38 1 nil)
97(define-opcode dload_1 39 1 nil)
98(define-opcode dload_2 40 1 nil)
99(define-opcode dload_3 41 1 nil)
100(define-opcode aload_0 42 1 1)
101(define-opcode aload_1 43 1 1)
102(define-opcode aload_2 44 1 1)
103(define-opcode aload_3 45 1 1)
104(define-opcode iaload 46 1 -1)
105(define-opcode laload 47 1 0)
106(define-opcode faload 48 1 -1)
107(define-opcode daload 49 1 0)
108(define-opcode aaload 50 1 -1)
109(define-opcode baload 51 1 nil)
110(define-opcode caload 52 1 nil)
111(define-opcode saload 53 1 nil)
112(define-opcode istore 54 2 -1)
113(define-opcode lstore 55 2 -2)
114(define-opcode fstore 56 2 nil)
115(define-opcode dstore 57 2 nil)
116(define-opcode astore 58 2 -1)
117(define-opcode istore_0 59 1 -1)
118(define-opcode istore_1 60 1 -1)
119(define-opcode istore_2 61 1 -1)
120(define-opcode istore_3 62 1 -1)
121(define-opcode lstore_0 63 1 -2)
122(define-opcode lstore_1 64 1 -2)
123(define-opcode lstore_2 65 1 -2)
124(define-opcode lstore_3 66 1 -2)
125(define-opcode fstore_0 67 1 nil)
126(define-opcode fstore_1 68 1 nil)
127(define-opcode fstore_2 69 1 nil)
128(define-opcode fstore_3 70 1 nil)
129(define-opcode dstore_0 71 1 nil)
130(define-opcode dstore_1 72 1 nil)
131(define-opcode dstore_2 73 1 nil)
132(define-opcode dstore_3 74 1 nil)
133(define-opcode astore_0 75 1 -1)
134(define-opcode astore_1 76 1 -1)
135(define-opcode astore_2 77 1 -1)
136(define-opcode astore_3 78 1 -1)
137(define-opcode iastore 79 1 -3)
138(define-opcode lastore 80 1 -4)
139(define-opcode fastore 81 1 -3)
140(define-opcode dastore 82 1 -4)
141(define-opcode aastore 83 1 -3)
142(define-opcode bastore 84 1 nil)
143(define-opcode castore 85 1 nil)
144(define-opcode sastore 86 1 nil)
145(define-opcode pop 87 1 -1)
146(define-opcode pop2 88 1 -2)
147(define-opcode dup 89 1 1)
148(define-opcode dup_x1 90 1 1)
149(define-opcode dup_x2 91 1 1)
150(define-opcode dup2 92 1 2)
151(define-opcode dup2_x1 93 1 2)
152(define-opcode dup2_x2 94 1 2)
153(define-opcode swap 95 1 0)
154(define-opcode iadd 96 1 -1)
155(define-opcode ladd 97 1 -2)
156(define-opcode fadd 98 1 -1)
157(define-opcode dadd 99 1 -2)
158(define-opcode isub 100 1 -1)
159(define-opcode lsub 101 1 -2)
160(define-opcode fsub 102 1 -1)
161(define-opcode dsub 103 1 -2)
162(define-opcode imul 104 1 -1)
163(define-opcode lmul 105 1 -2)
164(define-opcode fmul 106 1 -1)
165(define-opcode dmul 107 1 -2)
166(define-opcode idiv 108 1 nil)
167(define-opcode ldiv 109 1 nil)
168(define-opcode fdiv 110 1 nil)
169(define-opcode ddiv 111 1 nil)
170(define-opcode irem 112 1 nil)
171(define-opcode lrem 113 1 nil)
172(define-opcode frem 114 1 nil)
173(define-opcode drem 115 1 nil)
174(define-opcode ineg 116 1 0)
175(define-opcode lneg 117 1 0)
176(define-opcode fneg 118 1 0)
177(define-opcode dneg 119 1 0)
178(define-opcode ishl 120 1 -1)
179(define-opcode lshl 121 1 -1)
180(define-opcode ishr 122 1 -1)
181(define-opcode lshr 123 1 -1)
182(define-opcode iushr 124 1 nil)
183(define-opcode lushr 125 1 nil)
184(define-opcode iand 126 1 -1)
185(define-opcode land 127 1 -2)
186(define-opcode ior 128 1 -1)
187(define-opcode lor 129 1 -2)
188(define-opcode ixor 130 1 -1)
189(define-opcode lxor 131 1 -2)
190(define-opcode iinc 132 3 0)
191(define-opcode i2l 133 1 1)
192(define-opcode i2f 134 1 0)
193(define-opcode i2d 135 1 1)
194(define-opcode l2i 136 1 -1)
195(define-opcode l2f 137 1 -1)
196(define-opcode l2d 138 1 0)
197(define-opcode f2i 139 1 nil)
198(define-opcode f2l 140 1 nil)
199(define-opcode f2d 141 1 1)
200(define-opcode d2i 142 1 nil)
201(define-opcode d2l 143 1 nil)
202(define-opcode d2f 144 1 -1)
203(define-opcode i2b 145 1 nil)
204(define-opcode i2c 146 1 nil)
205(define-opcode i2s 147 1 nil)
206(define-opcode lcmp 148 1 -3)
207(define-opcode fcmpl 149 1 -1)
208(define-opcode fcmpg 150 1 -1)
209(define-opcode dcmpl 151 1 -3)
210(define-opcode dcmpg 152 1 -3)
211(define-opcode ifeq 153 3 -1)
212(define-opcode ifne 154 3 -1)
213(define-opcode iflt 155 3 -1)
214(define-opcode ifge 156 3 -1)
215(define-opcode ifgt 157 3 -1)
216(define-opcode ifle 158 3 -1)
217(define-opcode if_icmpeq 159 3 -2)
218(define-opcode if_icmpne 160 3 -2)
219(define-opcode if_icmplt 161 3 -2)
220(define-opcode if_icmpge 162 3 -2)
221(define-opcode if_icmpgt 163 3 -2)
222(define-opcode if_icmple 164 3 -2)
223(define-opcode if_acmpeq 165 3 -2)
224(define-opcode if_acmpne 166 3 -2)
225(define-opcode goto 167 3 0)
226;;(define-opcode jsr 168 3 1) Don't use these 2 opcodes: deprecated
227;;(define-opcode ret 169 2 0) their use results in JVM verifier errors
228(define-opcode tableswitch 170 0 nil)
229(define-opcode lookupswitch 171 0 nil)
230(define-opcode ireturn 172 1 nil)
231(define-opcode lreturn 173 1 nil)
232(define-opcode freturn 174 1 nil)
233(define-opcode dreturn 175 1 nil)
234(define-opcode areturn 176 1 -1)
235(define-opcode return 177 1 0)
236(define-opcode getstatic 178 3 1)
237(define-opcode putstatic 179 3 -1)
238(define-opcode getfield 180 3 0)
239(define-opcode putfield 181 3 -2)
240(define-opcode invokevirtual 182 3 nil)
241(define-opcode invokespecial 183 3 nil)
242(define-opcode invokestatic 184 3 nil)
243(define-opcode invokeinterface 185 5 nil)
244(define-opcode unused 186 0 nil)
245(define-opcode new 187 3 1)
246(define-opcode newarray 188 2 nil)
247(define-opcode anewarray 189 3 0)
248(define-opcode arraylength 190 1 0)
249(define-opcode athrow 191 1 0)
250(define-opcode checkcast 192 3 0)
251(define-opcode instanceof 193 3 0)
252(define-opcode monitorenter 194 1 -1)
253(define-opcode monitorexit 195 1 -1)
254(define-opcode wide 196 0 nil)
255(define-opcode multianewarray 197 4 nil)
256(define-opcode ifnull 198 3 -1)
257(define-opcode ifnonnull 199 3 nil)
258(define-opcode goto_w 200 5 nil)
259;; (define-opcode jsr_w 201 5 nil) Don't use: deprecated
260(define-opcode label 202 0 0)  ;; virtual: does not exist in the JVM
261;; (define-opcode push-value 203 nil 1)
262;; (define-opcode store-value 204 nil -1)
263(define-opcode clear-values 205 0 0)  ;; virtual: does not exist in the JVM
264;;(define-opcode var-ref 206 0 0)
265
266(defparameter *last-opcode* 206)
267
268(declaim (ftype (function (t) t) opcode-name))
269(defun opcode-name (opcode-number)
270  (let ((opcode (gethash opcode-number *opcodes*)))
271    (and opcode (jvm-opcode-name opcode))))
272
273(declaim (ftype (function (t) (integer 0 255)) opcode-number))
274(defun opcode-number (opcode-name)
275  (declare (optimize speed))
276  (let ((opcode (gethash (string opcode-name) *opcodes*)))
277    (if opcode
278        (jvm-opcode-number opcode)
279        (error "Unknown opcode ~S." opcode-name))))
280
281(declaim (ftype (function (t) fixnum) opcode-size))
282(defun opcode-size (opcode-number)
283  (declare (optimize speed (safety 0)))
284  (declare (type (integer 0 255) opcode-number))
285  (jvm-opcode-size (svref *opcode-table* opcode-number)))
286
287(declaim (ftype (function (t) t) opcode-stack-effect))
288(defun opcode-stack-effect (opcode-number)
289  (declare (optimize speed))
290  (jvm-opcode-stack-effect (svref *opcode-table* opcode-number)))
291
292
293
294
295;;   INSTRUCTION
296
297(defstruct (instruction (:constructor %make-instruction (opcode args)))
298  (opcode 0 :type (integer 0 255))
299  args
300  stack
301  depth
302  wide)
303
304(defun make-instruction (opcode args)
305  (let ((inst (apply #'%make-instruction
306                     (list opcode
307                           (remove :wide-prefix args)))))
308    (when (memq :wide-prefix args)
309      (setf (inst-wide inst) t))
310    inst))
311
312(defun print-instruction (instruction)
313  (sys::%format nil "~A ~A stack = ~S depth = ~S"
314          (opcode-name (instruction-opcode instruction))
315          (instruction-args instruction)
316          (instruction-stack instruction)
317          (instruction-depth instruction)))
318
319(declaim (ftype (function (t) t) instruction-label))
320(defun instruction-label (instruction)
321  (and instruction
322       (= (instruction-opcode (the instruction instruction)) 202)
323       (car (instruction-args instruction))))
324
325
326
327(defknown inst * t)
328(defun inst (instr &optional args)
329  (declare (optimize speed))
330  (let ((opcode (if (fixnump instr)
331                    instr
332                    (opcode-number instr))))
333    (unless (listp args)
334      (setf args (list args)))
335    (make-instruction opcode args)))
336
337
338;; Having %emit and %%emit output their code to *code*
339;; is currently an implementation detail exposed to all users.
340;; We need to have APIs to address this, but for now pass2 is
341;; our only user and we'll hard-code the use of *code*.
342(defvar *code* nil)
343
344(defknown %%emit * t)
345(defun %%emit (instr &rest args)
346  (declare (optimize speed))
347  (let ((instruction (make-instruction instr args)))
348    (push instruction *code*)
349    instruction))
350
351(defknown %emit * t)
352(defun %emit (instr &rest args)
353  (declare (optimize speed))
354  (let ((instruction (inst instr args)))
355    (push instruction *code*)
356    instruction))
357
358(defmacro emit (instr &rest args)
359  (when (and (consp instr)
360             (eq (car instr) 'QUOTE)
361             (symbolp (cadr instr)))
362    (setf instr (opcode-number (cadr instr))))
363  (if (fixnump instr)
364      `(%%emit ,instr ,@args)
365      `(%emit ,instr ,@args)))
366
367
368;;  Helper routines
369
370(defknown label (symbol) t)
371(defun label (symbol)
372  (declare (type symbol symbol))
373  (declare (optimize speed))
374  (emit 'label symbol)
375  (setf (symbol-value symbol) nil))
376
377(defknown aload (fixnum) t)
378(defun aload (index)
379  (case index
380    (0 (emit 'aload_0))
381    (1 (emit 'aload_1))
382    (2 (emit 'aload_2))
383    (3 (emit 'aload_3))
384    (t (emit 'aload index))))
385
386(defknown astore (fixnum) t)
387(defun astore (index)
388  (case index
389    (0 (emit 'astore_0))
390    (1 (emit 'astore_1))
391    (2 (emit 'astore_2))
392    (3 (emit 'astore_3))
393    (t (emit 'astore index))))
394
395(declaim (ftype (function (t) t) branch-p)
396         (inline branch-p))
397(defun branch-p (opcode)
398;;  (declare (optimize speed))
399;;  (declare (type '(integer 0 255) opcode))
400  (or (<= 153 opcode 167)
401      (<= 198 opcode 200))) ;; ifnull / ifnonnull / goto_w
402
403(declaim (ftype (function (t) t) unconditional-control-transfer-p)
404         (inline unconditional-control-transfer-p))
405(defun unconditional-control-transfer-p (opcode)
406  (or (= 167 opcode) ;; goto
407      (= 200 opcode) ;; goto_w
408      (<= 172 opcode 177) ;; ?return
409      (= 191 opcode) ;; athrow
410      ))
411
412(declaim (ftype (function (t) boolean) label-p)
413         (inline label-p))
414(defun label-p (instruction)
415  (and instruction
416       (= (the fixnum (instruction-opcode (the instruction instruction))) 202)))
417
418(defun print-code (code)
419  (dotimes (i (length code))
420    (let ((instruction (elt code i)))
421      (sys::%format t "~D ~A ~S ~S ~S~%"
422                    i
423                    (opcode-name (instruction-opcode instruction))
424                    (instruction-args instruction)
425                    (instruction-stack instruction)
426                    (instruction-depth instruction)))))
427
428(defun print-code2 (code)
429  (dotimes (i (length code))
430    (let ((instruction (elt code i)))
431      (case (instruction-opcode instruction)
432        (202 ; LABEL
433         (format t "~A:~%" (car (instruction-args instruction))))
434        (t
435         (format t "~8D:   ~A ~S~%"
436                 i
437                 (opcode-name (instruction-opcode instruction))
438                 (instruction-args instruction)))))))
439
440(defun expand-virtual-instructions (code)
441  (let* ((len (length code))
442         (vector (make-array (ash len 1) :fill-pointer 0 :adjustable t)))
443    (dotimes (index len vector)
444      (declare (type (unsigned-byte 16) index))
445      (let ((instruction (svref code index)))
446        (case (instruction-opcode instruction)
447          (205 ; CLEAR-VALUES
448           (dolist (instruction
449                     (list
450                      (inst 'aload *thread*)
451                      (inst 'aconst_null)
452                      (inst 'putfield (u2 (pool-field +lisp-thread+ "_values"
453                                                      +lisp-object-array+)))))
454             (vector-push-extend instruction vector)))
455          (t
456           (vector-push-extend instruction vector)))))))
457
458
459;;   RESOLVERS
460
461(defun unsupported-opcode (instruction)
462  (error "Unsupported opcode ~D." (instruction-opcode instruction)))
463
464(declaim (type hash-table +resolvers+))
465(defconst +resolvers+ (make-hash-table))
466
467(defun initialize-resolvers ()
468  (let ((ht +resolvers+))
469    (dotimes (n (1+ *last-opcode*))
470      (setf (gethash n ht) #'unsupported-opcode))
471    ;; The following opcodes resolve to themselves.
472    (dolist (n '(0 ; nop
473                 1 ; aconst_null
474                 2 ; iconst_m1
475                 3 ; iconst_0
476                 4 ; iconst_1
477                 5 ; iconst_2
478                 6 ; iconst_3
479                 7 ; iconst_4
480                 8 ; iconst_5
481                 9 ; lconst_0
482                 10 ; lconst_1
483                 11 ; fconst_0
484                 12 ; fconst_1
485                 13 ; fconst_2
486                 14 ; dconst_0
487                 15 ; dconst_1
488                 42 ; aload_0
489                 43 ; aload_1
490                 44 ; aload_2
491                 45 ; aload_3
492                 46 ; iaload
493                 47 ; laload
494                 48 ; faload
495                 49 ; daload
496                 50 ; aaload
497                 75 ; astore_0
498                 76 ; astore_1
499                 77 ; astore_2
500                 78 ; astore_3
501                 79 ; iastore
502                 80 ; lastore
503                 81 ; fastore
504                 82 ; dastore
505                 83 ; aastore
506                 87 ; pop
507                 88 ; pop2
508                 89 ; dup
509                 90 ; dup_x1
510                 91 ; dup_x2
511                 92 ; dup2
512                 93 ; dup2_x1
513                 94 ; dup2_x2
514                 95 ; swap
515                 96 ; iadd
516                 97 ; ladd
517                 98 ; fadd
518                 99 ; dadd
519                 100 ; isub
520                 101 ; lsub
521                 102 ; fsub
522                 103 ; dsub
523                 104 ; imul
524                 105 ; lmul
525                 106 ; fmul
526                 107 ; dmul
527                 116 ; ineg
528                 117 ; lneg
529                 118 ; fneg
530                 119 ; dneg
531                 120 ; ishl
532                 121 ; lshl
533                 122 ; ishr
534                 123 ; lshr
535                 126 ; iand
536                 127 ; land
537                 128 ; ior
538                 129 ; lor
539                 130 ; ixor
540                 131 ; lxor
541                 133 ; i2l
542                 134 ; i2f
543                 135 ; i2d
544                 136 ; l2i
545                 137 ; l2f
546                 138 ; l2d
547                 141 ; f2d
548                 144 ; d2f
549                 148 ; lcmp
550                 149 ; fcmpd
551                 150 ; fcmpg
552                 151 ; dcmpd
553                 152 ; dcmpg
554                 153 ; ifeq
555                 154 ; ifne
556                 155 ; ifge
557                 156 ; ifgt
558                 157 ; ifgt
559                 158 ; ifle
560                 159 ; if_icmpeq
561                 160 ; if_icmpne
562                 161 ; if_icmplt
563                 162 ; if_icmpge
564                 163 ; if_icmpgt
565                 164 ; if_icmple
566                 165 ; if_acmpeq
567                 166 ; if_acmpne
568                 167 ; goto
569                 176 ; areturn
570                 177 ; return
571                 178 ; getstatic
572                 179 ; putstatic
573                 180 ; getfield
574                 181 ; putfield
575                 182 ; invokevirtual
576                 183 ; invockespecial
577                 184 ; invokestatic
578                 187 ; new
579                 189 ; anewarray
580                 190 ; arraylength
581                 191 ; athrow
582                 192 ; checkcast
583                 193 ; instanceof
584                 194 ; monitorenter
585                 195 ; monitorexit
586                 198 ; ifnull
587                 202 ; label
588                 ))
589      (setf (gethash n ht) nil))))
590
591(initialize-resolvers)
592
593(defmacro define-resolver (opcodes args &body body)
594  (let ((name (gensym)))
595    `(progn
596       (defun ,name ,args ,@body)
597       (eval-when (:load-toplevel :execute)
598         ,(if (listp opcodes)
599              `(dolist (op ',opcodes)
600                 (setf (gethash op +resolvers+)
601                       (symbol-function ',name)))
602              `(setf (gethash ,opcodes +resolvers+)
603                     (symbol-function ',name)))))))
604
605(defun load/store-resolver (instruction inst-index inst-index2 error-text)
606 (let* ((args (instruction-args instruction))
607        (index (car args)))
608   (declare (type (unsigned-byte 16) index))
609   (cond ((<= 0 index 3)
610          (inst (+ index inst-index)))
611         ((<= 0 index 255)
612          (inst inst-index2 index))
613         (t
614          (error error-text)))))
615
616;; aload
617(define-resolver 25 (instruction)
618  (load/store-resolver instruction 42 25 "ALOAD unsupported case"))
619
620;; astore
621(define-resolver 58 (instruction)
622  (load/store-resolver instruction 75 58 "ASTORE unsupported case"))
623
624;; iload
625(define-resolver 21 (instruction)
626  (load/store-resolver instruction 26 21 "ILOAD unsupported case"))
627
628;; istore
629(define-resolver 54 (instruction)
630  (load/store-resolver instruction 59 54 "ISTORE unsupported case"))
631
632;; lload
633(define-resolver 22 (instruction)
634  (load/store-resolver instruction 30 22 "LLOAD unsupported case"))
635
636;; lstore
637(define-resolver 55 (instruction)
638  (load/store-resolver instruction 63 55 "LSTORE unsupported case"))
639
640;; bipush, sipush
641(define-resolver (16 17) (instruction)
642  (let* ((args (instruction-args instruction))
643         (n (first args)))
644    (declare (type fixnum n))
645    (cond ((<= 0 n 5)
646           (inst (+ n 3)))
647          ((<= -128 n 127)
648           (inst 16 (logand n #xff))) ; BIPUSH
649          (t ; SIPUSH
650           (inst 17 (s2 n))))))
651
652;; ldc
653(define-resolver 18 (instruction)
654  (let* ((args (instruction-args instruction)))
655    (unless (= (length args) 1)
656      (error "Wrong number of args for LDC."))
657    (if (> (car args) 255)
658        (inst 19 (u2 (car args))) ; LDC_W
659        (inst 18 args))))
660
661;; ldc2_w
662(define-resolver 20 (instruction)
663  (let* ((args (instruction-args instruction)))
664    (unless (= (length args) 1)
665      (error "Wrong number of args for LDC2_W."))
666    (inst 20 (u2 (car args)))))
667
668;; iinc
669(define-resolver 132 (instruction)
670  (let* ((args (instruction-args instruction))
671         (register (first args))
672         (n (second args)))
673    (when (not (<= -128 n 127))
674      (error "IINC argument ~A out of bounds." n))
675    (inst 132 (list register (s1 n)))))
676
677(defknown resolve-instruction (t) t)
678(defun resolve-instruction (instruction)
679  (declare (optimize speed))
680  (let ((resolver (gethash1 (instruction-opcode instruction) +resolvers+)))
681    (if resolver
682        (funcall resolver instruction)
683        instruction)))
684
685(defun resolve-instructions (code)
686  (let* ((len (length code))
687         (vector (make-array len :fill-pointer 0 :adjustable t)))
688    (dotimes (index len vector)
689      (declare (type (unsigned-byte 16) index))
690      (let ((instruction (aref code index)))
691        (vector-push-extend (resolve-instruction instruction) vector)))))
692
693
694
695;; BYTE CODE ANALYSIS AND OPTIMIZATION
696
697(declaim (ftype (function (t t t) t) analyze-stack-path))
698(defun analyze-stack-path (code start-index depth)
699  (declare (optimize speed))
700  (declare (type fixnum start-index depth))
701  (do* ((i start-index (1+ i))
702        (limit (length code)))
703       ((>= i limit))
704    (declare (type fixnum i limit))
705    (let* ((instruction (aref code i))
706           (instruction-depth (instruction-depth instruction))
707           (instruction-stack (instruction-stack instruction)))
708      (declare (type fixnum instruction-stack))
709      (when instruction-depth
710        (unless (= (the fixnum instruction-depth)
711                   (the fixnum (+ depth instruction-stack)))
712          (internal-compiler-error "Stack inconsistency detected ~
713                                    in ~A at index ~D: ~
714                                    found ~S, expected ~S."
715                                   (compiland-name *current-compiland*)
716                                   i instruction-depth
717                                   (+ depth instruction-stack)))
718        (return-from analyze-stack-path))
719      (let ((opcode (instruction-opcode instruction)))
720        (setf depth (+ depth instruction-stack))
721        (setf (instruction-depth instruction) depth)
722        (when (branch-p opcode)
723          (let ((label (car (instruction-args instruction))))
724            (declare (type symbol label))
725            (analyze-stack-path code (symbol-value label) depth)))
726        (when (unconditional-control-transfer-p opcode)
727          ;; Current path ends.
728          (return-from analyze-stack-path))))))
729
730(declaim (ftype (function (t) t) analyze-stack))
731(defun analyze-stack (code exception-entry-points)
732  (declare (optimize speed))
733  (let* ((code-length (length code)))
734    (declare (type vector code))
735    (dotimes (i code-length)
736      (let* ((instruction (aref code i))
737             (opcode (instruction-opcode instruction)))
738        (when (eql opcode 202) ; LABEL
739          (let ((label (car (instruction-args instruction))))
740            (set label i)))
741        (if (instruction-stack instruction)
742            (when (opcode-stack-effect opcode)
743              (unless (eql (instruction-stack instruction)
744                           (opcode-stack-effect opcode))
745                (sys::%format t "instruction-stack = ~S ~
746                                 opcode-stack-effect = ~S~%"
747                              (instruction-stack instruction)
748                              (opcode-stack-effect opcode))
749                (sys::%format t "index = ~D instruction = ~A~%" i
750                              (print-instruction instruction))))
751            (setf (instruction-stack instruction)
752                  (opcode-stack-effect opcode)))
753        (unless (instruction-stack instruction)
754          (sys::%format t "no stack information for instruction ~D~%"
755                        (instruction-opcode instruction))
756          (aver nil))))
757    (analyze-stack-path code 0 0)
758    (dolist (entry-point exception-entry-points)
759      ;; Stack depth is always 1 when handler is called.
760      (analyze-stack-path code (symbol-value entry-point) 1))
761    (let ((max-stack 0))
762      (declare (type fixnum max-stack))
763      (dotimes (i code-length)
764        (let* ((instruction (aref code i))
765               (instruction-depth (instruction-depth instruction)))
766          (when instruction-depth
767            (setf max-stack (max max-stack (the fixnum instruction-depth))))))
768      max-stack)))
769
770
771(defun delete-unused-labels (code handler-labels)
772  (declare (optimize speed))
773  (let ((code (coerce code 'vector))
774        (changed nil)
775        (marker (gensym)))
776    ;; Mark the labels that are actually branched to.
777    (dotimes (i (length code))
778      (let ((instruction (aref code i)))
779        (when (branch-p (instruction-opcode instruction))
780          (let ((label (car (instruction-args instruction))))
781            (set label marker)))))
782    ;; Add labels used for exception handlers.
783    (dolist (label handler-labels)
784      (set label marker))
785    ;; Remove labels that are not used as branch targets.
786    (dotimes (i (length code))
787      (let ((instruction (aref code i)))
788        (when (= (instruction-opcode instruction) 202) ; LABEL
789          (let ((label (car (instruction-args instruction))))
790            (declare (type symbol label))
791            (unless (eq (symbol-value label) marker)
792              (setf (aref code i) nil)
793              (setf changed t))))))
794    (values (if changed (delete nil code) code)
795            changed)))
796
797(defun delete-unreachable-code (code)
798  ;; Look for unreachable code after GOTO.
799  (declare (optimize speed))
800  (let* ((code (coerce code 'vector))
801         (changed nil)
802         (after-goto/areturn nil))
803    (dotimes (i (length code))
804      (declare (type (unsigned-byte 16) i))
805      (let* ((instruction (aref code i))
806             (opcode (instruction-opcode instruction)))
807        (cond (after-goto/areturn
808               (if (= opcode 202) ; LABEL
809                   (setf after-goto/areturn nil)
810                   ;; Unreachable.
811                   (progn
812                     (setf (aref code i) nil)
813                     (setf changed t))))
814              ((unconditional-control-transfer-p opcode)
815               (setf after-goto/areturn t)))))
816    (values (if changed (delete nil code) code)
817            changed)))
818
819
820(declaim (ftype (function (t) label-target-instructions) hash-labels))
821(defun label-target-instructions (code)
822  (let ((ht (make-hash-table :test 'eq))
823        (code (coerce code 'vector))
824        (pending-labels '()))
825    (dotimes (i (length code))
826      (let ((instruction (aref code i)))
827        (cond ((label-p instruction)
828               (push (instruction-label instruction) pending-labels))
829              (t
830               ;; Not a label.
831               (when pending-labels
832                 (dolist (label pending-labels)
833                   (setf (gethash label ht) instruction))
834                 (setf pending-labels nil))))))
835    ht))
836
837(defun optimize-jumps (code)
838  (declare (optimize speed))
839  (let* ((code (coerce code 'vector))
840         (ht (label-target-instructions code))
841         (changed nil))
842    (dotimes (i (length code))
843      (let* ((instruction (aref code i))
844             (opcode (and instruction (instruction-opcode instruction))))
845        (when (and opcode (branch-p opcode))
846          (let* ((target-label (car (instruction-args instruction)))
847                 (next-instruction (gethash1 target-label ht)))
848            (when next-instruction
849              (case (instruction-opcode next-instruction)
850                ((167 200)                  ;; GOTO
851                 (setf (instruction-args instruction)
852                       (instruction-args next-instruction)
853                       changed t))
854                (176 ; ARETURN
855                 (when (unconditional-control-transfer-p opcode)
856                   (setf (instruction-opcode instruction) 176
857                         (instruction-args instruction) nil
858                         changed t)))))))))
859    (values code changed)))
860
861
862(defun optimize-instruction-sequences (code)
863  (let* ((code (coerce code 'vector))
864         (changed nil))
865    (dotimes (i (1- (length code)))
866      (let* ((this-instruction (aref code i))
867             (this-opcode (and this-instruction
868                               (instruction-opcode this-instruction)))
869             (labels-skipped-p nil)
870             (next-instruction (do ((j (1+ i) (1+ j)))
871                                   ((or (>= j (length code))
872                                        (/= 202 ; LABEL
873                                            (instruction-opcode (aref code j))))
874                                    (when (< j (length code))
875                                      (aref code j)))
876                                 (setf labels-skipped-p t)))
877             (next-opcode (and next-instruction
878                               (instruction-opcode next-instruction))))
879        (case this-opcode
880          (205 ; CLEAR-VALUES
881           (when (eql next-opcode 205)       ; CLEAR-VALUES
882             (setf (aref code i) nil)
883             (setf changed t)))
884          (178 ; GETSTATIC
885           (when (and (eql next-opcode 87)   ; POP
886                      (not labels-skipped-p))
887             (setf (aref code i) nil)
888             (setf (aref code (1+ i)) nil)
889             (setf changed t)))
890          (176 ; ARETURN
891           (when (eql next-opcode 176)       ; ARETURN
892             (setf (aref code i) nil)
893             (setf changed t)))
894          ((200 167)                         ; GOTO GOTO_W
895           (when (and (or (eql next-opcode 202)  ; LABEL
896                          (eql next-opcode 200)  ; GOTO_W
897                          (eql next-opcode 167)) ; GOTO
898                      (eq (car (instruction-args this-instruction))
899                          (car (instruction-args next-instruction))))
900             (setf (aref code i) nil)
901             (setf changed t))))))
902    (values (if changed (delete nil code) code)
903            changed)))
904
905(defvar *enable-optimization* t)
906
907(defknown optimize-code (t t) t)
908(defun optimize-code (code handler-labels)
909  (unless *enable-optimization*
910    (format t "optimizations are disabled~%"))
911  (when *enable-optimization*
912    (when *compiler-debug*
913      (format t "----- before optimization -----~%")
914      (print-code code))
915    (loop
916       (let ((changed-p nil))
917         (multiple-value-setq
918             (code changed-p)
919           (delete-unused-labels code handler-labels))
920         (if changed-p
921             (setf code (optimize-instruction-sequences code))
922             (multiple-value-setq
923                 (code changed-p)
924               (optimize-instruction-sequences code)))
925         (if changed-p
926             (setf code (optimize-jumps code))
927             (multiple-value-setq
928                 (code changed-p)
929               (optimize-jumps code)))
930         (if changed-p
931             (setf code (delete-unreachable-code code))
932             (multiple-value-setq
933                 (code changed-p)
934               (delete-unreachable-code code)))
935         (unless changed-p
936           (return))))
937    (unless (vectorp code)
938      (setf code (coerce code 'vector)))
939    (when *compiler-debug*
940      (sys::%format t "----- after optimization -----~%")
941      (print-code code)))
942  code)
943
944
945
946
947(defun code-bytes (code)
948  (let ((length 0)
949        labels ;; alist
950        )
951    (declare (type (unsigned-byte 16) length))
952    ;; Pass 1: calculate label offsets and overall length.
953    (dotimes (i (length code))
954      (declare (type (unsigned-byte 16) i))
955      (let* ((instruction (aref code i))
956             (opcode (instruction-opcode instruction)))
957        (if (= opcode 202) ; LABEL
958            (let ((label (car (instruction-args instruction))))
959              (set label length)
960              (setf labels
961                    (acons label length labels)))
962            (incf length (opcode-size opcode)))))
963    ;; Pass 2: replace labels with calculated offsets.
964    (let ((index 0))
965      (declare (type (unsigned-byte 16) index))
966      (dotimes (i (length code))
967        (declare (type (unsigned-byte 16) i))
968        (let ((instruction (aref code i)))
969          (when (branch-p (instruction-opcode instruction))
970            (let* ((label (car (instruction-args instruction)))
971                   (offset (- (the (unsigned-byte 16)
972                                (symbol-value (the symbol label)))
973                              index)))
974              (setf (instruction-args instruction) (s2 offset))))
975          (unless (= (instruction-opcode instruction) 202) ; LABEL
976            (incf index (opcode-size (instruction-opcode instruction)))))))
977    ;; Expand instructions into bytes, skipping LABEL pseudo-instructions.
978    (let ((bytes (make-array length))
979          (index 0))
980      (declare (type (unsigned-byte 16) index))
981      (dotimes (i (length code))
982        (declare (type (unsigned-byte 16) i))
983        (let ((instruction (aref code i)))
984          (unless (= (instruction-opcode instruction) 202) ; LABEL
985            (setf (svref bytes index) (instruction-opcode instruction))
986            (incf index)
987            (dolist (byte (instruction-args instruction))
988              (setf (svref bytes index) byte)
989              (incf index)))))
990      (values bytes labels))))
991
992(defun finalize-code (code handler-labels optimize)
993  (setf code (coerce (nreverse code) 'vector))
994  (when optimize
995    (setf code (optimize-code code handler-labels)))
996  (resolve-instructions (expand-virtual-instructions code)))
997
998(provide '#:opcodes)
Note: See TracBrowser for help on using the repository browser.