blob: fe67de42227b5bded13b23178864f9a9b14373af [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"
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00006#include "ast.h"
7#include "code.h"
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00008#include "symtable.h"
9#include "opcode.h"
Serhiy Storchakab0f80b02016-05-24 09:15:14 +030010#include "wordcode_helpers.h"
Thomas Wouters00ee7ba2006-08-21 19:07:27 +000011
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000012#define UNCONDITIONAL_JUMP(op) (op==JUMP_ABSOLUTE || op==JUMP_FORWARD)
Jeffrey Yasskin9de7ec72009-02-25 02:25:04 +000013#define CONDITIONAL_JUMP(op) (op==POP_JUMP_IF_FALSE || op==POP_JUMP_IF_TRUE \
Mark Shannon9af0e472020-01-14 10:12:45 +000014 || op==JUMP_IF_FALSE_OR_POP || op==JUMP_IF_TRUE_OR_POP || op==JUMP_IF_NOT_EXC_MATCH)
Serhiy Storchaka520b7ae2018-02-22 23:33:30 +020015#define ABSOLUTE_JUMP(op) (op==JUMP_ABSOLUTE \
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000016 || op==POP_JUMP_IF_FALSE || op==POP_JUMP_IF_TRUE \
Mark Shannon9af0e472020-01-14 10:12:45 +000017 || op==JUMP_IF_FALSE_OR_POP || op==JUMP_IF_TRUE_OR_POP || op==JUMP_IF_NOT_EXC_MATCH)
Jeffrey Yasskin9de7ec72009-02-25 02:25:04 +000018#define JUMPS_ON_TRUE(op) (op==POP_JUMP_IF_TRUE || op==JUMP_IF_TRUE_OR_POP)
Serhiy Storchakaab874002016-09-11 13:48:15 +030019#define GETJUMPTGT(arr, i) (get_arg(arr, i) / sizeof(_Py_CODEUNIT) + \
20 (ABSOLUTE_JUMP(_Py_OPCODE(arr[i])) ? 0 : i+1))
Serhiy Storchakab0f80b02016-05-24 09:15:14 +030021#define ISBASICBLOCK(blocks, start, end) \
22 (blocks[start]==blocks[end])
Thomas Wouters00ee7ba2006-08-21 19:07:27 +000023
Antoine Pitrou17b880a2011-03-11 17:27:02 +010024
Serhiy Storchakab0f80b02016-05-24 09:15:14 +030025/* Scans back N consecutive LOAD_CONST instructions, skipping NOPs,
26 returns index of the Nth last's LOAD_CONST's EXTENDED_ARG prefix.
27 Callers are responsible to check CONST_STACK_LEN beforehand.
28*/
29static Py_ssize_t
Serhiy Storchakaab874002016-09-11 13:48:15 +030030lastn_const_start(const _Py_CODEUNIT *codestr, Py_ssize_t i, Py_ssize_t n)
Serhiy Storchakab0f80b02016-05-24 09:15:14 +030031{
Serhiy Storchakaab874002016-09-11 13:48:15 +030032 assert(n > 0);
Serhiy Storchakab0f80b02016-05-24 09:15:14 +030033 for (;;) {
Serhiy Storchakaab874002016-09-11 13:48:15 +030034 i--;
Serhiy Storchakab0f80b02016-05-24 09:15:14 +030035 assert(i >= 0);
Serhiy Storchakaab874002016-09-11 13:48:15 +030036 if (_Py_OPCODE(codestr[i]) == LOAD_CONST) {
Serhiy Storchakab0f80b02016-05-24 09:15:14 +030037 if (!--n) {
Serhiy Storchakaab874002016-09-11 13:48:15 +030038 while (i > 0 && _Py_OPCODE(codestr[i-1]) == EXTENDED_ARG) {
39 i--;
Serhiy Storchakab0f80b02016-05-24 09:15:14 +030040 }
41 return i;
42 }
43 }
44 else {
INADA Naoki87010e82017-12-18 15:52:54 +090045 assert(_Py_OPCODE(codestr[i]) == EXTENDED_ARG);
Serhiy Storchakab0f80b02016-05-24 09:15:14 +030046 }
47 }
48}
Antoine Pitrou17b880a2011-03-11 17:27:02 +010049
Serhiy Storchakab0f80b02016-05-24 09:15:14 +030050/* Scans through EXTENDED ARGs, seeking the index of the effective opcode */
51static Py_ssize_t
Gregory P. Smith49fa4a92018-11-08 17:55:07 -080052find_op(const _Py_CODEUNIT *codestr, Py_ssize_t codelen, Py_ssize_t i)
Serhiy Storchakab0f80b02016-05-24 09:15:14 +030053{
Gregory P. Smith49fa4a92018-11-08 17:55:07 -080054 while (i < codelen && _Py_OPCODE(codestr[i]) == EXTENDED_ARG) {
Serhiy Storchakaab874002016-09-11 13:48:15 +030055 i++;
Serhiy Storchakab0f80b02016-05-24 09:15:14 +030056 }
57 return i;
58}
Antoine Pitrou17b880a2011-03-11 17:27:02 +010059
Serhiy Storchakab0f80b02016-05-24 09:15:14 +030060/* Given the index of the effective opcode,
61 scan back to construct the oparg with EXTENDED_ARG */
62static unsigned int
Serhiy Storchakaab874002016-09-11 13:48:15 +030063get_arg(const _Py_CODEUNIT *codestr, Py_ssize_t i)
Serhiy Storchakab0f80b02016-05-24 09:15:14 +030064{
Serhiy Storchakaab874002016-09-11 13:48:15 +030065 _Py_CODEUNIT word;
66 unsigned int oparg = _Py_OPARG(codestr[i]);
67 if (i >= 1 && _Py_OPCODE(word = codestr[i-1]) == EXTENDED_ARG) {
68 oparg |= _Py_OPARG(word) << 8;
69 if (i >= 2 && _Py_OPCODE(word = codestr[i-2]) == EXTENDED_ARG) {
70 oparg |= _Py_OPARG(word) << 16;
71 if (i >= 3 && _Py_OPCODE(word = codestr[i-3]) == EXTENDED_ARG) {
72 oparg |= _Py_OPARG(word) << 24;
Serhiy Storchakab0f80b02016-05-24 09:15:14 +030073 }
74 }
75 }
76 return oparg;
77}
78
Serhiy Storchakaab874002016-09-11 13:48:15 +030079/* Fill the region with NOPs. */
80static void
81fill_nops(_Py_CODEUNIT *codestr, Py_ssize_t start, Py_ssize_t end)
82{
83 memset(codestr + start, NOP, (end - start) * sizeof(_Py_CODEUNIT));
84}
85
Serhiy Storchakab0f80b02016-05-24 09:15:14 +030086/* Given the index of the effective opcode,
87 attempt to replace the argument, taking into account EXTENDED_ARG.
88 Returns -1 on failure, or the new op index on success */
89static Py_ssize_t
Serhiy Storchakaab874002016-09-11 13:48:15 +030090set_arg(_Py_CODEUNIT *codestr, Py_ssize_t i, unsigned int oparg)
Serhiy Storchakab0f80b02016-05-24 09:15:14 +030091{
92 unsigned int curarg = get_arg(codestr, i);
93 int curilen, newilen;
94 if (curarg == oparg)
95 return i;
96 curilen = instrsize(curarg);
97 newilen = instrsize(oparg);
98 if (curilen < newilen) {
99 return -1;
100 }
101
Serhiy Storchakaab874002016-09-11 13:48:15 +0300102 write_op_arg(codestr + i + 1 - curilen, _Py_OPCODE(codestr[i]), oparg, newilen);
103 fill_nops(codestr, i + 1 - curilen + newilen, i + 1);
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300104 return i-curilen+newilen;
105}
106
107/* Attempt to write op/arg at end of specified region of memory.
108 Preceding memory in the region is overwritten with NOPs.
109 Returns -1 on failure, op index on success */
110static Py_ssize_t
Serhiy Storchakaab874002016-09-11 13:48:15 +0300111copy_op_arg(_Py_CODEUNIT *codestr, Py_ssize_t i, unsigned char op,
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300112 unsigned int oparg, Py_ssize_t maxi)
113{
114 int ilen = instrsize(oparg);
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300115 if (i + ilen > maxi) {
116 return -1;
117 }
118 write_op_arg(codestr + maxi - ilen, op, oparg, ilen);
Serhiy Storchakaab874002016-09-11 13:48:15 +0300119 fill_nops(codestr, i, maxi - ilen);
120 return maxi - 1;
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300121}
122
123/* Replace LOAD_CONST c1, LOAD_CONST c2 ... LOAD_CONST cn, BUILD_TUPLE n
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000124 with LOAD_CONST (c1, c2, ... cn).
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000125 The consts table must still be in list form so that the
126 new constant (c1, c2, ... cn) can be appended.
127 Called with codestr pointing to the first LOAD_CONST.
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000128*/
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300129static Py_ssize_t
Gregory P. Smith49fa4a92018-11-08 17:55:07 -0800130fold_tuple_on_constants(_Py_CODEUNIT *codestr, Py_ssize_t codelen,
131 Py_ssize_t c_start, Py_ssize_t opcode_end,
132 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);
Gregory P. Smith49fa4a92018-11-08 17:55:07 -0800145 pos = find_op(codestr, codelen, pos);
INADA Naoki87010e82017-12-18 15:52:54 +0900146 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
Victor Stinner028f0ef2018-12-07 17:54:18 +0100154 Py_ssize_t index = PyList_GET_SIZE(consts);
155#if SIZEOF_SIZE_T > SIZEOF_INT
156 if ((size_t)index >= UINT_MAX - 1) {
157 Py_DECREF(newconst);
158 PyErr_SetString(PyExc_OverflowError, "too many constants");
159 return -1;
160 }
161#endif
162
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000163 /* Append folded constant onto consts */
164 if (PyList_Append(consts, newconst)) {
165 Py_DECREF(newconst);
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300166 return -1;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000167 }
168 Py_DECREF(newconst);
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000169
INADA Naoki87010e82017-12-18 15:52:54 +0900170 return copy_op_arg(codestr, c_start, LOAD_CONST,
Victor Stinner028f0ef2018-12-07 17:54:18 +0100171 (unsigned int)index, opcode_end);
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000172}
173
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000174static unsigned int *
Serhiy Storchakaab874002016-09-11 13:48:15 +0300175markblocks(_Py_CODEUNIT *code, Py_ssize_t len)
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000176{
Serhiy Storchaka1a1ff292015-02-16 13:28:22 +0200177 unsigned int *blocks = PyMem_New(unsigned int, len);
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300178 int i, j, opcode, blockcnt = 0;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000179
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000180 if (blocks == NULL) {
181 PyErr_NoMemory();
182 return NULL;
183 }
184 memset(blocks, 0, len*sizeof(int));
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000185
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000186 /* Mark labels in the first pass */
Serhiy Storchakaab874002016-09-11 13:48:15 +0300187 for (i = 0; i < len; i++) {
188 opcode = _Py_OPCODE(code[i]);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000189 switch (opcode) {
190 case FOR_ITER:
191 case JUMP_FORWARD:
192 case JUMP_IF_FALSE_OR_POP:
193 case JUMP_IF_TRUE_OR_POP:
194 case POP_JUMP_IF_FALSE:
195 case POP_JUMP_IF_TRUE:
Mark Shannon9af0e472020-01-14 10:12:45 +0000196 case JUMP_IF_NOT_EXC_MATCH:
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000197 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:
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000201 j = GETJUMPTGT(code, i);
Serhiy Storchakaab874002016-09-11 13:48:15 +0300202 assert(j < len);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000203 blocks[j] = 1;
204 break;
205 }
206 }
207 /* Build block numbers in the second pass */
Serhiy Storchakaab874002016-09-11 13:48:15 +0300208 for (i = 0; i < len; i++) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000209 blockcnt += blocks[i]; /* increment blockcnt over labels */
210 blocks[i] = blockcnt;
211 }
212 return blocks;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000213}
214
215/* Perform basic peephole optimizations to components of a code object.
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000216 The consts object should still be in list form to allow new constants
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000217 to be appended.
218
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300219 To keep the optimizer simple, it bails when the lineno table has complex
220 encoding for gaps >= 255.
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000221
Martin Panter46f50722016-05-26 05:35:26 +0000222 Optimizations are restricted to simple transformations occurring within a
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000223 single basic block. All transformations keep the code size the same or
224 smaller. For those that reduce size, the gaps are initially filled with
225 NOPs. Later those NOPs are removed and the jump addresses retargeted in
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300226 a single pass. */
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000227
228PyObject *
229PyCode_Optimize(PyObject *code, PyObject* consts, PyObject *names,
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100230 PyObject *lnotab_obj)
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000231{
Victor Stinner028f0ef2018-12-07 17:54:18 +0100232 Py_ssize_t h, i, nexti, op_start, tgt;
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300233 unsigned int j, nops;
234 unsigned char opcode, nextop;
Serhiy Storchakaab874002016-09-11 13:48:15 +0300235 _Py_CODEUNIT *codestr = NULL;
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100236 unsigned char *lnotab;
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300237 unsigned int cum_orig_offset, last_offset;
Serhiy Storchaka67559bf2015-02-16 21:13:24 +0200238 Py_ssize_t tabsiz;
INADA Naoki87010e82017-12-18 15:52:54 +0900239 // Count runs of consecutive LOAD_CONSTs
240 unsigned int cumlc = 0, lastlc = 0;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000241 unsigned int *blocks = NULL;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000242
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000243 /* Bail out if an exception is set */
244 if (PyErr_Occurred())
245 goto exitError;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000246
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100247 /* Bypass optimization when the lnotab table is too complex */
248 assert(PyBytes_Check(lnotab_obj));
249 lnotab = (unsigned char*)PyBytes_AS_STRING(lnotab_obj);
250 tabsiz = PyBytes_GET_SIZE(lnotab_obj);
251 assert(tabsiz == 0 || Py_REFCNT(lnotab_obj) == 1);
Pablo Galindo3498c642019-06-13 19:16:22 +0100252
253 /* Don't optimize if lnotab contains instruction pointer delta larger
254 than +255 (encoded as multiple bytes), just to keep the peephole optimizer
255 simple. The optimizer leaves line number deltas unchanged. */
256
Raymond Hettinger0138c4c2019-08-27 09:55:13 -0700257 for (i = 0; i < tabsiz; i += 2) {
258 if (lnotab[i] == 255) {
Pablo Galindo3498c642019-06-13 19:16:22 +0100259 goto exitUnchanged;
260 }
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100261 }
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000262
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000263 assert(PyBytes_Check(code));
Victor Stinner028f0ef2018-12-07 17:54:18 +0100264 Py_ssize_t codesize = PyBytes_GET_SIZE(code);
265 assert(codesize % sizeof(_Py_CODEUNIT) == 0);
266 Py_ssize_t codelen = codesize / sizeof(_Py_CODEUNIT);
267 if (codelen > INT_MAX) {
268 /* Python assembler is limited to INT_MAX: see assembler.a_offset in
269 compile.c. */
270 goto exitUnchanged;
271 }
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000272
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000273 /* Make a modifiable copy of the code string */
Victor Stinner028f0ef2018-12-07 17:54:18 +0100274 codestr = (_Py_CODEUNIT *)PyMem_Malloc(codesize);
Victor Stinnere0af3a82013-07-09 00:32:04 +0200275 if (codestr == NULL) {
276 PyErr_NoMemory();
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000277 goto exitError;
Victor Stinnere0af3a82013-07-09 00:32:04 +0200278 }
Victor Stinner028f0ef2018-12-07 17:54:18 +0100279 memcpy(codestr, PyBytes_AS_STRING(code), codesize);
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000280
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000281 blocks = markblocks(codestr, codelen);
282 if (blocks == NULL)
283 goto exitError;
284 assert(PyList_Check(consts));
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000285
Gregory P. Smith49fa4a92018-11-08 17:55:07 -0800286 for (i=find_op(codestr, codelen, 0) ; i<codelen ; i=nexti) {
Serhiy Storchakaa1e9ab32016-09-11 15:19:12 +0300287 opcode = _Py_OPCODE(codestr[i]);
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300288 op_start = i;
Serhiy Storchakaab874002016-09-11 13:48:15 +0300289 while (op_start >= 1 && _Py_OPCODE(codestr[op_start-1]) == EXTENDED_ARG) {
290 op_start--;
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300291 }
292
Serhiy Storchakaab874002016-09-11 13:48:15 +0300293 nexti = i + 1;
294 while (nexti < codelen && _Py_OPCODE(codestr[nexti]) == EXTENDED_ARG)
295 nexti++;
296 nextop = nexti < codelen ? _Py_OPCODE(codestr[nexti]) : 0;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000297
INADA Naoki87010e82017-12-18 15:52:54 +0900298 lastlc = cumlc;
299 cumlc = 0;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000300
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000301 switch (opcode) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000302 /* Skip over LOAD_CONST trueconst
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300303 POP_JUMP_IF_FALSE xx. This improves
304 "while 1" performance. */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000305 case LOAD_CONST:
INADA Naoki87010e82017-12-18 15:52:54 +0900306 cumlc = lastlc + 1;
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300307 if (nextop != POP_JUMP_IF_FALSE ||
Pablo Galindoaf8646c2019-05-17 11:37:08 +0100308 !ISBASICBLOCK(blocks, op_start, i + 1)) {
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300309 break;
Pablo Galindoaf8646c2019-05-17 11:37:08 +0100310 }
311 PyObject* cnt = PyList_GET_ITEM(consts, get_arg(codestr, i));
312 int is_true = PyObject_IsTrue(cnt);
Pablo Galindo7a68f8c2019-06-15 15:58:00 +0100313 if (is_true == -1) {
314 goto exitError;
315 }
Pablo Galindoaf8646c2019-05-17 11:37:08 +0100316 if (is_true == 1) {
317 fill_nops(codestr, op_start, nexti + 1);
318 cumlc = 0;
Pablo Galindoaf8646c2019-05-17 11:37:08 +0100319 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000320 break;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000321
Serhiy Storchaka15a87282017-12-14 20:24:31 +0200322 /* Try to fold tuples of constants.
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000323 Skip over BUILD_SEQN 1 UNPACK_SEQN 1.
324 Replace BUILD_SEQN 2 UNPACK_SEQN 2 with ROT2.
325 Replace BUILD_SEQN 3 UNPACK_SEQN 3 with ROT3 ROT2. */
326 case BUILD_TUPLE:
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300327 j = get_arg(codestr, i);
INADA Naoki87010e82017-12-18 15:52:54 +0900328 if (j > 0 && lastlc >= j) {
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300329 h = lastn_const_start(codestr, op_start, j);
Serhiy Storchaka15a87282017-12-14 20:24:31 +0200330 if (ISBASICBLOCK(blocks, h, op_start)) {
Gregory P. Smith49fa4a92018-11-08 17:55:07 -0800331 h = fold_tuple_on_constants(codestr, codelen,
332 h, i+1, consts, j);
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300333 break;
334 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000335 }
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300336 if (nextop != UNPACK_SEQUENCE ||
Serhiy Storchakaab874002016-09-11 13:48:15 +0300337 !ISBASICBLOCK(blocks, op_start, i + 1) ||
Serhiy Storchaka15a87282017-12-14 20:24:31 +0200338 j != get_arg(codestr, nexti))
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300339 break;
340 if (j < 2) {
Serhiy Storchakaab874002016-09-11 13:48:15 +0300341 fill_nops(codestr, op_start, nexti + 1);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000342 } else if (j == 2) {
Serhiy Storchakaab874002016-09-11 13:48:15 +0300343 codestr[op_start] = PACKOPARG(ROT_TWO, 0);
344 fill_nops(codestr, op_start + 1, nexti + 1);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000345 } else if (j == 3) {
Serhiy Storchakaab874002016-09-11 13:48:15 +0300346 codestr[op_start] = PACKOPARG(ROT_THREE, 0);
347 codestr[op_start + 1] = PACKOPARG(ROT_TWO, 0);
348 fill_nops(codestr, op_start + 2, nexti + 1);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000349 }
350 break;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000351
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000352 /* Simplify conditional jump to conditional jump where the
353 result of the first test implies the success of a similar
354 test or the failure of the opposite test.
355 Arises in code like:
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000356 "a and b or c"
357 "(a and b) and c"
Serhiy Storchaka36ff4512017-06-11 14:50:22 +0300358 "(a or b) or c"
359 "(a or b) and c"
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000360 x:JUMP_IF_FALSE_OR_POP y y:JUMP_IF_FALSE_OR_POP z
361 --> x:JUMP_IF_FALSE_OR_POP z
362 x:JUMP_IF_FALSE_OR_POP y y:JUMP_IF_TRUE_OR_POP z
Serhiy Storchakaab874002016-09-11 13:48:15 +0300363 --> x:POP_JUMP_IF_FALSE y+1
364 where y+1 is the instruction following the second test.
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000365 */
366 case JUMP_IF_FALSE_OR_POP:
367 case JUMP_IF_TRUE_OR_POP:
Serhiy Storchakaab874002016-09-11 13:48:15 +0300368 h = get_arg(codestr, i) / sizeof(_Py_CODEUNIT);
Gregory P. Smith49fa4a92018-11-08 17:55:07 -0800369 tgt = find_op(codestr, codelen, h);
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300370
Serhiy Storchakaab874002016-09-11 13:48:15 +0300371 j = _Py_OPCODE(codestr[tgt]);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000372 if (CONDITIONAL_JUMP(j)) {
Raymond Hettinger08eef3f2016-08-07 20:20:33 -0700373 /* NOTE: all possible jumps here are absolute. */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000374 if (JUMPS_ON_TRUE(j) == JUMPS_ON_TRUE(opcode)) {
Raymond Hettinger08eef3f2016-08-07 20:20:33 -0700375 /* The second jump will be taken iff the first is.
376 The current opcode inherits its target's
377 stack effect */
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300378 h = set_arg(codestr, i, get_arg(codestr, tgt));
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000379 } else {
Raymond Hettinger08eef3f2016-08-07 20:20:33 -0700380 /* The second jump is not taken if the first is (so
381 jump past it), and all conditional jumps pop their
382 argument when they're not taken (so change the
383 first jump to pop its argument when it's taken). */
Victor Stinner028f0ef2018-12-07 17:54:18 +0100384 Py_ssize_t arg = (tgt + 1);
385 /* cannot overflow: codelen <= INT_MAX */
386 assert((size_t)arg <= UINT_MAX / sizeof(_Py_CODEUNIT));
387 arg *= sizeof(_Py_CODEUNIT);
388 h = set_arg(codestr, i, (unsigned int)arg);
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300389 j = opcode == JUMP_IF_TRUE_OR_POP ?
390 POP_JUMP_IF_TRUE : POP_JUMP_IF_FALSE;
391 }
392
393 if (h >= 0) {
394 nexti = h;
Serhiy Storchakaab874002016-09-11 13:48:15 +0300395 codestr[nexti] = PACKOPARG(j, _Py_OPARG(codestr[nexti]));
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300396 break;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000397 }
398 }
399 /* Intentional fallthrough */
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000400
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000401 /* Replace jumps to unconditional jumps */
402 case POP_JUMP_IF_FALSE:
403 case POP_JUMP_IF_TRUE:
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000404 case JUMP_FORWARD:
405 case JUMP_ABSOLUTE:
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300406 h = GETJUMPTGT(codestr, i);
Gregory P. Smith49fa4a92018-11-08 17:55:07 -0800407 tgt = find_op(codestr, codelen, h);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000408 /* Replace JUMP_* to a RETURN into just a RETURN */
409 if (UNCONDITIONAL_JUMP(opcode) &&
Serhiy Storchakaab874002016-09-11 13:48:15 +0300410 _Py_OPCODE(codestr[tgt]) == RETURN_VALUE) {
411 codestr[op_start] = PACKOPARG(RETURN_VALUE, 0);
412 fill_nops(codestr, op_start + 1, i + 1);
413 } else if (UNCONDITIONAL_JUMP(_Py_OPCODE(codestr[tgt]))) {
Victor Stinner028f0ef2018-12-07 17:54:18 +0100414 size_t arg = GETJUMPTGT(codestr, tgt);
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300415 if (opcode == JUMP_FORWARD) { /* JMP_ABS can go backwards */
416 opcode = JUMP_ABSOLUTE;
417 } else if (!ABSOLUTE_JUMP(opcode)) {
Victor Stinner028f0ef2018-12-07 17:54:18 +0100418 if (arg < (size_t)(i + 1)) {
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300419 break; /* No backward relative jumps */
420 }
Victor Stinner028f0ef2018-12-07 17:54:18 +0100421 arg -= i + 1; /* Calc relative jump addr */
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300422 }
Victor Stinner028f0ef2018-12-07 17:54:18 +0100423 /* cannot overflow: codelen <= INT_MAX */
424 assert(arg <= (UINT_MAX / sizeof(_Py_CODEUNIT)));
425 arg *= sizeof(_Py_CODEUNIT);
426 copy_op_arg(codestr, op_start, opcode,
427 (unsigned int)arg, i + 1);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000428 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000429 break;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000430
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300431 /* Remove unreachable ops after RETURN */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000432 case RETURN_VALUE:
Serhiy Storchakaab874002016-09-11 13:48:15 +0300433 h = i + 1;
Mark Shannonfee55262019-11-21 09:11:43 +0000434 while (h < codelen && ISBASICBLOCK(blocks, i, h))
Serhiy Storchaka520b7ae2018-02-22 23:33:30 +0200435 {
Mark Shannonfee55262019-11-21 09:11:43 +0000436 /* Leave SETUP_FINALLY and RERAISE in place to help find block limits. */
437 if (_Py_OPCODE(codestr[h]) == SETUP_FINALLY || _Py_OPCODE(codestr[h]) == RERAISE) {
Serhiy Storchaka520b7ae2018-02-22 23:33:30 +0200438 while (h > i + 1 &&
439 _Py_OPCODE(codestr[h - 1]) == EXTENDED_ARG)
440 {
441 h--;
442 }
443 break;
444 }
Serhiy Storchakaab874002016-09-11 13:48:15 +0300445 h++;
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300446 }
Serhiy Storchakaab874002016-09-11 13:48:15 +0300447 if (h > i + 1) {
Serhiy Storchaka7db3c482016-10-25 09:30:43 +0300448 fill_nops(codestr, i + 1, h);
Gregory P. Smith49fa4a92018-11-08 17:55:07 -0800449 nexti = find_op(codestr, codelen, h);
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300450 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000451 break;
452 }
453 }
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000454
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100455 /* Fixup lnotab */
Serhiy Storchakaab874002016-09-11 13:48:15 +0300456 for (i = 0, nops = 0; i < codelen; i++) {
Victor Stinner028f0ef2018-12-07 17:54:18 +0100457 size_t block = (size_t)i - nops;
458 /* cannot overflow: codelen <= INT_MAX */
459 assert(block <= UINT_MAX);
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100460 /* original code offset => new code offset */
Victor Stinner028f0ef2018-12-07 17:54:18 +0100461 blocks[i] = (unsigned int)block;
462 if (_Py_OPCODE(codestr[i]) == NOP) {
Serhiy Storchakaab874002016-09-11 13:48:15 +0300463 nops++;
Victor Stinner028f0ef2018-12-07 17:54:18 +0100464 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000465 }
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100466 cum_orig_offset = 0;
467 last_offset = 0;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000468 for (i=0 ; i < tabsiz ; i+=2) {
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300469 unsigned int offset_delta, new_offset;
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100470 cum_orig_offset += lnotab[i];
Serhiy Storchakaab874002016-09-11 13:48:15 +0300471 assert(cum_orig_offset % sizeof(_Py_CODEUNIT) == 0);
472 new_offset = blocks[cum_orig_offset / sizeof(_Py_CODEUNIT)] *
473 sizeof(_Py_CODEUNIT);
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100474 offset_delta = new_offset - last_offset;
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300475 assert(offset_delta <= 255);
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100476 lnotab[i] = (unsigned char)offset_delta;
477 last_offset = new_offset;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000478 }
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000479
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000480 /* Remove NOPs and fixup jump targets */
Serhiy Storchakaab874002016-09-11 13:48:15 +0300481 for (op_start = i = h = 0; i < codelen; i++, op_start = i) {
482 j = _Py_OPARG(codestr[i]);
483 while (_Py_OPCODE(codestr[i]) == EXTENDED_ARG) {
484 i++;
485 j = j<<8 | _Py_OPARG(codestr[i]);
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300486 }
Serhiy Storchakaab874002016-09-11 13:48:15 +0300487 opcode = _Py_OPCODE(codestr[i]);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000488 switch (opcode) {
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300489 case NOP:continue;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000490
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000491 case JUMP_ABSOLUTE:
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000492 case POP_JUMP_IF_FALSE:
493 case POP_JUMP_IF_TRUE:
494 case JUMP_IF_FALSE_OR_POP:
495 case JUMP_IF_TRUE_OR_POP:
Mark Shannon9af0e472020-01-14 10:12:45 +0000496 case JUMP_IF_NOT_EXC_MATCH:
Serhiy Storchakaab874002016-09-11 13:48:15 +0300497 j = blocks[j / sizeof(_Py_CODEUNIT)] * sizeof(_Py_CODEUNIT);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000498 break;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000499
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000500 case FOR_ITER:
501 case JUMP_FORWARD:
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000502 case SETUP_FINALLY:
503 case SETUP_WITH:
Yury Selivanov75445082015-05-11 22:57:16 -0400504 case SETUP_ASYNC_WITH:
Serhiy Storchakaab874002016-09-11 13:48:15 +0300505 j = blocks[j / sizeof(_Py_CODEUNIT) + i + 1] - blocks[i] - 1;
506 j *= sizeof(_Py_CODEUNIT);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000507 break;
508 }
Victor Stinner028f0ef2018-12-07 17:54:18 +0100509 Py_ssize_t ilen = i - op_start + 1;
510 if (instrsize(j) > ilen) {
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300511 goto exitUnchanged;
Victor Stinner028f0ef2018-12-07 17:54:18 +0100512 }
Victor Stinner028f0ef2018-12-07 17:54:18 +0100513 /* If instrsize(j) < ilen, we'll emit EXTENDED_ARG 0 */
Serhiy Storchakaeebaa9b2020-03-09 20:49:52 +0200514 if (ilen > 4) {
515 /* Can only happen when PyCode_Optimize() is called with
516 malformed bytecode. */
517 goto exitUnchanged;
518 }
Victor Stinner028f0ef2018-12-07 17:54:18 +0100519 write_op_arg(codestr + h, opcode, j, (int)ilen);
520 h += ilen;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000521 }
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300522 assert(h + (Py_ssize_t)nops == codelen);
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000523
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000524 PyMem_Free(blocks);
Serhiy Storchakaab874002016-09-11 13:48:15 +0300525 code = PyBytes_FromStringAndSize((char *)codestr, h * sizeof(_Py_CODEUNIT));
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300526 PyMem_Free(codestr);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000527 return code;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000528
Alexandre Vassalotti6f828182009-07-21 02:51:58 +0000529 exitError:
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000530 code = NULL;
Alexandre Vassalotti6f828182009-07-21 02:51:58 +0000531
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000532 exitUnchanged:
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300533 Py_XINCREF(code);
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100534 PyMem_Free(blocks);
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100535 PyMem_Free(codestr);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000536 return code;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000537}