Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions pytest/test_cross_dis.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import pytest
from xdis.cross_dis import findlabels
from xdis.op_imports import get_opcode_module
from xdis.version_info import IS_GRAAL, PYTHON_VERSION_TRIPLE
from xdis.version_info import IS_GRAAL, PYTHON_IMPLEMENTATION, PYTHON_VERSION_TRIPLE


@pytest.mark.skipif(IS_GRAAL, reason="Graal label finding is wonky")
Expand All @@ -13,7 +13,7 @@
)
def test_findlabels():
code = findlabels.__code__.co_code
opc = get_opcode_module()
opc = get_opcode_module(PYTHON_VERSION_TRIPLE, PYTHON_IMPLEMENTATION)

assert findlabels(code, opc) == findlabels_std(code)

Expand Down
2 changes: 1 addition & 1 deletion pytest/test_disasm.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ def run_check_disasm(test_tuple, function_to_test):
[
("01_fstring", "3.6", ["classic", "xasm"]),
# ("01_fstring", "3.10"), # FIXME
("04_pypy_lambda", "2.7pypy", ["classic", "xasm"]),
("04_pypy_lambda", "2.7PyPy", ["classic", "xasm"]),
("03_big_dict", "2.7", ["classic", "xasm"]),
("03_big_dict", "3.3", ["classic", "xasm"]),
("03_big_dict", "3.5", ["classic", "xasm"]),
Expand Down
7 changes: 2 additions & 5 deletions pytest/test_stack_effect.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from xdis import get_opcode
from xdis.cross_dis import op_has_argument, xstack_effect
from xdis.op_imports import get_opcode_module
from xdis.version_info import PYTHON_IMPLEMENTATION, PYTHON_VERSION_TRIPLE


def get_srcdir() -> str:
Expand Down Expand Up @@ -123,11 +124,7 @@ def test_one(xdis_args, dis_args, has_arg: bool) -> None:
)
print("%d (%s) is good: effect %d" % (opcode, opname, effect))

if xdis.IS_PYPY:
variant = "pypy"
else:
variant = ""
opc = get_opcode_module(None, variant)
opc = get_opcode_module(PYTHON_VERSION_TRIPLE, PYTHON_IMPLEMENTATION)
for (
opname,
opcode,
Expand Down
2 changes: 2 additions & 0 deletions xdis/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@
IS_GRAAL,
IS_PYPY,
PYTHON3,
PYTHON_IMPLEMENTATION,
PYTHON_VERSION_STR,
PYTHON_VERSION_TRIPLE,
)
Expand Down Expand Up @@ -284,6 +285,7 @@
"IS_GRAAL",
"IS_PYPY",
"PYTHON3",
"PYTHON_IMPLEMENTATION",
"PYTHON_VERSION_STR",
"PYTHON_VERSION_TRIPLE",
"__version__",
Expand Down
6 changes: 2 additions & 4 deletions xdis/bytecode.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,7 @@
from xdis.op_imports import get_opcode_module
from xdis.opcodes.opcode_36 import format_CALL_FUNCTION, format_CALL_FUNCTION_EX
from xdis.util import code2num, num2code
from xdis.version_info import IS_PYPY

VARIANT = "pypy" if IS_PYPY else None
from xdis.version_info import PYTHON_IMPLEMENTATION


def get_docstring(filename: str, line_number: int, doc_str: str) -> str:
Expand Down Expand Up @@ -573,7 +571,7 @@ def __repr__(self) -> str:
def from_traceback(cls, tb, opc=None):
"""Construct a Bytecode from the given traceback"""
if opc is None:
opc = get_opcode_module(sys.version_info, VARIANT)
opc = get_opcode_module(sys.version_info, PYTHON_IMPLEMENTATION)
while tb.tb_next:
tb = tb.tb_next
return cls(
Expand Down
44 changes: 31 additions & 13 deletions xdis/cross_dis.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,15 @@
# earlier versions of xdis (and without attribution).

from types import CodeType
from typing import List, Optional
from typing import List, Optional, Tuple

from xdis.util import (
COMPILER_FLAG_NAMES,
PYPY_COMPILER_FLAG_NAMES,
better_repr,
code2num,
)
from xdis.version_info import IS_GRAAL
from xdis.version_info import IS_GRAAL, PYTHON_IMPLEMENTATION, PythonImplementation


def _try_compile(source: str, name: str) -> CodeType:
Expand All @@ -44,9 +44,13 @@ def _try_compile(source: str, name: str) -> CodeType:
return c


def code_info(x, version_tuple, is_pypy=False) -> str:
def code_info(
x, version_tuple: Tuple[int, ...], python_implementation: PythonImplementation
) -> str:
"""Formatted details of methods, functions, or code."""
return format_code_info(get_code_object(x), version_tuple, is_pypy=is_pypy)
return format_code_info(
get_code_object(x), version_tuple, python_implementation=python_implementation
)


def get_code_object(x):
Expand Down Expand Up @@ -96,9 +100,11 @@ def get_cache_size_313(opname: str) -> int:
}
return _inline_cache_entries.get(opname, 0)


