Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 4e3ae98

Browse files
committed
Python: CG trace: Handle list-comprehension and iteration
Which relies on LOAD_CONST and MAKE_FUNCTION
1 parent 58f1119 commit 4e3ae98

2 files changed

Lines changed: 40 additions & 5 deletions

File tree

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
for i in range(10):
2+
print(i)
3+
4+
[i + 1 for i in range(10)]
5+
l = list(range(10))
6+
[i + 1 for i in l]
7+
[i + 1 for i in l]

python/tools/recorded-call-graph-metrics/src/cg_trace/bytecode_reconstructor.py

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import logging
44
from dis import Instruction
55
from types import FrameType
6-
from typing import List
6+
from typing import Any, List
77

88
LOGGER = logging.getLogger(__name__)
99

@@ -18,6 +18,16 @@ class BytecodeExpr:
1818
"""
1919

2020

21+
@dataclasses.dataclass(frozen=True, eq=True, order=True)
22+
class BytecodeConst(BytecodeExpr):
23+
"""FOR LOAD_CONST"""
24+
25+
value: Any
26+
27+
def __str__(self):
28+
return repr(self.value)
29+
30+
2131
@dataclasses.dataclass(frozen=True, eq=True, order=True)
2232
class BytecodeVariableName(BytecodeExpr):
2333
name: str
@@ -51,6 +61,16 @@ def __str__(self):
5161
return f"<{self.opname}>"
5262

5363

64+
@dataclasses.dataclass(frozen=True, eq=True, order=True)
65+
class BytecodeMakeFunction(BytecodeExpr):
66+
"""For MAKE_FUNCTION opcode"""
67+
68+
qualified_name: BytecodeExpr
69+
70+
def __str__(self):
71+
return f"<MAKE_FUNCTION>(qualified_name={self.qualified_name})>"
72+
73+
5474
def expr_that_added_elem_to_stack(
5575
instructions: List[Instruction], start_index: int, stack_pos: int
5676
):
@@ -101,6 +121,9 @@ def expr_from_instruction(instructions: List[Instruction], index: int) -> Byteco
101121
if inst.opname in ["LOAD_GLOBAL", "LOAD_FAST", "LOAD_NAME"]:
102122
return BytecodeVariableName(inst.argval)
103123

124+
elif inst.opname in ["LOAD_CONST"]:
125+
return BytecodeConst(inst.argval)
126+
104127
# https://docs.python.org/3/library/dis.html#opcode-LOAD_METHOD
105128
# https://docs.python.org/3/library/dis.html#opcode-LOAD_ATTR
106129
elif inst.opname in ["LOAD_METHOD", "LOAD_ATTR"]:
@@ -122,11 +145,16 @@ def expr_from_instruction(instructions: List[Instruction], index: int) -> Byteco
122145
)
123146
return BytecodeCall(function=func_expr)
124147

125-
else:
126-
# LOAD_BUILD_CLASS is included here intentionally for now, since I don't really
127-
# know what to do about it.
148+
elif inst.opname in ["MAKE_FUNCTION"]:
149+
name_expr = expr_that_added_elem_to_stack(instructions, index - 1, 0)
150+
assert isinstance(name_expr, BytecodeConst)
151+
return BytecodeMakeFunction(qualified_name=name_expr)
152+
153+
# LOAD_BUILD_CLASS is included here intentionally for now, since I don't really
154+
# know what to do about it.
155+
if inst.opname not in ["LOAD_BUILD_CLASS"]:
128156
LOGGER.warning(f"Don't know how to handle this type of instruction: {inst}")
129-
return BytecodeUnknown(inst.opname)
157+
return BytecodeUnknown(inst.opname)
130158

131159

132160
def expr_from_frame(frame: FrameType) -> BytecodeExpr:

0 commit comments

Comments
 (0)