-
Notifications
You must be signed in to change notification settings - Fork 0
/
patch.py
61 lines (49 loc) · 1.96 KB
/
patch.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
def bytecode_recursion_opt():
from bytecode import SetLineno
from bytecode import cfg
def compute_stack_size(block, size, maxsize):
coro = _compute_stack_size(block, size, maxsize)
coroutines = []
args = None
try:
while True:
args = coro.send(None)
while isinstance(args, int):
coro = coroutines.pop()
args = coro.send(args)
coroutines.append(coro)
coro = _compute_stack_size(*args)
except IndexError:
assert args is not None
return args
def _compute_stack_size(block, size, maxsize):
if block.seen or block.startsize >= size:
yield maxsize
def update_size(delta, size, maxsize):
size += delta
if size < 0:
msg = "Failed to compute stacksize, got negative size"
raise RuntimeError(msg)
maxsize = max(maxsize, size)
return size, maxsize
block.seen = True
block.startsize = size
for instr in block:
if isinstance(instr, SetLineno):
continue
if instr.has_jump():
# first compute the taken-jump path
taken_size, maxsize = update_size(
instr.stack_effect(jump=True), size, maxsize
)
maxsize = yield instr.arg, taken_size, maxsize
if instr.is_uncond_jump():
block.seen = False
yield maxsize
# jump=False: non-taken path of jumps, or any non-jump
size, maxsize = update_size(instr.stack_effect(jump=False), size, maxsize)
if block.next_block:
maxsize = yield block.next_block, size, maxsize
block.seen = 0
yield maxsize
cfg._compute_stack_size = compute_stack_size