blob: 16fd5009bf1d8c8f4d22535a90789bb5d7f6d636 [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)
Serhiy Storchaka520b7ae2018-02-22 23:33:30 +020016#define ABSOLUTE_JUMP(op) (op==JUMP_ABSOLUTE \
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
Serhiy Storchakaab874002016-09-11 13:48:15 +030053find_op(const _Py_CODEUNIT *codestr, Py_ssize_t i)
Serhiy Storchakab0f80b02016-05-24 09:15:14 +030054{
Serhiy Storchakaab874002016-09-11 13:48:15 +030055 while (_Py_OPCODE(codestr[i]) == EXTENDED_ARG) {
56 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
Serhiy Storchakaab874002016-09-11 13:48:15 +0300131fold_tuple_on_constants(_Py_CODEUNIT *codestr, Py_ssize_t c_start,
INADA Naoki87010e82017-12-18 15:52:54 +0900132 Py_ssize_t opcode_end, PyObject *consts, int n)
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000133{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000134 /* Pre-conditions */
135 assert(PyList_CheckExact(consts));
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000136
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000137 /* Buildup new tuple of constants */
INADA Naoki87010e82017-12-18 15:52:54 +0900138 PyObject *newconst = PyTuple_New(n);
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300139 if (newconst == NULL) {
140 return -1;
141 }
INADA Naoki87010e82017-12-18 15:52:54 +0900142
143 for (Py_ssize_t i = 0, pos = c_start; i < n; i++, pos++) {
144 assert(pos < opcode_end);
145 pos = find_op(codestr, pos);
146 assert(_Py_OPCODE(codestr[pos]) == LOAD_CONST);
147
148 unsigned int arg = get_arg(codestr, pos);
149 PyObject *constant = PyList_GET_ITEM(consts, arg);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000150 Py_INCREF(constant);
151 PyTuple_SET_ITEM(newconst, i, constant);
152 }
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000153
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000154 /* Append folded constant onto consts */
155 if (PyList_Append(consts, newconst)) {
156 Py_DECREF(newconst);
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300157 return -1;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000158 }
159 Py_DECREF(newconst);
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000160
INADA Naoki87010e82017-12-18 15:52:54 +0900161 return copy_op_arg(codestr, c_start, LOAD_CONST,
162 PyList_GET_SIZE(consts)-1, opcode_end);
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000163}
164
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000165static unsigned int *
Serhiy Storchakaab874002016-09-11 13:48:15 +0300166markblocks(_Py_CODEUNIT *code, Py_ssize_t len)
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000167{
Serhiy Storchaka1a1ff292015-02-16 13:28:22 +0200168 unsigned int *blocks = PyMem_New(unsigned int, len);
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300169 int i, j, opcode, blockcnt = 0;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000170
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000171 if (blocks == NULL) {
172 PyErr_NoMemory();
173 return NULL;
174 }
175 memset(blocks, 0, len*sizeof(int));
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000176
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000177 /* Mark labels in the first pass */
Serhiy Storchakaab874002016-09-11 13:48:15 +0300178 for (i = 0; i < len; i++) {
179 opcode = _Py_OPCODE(code[i]);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000180 switch (opcode) {
181 case FOR_ITER:
182 case JUMP_FORWARD:
183 case JUMP_IF_FALSE_OR_POP:
184 case JUMP_IF_TRUE_OR_POP:
185 case POP_JUMP_IF_FALSE:
186 case POP_JUMP_IF_TRUE:
187 case JUMP_ABSOLUTE:
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000188 case SETUP_FINALLY:
189 case SETUP_WITH:
Yury Selivanov75445082015-05-11 22:57:16 -0400190 case SETUP_ASYNC_WITH:
Serhiy Storchaka520b7ae2018-02-22 23:33:30 +0200191 case CALL_FINALLY:
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000192 j = GETJUMPTGT(code, i);
Serhiy Storchakaab874002016-09-11 13:48:15 +0300193 assert(j < len);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000194 blocks[j] = 1;
195 break;
196 }
197 }
198 /* Build block numbers in the second pass */
Serhiy Storchakaab874002016-09-11 13:48:15 +0300199 for (i = 0; i < len; i++) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000200 blockcnt += blocks[i]; /* increment blockcnt over labels */
201 blocks[i] = blockcnt;
202 }
203 return blocks;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000204}
205
206/* Perform basic peephole optimizations to components of a code object.
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000207 The consts object should still be in list form to allow new constants
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000208 to be appended.
209
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300210 To keep the optimizer simple, it bails when the lineno table has complex
211 encoding for gaps >= 255.
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000212
Martin Panter46f50722016-05-26 05:35:26 +0000213 Optimizations are restricted to simple transformations occurring within a
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000214 single basic block. All transformations keep the code size the same or
215 smaller. For those that reduce size, the gaps are initially filled with
216 NOPs. Later those NOPs are removed and the jump addresses retargeted in
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300217 a single pass. */
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000218
219PyObject *
220PyCode_Optimize(PyObject *code, PyObject* consts, PyObject *names,
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100221 PyObject *lnotab_obj)
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000222{
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300223 Py_ssize_t h, i, nexti, op_start, codelen, tgt;
224 unsigned int j, nops;
225 unsigned char opcode, nextop;
Serhiy Storchakaab874002016-09-11 13:48:15 +0300226 _Py_CODEUNIT *codestr = NULL;
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100227 unsigned char *lnotab;
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300228 unsigned int cum_orig_offset, last_offset;
Serhiy Storchaka67559bf2015-02-16 21:13:24 +0200229 Py_ssize_t tabsiz;
INADA Naoki87010e82017-12-18 15:52:54 +0900230 // Count runs of consecutive LOAD_CONSTs
231 unsigned int cumlc = 0, lastlc = 0;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000232 unsigned int *blocks = NULL;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000233
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000234 /* Bail out if an exception is set */
235 if (PyErr_Occurred())
236 goto exitError;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000237
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100238 /* Bypass optimization when the lnotab table is too complex */
239 assert(PyBytes_Check(lnotab_obj));
240 lnotab = (unsigned char*)PyBytes_AS_STRING(lnotab_obj);
241 tabsiz = PyBytes_GET_SIZE(lnotab_obj);
242 assert(tabsiz == 0 || Py_REFCNT(lnotab_obj) == 1);
243 if (memchr(lnotab, 255, tabsiz) != NULL) {
244 /* 255 value are used for multibyte bytecode instructions */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000245 goto exitUnchanged;
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100246 }
247 /* Note: -128 and 127 special values for line number delta are ok,
248 the peephole optimizer doesn't modify line numbers. */
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000249
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000250 assert(PyBytes_Check(code));
251 codelen = PyBytes_GET_SIZE(code);
Serhiy Storchakaab874002016-09-11 13:48:15 +0300252 assert(codelen % sizeof(_Py_CODEUNIT) == 0);
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000253
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000254 /* Make a modifiable copy of the code string */
Serhiy Storchakaab874002016-09-11 13:48:15 +0300255 codestr = (_Py_CODEUNIT *)PyMem_Malloc(codelen);
Victor Stinnere0af3a82013-07-09 00:32:04 +0200256 if (codestr == NULL) {
257 PyErr_NoMemory();
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000258 goto exitError;
Victor Stinnere0af3a82013-07-09 00:32:04 +0200259 }
Serhiy Storchakaab874002016-09-11 13:48:15 +0300260 memcpy(codestr, PyBytes_AS_STRING(code), codelen);
261 codelen /= sizeof(_Py_CODEUNIT);
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000262
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000263 blocks = markblocks(codestr, codelen);
264 if (blocks == NULL)
265 goto exitError;
266 assert(PyList_Check(consts));
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000267
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300268 for (i=find_op(codestr, 0) ; i<codelen ; i=nexti) {
Serhiy Storchakaa1e9ab32016-09-11 15:19:12 +0300269 opcode = _Py_OPCODE(codestr[i]);
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300270 op_start = i;
Serhiy Storchakaab874002016-09-11 13:48:15 +0300271 while (op_start >= 1 && _Py_OPCODE(codestr[op_start-1]) == EXTENDED_ARG) {
272 op_start--;
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300273 }
274
Serhiy Storchakaab874002016-09-11 13:48:15 +0300275 nexti = i + 1;
276 while (nexti < codelen && _Py_OPCODE(codestr[nexti]) == EXTENDED_ARG)
277 nexti++;
278 nextop = nexti < codelen ? _Py_OPCODE(codestr[nexti]) : 0;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000279
INADA Naoki87010e82017-12-18 15:52:54 +0900280 lastlc = cumlc;
281 cumlc = 0;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000282
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000283 switch (opcode) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000284 /* Skip over LOAD_CONST trueconst
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300285 POP_JUMP_IF_FALSE xx. This improves
286 "while 1" performance. */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000287 case LOAD_CONST:
INADA Naoki87010e82017-12-18 15:52:54 +0900288 cumlc = lastlc + 1;
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300289 if (nextop != POP_JUMP_IF_FALSE ||
Serhiy Storchakaab874002016-09-11 13:48:15 +0300290 !ISBASICBLOCK(blocks, op_start, i + 1) ||
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300291 !PyObject_IsTrue(PyList_GET_ITEM(consts, get_arg(codestr, i))))
292 break;
Serhiy Storchakaab874002016-09-11 13:48:15 +0300293 fill_nops(codestr, op_start, nexti + 1);
INADA Naoki87010e82017-12-18 15:52:54 +0900294 cumlc = 0;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000295 break;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000296
Serhiy Storchaka15a87282017-12-14 20:24:31 +0200297 /* Try to fold tuples of constants.
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000298 Skip over BUILD_SEQN 1 UNPACK_SEQN 1.
299 Replace BUILD_SEQN 2 UNPACK_SEQN 2 with ROT2.
300 Replace BUILD_SEQN 3 UNPACK_SEQN 3 with ROT3 ROT2. */
301 case BUILD_TUPLE:
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300302 j = get_arg(codestr, i);
INADA Naoki87010e82017-12-18 15:52:54 +0900303 if (j > 0 && lastlc >= j) {
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300304 h = lastn_const_start(codestr, op_start, j);
Serhiy Storchaka15a87282017-12-14 20:24:31 +0200305 if (ISBASICBLOCK(blocks, h, op_start)) {
INADA Naoki87010e82017-12-18 15:52:54 +0900306 h = fold_tuple_on_constants(codestr, h, i+1, consts, j);
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300307 break;
308 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000309 }
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300310 if (nextop != UNPACK_SEQUENCE ||
Serhiy Storchakaab874002016-09-11 13:48:15 +0300311 !ISBASICBLOCK(blocks, op_start, i + 1) ||
Serhiy Storchaka15a87282017-12-14 20:24:31 +0200312 j != get_arg(codestr, nexti))
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300313 break;
314 if (j < 2) {
Serhiy Storchakaab874002016-09-11 13:48:15 +0300315 fill_nops(codestr, op_start, nexti + 1);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000316 } else if (j == 2) {
Serhiy Storchakaab874002016-09-11 13:48:15 +0300317 codestr[op_start] = PACKOPARG(ROT_TWO, 0);
318 fill_nops(codestr, op_start + 1, nexti + 1);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000319 } else if (j == 3) {
Serhiy Storchakaab874002016-09-11 13:48:15 +0300320 codestr[op_start] = PACKOPARG(ROT_THREE, 0);
321 codestr[op_start + 1] = PACKOPARG(ROT_TWO, 0);
322 fill_nops(codestr, op_start + 2, nexti + 1);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000323 }
324 break;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000325
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000326 /* Simplify conditional jump to conditional jump where the
327 result of the first test implies the success of a similar
328 test or the failure of the opposite test.
329 Arises in code like:
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000330 "a and b or c"
331 "(a and b) and c"
Serhiy Storchaka36ff4512017-06-11 14:50:22 +0300332 "(a or b) or c"
333 "(a or b) and c"
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000334 x:JUMP_IF_FALSE_OR_POP y y:JUMP_IF_FALSE_OR_POP z
335 --> x:JUMP_IF_FALSE_OR_POP z
336 x:JUMP_IF_FALSE_OR_POP y y:JUMP_IF_TRUE_OR_POP z
Serhiy Storchakaab874002016-09-11 13:48:15 +0300337 --> x:POP_JUMP_IF_FALSE y+1
338 where y+1 is the instruction following the second test.
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000339 */
340 case JUMP_IF_FALSE_OR_POP:
341 case JUMP_IF_TRUE_OR_POP:
Serhiy Storchakaab874002016-09-11 13:48:15 +0300342 h = get_arg(codestr, i) / sizeof(_Py_CODEUNIT);
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300343 tgt = find_op(codestr, h);
344
Serhiy Storchakaab874002016-09-11 13:48:15 +0300345 j = _Py_OPCODE(codestr[tgt]);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000346 if (CONDITIONAL_JUMP(j)) {
Raymond Hettinger08eef3f2016-08-07 20:20:33 -0700347 /* NOTE: all possible jumps here are absolute. */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000348 if (JUMPS_ON_TRUE(j) == JUMPS_ON_TRUE(opcode)) {
Raymond Hettinger08eef3f2016-08-07 20:20:33 -0700349 /* The second jump will be taken iff the first is.
350 The current opcode inherits its target's
351 stack effect */
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300352 h = set_arg(codestr, i, get_arg(codestr, tgt));
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000353 } else {
Raymond Hettinger08eef3f2016-08-07 20:20:33 -0700354 /* The second jump is not taken if the first is (so
355 jump past it), and all conditional jumps pop their
356 argument when they're not taken (so change the
357 first jump to pop its argument when it's taken). */
Serhiy Storchakaab874002016-09-11 13:48:15 +0300358 h = set_arg(codestr, i, (tgt + 1) * sizeof(_Py_CODEUNIT));
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300359 j = opcode == JUMP_IF_TRUE_OR_POP ?
360 POP_JUMP_IF_TRUE : POP_JUMP_IF_FALSE;
361 }
362
363 if (h >= 0) {
364 nexti = h;
Serhiy Storchakaab874002016-09-11 13:48:15 +0300365 codestr[nexti] = PACKOPARG(j, _Py_OPARG(codestr[nexti]));
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300366 break;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000367 }
368 }
369 /* Intentional fallthrough */
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000370
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000371 /* Replace jumps to unconditional jumps */
372 case POP_JUMP_IF_FALSE:
373 case POP_JUMP_IF_TRUE:
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000374 case JUMP_FORWARD:
375 case JUMP_ABSOLUTE:
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300376 h = GETJUMPTGT(codestr, i);
377 tgt = find_op(codestr, h);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000378 /* Replace JUMP_* to a RETURN into just a RETURN */
379 if (UNCONDITIONAL_JUMP(opcode) &&
Serhiy Storchakaab874002016-09-11 13:48:15 +0300380 _Py_OPCODE(codestr[tgt]) == RETURN_VALUE) {
381 codestr[op_start] = PACKOPARG(RETURN_VALUE, 0);
382 fill_nops(codestr, op_start + 1, i + 1);
383 } else if (UNCONDITIONAL_JUMP(_Py_OPCODE(codestr[tgt]))) {
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300384 j = GETJUMPTGT(codestr, tgt);
385 if (opcode == JUMP_FORWARD) { /* JMP_ABS can go backwards */
386 opcode = JUMP_ABSOLUTE;
387 } else if (!ABSOLUTE_JUMP(opcode)) {
Serhiy Storchakaab874002016-09-11 13:48:15 +0300388 if ((Py_ssize_t)j < i + 1) {
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300389 break; /* No backward relative jumps */
390 }
Serhiy Storchakaab874002016-09-11 13:48:15 +0300391 j -= i + 1; /* Calc relative jump addr */
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300392 }
Serhiy Storchakaab874002016-09-11 13:48:15 +0300393 j *= sizeof(_Py_CODEUNIT);
394 copy_op_arg(codestr, op_start, opcode, j, i + 1);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000395 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000396 break;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000397
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300398 /* Remove unreachable ops after RETURN */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000399 case RETURN_VALUE:
Serhiy Storchakaab874002016-09-11 13:48:15 +0300400 h = i + 1;
Serhiy Storchaka520b7ae2018-02-22 23:33:30 +0200401 /* END_FINALLY should be kept since it denotes the end of
402 the 'finally' block in frame_setlineno() in frameobject.c.
403 SETUP_FINALLY should be kept for balancing.
404 */
405 while (h < codelen && ISBASICBLOCK(blocks, i, h) &&
406 _Py_OPCODE(codestr[h]) != END_FINALLY)
407 {
408 if (_Py_OPCODE(codestr[h]) == SETUP_FINALLY) {
409 while (h > i + 1 &&
410 _Py_OPCODE(codestr[h - 1]) == EXTENDED_ARG)
411 {
412 h--;
413 }
414 break;
415 }
Serhiy Storchakaab874002016-09-11 13:48:15 +0300416 h++;
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300417 }
Serhiy Storchakaab874002016-09-11 13:48:15 +0300418 if (h > i + 1) {
Serhiy Storchaka7db3c482016-10-25 09:30:43 +0300419 fill_nops(codestr, i + 1, h);
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300420 nexti = find_op(codestr, h);
421 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000422 break;
423 }
424 }
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000425
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100426 /* Fixup lnotab */
Serhiy Storchakaab874002016-09-11 13:48:15 +0300427 for (i = 0, nops = 0; i < codelen; i++) {
Serhiy Storchaka67559bf2015-02-16 21:13:24 +0200428 assert(i - nops <= INT_MAX);
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100429 /* original code offset => new code offset */
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300430 blocks[i] = i - nops;
Serhiy Storchakaab874002016-09-11 13:48:15 +0300431 if (_Py_OPCODE(codestr[i]) == NOP)
432 nops++;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000433 }
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100434 cum_orig_offset = 0;
435 last_offset = 0;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000436 for (i=0 ; i < tabsiz ; i+=2) {
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300437 unsigned int offset_delta, new_offset;
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100438 cum_orig_offset += lnotab[i];
Serhiy Storchakaab874002016-09-11 13:48:15 +0300439 assert(cum_orig_offset % sizeof(_Py_CODEUNIT) == 0);
440 new_offset = blocks[cum_orig_offset / sizeof(_Py_CODEUNIT)] *
441 sizeof(_Py_CODEUNIT);
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100442 offset_delta = new_offset - last_offset;
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300443 assert(offset_delta <= 255);
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100444 lnotab[i] = (unsigned char)offset_delta;
445 last_offset = new_offset;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000446 }
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000447
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000448 /* Remove NOPs and fixup jump targets */
Serhiy Storchakaab874002016-09-11 13:48:15 +0300449 for (op_start = i = h = 0; i < codelen; i++, op_start = i) {
450 j = _Py_OPARG(codestr[i]);
451 while (_Py_OPCODE(codestr[i]) == EXTENDED_ARG) {
452 i++;
453 j = j<<8 | _Py_OPARG(codestr[i]);
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300454 }
Serhiy Storchakaab874002016-09-11 13:48:15 +0300455 opcode = _Py_OPCODE(codestr[i]);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000456 switch (opcode) {
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300457 case NOP:continue;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000458
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000459 case JUMP_ABSOLUTE:
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000460 case POP_JUMP_IF_FALSE:
461 case POP_JUMP_IF_TRUE:
462 case JUMP_IF_FALSE_OR_POP:
463 case JUMP_IF_TRUE_OR_POP:
Serhiy Storchakaab874002016-09-11 13:48:15 +0300464 j = blocks[j / sizeof(_Py_CODEUNIT)] * sizeof(_Py_CODEUNIT);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000465 break;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000466
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000467 case FOR_ITER:
468 case JUMP_FORWARD:
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000469 case SETUP_FINALLY:
470 case SETUP_WITH:
Yury Selivanov75445082015-05-11 22:57:16 -0400471 case SETUP_ASYNC_WITH:
Serhiy Storchaka520b7ae2018-02-22 23:33:30 +0200472 case CALL_FINALLY:
Serhiy Storchakaab874002016-09-11 13:48:15 +0300473 j = blocks[j / sizeof(_Py_CODEUNIT) + i + 1] - blocks[i] - 1;
474 j *= sizeof(_Py_CODEUNIT);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000475 break;
476 }
Serhiy Storchakaab874002016-09-11 13:48:15 +0300477 nexti = i - op_start + 1;
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300478 if (instrsize(j) > nexti)
479 goto exitUnchanged;
480 /* If instrsize(j) < nexti, we'll emit EXTENDED_ARG 0 */
481 write_op_arg(codestr + h, opcode, j, nexti);
482 h += nexti;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000483 }
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300484 assert(h + (Py_ssize_t)nops == codelen);
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000485
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000486 PyMem_Free(blocks);
Serhiy Storchakaab874002016-09-11 13:48:15 +0300487 code = PyBytes_FromStringAndSize((char *)codestr, h * sizeof(_Py_CODEUNIT));
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300488 PyMem_Free(codestr);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000489 return code;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000490
Alexandre Vassalotti6f828182009-07-21 02:51:58 +0000491 exitError:
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000492 code = NULL;
Alexandre Vassalotti6f828182009-07-21 02:51:58 +0000493
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000494 exitUnchanged:
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300495 Py_XINCREF(code);
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100496 PyMem_Free(blocks);
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100497 PyMem_Free(codestr);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000498 return code;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000499}