blob: dd8f3e4807fce58d9d91b98600e4fbdd85f4c56a [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) {
495 /* Replace UNARY_NOT POP_JUMP_IF_FALSE
496 with POP_JUMP_IF_TRUE */
497 case UNARY_NOT:
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300498 if (nextop != POP_JUMP_IF_FALSE
Serhiy Storchakaab874002016-09-11 13:48:15 +0300499 || !ISBASICBLOCK(blocks, op_start, i + 1))
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300500 break;
Serhiy Storchakaab874002016-09-11 13:48:15 +0300501 fill_nops(codestr, op_start, i + 1);
502 codestr[nexti] = PACKOPARG(POP_JUMP_IF_TRUE, _Py_OPARG(codestr[nexti]));
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300503 break;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000504
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000505 /* not a is b --> a is not b
506 not a in b --> a not in b
507 not a is not b --> a is b
508 not a not in b --> a in b
509 */
510 case COMPARE_OP:
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300511 j = get_arg(codestr, i);
512 if (j < 6 || j > 9 ||
513 nextop != UNARY_NOT ||
Serhiy Storchakaab874002016-09-11 13:48:15 +0300514 !ISBASICBLOCK(blocks, op_start, i + 1))
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300515 break;
Serhiy Storchakaab874002016-09-11 13:48:15 +0300516 codestr[i] = PACKOPARG(opcode, j^1);
517 fill_nops(codestr, i + 1, nexti + 1);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000518 break;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000519
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000520 /* Skip over LOAD_CONST trueconst
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300521 POP_JUMP_IF_FALSE xx. This improves
522 "while 1" performance. */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000523 case LOAD_CONST:
Antoine Pitrou17b880a2011-03-11 17:27:02 +0100524 CONST_STACK_PUSH_OP(i);
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300525 if (nextop != POP_JUMP_IF_FALSE ||
Serhiy Storchakaab874002016-09-11 13:48:15 +0300526 !ISBASICBLOCK(blocks, op_start, i + 1) ||
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300527 !PyObject_IsTrue(PyList_GET_ITEM(consts, get_arg(codestr, i))))
528 break;
Serhiy Storchakaab874002016-09-11 13:48:15 +0300529 fill_nops(codestr, op_start, nexti + 1);
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300530 CONST_STACK_POP(1);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000531 break;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000532
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300533 /* Try to fold tuples of constants (includes a case for lists
534 and sets which are only used for "in" and "not in" tests).
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000535 Skip over BUILD_SEQN 1 UNPACK_SEQN 1.
536 Replace BUILD_SEQN 2 UNPACK_SEQN 2 with ROT2.
537 Replace BUILD_SEQN 3 UNPACK_SEQN 3 with ROT3 ROT2. */
538 case BUILD_TUPLE:
539 case BUILD_LIST:
540 case BUILD_SET:
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300541 j = get_arg(codestr, i);
542 if (j > 0 && CONST_STACK_LEN() >= j) {
543 h = lastn_const_start(codestr, op_start, j);
544 if ((opcode == BUILD_TUPLE &&
545 ISBASICBLOCK(blocks, h, op_start)) ||
546 ((opcode == BUILD_LIST || opcode == BUILD_SET) &&
547 ((nextop==COMPARE_OP &&
Serhiy Storchakaab874002016-09-11 13:48:15 +0300548 (_Py_OPARG(codestr[nexti]) == PyCmp_IN ||
549 _Py_OPARG(codestr[nexti]) == PyCmp_NOT_IN)) ||
550 nextop == GET_ITER) && ISBASICBLOCK(blocks, h, i + 1))) {
551 h = fold_tuple_on_constants(codestr, h, i + 1, opcode,
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300552 consts, CONST_STACK_LASTN(j), j);
553 if (h >= 0) {
554 CONST_STACK_POP(j);
555 CONST_STACK_PUSH_OP(h);
556 }
557 break;
558 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000559 }
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300560 if (nextop != UNPACK_SEQUENCE ||
Serhiy Storchakaab874002016-09-11 13:48:15 +0300561 !ISBASICBLOCK(blocks, op_start, i + 1) ||
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300562 j != get_arg(codestr, nexti) ||
Raymond Hettinger0661e912011-03-15 15:03:36 -0700563 opcode == BUILD_SET)
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300564 break;
565 if (j < 2) {
Serhiy Storchakaab874002016-09-11 13:48:15 +0300566 fill_nops(codestr, op_start, nexti + 1);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000567 } else if (j == 2) {
Serhiy Storchakaab874002016-09-11 13:48:15 +0300568 codestr[op_start] = PACKOPARG(ROT_TWO, 0);
569 fill_nops(codestr, op_start + 1, nexti + 1);
Antoine Pitrou17b880a2011-03-11 17:27:02 +0100570 CONST_STACK_RESET();
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000571 } else if (j == 3) {
Serhiy Storchakaab874002016-09-11 13:48:15 +0300572 codestr[op_start] = PACKOPARG(ROT_THREE, 0);
573 codestr[op_start + 1] = PACKOPARG(ROT_TWO, 0);
574 fill_nops(codestr, op_start + 2, nexti + 1);
Antoine Pitrou17b880a2011-03-11 17:27:02 +0100575 CONST_STACK_RESET();
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000576 }
577 break;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000578
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000579 /* Fold binary ops on constants.
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300580 LOAD_CONST c1 LOAD_CONST c2 BINOP --> LOAD_CONST binop(c1,c2) */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000581 case BINARY_POWER:
582 case BINARY_MULTIPLY:
583 case BINARY_TRUE_DIVIDE:
584 case BINARY_FLOOR_DIVIDE:
585 case BINARY_MODULO:
586 case BINARY_ADD:
587 case BINARY_SUBTRACT:
588 case BINARY_SUBSCR:
589 case BINARY_LSHIFT:
590 case BINARY_RSHIFT:
591 case BINARY_AND:
592 case BINARY_XOR:
593 case BINARY_OR:
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300594 if (CONST_STACK_LEN() < 2)
595 break;
596 h = lastn_const_start(codestr, op_start, 2);
597 if (ISBASICBLOCK(blocks, h, op_start)) {
Serhiy Storchakaab874002016-09-11 13:48:15 +0300598 h = fold_binops_on_constants(codestr, h, i + 1, opcode,
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300599 consts, CONST_STACK_LASTN(2));
600 if (h >= 0) {
601 CONST_STACK_POP(2);
602 CONST_STACK_PUSH_OP(h);
603 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000604 }
605 break;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000606
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000607 /* Fold unary ops on constants.
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300608 LOAD_CONST c1 UNARY_OP --> LOAD_CONST unary_op(c) */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000609 case UNARY_NEGATIVE:
610 case UNARY_INVERT:
611 case UNARY_POSITIVE:
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300612 if (CONST_STACK_LEN() < 1)
613 break;
614 h = lastn_const_start(codestr, op_start, 1);
615 if (ISBASICBLOCK(blocks, h, op_start)) {
Serhiy Storchakaab874002016-09-11 13:48:15 +0300616 h = fold_unaryops_on_constants(codestr, h, i + 1, opcode,
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300617 consts, *CONST_STACK_LASTN(1));
618 if (h >= 0) {
619 CONST_STACK_POP(1);
620 CONST_STACK_PUSH_OP(h);
621 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000622 }
623 break;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000624
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000625 /* Simplify conditional jump to conditional jump where the
626 result of the first test implies the success of a similar
627 test or the failure of the opposite test.
628 Arises in code like:
629 "if a and b:"
630 "if a or b:"
631 "a and b or c"
632 "(a and b) and c"
633 x:JUMP_IF_FALSE_OR_POP y y:JUMP_IF_FALSE_OR_POP z
634 --> x:JUMP_IF_FALSE_OR_POP z
635 x:JUMP_IF_FALSE_OR_POP y y:JUMP_IF_TRUE_OR_POP z
Serhiy Storchakaab874002016-09-11 13:48:15 +0300636 --> x:POP_JUMP_IF_FALSE y+1
637 where y+1 is the instruction following the second test.
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000638 */
639 case JUMP_IF_FALSE_OR_POP:
640 case JUMP_IF_TRUE_OR_POP:
Serhiy Storchakaab874002016-09-11 13:48:15 +0300641 h = get_arg(codestr, i) / sizeof(_Py_CODEUNIT);
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300642 tgt = find_op(codestr, h);
643
Serhiy Storchakaab874002016-09-11 13:48:15 +0300644 j = _Py_OPCODE(codestr[tgt]);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000645 if (CONDITIONAL_JUMP(j)) {
Raymond Hettinger08eef3f2016-08-07 20:20:33 -0700646 /* NOTE: all possible jumps here are absolute. */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000647 if (JUMPS_ON_TRUE(j) == JUMPS_ON_TRUE(opcode)) {
Raymond Hettinger08eef3f2016-08-07 20:20:33 -0700648 /* The second jump will be taken iff the first is.
649 The current opcode inherits its target's
650 stack effect */
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300651 h = set_arg(codestr, i, get_arg(codestr, tgt));
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000652 } else {
Raymond Hettinger08eef3f2016-08-07 20:20:33 -0700653 /* The second jump is not taken if the first is (so
654 jump past it), and all conditional jumps pop their
655 argument when they're not taken (so change the
656 first jump to pop its argument when it's taken). */
Serhiy Storchakaab874002016-09-11 13:48:15 +0300657 h = set_arg(codestr, i, (tgt + 1) * sizeof(_Py_CODEUNIT));
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300658 j = opcode == JUMP_IF_TRUE_OR_POP ?
659 POP_JUMP_IF_TRUE : POP_JUMP_IF_FALSE;
660 }
661
662 if (h >= 0) {
663 nexti = h;
Serhiy Storchakaab874002016-09-11 13:48:15 +0300664 codestr[nexti] = PACKOPARG(j, _Py_OPARG(codestr[nexti]));
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300665 break;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000666 }
667 }
668 /* Intentional fallthrough */
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000669
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000670 /* Replace jumps to unconditional jumps */
671 case POP_JUMP_IF_FALSE:
672 case POP_JUMP_IF_TRUE:
673 case FOR_ITER:
674 case JUMP_FORWARD:
675 case JUMP_ABSOLUTE:
676 case CONTINUE_LOOP:
677 case SETUP_LOOP:
678 case SETUP_EXCEPT:
679 case SETUP_FINALLY:
680 case SETUP_WITH:
Yury Selivanov75445082015-05-11 22:57:16 -0400681 case SETUP_ASYNC_WITH:
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300682 h = GETJUMPTGT(codestr, i);
683 tgt = find_op(codestr, h);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000684 /* Replace JUMP_* to a RETURN into just a RETURN */
685 if (UNCONDITIONAL_JUMP(opcode) &&
Serhiy Storchakaab874002016-09-11 13:48:15 +0300686 _Py_OPCODE(codestr[tgt]) == RETURN_VALUE) {
687 codestr[op_start] = PACKOPARG(RETURN_VALUE, 0);
688 fill_nops(codestr, op_start + 1, i + 1);
689 } else if (UNCONDITIONAL_JUMP(_Py_OPCODE(codestr[tgt]))) {
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300690 j = GETJUMPTGT(codestr, tgt);
691 if (opcode == JUMP_FORWARD) { /* JMP_ABS can go backwards */
692 opcode = JUMP_ABSOLUTE;
693 } else if (!ABSOLUTE_JUMP(opcode)) {
Serhiy Storchakaab874002016-09-11 13:48:15 +0300694 if ((Py_ssize_t)j < i + 1) {
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300695 break; /* No backward relative jumps */
696 }
Serhiy Storchakaab874002016-09-11 13:48:15 +0300697 j -= i + 1; /* Calc relative jump addr */
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300698 }
Serhiy Storchakaab874002016-09-11 13:48:15 +0300699 j *= sizeof(_Py_CODEUNIT);
700 copy_op_arg(codestr, op_start, opcode, j, i + 1);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000701 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000702 break;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000703
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300704 /* Remove unreachable ops after RETURN */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000705 case RETURN_VALUE:
Serhiy Storchakaab874002016-09-11 13:48:15 +0300706 h = i + 1;
Serhiy Storchaka7db3c482016-10-25 09:30:43 +0300707 while (h < codelen && ISBASICBLOCK(blocks, i, h)) {
Serhiy Storchakaab874002016-09-11 13:48:15 +0300708 h++;
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300709 }
Serhiy Storchakaab874002016-09-11 13:48:15 +0300710 if (h > i + 1) {
Serhiy Storchaka7db3c482016-10-25 09:30:43 +0300711 fill_nops(codestr, i + 1, h);
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300712 nexti = find_op(codestr, h);
713 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000714 break;
715 }
716 }
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000717
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100718 /* Fixup lnotab */
Serhiy Storchakaab874002016-09-11 13:48:15 +0300719 for (i = 0, nops = 0; i < codelen; i++) {
Serhiy Storchaka67559bf2015-02-16 21:13:24 +0200720 assert(i - nops <= INT_MAX);
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100721 /* original code offset => new code offset */
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300722 blocks[i] = i - nops;
Serhiy Storchakaab874002016-09-11 13:48:15 +0300723 if (_Py_OPCODE(codestr[i]) == NOP)
724 nops++;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000725 }
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100726 cum_orig_offset = 0;
727 last_offset = 0;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000728 for (i=0 ; i < tabsiz ; i+=2) {
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300729 unsigned int offset_delta, new_offset;
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100730 cum_orig_offset += lnotab[i];
Serhiy Storchakaab874002016-09-11 13:48:15 +0300731 assert(cum_orig_offset % sizeof(_Py_CODEUNIT) == 0);
732 new_offset = blocks[cum_orig_offset / sizeof(_Py_CODEUNIT)] *
733 sizeof(_Py_CODEUNIT);
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100734 offset_delta = new_offset - last_offset;
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300735 assert(offset_delta <= 255);
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100736 lnotab[i] = (unsigned char)offset_delta;
737 last_offset = new_offset;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000738 }
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000739
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000740 /* Remove NOPs and fixup jump targets */
Serhiy Storchakaab874002016-09-11 13:48:15 +0300741 for (op_start = i = h = 0; i < codelen; i++, op_start = i) {
742 j = _Py_OPARG(codestr[i]);
743 while (_Py_OPCODE(codestr[i]) == EXTENDED_ARG) {
744 i++;
745 j = j<<8 | _Py_OPARG(codestr[i]);
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300746 }
Serhiy Storchakaab874002016-09-11 13:48:15 +0300747 opcode = _Py_OPCODE(codestr[i]);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000748 switch (opcode) {
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300749 case NOP:continue;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000750
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000751 case JUMP_ABSOLUTE:
752 case CONTINUE_LOOP:
753 case POP_JUMP_IF_FALSE:
754 case POP_JUMP_IF_TRUE:
755 case JUMP_IF_FALSE_OR_POP:
756 case JUMP_IF_TRUE_OR_POP:
Serhiy Storchakaab874002016-09-11 13:48:15 +0300757 j = blocks[j / sizeof(_Py_CODEUNIT)] * sizeof(_Py_CODEUNIT);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000758 break;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000759
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000760 case FOR_ITER:
761 case JUMP_FORWARD:
762 case SETUP_LOOP:
763 case SETUP_EXCEPT:
764 case SETUP_FINALLY:
765 case SETUP_WITH:
Yury Selivanov75445082015-05-11 22:57:16 -0400766 case SETUP_ASYNC_WITH:
Serhiy Storchakaab874002016-09-11 13:48:15 +0300767 j = blocks[j / sizeof(_Py_CODEUNIT) + i + 1] - blocks[i] - 1;
768 j *= sizeof(_Py_CODEUNIT);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000769 break;
770 }
Serhiy Storchakaab874002016-09-11 13:48:15 +0300771 nexti = i - op_start + 1;
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300772 if (instrsize(j) > nexti)
773 goto exitUnchanged;
774 /* If instrsize(j) < nexti, we'll emit EXTENDED_ARG 0 */
775 write_op_arg(codestr + h, opcode, j, nexti);
776 h += nexti;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000777 }
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300778 assert(h + (Py_ssize_t)nops == codelen);
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000779
Antoine Pitrou17b880a2011-03-11 17:27:02 +0100780 CONST_STACK_DELETE();
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000781 PyMem_Free(blocks);
Serhiy Storchakaab874002016-09-11 13:48:15 +0300782 code = PyBytes_FromStringAndSize((char *)codestr, h * sizeof(_Py_CODEUNIT));
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300783 PyMem_Free(codestr);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000784 return code;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000785
Alexandre Vassalotti6f828182009-07-21 02:51:58 +0000786 exitError:
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000787 code = NULL;
Alexandre Vassalotti6f828182009-07-21 02:51:58 +0000788
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000789 exitUnchanged:
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300790 Py_XINCREF(code);
Antoine Pitrou17b880a2011-03-11 17:27:02 +0100791 CONST_STACK_DELETE();
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100792 PyMem_Free(blocks);
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100793 PyMem_Free(codestr);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000794 return code;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000795}