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