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