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