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