Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
fabioz committed Dec 10, 2023
1 parent 6baea7b commit 24be7e0
Show file tree
Hide file tree
Showing 4 changed files with 220 additions and 81 deletions.
86 changes: 74 additions & 12 deletions _pydevd_bundle/pydevd_bytecode_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from _pydev_bundle import pydev_log
from types import CodeType
from _pydevd_frame_eval.vendored.bytecode.instr import _Variable, TryBegin, \
TryEnd
TryEnd, Label
from _pydevd_frame_eval.vendored import bytecode
from _pydevd_frame_eval.vendored.bytecode import cfg as bytecode_cfg
import dis
Expand All @@ -16,10 +16,13 @@
from _pydevd_bundle.pydevd_constants import KeyifyList, DebugInfoHolder, IS_PY311_OR_GREATER
from bisect import bisect
from collections import deque
import traceback

# When True, throws errors on unknown bytecodes, when False, ignore those as if they didn't change the stack.
STRICT_MODE = False

GO_INTO_INNER_CODES = True

DEBUG = False

_BINARY_OPS = set([opname for opname in dis.opname if opname.startswith('BINARY_')])
Expand Down Expand Up @@ -130,6 +133,10 @@ def _getcallname(self, instr):
name = name.co_qualname # Note: only available for Python 3.11
if isinstance(name, _Variable):
name = name.name
if isinstance(name, tuple):
# Load attr in Python 3.12 comes with (bool, name)
if len(name) == 2 and isinstance(name[0], bool) and isinstance(name[1], str):
name = name[1]

if not isinstance(name, str):
return None
Expand Down Expand Up @@ -206,7 +213,7 @@ def _handle_call_from_instr(self, func_name_instr, func_call_instr):
pass # Ignore if we can't identify a name
elif call_name in ('<listcomp>', '<genexpr>', '<setcomp>', '<dictcomp>'):
code_obj = self.func_name_id_to_code_object[_TargetIdHashable(func_name_instr)]
if code_obj is not None:
if code_obj is not None and GO_INTO_INNER_CODES:
children_targets = _get_smart_step_into_targets(code_obj)
if children_targets:
# i.e.: we have targets inside of a <listcomp> or <genexpr>.
Expand Down Expand Up @@ -309,6 +316,9 @@ def on_MAKE_FUNCTION(self, instr):
def on_LOAD_FAST(self, instr):
self._stack.append(instr)

on_LOAD_FAST_AND_CLEAR = on_LOAD_FAST
on_LOAD_FAST_CHECK = on_LOAD_FAST

def on_LOAD_ASSERTION_ERROR(self, instr):
self._stack.append(instr)

Expand All @@ -322,9 +332,44 @@ def on_CALL_METHOD(self, instr):
func_name_instr = self._stack.pop()
self._handle_call_from_instr(func_name_instr, instr)

def on_CALL(self, instr):
# pop the actual args
for _ in range(instr.arg):
self._stack.pop()

func_name_instr = self._stack.pop()
if self._getcallname(func_name_instr) is None:
func_name_instr = self._stack.pop()

if self._stack:
peeked = self._stack[-1]
if peeked.name == 'PUSH_NULL':
self._stack.pop()

self._handle_call_from_instr(func_name_instr, instr)

def on_CALL_INTRINSIC_1(self, instr):
try:
func_name_instr = self._stack.pop()
except IndexError:
return

if self._stack:
peeked = self._stack[-1]
if peeked.name == 'PUSH_NULL':
self._stack.pop()

self._handle_call_from_instr(func_name_instr, instr)

def on_PUSH_NULL(self, instr):
self._stack.append(instr)

def on_KW_NAMES(self, instr):
return

def on_RETURN_CONST(self, instr):
return

def on_CALL_FUNCTION(self, instr):
arg = instr.arg

Expand Down Expand Up @@ -402,9 +447,9 @@ def on_CALL_FUNCTION_EX(self, instr):
func_name_instr = self._stack.pop()
self._handle_call_from_instr(func_name_instr, instr)

