Python: CG trace: Handle list-comprehension and iteration

Which relies on LOAD_CONST and MAKE_FUNCTION
This commit is contained in:
Rasmus Wriedt Larsen
2020-07-21 19:54:59 +02:00
parent 58f11194a8
commit 4e3ae98ddf
2 changed files with 40 additions and 5 deletions

View File

@@ -0,0 +1,7 @@
for i in range(10):
print(i)
[i + 1 for i in range(10)]
l = list(range(10))
[i + 1 for i in l]
[i + 1 for i in l]

View File

@@ -3,7 +3,7 @@ import dis
import logging import logging
from dis import Instruction from dis import Instruction
from types import FrameType from types import FrameType
from typing import List from typing import Any, List
LOGGER = logging.getLogger(__name__) LOGGER = logging.getLogger(__name__)
@@ -18,6 +18,16 @@ class BytecodeExpr:
""" """
@dataclasses.dataclass(frozen=True, eq=True, order=True)
class BytecodeConst(BytecodeExpr):
"""FOR LOAD_CONST"""
value: Any
def __str__(self):
return repr(self.value)
@dataclasses.dataclass(frozen=True, eq=True, order=True) @dataclasses.dataclass(frozen=True, eq=True, order=True)
class BytecodeVariableName(BytecodeExpr): class BytecodeVariableName(BytecodeExpr):
name: str name: str
@@ -51,6 +61,16 @@ class BytecodeUnknown(BytecodeExpr):
return f"<{self.opname}>" return f"<{self.opname}>"
@dataclasses.dataclass(frozen=True, eq=True, order=True)
class BytecodeMakeFunction(BytecodeExpr):
"""For MAKE_FUNCTION opcode"""
qualified_name: BytecodeExpr
def __str__(self):
return f"<MAKE_FUNCTION>(qualified_name={self.qualified_name})>"
def expr_that_added_elem_to_stack( def expr_that_added_elem_to_stack(
instructions: List[Instruction], start_index: int, stack_pos: int instructions: List[Instruction], start_index: int, stack_pos: int
): ):
@@ -101,6 +121,9 @@ def expr_from_instruction(instructions: List[Instruction], index: int) -> Byteco
if inst.opname in ["LOAD_GLOBAL", "LOAD_FAST", "LOAD_NAME"]: if inst.opname in ["LOAD_GLOBAL", "LOAD_FAST", "LOAD_NAME"]:
return BytecodeVariableName(inst.argval) return BytecodeVariableName(inst.argval)
elif inst.opname in ["LOAD_CONST"]:
return BytecodeConst(inst.argval)
# https://docs.python.org/3/library/dis.html#opcode-LOAD_METHOD # https://docs.python.org/3/library/dis.html#opcode-LOAD_METHOD
# https://docs.python.org/3/library/dis.html#opcode-LOAD_ATTR # https://docs.python.org/3/library/dis.html#opcode-LOAD_ATTR
elif inst.opname in ["LOAD_METHOD", "LOAD_ATTR"]: elif inst.opname in ["LOAD_METHOD", "LOAD_ATTR"]:
@@ -122,11 +145,16 @@ def expr_from_instruction(instructions: List[Instruction], index: int) -> Byteco
) )
return BytecodeCall(function=func_expr) return BytecodeCall(function=func_expr)
else: elif inst.opname in ["MAKE_FUNCTION"]:
# LOAD_BUILD_CLASS is included here intentionally for now, since I don't really name_expr = expr_that_added_elem_to_stack(instructions, index - 1, 0)
# know what to do about it. assert isinstance(name_expr, BytecodeConst)
return BytecodeMakeFunction(qualified_name=name_expr)
# LOAD_BUILD_CLASS is included here intentionally for now, since I don't really
# know what to do about it.
if inst.opname not in ["LOAD_BUILD_CLASS"]:
LOGGER.warning(f"Don't know how to handle this type of instruction: {inst}") LOGGER.warning(f"Don't know how to handle this type of instruction: {inst}")
return BytecodeUnknown(inst.opname) return BytecodeUnknown(inst.opname)
def expr_from_frame(frame: FrameType) -> BytecodeExpr: def expr_from_frame(frame: FrameType) -> BytecodeExpr: