1 package io.jawk.intermediate;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 import java.io.PrintStream;
26 import java.io.Serializable;
27 import java.util.ArrayDeque;
28 import java.util.ArrayList;
29 import java.util.Arrays;
30 import java.util.Collections;
31 import java.util.Deque;
32 import java.util.HashMap;
33 import java.util.HashSet;
34 import java.util.IdentityHashMap;
35 import java.util.List;
36 import java.util.Map;
37 import java.util.Set;
38 import java.util.function.Supplier;
39 import java.util.regex.Pattern;
40 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
41 import io.jawk.ext.ExtensionFunction;
42 import io.jawk.jrt.JRT;
43
44
45
46
47
48
49
50
51 public class AwkTuples implements Serializable {
52
53 private static final long serialVersionUID = 2L;
54
55
56 private final AddressManager addressManager = new AddressManager();
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73 private List<Tuple> queue = new ArrayList<Tuple>(100) {
74 private static final long serialVersionUID = -6334362156408598578L;
75
76 @Override
77 public boolean add(Tuple t) {
78 t.setLineNumber(linenoStack.peek());
79 return super.add(t);
80 }
81 };
82
83
84 private boolean postProcessed;
85
86
87 private boolean optimized;
88
89
90 private boolean evalTupleStream;
91
92
93
94
95
96
97
98
99
100 public static String toOpcodeString(int opcode) {
101 return Opcode.fromId(opcode).name();
102 }
103
104
105
106
107
108
109 public void pop() {
110 queue.add(new Tuple.NoOperandTuple(Opcode.POP));
111 }
112
113
114
115
116
117
118
119
120 public void push(Object o) {
121 if (o instanceof String) {
122 queue.add(new Tuple.PushStringTuple(o.toString()));
123 } else if (o instanceof Integer) {
124 queue.add(new Tuple.PushLongTuple((long) (Integer) o));
125 } else if (o instanceof Long) {
126 queue.add(new Tuple.PushLongTuple((long) (Long) o));
127 } else if (o instanceof Double) {
128 queue.add(new Tuple.PushDoubleTuple((Double) o));
129 }
130 }
131
132
133
134
135
136
137
138
139 public void ifFalse(Address address) {
140 queue.add(new Tuple.AddressTuple(Opcode.IFFALSE, address));
141 }
142
143
144
145
146
147
148 public void toNumber() {
149 queue.add(new Tuple.NoOperandTuple(Opcode.TO_NUMBER));
150 }
151
152
153
154
155
156
157
158
159 public void ifTrue(Address address) {
160 queue.add(new Tuple.AddressTuple(Opcode.IFTRUE, address));
161 }
162
163
164
165
166
167
168
169
170 public void gotoAddress(Address address) {
171 queue.add(new Tuple.AddressTuple(Opcode.GOTO, address));
172 }
173
174
175
176
177
178
179
180
181
182 public Address createAddress(String label) {
183 return addressManager.createAddress(label);
184 }
185
186
187
188
189
190
191
192
193
194 public AwkTuples address(Address address) {
195 addressManager.resolveAddress(address, queue.size());
196 return this;
197 }
198
199
200
201
202
203
204 public void nop() {
205 queue.add(new Tuple.NoOperandTuple(Opcode.NOP));
206 }
207
208
209
210
211
212
213
214
215 public void print(int numExprs) {
216 queue.add(new Tuple.CountTuple(Opcode.PRINT, numExprs));
217 }
218
219
220
221
222
223
224
225
226
227 public void printToFile(int numExprs, boolean append) {
228 queue.add(new Tuple.CountAndAppendTuple(Opcode.PRINT_TO_FILE, numExprs, append));
229 }
230
231
232
233
234
235
236
237
238 public void printToPipe(int numExprs) {
239 queue.add(new Tuple.CountTuple(Opcode.PRINT_TO_PIPE, numExprs));
240 }
241
242
243
244
245
246
247
248
249 public void printf(int numExprs) {
250 queue.add(new Tuple.CountTuple(Opcode.PRINTF, numExprs));
251 }
252
253
254
255
256
257
258
259
260
261 public void printfToFile(int numExprs, boolean append) {
262 queue.add(new Tuple.CountAndAppendTuple(Opcode.PRINTF_TO_FILE, numExprs, append));
263 }
264
265
266
267
268
269
270
271
272 public void printfToPipe(int numExprs) {
273 queue.add(new Tuple.CountTuple(Opcode.PRINTF_TO_PIPE, numExprs));
274 }
275
276
277
278
279
280
281
282
283 public void sprintf(int numExprs) {
284 queue.add(new Tuple.CountTuple(Opcode.SPRINTF, numExprs));
285 }
286
287
288
289
290
291
292
293
294 public void length(int numExprs) {
295 queue.add(new Tuple.CountTuple(Opcode.LENGTH, numExprs));
296 }
297
298
299
300
301
302
303 public void concat() {
304 queue.add(new Tuple.NoOperandTuple(Opcode.CONCAT));
305 }
306
307
308
309
310
311
312
313
314
315 public void assign(int offset, boolean isGlobal) {
316 queue.add(new Tuple.VariableTuple(Opcode.ASSIGN, offset, isGlobal));
317 }
318
319
320
321
322
323
324
325
326
327 public void assignArray(int offset, boolean isGlobal) {
328 queue.add(new Tuple.VariableTuple(Opcode.ASSIGN_ARRAY, offset, isGlobal));
329 }
330
331
332
333
334 public void assignMapElement() {
335 queue.add(new Tuple.NoOperandTuple(Opcode.ASSIGN_MAP_ELEMENT));
336 }
337
338
339
340
341
342
343 public void assignAsInput() {
344 queue.add(new Tuple.NoOperandTuple(Opcode.ASSIGN_AS_INPUT));
345 }
346
347
348
349
350
351
352 public void markEvalTupleStream() {
353 evalTupleStream = true;
354 }
355
356
357
358
359
360
361 public void assignAsInputField() {
362 queue.add(new Tuple.NoOperandTuple(Opcode.ASSIGN_AS_INPUT_FIELD));
363 }
364
365
366
367
368
369
370
371
372
373
374 public void dereference(int offset, boolean isArray, boolean isGlobal) {
375 queue.add(new Tuple.DereferenceTuple(offset, isArray, isGlobal));
376 }
377
378
379
380
381
382
383
384
385
386 public void plusEq(int offset, boolean isGlobal) {
387 queue.add(new Tuple.CompoundAssignTuple(Opcode.PLUS_EQ, offset, isGlobal));
388 }
389
390
391
392
393
394
395
396
397
398 public void minusEq(int offset, boolean isGlobal) {
399 queue.add(new Tuple.CompoundAssignTuple(Opcode.MINUS_EQ, offset, isGlobal));
400 }
401
402
403
404
405
406
407
408
409
410 public void multEq(int offset, boolean isGlobal) {
411 queue.add(new Tuple.CompoundAssignTuple(Opcode.MULT_EQ, offset, isGlobal));
412 }
413
414
415
416
417
418
419
420
421
422 public void divEq(int offset, boolean isGlobal) {
423 queue.add(new Tuple.CompoundAssignTuple(Opcode.DIV_EQ, offset, isGlobal));
424 }
425
426
427
428
429
430
431
432
433
434 public void modEq(int offset, boolean isGlobal) {
435 queue.add(new Tuple.CompoundAssignTuple(Opcode.MOD_EQ, offset, isGlobal));
436 }
437
438
439
440
441
442
443
444
445
446 public void powEq(int offset, boolean isGlobal) {
447 queue.add(new Tuple.CompoundAssignTuple(Opcode.POW_EQ, offset, isGlobal));
448 }
449
450
451
452
453
454
455
456
457
458 public void plusEqArray(int offset, boolean isGlobal) {
459 queue.add(new Tuple.CompoundAssignArrayTuple(Opcode.PLUS_EQ_ARRAY, offset, isGlobal));
460 }
461
462
463
464
465 public void plusEqMapElement() {
466 queue.add(new Tuple.CompoundAssignMapElementTuple(Opcode.PLUS_EQ_MAP_ELEMENT));
467 }
468
469
470
471
472
473
474
475
476
477 public void minusEqArray(int offset, boolean isGlobal) {
478 queue.add(new Tuple.CompoundAssignArrayTuple(Opcode.MINUS_EQ_ARRAY, offset, isGlobal));
479 }
480
481
482
483
484 public void minusEqMapElement() {
485 queue.add(new Tuple.CompoundAssignMapElementTuple(Opcode.MINUS_EQ_MAP_ELEMENT));
486 }
487
488
489
490
491
492
493
494
495
496 public void multEqArray(int offset, boolean isGlobal) {
497 queue.add(new Tuple.CompoundAssignArrayTuple(Opcode.MULT_EQ_ARRAY, offset, isGlobal));
498 }
499
500
501
502
503 public void multEqMapElement() {
504 queue.add(new Tuple.CompoundAssignMapElementTuple(Opcode.MULT_EQ_MAP_ELEMENT));
505 }
506
507
508
509
510
511
512
513
514
515 public void divEqArray(int offset, boolean isGlobal) {
516 queue.add(new Tuple.CompoundAssignArrayTuple(Opcode.DIV_EQ_ARRAY, offset, isGlobal));
517 }
518
519
520
521
522 public void divEqMapElement() {
523 queue.add(new Tuple.CompoundAssignMapElementTuple(Opcode.DIV_EQ_MAP_ELEMENT));
524 }
525
526
527
528
529
530
531
532
533
534 public void modEqArray(int offset, boolean isGlobal) {
535 queue.add(new Tuple.CompoundAssignArrayTuple(Opcode.MOD_EQ_ARRAY, offset, isGlobal));
536 }
537
538
539
540
541 public void modEqMapElement() {
542 queue.add(new Tuple.CompoundAssignMapElementTuple(Opcode.MOD_EQ_MAP_ELEMENT));
543 }
544
545
546
547
548
549
550
551
552
553 public void powEqArray(int offset, boolean isGlobal) {
554 queue.add(new Tuple.CompoundAssignArrayTuple(Opcode.POW_EQ_ARRAY, offset, isGlobal));
555 }
556
557
558
559
560
561 public void powEqMapElement() {
562 queue.add(new Tuple.CompoundAssignMapElementTuple(Opcode.POW_EQ_MAP_ELEMENT));
563 }
564
565
566
567
568
569
570 public void plusEqInputField() {
571 queue.add(new Tuple.CompoundAssignInputFieldTuple(Opcode.PLUS_EQ_INPUT_FIELD));
572 }
573
574
575
576
577
578
579 public void minusEqInputField() {
580 queue.add(new Tuple.CompoundAssignInputFieldTuple(Opcode.MINUS_EQ_INPUT_FIELD));
581 }
582
583
584
585
586
587
588 public void multEqInputField() {
589 queue.add(new Tuple.CompoundAssignInputFieldTuple(Opcode.MULT_EQ_INPUT_FIELD));
590 }
591
592
593
594
595
596
597 public void divEqInputField() {
598 queue.add(new Tuple.CompoundAssignInputFieldTuple(Opcode.DIV_EQ_INPUT_FIELD));
599 }
600
601
602
603
604
605
606 public void modEqInputField() {
607 queue.add(new Tuple.CompoundAssignInputFieldTuple(Opcode.MOD_EQ_INPUT_FIELD));
608 }
609
610
611
612
613
614
615 public void powEqInputField() {
616 queue.add(new Tuple.CompoundAssignInputFieldTuple(Opcode.POW_EQ_INPUT_FIELD));
617 }
618
619
620
621
622
623
624
625
626 public void srand(int num) {
627 queue.add(new Tuple.CountTuple(Opcode.SRAND, num));
628 }
629
630
631
632
633
634
635 public void rand() {
636 queue.add(new Tuple.NoOperandTuple(Opcode.RAND));
637 }
638
639
640
641
642
643
644 public void intFunc() {
645 queue.add(new Tuple.NoOperandTuple(Opcode.INTFUNC));
646 }
647
648
649
650
651
652
653 public void sqrt() {
654 queue.add(new Tuple.NoOperandTuple(Opcode.SQRT));
655 }
656
657
658
659
660
661
662 public void log() {
663 queue.add(new Tuple.NoOperandTuple(Opcode.LOG));
664 }
665
666
667
668
669
670
671 public void exp() {
672 queue.add(new Tuple.NoOperandTuple(Opcode.EXP));
673 }
674
675
676
677
678
679
680 public void sin() {
681 queue.add(new Tuple.NoOperandTuple(Opcode.SIN));
682 }
683
684
685
686
687
688
689 public void cos() {
690 queue.add(new Tuple.NoOperandTuple(Opcode.COS));
691 }
692
693
694
695
696
697
698 public void atan2() {
699 queue.add(new Tuple.NoOperandTuple(Opcode.ATAN2));
700 }
701
702
703
704
705
706
707 public void match() {
708 queue.add(new Tuple.NoOperandTuple(Opcode.MATCH));
709 }
710
711
712
713
714
715
716 public void index() {
717 queue.add(new Tuple.NoOperandTuple(Opcode.INDEX));
718 }
719
720
721
722
723
724
725
726
727 public void subForDollar0(boolean isGsub) {
728 queue.add(new Tuple.BooleanTuple(Opcode.SUB_FOR_DOLLAR_0, isGsub));
729 }
730
731
732
733
734
735
736
737
738 public void subForDollarReference(boolean isGsub) {
739 queue.add(new Tuple.BooleanTuple(Opcode.SUB_FOR_DOLLAR_REFERENCE, isGsub));
740 }
741
742
743
744
745
746
747
748
749
750
751 public void subForVariable(int offset, boolean isGlobal, boolean isGsub) {
752 queue.add(new Tuple.SubstitutionVariableTuple(Opcode.SUB_FOR_VARIABLE, offset, isGlobal, isGsub));
753 }
754
755
756
757
758
759
760
761
762
763
764 public void subForArrayReference(int offset, boolean isGlobal, boolean isGsub) {
765 queue.add(new Tuple.SubstitutionVariableTuple(Opcode.SUB_FOR_ARRAY_REFERENCE, offset, isGlobal, isGsub));
766 }
767
768
769
770
771
772
773
774 public void subForMapReference(boolean isGsub) {
775 queue.add(new Tuple.BooleanTuple(Opcode.SUB_FOR_MAP_REFERENCE, isGsub));
776 }
777
778
779
780
781
782
783
784
785 public void split(int numargs) {
786 queue.add(new Tuple.CountTuple(Opcode.SPLIT, numargs));
787 }
788
789
790
791
792
793
794
795
796 public void substr(int numargs) {
797 queue.add(new Tuple.CountTuple(Opcode.SUBSTR, numargs));
798 }
799
800
801
802
803
804
805 public void tolower() {
806 queue.add(new Tuple.NoOperandTuple(Opcode.TOLOWER));
807 }
808
809
810
811
812
813
814 public void toupper() {
815 queue.add(new Tuple.NoOperandTuple(Opcode.TOUPPER));
816 }
817
818
819
820
821
822
823 public void system() {
824 queue.add(new Tuple.NoOperandTuple(Opcode.SYSTEM));
825 }
826
827
828
829
830
831
832 public void swap() {
833 queue.add(new Tuple.NoOperandTuple(Opcode.SWAP));
834 }
835
836
837
838
839
840
841 public void add() {
842 queue.add(new Tuple.NoOperandTuple(Opcode.ADD));
843 }
844
845
846
847
848
849
850 public void subtract() {
851 queue.add(new Tuple.NoOperandTuple(Opcode.SUBTRACT));
852 }
853
854
855
856
857
858
859 public void multiply() {
860 queue.add(new Tuple.NoOperandTuple(Opcode.MULTIPLY));
861 }
862
863
864
865
866
867
868 public void divide() {
869 queue.add(new Tuple.NoOperandTuple(Opcode.DIVIDE));
870 }
871
872
873
874
875
876
877 public void mod() {
878 queue.add(new Tuple.NoOperandTuple(Opcode.MOD));
879 }
880
881
882
883
884
885
886 public void pow() {
887 queue.add(new Tuple.NoOperandTuple(Opcode.POW));
888 }
889
890
891
892
893
894
895
896
897
898 public void inc(int offset, boolean isGlobal) {
899 queue.add(new Tuple.VariableTuple(Opcode.INC, offset, isGlobal));
900 }
901
902
903
904
905
906
907
908
909
910 public void dec(int offset, boolean isGlobal) {
911 queue.add(new Tuple.VariableTuple(Opcode.DEC, offset, isGlobal));
912 }
913
914
915
916
917
918
919
920
921
922 public void postInc(int offset, boolean isGlobal) {
923 queue.add(new Tuple.VariableTuple(Opcode.POSTINC, offset, isGlobal));
924 }
925
926
927
928
929
930
931
932
933
934 public void postDec(int offset, boolean isGlobal) {
935 queue.add(new Tuple.VariableTuple(Opcode.POSTDEC, offset, isGlobal));
936 }
937
938
939
940
941
942
943
944
945
946 public void incArrayRef(int offset, boolean isGlobal) {
947 queue.add(new Tuple.VariableTuple(Opcode.INC_ARRAY_REF, offset, isGlobal));
948 }
949
950
951
952
953 public void incMapRef() {
954 queue.add(new Tuple.NoOperandTuple(Opcode.INC_MAP_REF));
955 }
956
957
958
959
960
961
962
963
964
965 public void decArrayRef(int offset, boolean isGlobal) {
966 queue.add(new Tuple.VariableTuple(Opcode.DEC_ARRAY_REF, offset, isGlobal));
967 }
968
969
970
971
972 public void decMapRef() {
973 queue.add(new Tuple.NoOperandTuple(Opcode.DEC_MAP_REF));
974 }
975
976
977
978
979
980
981 public void incDollarRef() {
982 queue.add(new Tuple.NoOperandTuple(Opcode.INC_DOLLAR_REF));
983 }
984
985
986
987
988
989
990 public void decDollarRef() {
991 queue.add(new Tuple.NoOperandTuple(Opcode.DEC_DOLLAR_REF));
992 }
993
994
995
996
997
998
999 public void dup() {
1000 queue.add(new Tuple.NoOperandTuple(Opcode.DUP));
1001 }
1002
1003
1004
1005
1006
1007
1008 public void not() {
1009 queue.add(new Tuple.NoOperandTuple(Opcode.NOT));
1010 }
1011
1012
1013
1014
1015
1016
1017 public void negate() {
1018 queue.add(new Tuple.NoOperandTuple(Opcode.NEGATE));
1019 }
1020
1021
1022
1023
1024
1025
1026 public void unaryPlus() {
1027 queue.add(new Tuple.NoOperandTuple(Opcode.UNARY_PLUS));
1028 }
1029
1030
1031
1032
1033
1034
1035 public void cmpEq() {
1036 queue.add(new Tuple.NoOperandTuple(Opcode.CMP_EQ));
1037 }
1038
1039
1040
1041
1042
1043
1044 public void cmpLt() {
1045 queue.add(new Tuple.NoOperandTuple(Opcode.CMP_LT));
1046 }
1047
1048
1049
1050
1051
1052
1053 public void cmpGt() {
1054 queue.add(new Tuple.NoOperandTuple(Opcode.CMP_GT));
1055 }
1056
1057
1058
1059
1060
1061
1062 public void matches() {
1063 queue.add(new Tuple.NoOperandTuple(Opcode.MATCHES));
1064 }
1065
1066
1067
1068
1069
1070
1071 public void dereferenceArray() {
1072 queue.add(new Tuple.NoOperandTuple(Opcode.DEREF_ARRAY));
1073 }
1074
1075
1076
1077
1078
1079 public void peekArrayElement() {
1080 queue.add(new Tuple.NoOperandTuple(Opcode.PEEK_ARRAY_ELEMENT));
1081 }
1082
1083
1084
1085
1086
1087 public void ensureArrayElement() {
1088 queue.add(new Tuple.NoOperandTuple(Opcode.ENSURE_ARRAY_ELEMENT));
1089 }
1090
1091
1092
1093
1094
1095
1096 public void keylist() {
1097 queue.add(new Tuple.NoOperandTuple(Opcode.KEYLIST));
1098 }
1099
1100
1101
1102
1103
1104
1105
1106
1107 public void isEmptyList(Address address) {
1108 queue.add(new Tuple.AddressTuple(Opcode.IS_EMPTY_KEYLIST, address));
1109 }
1110
1111
1112
1113
1114
1115
1116 public void getFirstAndRemoveFromList() {
1117 queue.add(new Tuple.NoOperandTuple(Opcode.GET_FIRST_AND_REMOVE_FROM_KEYLIST));
1118 }
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128 public boolean checkClass(Class<?> cls) {
1129 queue.add(new Tuple.ClassTuple(cls));
1130 return true;
1131 }
1132
1133
1134
1135
1136
1137
1138 public void getInputField() {
1139 queue.add(new Tuple.NoOperandTuple(Opcode.GET_INPUT_FIELD));
1140 }
1141
1142
1143
1144
1145
1146
1147
1148
1149 public void getInputField(long fieldIndex) {
1150 queue.add(new Tuple.InputFieldTuple(fieldIndex));
1151 }
1152
1153
1154
1155
1156
1157
1158
1159
1160 public void consumeInput(Address address) {
1161 queue.add(new Tuple.AddressTuple(Opcode.CONSUME_INPUT, address));
1162 }
1163
1164
1165
1166
1167
1168
1169 public void getlineInput() {
1170 queue.add(new Tuple.NoOperandTuple(Opcode.GETLINE_INPUT));
1171 }
1172
1173
1174
1175
1176
1177
1178 public void getlineInputToTarget() {
1179 queue.add(new Tuple.NoOperandTuple(Opcode.GETLINE_INPUT_TO_TARGET));
1180 }
1181
1182
1183
1184
1185
1186
1187 public void useAsFileInput() {
1188 queue.add(new Tuple.NoOperandTuple(Opcode.USE_AS_FILE_INPUT));
1189 }
1190
1191
1192
1193
1194
1195
1196 public void useAsCommandInput() {
1197 queue.add(new Tuple.NoOperandTuple(Opcode.USE_AS_COMMAND_INPUT));
1198 }
1199
1200
1201
1202
1203
1204
1205
1206
1207 public void nfOffset(int offset) {
1208 queue.add(new Tuple.LongTuple(Opcode.NF_OFFSET, offset));
1209 }
1210
1211
1212
1213
1214
1215
1216
1217
1218 public void nrOffset(int offset) {
1219 queue.add(new Tuple.LongTuple(Opcode.NR_OFFSET, offset));
1220 }
1221
1222
1223
1224
1225
1226
1227
1228
1229 public void fnrOffset(int offset) {
1230 queue.add(new Tuple.LongTuple(Opcode.FNR_OFFSET, offset));
1231 }
1232
1233
1234
1235
1236
1237
1238
1239
1240 public void fsOffset(int offset) {
1241 queue.add(new Tuple.LongTuple(Opcode.FS_OFFSET, offset));
1242 }
1243
1244
1245
1246
1247
1248
1249
1250
1251 public void rsOffset(int offset) {
1252 queue.add(new Tuple.LongTuple(Opcode.RS_OFFSET, offset));
1253 }
1254
1255
1256
1257
1258
1259
1260
1261
1262 public void ofsOffset(int offset) {
1263 queue.add(new Tuple.LongTuple(Opcode.OFS_OFFSET, offset));
1264 }
1265
1266
1267
1268
1269
1270
1271
1272
1273 public void orsOffset(int offset) {
1274 queue.add(new Tuple.LongTuple(Opcode.ORS_OFFSET, offset));
1275 }
1276
1277
1278
1279
1280
1281
1282
1283
1284 public void rstartOffset(int offset) {
1285 queue.add(new Tuple.LongTuple(Opcode.RSTART_OFFSET, offset));
1286 }
1287
1288
1289
1290
1291
1292
1293
1294
1295 public void rlengthOffset(int offset) {
1296 queue.add(new Tuple.LongTuple(Opcode.RLENGTH_OFFSET, offset));
1297 }
1298
1299
1300
1301
1302
1303
1304
1305
1306 public void filenameOffset(int offset) {
1307 queue.add(new Tuple.LongTuple(Opcode.FILENAME_OFFSET, offset));
1308 }
1309
1310
1311
1312
1313
1314
1315
1316
1317 public void subsepOffset(int offset) {
1318 queue.add(new Tuple.LongTuple(Opcode.SUBSEP_OFFSET, offset));
1319 }
1320
1321
1322
1323
1324
1325
1326
1327
1328 public void convfmtOffset(int offset) {
1329 queue.add(new Tuple.LongTuple(Opcode.CONVFMT_OFFSET, offset));
1330 }
1331
1332
1333
1334
1335
1336
1337
1338
1339 public void ofmtOffset(int offset) {
1340 queue.add(new Tuple.LongTuple(Opcode.OFMT_OFFSET, offset));
1341 }
1342
1343
1344
1345
1346
1347
1348
1349
1350 public void environOffset(int offset) {
1351 queue.add(new Tuple.LongTuple(Opcode.ENVIRON_OFFSET, offset));
1352 }
1353
1354
1355
1356
1357
1358
1359
1360
1361 public void argcOffset(int offset) {
1362 queue.add(new Tuple.LongTuple(Opcode.ARGC_OFFSET, offset));
1363 }
1364
1365
1366
1367
1368
1369
1370
1371
1372 public void argvOffset(int offset) {
1373 queue.add(new Tuple.LongTuple(Opcode.ARGV_OFFSET, offset));
1374 }
1375
1376
1377
1378 public void pushNF() {
1379 queue.add(new Tuple.BuiltinVarTuple(Opcode.PUSH_NF));
1380 }
1381
1382
1383 public void assignNF() {
1384 queue.add(new Tuple.BuiltinVarTuple(Opcode.ASSIGN_NF));
1385 }
1386
1387
1388 public void pushNR() {
1389 queue.add(new Tuple.BuiltinVarTuple(Opcode.PUSH_NR));
1390 }
1391
1392
1393 public void assignNR() {
1394 queue.add(new Tuple.BuiltinVarTuple(Opcode.ASSIGN_NR));
1395 }
1396
1397
1398 public void pushFNR() {
1399 queue.add(new Tuple.BuiltinVarTuple(Opcode.PUSH_FNR));
1400 }
1401
1402
1403 public void assignFNR() {
1404 queue.add(new Tuple.BuiltinVarTuple(Opcode.ASSIGN_FNR));
1405 }
1406
1407
1408 public void pushFS() {
1409 queue.add(new Tuple.BuiltinVarTuple(Opcode.PUSH_FS));
1410 }
1411
1412
1413 public void assignFS() {
1414 queue.add(new Tuple.BuiltinVarTuple(Opcode.ASSIGN_FS));
1415 }
1416
1417
1418 public void pushRS() {
1419 queue.add(new Tuple.BuiltinVarTuple(Opcode.PUSH_RS));
1420 }
1421
1422
1423 public void assignRS() {
1424 queue.add(new Tuple.BuiltinVarTuple(Opcode.ASSIGN_RS));
1425 }
1426
1427
1428 public void pushOFS() {
1429 queue.add(new Tuple.BuiltinVarTuple(Opcode.PUSH_OFS));
1430 }
1431
1432
1433 public void assignOFS() {
1434 queue.add(new Tuple.BuiltinVarTuple(Opcode.ASSIGN_OFS));
1435 }
1436
1437
1438 public void pushORS() {
1439 queue.add(new Tuple.BuiltinVarTuple(Opcode.PUSH_ORS));
1440 }
1441
1442
1443 public void assignORS() {
1444 queue.add(new Tuple.BuiltinVarTuple(Opcode.ASSIGN_ORS));
1445 }
1446
1447
1448 public void pushRSTART() {
1449 queue.add(new Tuple.BuiltinVarTuple(Opcode.PUSH_RSTART));
1450 }
1451
1452
1453 public void assignRSTART() {
1454 queue.add(new Tuple.BuiltinVarTuple(Opcode.ASSIGN_RSTART));
1455 }
1456
1457
1458 public void pushRLENGTH() {
1459 queue.add(new Tuple.BuiltinVarTuple(Opcode.PUSH_RLENGTH));
1460 }
1461
1462
1463 public void assignRLENGTH() {
1464 queue.add(new Tuple.BuiltinVarTuple(Opcode.ASSIGN_RLENGTH));
1465 }
1466
1467
1468 public void pushFILENAME() {
1469 queue.add(new Tuple.BuiltinVarTuple(Opcode.PUSH_FILENAME));
1470 }
1471
1472
1473 public void assignFILENAME() {
1474 queue.add(new Tuple.BuiltinVarTuple(Opcode.ASSIGN_FILENAME));
1475 }
1476
1477
1478 public void pushSUBSEP() {
1479 queue.add(new Tuple.BuiltinVarTuple(Opcode.PUSH_SUBSEP));
1480 }
1481
1482
1483 public void assignSUBSEP() {
1484 queue.add(new Tuple.BuiltinVarTuple(Opcode.ASSIGN_SUBSEP));
1485 }
1486
1487
1488 public void pushCONVFMT() {
1489 queue.add(new Tuple.BuiltinVarTuple(Opcode.PUSH_CONVFMT));
1490 }
1491
1492
1493 public void assignCONVFMT() {
1494 queue.add(new Tuple.BuiltinVarTuple(Opcode.ASSIGN_CONVFMT));
1495 }
1496
1497
1498 public void pushOFMT() {
1499 queue.add(new Tuple.BuiltinVarTuple(Opcode.PUSH_OFMT));
1500 }
1501
1502
1503 public void assignOFMT() {
1504 queue.add(new Tuple.BuiltinVarTuple(Opcode.ASSIGN_OFMT));
1505 }
1506
1507
1508 public void pushARGC() {
1509 queue.add(new Tuple.BuiltinVarTuple(Opcode.PUSH_ARGC));
1510 }
1511
1512
1513 public void assignARGC() {
1514 queue.add(new Tuple.BuiltinVarTuple(Opcode.ASSIGN_ARGC));
1515 }
1516
1517
1518
1519
1520
1521
1522 public void applyRS() {
1523 queue.add(new Tuple.NoOperandTuple(Opcode.APPLY_RS));
1524 }
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534 public void function(String funcName, int numFormalParams) {
1535 queue.add(new Tuple.FunctionTuple(funcName, numFormalParams));
1536 }
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548 public void callFunction(
1549 Supplier<Address> addressSupplier,
1550 String funcName,
1551 int numFormalParams,
1552 int numActualParams) {
1553 queue.add(new Tuple.CallFunctionTuple(addressSupplier, funcName, numFormalParams, numActualParams));
1554 }
1555
1556
1557
1558
1559
1560
1561 public void setReturnResult() {
1562 queue.add(new Tuple.NoOperandTuple(Opcode.SET_RETURN_RESULT));
1563 }
1564
1565
1566
1567
1568
1569
1570 public void returnFromFunction() {
1571 queue.add(new Tuple.NoOperandTuple(Opcode.RETURN_FROM_FUNCTION));
1572 }
1573
1574
1575
1576
1577
1578
1579
1580
1581 public void setNumGlobals(int numGlobals) {
1582 queue.add(new Tuple.CountTuple(Opcode.SET_NUM_GLOBALS, numGlobals));
1583 }
1584
1585
1586
1587
1588
1589
1590 public void close() {
1591 queue.add(new Tuple.NoOperandTuple(Opcode.CLOSE));
1592 }
1593
1594
1595
1596
1597
1598
1599
1600
1601 public void applySubsep(int count) {
1602 queue.add(new Tuple.CountTuple(Opcode.APPLY_SUBSEP, count));
1603 }
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613 public void deleteArrayElement(int offset, boolean isGlobal) {
1614 queue.add(new Tuple.VariableTuple(Opcode.DELETE_ARRAY_ELEMENT, offset, isGlobal));
1615 }
1616
1617
1618
1619
1620 public void deleteMapElement() {
1621 queue.add(new Tuple.NoOperandTuple(Opcode.DELETE_MAP_ELEMENT));
1622 }
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632 public void deleteArray(int offset, boolean isGlobal) {
1633 queue.add(new Tuple.VariableTuple(Opcode.DELETE_ARRAY, offset, isGlobal));
1634 }
1635
1636
1637
1638
1639
1640
1641
1642
1643 public void setExitAddress(Address addr) {
1644 queue.add(new Tuple.AddressTuple(Opcode.SET_EXIT_ADDRESS, addr));
1645 }
1646
1647
1648
1649
1650
1651
1652
1653
1654 public void setWithinEndBlocks(boolean b) {
1655 queue.add(new Tuple.BooleanTuple(Opcode.SET_WITHIN_END_BLOCKS, b));
1656 }
1657
1658
1659
1660
1661
1662
1663 public void exitWithCode() {
1664 queue.add(new Tuple.NoOperandTuple(Opcode.EXIT_WITH_CODE));
1665 }
1666
1667
1668
1669
1670
1671
1672 public void exitWithoutCode() {
1673 queue.add(new Tuple.NoOperandTuple(Opcode.EXIT_WITHOUT_CODE));
1674 }
1675
1676
1677
1678
1679
1680
1681
1682
1683 public void regexp(String regexpStr) {
1684
1685
1686 Pattern precompiled = Pattern.compile(regexpStr);
1687 queue.add(new Tuple.RegexTuple(regexpStr, precompiled));
1688 }
1689
1690
1691
1692
1693
1694
1695 public void conditionPair() {
1696 queue.add(new Tuple.NoOperandTuple(Opcode.CONDITION_PAIR));
1697 }
1698
1699
1700
1701
1702
1703
1704 public void isIn() {
1705 queue.add(new Tuple.NoOperandTuple(Opcode.IS_IN));
1706 }
1707
1708
1709
1710
1711 public void scriptThis() {
1712 queue.add(new Tuple.NoOperandTuple(Opcode.THIS));
1713 }
1714
1715
1716
1717
1718
1719
1720
1721
1722 public void extension(ExtensionFunction function, int paramCount, boolean isInitial) {
1723 queue.add(new Tuple.ExtensionTuple(function, paramCount, isInitial));
1724 }
1725
1726
1727
1728
1729
1730
1731 public void dump(PrintStream ps) {
1732 ps.println("(intermediate serialVersionUID = " + serialVersionUID + ")");
1733 ps.println();
1734 for (int i = 0; i < queue.size(); i++) {
1735 Address address = addressManager.getAddress(i);
1736 if (address == null) {
1737 ps.println(i + " : " + queue.get(i));
1738 } else {
1739 ps.println(i + " : [" + address + "] : " + queue.get(i));
1740 }
1741 }
1742 }
1743
1744
1745
1746
1747
1748
1749
1750
1751 public PositionTracker top() {
1752 return new PositionTracker(queue);
1753 }
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764 public void postProcess() {
1765 if (postProcessed) {
1766 return;
1767 }
1768 if (!queue.isEmpty() && queue.get(0).hasNext()) {
1769 postProcessed = true;
1770 return;
1771 }
1772 assignSequentialNextPointers();
1773 for (Tuple tuple : queue) {
1774 tuple.touch(queue);
1775 }
1776 postProcessed = true;
1777 }
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795 public void optimize() {
1796 if (optimized) {
1797 return;
1798 }
1799 if (!postProcessed) {
1800 postProcess();
1801 }
1802 boolean queueModified = removeRedundantEvalSetNumGlobals();
1803 queueModified |= peepholeOptimize();
1804 if (queueModified) {
1805 reprocessQueue();
1806 }
1807 simplifyControlFlow();
1808 optimizeQueue();
1809 optimized = true;
1810 }
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825 private boolean removeRedundantEvalSetNumGlobals() {
1826 int setNumGlobalsIndex = -1;
1827 for (int i = 0; i < queue.size(); i++) {
1828 Opcode opcode = queue.get(i).getOpcode();
1829 if (opcode == null) {
1830 continue;
1831 }
1832 switch (opcode) {
1833 case SET_NUM_GLOBALS:
1834 if (setNumGlobalsIndex != -1) {
1835 return false;
1836 }
1837 setNumGlobalsIndex = i;
1838 break;
1839 default:
1840 if (requiresEvalGlobalFrame(opcode)) {
1841 return false;
1842 }
1843 break;
1844 }
1845 }
1846 if (!evalTupleStream || setNumGlobalsIndex < 0) {
1847 return false;
1848 }
1849
1850 int[] indexMapping = new int[queue.size()];
1851 for (int i = 0, nextIndex = 0; i < queue.size(); i++) {
1852 if (i == setNumGlobalsIndex) {
1853 indexMapping[i] = nextIndex;
1854 } else {
1855 indexMapping[i] = nextIndex++;
1856 }
1857 }
1858 queue.remove(setNumGlobalsIndex);
1859 remapAddresses(indexMapping);
1860 return true;
1861 }
1862
1863 private boolean peepholeOptimize() {
1864
1865
1866
1867 boolean modified = false;
1868 boolean passModified;
1869 do {
1870 passModified = peepholeOptimizePass();
1871 modified |= passModified;
1872 } while (passModified);
1873 return modified;
1874 }
1875
1876 private boolean peepholeOptimizePass() {
1877 int originalSize = queue.size();
1878 if (originalSize < 2) {
1879 return false;
1880 }
1881
1882 List<Tuple> original = new ArrayList<Tuple>(queue);
1883 int[] indexMapping = new int[originalSize];
1884 Arrays.fill(indexMapping, -1);
1885 List<Tuple> optimizedQueue = new ArrayList<Tuple>(originalSize);
1886 boolean[] isAddressTarget = addressTargets(original, originalSize);
1887
1888 boolean modified = false;
1889 int oldIndex = 0;
1890 int newIndex = 0;
1891 while (oldIndex < originalSize) {
1892 Tuple tuple = original.get(oldIndex);
1893
1894
1895
1896
1897 ConcatRun concatRun = !modified ? concatRun(original, isAddressTarget, oldIndex) : null;
1898 if (concatRun != null) {
1899
1900
1901
1902
1903 Tuple replacement = createMultiConcat(concatRun.itemCount, tuple.getLineNumber());
1904 optimizedQueue.add(replacement);
1905 mapFoldedRange(indexMapping, oldIndex, concatRun.tupleCount, newIndex);
1906 oldIndex += concatRun.tupleCount;
1907 newIndex++;
1908 modified = true;
1909 continue;
1910 }
1911
1912 if (tuple.getOpcode() == Opcode.ASSIGN && (oldIndex + 1) < originalSize) {
1913 Tuple nextTuple = original.get(oldIndex + 1);
1914
1915
1916
1917
1918
1919
1920
1921 if (nextTuple.getOpcode() == Opcode.POP && !isAddressTarget[oldIndex + 1]) {
1922 Tuple replacement = createAssignNoPush(tuple);
1923 optimizedQueue.add(replacement);
1924 mapFoldedRange(indexMapping, oldIndex, 2, newIndex);
1925 oldIndex += 2;
1926 newIndex++;
1927 modified = true;
1928 continue;
1929 }
1930 }
1931
1932 Object literal = literalValue(tuple);
1933 if (literal != null) {
1934 if ((oldIndex + 1) < originalSize) {
1935 Tuple nextTuple = original.get(oldIndex + 1);
1936 if (nextTuple.getOpcode() == Opcode.GET_INPUT_FIELD) {
1937
1938
1939
1940 long fieldIndex = JRT.toLong(literal);
1941 Tuple replacement = createGetInputFieldConst(
1942 fieldIndex,
1943 tuple.getLineNumber());
1944 optimizedQueue.add(replacement);
1945 mapFoldedRange(indexMapping, oldIndex, 2, newIndex);
1946 oldIndex += 2;
1947 newIndex++;
1948 modified = true;
1949 continue;
1950 }
1951 }
1952 if ((oldIndex + 2) < originalSize) {
1953 Tuple nextTuple = original.get(oldIndex + 1);
1954 Tuple opTuple = original.get(oldIndex + 2);
1955 Object secondLiteral = literalValue(nextTuple);
1956 if (secondLiteral != null) {
1957 Object folded = foldBinary(literal, secondLiteral, opTuple);
1958 if (folded != null) {
1959
1960
1961
1962 Tuple replacement = createLiteralPush(folded, tuple.getLineNumber());
1963 optimizedQueue.add(replacement);
1964 mapFoldedRange(indexMapping, oldIndex, 3, newIndex);
1965 oldIndex += 3;
1966 newIndex++;
1967 modified = true;
1968 continue;
1969 }
1970 }
1971 }
1972 if ((oldIndex + 1) < originalSize) {
1973 Tuple opTuple = original.get(oldIndex + 1);
1974 Object folded = foldUnary(literal, opTuple);
1975 if (folded != null) {
1976
1977
1978 Tuple replacement = createLiteralPush(folded, tuple.getLineNumber());
1979 optimizedQueue.add(replacement);
1980 mapFoldedRange(indexMapping, oldIndex, 2, newIndex);
1981 oldIndex += 2;
1982 newIndex++;
1983 modified = true;
1984 continue;
1985 }
1986 }
1987 }
1988
1989 optimizedQueue.add(tuple);
1990 indexMapping[oldIndex] = newIndex;
1991 oldIndex++;
1992 newIndex++;
1993 }
1994
1995 if (!modified) {
1996 return false;
1997 }
1998
1999 for (int i = 0; i < optimizedQueue.size(); i++) {
2000 queue.set(i, optimizedQueue.get(i));
2001 }
2002 for (int i = queue.size() - 1; i >= optimizedQueue.size(); i--) {
2003 queue.remove(i);
2004 }
2005
2006 remapAddresses(indexMapping);
2007 return true;
2008 }
2009
2010 private boolean[] addressTargets(List<Tuple> tuples, int tupleCount) {
2011 boolean[] targets = new boolean[tupleCount];
2012 for (Tuple tuple : tuples) {
2013 Address address = tuple.getAddress();
2014 if (address != null) {
2015 int index = address.index();
2016 if (index >= 0 && index < tupleCount) {
2017 targets[index] = true;
2018 }
2019 }
2020 }
2021 return targets;
2022 }
2023
2024 private void mapFoldedRange(int[] indexMapping, int startIndex, int length, int newIndex) {
2025 for (int idx = 0; idx < length; idx++) {
2026 indexMapping[startIndex + idx] = newIndex;
2027 }
2028 }
2029
2030 private ConcatRun concatRun(List<Tuple> original, boolean[] isAddressTarget, int oldIndex) {
2031 Tuple tuple = original.get(oldIndex);
2032 if (tuple.getOpcode() != Opcode.CONCAT || isAddressTarget[oldIndex]) {
2033 return null;
2034 }
2035
2036 int itemCount = 2;
2037 int tupleCount = 1;
2038 int currentIndex = oldIndex + 1;
2039 while (currentIndex < original.size()
2040 && original.get(currentIndex).getOpcode() == Opcode.CONCAT
2041 && !isAddressTarget[currentIndex]) {
2042 itemCount++;
2043 tupleCount++;
2044 currentIndex++;
2045 }
2046
2047 if (tupleCount < 2) {
2048 return null;
2049 }
2050 return new ConcatRun(tupleCount, itemCount);
2051 }
2052
2053 private Object literalValue(Tuple tuple) {
2054 switch (tuple.getOpcode()) {
2055 case PUSH_LONG:
2056 return Long.valueOf(((Tuple.PushLongTuple) tuple).getValue());
2057 case PUSH_DOUBLE:
2058 return Double.valueOf(((Tuple.PushDoubleTuple) tuple).getValue());
2059 case PUSH_STRING:
2060 return ((Tuple.PushStringTuple) tuple).getValue();
2061 default:
2062 return null;
2063 }
2064 }
2065
2066 private Object foldBinary(Object left, Object right, Tuple operation) {
2067 Opcode opcode = operation.getOpcode();
2068 if (opcode == null) {
2069 return null;
2070 }
2071 switch (opcode) {
2072 case ADD: {
2073 double d1 = JRT.toDouble(left);
2074 double d2 = JRT.toDouble(right);
2075 double ans = d1 + d2;
2076 if (JRT.isActuallyLong(ans)) {
2077 return Long.valueOf((long) Math.rint(ans));
2078 }
2079 return Double.valueOf(ans);
2080 }
2081 case SUBTRACT: {
2082 double d1 = JRT.toDouble(left);
2083 double d2 = JRT.toDouble(right);
2084 double ans = d1 - d2;
2085 if (JRT.isActuallyLong(ans)) {
2086 return Long.valueOf((long) Math.rint(ans));
2087 }
2088 return Double.valueOf(ans);
2089 }
2090 case MULTIPLY: {
2091 double d1 = JRT.toDouble(left);
2092 double d2 = JRT.toDouble(right);
2093 double ans = d1 * d2;
2094 if (JRT.isActuallyLong(ans)) {
2095 return Long.valueOf((long) Math.rint(ans));
2096 }
2097 return Double.valueOf(ans);
2098 }
2099 case DIVIDE: {
2100 double d1 = JRT.toDouble(left);
2101 double d2 = JRT.toDouble(right);
2102 double ans = d1 / d2;
2103 if (JRT.isActuallyLong(ans)) {
2104 return Long.valueOf((long) Math.rint(ans));
2105 }
2106 return Double.valueOf(ans);
2107 }
2108 case MOD: {
2109 double d1 = JRT.toDouble(left);
2110 double d2 = JRT.toDouble(right);
2111 double ans = d1 % d2;
2112 if (JRT.isActuallyLong(ans)) {
2113 return Long.valueOf((long) Math.rint(ans));
2114 }
2115 return Double.valueOf(ans);
2116 }
2117 case POW: {
2118 double d1 = JRT.toDouble(left);
2119 double d2 = JRT.toDouble(right);
2120 double ans = Math.pow(d1, d2);
2121 if (JRT.isActuallyLong(ans)) {
2122 return Long.valueOf((long) Math.rint(ans));
2123 }
2124 return Double.valueOf(ans);
2125 }
2126 case CMP_EQ:
2127 return JRT.compare2(left, right, 0) ? Long.valueOf(1L) : Long.valueOf(0L);
2128 case CMP_LT:
2129 return JRT.compare2(left, right, -1) ? Long.valueOf(1L) : Long.valueOf(0L);
2130 case CMP_GT:
2131 return JRT.compare2(left, right, 1) ? Long.valueOf(1L) : Long.valueOf(0L);
2132 case CONCAT:
2133 if (left instanceof String && right instanceof String) {
2134 return ((String) left) + ((String) right);
2135 }
2136 return null;
2137 default:
2138 return null;
2139 }
2140 }
2141
2142 private Object foldUnary(Object literal, Tuple operation) {
2143 Opcode opcode = operation.getOpcode();
2144 if (opcode == null) {
2145 return null;
2146 }
2147 switch (opcode) {
2148 case NEGATE: {
2149 double value = JRT.toDouble(literal);
2150 double ans = -value;
2151 if (JRT.isActuallyLong(ans)) {
2152 return Long.valueOf((long) Math.rint(ans));
2153 }
2154 return Double.valueOf(ans);
2155 }
2156 case UNARY_PLUS: {
2157 double value = JRT.toDouble(literal);
2158 if (JRT.isActuallyLong(value)) {
2159 return Long.valueOf((long) Math.rint(value));
2160 }
2161 return Double.valueOf(value);
2162 }
2163 default:
2164 return null;
2165 }
2166 }
2167
2168 private Tuple createLiteralPush(Object value, int lineNumber) {
2169 Tuple tuple;
2170 if (value instanceof Long) {
2171 tuple = new Tuple.PushLongTuple(((Long) value).longValue());
2172 } else if (value instanceof Integer) {
2173 tuple = new Tuple.PushLongTuple(((Integer) value).longValue());
2174 } else if (value instanceof Double) {
2175 tuple = new Tuple.PushDoubleTuple(((Double) value).doubleValue());
2176 } else if (value instanceof Number) {
2177 double d = ((Number) value).doubleValue();
2178 if (JRT.isActuallyLong(d)) {
2179 tuple = new Tuple.PushLongTuple((long) Math.rint(d));
2180 } else {
2181 tuple = new Tuple.PushDoubleTuple(d);
2182 }
2183 } else if (value instanceof String) {
2184 tuple = new Tuple.PushStringTuple((String) value);
2185 } else {
2186 throw new IllegalArgumentException("Unsupported literal value: " + value);
2187 }
2188 tuple.setLineNumber(lineNumber);
2189 return tuple;
2190 }
2191
2192 private Tuple createAssignNoPush(Tuple tuple) {
2193 Tuple.VariableTuple variableTuple = (Tuple.VariableTuple) tuple;
2194 Tuple replacement = new Tuple.VariableTuple(
2195 Opcode.ASSIGN_NOPUSH,
2196 variableTuple.getVariableOffset(),
2197 variableTuple.isGlobal());
2198 replacement.setLineNumber(tuple.getLineNumber());
2199 return replacement;
2200 }
2201
2202 private Tuple createGetInputFieldConst(long fieldIndex, int lineNumber) {
2203 Tuple tuple = new Tuple.InputFieldTuple(fieldIndex);
2204 tuple.setLineNumber(lineNumber);
2205 return tuple;
2206 }
2207
2208 private Tuple createMultiConcat(int itemCount, int lineNumber) {
2209 Tuple tuple = new Tuple.CountTuple(Opcode.MULTI_CONCAT, itemCount);
2210 tuple.setLineNumber(lineNumber);
2211 return tuple;
2212 }
2213
2214 private static final class ConcatRun {
2215 private final int tupleCount;
2216 private final int itemCount;
2217
2218 private ConcatRun(int tupleCount, int itemCount) {
2219 this.tupleCount = tupleCount;
2220 this.itemCount = itemCount;
2221 }
2222 }
2223
2224 private void remapAddresses(int[] indexMapping) {
2225 if (indexMapping.length == 0) {
2226 return;
2227 }
2228 Set<Address> processedAddresses = Collections.newSetFromMap(new IdentityHashMap<Address, Boolean>());
2229 for (Tuple tuple : queue) {
2230 Address address = tuple.getAddress();
2231 if (address != null && processedAddresses.add(address)) {
2232 int oldIndex = address.index();
2233 if (oldIndex >= 0 && oldIndex < indexMapping.length) {
2234 int mappedIndex = indexMapping[oldIndex];
2235 if (mappedIndex < 0) {
2236 throw new Error("Address " + address + " references removed tuple " + oldIndex);
2237 }
2238 address.assignIndex(mappedIndex);
2239 }
2240 }
2241 }
2242 addressManager.remapIndexes(indexMapping);
2243 }
2244
2245 private void reprocessQueue() {
2246 assignSequentialNextPointers();
2247 for (Tuple tuple : queue) {
2248 tuple.touch(queue);
2249 }
2250 }
2251
2252 private boolean simplifyControlFlow() {
2253 boolean modified = false;
2254 boolean passModified;
2255 do {
2256 passModified = simplifyControlFlowPass();
2257 if (passModified) {
2258 reprocessQueue();
2259 }
2260 modified |= passModified;
2261 } while (passModified);
2262 return modified;
2263 }
2264
2265 private boolean simplifyControlFlowPass() {
2266 int size = queue.size();
2267 if (size < 2) {
2268 return false;
2269 }
2270
2271 boolean modified = false;
2272 boolean[] remove = new boolean[size];
2273 int[] redirectTargets = new int[size];
2274 int[] visitStamps = new int[size];
2275 int nextVisitStamp = 1;
2276 Arrays.fill(redirectTargets, -1);
2277
2278 for (int i = 0; i < size; i++) {
2279 Tuple tuple = queue.get(i);
2280 Address address = tuple.getAddress();
2281 if (address != null) {
2282 int resolvedTarget = resolveJumpEquivalentIndex(
2283 address.index(),
2284 size,
2285 visitStamps,
2286 nextVisitStamp++);
2287 if (resolvedTarget >= 0 && resolvedTarget != address.index()) {
2288 addressManager.reassignAddress(address, resolvedTarget);
2289 modified = true;
2290 }
2291 }
2292
2293 switch (tuple.getOpcode()) {
2294 case NOP: {
2295 int redirectTarget = resolveJumpEquivalentIndex(
2296 i + 1,
2297 size,
2298 visitStamps,
2299 nextVisitStamp++);
2300 if (redirectTarget >= 0) {
2301 remove[i] = true;
2302 redirectTargets[i] = redirectTarget;
2303 modified = true;
2304 }
2305 break;
2306 }
2307 case GOTO: {
2308 int target = resolveJumpEquivalentIndex(
2309 tuple.getAddress().index(),
2310 size,
2311 visitStamps,
2312 nextVisitStamp++);
2313 int fallthroughTarget = resolveJumpEquivalentIndex(
2314 i + 1,
2315 size,
2316 visitStamps,
2317 nextVisitStamp++);
2318 if (target >= 0 && target == fallthroughTarget) {
2319 remove[i] = true;
2320 redirectTargets[i] = fallthroughTarget;
2321 modified = true;
2322 }
2323 break;
2324 }
2325 default:
2326 break;
2327 }
2328 }
2329
2330 if (!modified) {
2331 return false;
2332 }
2333
2334 boolean anyRemoved = false;
2335 for (boolean removeTuple : remove) {
2336 if (removeTuple) {
2337 anyRemoved = true;
2338 break;
2339 }
2340 }
2341 if (!anyRemoved) {
2342 return true;
2343 }
2344
2345 int[] indexMapping = new int[size];
2346 Arrays.fill(indexMapping, -1);
2347 int nextIndex = 0;
2348 for (int i = 0; i < size; i++) {
2349 if (!remove[i]) {
2350 indexMapping[i] = nextIndex++;
2351 }
2352 }
2353 for (int i = 0; i < size; i++) {
2354 if (remove[i] && redirectTargets[i] >= 0) {
2355 indexMapping[i] = indexMapping[redirectTargets[i]];
2356 }
2357 }
2358
2359 compactQueue(remove);
2360
2361 remapAddresses(indexMapping);
2362 return true;
2363 }
2364
2365 private int resolveJumpEquivalentIndex(int index, int size, int[] visitStamps, int stamp) {
2366 if (index < 0 || index >= size) {
2367 return -1;
2368 }
2369 int current = index;
2370 while (current >= 0 && current < size && visitStamps[current] != stamp) {
2371 visitStamps[current] = stamp;
2372 Tuple tuple = queue.get(current);
2373 switch (tuple.getOpcode()) {
2374 case NOP:
2375 current++;
2376 break;
2377 case GOTO: {
2378 Address address = tuple.getAddress();
2379 if (address == null) {
2380 return current;
2381 }
2382 current = address.index();
2383 break;
2384 }
2385 default:
2386 return current;
2387 }
2388 }
2389 return -1;
2390 }
2391
2392 private void assignSequentialNextPointers() {
2393 for (int i = 0; i < queue.size(); i++) {
2394 Tuple nextTuple = (i + 1) < queue.size() ? queue.get(i + 1) : null;
2395 queue.get(i).setNext(nextTuple);
2396 }
2397 }
2398
2399 private void compactQueue(boolean[] remove) {
2400 ArrayList<Tuple> compactedQueue = new ArrayList<Tuple>(queue.size());
2401 for (int i = 0; i < remove.length; i++) {
2402 if (!remove[i]) {
2403 compactedQueue.add(queue.get(i));
2404 }
2405 }
2406 queue.clear();
2407 queue.addAll(compactedQueue);
2408 }
2409
2410 private void optimizeQueue() {
2411 int size = queue.size();
2412 if (size <= 1) {
2413 return;
2414 }
2415
2416 boolean[] reachable = new boolean[size];
2417 int[] referencesFromReachable = new int[size];
2418
2419 Deque<Integer> worklist = new ArrayDeque<>();
2420 if (!queue.isEmpty()) {
2421 reachable[0] = true;
2422 worklist.add(0);
2423 }
2424
2425 while (!worklist.isEmpty()) {
2426 int index = worklist.removeFirst();
2427 Tuple tuple = queue.get(index);
2428
2429 if (fallsThrough(tuple.getOpcode())) {
2430 Tuple nextTuple = tuple.getNext();
2431 if (nextTuple != null) {
2432 int nextIndex = index + 1;
2433 if (!reachable[nextIndex]) {
2434 reachable[nextIndex] = true;
2435 worklist.addLast(nextIndex);
2436 }
2437 }
2438 }
2439
2440 Address address = tuple.getAddress();
2441 if (address != null) {
2442 int targetIndex = address.index();
2443 if (targetIndex < 0 || targetIndex >= size) {
2444 throw new Error("address " + address + " doesn't resolve to an actual list element");
2445 }
2446 referencesFromReachable[targetIndex]++;
2447 if (!reachable[targetIndex]) {
2448 reachable[targetIndex] = true;
2449 worklist.addLast(targetIndex);
2450 }
2451 }
2452 }
2453
2454 for (int i = 0; i < size; i++) {
2455 if (!reachable[i] && referencesFromReachable[i] > 0) {
2456 reachable[i] = true;
2457 worklist.addLast(i);
2458 }
2459 }
2460
2461 while (!worklist.isEmpty()) {
2462 int index = worklist.removeFirst();
2463 Tuple tuple = queue.get(index);
2464
2465 if (fallsThrough(tuple.getOpcode())) {
2466 Tuple nextTuple = tuple.getNext();
2467 if (nextTuple != null) {
2468 int nextIndex = index + 1;
2469 if (!reachable[nextIndex]) {
2470 reachable[nextIndex] = true;
2471 worklist.addLast(nextIndex);
2472 }
2473 }
2474 }
2475
2476 Address address = tuple.getAddress();
2477 if (address != null) {
2478 int targetIndex = address.index();
2479 if (targetIndex < 0 || targetIndex >= size) {
2480 throw new Error("address " + address + " doesn't resolve to an actual list element");
2481 }
2482 referencesFromReachable[targetIndex]++;
2483 if (!reachable[targetIndex]) {
2484 reachable[targetIndex] = true;
2485 worklist.addLast(targetIndex);
2486 }
2487 }
2488 }
2489
2490 boolean anyRemoved = false;
2491 boolean[] remove = new boolean[size];
2492 for (int i = 0; i < size; i++) {
2493 if (!reachable[i]) {
2494 remove[i] = true;
2495 anyRemoved = true;
2496 continue;
2497 }
2498 Tuple tuple = queue.get(i);
2499 if (tuple.getOpcode() == Opcode.NOP && referencesFromReachable[i] == 0) {
2500 remove[i] = true;
2501 anyRemoved = true;
2502 }
2503 }
2504
2505 if (!anyRemoved) {
2506 return;
2507 }
2508
2509 int[] indexMapping = new int[size];
2510 int nextIndex = 0;
2511 for (int i = 0; i < size; i++) {
2512 if (remove[i]) {
2513 indexMapping[i] = -1;
2514 } else {
2515 indexMapping[i] = nextIndex++;
2516 }
2517 }
2518
2519 compactQueue(remove);
2520
2521 if (!queue.isEmpty()) {
2522 assignSequentialNextPointers();
2523 }
2524
2525 remapAddresses(indexMapping);
2526 }
2527
2528 private boolean fallsThrough(Opcode opcode) {
2529 if (opcode == null) {
2530 return true;
2531 }
2532 switch (opcode) {
2533 case GOTO:
2534 case EXIT_WITH_CODE:
2535 case EXIT_WITHOUT_CODE:
2536 return false;
2537 default:
2538 return true;
2539 }
2540 }
2541
2542
2543 private Map<String, Integer> globalVarOffsetMap = new HashMap<String, Integer>();
2544
2545
2546 private Map<String, Boolean> globalVarAarrayMap = new HashMap<String, Boolean>();
2547
2548
2549 private Set<String> functionNames = new HashSet<String>();
2550
2551
2552 private boolean metadataFrozen;
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562 public void addGlobalVariableNameToOffsetMapping(String varname, int offset, boolean isArray) {
2563 ensureMetadataMutable();
2564 if (globalVarOffsetMap.get(varname) != null) {
2565 return;
2566 }
2567 globalVarOffsetMap.put(varname, offset);
2568 globalVarAarrayMap.put(varname, isArray);
2569 }
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579 public void setFunctionNameSet(Set<String> names) {
2580 ensureMetadataMutable();
2581
2582
2583
2584
2585
2586
2587
2588
2589 this.functionNames = new HashSet<String>(names);
2590 }
2591
2592
2593
2594
2595
2596
2597 public void freezeMetadata() {
2598 if (metadataFrozen) {
2599 return;
2600 }
2601 globalVarOffsetMap = freezeMap(globalVarOffsetMap);
2602 globalVarAarrayMap = freezeMap(globalVarAarrayMap);
2603 functionNames = freezeSet(functionNames);
2604 metadataFrozen = true;
2605 }
2606
2607
2608
2609
2610
2611
2612
2613
2614 @SuppressFBWarnings(value = "EI_EXPOSE_REP", justification = "freezeMetadata() replaces this field with an unmodifiable snapshot before compiled tuples are exposed")
2615 public Map<String, Integer> getGlobalVariableOffsetMap() {
2616 return globalVarOffsetMap;
2617 }
2618
2619
2620
2621
2622
2623
2624
2625
2626 @SuppressFBWarnings(value = "EI_EXPOSE_REP", justification = "freezeMetadata() replaces this field with an unmodifiable snapshot before compiled tuples are exposed")
2627 public Map<String, Boolean> getGlobalVariableAarrayMap() {
2628 return globalVarAarrayMap;
2629 }
2630
2631
2632
2633
2634
2635
2636
2637
2638 @SuppressFBWarnings(value = "EI_EXPOSE_REP", justification = "freezeMetadata() replaces this field with an unmodifiable snapshot before compiled tuples are exposed")
2639 public Set<String> getFunctionNameSet() {
2640 return functionNames;
2641 }
2642
2643 private void ensureMetadataMutable() {
2644 if (metadataFrozen) {
2645 throw new IllegalStateException("Tuple metadata is frozen.");
2646 }
2647 }
2648
2649 private static <K, V> Map<K, V> freezeMap(Map<K, V> map) {
2650 if (map.isEmpty()) {
2651 return Collections.emptyMap();
2652 }
2653 return Collections.unmodifiableMap(new HashMap<K, V>(map));
2654 }
2655
2656 private static <T> Set<T> freezeSet(Set<T> set) {
2657 if (set.isEmpty()) {
2658 return Collections.emptySet();
2659 }
2660 return Collections.unmodifiableSet(new HashSet<T>(set));
2661 }
2662
2663 private boolean requiresEvalGlobalFrame(Opcode opcode) {
2664 switch (opcode) {
2665 case ASSIGN:
2666 case ASSIGN_NOPUSH:
2667 case ASSIGN_ARRAY:
2668 case DEREFERENCE:
2669 case PLUS_EQ:
2670 case MINUS_EQ:
2671 case MULT_EQ:
2672 case DIV_EQ:
2673 case MOD_EQ:
2674 case POW_EQ:
2675 case PLUS_EQ_ARRAY:
2676 case MINUS_EQ_ARRAY:
2677 case MULT_EQ_ARRAY:
2678 case DIV_EQ_ARRAY:
2679 case MOD_EQ_ARRAY:
2680 case POW_EQ_ARRAY:
2681 case CALL_FUNCTION:
2682 case SET_RETURN_RESULT:
2683 case RETURN_FROM_FUNCTION:
2684 case MATCH:
2685 case DELETE_ARRAY_ELEMENT:
2686 case DELETE_ARRAY:
2687 case ENVIRON_OFFSET:
2688 case ARGC_OFFSET:
2689 case ARGV_OFFSET:
2690 case ASSIGN_ARGC:
2691 case PUSH_ARGC:
2692 return true;
2693 default:
2694 return false;
2695 }
2696 }
2697
2698
2699 private Deque<Integer> linenoStack = new ArrayDeque<Integer>();
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711 public void pushSourceLineNumber(int lineno) {
2712 linenoStack.push(lineno);
2713 }
2714
2715
2716
2717
2718
2719
2720
2721
2722 public void popSourceLineNumber(int lineno) {
2723 linenoStack.pop();
2724 }
2725
2726 }