Skip to content

Commit 3510a3c

Browse files
committed
Use subclass of Instr to distinguish original and artifical instructions.
1 parent 85707a4 commit 3510a3c

File tree

1 file changed

+105
-88
lines changed

1 file changed

+105
-88
lines changed

pynguin/instrumentation/instrumentation.py

Lines changed: 105 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,11 @@
2828
CODE_OBJECT_ID_KEY = "code_object_id"
2929

3030

31+
class ArtificialInstr(Instr):
32+
"""Marker subclass to distinguish between original instructions
33+
and instructions that were inserted by the instrumentation."""
34+
35+
3136
# pylint:disable=too-few-public-methods
3237
class InstrumentationAdapter:
3338
"""Abstract base class for bytecode instrumentation adapters.
@@ -94,7 +99,7 @@ def _create_consecutive_blocks(
9499
current: BasicBlock = first
95100
nodes: list[BasicBlock] = []
96101
# Can be any instruction, as it is discarded anyway.
97-
dummy_instruction = Instr("POP_TOP")
102+
dummy_instruction = ArtificialInstr("POP_TOP")
98103
for _ in range(amount):
99104
# Insert dummy instruction, which we can use to split off another block
100105
current.insert(0, dummy_instruction)
@@ -348,18 +353,18 @@ def _instrument_bool_based_conditional_jump(
348353
# We duplicate the value on top of the stack and report
349354
# it to the tracer.
350355
block[self._JUMP_OP_POS : self._JUMP_OP_POS] = [
351-
Instr("DUP_TOP", lineno=lineno),
352-
Instr("LOAD_CONST", self._tracer, lineno=lineno),
353-
Instr(
356+
ArtificialInstr("DUP_TOP", lineno=lineno),
357+
ArtificialInstr("LOAD_CONST", self._tracer, lineno=lineno),
358+
ArtificialInstr(
354359
"LOAD_METHOD",
355360
ExecutionTracer.executed_bool_predicate.__name__,
356361
lineno=lineno,
357362
),
358-
Instr("ROT_THREE", lineno=lineno),
359-
Instr("ROT_THREE", lineno=lineno),
360-
Instr("LOAD_CONST", predicate_id, lineno=lineno),
361-
Instr("CALL_METHOD", 2, lineno=lineno),
362-
Instr("POP_TOP", lineno=lineno),
363+
ArtificialInstr("ROT_THREE", lineno=lineno),
364+
ArtificialInstr("ROT_THREE", lineno=lineno),
365+
ArtificialInstr("LOAD_CONST", predicate_id, lineno=lineno),
366+
ArtificialInstr("CALL_METHOD", 2, lineno=lineno),
367+
ArtificialInstr("POP_TOP", lineno=lineno),
363368
]
364369
return predicate_id
365370

@@ -405,19 +410,19 @@ def _instrument_compare_based_conditional_jump(
405410
# We duplicate the values on top of the stack and report
406411
# them to the tracer.
407412
block[self._COMPARE_OP_POS : self._COMPARE_OP_POS] = [
408-
Instr("DUP_TOP_TWO", lineno=lineno),
409-
Instr("LOAD_CONST", self._tracer, lineno=lineno),
410-
Instr(
413+
ArtificialInstr("DUP_TOP_TWO", lineno=lineno),
414+
ArtificialInstr("LOAD_CONST", self._tracer, lineno=lineno),
415+
ArtificialInstr(
411416
"LOAD_METHOD",
412417
ExecutionTracer.executed_compare_predicate.__name__,
413418
lineno=lineno,
414419
),
415-
Instr("ROT_FOUR", lineno=lineno),
416-
Instr("ROT_FOUR", lineno=lineno),
417-
Instr("LOAD_CONST", predicate_id, lineno=lineno),
418-
Instr("LOAD_CONST", compare, lineno=lineno),
419-
Instr("CALL_METHOD", 4, lineno=lineno),
420-
Instr("POP_TOP", lineno=lineno),
420+
ArtificialInstr("ROT_FOUR", lineno=lineno),
421+
ArtificialInstr("ROT_FOUR", lineno=lineno),
422+
ArtificialInstr("LOAD_CONST", predicate_id, lineno=lineno),
423+
ArtificialInstr("LOAD_CONST", compare, lineno=lineno),
424+
ArtificialInstr("CALL_METHOD", 4, lineno=lineno),
425+
ArtificialInstr("POP_TOP", lineno=lineno),
421426
]
422427
return predicate_id
423428

@@ -445,18 +450,18 @@ def _instrument_exception_based_conditional_jump(
445450
# We duplicate the values on top of the stack and report
446451
# them to the tracer.
447452
block[self._JUMP_OP_POS : self._JUMP_OP_POS] = [
448-
Instr("DUP_TOP_TWO", lineno=lineno),
449-
Instr("LOAD_CONST", self._tracer, lineno=lineno),
450-
Instr(
453+
ArtificialInstr("DUP_TOP_TWO", lineno=lineno),
454+
ArtificialInstr("LOAD_CONST", self._tracer, lineno=lineno),
455+
ArtificialInstr(
451456
"LOAD_METHOD",
452457
ExecutionTracer.executed_exception_match.__name__,
453458
lineno=lineno,
454459
),
455-
Instr("ROT_FOUR", lineno=lineno),
456-
Instr("ROT_FOUR", lineno=lineno),
457-
Instr("LOAD_CONST", predicate_id, lineno=lineno),
458-
Instr("CALL_METHOD", 3, lineno=lineno),
459-
Instr("POP_TOP", lineno=lineno),
460+
ArtificialInstr("ROT_FOUR", lineno=lineno),
461+
ArtificialInstr("ROT_FOUR", lineno=lineno),
462+
ArtificialInstr("LOAD_CONST", predicate_id, lineno=lineno),
463+
ArtificialInstr("CALL_METHOD", 3, lineno=lineno),
464+
ArtificialInstr("POP_TOP", lineno=lineno),
460465
]
461466
return predicate_id
462467

@@ -473,15 +478,15 @@ def visit_entry_node(self, block: BasicBlock, code_object_id: int) -> None:
473478
lineno = block[0].lineno
474479
# Insert instructions at the beginning.
475480
block[0:0] = [
476-
Instr("LOAD_CONST", self._tracer, lineno=lineno),
477-
Instr(
481+
ArtificialInstr("LOAD_CONST", self._tracer, lineno=lineno),
482+
ArtificialInstr(
478483
"LOAD_METHOD",
479484
ExecutionTracer.executed_code_object.__name__,
480485
lineno=lineno,
481486
),
482-
Instr("LOAD_CONST", code_object_id, lineno=lineno),
483-
Instr("CALL_METHOD", 1, lineno=lineno),
484-
Instr("POP_TOP", lineno=lineno),
487+
ArtificialInstr("LOAD_CONST", code_object_id, lineno=lineno),
488+
ArtificialInstr("CALL_METHOD", 1, lineno=lineno),
489+
ArtificialInstr("POP_TOP", lineno=lineno),
485490
]
486491

487492
def _instrument_for_loop(
@@ -537,37 +542,39 @@ def _instrument_for_loop(
537542
entered, not_entered = self._create_consecutive_blocks(
538543
cfg.bytecode_cfg(), basic_block, 2
539544
)
545+
# TODO(fk) for_instr is not artificial but we changed it
546+
# How to deal with this?
540547
for_instr.arg = not_entered
541548

542549
entered.extend(
543550
[
544-
Instr("LOAD_CONST", self._tracer, lineno=lineno),
545-
Instr(
551+
ArtificialInstr("LOAD_CONST", self._tracer, lineno=lineno),
552+
ArtificialInstr(
546553
"LOAD_METHOD",
547554
ExecutionTracer.executed_bool_predicate.__name__,
548555
lineno=lineno,
549556
),
550-
Instr("LOAD_CONST", True, lineno=lineno),
551-
Instr("LOAD_CONST", predicate_id, lineno=lineno),
552-
Instr("CALL_METHOD", 2, lineno=lineno),
553-
Instr("POP_TOP", lineno=lineno),
554-
Instr("JUMP_ABSOLUTE", for_loop_body, lineno=lineno),
557+
ArtificialInstr("LOAD_CONST", True, lineno=lineno),
558+
ArtificialInstr("LOAD_CONST", predicate_id, lineno=lineno),
559+
ArtificialInstr("CALL_METHOD", 2, lineno=lineno),
560+
ArtificialInstr("POP_TOP", lineno=lineno),
561+
ArtificialInstr("JUMP_ABSOLUTE", for_loop_body, lineno=lineno),
555562
]
556563
)
557564

558565
not_entered.extend(
559566
[
560-
Instr("LOAD_CONST", self._tracer, lineno=lineno),
561-
Instr(
567+
ArtificialInstr("LOAD_CONST", self._tracer, lineno=lineno),
568+
ArtificialInstr(
562569
"LOAD_METHOD",
563570
ExecutionTracer.executed_bool_predicate.__name__,
564571
lineno=lineno,
565572
),
566-
Instr("LOAD_CONST", False, lineno=lineno),
567-
Instr("LOAD_CONST", predicate_id, lineno=lineno),
568-
Instr("CALL_METHOD", 2, lineno=lineno),
569-
Instr("POP_TOP", lineno=lineno),
570-
Instr("JUMP_ABSOLUTE", for_loop_exit, lineno=lineno),
573+
ArtificialInstr("LOAD_CONST", False, lineno=lineno),
574+
ArtificialInstr("LOAD_CONST", predicate_id, lineno=lineno),
575+
ArtificialInstr("CALL_METHOD", 2, lineno=lineno),
576+
ArtificialInstr("POP_TOP", lineno=lineno),
577+
ArtificialInstr("JUMP_ABSOLUTE", for_loop_exit, lineno=lineno),
571578
]
572579
)
573580

@@ -622,15 +629,15 @@ def instrument_line(
622629
The number of instructions inserted into the block
623630
"""
624631
inserted_instructions = [
625-
Instr("LOAD_CONST", self._tracer, lineno=lineno),
626-
Instr(
632+
ArtificialInstr("LOAD_CONST", self._tracer, lineno=lineno),
633+
ArtificialInstr(
627634
"LOAD_METHOD",
628635
self._tracer.track_line_visit.__name__,
629636
lineno=lineno,
630637
),
631-
Instr("LOAD_CONST", line_id, lineno=lineno),
632-
Instr("CALL_METHOD", 1, lineno=lineno),
633-
Instr("POP_TOP", lineno=lineno),
638+
ArtificialInstr("LOAD_CONST", line_id, lineno=lineno),
639+
ArtificialInstr("CALL_METHOD", 1, lineno=lineno),
640+
ArtificialInstr("POP_TOP", lineno=lineno),
634641
]
635642
# Insert instructions at the beginning.
636643
block[instr_index:instr_index] = inserted_instructions
@@ -734,19 +741,21 @@ def _instrument_startswith_function(self, block: BasicBlock) -> None:
734741
insert_pos = self._STRING_FUNC_POS_WITH_ARG + 2
735742
lineno = block[insert_pos].lineno
736743
block[insert_pos:insert_pos] = [
737-
Instr("DUP_TOP_TWO", lineno=lineno),
738-
Instr("ROT_TWO", lineno=lineno),
739-
Instr("BINARY_ADD", lineno=lineno),
740-
Instr("LOAD_CONST", self._dynamic_constant_seeding, lineno=lineno),
741-
Instr(
744+
ArtificialInstr("DUP_TOP_TWO", lineno=lineno),
745+
ArtificialInstr("ROT_TWO", lineno=lineno),
746+
ArtificialInstr("BINARY_ADD", lineno=lineno),
747+
ArtificialInstr(
748+
"LOAD_CONST", self._dynamic_constant_seeding, lineno=lineno
749+
),
750+
ArtificialInstr(
742751
"LOAD_METHOD",
743752
self._dynamic_constant_seeding.add_value.__name__,
744753
lineno=lineno,
745754
),
746-
Instr("ROT_THREE", lineno=lineno),
747-
Instr("ROT_THREE", lineno=lineno),
748-
Instr("CALL_METHOD", 1, lineno=lineno),
749-
Instr("POP_TOP", lineno=lineno),
755+
ArtificialInstr("ROT_THREE", lineno=lineno),
756+
ArtificialInstr("ROT_THREE", lineno=lineno),
757+
ArtificialInstr("CALL_METHOD", 1, lineno=lineno),
758+
ArtificialInstr("POP_TOP", lineno=lineno),
750759
]
751760
self._logger.info("Instrumented startswith function")
752761

@@ -761,18 +770,20 @@ def _instrument_endswith_function(self, block: BasicBlock) -> None:
761770
insert_pos = self._STRING_FUNC_POS_WITH_ARG + 2
762771
lineno = block[insert_pos].lineno
763772
block[insert_pos:insert_pos] = [
764-
Instr("DUP_TOP_TWO", lineno=lineno),
765-
Instr("BINARY_ADD", lineno=lineno),
766-
Instr("LOAD_CONST", self._dynamic_constant_seeding, lineno=lineno),
767-
Instr(
773+
ArtificialInstr("DUP_TOP_TWO", lineno=lineno),
774+
ArtificialInstr("BINARY_ADD", lineno=lineno),
775+
ArtificialInstr(
776+
"LOAD_CONST", self._dynamic_constant_seeding, lineno=lineno
777+
),
778+
ArtificialInstr(
768779
"LOAD_METHOD",
769780
DynamicConstantSeeding.add_value.__name__,
770781
lineno=lineno,
771782
),
772-
Instr("ROT_THREE", lineno=lineno),
773-
Instr("ROT_THREE", lineno=lineno),
774-
Instr("CALL_METHOD", 1, lineno=lineno),
775-
Instr("POP_TOP", lineno=lineno),
783+
ArtificialInstr("ROT_THREE", lineno=lineno),
784+
ArtificialInstr("ROT_THREE", lineno=lineno),
785+
ArtificialInstr("CALL_METHOD", 1, lineno=lineno),
786+
ArtificialInstr("POP_TOP", lineno=lineno),
776787
]
777788
self._logger.info("Instrumented endswith function")
778789

@@ -788,18 +799,20 @@ def _instrument_string_function_without_arg(
788799
insert_pos = self._STRING_FUNC_POS_WITH_ARG + 2
789800
lineno = block[insert_pos].lineno
790801
block[insert_pos:insert_pos] = [
791-
Instr("DUP_TOP", lineno=lineno),
792-
Instr("LOAD_CONST", self._dynamic_constant_seeding, lineno=lineno),
793-
Instr(
802+
ArtificialInstr("DUP_TOP", lineno=lineno),
803+
ArtificialInstr(
804+
"LOAD_CONST", self._dynamic_constant_seeding, lineno=lineno
805+
),
806+
ArtificialInstr(
794807
"LOAD_METHOD",
795808
DynamicConstantSeeding.add_value_for_strings.__name__,
796809
lineno=lineno,
797810
),
798-
Instr("ROT_THREE", lineno=lineno),
799-
Instr("ROT_THREE", lineno=lineno),
800-
Instr("LOAD_CONST", function_name, lineno=lineno),
801-
Instr("CALL_METHOD", 2, lineno=lineno),
802-
Instr("POP_TOP", lineno=lineno),
811+
ArtificialInstr("ROT_THREE", lineno=lineno),
812+
ArtificialInstr("ROT_THREE", lineno=lineno),
813+
ArtificialInstr("LOAD_CONST", function_name, lineno=lineno),
814+
ArtificialInstr("CALL_METHOD", 2, lineno=lineno),
815+
ArtificialInstr("POP_TOP", lineno=lineno),
803816
]
804817
self._logger.info("Instrumented string function")
805818

@@ -827,26 +840,30 @@ def _instrument_compare_op(self, block: BasicBlock) -> None:
827840
"""
828841
lineno = block[self._COMPARE_OP_POS].lineno
829842
block[self._COMPARE_OP_POS : self._COMPARE_OP_POS] = [
830-
Instr("DUP_TOP_TWO", lineno=lineno),
831-
Instr("LOAD_CONST", self._dynamic_constant_seeding, lineno=lineno),
832-
Instr(
843+
ArtificialInstr("DUP_TOP_TWO", lineno=lineno),
844+
ArtificialInstr(
845+
"LOAD_CONST", self._dynamic_constant_seeding, lineno=lineno
846+
),
847+
ArtificialInstr(
833848
"LOAD_METHOD",
834849
DynamicConstantSeeding.add_value.__name__,
835850
lineno=lineno,
836851
),
837-
Instr("ROT_THREE", lineno=lineno),
838-
Instr("ROT_THREE", lineno=lineno),
839-
Instr("CALL_METHOD", 1, lineno=lineno),
840-
Instr("POP_TOP", lineno=lineno),
841-
Instr("LOAD_CONST", self._dynamic_constant_seeding, lineno=lineno),
842-
Instr(
852+
ArtificialInstr("ROT_THREE", lineno=lineno),
853+
ArtificialInstr("ROT_THREE", lineno=lineno),
854+
ArtificialInstr("CALL_METHOD", 1, lineno=lineno),
855+
ArtificialInstr("POP_TOP", lineno=lineno),
856+
ArtificialInstr(
857+
"LOAD_CONST", self._dynamic_constant_seeding, lineno=lineno
858+
),
859+
ArtificialInstr(
843860
"LOAD_METHOD",
844861
DynamicConstantSeeding.add_value.__name__,
845862
lineno=lineno,
846863
),
847-
Instr("ROT_THREE", lineno=lineno),
848-
Instr("ROT_THREE", lineno=lineno),
849-
Instr("CALL_METHOD", 1, lineno=lineno),
850-
Instr("POP_TOP", lineno=lineno),
864+
ArtificialInstr("ROT_THREE", lineno=lineno),
865+
ArtificialInstr("ROT_THREE", lineno=lineno),
866+
ArtificialInstr("CALL_METHOD", 1, lineno=lineno),
867+
ArtificialInstr("POP_TOP", lineno=lineno),
851868
]
852869
self._logger.debug("Instrumented compare_op")

0 commit comments

Comments
 (0)