Skip to content

Commit

Permalink
fewer tests are failing
Browse files Browse the repository at this point in the history
  • Loading branch information
iritkatriel committed Dec 8, 2022
1 parent 144c64d commit ac05ae0
Show file tree
Hide file tree
Showing 4 changed files with 236 additions and 209 deletions.
37 changes: 29 additions & 8 deletions Lib/dis.py
Original file line number Diff line number Diff line change
Expand Up @@ -346,11 +346,12 @@ def get_instructions(x, *, first_line=None, show_caches=False, adaptive=False):
line_offset = first_line - co.co_firstlineno
else:
line_offset = 0
co_positions = _get_co_positions(co, show_caches=show_caches)
return _get_instructions_bytes(_get_code_array(co, adaptive),
co._varname_from_oparg,
co.co_names, co.co_consts,
linestarts, line_offset,
co_positions=co.co_positions(),
co_positions=co_positions,
show_caches=show_caches)

def _get_const_value(op, arg, co_consts):
Expand Down Expand Up @@ -422,6 +423,24 @@ def _parse_exception_table(code):
def _is_backward_jump(op):
return 'JUMP_BACKWARD' in opname[op]

def _get_co_positions(code, show_caches=False):
# generate all co_positions, with or without caches,
# skipping the oparg2, oparg3 codewords.

if code is None:
return iter(())

ops = code.co_code[::2]
prev_op = 0
for op, positions in zip(ops, code.co_positions()):
if prev_op != 0:
# skip oparg2, oparg3
prev_op = op
continue
if show_caches or op != CACHE:
yield positions
prev_op = op

def _get_instructions_bytes(code, varname_from_oparg=None,
names=None, co_consts=None,
linestarts=None, line_offset=0,
Expand Down Expand Up @@ -504,9 +523,6 @@ def _get_instructions_bytes(code, varname_from_oparg=None,
if not caches:
continue
if not show_caches:
# We still need to advance the co_positions iterator:
for _ in range(caches):
next(co_positions, ())
continue
for name, size in _cache_format[opname[deop]].items():
for i in range(size):
Expand All @@ -527,11 +543,13 @@ def disassemble(co, lasti=-1, *, file=None, show_caches=False, adaptive=False):
"""Disassemble a code object."""
linestarts = dict(findlinestarts(co))
exception_entries = _parse_exception_table(co)
co_positions = _get_co_positions(co, show_caches=show_caches)
_disassemble_bytes(_get_code_array(co, adaptive),
lasti, co._varname_from_oparg,
co.co_names, co.co_consts, linestarts, file=file,
exception_entries=exception_entries,
co_positions=co.co_positions(), show_caches=show_caches)
co_positions=co_positions,
show_caches=show_caches)

def _disassemble_recursive(co, *, file=None, depth=None, show_caches=False, adaptive=False):
disassemble(co, file=file, show_caches=show_caches, adaptive=adaptive)
Expand Down Expand Up @@ -609,6 +627,7 @@ def _unpack_opargs(code):
op = code[i]
deop = _deoptop(op)
caches = _inline_cache_entries[deop]
caches += 1 # also skip over arg2, arg3
if deop in hasarg:
arg = code[i+1] | extended_arg
extended_arg = (arg << 8) if deop == EXTENDED_ARG else 0
Expand All @@ -635,7 +654,7 @@ def findlabels(code):
if deop in hasjrel:
if _is_backward_jump(deop):
arg = -arg
label = offset + 2 + arg*2
label = offset + 4 + arg*2
if deop == FOR_ITER:
label += 2
elif deop in hasjabs:
Expand Down Expand Up @@ -722,13 +741,14 @@ def __init__(self, x, *, first_line=None, current_offset=None, show_caches=False

def __iter__(self):
co = self.codeobj
co_positions = _get_co_positions(co, show_caches=self.show_caches)
return _get_instructions_bytes(_get_code_array(co, self.adaptive),
co._varname_from_oparg,
co.co_names, co.co_consts,
self._linestarts,
line_offset=self._line_offset,
exception_entries=self.exception_entries,
co_positions=co.co_positions(),
co_positions=co_positions,
show_caches=self.show_caches)

def __repr__(self):
Expand Down Expand Up @@ -756,6 +776,7 @@ def dis(self):
else:
offset = -1
with io.StringIO() as output:
co_positions=_get_co_positions(co, show_caches=self.show_caches)
_disassemble_bytes(_get_code_array(co, self.adaptive),
varname_from_oparg=co._varname_from_oparg,
names=co.co_names, co_consts=co.co_consts,
Expand All @@ -764,7 +785,7 @@ def dis(self):
file=output,
lasti=offset,
exception_entries=self.exception_entries,
co_positions=co.co_positions(),
co_positions=co_positions,
show_caches=self.show_caches)
return output.getvalue()

Expand Down
24 changes: 14 additions & 10 deletions Lib/test/test_code.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@
gc_collect)
from test.support.script_helper import assert_python_ok
from test.support import threading_helper
from opcode import opmap
from opcode import opmap, opname
COPY_FREE_VARS = opmap['COPY_FREE_VARS']


Expand Down Expand Up @@ -192,7 +192,7 @@ def create_closure(__class__):

def new_code(c):
'''A new code object with a __class__ cell added to freevars'''
return c.replace(co_freevars=c.co_freevars + ('__class__',), co_code=bytes([COPY_FREE_VARS, 1])+c.co_code)
return c.replace(co_freevars=c.co_freevars + ('__class__',), co_code=bytes([COPY_FREE_VARS, 1, 0, 0])+c.co_code)

def add_foreign_method(cls, name, f):
code = new_code(f.__code__)
Expand Down Expand Up @@ -339,15 +339,19 @@ def func():
self.assertEqual(list(new_code.co_lines()), [])

def test_invalid_bytecode(self):
def foo(): pass
foo.__code__ = co = foo.__code__.replace(co_code=b'\xee\x00d\x00S\x00')
def foo():
pass

with self.assertRaises(SystemError) as se:
foo()
self.assertEqual(
f"{co.co_filename}:{co.co_firstlineno}: unknown opcode 238",
str(se.exception))
# assert that opcode 238 is invalid
self.assertEqual(opname[238], '<238>')

# change first opcode to 0xee (=238)
foo.__code__ = foo.__code__.replace(
co_code=b'\xee' + foo.__code__.co_code[1:])

msg = f"unknown opcode 238"
with self.assertRaisesRegex(SystemError, msg):
foo()

@requires_debug_ranges()
def test_co_positions_artificial_instructions(self):
Expand All @@ -368,7 +372,7 @@ def test_co_positions_artificial_instructions(self):
artificial_instructions = []
for instr, positions in zip(
dis.get_instructions(code, show_caches=True),
code.co_positions(),
dis._get_co_positions(code, show_caches=True),
strict=True
):
# If any of the positions is None, then all have to
Expand Down
Loading

0 comments on commit ac05ae0

Please sign in to comment.