blob: d7b1dfc4d9c1419d2b1fbd8d59bdeded5d9b7f56 [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
Gregory P. Smith49fa4a92018-11-08 17:55:07 -080053find_op(const _Py_CODEUNIT *codestr, Py_ssize_t codelen, Py_ssize_t i)
Serhiy Storchakab0f80b02016-05-24 09:15:14 +030054{
Gregory P. Smith49fa4a92018-11-08 17:55:07 -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
Gregory P. Smith49fa4a92018-11-08 17:55:07 -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);
Gregory P. Smith49fa4a92018-11-08 17:55:07 -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 Stinner028f0ef2018-12-07 17:54:18 +0100155 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 Stinner028f0ef2018-12-07 17:54:18 +0100172 (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:
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000198 case SETUP_FINALLY:
199 case SETUP_WITH:
Yury Selivanov75445082015-05-11 22:57:16 -0400200 case SETUP_ASYNC_WITH:
Serhiy Storchaka520b7ae2018-02-22 23:33:30 +0200201 case CALL_FINALLY:
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000202 j = GETJUMPTGT(code, i);
Serhiy Storchakaab874002016-09-11 13:48:15 +0300203 assert(j < len);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000204 blocks[j] = 1;
205 break;
206 }
207 }
208 /* Build block numbers in the second pass */
Serhiy Storchakaab874002016-09-11 13:48:15 +0300209 for (i = 0; i < len; i++) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000210 blockcnt += blocks[i]; /* increment blockcnt over labels */
211 blocks[i] = blockcnt;
212 }
213 return blocks;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000214}
215
216/* Perform basic peephole optimizations to components of a code object.
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000217 The consts object should still be in list form to allow new constants
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000218 to be appended.
219
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300220 To keep the optimizer simple, it bails when the lineno table has complex
221 encoding for gaps >= 255.
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000222
Martin Panter46f50722016-05-26 05:35:26 +0000223 Optimizations are restricted to simple transformations occurring within a
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000224 single basic block. All transformations keep the code size the same or
225 smaller. For those that reduce size, the gaps are initially filled with
226 NOPs. Later those NOPs are removed and the jump addresses retargeted in
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300227 a single pass. */
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000228
229PyObject *
230PyCode_Optimize(PyObject *code, PyObject* consts, PyObject *names,
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100231 PyObject *lnotab_obj)
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000232{
Victor Stinner028f0ef2018-12-07 17:54:18 +0100233 Py_ssize_t h, i, nexti, op_start, tgt;
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300234 unsigned int j, nops;
235 unsigned char opcode, nextop;
Serhiy Storchakaab874002016-09-11 13:48:15 +0300236 _Py_CODEUNIT *codestr = NULL;
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100237 unsigned char *lnotab;
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300238 unsigned int cum_orig_offset, last_offset;
Serhiy Storchaka67559bf2015-02-16 21:13:24 +0200239 Py_ssize_t tabsiz;
INADA Naoki87010e82017-12-18 15:52:54 +0900240 // Count runs of consecutive LOAD_CONSTs
241 unsigned int cumlc = 0, lastlc = 0;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000242 unsigned int *blocks = NULL;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000243
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000244 /* Bail out if an exception is set */
245 if (PyErr_Occurred())
246 goto exitError;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000247
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100248 /* Bypass optimization when the lnotab table is too complex */
249 assert(PyBytes_Check(lnotab_obj));
250 lnotab = (unsigned char*)PyBytes_AS_STRING(lnotab_obj);
251 tabsiz = PyBytes_GET_SIZE(lnotab_obj);
252 assert(tabsiz == 0 || Py_REFCNT(lnotab_obj) == 1);
Pablo Galindo3498c642019-06-13 19:16:22 +0100253
254 /* Don't optimize if lnotab contains instruction pointer delta larger
255 than +255 (encoded as multiple bytes), just to keep the peephole optimizer
256 simple. The optimizer leaves line number deltas unchanged. */
257
258 for (j = 0; j < tabsiz; j += 2) {
259 if (lnotab[j] == 255) {
260 goto exitUnchanged;
261 }
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100262 }
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000263
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000264 assert(PyBytes_Check(code));
Victor Stinner028f0ef2018-12-07 17:54:18 +0100265 Py_ssize_t codesize = PyBytes_GET_SIZE(code);
266 assert(codesize % sizeof(_Py_CODEUNIT) == 0);
267 Py_ssize_t codelen = codesize / sizeof(_Py_CODEUNIT);
268 if (codelen > INT_MAX) {
269 /* Python assembler is limited to INT_MAX: see assembler.a_offset in
270 compile.c. */
271 goto exitUnchanged;
272 }
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000273
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000274 /* Make a modifiable copy of the code string */
Victor Stinner028f0ef2018-12-07 17:54:18 +0100275 codestr = (_Py_CODEUNIT *)PyMem_Malloc(codesize);
Victor Stinnere0af3a82013-07-09 00:32:04 +0200276 if (codestr == NULL) {
277 PyErr_NoMemory();
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000278 goto exitError;
Victor Stinnere0af3a82013-07-09 00:32:04 +0200279 }
Victor Stinner028f0ef2018-12-07 17:54:18 +0100280 memcpy(codestr, PyBytes_AS_STRING(code), codesize);
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000281
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000282 blocks = markblocks(codestr, codelen);
283 if (blocks == NULL)
284 goto exitError;
285 assert(PyList_Check(consts));
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000286
Gregory P. Smith49fa4a92018-11-08 17:55:07 -0800287 for (i=find_op(codestr, codelen, 0) ; i<codelen ; i=nexti) {
Serhiy Storchakaa1e9ab32016-09-11 15:19:12 +0300288 opcode = _Py_OPCODE(codestr[i]);
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300289 op_start = i;
Serhiy Storchakaab874002016-09-11 13:48:15 +0300290 while (op_start >= 1 && _Py_OPCODE(codestr[op_start-1]) == EXTENDED_ARG) {
291 op_start--;
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300292 }
293
Serhiy Storchakaab874002016-09-11 13:48:15 +0300294 nexti = i + 1;
295 while (nexti < codelen && _Py_OPCODE(codestr[nexti]) == EXTENDED_ARG)
296 nexti++;
297 nextop = nexti < codelen ? _Py_OPCODE(codestr[nexti]) : 0;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000298
INADA Naoki87010e82017-12-18 15:52:54 +0900299 lastlc = cumlc;
300 cumlc = 0;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000301
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000302 switch (opcode) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000303 /* Skip over LOAD_CONST trueconst
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300304 POP_JUMP_IF_FALSE xx. This improves
305 "while 1" performance. */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000306 case LOAD_CONST:
INADA Naoki87010e82017-12-18 15:52:54 +0900307 cumlc = lastlc + 1;
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300308 if (nextop != POP_JUMP_IF_FALSE ||
Pablo Galindoaf8646c2019-05-17 11:37:08 +0100309 !ISBASICBLOCK(blocks, op_start, i + 1)) {
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300310 break;
Pablo Galindoaf8646c2019-05-17 11:37:08 +0100311 }
312 PyObject* cnt = PyList_GET_ITEM(consts, get_arg(codestr, i));
313 int is_true = PyObject_IsTrue(cnt);
314 if (is_true == 1) {
315 fill_nops(codestr, op_start, nexti + 1);
316 cumlc = 0;
317 } else if (is_true == 0) {
Pablo Galindo05f83182019-06-14 06:54:53 +0100318 if (i > 1 &&
319 (_Py_OPCODE(codestr[i - 1]) == POP_JUMP_IF_TRUE ||
320 _Py_OPCODE(codestr[i - 1]) == POP_JUMP_IF_FALSE)) {
321 break;
322 }
Pablo Galindoaf8646c2019-05-17 11:37:08 +0100323 h = get_arg(codestr, nexti) / sizeof(_Py_CODEUNIT);
324 tgt = find_op(codestr, codelen, h);
325 fill_nops(codestr, op_start, tgt);
326 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000327 break;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000328
Serhiy Storchaka15a87282017-12-14 20:24:31 +0200329 /* Try to fold tuples of constants.
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000330 Skip over BUILD_SEQN 1 UNPACK_SEQN 1.
331 Replace BUILD_SEQN 2 UNPACK_SEQN 2 with ROT2.
332 Replace BUILD_SEQN 3 UNPACK_SEQN 3 with ROT3 ROT2. */
333 case BUILD_TUPLE:
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300334 j = get_arg(codestr, i);
INADA Naoki87010e82017-12-18 15:52:54 +0900335 if (j > 0 && lastlc >= j) {
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300336 h = lastn_const_start(codestr, op_start, j);
Serhiy Storchaka15a87282017-12-14 20:24:31 +0200337 if (ISBASICBLOCK(blocks, h, op_start)) {
Gregory P. Smith49fa4a92018-11-08 17:55:07 -0800338 h = fold_tuple_on_constants(codestr, codelen,
339 h, i+1, consts, j);
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300340 break;
341 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000342 }
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300343 if (nextop != UNPACK_SEQUENCE ||
Serhiy Storchakaab874002016-09-11 13:48:15 +0300344 !ISBASICBLOCK(blocks, op_start, i + 1) ||
Serhiy Storchaka15a87282017-12-14 20:24:31 +0200345 j != get_arg(codestr, nexti))
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300346 break;
347 if (j < 2) {
Serhiy Storchakaab874002016-09-11 13:48:15 +0300348 fill_nops(codestr, op_start, nexti + 1);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000349 } else if (j == 2) {
Serhiy Storchakaab874002016-09-11 13:48:15 +0300350 codestr[op_start] = PACKOPARG(ROT_TWO, 0);
351 fill_nops(codestr, op_start + 1, nexti + 1);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000352 } else if (j == 3) {
Serhiy Storchakaab874002016-09-11 13:48:15 +0300353 codestr[op_start] = PACKOPARG(ROT_THREE, 0);
354 codestr[op_start + 1] = PACKOPARG(ROT_TWO, 0);
355 fill_nops(codestr, op_start + 2, nexti + 1);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000356 }
357 break;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000358
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000359 /* Simplify conditional jump to conditional jump where the
360 result of the first test implies the success of a similar
361 test or the failure of the opposite test.
362 Arises in code like:
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000363 "a and b or c"
364 "(a and b) and c"
Serhiy Storchaka36ff4512017-06-11 14:50:22 +0300365 "(a or b) or c"
366 "(a or b) and c"
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000367 x:JUMP_IF_FALSE_OR_POP y y:JUMP_IF_FALSE_OR_POP z
368 --> x:JUMP_IF_FALSE_OR_POP z
369 x:JUMP_IF_FALSE_OR_POP y y:JUMP_IF_TRUE_OR_POP z
Serhiy Storchakaab874002016-09-11 13:48:15 +0300370 --> x:POP_JUMP_IF_FALSE y+1
371 where y+1 is the instruction following the second test.
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000372 */
373 case JUMP_IF_FALSE_OR_POP:
374 case JUMP_IF_TRUE_OR_POP:
Serhiy Storchakaab874002016-09-11 13:48:15 +0300375 h = get_arg(codestr, i) / sizeof(_Py_CODEUNIT);
Gregory P. Smith49fa4a92018-11-08 17:55:07 -0800376 tgt = find_op(codestr, codelen, h);
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300377
Serhiy Storchakaab874002016-09-11 13:48:15 +0300378 j = _Py_OPCODE(codestr[tgt]);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000379 if (CONDITIONAL_JUMP(j)) {
Raymond Hettinger08eef3f2016-08-07 20:20:33 -0700380 /* NOTE: all possible jumps here are absolute. */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000381 if (JUMPS_ON_TRUE(j) == JUMPS_ON_TRUE(opcode)) {
Raymond Hettinger08eef3f2016-08-07 20:20:33 -0700382 /* The second jump will be taken iff the first is.
383 The current opcode inherits its target's
384 stack effect */
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300385 h = set_arg(codestr, i, get_arg(codestr, tgt));
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000386 } else {
Raymond Hettinger08eef3f2016-08-07 20:20:33 -0700387 /* The second jump is not taken if the first is (so
388 jump past it), and all conditional jumps pop their
389 argument when they're not taken (so change the
390 first jump to pop its argument when it's taken). */
Victor Stinner028f0ef2018-12-07 17:54:18 +0100391 Py_ssize_t arg = (tgt + 1);
392 /* cannot overflow: codelen <= INT_MAX */
393 assert((size_t)arg <= UINT_MAX / sizeof(_Py_CODEUNIT));
394 arg *= sizeof(_Py_CODEUNIT);
395 h = set_arg(codestr, i, (unsigned int)arg);
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300396 j = opcode == JUMP_IF_TRUE_OR_POP ?
397 POP_JUMP_IF_TRUE : POP_JUMP_IF_FALSE;
398 }
399
400 if (h >= 0) {
401 nexti = h;
Serhiy Storchakaab874002016-09-11 13:48:15 +0300402 codestr[nexti] = PACKOPARG(j, _Py_OPARG(codestr[nexti]));
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300403 break;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000404 }
405 }
406 /* Intentional fallthrough */
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000407
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000408 /* Replace jumps to unconditional jumps */
409 case POP_JUMP_IF_FALSE:
410 case POP_JUMP_IF_TRUE:
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000411 case JUMP_FORWARD:
412 case JUMP_ABSOLUTE:
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300413 h = GETJUMPTGT(codestr, i);
Gregory P. Smith49fa4a92018-11-08 17:55:07 -0800414 tgt = find_op(codestr, codelen, h);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000415 /* Replace JUMP_* to a RETURN into just a RETURN */
416 if (UNCONDITIONAL_JUMP(opcode) &&
Serhiy Storchakaab874002016-09-11 13:48:15 +0300417 _Py_OPCODE(codestr[tgt]) == RETURN_VALUE) {
418 codestr[op_start] = PACKOPARG(RETURN_VALUE, 0);
419 fill_nops(codestr, op_start + 1, i + 1);
420 } else if (UNCONDITIONAL_JUMP(_Py_OPCODE(codestr[tgt]))) {
Victor Stinner028f0ef2018-12-07 17:54:18 +0100421 size_t arg = GETJUMPTGT(codestr, tgt);
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300422 if (opcode == JUMP_FORWARD) { /* JMP_ABS can go backwards */
423 opcode = JUMP_ABSOLUTE;
424 } else if (!ABSOLUTE_JUMP(opcode)) {
Victor Stinner028f0ef2018-12-07 17:54:18 +0100425 if (arg < (size_t)(i + 1)) {
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300426 break; /* No backward relative jumps */
427 }
Victor Stinner028f0ef2018-12-07 17:54:18 +0100428 arg -= i + 1; /* Calc relative jump addr */
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300429 }
Victor Stinner028f0ef2018-12-07 17:54:18 +0100430 /* cannot overflow: codelen <= INT_MAX */
431 assert(arg <= (UINT_MAX / sizeof(_Py_CODEUNIT)));
432 arg *= sizeof(_Py_CODEUNIT);
433 copy_op_arg(codestr, op_start, opcode,
434 (unsigned int)arg, i + 1);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000435 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000436 break;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000437
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300438 /* Remove unreachable ops after RETURN */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000439 case RETURN_VALUE:
Serhiy Storchakaab874002016-09-11 13:48:15 +0300440 h = i + 1;
Serhiy Storchaka520b7ae2018-02-22 23:33:30 +0200441 /* END_FINALLY should be kept since it denotes the end of
442 the 'finally' block in frame_setlineno() in frameobject.c.
443 SETUP_FINALLY should be kept for balancing.
444 */
445 while (h < codelen && ISBASICBLOCK(blocks, i, h) &&
446 _Py_OPCODE(codestr[h]) != END_FINALLY)
447 {
448 if (_Py_OPCODE(codestr[h]) == SETUP_FINALLY) {
449 while (h > i + 1 &&
450 _Py_OPCODE(codestr[h - 1]) == EXTENDED_ARG)
451 {
452 h--;
453 }
454 break;
455 }
Serhiy Storchakaab874002016-09-11 13:48:15 +0300456 h++;
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300457 }
Serhiy Storchakaab874002016-09-11 13:48:15 +0300458 if (h > i + 1) {
Serhiy Storchaka7db3c482016-10-25 09:30:43 +0300459 fill_nops(codestr, i + 1, h);
Gregory P. Smith49fa4a92018-11-08 17:55:07 -0800460 nexti = find_op(codestr, codelen, h);
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300461 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000462 break;
463 }
464 }
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000465
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100466 /* Fixup lnotab */
Serhiy Storchakaab874002016-09-11 13:48:15 +0300467 for (i = 0, nops = 0; i < codelen; i++) {
Victor Stinner028f0ef2018-12-07 17:54:18 +0100468 size_t block = (size_t)i - nops;
469 /* cannot overflow: codelen <= INT_MAX */
470 assert(block <= UINT_MAX);
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100471 /* original code offset => new code offset */
Victor Stinner028f0ef2018-12-07 17:54:18 +0100472 blocks[i] = (unsigned int)block;
473 if (_Py_OPCODE(codestr[i]) == NOP) {
Serhiy Storchakaab874002016-09-11 13:48:15 +0300474 nops++;
Victor Stinner028f0ef2018-12-07 17:54:18 +0100475 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000476 }
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100477 cum_orig_offset = 0;
478 last_offset = 0;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000479 for (i=0 ; i < tabsiz ; i+=2) {
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300480 unsigned int offset_delta, new_offset;
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100481 cum_orig_offset += lnotab[i];
Serhiy Storchakaab874002016-09-11 13:48:15 +0300482 assert(cum_orig_offset % sizeof(_Py_CODEUNIT) == 0);
483 new_offset = blocks[cum_orig_offset / sizeof(_Py_CODEUNIT)] *
484 sizeof(_Py_CODEUNIT);
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100485 offset_delta = new_offset - last_offset;
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300486 assert(offset_delta <= 255);
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100487 lnotab[i] = (unsigned char)offset_delta;
488 last_offset = new_offset;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000489 }
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000490
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000491 /* Remove NOPs and fixup jump targets */
Serhiy Storchakaab874002016-09-11 13:48:15 +0300492 for (op_start = i = h = 0; i < codelen; i++, op_start = i) {
493 j = _Py_OPARG(codestr[i]);
494 while (_Py_OPCODE(codestr[i]) == EXTENDED_ARG) {
495 i++;
496 j = j<<8 | _Py_OPARG(codestr[i]);
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300497 }
Serhiy Storchakaab874002016-09-11 13:48:15 +0300498 opcode = _Py_OPCODE(codestr[i]);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000499 switch (opcode) {
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300500 case NOP:continue;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000501
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000502 case JUMP_ABSOLUTE:
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000503 case POP_JUMP_IF_FALSE:
504 case POP_JUMP_IF_TRUE:
505 case JUMP_IF_FALSE_OR_POP:
506 case JUMP_IF_TRUE_OR_POP:
Serhiy Storchakaab874002016-09-11 13:48:15 +0300507 j = blocks[j / sizeof(_Py_CODEUNIT)] * sizeof(_Py_CODEUNIT);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000508 break;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000509
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000510 case FOR_ITER:
511 case JUMP_FORWARD:
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000512 case SETUP_FINALLY:
513 case SETUP_WITH:
Yury Selivanov75445082015-05-11 22:57:16 -0400514 case SETUP_ASYNC_WITH:
Serhiy Storchaka520b7ae2018-02-22 23:33:30 +0200515 case CALL_FINALLY:
Serhiy Storchakaab874002016-09-11 13:48:15 +0300516 j = blocks[j / sizeof(_Py_CODEUNIT) + i + 1] - blocks[i] - 1;
517 j *= sizeof(_Py_CODEUNIT);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000518 break;
519 }
Victor Stinner028f0ef2018-12-07 17:54:18 +0100520 Py_ssize_t ilen = i - op_start + 1;
521 if (instrsize(j) > ilen) {
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300522 goto exitUnchanged;
Victor Stinner028f0ef2018-12-07 17:54:18 +0100523 }
524 assert(ilen <= INT_MAX);
525 /* If instrsize(j) < ilen, we'll emit EXTENDED_ARG 0 */
526 write_op_arg(codestr + h, opcode, j, (int)ilen);
527 h += ilen;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000528 }
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300529 assert(h + (Py_ssize_t)nops == codelen);
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000530
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000531 PyMem_Free(blocks);
Serhiy Storchakaab874002016-09-11 13:48:15 +0300532 code = PyBytes_FromStringAndSize((char *)codestr, h * sizeof(_Py_CODEUNIT));
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300533 PyMem_Free(codestr);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000534 return code;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000535
Alexandre Vassalotti6f828182009-07-21 02:51:58 +0000536 exitError:
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000537 code = NULL;
Alexandre Vassalotti6f828182009-07-21 02:51:58 +0000538
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000539 exitUnchanged:
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300540 Py_XINCREF(code);
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100541 PyMem_Free(blocks);
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100542 PyMem_Free(codestr);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000543 return code;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000544}