on_YIELD_VALUE = _no_stack_change
on_GET_AITER = _no_stack_change
on_GET_ANEXT = _no_stack_change
on_END_FOR = _no_stack_change
on_END_ASYNC_FOR = _no_stack_change
on_BEFORE_ASYNC_WITH = _no_stack_change
on_SETUP_ASYNC_WITH = _no_stack_change
Expand Down Expand Up @@ -436,6 +481,13 @@ def on_JUMP_IF_NOT_EXC_MATCH(self, instr):
except IndexError:
return

def on_SWAP(self, instr):
i = instr.arg
try:
self._stack[-i], self._stack[-1] = self._stack[-1], self._stack[-i]
except:
pass

def on_ROT_TWO(self, instr):
try:
p0 = self._stack.pop()
Expand Down Expand Up @@ -521,6 +573,7 @@ def on_BUILD_CONST_KEY_MAP(self, instr):
self.on_POP_TOP(instr) # value
self._stack.append(instr)

on_YIELD_VALUE = on_POP_TOP
on_RETURN_VALUE = on_POP_TOP
on_POP_JUMP_IF_FALSE = on_POP_TOP
on_POP_JUMP_IF_TRUE = on_POP_TOP
Expand Down Expand Up @@ -576,6 +629,8 @@ def on_RAISE_VARARGS(self, instr):

on_POP_BLOCK = _no_stack_change
on_JUMP_FORWARD = _no_stack_change
on_JUMP_BACKWARD = _no_stack_change
on_JUMP_BACKWARD_NO_INTERRUPT = _no_stack_change
on_POP_EXCEPT = _no_stack_change
on_SETUP_EXCEPT = _no_stack_change
on_WITH_EXCEPT_START = _no_stack_change
Expand Down Expand Up @@ -663,6 +718,7 @@ def on_DELETE_SUBSCR(self, instr):
# some evaluation.
on_PRINT_EXPR = on_POP_TOP

on_LABEL = _no_stack_change
on_UNARY_POSITIVE = _no_stack_change
on_UNARY_NEGATIVE = _no_stack_change
on_UNARY_NOT = _no_stack_change
Expand All @@ -677,7 +733,8 @@ def _get_smart_step_into_targets(code):
:return list(Target)
'''
b = bytecode.Bytecode.from_code(code)
cfg = bytecode_cfg.ControlFlowGraph.from_bytecode(b)
# cfg = bytecode_cfg.ControlFlowGraph.from_bytecode(b)
cfg = [b]

ret = []

Expand All @@ -686,26 +743,29 @@ def _get_smart_step_into_targets(code):
print('\nStart block----')
stack = _StackInterpreter(block)
for instr in block:
if isinstance(instr, (TryBegin, TryEnd)):
if isinstance(instr, (TryBegin, TryEnd, Label)):
# No name for these
continue
try:
func_name = 'on_%s' % (instr.name,)
func = getattr(stack, func_name, None)

if DEBUG:
if instr.name != 'CACHE': # Filter the ones we don't want to see.
print('\nWill handle: ', instr, '>>', stack._getname(instr), '<<')
print('Current stack:')
for entry in stack._stack:
print(' arg:', stack._getname(entry), '(', entry, ')')

if func is None:
if STRICT_MODE:
raise AssertionError('%s not found.' % (func_name,))
else:
if DEBUG:
print('Skipping: %s.' % (func_name,))

continue
func(instr)

if DEBUG:
if instr.name != 'CACHE': # Filter the ones we don't want to see.
print('\nHandled: ', instr, '>>', stack._getname(instr), '<<')
print('New stack:')
for entry in stack._stack:
print(' arg:', stack._getname(entry), '(', entry, ')')
except:
if STRICT_MODE:
raise # Error in strict mode.
Expand All @@ -721,6 +781,8 @@ def _get_smart_step_into_targets(code):
# step into from stepping into properties).
# ret.extend(stack.load_attrs.values())

if DEBUG:
print('\nEnd block----')
return ret


Expand Down
Loading

0 comments on commit 24be7e0

Please sign in to comment.