blob: 49d62a2c3422cf423242794cab2422bbbae660a3 [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.
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000176*/
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300177static Py_ssize_t
Serhiy Storchakaab874002016-09-11 13:48:15 +0300178fold_tuple_on_constants(_Py_CODEUNIT *codestr, Py_ssize_t c_start,
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300179 Py_ssize_t opcode_end, unsigned char opcode,
180 PyObject *consts, PyObject **objs, int n)
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000181{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000182 PyObject *newconst, *constant;
Antoine Pitrou17b880a2011-03-11 17:27:02 +0100183 Py_ssize_t i, len_consts;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000184
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000185 /* Pre-conditions */
186 assert(PyList_CheckExact(consts));
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000187
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000188 /* Buildup new tuple of constants */
189 newconst = PyTuple_New(n);
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300190 if (newconst == NULL) {
191 return -1;
192 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000193 for (i=0 ; i<n ; i++) {
Antoine Pitrou17b880a2011-03-11 17:27:02 +0100194 constant = objs[i];
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000195 Py_INCREF(constant);
196 PyTuple_SET_ITEM(newconst, i, constant);
197 }
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000198
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000199 /* Append folded constant onto consts */
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300200 len_consts = PyList_GET_SIZE(consts);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000201 if (PyList_Append(consts, newconst)) {
202 Py_DECREF(newconst);
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300203 return -1;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000204 }
205 Py_DECREF(newconst);
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000206
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300207 return copy_op_arg(codestr, c_start, LOAD_CONST, len_consts, opcode_end);
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000208}
209
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000210static unsigned int *
Serhiy Storchakaab874002016-09-11 13:48:15 +0300211markblocks(_Py_CODEUNIT *code, Py_ssize_t len)
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000212{
Serhiy Storchaka1a1ff292015-02-16 13:28:22 +0200213 unsigned int *blocks = PyMem_New(unsigned int, len);
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300214 int i, j, opcode, blockcnt = 0;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000215
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000216 if (blocks == NULL) {
217 PyErr_NoMemory();
218 return NULL;
219 }
220 memset(blocks, 0, len*sizeof(int));
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000221
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000222 /* Mark labels in the first pass */
Serhiy Storchakaab874002016-09-11 13:48:15 +0300223 for (i = 0; i < len; i++) {
224 opcode = _Py_OPCODE(code[i]);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000225 switch (opcode) {
226 case FOR_ITER:
227 case JUMP_FORWARD:
228 case JUMP_IF_FALSE_OR_POP:
229 case JUMP_IF_TRUE_OR_POP:
230 case POP_JUMP_IF_FALSE:
231 case POP_JUMP_IF_TRUE:
232 case JUMP_ABSOLUTE:
233 case CONTINUE_LOOP:
234 case SETUP_LOOP:
235 case SETUP_EXCEPT:
236 case SETUP_FINALLY:
237 case SETUP_WITH:
Yury Selivanov75445082015-05-11 22:57:16 -0400238 case SETUP_ASYNC_WITH:
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000239 j = GETJUMPTGT(code, i);
Serhiy Storchakaab874002016-09-11 13:48:15 +0300240 assert(j < len);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000241 blocks[j] = 1;
242 break;
243 }
244 }
245 /* Build block numbers in the second pass */
Serhiy Storchakaab874002016-09-11 13:48:15 +0300246 for (i = 0; i < len; i++) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000247 blockcnt += blocks[i]; /* increment blockcnt over labels */
248 blocks[i] = blockcnt;
249 }
250 return blocks;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000251}
252
253/* Perform basic peephole optimizations to components of a code object.
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000254 The consts object should still be in list form to allow new constants
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000255 to be appended.
256
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300257 To keep the optimizer simple, it bails when the lineno table has complex
258 encoding for gaps >= 255.
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000259
Martin Panter46f50722016-05-26 05:35:26 +0000260 Optimizations are restricted to simple transformations occurring within a
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000261 single basic block. All transformations keep the code size the same or
262 smaller. For those that reduce size, the gaps are initially filled with
263 NOPs. Later those NOPs are removed and the jump addresses retargeted in
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300264 a single pass. */
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000265
266PyObject *
267PyCode_Optimize(PyObject *code, PyObject* consts, PyObject *names,
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100268 PyObject *lnotab_obj)
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000269{
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300270 Py_ssize_t h, i, nexti, op_start, codelen, tgt;
271 unsigned int j, nops;
272 unsigned char opcode, nextop;
Serhiy Storchakaab874002016-09-11 13:48:15 +0300273 _Py_CODEUNIT *codestr = NULL;
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100274 unsigned char *lnotab;
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300275 unsigned int cum_orig_offset, last_offset;
Serhiy Storchaka67559bf2015-02-16 21:13:24 +0200276 Py_ssize_t tabsiz;
Antoine Pitrou17b880a2011-03-11 17:27:02 +0100277 PyObject **const_stack = NULL;
Antoine Pitrou17b880a2011-03-11 17:27:02 +0100278 Py_ssize_t const_stack_top = -1;
279 Py_ssize_t const_stack_size = 0;
280 int in_consts = 0; /* whether we are in a LOAD_CONST sequence */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000281 unsigned int *blocks = NULL;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000282
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000283 /* Bail out if an exception is set */
284 if (PyErr_Occurred())
285 goto exitError;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000286
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100287 /* Bypass optimization when the lnotab table is too complex */
288 assert(PyBytes_Check(lnotab_obj));
289 lnotab = (unsigned char*)PyBytes_AS_STRING(lnotab_obj);
290 tabsiz = PyBytes_GET_SIZE(lnotab_obj);
291 assert(tabsiz == 0 || Py_REFCNT(lnotab_obj) == 1);
292 if (memchr(lnotab, 255, tabsiz) != NULL) {
293 /* 255 value are used for multibyte bytecode instructions */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000294 goto exitUnchanged;
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100295 }
296 /* Note: -128 and 127 special values for line number delta are ok,
297 the peephole optimizer doesn't modify line numbers. */
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000298
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000299 assert(PyBytes_Check(code));
300 codelen = PyBytes_GET_SIZE(code);
Serhiy Storchakaab874002016-09-11 13:48:15 +0300301 assert(codelen % sizeof(_Py_CODEUNIT) == 0);
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000302
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000303 /* Make a modifiable copy of the code string */
Serhiy Storchakaab874002016-09-11 13:48:15 +0300304 codestr = (_Py_CODEUNIT *)PyMem_Malloc(codelen);
Victor Stinnere0af3a82013-07-09 00:32:04 +0200305 if (codestr == NULL) {
306 PyErr_NoMemory();
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000307 goto exitError;
Victor Stinnere0af3a82013-07-09 00:32:04 +0200308 }
Serhiy Storchakaab874002016-09-11 13:48:15 +0300309 memcpy(codestr, PyBytes_AS_STRING(code), codelen);
310 codelen /= sizeof(_Py_CODEUNIT);
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000311
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000312 blocks = markblocks(codestr, codelen);
313 if (blocks == NULL)
314 goto exitError;
315 assert(PyList_Check(consts));
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000316
Antoine Pitrou17b880a2011-03-11 17:27:02 +0100317 CONST_STACK_CREATE();
318
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300319 for (i=find_op(codestr, 0) ; i<codelen ; i=nexti) {
Serhiy Storchakaa1e9ab32016-09-11 15:19:12 +0300320 opcode = _Py_OPCODE(codestr[i]);
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300321 op_start = i;
Serhiy Storchakaab874002016-09-11 13:48:15 +0300322 while (op_start >= 1 && _Py_OPCODE(codestr[op_start-1]) == EXTENDED_ARG) {
323 op_start--;
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300324 }
325
Serhiy Storchakaab874002016-09-11 13:48:15 +0300326 nexti = i + 1;
327 while (nexti < codelen && _Py_OPCODE(codestr[nexti]) == EXTENDED_ARG)
328 nexti++;
329 nextop = nexti < codelen ? _Py_OPCODE(codestr[nexti]) : 0;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000330
Antoine Pitrou17b880a2011-03-11 17:27:02 +0100331 if (!in_consts) {
332 CONST_STACK_RESET();
333 }
334 in_consts = 0;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000335
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000336 switch (opcode) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000337 /* Skip over LOAD_CONST trueconst
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300338 POP_JUMP_IF_FALSE xx. This improves
339 "while 1" performance. */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000340 case LOAD_CONST:
Antoine Pitrou17b880a2011-03-11 17:27:02 +0100341 CONST_STACK_PUSH_OP(i);
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300342 if (nextop != POP_JUMP_IF_FALSE ||
Serhiy Storchakaab874002016-09-11 13:48:15 +0300343 !ISBASICBLOCK(blocks, op_start, i + 1) ||
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300344 !PyObject_IsTrue(PyList_GET_ITEM(consts, get_arg(codestr, i))))
345 break;
Serhiy Storchakaab874002016-09-11 13:48:15 +0300346 fill_nops(codestr, op_start, nexti + 1);
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300347 CONST_STACK_POP(1);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000348 break;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000349
Serhiy Storchaka15a87282017-12-14 20:24:31 +0200350 /* Try to fold tuples of constants.
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000351 Skip over BUILD_SEQN 1 UNPACK_SEQN 1.
352 Replace BUILD_SEQN 2 UNPACK_SEQN 2 with ROT2.
353 Replace BUILD_SEQN 3 UNPACK_SEQN 3 with ROT3 ROT2. */
354 case BUILD_TUPLE:
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300355 j = get_arg(codestr, i);
356 if (j > 0 && CONST_STACK_LEN() >= j) {
357 h = lastn_const_start(codestr, op_start, j);
Serhiy Storchaka15a87282017-12-14 20:24:31 +0200358 if (ISBASICBLOCK(blocks, h, op_start)) {
Serhiy Storchakaab874002016-09-11 13:48:15 +0300359 h = fold_tuple_on_constants(codestr, h, i + 1, opcode,
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300360 consts, CONST_STACK_LASTN(j), j);
361 if (h >= 0) {
362 CONST_STACK_POP(j);
363 CONST_STACK_PUSH_OP(h);
364 }
365 break;
366 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000367 }
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300368 if (nextop != UNPACK_SEQUENCE ||
Serhiy Storchakaab874002016-09-11 13:48:15 +0300369 !ISBASICBLOCK(blocks, op_start, i + 1) ||
Serhiy Storchaka15a87282017-12-14 20:24:31 +0200370 j != get_arg(codestr, nexti))
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300371 break;
372 if (j < 2) {
Serhiy Storchakaab874002016-09-11 13:48:15 +0300373 fill_nops(codestr, op_start, nexti + 1);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000374 } else if (j == 2) {
Serhiy Storchakaab874002016-09-11 13:48:15 +0300375 codestr[op_start] = PACKOPARG(ROT_TWO, 0);
376 fill_nops(codestr, op_start + 1, nexti + 1);
Antoine Pitrou17b880a2011-03-11 17:27:02 +0100377 CONST_STACK_RESET();
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000378 } else if (j == 3) {
Serhiy Storchakaab874002016-09-11 13:48:15 +0300379 codestr[op_start] = PACKOPARG(ROT_THREE, 0);
380 codestr[op_start + 1] = PACKOPARG(ROT_TWO, 0);
381 fill_nops(codestr, op_start + 2, nexti + 1);
Antoine Pitrou17b880a2011-03-11 17:27:02 +0100382 CONST_STACK_RESET();
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000383 }
384 break;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000385
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000386 /* Simplify conditional jump to conditional jump where the
387 result of the first test implies the success of a similar
388 test or the failure of the opposite test.
389 Arises in code like:
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000390 "a and b or c"
391 "(a and b) and c"
Serhiy Storchaka36ff4512017-06-11 14:50:22 +0300392 "(a or b) or c"
393 "(a or b) and c"
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000394 x:JUMP_IF_FALSE_OR_POP y y:JUMP_IF_FALSE_OR_POP z
395 --> x:JUMP_IF_FALSE_OR_POP z
396 x:JUMP_IF_FALSE_OR_POP y y:JUMP_IF_TRUE_OR_POP z
Serhiy Storchakaab874002016-09-11 13:48:15 +0300397 --> x:POP_JUMP_IF_FALSE y+1
398 where y+1 is the instruction following the second test.
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000399 */
400 case JUMP_IF_FALSE_OR_POP:
401 case JUMP_IF_TRUE_OR_POP:
Serhiy Storchakaab874002016-09-11 13:48:15 +0300402 h = get_arg(codestr, i) / sizeof(_Py_CODEUNIT);
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300403 tgt = find_op(codestr, h);
404
Serhiy Storchakaab874002016-09-11 13:48:15 +0300405 j = _Py_OPCODE(codestr[tgt]);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000406 if (CONDITIONAL_JUMP(j)) {
Raymond Hettinger08eef3f2016-08-07 20:20:33 -0700407 /* NOTE: all possible jumps here are absolute. */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000408 if (JUMPS_ON_TRUE(j) == JUMPS_ON_TRUE(opcode)) {
Raymond Hettinger08eef3f2016-08-07 20:20:33 -0700409 /* The second jump will be taken iff the first is.
410 The current opcode inherits its target's
411 stack effect */
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300412 h = set_arg(codestr, i, get_arg(codestr, tgt));
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000413 } else {
Raymond Hettinger08eef3f2016-08-07 20:20:33 -0700414 /* The second jump is not taken if the first is (so
415 jump past it), and all conditional jumps pop their
416 argument when they're not taken (so change the
417 first jump to pop its argument when it's taken). */
Serhiy Storchakaab874002016-09-11 13:48:15 +0300418 h = set_arg(codestr, i, (tgt + 1) * sizeof(_Py_CODEUNIT));
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300419 j = opcode == JUMP_IF_TRUE_OR_POP ?
420 POP_JUMP_IF_TRUE : POP_JUMP_IF_FALSE;
421 }
422
423 if (h >= 0) {
424 nexti = h;
Serhiy Storchakaab874002016-09-11 13:48:15 +0300425 codestr[nexti] = PACKOPARG(j, _Py_OPARG(codestr[nexti]));
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300426 break;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000427 }
428 }
429 /* Intentional fallthrough */
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000430
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000431 /* Replace jumps to unconditional jumps */
432 case POP_JUMP_IF_FALSE:
433 case POP_JUMP_IF_TRUE:
434 case FOR_ITER:
435 case JUMP_FORWARD:
436 case JUMP_ABSOLUTE:
437 case CONTINUE_LOOP:
438 case SETUP_LOOP:
439 case SETUP_EXCEPT:
440 case SETUP_FINALLY:
441 case SETUP_WITH:
Yury Selivanov75445082015-05-11 22:57:16 -0400442 case SETUP_ASYNC_WITH:
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300443 h = GETJUMPTGT(codestr, i);
444 tgt = find_op(codestr, h);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000445 /* Replace JUMP_* to a RETURN into just a RETURN */
446 if (UNCONDITIONAL_JUMP(opcode) &&
Serhiy Storchakaab874002016-09-11 13:48:15 +0300447 _Py_OPCODE(codestr[tgt]) == RETURN_VALUE) {
448 codestr[op_start] = PACKOPARG(RETURN_VALUE, 0);
449 fill_nops(codestr, op_start + 1, i + 1);
450 } else if (UNCONDITIONAL_JUMP(_Py_OPCODE(codestr[tgt]))) {
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300451 j = GETJUMPTGT(codestr, tgt);
452 if (opcode == JUMP_FORWARD) { /* JMP_ABS can go backwards */
453 opcode = JUMP_ABSOLUTE;
454 } else if (!ABSOLUTE_JUMP(opcode)) {
Serhiy Storchakaab874002016-09-11 13:48:15 +0300455 if ((Py_ssize_t)j < i + 1) {
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300456 break; /* No backward relative jumps */
457 }
Serhiy Storchakaab874002016-09-11 13:48:15 +0300458 j -= i + 1; /* Calc relative jump addr */
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300459 }
Serhiy Storchakaab874002016-09-11 13:48:15 +0300460 j *= sizeof(_Py_CODEUNIT);
461 copy_op_arg(codestr, op_start, opcode, j, i + 1);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000462 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000463 break;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000464
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300465 /* Remove unreachable ops after RETURN */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000466 case RETURN_VALUE:
Serhiy Storchakaab874002016-09-11 13:48:15 +0300467 h = i + 1;
Serhiy Storchaka7db3c482016-10-25 09:30:43 +0300468 while (h < codelen && ISBASICBLOCK(blocks, i, h)) {
Serhiy Storchakaab874002016-09-11 13:48:15 +0300469 h++;
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300470 }
Serhiy Storchakaab874002016-09-11 13:48:15 +0300471 if (h > i + 1) {
Serhiy Storchaka7db3c482016-10-25 09:30:43 +0300472 fill_nops(codestr, i + 1, h);
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300473 nexti = find_op(codestr, h);
474 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000475 break;
476 }
477 }
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000478
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100479 /* Fixup lnotab */
Serhiy Storchakaab874002016-09-11 13:48:15 +0300480 for (i = 0, nops = 0; i < codelen; i++) {
Serhiy Storchaka67559bf2015-02-16 21:13:24 +0200481 assert(i - nops <= INT_MAX);
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100482 /* original code offset => new code offset */
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300483 blocks[i] = i - nops;
Serhiy Storchakaab874002016-09-11 13:48:15 +0300484 if (_Py_OPCODE(codestr[i]) == NOP)
485 nops++;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000486 }
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100487 cum_orig_offset = 0;
488 last_offset = 0;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000489 for (i=0 ; i < tabsiz ; i+=2) {
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300490 unsigned int offset_delta, new_offset;
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100491 cum_orig_offset += lnotab[i];
Serhiy Storchakaab874002016-09-11 13:48:15 +0300492 assert(cum_orig_offset % sizeof(_Py_CODEUNIT) == 0);
493 new_offset = blocks[cum_orig_offset / sizeof(_Py_CODEUNIT)] *
494 sizeof(_Py_CODEUNIT);
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100495 offset_delta = new_offset - last_offset;
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300496 assert(offset_delta <= 255);
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100497 lnotab[i] = (unsigned char)offset_delta;
498 last_offset = new_offset;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000499 }
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000500
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000501 /* Remove NOPs and fixup jump targets */
Serhiy Storchakaab874002016-09-11 13:48:15 +0300502 for (op_start = i = h = 0; i < codelen; i++, op_start = i) {
503 j = _Py_OPARG(codestr[i]);
504 while (_Py_OPCODE(codestr[i]) == EXTENDED_ARG) {
505 i++;
506 j = j<<8 | _Py_OPARG(codestr[i]);
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300507 }
Serhiy Storchakaab874002016-09-11 13:48:15 +0300508 opcode = _Py_OPCODE(codestr[i]);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000509 switch (opcode) {
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300510 case NOP:continue;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000511
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000512 case JUMP_ABSOLUTE:
513 case CONTINUE_LOOP:
514 case POP_JUMP_IF_FALSE:
515 case POP_JUMP_IF_TRUE:
516 case JUMP_IF_FALSE_OR_POP:
517 case JUMP_IF_TRUE_OR_POP:
Serhiy Storchakaab874002016-09-11 13:48:15 +0300518 j = blocks[j / sizeof(_Py_CODEUNIT)] * sizeof(_Py_CODEUNIT);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000519 break;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000520
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000521 case FOR_ITER:
522 case JUMP_FORWARD:
523 case SETUP_LOOP:
524 case SETUP_EXCEPT:
525 case SETUP_FINALLY:
526 case SETUP_WITH:
Yury Selivanov75445082015-05-11 22:57:16 -0400527 case SETUP_ASYNC_WITH:
Serhiy Storchakaab874002016-09-11 13:48:15 +0300528 j = blocks[j / sizeof(_Py_CODEUNIT) + i + 1] - blocks[i] - 1;
529 j *= sizeof(_Py_CODEUNIT);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000530 break;
531 }
Serhiy Storchakaab874002016-09-11 13:48:15 +0300532 nexti = i - op_start + 1;
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300533 if (instrsize(j) > nexti)
534 goto exitUnchanged;
535 /* If instrsize(j) < nexti, we'll emit EXTENDED_ARG 0 */
536 write_op_arg(codestr + h, opcode, j, nexti);
537 h += nexti;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000538 }
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300539 assert(h + (Py_ssize_t)nops == codelen);
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000540
Antoine Pitrou17b880a2011-03-11 17:27:02 +0100541 CONST_STACK_DELETE();
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000542 PyMem_Free(blocks);
Serhiy Storchakaab874002016-09-11 13:48:15 +0300543 code = PyBytes_FromStringAndSize((char *)codestr, h * sizeof(_Py_CODEUNIT));
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300544 PyMem_Free(codestr);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000545 return code;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000546
Alexandre Vassalotti6f828182009-07-21 02:51:58 +0000547 exitError:
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000548 code = NULL;
Alexandre Vassalotti6f828182009-07-21 02:51:58 +0000549
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000550 exitUnchanged:
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300551 Py_XINCREF(code);
Antoine Pitrou17b880a2011-03-11 17:27:02 +0100552 CONST_STACK_DELETE();
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100553 PyMem_Free(blocks);
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100554 PyMem_Free(codestr);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000555 return code;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000556}