blob: 1bee7102d9cc8a168e4d3b47588d053ee354a9db [file] [log] [blame]
Guido van Rossumd8faa362007-04-27 19:54:29 +00001/* Peephole optimizations for bytecode compiler. */
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00002
3#include "Python.h"
4
5#include "Python-ast.h"
6#include "node.h"
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00007#include "ast.h"
8#include "code.h"
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00009#include "symtable.h"
10#include "opcode.h"
Serhiy Storchakab0f80b02016-05-24 09:15:14 +030011#include "wordcode_helpers.h"
Thomas Wouters00ee7ba2006-08-21 19:07:27 +000012
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000013#define UNCONDITIONAL_JUMP(op) (op==JUMP_ABSOLUTE || op==JUMP_FORWARD)
Jeffrey Yasskin9de7ec72009-02-25 02:25:04 +000014#define CONDITIONAL_JUMP(op) (op==POP_JUMP_IF_FALSE || op==POP_JUMP_IF_TRUE \
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000015 || op==JUMP_IF_FALSE_OR_POP || op==JUMP_IF_TRUE_OR_POP)
Jeffrey Yasskin9de7ec72009-02-25 02:25:04 +000016#define ABSOLUTE_JUMP(op) (op==JUMP_ABSOLUTE || op==CONTINUE_LOOP \
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000017 || op==POP_JUMP_IF_FALSE || op==POP_JUMP_IF_TRUE \
18 || op==JUMP_IF_FALSE_OR_POP || op==JUMP_IF_TRUE_OR_POP)
Jeffrey Yasskin9de7ec72009-02-25 02:25:04 +000019#define JUMPS_ON_TRUE(op) (op==POP_JUMP_IF_TRUE || op==JUMP_IF_TRUE_OR_POP)
Serhiy Storchakaab874002016-09-11 13:48:15 +030020#define GETJUMPTGT(arr, i) (get_arg(arr, i) / sizeof(_Py_CODEUNIT) + \
21 (ABSOLUTE_JUMP(_Py_OPCODE(arr[i])) ? 0 : i+1))
Serhiy Storchakab0f80b02016-05-24 09:15:14 +030022#define ISBASICBLOCK(blocks, start, end) \
23 (blocks[start]==blocks[end])
Thomas Wouters00ee7ba2006-08-21 19:07:27 +000024
Antoine Pitrou17b880a2011-03-11 17:27:02 +010025
26#define CONST_STACK_CREATE() { \
27 const_stack_size = 256; \
28 const_stack = PyMem_New(PyObject *, const_stack_size); \
Serhiy Storchakab0f80b02016-05-24 09:15:14 +030029 if (!const_stack) { \
Antoine Pitrou17b880a2011-03-11 17:27:02 +010030 PyErr_NoMemory(); \
31 goto exitError; \
32 } \
33 }
34
35#define CONST_STACK_DELETE() do { \
36 if (const_stack) \
37 PyMem_Free(const_stack); \
Antoine Pitrou17b880a2011-03-11 17:27:02 +010038 } while(0)
39
Serhiy Storchakab0f80b02016-05-24 09:15:14 +030040#define CONST_STACK_LEN() ((unsigned)(const_stack_top + 1))
Antoine Pitrou17b880a2011-03-11 17:27:02 +010041
42#define CONST_STACK_PUSH_OP(i) do { \
43 PyObject *_x; \
Serhiy Storchakaab874002016-09-11 13:48:15 +030044 assert(_Py_OPCODE(codestr[i]) == LOAD_CONST); \
Serhiy Storchakab0f80b02016-05-24 09:15:14 +030045 assert(PyList_GET_SIZE(consts) > (Py_ssize_t)get_arg(codestr, i)); \
46 _x = PyList_GET_ITEM(consts, get_arg(codestr, i)); \
Antoine Pitrou17b880a2011-03-11 17:27:02 +010047 if (++const_stack_top >= const_stack_size) { \
48 const_stack_size *= 2; \
49 PyMem_Resize(const_stack, PyObject *, const_stack_size); \
Serhiy Storchakab0f80b02016-05-24 09:15:14 +030050 if (!const_stack) { \
Antoine Pitrou17b880a2011-03-11 17:27:02 +010051 PyErr_NoMemory(); \
52 goto exitError; \
53 } \
54 } \
Antoine Pitrou17b880a2011-03-11 17:27:02 +010055 const_stack[const_stack_top] = _x; \
56 in_consts = 1; \
57 } while(0)
58
59#define CONST_STACK_RESET() do { \
60 const_stack_top = -1; \
61 } while(0)
62
Antoine Pitrou17b880a2011-03-11 17:27:02 +010063#define CONST_STACK_LASTN(i) \
Serhiy Storchakab0f80b02016-05-24 09:15:14 +030064 &const_stack[CONST_STACK_LEN() - i]
Antoine Pitrou17b880a2011-03-11 17:27:02 +010065
66#define CONST_STACK_POP(i) do { \
Serhiy Storchakab0f80b02016-05-24 09:15:14 +030067 assert(CONST_STACK_LEN() >= i); \
Antoine Pitrou17b880a2011-03-11 17:27:02 +010068 const_stack_top -= i; \
69 } while(0)
70
Serhiy Storchakab0f80b02016-05-24 09:15:14 +030071/* Scans back N consecutive LOAD_CONST instructions, skipping NOPs,
72 returns index of the Nth last's LOAD_CONST's EXTENDED_ARG prefix.
73 Callers are responsible to check CONST_STACK_LEN beforehand.
74*/
75static Py_ssize_t
Serhiy Storchakaab874002016-09-11 13:48:15 +030076lastn_const_start(const _Py_CODEUNIT *codestr, Py_ssize_t i, Py_ssize_t n)
Serhiy Storchakab0f80b02016-05-24 09:15:14 +030077{
Serhiy Storchakaab874002016-09-11 13:48:15 +030078 assert(n > 0);
Serhiy Storchakab0f80b02016-05-24 09:15:14 +030079 for (;;) {
Serhiy Storchakaab874002016-09-11 13:48:15 +030080 i--;
Serhiy Storchakab0f80b02016-05-24 09:15:14 +030081 assert(i >= 0);
Serhiy Storchakaab874002016-09-11 13:48:15 +030082 if (_Py_OPCODE(codestr[i]) == LOAD_CONST) {
Serhiy Storchakab0f80b02016-05-24 09:15:14 +030083 if (!--n) {
Serhiy Storchakaab874002016-09-11 13:48:15 +030084 while (i > 0 && _Py_OPCODE(codestr[i-1]) == EXTENDED_ARG) {
85 i--;
Serhiy Storchakab0f80b02016-05-24 09:15:14 +030086 }
87 return i;
88 }
89 }
90 else {
Serhiy Storchakaab874002016-09-11 13:48:15 +030091 assert(_Py_OPCODE(codestr[i]) == NOP ||
92 _Py_OPCODE(codestr[i]) == EXTENDED_ARG);
Serhiy Storchakab0f80b02016-05-24 09:15:14 +030093 }
94 }
95}
Antoine Pitrou17b880a2011-03-11 17:27:02 +010096
Serhiy Storchakab0f80b02016-05-24 09:15:14 +030097/* Scans through EXTENDED ARGs, seeking the index of the effective opcode */
98static Py_ssize_t
Serhiy Storchakaab874002016-09-11 13:48:15 +030099find_op(const _Py_CODEUNIT *codestr, Py_ssize_t i)
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300100{
Serhiy Storchakaab874002016-09-11 13:48:15 +0300101 while (_Py_OPCODE(codestr[i]) == EXTENDED_ARG) {
102 i++;
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300103 }
104 return i;
105}
Antoine Pitrou17b880a2011-03-11 17:27:02 +0100106
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300107/* Given the index of the effective opcode,
108 scan back to construct the oparg with EXTENDED_ARG */
109static unsigned int
Serhiy Storchakaab874002016-09-11 13:48:15 +0300110get_arg(const _Py_CODEUNIT *codestr, Py_ssize_t i)
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300111{
Serhiy Storchakaab874002016-09-11 13:48:15 +0300112 _Py_CODEUNIT word;
113 unsigned int oparg = _Py_OPARG(codestr[i]);
114 if (i >= 1 && _Py_OPCODE(word = codestr[i-1]) == EXTENDED_ARG) {
115 oparg |= _Py_OPARG(word) << 8;
116 if (i >= 2 && _Py_OPCODE(word = codestr[i-2]) == EXTENDED_ARG) {
117 oparg |= _Py_OPARG(word) << 16;
118 if (i >= 3 && _Py_OPCODE(word = codestr[i-3]) == EXTENDED_ARG) {
119 oparg |= _Py_OPARG(word) << 24;
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300120 }
121 }
122 }
123 return oparg;
124}
125
Serhiy Storchakaab874002016-09-11 13:48:15 +0300126/* Fill the region with NOPs. */
127static void
128fill_nops(_Py_CODEUNIT *codestr, Py_ssize_t start, Py_ssize_t end)
129{
130 memset(codestr + start, NOP, (end - start) * sizeof(_Py_CODEUNIT));
131}
132
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300133/* Given the index of the effective opcode,
134 attempt to replace the argument, taking into account EXTENDED_ARG.
135 Returns -1 on failure, or the new op index on success */
136static Py_ssize_t
Serhiy Storchakaab874002016-09-11 13:48:15 +0300137set_arg(_Py_CODEUNIT *codestr, Py_ssize_t i, unsigned int oparg)
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300138{
139 unsigned int curarg = get_arg(codestr, i);
140 int curilen, newilen;
141 if (curarg == oparg)
142 return i;
143 curilen = instrsize(curarg);
144 newilen = instrsize(oparg);
145 if (curilen < newilen) {
146 return -1;
147 }
148
Serhiy Storchakaab874002016-09-11 13:48:15 +0300149 write_op_arg(codestr + i + 1 - curilen, _Py_OPCODE(codestr[i]), oparg, newilen);
150 fill_nops(codestr, i + 1 - curilen + newilen, i + 1);
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300151 return i-curilen+newilen;
152}
153
154/* Attempt to write op/arg at end of specified region of memory.
155 Preceding memory in the region is overwritten with NOPs.
156 Returns -1 on failure, op index on success */
157static Py_ssize_t
Serhiy Storchakaab874002016-09-11 13:48:15 +0300158copy_op_arg(_Py_CODEUNIT *codestr, Py_ssize_t i, unsigned char op,
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300159 unsigned int oparg, Py_ssize_t maxi)
160{
161 int ilen = instrsize(oparg);
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300162 if (i + ilen > maxi) {
163 return -1;
164 }
165 write_op_arg(codestr + maxi - ilen, op, oparg, ilen);
Serhiy Storchakaab874002016-09-11 13:48:15 +0300166 fill_nops(codestr, i, maxi - ilen);
167 return maxi - 1;
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300168}
169
170/* Replace LOAD_CONST c1, LOAD_CONST c2 ... LOAD_CONST cn, BUILD_TUPLE n
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000171 with LOAD_CONST (c1, c2, ... cn).
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000172 The consts table must still be in list form so that the
173 new constant (c1, c2, ... cn) can be appended.
174 Called with codestr pointing to the first LOAD_CONST.
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000175 Bails out with no change if one or more of the LOAD_CONSTs is missing.
Antoine Pitroub7fbcd32010-01-16 18:37:38 +0000176 Also works for BUILD_LIST and BUILT_SET when followed by an "in" or "not in"
177 test; for BUILD_SET it assembles a frozenset rather than a tuple.
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000178*/
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300179static Py_ssize_t
Serhiy Storchakaab874002016-09-11 13:48:15 +0300180fold_tuple_on_constants(_Py_CODEUNIT *codestr, Py_ssize_t c_start,
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300181 Py_ssize_t opcode_end, unsigned char opcode,
182 PyObject *consts, PyObject **objs, int n)
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000183{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000184 PyObject *newconst, *constant;
Antoine Pitrou17b880a2011-03-11 17:27:02 +0100185 Py_ssize_t i, len_consts;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000186
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000187 /* Pre-conditions */
188 assert(PyList_CheckExact(consts));
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000189
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000190 /* Buildup new tuple of constants */
191 newconst = PyTuple_New(n);
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300192 if (newconst == NULL) {
193 return -1;
194 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000195 for (i=0 ; i<n ; i++) {
Antoine Pitrou17b880a2011-03-11 17:27:02 +0100196 constant = objs[i];
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000197 Py_INCREF(constant);
198 PyTuple_SET_ITEM(newconst, i, constant);
199 }
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000200
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000201 /* If it's a BUILD_SET, use the PyTuple we just built to create a
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300202 PyFrozenSet, and use that as the constant instead: */
203 if (opcode == BUILD_SET) {
204 Py_SETREF(newconst, PyFrozenSet_New(newconst));
205 if (newconst == NULL) {
206 return -1;
207 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000208 }
Antoine Pitroub7fbcd32010-01-16 18:37:38 +0000209
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000210 /* Append folded constant onto consts */
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300211 len_consts = PyList_GET_SIZE(consts);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000212 if (PyList_Append(consts, newconst)) {
213 Py_DECREF(newconst);
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300214 return -1;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000215 }
216 Py_DECREF(newconst);
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000217
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300218 return copy_op_arg(codestr, c_start, LOAD_CONST, len_consts, opcode_end);
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000219}
220
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300221/* Replace LOAD_CONST c1, LOAD_CONST c2, BINOP
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000222 with LOAD_CONST binop(c1,c2)
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000223 The consts table must still be in list form so that the
224 new constant can be appended.
Antoine Pitrou17b880a2011-03-11 17:27:02 +0100225 Called with codestr pointing to the BINOP.
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000226 Abandons the transformation if the folding fails (i.e. 1+'a').
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000227 If the new constant is a sequence, only folds when the size
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000228 is below a threshold value. That keeps pyc files from
229 becoming large in the presence of code like: (None,)*1000.
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000230*/
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300231static Py_ssize_t
Serhiy Storchakaab874002016-09-11 13:48:15 +0300232fold_binops_on_constants(_Py_CODEUNIT *codestr, Py_ssize_t c_start,
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300233 Py_ssize_t opcode_end, unsigned char opcode,
234 PyObject *consts, PyObject **objs)
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000235{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000236 PyObject *newconst, *v, *w;
237 Py_ssize_t len_consts, size;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000238
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000239 /* Pre-conditions */
240 assert(PyList_CheckExact(consts));
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300241 len_consts = PyList_GET_SIZE(consts);
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000242
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000243 /* Create new constant */
Antoine Pitrou17b880a2011-03-11 17:27:02 +0100244 v = objs[0];
245 w = objs[1];
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000246 switch (opcode) {
247 case BINARY_POWER:
248 newconst = PyNumber_Power(v, w, Py_None);
249 break;
250 case BINARY_MULTIPLY:
251 newconst = PyNumber_Multiply(v, w);
252 break;
253 case BINARY_TRUE_DIVIDE:
254 newconst = PyNumber_TrueDivide(v, w);
255 break;
256 case BINARY_FLOOR_DIVIDE:
257 newconst = PyNumber_FloorDivide(v, w);
258 break;
259 case BINARY_MODULO:
260 newconst = PyNumber_Remainder(v, w);
261 break;
262 case BINARY_ADD:
263 newconst = PyNumber_Add(v, w);
264 break;
265 case BINARY_SUBTRACT:
266 newconst = PyNumber_Subtract(v, w);
267 break;
268 case BINARY_SUBSCR:
269 newconst = PyObject_GetItem(v, w);
270 break;
271 case BINARY_LSHIFT:
272 newconst = PyNumber_Lshift(v, w);
273 break;
274 case BINARY_RSHIFT:
275 newconst = PyNumber_Rshift(v, w);
276 break;
277 case BINARY_AND:
278 newconst = PyNumber_And(v, w);
279 break;
280 case BINARY_XOR:
281 newconst = PyNumber_Xor(v, w);
282 break;
283 case BINARY_OR:
284 newconst = PyNumber_Or(v, w);
285 break;
286 default:
287 /* Called with an unknown opcode */
288 PyErr_Format(PyExc_SystemError,
289 "unexpected binary operation %d on a constant",
290 opcode);
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300291 return -1;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000292 }
293 if (newconst == NULL) {
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300294 if(!PyErr_ExceptionMatches(PyExc_KeyboardInterrupt)) {
Raymond Hettinger819a0642010-08-22 08:39:49 +0000295 PyErr_Clear();
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300296 }
297 return -1;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000298 }
299 size = PyObject_Size(newconst);
Raymond Hettinger819a0642010-08-22 08:39:49 +0000300 if (size == -1) {
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300301 if (PyErr_ExceptionMatches(PyExc_KeyboardInterrupt)) {
302 return -1;
303 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000304 PyErr_Clear();
Raymond Hettinger819a0642010-08-22 08:39:49 +0000305 } else if (size > 20) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000306 Py_DECREF(newconst);
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300307 return -1;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000308 }
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000309
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000310 /* Append folded constant into consts table */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000311 if (PyList_Append(consts, newconst)) {
312 Py_DECREF(newconst);
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300313 return -1;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000314 }
315 Py_DECREF(newconst);
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000316
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300317 return copy_op_arg(codestr, c_start, LOAD_CONST, len_consts, opcode_end);
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000318}
319
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300320static Py_ssize_t
Serhiy Storchakaab874002016-09-11 13:48:15 +0300321fold_unaryops_on_constants(_Py_CODEUNIT *codestr, Py_ssize_t c_start,
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300322 Py_ssize_t opcode_end, unsigned char opcode,
323 PyObject *consts, PyObject *v)
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000324{
Mark Dickinson7c9e8032011-03-23 17:59:37 +0000325 PyObject *newconst;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000326 Py_ssize_t len_consts;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000327
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000328 /* Pre-conditions */
329 assert(PyList_CheckExact(consts));
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300330 len_consts = PyList_GET_SIZE(consts);
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000331
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000332 /* Create new constant */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000333 switch (opcode) {
334 case UNARY_NEGATIVE:
Mark Dickinson7c9e8032011-03-23 17:59:37 +0000335 newconst = PyNumber_Negative(v);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000336 break;
337 case UNARY_INVERT:
338 newconst = PyNumber_Invert(v);
339 break;
340 case UNARY_POSITIVE:
341 newconst = PyNumber_Positive(v);
342 break;
343 default:
344 /* Called with an unknown opcode */
345 PyErr_Format(PyExc_SystemError,
346 "unexpected unary operation %d on a constant",
347 opcode);
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300348 return -1;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000349 }
350 if (newconst == NULL) {
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300351 if(!PyErr_ExceptionMatches(PyExc_KeyboardInterrupt)) {
Raymond Hettinger819a0642010-08-22 08:39:49 +0000352 PyErr_Clear();
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300353 }
354 return -1;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000355 }
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000356
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000357 /* Append folded constant into consts table */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000358 if (PyList_Append(consts, newconst)) {
359 Py_DECREF(newconst);
Victor Stinnerc82729e2013-11-14 01:21:00 +0100360 PyErr_Clear();
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300361 return -1;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000362 }
363 Py_DECREF(newconst);
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000364
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300365 return copy_op_arg(codestr, c_start, LOAD_CONST, len_consts, opcode_end);
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000366}
367
368static unsigned int *
Serhiy Storchakaab874002016-09-11 13:48:15 +0300369markblocks(_Py_CODEUNIT *code, Py_ssize_t len)
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000370{
Serhiy Storchaka1a1ff292015-02-16 13:28:22 +0200371 unsigned int *blocks = PyMem_New(unsigned int, len);
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300372 int i, j, opcode, blockcnt = 0;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000373
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000374 if (blocks == NULL) {
375 PyErr_NoMemory();
376 return NULL;
377 }
378 memset(blocks, 0, len*sizeof(int));
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000379
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000380 /* Mark labels in the first pass */
Serhiy Storchakaab874002016-09-11 13:48:15 +0300381 for (i = 0; i < len; i++) {
382 opcode = _Py_OPCODE(code[i]);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000383 switch (opcode) {
384 case FOR_ITER:
385 case JUMP_FORWARD:
386 case JUMP_IF_FALSE_OR_POP:
387 case JUMP_IF_TRUE_OR_POP:
388 case POP_JUMP_IF_FALSE:
389 case POP_JUMP_IF_TRUE:
390 case JUMP_ABSOLUTE:
391 case CONTINUE_LOOP:
392 case SETUP_LOOP:
393 case SETUP_EXCEPT:
394 case SETUP_FINALLY:
395 case SETUP_WITH:
Yury Selivanov75445082015-05-11 22:57:16 -0400396 case SETUP_ASYNC_WITH:
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000397 j = GETJUMPTGT(code, i);
Serhiy Storchakaab874002016-09-11 13:48:15 +0300398 assert(j < len);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000399 blocks[j] = 1;
400 break;
401 }
402 }
403 /* Build block numbers in the second pass */
Serhiy Storchakaab874002016-09-11 13:48:15 +0300404 for (i = 0; i < len; i++) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000405 blockcnt += blocks[i]; /* increment blockcnt over labels */
406 blocks[i] = blockcnt;
407 }
408 return blocks;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000409}
410
411/* Perform basic peephole optimizations to components of a code object.
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000412 The consts object should still be in list form to allow new constants
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000413 to be appended.
414
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300415 To keep the optimizer simple, it bails when the lineno table has complex
416 encoding for gaps >= 255.
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000417
Martin Panter46f50722016-05-26 05:35:26 +0000418 Optimizations are restricted to simple transformations occurring within a
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000419 single basic block. All transformations keep the code size the same or
420 smaller. For those that reduce size, the gaps are initially filled with
421 NOPs. Later those NOPs are removed and the jump addresses retargeted in
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300422 a single pass. */
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000423
424PyObject *
425PyCode_Optimize(PyObject *code, PyObject* consts, PyObject *names,
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100426 PyObject *lnotab_obj)
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000427{
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300428 Py_ssize_t h, i, nexti, op_start, codelen, tgt;
429 unsigned int j, nops;
430 unsigned char opcode, nextop;
Serhiy Storchakaab874002016-09-11 13:48:15 +0300431 _Py_CODEUNIT *codestr = NULL;
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100432 unsigned char *lnotab;
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300433 unsigned int cum_orig_offset, last_offset;
Serhiy Storchaka67559bf2015-02-16 21:13:24 +0200434 Py_ssize_t tabsiz;
Antoine Pitrou17b880a2011-03-11 17:27:02 +0100435 PyObject **const_stack = NULL;
Antoine Pitrou17b880a2011-03-11 17:27:02 +0100436 Py_ssize_t const_stack_top = -1;
437 Py_ssize_t const_stack_size = 0;
438 int in_consts = 0; /* whether we are in a LOAD_CONST sequence */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000439 unsigned int *blocks = NULL;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000440
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000441 /* Bail out if an exception is set */
442 if (PyErr_Occurred())
443 goto exitError;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000444
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100445 /* Bypass optimization when the lnotab table is too complex */
446 assert(PyBytes_Check(lnotab_obj));
447 lnotab = (unsigned char*)PyBytes_AS_STRING(lnotab_obj);
448 tabsiz = PyBytes_GET_SIZE(lnotab_obj);
449 assert(tabsiz == 0 || Py_REFCNT(lnotab_obj) == 1);
450 if (memchr(lnotab, 255, tabsiz) != NULL) {
451 /* 255 value are used for multibyte bytecode instructions */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000452 goto exitUnchanged;
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100453 }
454 /* Note: -128 and 127 special values for line number delta are ok,
455 the peephole optimizer doesn't modify line numbers. */
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000456
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000457 assert(PyBytes_Check(code));
458 codelen = PyBytes_GET_SIZE(code);
Serhiy Storchakaab874002016-09-11 13:48:15 +0300459 assert(codelen % sizeof(_Py_CODEUNIT) == 0);
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000460
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000461 /* Make a modifiable copy of the code string */
Serhiy Storchakaab874002016-09-11 13:48:15 +0300462 codestr = (_Py_CODEUNIT *)PyMem_Malloc(codelen);
Victor Stinnere0af3a82013-07-09 00:32:04 +0200463 if (codestr == NULL) {
464 PyErr_NoMemory();
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000465 goto exitError;
Victor Stinnere0af3a82013-07-09 00:32:04 +0200466 }
Serhiy Storchakaab874002016-09-11 13:48:15 +0300467 memcpy(codestr, PyBytes_AS_STRING(code), codelen);
468 codelen /= sizeof(_Py_CODEUNIT);
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000469
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000470 blocks = markblocks(codestr, codelen);
471 if (blocks == NULL)
472 goto exitError;
473 assert(PyList_Check(consts));
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000474
Antoine Pitrou17b880a2011-03-11 17:27:02 +0100475 CONST_STACK_CREATE();
476
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300477 for (i=find_op(codestr, 0) ; i<codelen ; i=nexti) {
Serhiy Storchakaa1e9ab32016-09-11 15:19:12 +0300478 opcode = _Py_OPCODE(codestr[i]);
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300479 op_start = i;
Serhiy Storchakaab874002016-09-11 13:48:15 +0300480 while (op_start >= 1 && _Py_OPCODE(codestr[op_start-1]) == EXTENDED_ARG) {
481 op_start--;
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300482 }
483
Serhiy Storchakaab874002016-09-11 13:48:15 +0300484 nexti = i + 1;
485 while (nexti < codelen && _Py_OPCODE(codestr[nexti]) == EXTENDED_ARG)
486 nexti++;
487 nextop = nexti < codelen ? _Py_OPCODE(codestr[nexti]) : 0;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000488
Antoine Pitrou17b880a2011-03-11 17:27:02 +0100489 if (!in_consts) {
490 CONST_STACK_RESET();
491 }
492 in_consts = 0;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000493
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000494 switch (opcode) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000495 /* not a is b --> a is not b
496 not a in b --> a not in b
497 not a is not b --> a is b
498 not a not in b --> a in b
499 */
500 case COMPARE_OP:
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300501 j = get_arg(codestr, i);
502 if (j < 6 || j > 9 ||
503 nextop != UNARY_NOT ||
Serhiy Storchakaab874002016-09-11 13:48:15 +0300504 !ISBASICBLOCK(blocks, op_start, i + 1))
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300505 break;
Serhiy Storchakaab874002016-09-11 13:48:15 +0300506 codestr[i] = PACKOPARG(opcode, j^1);
507 fill_nops(codestr, i + 1, nexti + 1);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000508 break;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000509
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000510 /* Skip over LOAD_CONST trueconst
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300511 POP_JUMP_IF_FALSE xx. This improves
512 "while 1" performance. */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000513 case LOAD_CONST:
Antoine Pitrou17b880a2011-03-11 17:27:02 +0100514 CONST_STACK_PUSH_OP(i);
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300515 if (nextop != POP_JUMP_IF_FALSE ||
Serhiy Storchakaab874002016-09-11 13:48:15 +0300516 !ISBASICBLOCK(blocks, op_start, i + 1) ||
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300517 !PyObject_IsTrue(PyList_GET_ITEM(consts, get_arg(codestr, i))))
518 break;
Serhiy Storchakaab874002016-09-11 13:48:15 +0300519 fill_nops(codestr, op_start, nexti + 1);
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300520 CONST_STACK_POP(1);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000521 break;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000522
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300523 /* Try to fold tuples of constants (includes a case for lists
524 and sets which are only used for "in" and "not in" tests).
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000525 Skip over BUILD_SEQN 1 UNPACK_SEQN 1.
526 Replace BUILD_SEQN 2 UNPACK_SEQN 2 with ROT2.
527 Replace BUILD_SEQN 3 UNPACK_SEQN 3 with ROT3 ROT2. */
528 case BUILD_TUPLE:
529 case BUILD_LIST:
530 case BUILD_SET:
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300531 j = get_arg(codestr, i);
532 if (j > 0 && CONST_STACK_LEN() >= j) {
533 h = lastn_const_start(codestr, op_start, j);
534 if ((opcode == BUILD_TUPLE &&
535 ISBASICBLOCK(blocks, h, op_start)) ||
536 ((opcode == BUILD_LIST || opcode == BUILD_SET) &&
537 ((nextop==COMPARE_OP &&
Serhiy Storchakaab874002016-09-11 13:48:15 +0300538 (_Py_OPARG(codestr[nexti]) == PyCmp_IN ||
539 _Py_OPARG(codestr[nexti]) == PyCmp_NOT_IN)) ||
540 nextop == GET_ITER) && ISBASICBLOCK(blocks, h, i + 1))) {
541 h = fold_tuple_on_constants(codestr, h, i + 1, opcode,
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300542 consts, CONST_STACK_LASTN(j), j);
543 if (h >= 0) {
544 CONST_STACK_POP(j);
545 CONST_STACK_PUSH_OP(h);
546 }
547 break;
548 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000549 }
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300550 if (nextop != UNPACK_SEQUENCE ||
Serhiy Storchakaab874002016-09-11 13:48:15 +0300551 !ISBASICBLOCK(blocks, op_start, i + 1) ||
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300552 j != get_arg(codestr, nexti) ||
Raymond Hettinger0661e912011-03-15 15:03:36 -0700553 opcode == BUILD_SET)
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300554 break;
555 if (j < 2) {
Serhiy Storchakaab874002016-09-11 13:48:15 +0300556 fill_nops(codestr, op_start, nexti + 1);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000557 } else if (j == 2) {
Serhiy Storchakaab874002016-09-11 13:48:15 +0300558 codestr[op_start] = PACKOPARG(ROT_TWO, 0);
559 fill_nops(codestr, op_start + 1, nexti + 1);
Antoine Pitrou17b880a2011-03-11 17:27:02 +0100560 CONST_STACK_RESET();
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000561 } else if (j == 3) {
Serhiy Storchakaab874002016-09-11 13:48:15 +0300562 codestr[op_start] = PACKOPARG(ROT_THREE, 0);
563 codestr[op_start + 1] = PACKOPARG(ROT_TWO, 0);
564 fill_nops(codestr, op_start + 2, nexti + 1);
Antoine Pitrou17b880a2011-03-11 17:27:02 +0100565 CONST_STACK_RESET();
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000566 }
567 break;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000568
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000569 /* Fold binary ops on constants.
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300570 LOAD_CONST c1 LOAD_CONST c2 BINOP --> LOAD_CONST binop(c1,c2) */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000571 case BINARY_POWER:
572 case BINARY_MULTIPLY:
573 case BINARY_TRUE_DIVIDE:
574 case BINARY_FLOOR_DIVIDE:
575 case BINARY_MODULO:
576 case BINARY_ADD:
577 case BINARY_SUBTRACT:
578 case BINARY_SUBSCR:
579 case BINARY_LSHIFT:
580 case BINARY_RSHIFT:
581 case BINARY_AND:
582 case BINARY_XOR:
583 case BINARY_OR:
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300584 if (CONST_STACK_LEN() < 2)
585 break;
586 h = lastn_const_start(codestr, op_start, 2);
587 if (ISBASICBLOCK(blocks, h, op_start)) {
Serhiy Storchakaab874002016-09-11 13:48:15 +0300588 h = fold_binops_on_constants(codestr, h, i + 1, opcode,
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300589 consts, CONST_STACK_LASTN(2));
590 if (h >= 0) {
591 CONST_STACK_POP(2);
592 CONST_STACK_PUSH_OP(h);
593 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000594 }
595 break;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000596
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000597 /* Fold unary ops on constants.
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300598 LOAD_CONST c1 UNARY_OP --> LOAD_CONST unary_op(c) */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000599 case UNARY_NEGATIVE:
600 case UNARY_INVERT:
601 case UNARY_POSITIVE:
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300602 if (CONST_STACK_LEN() < 1)
603 break;
604 h = lastn_const_start(codestr, op_start, 1);
605 if (ISBASICBLOCK(blocks, h, op_start)) {
Serhiy Storchakaab874002016-09-11 13:48:15 +0300606 h = fold_unaryops_on_constants(codestr, h, i + 1, opcode,
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300607 consts, *CONST_STACK_LASTN(1));
608 if (h >= 0) {
609 CONST_STACK_POP(1);
610 CONST_STACK_PUSH_OP(h);
611 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000612 }
613 break;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000614
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000615 /* Simplify conditional jump to conditional jump where the
616 result of the first test implies the success of a similar
617 test or the failure of the opposite test.
618 Arises in code like:
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000619 "a and b or c"
620 "(a and b) and c"
Serhiy Storchaka36ff4512017-06-11 14:50:22 +0300621 "(a or b) or c"
622 "(a or b) and c"
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000623 x:JUMP_IF_FALSE_OR_POP y y:JUMP_IF_FALSE_OR_POP z
624 --> x:JUMP_IF_FALSE_OR_POP z
625 x:JUMP_IF_FALSE_OR_POP y y:JUMP_IF_TRUE_OR_POP z
Serhiy Storchakaab874002016-09-11 13:48:15 +0300626 --> x:POP_JUMP_IF_FALSE y+1
627 where y+1 is the instruction following the second test.
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000628 */
629 case JUMP_IF_FALSE_OR_POP:
630 case JUMP_IF_TRUE_OR_POP:
Serhiy Storchakaab874002016-09-11 13:48:15 +0300631 h = get_arg(codestr, i) / sizeof(_Py_CODEUNIT);
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300632 tgt = find_op(codestr, h);
633
Serhiy Storchakaab874002016-09-11 13:48:15 +0300634 j = _Py_OPCODE(codestr[tgt]);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000635 if (CONDITIONAL_JUMP(j)) {
Raymond Hettinger08eef3f2016-08-07 20:20:33 -0700636 /* NOTE: all possible jumps here are absolute. */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000637 if (JUMPS_ON_TRUE(j) == JUMPS_ON_TRUE(opcode)) {
Raymond Hettinger08eef3f2016-08-07 20:20:33 -0700638 /* The second jump will be taken iff the first is.
639 The current opcode inherits its target's
640 stack effect */
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300641 h = set_arg(codestr, i, get_arg(codestr, tgt));
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000642 } else {
Raymond Hettinger08eef3f2016-08-07 20:20:33 -0700643 /* The second jump is not taken if the first is (so
644 jump past it), and all conditional jumps pop their
645 argument when they're not taken (so change the
646 first jump to pop its argument when it's taken). */
Serhiy Storchakaab874002016-09-11 13:48:15 +0300647 h = set_arg(codestr, i, (tgt + 1) * sizeof(_Py_CODEUNIT));
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300648 j = opcode == JUMP_IF_TRUE_OR_POP ?
649 POP_JUMP_IF_TRUE : POP_JUMP_IF_FALSE;
650 }
651
652 if (h >= 0) {
653 nexti = h;
Serhiy Storchakaab874002016-09-11 13:48:15 +0300654 codestr[nexti] = PACKOPARG(j, _Py_OPARG(codestr[nexti]));
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300655 break;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000656 }
657 }
658 /* Intentional fallthrough */
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000659
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000660 /* Replace jumps to unconditional jumps */
661 case POP_JUMP_IF_FALSE:
662 case POP_JUMP_IF_TRUE:
663 case FOR_ITER:
664 case JUMP_FORWARD:
665 case JUMP_ABSOLUTE:
666 case CONTINUE_LOOP:
667 case SETUP_LOOP:
668 case SETUP_EXCEPT:
669 case SETUP_FINALLY:
670 case SETUP_WITH:
Yury Selivanov75445082015-05-11 22:57:16 -0400671 case SETUP_ASYNC_WITH:
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300672 h = GETJUMPTGT(codestr, i);
673 tgt = find_op(codestr, h);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000674 /* Replace JUMP_* to a RETURN into just a RETURN */
675 if (UNCONDITIONAL_JUMP(opcode) &&
Serhiy Storchakaab874002016-09-11 13:48:15 +0300676 _Py_OPCODE(codestr[tgt]) == RETURN_VALUE) {
677 codestr[op_start] = PACKOPARG(RETURN_VALUE, 0);
678 fill_nops(codestr, op_start + 1, i + 1);
679 } else if (UNCONDITIONAL_JUMP(_Py_OPCODE(codestr[tgt]))) {
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300680 j = GETJUMPTGT(codestr, tgt);
681 if (opcode == JUMP_FORWARD) { /* JMP_ABS can go backwards */
682 opcode = JUMP_ABSOLUTE;
683 } else if (!ABSOLUTE_JUMP(opcode)) {
Serhiy Storchakaab874002016-09-11 13:48:15 +0300684 if ((Py_ssize_t)j < i + 1) {
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300685 break; /* No backward relative jumps */
686 }
Serhiy Storchakaab874002016-09-11 13:48:15 +0300687 j -= i + 1; /* Calc relative jump addr */
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300688 }
Serhiy Storchakaab874002016-09-11 13:48:15 +0300689 j *= sizeof(_Py_CODEUNIT);
690 copy_op_arg(codestr, op_start, opcode, j, i + 1);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000691 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000692 break;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000693
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300694 /* Remove unreachable ops after RETURN */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000695 case RETURN_VALUE:
Serhiy Storchakaab874002016-09-11 13:48:15 +0300696 h = i + 1;
Serhiy Storchaka7db3c482016-10-25 09:30:43 +0300697 while (h < codelen && ISBASICBLOCK(blocks, i, h)) {
Serhiy Storchakaab874002016-09-11 13:48:15 +0300698 h++;
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300699 }
Serhiy Storchakaab874002016-09-11 13:48:15 +0300700 if (h > i + 1) {
Serhiy Storchaka7db3c482016-10-25 09:30:43 +0300701 fill_nops(codestr, i + 1, h);
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300702 nexti = find_op(codestr, h);
703 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000704 break;
705 }
706 }
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000707
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100708 /* Fixup lnotab */
Serhiy Storchakaab874002016-09-11 13:48:15 +0300709 for (i = 0, nops = 0; i < codelen; i++) {
Serhiy Storchaka67559bf2015-02-16 21:13:24 +0200710 assert(i - nops <= INT_MAX);
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100711 /* original code offset => new code offset */
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300712 blocks[i] = i - nops;
Serhiy Storchakaab874002016-09-11 13:48:15 +0300713 if (_Py_OPCODE(codestr[i]) == NOP)
714 nops++;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000715 }
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100716 cum_orig_offset = 0;
717 last_offset = 0;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000718 for (i=0 ; i < tabsiz ; i+=2) {
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300719 unsigned int offset_delta, new_offset;
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100720 cum_orig_offset += lnotab[i];
Serhiy Storchakaab874002016-09-11 13:48:15 +0300721 assert(cum_orig_offset % sizeof(_Py_CODEUNIT) == 0);
722 new_offset = blocks[cum_orig_offset / sizeof(_Py_CODEUNIT)] *
723 sizeof(_Py_CODEUNIT);
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100724 offset_delta = new_offset - last_offset;
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300725 assert(offset_delta <= 255);
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100726 lnotab[i] = (unsigned char)offset_delta;
727 last_offset = new_offset;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000728 }
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000729
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000730 /* Remove NOPs and fixup jump targets */
Serhiy Storchakaab874002016-09-11 13:48:15 +0300731 for (op_start = i = h = 0; i < codelen; i++, op_start = i) {
732 j = _Py_OPARG(codestr[i]);
733 while (_Py_OPCODE(codestr[i]) == EXTENDED_ARG) {
734 i++;
735 j = j<<8 | _Py_OPARG(codestr[i]);
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300736 }
Serhiy Storchakaab874002016-09-11 13:48:15 +0300737 opcode = _Py_OPCODE(codestr[i]);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000738 switch (opcode) {
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300739 case NOP:continue;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000740
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000741 case JUMP_ABSOLUTE:
742 case CONTINUE_LOOP:
743 case POP_JUMP_IF_FALSE:
744 case POP_JUMP_IF_TRUE:
745 case JUMP_IF_FALSE_OR_POP:
746 case JUMP_IF_TRUE_OR_POP:
Serhiy Storchakaab874002016-09-11 13:48:15 +0300747 j = blocks[j / sizeof(_Py_CODEUNIT)] * sizeof(_Py_CODEUNIT);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000748 break;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000749
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000750 case FOR_ITER:
751 case JUMP_FORWARD:
752 case SETUP_LOOP:
753 case SETUP_EXCEPT:
754 case SETUP_FINALLY:
755 case SETUP_WITH:
Yury Selivanov75445082015-05-11 22:57:16 -0400756 case SETUP_ASYNC_WITH:
Serhiy Storchakaab874002016-09-11 13:48:15 +0300757 j = blocks[j / sizeof(_Py_CODEUNIT) + i + 1] - blocks[i] - 1;
758 j *= sizeof(_Py_CODEUNIT);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000759 break;
760 }
Serhiy Storchakaab874002016-09-11 13:48:15 +0300761 nexti = i - op_start + 1;
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300762 if (instrsize(j) > nexti)
763 goto exitUnchanged;
764 /* If instrsize(j) < nexti, we'll emit EXTENDED_ARG 0 */
765 write_op_arg(codestr + h, opcode, j, nexti);
766 h += nexti;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000767 }
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300768 assert(h + (Py_ssize_t)nops == codelen);
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000769
Antoine Pitrou17b880a2011-03-11 17:27:02 +0100770 CONST_STACK_DELETE();
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000771 PyMem_Free(blocks);
Serhiy Storchakaab874002016-09-11 13:48:15 +0300772 code = PyBytes_FromStringAndSize((char *)codestr, h * sizeof(_Py_CODEUNIT));
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300773 PyMem_Free(codestr);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000774 return code;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000775
Alexandre Vassalotti6f828182009-07-21 02:51:58 +0000776 exitError:
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000777 code = NULL;
Alexandre Vassalotti6f828182009-07-21 02:51:58 +0000778
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000779 exitUnchanged:
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300780 Py_XINCREF(code);
Antoine Pitrou17b880a2011-03-11 17:27:02 +0100781 CONST_STACK_DELETE();
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100782 PyMem_Free(blocks);
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100783 PyMem_Free(codestr);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000784 return code;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000785}