# For compatibility
_get_cache_size_313 = get_cache_size_313


def findlabels(code: bytes, opc):
if opc.version_tuple < (3, 10) or IS_GRAAL:
return findlabels_pre_310(code, opc)
Expand All @@ -114,7 +120,10 @@ def findlabels_310(code: bytes, opc):
for offset, op, arg in unpack_opargs_bytecode_310(code, opc):
if arg is not None:
if op in opc.JREL_OPS:
if opc.version_tuple >= (3, 11) and opc.opname[op] in ("JUMP_BACKWARD", "JUMP_BACKWARD_NO_INTERRUPT"):
if opc.version_tuple >= (3, 11) and opc.opname[op] in (
"JUMP_BACKWARD",
"JUMP_BACKWARD_NO_INTERRUPT",
):
arg = -arg
label = offset + 2 + arg * 2
# in 3.13 we have to add total cache offsets to label
Expand Down Expand Up @@ -155,7 +164,7 @@ def findlabels_pre_310(code, opc):
NO_LINE_NUMBER = -128


def findlinestarts(code, dup_lines: bool=False):
def findlinestarts(code, dup_lines: bool = False):
"""Find the offsets in a byte code which are start of lines in the source.

Generate pairs (offset, lineno) as described in Python/compile.c.
Expand Down Expand Up @@ -234,15 +243,20 @@ def instruction_size(op, opc) -> int:
op_size = instruction_size


def show_code(co, version_tuple, file=None, is_pypy: bool=False) -> None:
def show_code(
co,
version_tuple: Tuple[int, ...],
file=None,
python_implementation=PYTHON_IMPLEMENTATION,
) -> None:
"""Print details of methods, functions, or code to *file*.

If *file* is not provided, the output is printed on stdout.
"""
if file is None:
print(code_info(co, version_tuple, is_pypy=is_pypy))
print(code_info(co, version_tuple, python_implementation))
else:
file.write(code_info(co, version_tuple) + "\n")
file.write(code_info(co, version_tuple, python_implementation) + "\n")


def op_has_argument(opcode: int, opc) -> bool:
Expand All @@ -252,15 +266,15 @@ def op_has_argument(opcode: int, opc) -> bool:
return opcode >= opc.HAVE_ARGUMENT


def pretty_flags(flags, is_pypy=False) -> str:
def pretty_flags(flags, python_implementation=PYTHON_IMPLEMENTATION) -> str:
"""Return pretty representation of code flags."""
names = []
result = "0x%08x" % flags
for i in range(32):
flag = 1 << i
if flags & flag:
names.append(COMPILER_FLAG_NAMES.get(flag, hex(flag)))
if is_pypy:
if python_implementation == PythonImplementation.PyPy:
names.append(PYPY_COMPILER_FLAG_NAMES.get(flag, hex(flag)))
flags ^= flag
if not flags:
Expand All @@ -272,7 +286,11 @@ def pretty_flags(flags, is_pypy=False) -> str:


def format_code_info(
co, version_tuple: tuple, name=None, is_pypy=False, is_graal=False, file_offset: Optional[tuple]=None
co,
version_tuple: tuple,
name=None,
python_implementation=PYTHON_IMPLEMENTATION,
file_offset: Optional[tuple] = None,
) -> str:
if not name:
name = co.co_name
Expand Down Expand Up @@ -306,7 +324,7 @@ def format_code_info(

if version_tuple >= (1, 3):
lines.append(
"# Flags: %s" % pretty_flags(co.co_flags, is_pypy=is_pypy)
"# Flags: %s" % pretty_flags(co.co_flags, python_implementation)
)

if version_tuple >= (1, 5):
Expand Down
Loading