|
2 | 2 | import dis |
3 | 3 | import math |
4 | 4 | import opcode as _opcode |
| 5 | +import sys |
5 | 6 | import types |
6 | 7 |
|
7 | 8 | import bytecode as _bytecode |
@@ -144,6 +145,33 @@ def _check_arg_int(name, arg): |
144 | 145 | % name) |
145 | 146 |
|
146 | 147 |
|
| 148 | +_stack_effects = { |
| 149 | + # NOTE: the entries are all 2-tuples. Entry[0/False] is non-taken jumps. |
| 150 | + # Entry[1/True] is for taken jumps. |
| 151 | + |
| 152 | + # opcodes not in dis.stack_effect |
| 153 | + _opcode.opmap['EXTENDED_ARG']: (0, 0), |
| 154 | + _opcode.opmap['NOP']: (0, 0), |
| 155 | + |
| 156 | + # Jump taken/not-taken are different: |
| 157 | + _opcode.opmap['JUMP_IF_TRUE_OR_POP']: (-1, 0), |
| 158 | + _opcode.opmap['JUMP_IF_FALSE_OR_POP']: (-1, 0), |
| 159 | + _opcode.opmap['FOR_ITER']: (1, -1), |
| 160 | + _opcode.opmap['SETUP_WITH']: (1, 6), |
| 161 | + _opcode.opmap['SETUP_ASYNC_WITH']: (0, 5), |
| 162 | + _opcode.opmap['SETUP_EXCEPT']: (0, 6), # as of 3.7, below for <=3.6 |
| 163 | + _opcode.opmap['SETUP_FINALLY']: (0, 6), # as of 3.7, below for <=3.6 |
| 164 | +} |
| 165 | + |
| 166 | +# More stack effect values that are unique to the version of Python. |
| 167 | +if sys.version_info < (3, 7): |
| 168 | + _stack_effects.update({ |
| 169 | + _opcode.opmap['SETUP_WITH']: (7, 7), |
| 170 | + _opcode.opmap['SETUP_EXCEPT']: (6, 9), |
| 171 | + _opcode.opmap['SETUP_FINALLY']: (6, 9), |
| 172 | + }) |
| 173 | + |
| 174 | + |
147 | 175 | class Instr: |
148 | 176 | """Abstract instruction.""" |
149 | 177 |
|
@@ -269,15 +297,19 @@ def lineno(self): |
269 | 297 | def lineno(self, lineno): |
270 | 298 | self._set(self._name, self._arg, lineno) |
271 | 299 |
|
272 | | - @property |
273 | | - def stack_effect(self): |
| 300 | + def stack_effect(self, jump=None): |
| 301 | + effect = _stack_effects.get(self._opcode, None) |
| 302 | + if effect is not None: |
| 303 | + return max(effect) if jump is None else effect[jump] |
| 304 | + |
| 305 | + # TODO: if dis.stack_effect ever expands to take the 'jump' parameter |
| 306 | + # then we should pass that through, and perhaps remove some of the |
| 307 | + # overrides that are set up in _init_stack_effects() |
| 308 | + |
274 | 309 | # All opcodes whose arguments are not represented by integers have |
275 | 310 | # a stack_effect indepent of their argument. |
276 | 311 | arg = (self._arg if isinstance(self._arg, int) else |
277 | 312 | 0 if self._opcode >= _opcode.HAVE_ARGUMENT else None) |
278 | | - # EXTENDED_ARG has no stack effect but is not supported by dis |
279 | | - if self._name == 'EXTENDED_ARG': |
280 | | - return 0 |
281 | 313 | return dis.stack_effect(self._opcode, arg) |
282 | 314 |
|
283 | 315 | def copy(self): |
|
0 commit comments