blob: 95b3dbb6bf519292344f39c200847165bd821241 [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
Serhiy Storchakab0f80b02016-05-24 09:15:14 +030026/* Scans back N consecutive LOAD_CONST instructions, skipping NOPs,
27 returns index of the Nth last's LOAD_CONST's EXTENDED_ARG prefix.
28 Callers are responsible to check CONST_STACK_LEN beforehand.
29*/
30static Py_ssize_t
Serhiy Storchakaab874002016-09-11 13:48:15 +030031lastn_const_start(const _Py_CODEUNIT *codestr, Py_ssize_t i, Py_ssize_t n)
Serhiy Storchakab0f80b02016-05-24 09:15:14 +030032{
Serhiy Storchakaab874002016-09-11 13:48:15 +030033 assert(n > 0);
Serhiy Storchakab0f80b02016-05-24 09:15:14 +030034 for (;;) {
Serhiy Storchakaab874002016-09-11 13:48:15 +030035 i--;
Serhiy Storchakab0f80b02016-05-24 09:15:14 +030036 assert(i >= 0);
Serhiy Storchakaab874002016-09-11 13:48:15 +030037 if (_Py_OPCODE(codestr[i]) == LOAD_CONST) {
Serhiy Storchakab0f80b02016-05-24 09:15:14 +030038 if (!--n) {
Serhiy Storchakaab874002016-09-11 13:48:15 +030039 while (i > 0 && _Py_OPCODE(codestr[i-1]) == EXTENDED_ARG) {
40 i--;
Serhiy Storchakab0f80b02016-05-24 09:15:14 +030041 }
42 return i;
43 }
44 }
45 else {
INADA Naoki87010e82017-12-18 15:52:54 +090046 assert(_Py_OPCODE(codestr[i]) == EXTENDED_ARG);
Serhiy Storchakab0f80b02016-05-24 09:15:14 +030047 }
48 }
49}
Antoine Pitrou17b880a2011-03-11 17:27:02 +010050
Serhiy Storchakab0f80b02016-05-24 09:15:14 +030051/* Scans through EXTENDED ARGs, seeking the index of the effective opcode */
52static Py_ssize_t
Miss Islington (bot)f16ebcd2018-11-08 18:13:14 -080053find_op(const _Py_CODEUNIT *codestr, Py_ssize_t codelen, Py_ssize_t i)
Serhiy Storchakab0f80b02016-05-24 09:15:14 +030054{
Miss Islington (bot)f16ebcd2018-11-08 18:13:14 -080055 while (i < codelen && _Py_OPCODE(codestr[i]) == EXTENDED_ARG) {
Serhiy Storchakaab874002016-09-11 13:48:15 +030056 i++;
Serhiy Storchakab0f80b02016-05-24 09:15:14 +030057 }
58 return i;
59}
Antoine Pitrou17b880a2011-03-11 17:27:02 +010060
Serhiy Storchakab0f80b02016-05-24 09:15:14 +030061/* Given the index of the effective opcode,
62 scan back to construct the oparg with EXTENDED_ARG */
63static unsigned int
Serhiy Storchakaab874002016-09-11 13:48:15 +030064get_arg(const _Py_CODEUNIT *codestr, Py_ssize_t i)
Serhiy Storchakab0f80b02016-05-24 09:15:14 +030065{
Serhiy Storchakaab874002016-09-11 13:48:15 +030066 _Py_CODEUNIT word;
67 unsigned int oparg = _Py_OPARG(codestr[i]);
68 if (i >= 1 && _Py_OPCODE(word = codestr[i-1]) == EXTENDED_ARG) {
69 oparg |= _Py_OPARG(word) << 8;
70 if (i >= 2 && _Py_OPCODE(word = codestr[i-2]) == EXTENDED_ARG) {
71 oparg |= _Py_OPARG(word) << 16;
72 if (i >= 3 && _Py_OPCODE(word = codestr[i-3]) == EXTENDED_ARG) {
73 oparg |= _Py_OPARG(word) << 24;
Serhiy Storchakab0f80b02016-05-24 09:15:14 +030074 }
75 }
76 }
77 return oparg;
78}
79
Serhiy Storchakaab874002016-09-11 13:48:15 +030080/* Fill the region with NOPs. */
81static void
82fill_nops(_Py_CODEUNIT *codestr, Py_ssize_t start, Py_ssize_t end)
83{
84 memset(codestr + start, NOP, (end - start) * sizeof(_Py_CODEUNIT));
85}
86
Serhiy Storchakab0f80b02016-05-24 09:15:14 +030087/* Given the index of the effective opcode,
88 attempt to replace the argument, taking into account EXTENDED_ARG.
89 Returns -1 on failure, or the new op index on success */
90static Py_ssize_t
Serhiy Storchakaab874002016-09-11 13:48:15 +030091set_arg(_Py_CODEUNIT *codestr, Py_ssize_t i, unsigned int oparg)
Serhiy Storchakab0f80b02016-05-24 09:15:14 +030092{
93 unsigned int curarg = get_arg(codestr, i);
94 int curilen, newilen;
95 if (curarg == oparg)
96 return i;
97 curilen = instrsize(curarg);
98 newilen = instrsize(oparg);
99 if (curilen < newilen) {
100 return -1;
101 }
102
Serhiy Storchakaab874002016-09-11 13:48:15 +0300103 write_op_arg(codestr + i + 1 - curilen, _Py_OPCODE(codestr[i]), oparg, newilen);
104 fill_nops(codestr, i + 1 - curilen + newilen, i + 1);
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300105 return i-curilen+newilen;
106}
107
108/* Attempt to write op/arg at end of specified region of memory.
109 Preceding memory in the region is overwritten with NOPs.
110 Returns -1 on failure, op index on success */
111static Py_ssize_t
Serhiy Storchakaab874002016-09-11 13:48:15 +0300112copy_op_arg(_Py_CODEUNIT *codestr, Py_ssize_t i, unsigned char op,
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300113 unsigned int oparg, Py_ssize_t maxi)
114{
115 int ilen = instrsize(oparg);
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300116 if (i + ilen > maxi) {
117 return -1;
118 }
119 write_op_arg(codestr + maxi - ilen, op, oparg, ilen);
Serhiy Storchakaab874002016-09-11 13:48:15 +0300120 fill_nops(codestr, i, maxi - ilen);
121 return maxi - 1;
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300122}
123
124/* Replace LOAD_CONST c1, LOAD_CONST c2 ... LOAD_CONST cn, BUILD_TUPLE n
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000125 with LOAD_CONST (c1, c2, ... cn).
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000126 The consts table must still be in list form so that the
127 new constant (c1, c2, ... cn) can be appended.
128 Called with codestr pointing to the first LOAD_CONST.
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000129*/
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300130static Py_ssize_t
Miss Islington (bot)f16ebcd2018-11-08 18:13:14 -0800131fold_tuple_on_constants(_Py_CODEUNIT *codestr, Py_ssize_t codelen,
132 Py_ssize_t c_start, Py_ssize_t opcode_end,
133 PyObject *consts, int n)
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000134{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000135 /* Pre-conditions */
136 assert(PyList_CheckExact(consts));
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000137
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000138 /* Buildup new tuple of constants */
INADA Naoki87010e82017-12-18 15:52:54 +0900139 PyObject *newconst = PyTuple_New(n);
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300140 if (newconst == NULL) {
141 return -1;
142 }
INADA Naoki87010e82017-12-18 15:52:54 +0900143
144 for (Py_ssize_t i = 0, pos = c_start; i < n; i++, pos++) {
145 assert(pos < opcode_end);
Miss Islington (bot)f16ebcd2018-11-08 18:13:14 -0800146 pos = find_op(codestr, codelen, pos);
INADA Naoki87010e82017-12-18 15:52:54 +0900147 assert(_Py_OPCODE(codestr[pos]) == LOAD_CONST);
148
149 unsigned int arg = get_arg(codestr, pos);
150 PyObject *constant = PyList_GET_ITEM(consts, arg);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000151 Py_INCREF(constant);
152 PyTuple_SET_ITEM(newconst, i, constant);
153 }
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000154
Victor Stinner8a9a6b42019-04-23 10:26:11 +0200155 Py_ssize_t index = PyList_GET_SIZE(consts);
156#if SIZEOF_SIZE_T > SIZEOF_INT
157 if ((size_t)index >= UINT_MAX - 1) {
158 Py_DECREF(newconst);
159 PyErr_SetString(PyExc_OverflowError, "too many constants");
160 return -1;
161 }
162#endif
163
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000164 /* Append folded constant onto consts */
165 if (PyList_Append(consts, newconst)) {
166 Py_DECREF(newconst);
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300167 return -1;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000168 }
169 Py_DECREF(newconst);
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000170
INADA Naoki87010e82017-12-18 15:52:54 +0900171 return copy_op_arg(codestr, c_start, LOAD_CONST,
Victor Stinner8a9a6b42019-04-23 10:26:11 +0200172 (unsigned int)index, opcode_end);
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000173}
174
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000175static unsigned int *
Serhiy Storchakaab874002016-09-11 13:48:15 +0300176markblocks(_Py_CODEUNIT *code, Py_ssize_t len)
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000177{
Serhiy Storchaka1a1ff292015-02-16 13:28:22 +0200178 unsigned int *blocks = PyMem_New(unsigned int, len);
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300179 int i, j, opcode, blockcnt = 0;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000180
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000181 if (blocks == NULL) {
182 PyErr_NoMemory();
183 return NULL;
184 }
185 memset(blocks, 0, len*sizeof(int));
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000186
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000187 /* Mark labels in the first pass */
Serhiy Storchakaab874002016-09-11 13:48:15 +0300188 for (i = 0; i < len; i++) {
189 opcode = _Py_OPCODE(code[i]);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000190 switch (opcode) {
191 case FOR_ITER:
192 case JUMP_FORWARD:
193 case JUMP_IF_FALSE_OR_POP:
194 case JUMP_IF_TRUE_OR_POP:
195 case POP_JUMP_IF_FALSE:
196 case POP_JUMP_IF_TRUE:
197 case JUMP_ABSOLUTE:
198 case CONTINUE_LOOP:
199 case SETUP_LOOP:
200 case SETUP_EXCEPT:
201 case SETUP_FINALLY:
202 case SETUP_WITH:
Yury Selivanov75445082015-05-11 22:57:16 -0400203 case SETUP_ASYNC_WITH:
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000204 j = GETJUMPTGT(code, i);
Serhiy Storchakaab874002016-09-11 13:48:15 +0300205 assert(j < len);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000206 blocks[j] = 1;
207 break;
208 }
209 }
210 /* Build block numbers in the second pass */
Serhiy Storchakaab874002016-09-11 13:48:15 +0300211 for (i = 0; i < len; i++) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000212 blockcnt += blocks[i]; /* increment blockcnt over labels */
213 blocks[i] = blockcnt;
214 }
215 return blocks;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000216}
217
218/* Perform basic peephole optimizations to components of a code object.
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000219 The consts object should still be in list form to allow new constants
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000220 to be appended.
221
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300222 To keep the optimizer simple, it bails when the lineno table has complex
223 encoding for gaps >= 255.
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000224
Martin Panter46f50722016-05-26 05:35:26 +0000225 Optimizations are restricted to simple transformations occurring within a
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000226 single basic block. All transformations keep the code size the same or
227 smaller. For those that reduce size, the gaps are initially filled with
228 NOPs. Later those NOPs are removed and the jump addresses retargeted in
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300229 a single pass. */
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000230
231PyObject *
232PyCode_Optimize(PyObject *code, PyObject* consts, PyObject *names,
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100233 PyObject *lnotab_obj)
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000234{
Victor Stinner8a9a6b42019-04-23 10:26:11 +0200235 Py_ssize_t h, i, nexti, op_start, tgt;
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300236 unsigned int j, nops;
237 unsigned char opcode, nextop;
Serhiy Storchakaab874002016-09-11 13:48:15 +0300238 _Py_CODEUNIT *codestr = NULL;
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100239 unsigned char *lnotab;
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300240 unsigned int cum_orig_offset, last_offset;
Serhiy Storchaka67559bf2015-02-16 21:13:24 +0200241 Py_ssize_t tabsiz;
INADA Naoki87010e82017-12-18 15:52:54 +0900242 // Count runs of consecutive LOAD_CONSTs
243 unsigned int cumlc = 0, lastlc = 0;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000244 unsigned int *blocks = NULL;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000245
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000246 /* Bail out if an exception is set */
247 if (PyErr_Occurred())
248 goto exitError;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000249
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100250 /* Bypass optimization when the lnotab table is too complex */
251 assert(PyBytes_Check(lnotab_obj));
252 lnotab = (unsigned char*)PyBytes_AS_STRING(lnotab_obj);
253 tabsiz = PyBytes_GET_SIZE(lnotab_obj);
254 assert(tabsiz == 0 || Py_REFCNT(lnotab_obj) == 1);
255 if (memchr(lnotab, 255, tabsiz) != NULL) {
256 /* 255 value are used for multibyte bytecode instructions */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000257 goto exitUnchanged;
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100258 }
259 /* Note: -128 and 127 special values for line number delta are ok,
260 the peephole optimizer doesn't modify line numbers. */
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000261
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000262 assert(PyBytes_Check(code));
Victor Stinner8a9a6b42019-04-23 10:26:11 +0200263 Py_ssize_t codesize = PyBytes_GET_SIZE(code);
264 assert(codesize % sizeof(_Py_CODEUNIT) == 0);
265 Py_ssize_t codelen = codesize / sizeof(_Py_CODEUNIT);
266 if (codelen > INT_MAX) {
267 /* Python assembler is limited to INT_MAX: see assembler.a_offset in
268 compile.c. */
269 goto exitUnchanged;
270 }
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000271
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000272 /* Make a modifiable copy of the code string */
Victor Stinner8a9a6b42019-04-23 10:26:11 +0200273 codestr = (_Py_CODEUNIT *)PyMem_Malloc(codesize);
Victor Stinnere0af3a82013-07-09 00:32:04 +0200274 if (codestr == NULL) {
275 PyErr_NoMemory();
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000276 goto exitError;
Victor Stinnere0af3a82013-07-09 00:32:04 +0200277 }
Victor Stinner8a9a6b42019-04-23 10:26:11 +0200278 memcpy(codestr, PyBytes_AS_STRING(code), codesize);
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000279
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000280 blocks = markblocks(codestr, codelen);
281 if (blocks == NULL)
282 goto exitError;
283 assert(PyList_Check(consts));
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000284
Miss Islington (bot)f16ebcd2018-11-08 18:13:14 -0800285 for (i=find_op(codestr, codelen, 0) ; i<codelen ; i=nexti) {
Serhiy Storchakaa1e9ab32016-09-11 15:19:12 +0300286 opcode = _Py_OPCODE(codestr[i]);
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300287 op_start = i;
Serhiy Storchakaab874002016-09-11 13:48:15 +0300288 while (op_start >= 1 && _Py_OPCODE(codestr[op_start-1]) == EXTENDED_ARG) {
289 op_start--;
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300290 }
291
Serhiy Storchakaab874002016-09-11 13:48:15 +0300292 nexti = i + 1;
293 while (nexti < codelen && _Py_OPCODE(codestr[nexti]) == EXTENDED_ARG)
294 nexti++;
295 nextop = nexti < codelen ? _Py_OPCODE(codestr[nexti]) : 0;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000296
INADA Naoki87010e82017-12-18 15:52:54 +0900297 lastlc = cumlc;
298 cumlc = 0;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000299
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000300 switch (opcode) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000301 /* Skip over LOAD_CONST trueconst
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300302 POP_JUMP_IF_FALSE xx. This improves
303 "while 1" performance. */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000304 case LOAD_CONST:
INADA Naoki87010e82017-12-18 15:52:54 +0900305 cumlc = lastlc + 1;
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300306 if (nextop != POP_JUMP_IF_FALSE ||
Serhiy Storchakaab874002016-09-11 13:48:15 +0300307 !ISBASICBLOCK(blocks, op_start, i + 1) ||
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300308 !PyObject_IsTrue(PyList_GET_ITEM(consts, get_arg(codestr, i))))
309 break;
Serhiy Storchakaab874002016-09-11 13:48:15 +0300310 fill_nops(codestr, op_start, nexti + 1);
INADA Naoki87010e82017-12-18 15:52:54 +0900311 cumlc = 0;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000312 break;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000313
Serhiy Storchaka15a87282017-12-14 20:24:31 +0200314 /* Try to fold tuples of constants.
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000315 Skip over BUILD_SEQN 1 UNPACK_SEQN 1.
316 Replace BUILD_SEQN 2 UNPACK_SEQN 2 with ROT2.
317 Replace BUILD_SEQN 3 UNPACK_SEQN 3 with ROT3 ROT2. */
318 case BUILD_TUPLE:
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300319 j = get_arg(codestr, i);
INADA Naoki87010e82017-12-18 15:52:54 +0900320 if (j > 0 && lastlc >= j) {
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300321 h = lastn_const_start(codestr, op_start, j);
Serhiy Storchaka15a87282017-12-14 20:24:31 +0200322 if (ISBASICBLOCK(blocks, h, op_start)) {
Miss Islington (bot)f16ebcd2018-11-08 18:13:14 -0800323 h = fold_tuple_on_constants(codestr, codelen,
324 h, i+1, consts, j);
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300325 break;
326 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000327 }
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300328 if (nextop != UNPACK_SEQUENCE ||
Serhiy Storchakaab874002016-09-11 13:48:15 +0300329 !ISBASICBLOCK(blocks, op_start, i + 1) ||
Serhiy Storchaka15a87282017-12-14 20:24:31 +0200330 j != get_arg(codestr, nexti))
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300331 break;
332 if (j < 2) {
Serhiy Storchakaab874002016-09-11 13:48:15 +0300333 fill_nops(codestr, op_start, nexti + 1);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000334 } else if (j == 2) {
Serhiy Storchakaab874002016-09-11 13:48:15 +0300335 codestr[op_start] = PACKOPARG(ROT_TWO, 0);
336 fill_nops(codestr, op_start + 1, nexti + 1);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000337 } else if (j == 3) {
Serhiy Storchakaab874002016-09-11 13:48:15 +0300338 codestr[op_start] = PACKOPARG(ROT_THREE, 0);
339 codestr[op_start + 1] = PACKOPARG(ROT_TWO, 0);
340 fill_nops(codestr, op_start + 2, nexti + 1);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000341 }
342 break;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000343
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000344 /* Simplify conditional jump to conditional jump where the
345 result of the first test implies the success of a similar
346 test or the failure of the opposite test.
347 Arises in code like:
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000348 "a and b or c"
349 "(a and b) and c"
Serhiy Storchaka36ff4512017-06-11 14:50:22 +0300350 "(a or b) or c"
351 "(a or b) and c"
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000352 x:JUMP_IF_FALSE_OR_POP y y:JUMP_IF_FALSE_OR_POP z
353 --> x:JUMP_IF_FALSE_OR_POP z
354 x:JUMP_IF_FALSE_OR_POP y y:JUMP_IF_TRUE_OR_POP z
Serhiy Storchakaab874002016-09-11 13:48:15 +0300355 --> x:POP_JUMP_IF_FALSE y+1
356 where y+1 is the instruction following the second test.
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000357 */
358 case JUMP_IF_FALSE_OR_POP:
359 case JUMP_IF_TRUE_OR_POP:
Serhiy Storchakaab874002016-09-11 13:48:15 +0300360 h = get_arg(codestr, i) / sizeof(_Py_CODEUNIT);
Miss Islington (bot)f16ebcd2018-11-08 18:13:14 -0800361 tgt = find_op(codestr, codelen, h);
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300362
Serhiy Storchakaab874002016-09-11 13:48:15 +0300363 j = _Py_OPCODE(codestr[tgt]);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000364 if (CONDITIONAL_JUMP(j)) {
Raymond Hettinger08eef3f2016-08-07 20:20:33 -0700365 /* NOTE: all possible jumps here are absolute. */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000366 if (JUMPS_ON_TRUE(j) == JUMPS_ON_TRUE(opcode)) {
Raymond Hettinger08eef3f2016-08-07 20:20:33 -0700367 /* The second jump will be taken iff the first is.
368 The current opcode inherits its target's
369 stack effect */
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300370 h = set_arg(codestr, i, get_arg(codestr, tgt));
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000371 } else {
Raymond Hettinger08eef3f2016-08-07 20:20:33 -0700372 /* The second jump is not taken if the first is (so
373 jump past it), and all conditional jumps pop their
374 argument when they're not taken (so change the
375 first jump to pop its argument when it's taken). */
Victor Stinner8a9a6b42019-04-23 10:26:11 +0200376 Py_ssize_t arg = (tgt + 1);
377 /* cannot overflow: codelen <= INT_MAX */
378 assert((size_t)arg <= UINT_MAX / sizeof(_Py_CODEUNIT));
379 arg *= sizeof(_Py_CODEUNIT);
380 h = set_arg(codestr, i, (unsigned int)arg);
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300381 j = opcode == JUMP_IF_TRUE_OR_POP ?
382 POP_JUMP_IF_TRUE : POP_JUMP_IF_FALSE;
383 }
384
385 if (h >= 0) {
386 nexti = h;
Serhiy Storchakaab874002016-09-11 13:48:15 +0300387 codestr[nexti] = PACKOPARG(j, _Py_OPARG(codestr[nexti]));
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300388 break;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000389 }
390 }
391 /* Intentional fallthrough */
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000392
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000393 /* Replace jumps to unconditional jumps */
394 case POP_JUMP_IF_FALSE:
395 case POP_JUMP_IF_TRUE:
396 case FOR_ITER:
397 case JUMP_FORWARD:
398 case JUMP_ABSOLUTE:
399 case CONTINUE_LOOP:
400 case SETUP_LOOP:
401 case SETUP_EXCEPT:
402 case SETUP_FINALLY:
403 case SETUP_WITH:
Yury Selivanov75445082015-05-11 22:57:16 -0400404 case SETUP_ASYNC_WITH:
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300405 h = GETJUMPTGT(codestr, i);
Miss Islington (bot)f16ebcd2018-11-08 18:13:14 -0800406 tgt = find_op(codestr, codelen, h);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000407 /* Replace JUMP_* to a RETURN into just a RETURN */
408 if (UNCONDITIONAL_JUMP(opcode) &&
Serhiy Storchakaab874002016-09-11 13:48:15 +0300409 _Py_OPCODE(codestr[tgt]) == RETURN_VALUE) {
410 codestr[op_start] = PACKOPARG(RETURN_VALUE, 0);
411 fill_nops(codestr, op_start + 1, i + 1);
412 } else if (UNCONDITIONAL_JUMP(_Py_OPCODE(codestr[tgt]))) {
Victor Stinner8a9a6b42019-04-23 10:26:11 +0200413 size_t arg = GETJUMPTGT(codestr, tgt);
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300414 if (opcode == JUMP_FORWARD) { /* JMP_ABS can go backwards */
415 opcode = JUMP_ABSOLUTE;
416 } else if (!ABSOLUTE_JUMP(opcode)) {
Victor Stinner8a9a6b42019-04-23 10:26:11 +0200417 if (arg < (size_t)(i + 1)) {
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300418 break; /* No backward relative jumps */
419 }
Victor Stinner8a9a6b42019-04-23 10:26:11 +0200420 arg -= i + 1; /* Calc relative jump addr */
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300421 }
Victor Stinner8a9a6b42019-04-23 10:26:11 +0200422 /* cannot overflow: codelen <= INT_MAX */
423 assert(arg <= (UINT_MAX / sizeof(_Py_CODEUNIT)));
424 arg *= sizeof(_Py_CODEUNIT);
425 copy_op_arg(codestr, op_start, opcode,
426 (unsigned int)arg, i + 1);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000427 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000428 break;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000429
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300430 /* Remove unreachable ops after RETURN */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000431 case RETURN_VALUE:
Serhiy Storchakaab874002016-09-11 13:48:15 +0300432 h = i + 1;
Serhiy Storchaka7db3c482016-10-25 09:30:43 +0300433 while (h < codelen && ISBASICBLOCK(blocks, i, h)) {
Serhiy Storchakaab874002016-09-11 13:48:15 +0300434 h++;
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300435 }
Serhiy Storchakaab874002016-09-11 13:48:15 +0300436 if (h > i + 1) {
Serhiy Storchaka7db3c482016-10-25 09:30:43 +0300437 fill_nops(codestr, i + 1, h);
Miss Islington (bot)f16ebcd2018-11-08 18:13:14 -0800438 nexti = find_op(codestr, codelen, h);
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300439 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000440 break;
441 }
442 }
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000443
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100444 /* Fixup lnotab */
Serhiy Storchakaab874002016-09-11 13:48:15 +0300445 for (i = 0, nops = 0; i < codelen; i++) {
Victor Stinner8a9a6b42019-04-23 10:26:11 +0200446 size_t block = (size_t)i - nops;
447 /* cannot overflow: codelen <= INT_MAX */
448 assert(block <= UINT_MAX);
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100449 /* original code offset => new code offset */
Victor Stinner8a9a6b42019-04-23 10:26:11 +0200450 blocks[i] = (unsigned int)block;
451 if (_Py_OPCODE(codestr[i]) == NOP) {
Serhiy Storchakaab874002016-09-11 13:48:15 +0300452 nops++;
Victor Stinner8a9a6b42019-04-23 10:26:11 +0200453 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000454 }
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100455 cum_orig_offset = 0;
456 last_offset = 0;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000457 for (i=0 ; i < tabsiz ; i+=2) {
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300458 unsigned int offset_delta, new_offset;
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100459 cum_orig_offset += lnotab[i];
Serhiy Storchakaab874002016-09-11 13:48:15 +0300460 assert(cum_orig_offset % sizeof(_Py_CODEUNIT) == 0);
461 new_offset = blocks[cum_orig_offset / sizeof(_Py_CODEUNIT)] *
462 sizeof(_Py_CODEUNIT);
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100463 offset_delta = new_offset - last_offset;
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300464 assert(offset_delta <= 255);
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100465 lnotab[i] = (unsigned char)offset_delta;
466 last_offset = new_offset;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000467 }
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000468
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000469 /* Remove NOPs and fixup jump targets */
Serhiy Storchakaab874002016-09-11 13:48:15 +0300470 for (op_start = i = h = 0; i < codelen; i++, op_start = i) {
471 j = _Py_OPARG(codestr[i]);
472 while (_Py_OPCODE(codestr[i]) == EXTENDED_ARG) {
473 i++;
474 j = j<<8 | _Py_OPARG(codestr[i]);
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300475 }
Serhiy Storchakaab874002016-09-11 13:48:15 +0300476 opcode = _Py_OPCODE(codestr[i]);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000477 switch (opcode) {
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300478 case NOP:continue;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000479
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000480 case JUMP_ABSOLUTE:
481 case CONTINUE_LOOP:
482 case POP_JUMP_IF_FALSE:
483 case POP_JUMP_IF_TRUE:
484 case JUMP_IF_FALSE_OR_POP:
485 case JUMP_IF_TRUE_OR_POP:
Serhiy Storchakaab874002016-09-11 13:48:15 +0300486 j = blocks[j / sizeof(_Py_CODEUNIT)] * sizeof(_Py_CODEUNIT);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000487 break;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000488
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000489 case FOR_ITER:
490 case JUMP_FORWARD:
491 case SETUP_LOOP:
492 case SETUP_EXCEPT:
493 case SETUP_FINALLY:
494 case SETUP_WITH:
Yury Selivanov75445082015-05-11 22:57:16 -0400495 case SETUP_ASYNC_WITH:
Serhiy Storchakaab874002016-09-11 13:48:15 +0300496 j = blocks[j / sizeof(_Py_CODEUNIT) + i + 1] - blocks[i] - 1;
497 j *= sizeof(_Py_CODEUNIT);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000498 break;
499 }
Victor Stinner8a9a6b42019-04-23 10:26:11 +0200500 Py_ssize_t ilen = i - op_start + 1;
501 if (instrsize(j) > ilen) {
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300502 goto exitUnchanged;
Victor Stinner8a9a6b42019-04-23 10:26:11 +0200503 }
504 assert(ilen <= INT_MAX);
505 /* If instrsize(j) < ilen, we'll emit EXTENDED_ARG 0 */
506 write_op_arg(codestr + h, opcode, j, (int)ilen);
507 h += ilen;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000508 }
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300509 assert(h + (Py_ssize_t)nops == codelen);
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000510
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000511 PyMem_Free(blocks);
Serhiy Storchakaab874002016-09-11 13:48:15 +0300512 code = PyBytes_FromStringAndSize((char *)codestr, h * sizeof(_Py_CODEUNIT));
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300513 PyMem_Free(codestr);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000514 return code;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000515
Alexandre Vassalotti6f828182009-07-21 02:51:58 +0000516 exitError:
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000517 code = NULL;
Alexandre Vassalotti6f828182009-07-21 02:51:58 +0000518
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000519 exitUnchanged:
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300520 Py_XINCREF(code);
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100521 PyMem_Free(blocks);
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100522 PyMem_Free(codestr);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000523 return code;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000524}