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.Serializable;
26 import java.util.ArrayList;
27 import java.util.Collections;
28 import java.util.HashSet;
29 import java.util.List;
30 import java.util.Map;
31 import java.util.Set;
32 import java.util.function.Supplier;
33 import java.util.regex.Pattern;
34 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
35 import io.jawk.ext.ExtensionFunction;
36
37
38
39
40
41
42
43
44
45 public abstract class Tuple implements Serializable {
46
47 private static final long serialVersionUID = 8105941219003992817L;
48
49
50 private final Opcode opcode;
51
52
53 private int lineNumber = -1;
54
55
56 private Tuple next = null;
57
58 Tuple(Opcode opcode) {
59 this.opcode = opcode;
60 }
61
62
63
64
65
66
67 public final Opcode getOpcode() {
68 return opcode;
69 }
70
71
72
73
74
75
76 public Address getAddress() {
77 return null;
78 }
79
80
81
82
83
84
85 public List<Address> getAddresses() {
86 Address address = getAddress();
87 if (address == null) {
88 return Collections.emptyList();
89 }
90 return Collections.singletonList(address);
91 }
92
93
94
95
96
97
98 public void touch(List<Tuple> queue) {
99 for (Address address : getAddresses()) {
100 if (address.index() == -1) {
101 throw new Error("address " + address + " is unresolved");
102 }
103 if (address.index() >= queue.size()) {
104 throw new Error("address " + address + " doesn't resolve to an actual list element");
105 }
106 }
107 }
108
109 boolean hasNext() {
110 return next != null;
111 }
112
113
114
115
116
117
118 Tuple getNext() {
119 return next;
120 }
121
122 void setNext(Tuple next) {
123 this.next = next;
124 }
125
126 void setLineNumber(int lineNumber) {
127 this.lineNumber = lineNumber;
128 }
129
130
131
132
133
134
135 public int getLineNumber() {
136 return lineNumber;
137 }
138
139 private static String stringArgument(String value) {
140 return ", \"" + value + '"';
141 }
142
143 private static String patternArgument(Pattern pattern) {
144 return ", /" + (pattern == null ? "" : pattern.pattern()) + '/';
145 }
146
147
148
149
150 public static class NoOperandTuple extends Tuple {
151 private static final long serialVersionUID = 1L;
152
153 NoOperandTuple(Opcode opcode) {
154 super(opcode);
155 }
156
157 @Override
158 public String toString() {
159 return getOpcode().name();
160 }
161 }
162
163
164
165
166
167 public static final class ScalarPopTuple extends NoOperandTuple {
168 private static final long serialVersionUID = 1L;
169
170 ScalarPopTuple() {
171 super(Opcode.POP);
172 }
173 }
174
175
176
177
178 public static final class BuiltinVarTuple extends NoOperandTuple {
179 private static final long serialVersionUID = 1L;
180
181 BuiltinVarTuple(Opcode opcode) {
182 super(opcode);
183 }
184 }
185
186
187
188
189 public static final class PushLongTuple extends Tuple {
190 private static final long serialVersionUID = 1L;
191
192
193 private final long value;
194
195 PushLongTuple(long value) {
196 super(Opcode.PUSH_LONG);
197 this.value = value;
198 }
199
200
201
202
203
204
205 public long getValue() {
206 return value;
207 }
208
209 @Override
210 public String toString() {
211 return getOpcode().name() + ", " + value;
212 }
213 }
214
215
216
217
218 public static final class PushDoubleTuple extends Tuple {
219 private static final long serialVersionUID = 1L;
220
221
222 private final double value;
223
224 PushDoubleTuple(double value) {
225 super(Opcode.PUSH_DOUBLE);
226 this.value = value;
227 }
228
229
230
231
232
233
234 public double getValue() {
235 return value;
236 }
237
238 @Override
239 public String toString() {
240 return getOpcode().name() + ", " + value;
241 }
242 }
243
244
245
246
247 public static final class PushStringTuple extends Tuple {
248 private static final long serialVersionUID = 1L;
249
250
251 private final String value;
252
253 PushStringTuple(String value) {
254 super(Opcode.PUSH_STRING);
255 this.value = value;
256 }
257
258
259
260
261
262
263 public String getValue() {
264 return value;
265 }
266
267 @Override
268 public String toString() {
269 return getOpcode().name() + stringArgument(value);
270 }
271 }
272
273
274
275
276 public static class CountTuple extends Tuple {
277 private static final long serialVersionUID = 1L;
278
279
280 private final long count;
281
282 CountTuple(Opcode opcode, long count) {
283 super(opcode);
284 this.count = count;
285 }
286
287
288
289
290
291
292 public final long getCount() {
293 return count;
294 }
295
296 @Override
297 public String toString() {
298 return getOpcode().name() + ", " + count;
299 }
300 }
301
302
303
304
305 public static final class CountAndAppendTuple extends CountTuple {
306 private static final long serialVersionUID = 1L;
307
308
309 private final boolean append;
310
311 CountAndAppendTuple(Opcode opcode, long count, boolean append) {
312 super(opcode, count);
313 this.append = append;
314 }
315
316
317
318
319
320
321 public boolean isAppend() {
322 return append;
323 }
324
325 @Override
326 public String toString() {
327 return getOpcode().name() + ", " + getCount() + ", " + append;
328 }
329 }
330
331
332
333
334 public static class LongTuple extends Tuple {
335 private static final long serialVersionUID = 1L;
336
337
338 private final long value;
339
340 LongTuple(Opcode opcode, long value) {
341 super(opcode);
342 this.value = value;
343 }
344
345
346
347
348
349
350 public final long getValue() {
351 return value;
352 }
353
354 @Override
355 public String toString() {
356 return getOpcode().name() + ", " + value;
357 }
358 }
359
360
361
362
363 public static final class InputFieldTuple extends LongTuple {
364 private static final long serialVersionUID = 1L;
365
366 InputFieldTuple(long fieldIndex) {
367 super(Opcode.GET_INPUT_FIELD_CONST, fieldIndex);
368 }
369
370
371
372
373
374
375 public long getFieldIndex() {
376 return getValue();
377 }
378 }
379
380
381
382
383 public static class AddressTuple extends Tuple {
384 private static final long serialVersionUID = 1L;
385
386
387 private Address address;
388
389 AddressTuple(Opcode opcode, Address address) {
390 super(opcode);
391 this.address = address;
392 }
393
394 @Override
395 public Address getAddress() {
396 return address;
397 }
398
399 void setAddress(Address address) {
400 this.address = address;
401 }
402
403 @Override
404 public String toString() {
405 return getOpcode().name() + ", " + address;
406 }
407 }
408
409
410
411
412 public static class VariableTuple extends Tuple {
413 private static final long serialVersionUID = 1L;
414
415
416 private final long variableOffset;
417
418
419 private final boolean global;
420
421 VariableTuple(Opcode opcode, long variableOffset, boolean global) {
422 super(opcode);
423 this.variableOffset = variableOffset;
424 this.global = global;
425 }
426
427
428
429
430
431
432 public final long getVariableOffset() {
433 return variableOffset;
434 }
435
436
437
438
439
440
441 public final boolean isGlobal() {
442 return global;
443 }
444
445 @Override
446 public String toString() {
447 return getOpcode().name() + ", " + variableOffset + ", " + global;
448 }
449 }
450
451
452
453
454 public static final class CompoundAssignTuple extends VariableTuple {
455 private static final long serialVersionUID = 1L;
456
457 CompoundAssignTuple(Opcode opcode, long variableOffset, boolean global) {
458 super(opcode, variableOffset, global);
459 }
460 }
461
462
463
464
465 public static final class CompoundAssignArrayTuple extends VariableTuple {
466 private static final long serialVersionUID = 1L;
467
468 CompoundAssignArrayTuple(Opcode opcode, long variableOffset, boolean global) {
469 super(opcode, variableOffset, global);
470 }
471 }
472
473
474
475
476 public static final class CompoundAssignMapElementTuple extends NoOperandTuple {
477 private static final long serialVersionUID = 1L;
478
479 CompoundAssignMapElementTuple(Opcode opcode) {
480 super(opcode);
481 }
482 }
483
484
485
486
487 public static final class CompoundAssignInputFieldTuple extends NoOperandTuple {
488 private static final long serialVersionUID = 1L;
489
490 CompoundAssignInputFieldTuple(Opcode opcode) {
491 super(opcode);
492 }
493 }
494
495
496
497
498 public static final class DereferenceTuple extends Tuple {
499 private static final long serialVersionUID = 1L;
500
501
502 private final long variableOffset;
503
504
505 private final boolean array;
506
507
508 private final boolean global;
509
510 DereferenceTuple(long variableOffset, boolean array, boolean global) {
511 super(Opcode.DEREFERENCE);
512 this.variableOffset = variableOffset;
513 this.array = array;
514 this.global = global;
515 }
516
517
518
519
520
521
522 public long getVariableOffset() {
523 return variableOffset;
524 }
525
526
527
528
529
530
531 public boolean isArray() {
532 return array;
533 }
534
535
536
537
538
539
540 public boolean isGlobal() {
541 return global;
542 }
543
544 @Override
545 public String toString() {
546 return getOpcode().name() + ", " + variableOffset + ", " + array + ", " + global;
547 }
548 }
549
550
551
552
553 public static final class BooleanTuple extends Tuple {
554 private static final long serialVersionUID = 1L;
555
556
557 private final boolean value;
558
559 BooleanTuple(Opcode opcode, boolean value) {
560 super(opcode);
561 this.value = value;
562 }
563
564
565
566
567
568
569 public boolean getValue() {
570 return value;
571 }
572
573 @Override
574 public String toString() {
575 return getOpcode().name() + ", " + value;
576 }
577 }
578
579
580
581
582 public static final class SubstitutionVariableTuple extends VariableTuple {
583 private static final long serialVersionUID = 1L;
584
585
586 private final boolean globalSubstitution;
587
588 SubstitutionVariableTuple(Opcode opcode, long variableOffset, boolean global, boolean globalSubstitution) {
589 super(opcode, variableOffset, global);
590 this.globalSubstitution = globalSubstitution;
591 }
592
593
594
595
596
597
598 public boolean isGlobalSubstitution() {
599 return globalSubstitution;
600 }
601
602 @Override
603 public String toString() {
604 return getOpcode().name() + ", " + getVariableOffset() + ", " + isGlobal() + ", " + globalSubstitution;
605 }
606 }
607
608
609
610
611 public static final class RegexTuple extends Tuple {
612 private static final long serialVersionUID = 1L;
613
614
615 private final String regex;
616
617
618 private final Pattern pattern;
619
620 RegexTuple(String regex, Pattern pattern) {
621 super(Opcode.REGEXP);
622 this.regex = regex;
623 this.pattern = pattern;
624 }
625
626
627
628
629
630
631 public String getRegex() {
632 return regex;
633 }
634
635
636
637
638
639
640 public Pattern getPattern() {
641 return pattern;
642 }
643
644 @Override
645 public String toString() {
646 return getOpcode().name() + stringArgument(regex) + patternArgument(pattern);
647 }
648 }
649
650
651
652
653 public static final class ClassTuple extends Tuple {
654 private static final long serialVersionUID = 1L;
655
656
657 private final Class<?> type;
658
659 ClassTuple(Class<?> type) {
660 super(Opcode.CHECK_CLASS);
661 this.type = type;
662 }
663
664
665
666
667
668
669 public Class<?> getType() {
670 return type;
671 }
672
673 @Override
674 public String toString() {
675 return getOpcode().name() + ", " + type;
676 }
677 }
678
679
680
681
682 public static final class FunctionTuple extends Tuple {
683 private static final long serialVersionUID = 1L;
684
685
686 private final String functionName;
687
688
689 private final long numFormalParams;
690
691 FunctionTuple(String functionName, long numFormalParams) {
692 super(Opcode.FUNCTION);
693 this.functionName = functionName;
694 this.numFormalParams = numFormalParams;
695 }
696
697
698
699
700
701
702 public String getFunctionName() {
703 return functionName;
704 }
705
706
707
708
709
710
711 public long getNumFormalParams() {
712 return numFormalParams;
713 }
714
715 @Override
716 public String toString() {
717 return getOpcode().name() + stringArgument(functionName) + ", " + numFormalParams;
718 }
719 }
720
721
722
723
724 public static final class CallFunctionTuple extends AddressTuple {
725 private static final long serialVersionUID = 1L;
726 private transient Supplier<Address> addressSupplier;
727
728
729 private final String functionName;
730
731
732 private final long numFormalParams;
733
734
735 private final long numActualParams;
736
737 CallFunctionTuple(
738 Supplier<Address> addressSupplier,
739 String functionName,
740 long numFormalParams,
741 long numActualParams) {
742 super(Opcode.CALL_FUNCTION, null);
743 this.addressSupplier = addressSupplier;
744 this.functionName = functionName;
745 this.numFormalParams = numFormalParams;
746 this.numActualParams = numActualParams;
747 }
748
749 @Override
750 public Address getAddress() {
751 Address address = super.getAddress();
752 if (address == null && addressSupplier != null) {
753 address = addressSupplier.get();
754 setAddress(address);
755 addressSupplier = null;
756 }
757 return address;
758 }
759
760 @Override
761 public void touch(List<Tuple> queue) {
762 getAddress();
763 super.touch(queue);
764 }
765
766
767
768
769
770
771 public String getFunctionName() {
772 return functionName;
773 }
774
775
776
777
778
779
780 public long getNumFormalParams() {
781 return numFormalParams;
782 }
783
784
785
786
787
788
789 public long getNumActualParams() {
790 return numActualParams;
791 }
792
793 @Override
794 public String toString() {
795 return getOpcode().name()
796 + ", "
797 + getAddress()
798 + stringArgument(functionName)
799 + ", "
800 + numFormalParams
801 + ", "
802 + numActualParams;
803 }
804 }
805
806
807
808
809 public static final class IndirectFunctionTarget implements Serializable {
810 private static final long serialVersionUID = 1L;
811 private transient Supplier<Address> addressSupplier;
812
813
814 private Address address;
815
816
817 private final long numFormalParams;
818
819
820 private final Set<Integer> arrayParameterIndexes;
821
822
823
824
825
826
827
828
829
830 public IndirectFunctionTarget(
831 Supplier<Address> addressSupplierParam,
832 long numFormalParamsParam,
833 Set<Integer> arrayParameterIndexesParam) {
834 addressSupplier = addressSupplierParam;
835 numFormalParams = numFormalParamsParam;
836 arrayParameterIndexes = Collections.unmodifiableSet(new HashSet<Integer>(arrayParameterIndexesParam));
837 }
838
839 private void resolve() {
840 if (address == null && addressSupplier != null) {
841 address = addressSupplier.get();
842 addressSupplier = null;
843 }
844 }
845
846
847
848
849
850
851 public Address getAddress() {
852 resolve();
853 return address;
854 }
855
856
857
858
859
860
861 public long getNumFormalParams() {
862 return numFormalParams;
863 }
864
865
866
867
868
869
870
871 public boolean isArrayParameter(int index) {
872 return arrayParameterIndexes.contains(Integer.valueOf(index));
873 }
874 }
875
876
877
878
879 public static final class IndirectCallTuple extends Tuple {
880 private static final long serialVersionUID = 1L;
881
882
883 private final Map<String, IndirectFunctionTarget> userFunctions;
884
885
886 private final Map<String, ExtensionFunction> extensionFunctions;
887
888
889 private final long numActualParams;
890
891
892 private final String sourceName;
893
894
895 private final int sourceLine;
896
897 IndirectCallTuple(
898 Map<String, IndirectFunctionTarget> userFunctionsParam,
899 Map<String, ExtensionFunction> extensionFunctionsParam,
900 long numActualParamsParam,
901 String sourceNameParam,
902 int sourceLineParam) {
903 super(Opcode.INDIRECT_CALL);
904 userFunctions = userFunctionsParam;
905 extensionFunctions = extensionFunctionsParam;
906 numActualParams = numActualParamsParam;
907 sourceName = sourceNameParam;
908 sourceLine = sourceLineParam;
909 }
910
911 @Override
912 public void touch(List<Tuple> queue) {
913 for (IndirectFunctionTarget target : userFunctions.values()) {
914 target.resolve();
915 }
916 super.touch(queue);
917 }
918
919 @Override
920 public List<Address> getAddresses() {
921 List<Address> addresses = new ArrayList<Address>(userFunctions.size());
922 for (IndirectFunctionTarget target : userFunctions.values()) {
923 addresses.add(target.getAddress());
924 }
925 return addresses;
926 }
927
928
929
930
931
932
933 @SuppressFBWarnings(value = "EI_EXPOSE_REP", justification = "The map is an immutable metadata snapshot shared by every indirect call tuple")
934 public Map<String, IndirectFunctionTarget> getUserFunctions() {
935 return userFunctions;
936 }
937
938
939
940
941
942
943 @SuppressFBWarnings(value = "EI_EXPOSE_REP", justification = "The map is an immutable metadata snapshot shared by every indirect call tuple")
944 public Map<String, ExtensionFunction> getExtensionFunctions() {
945 return extensionFunctions;
946 }
947
948
949
950
951
952
953 public long getNumActualParams() {
954 return numActualParams;
955 }
956
957
958
959
960
961
962 public String getSourceName() {
963 return sourceName;
964 }
965
966
967
968
969
970
971 public int getSourceLine() {
972 return sourceLine;
973 }
974
975 @Override
976 public String toString() {
977 return getOpcode().name() + ", " + numActualParams;
978 }
979 }
980
981
982
983
984 public static final class ExtensionTuple extends Tuple {
985 private static final long serialVersionUID = 2L;
986
987
988 private final ExtensionFunction function;
989
990
991 private final long argCount;
992
993 ExtensionTuple(ExtensionFunction function, long argCount) {
994 super(Opcode.EXTENSION);
995 this.function = function;
996 this.argCount = argCount;
997 }
998
999
1000
1001
1002
1003
1004 public ExtensionFunction getFunction() {
1005 return function;
1006 }
1007
1008
1009
1010
1011
1012
1013 public long getArgCount() {
1014 return argCount;
1015 }
1016
1017 @Override
1018 public String toString() {
1019 return getOpcode().name()
1020 + ", "
1021 + function.getKeyword()
1022 + ", "
1023 + argCount;
1024 }
1025 }
1026
1027
1028
1029
1030
1031
1032
1033 public static final class WarningTuple extends Tuple {
1034 private static final long serialVersionUID = 1L;
1035
1036
1037 private final String message;
1038
1039 WarningTuple(String message) {
1040 super(Opcode.WARNING);
1041 this.message = message;
1042 }
1043
1044
1045
1046
1047
1048
1049 public String getMessage() {
1050 return message;
1051 }
1052
1053 @Override
1054 public String toString() {
1055 return getOpcode().name() + stringArgument(message);
1056 }
1057 }
1058 }