blob: a3b078fdf1d40e4deb4a8cc083b2649956ec2a01 [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
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000155 /* Append folded constant onto consts */
156 if (PyList_Append(consts, newconst)) {
157 Py_DECREF(newconst);
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300158 return -1;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000159 }
160 Py_DECREF(newconst);
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000161
INADA Naoki87010e82017-12-18 15:52:54 +0900162 return copy_op_arg(codestr, c_start, LOAD_CONST,
163 PyList_GET_SIZE(consts)-1, opcode_end);
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000164}
165
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000166static unsigned int *
Serhiy Storchakaab874002016-09-11 13:48:15 +0300167markblocks(_Py_CODEUNIT *code, Py_ssize_t len)
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000168{
Serhiy Storchaka1a1ff292015-02-16 13:28:22 +0200169 unsigned int *blocks = PyMem_New(unsigned int, len);
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300170 int i, j, opcode, blockcnt = 0;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000171
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000172 if (blocks == NULL) {
173 PyErr_NoMemory();
174 return NULL;
175 }
176 memset(blocks, 0, len*sizeof(int));
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000177
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000178 /* Mark labels in the first pass */
Serhiy Storchakaab874002016-09-11 13:48:15 +0300179 for (i = 0; i < len; i++) {
180 opcode = _Py_OPCODE(code[i]);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000181 switch (opcode) {
182 case FOR_ITER:
183 case JUMP_FORWARD:
184 case JUMP_IF_FALSE_OR_POP:
185 case JUMP_IF_TRUE_OR_POP:
186 case POP_JUMP_IF_FALSE:
187 case POP_JUMP_IF_TRUE:
188 case JUMP_ABSOLUTE:
189 case CONTINUE_LOOP:
190 case SETUP_LOOP:
191 case SETUP_EXCEPT:
192 case SETUP_FINALLY:
193 case SETUP_WITH:
Yury Selivanov75445082015-05-11 22:57:16 -0400194 case SETUP_ASYNC_WITH:
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000195 j = GETJUMPTGT(code, i);
Serhiy Storchakaab874002016-09-11 13:48:15 +0300196 assert(j < len);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000197 blocks[j] = 1;
198 break;
199 }
200 }
201 /* Build block numbers in the second pass */
Serhiy Storchakaab874002016-09-11 13:48:15 +0300202 for (i = 0; i < len; i++) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000203 blockcnt += blocks[i]; /* increment blockcnt over labels */
204 blocks[i] = blockcnt;
205 }
206 return blocks;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000207}
208
209/* Perform basic peephole optimizations to components of a code object.
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000210 The consts object should still be in list form to allow new constants
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000211 to be appended.
212
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300213 To keep the optimizer simple, it bails when the lineno table has complex
214 encoding for gaps >= 255.
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000215
Martin Panter46f50722016-05-26 05:35:26 +0000216 Optimizations are restricted to simple transformations occurring within a
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000217 single basic block. All transformations keep the code size the same or
218 smaller. For those that reduce size, the gaps are initially filled with
219 NOPs. Later those NOPs are removed and the jump addresses retargeted in
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300220 a single pass. */
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000221
222PyObject *
223PyCode_Optimize(PyObject *code, PyObject* consts, PyObject *names,
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100224 PyObject *lnotab_obj)
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000225{
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300226 Py_ssize_t h, i, nexti, op_start, codelen, tgt;
227 unsigned int j, nops;
228 unsigned char opcode, nextop;
Serhiy Storchakaab874002016-09-11 13:48:15 +0300229 _Py_CODEUNIT *codestr = NULL;
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100230 unsigned char *lnotab;
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300231 unsigned int cum_orig_offset, last_offset;
Serhiy Storchaka67559bf2015-02-16 21:13:24 +0200232 Py_ssize_t tabsiz;
INADA Naoki87010e82017-12-18 15:52:54 +0900233 // Count runs of consecutive LOAD_CONSTs
234 unsigned int cumlc = 0, lastlc = 0;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000235 unsigned int *blocks = NULL;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000236
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000237 /* Bail out if an exception is set */
238 if (PyErr_Occurred())
239 goto exitError;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000240
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100241 /* Bypass optimization when the lnotab table is too complex */
242 assert(PyBytes_Check(lnotab_obj));
243 lnotab = (unsigned char*)PyBytes_AS_STRING(lnotab_obj);
244 tabsiz = PyBytes_GET_SIZE(lnotab_obj);
245 assert(tabsiz == 0 || Py_REFCNT(lnotab_obj) == 1);
246 if (memchr(lnotab, 255, tabsiz) != NULL) {
247 /* 255 value are used for multibyte bytecode instructions */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000248 goto exitUnchanged;
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100249 }
250 /* Note: -128 and 127 special values for line number delta are ok,
251 the peephole optimizer doesn't modify line numbers. */
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000252
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000253 assert(PyBytes_Check(code));
254 codelen = PyBytes_GET_SIZE(code);
Serhiy Storchakaab874002016-09-11 13:48:15 +0300255 assert(codelen % sizeof(_Py_CODEUNIT) == 0);
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000256
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000257 /* Make a modifiable copy of the code string */
Serhiy Storchakaab874002016-09-11 13:48:15 +0300258 codestr = (_Py_CODEUNIT *)PyMem_Malloc(codelen);
Victor Stinnere0af3a82013-07-09 00:32:04 +0200259 if (codestr == NULL) {
260 PyErr_NoMemory();
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000261 goto exitError;
Victor Stinnere0af3a82013-07-09 00:32:04 +0200262 }
Serhiy Storchakaab874002016-09-11 13:48:15 +0300263 memcpy(codestr, PyBytes_AS_STRING(code), codelen);
264 codelen /= sizeof(_Py_CODEUNIT);
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000265
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000266 blocks = markblocks(codestr, codelen);
267 if (blocks == NULL)
268 goto exitError;
269 assert(PyList_Check(consts));
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000270
Miss Islington (bot)f16ebcd2018-11-08 18:13:14 -0800271 for (i=find_op(codestr, codelen, 0) ; i<codelen ; i=nexti) {
Serhiy Storchakaa1e9ab32016-09-11 15:19:12 +0300272 opcode = _Py_OPCODE(codestr[i]);
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300273 op_start = i;
Serhiy Storchakaab874002016-09-11 13:48:15 +0300274 while (op_start >= 1 && _Py_OPCODE(codestr[op_start-1]) == EXTENDED_ARG) {
275 op_start--;
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300276 }
277
Serhiy Storchakaab874002016-09-11 13:48:15 +0300278 nexti = i + 1;
279 while (nexti < codelen && _Py_OPCODE(codestr[nexti]) == EXTENDED_ARG)
280 nexti++;
281 nextop = nexti < codelen ? _Py_OPCODE(codestr[nexti]) : 0;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000282
INADA Naoki87010e82017-12-18 15:52:54 +0900283 lastlc = cumlc;
284 cumlc = 0;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000285
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000286 switch (opcode) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000287 /* Skip over LOAD_CONST trueconst
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300288 POP_JUMP_IF_FALSE xx. This improves
289 "while 1" performance. */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000290 case LOAD_CONST:
INADA Naoki87010e82017-12-18 15:52:54 +0900291 cumlc = lastlc + 1;
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300292 if (nextop != POP_JUMP_IF_FALSE ||
Serhiy Storchakaab874002016-09-11 13:48:15 +0300293 !ISBASICBLOCK(blocks, op_start, i + 1) ||
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300294 !PyObject_IsTrue(PyList_GET_ITEM(consts, get_arg(codestr, i))))
295 break;
Serhiy Storchakaab874002016-09-11 13:48:15 +0300296 fill_nops(codestr, op_start, nexti + 1);
INADA Naoki87010e82017-12-18 15:52:54 +0900297 cumlc = 0;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000298 break;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000299
Serhiy Storchaka15a87282017-12-14 20:24:31 +0200300 /* Try to fold tuples of constants.
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000301 Skip over BUILD_SEQN 1 UNPACK_SEQN 1.
302 Replace BUILD_SEQN 2 UNPACK_SEQN 2 with ROT2.
303 Replace BUILD_SEQN 3 UNPACK_SEQN 3 with ROT3 ROT2. */
304 case BUILD_TUPLE:
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300305 j = get_arg(codestr, i);
INADA Naoki87010e82017-12-18 15:52:54 +0900306 if (j > 0 && lastlc >= j) {
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300307 h = lastn_const_start(codestr, op_start, j);
Serhiy Storchaka15a87282017-12-14 20:24:31 +0200308 if (ISBASICBLOCK(blocks, h, op_start)) {
Miss Islington (bot)f16ebcd2018-11-08 18:13:14 -0800309 h = fold_tuple_on_constants(codestr, codelen,
310 h, i+1, consts, j);
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300311 break;
312 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000313 }
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300314 if (nextop != UNPACK_SEQUENCE ||
Serhiy Storchakaab874002016-09-11 13:48:15 +0300315 !ISBASICBLOCK(blocks, op_start, i + 1) ||
Serhiy Storchaka15a87282017-12-14 20:24:31 +0200316 j != get_arg(codestr, nexti))
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300317 break;
318 if (j < 2) {
Serhiy Storchakaab874002016-09-11 13:48:15 +0300319 fill_nops(codestr, op_start, nexti + 1);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000320 } else if (j == 2) {
Serhiy Storchakaab874002016-09-11 13:48:15 +0300321 codestr[op_start] = PACKOPARG(ROT_TWO, 0);
322 fill_nops(codestr, op_start + 1, nexti + 1);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000323 } else if (j == 3) {
Serhiy Storchakaab874002016-09-11 13:48:15 +0300324 codestr[op_start] = PACKOPARG(ROT_THREE, 0);
325 codestr[op_start + 1] = PACKOPARG(ROT_TWO, 0);
326 fill_nops(codestr, op_start + 2, nexti + 1);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000327 }
328 break;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000329
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000330 /* Simplify conditional jump to conditional jump where the
331 result of the first test implies the success of a similar
332 test or the failure of the opposite test.
333 Arises in code like:
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000334 "a and b or c"
335 "(a and b) and c"
Serhiy Storchaka36ff4512017-06-11 14:50:22 +0300336 "(a or b) or c"
337 "(a or b) and c"
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000338 x:JUMP_IF_FALSE_OR_POP y y:JUMP_IF_FALSE_OR_POP z
339 --> x:JUMP_IF_FALSE_OR_POP z
340 x:JUMP_IF_FALSE_OR_POP y y:JUMP_IF_TRUE_OR_POP z
Serhiy Storchakaab874002016-09-11 13:48:15 +0300341 --> x:POP_JUMP_IF_FALSE y+1
342 where y+1 is the instruction following the second test.
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000343 */
344 case JUMP_IF_FALSE_OR_POP:
345 case JUMP_IF_TRUE_OR_POP:
Serhiy Storchakaab874002016-09-11 13:48:15 +0300346 h = get_arg(codestr, i) / sizeof(_Py_CODEUNIT);
Miss Islington (bot)f16ebcd2018-11-08 18:13:14 -0800347 tgt = find_op(codestr, codelen, h);
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300348
Serhiy Storchakaab874002016-09-11 13:48:15 +0300349 j = _Py_OPCODE(codestr[tgt]);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000350 if (CONDITIONAL_JUMP(j)) {
Raymond Hettinger08eef3f2016-08-07 20:20:33 -0700351 /* NOTE: all possible jumps here are absolute. */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000352 if (JUMPS_ON_TRUE(j) == JUMPS_ON_TRUE(opcode)) {
Raymond Hettinger08eef3f2016-08-07 20:20:33 -0700353 /* The second jump will be taken iff the first is.
354 The current opcode inherits its target's
355 stack effect */
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300356 h = set_arg(codestr, i, get_arg(codestr, tgt));
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000357 } else {
Raymond Hettinger08eef3f2016-08-07 20:20:33 -0700358 /* The second jump is not taken if the first is (so
359 jump past it), and all conditional jumps pop their
360 argument when they're not taken (so change the
361 first jump to pop its argument when it's taken). */
Serhiy Storchakaab874002016-09-11 13:48:15 +0300362 h = set_arg(codestr, i, (tgt + 1) * sizeof(_Py_CODEUNIT));
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300363 j = opcode == JUMP_IF_TRUE_OR_POP ?
364 POP_JUMP_IF_TRUE : POP_JUMP_IF_FALSE;
365 }
366
367 if (h >= 0) {
368 nexti = h;
Serhiy Storchakaab874002016-09-11 13:48:15 +0300369 codestr[nexti] = PACKOPARG(j, _Py_OPARG(codestr[nexti]));
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300370 break;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000371 }
372 }
373 /* Intentional fallthrough */
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000374
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000375 /* Replace jumps to unconditional jumps */
376 case POP_JUMP_IF_FALSE:
377 case POP_JUMP_IF_TRUE:
378 case FOR_ITER:
379 case JUMP_FORWARD:
380 case JUMP_ABSOLUTE:
381 case CONTINUE_LOOP:
382 case SETUP_LOOP:
383 case SETUP_EXCEPT:
384 case SETUP_FINALLY:
385 case SETUP_WITH:
Yury Selivanov75445082015-05-11 22:57:16 -0400386 case SETUP_ASYNC_WITH:
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300387 h = GETJUMPTGT(codestr, i);
Miss Islington (bot)f16ebcd2018-11-08 18:13:14 -0800388 tgt = find_op(codestr, codelen, h);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000389 /* Replace JUMP_* to a RETURN into just a RETURN */
390 if (UNCONDITIONAL_JUMP(opcode) &&
Serhiy Storchakaab874002016-09-11 13:48:15 +0300391 _Py_OPCODE(codestr[tgt]) == RETURN_VALUE) {
392 codestr[op_start] = PACKOPARG(RETURN_VALUE, 0);
393 fill_nops(codestr, op_start + 1, i + 1);
394 } else if (UNCONDITIONAL_JUMP(_Py_OPCODE(codestr[tgt]))) {
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300395 j = GETJUMPTGT(codestr, tgt);
396 if (opcode == JUMP_FORWARD) { /* JMP_ABS can go backwards */
397 opcode = JUMP_ABSOLUTE;
398 } else if (!ABSOLUTE_JUMP(opcode)) {
Serhiy Storchakaab874002016-09-11 13:48:15 +0300399 if ((Py_ssize_t)j < i + 1) {
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300400 break; /* No backward relative jumps */
401 }
Serhiy Storchakaab874002016-09-11 13:48:15 +0300402 j -= i + 1; /* Calc relative jump addr */
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300403 }
Serhiy Storchakaab874002016-09-11 13:48:15 +0300404 j *= sizeof(_Py_CODEUNIT);
405 copy_op_arg(codestr, op_start, opcode, j, i + 1);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000406 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000407 break;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000408
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300409 /* Remove unreachable ops after RETURN */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000410 case RETURN_VALUE:
Serhiy Storchakaab874002016-09-11 13:48:15 +0300411 h = i + 1;
Serhiy Storchaka7db3c482016-10-25 09:30:43 +0300412 while (h < codelen && ISBASICBLOCK(blocks, i, h)) {
Serhiy Storchakaab874002016-09-11 13:48:15 +0300413 h++;
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300414 }
Serhiy Storchakaab874002016-09-11 13:48:15 +0300415 if (h > i + 1) {
Serhiy Storchaka7db3c482016-10-25 09:30:43 +0300416 fill_nops(codestr, i + 1, h);
Miss Islington (bot)f16ebcd2018-11-08 18:13:14 -0800417 nexti = find_op(codestr, codelen, h);
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300418 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000419 break;
420 }
421 }
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000422
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100423 /* Fixup lnotab */
Serhiy Storchakaab874002016-09-11 13:48:15 +0300424 for (i = 0, nops = 0; i < codelen; i++) {
Serhiy Storchaka67559bf2015-02-16 21:13:24 +0200425 assert(i - nops <= INT_MAX);
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100426 /* original code offset => new code offset */
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300427 blocks[i] = i - nops;
Serhiy Storchakaab874002016-09-11 13:48:15 +0300428 if (_Py_OPCODE(codestr[i]) == NOP)
429 nops++;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000430 }
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100431 cum_orig_offset = 0;
432 last_offset = 0;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000433 for (i=0 ; i < tabsiz ; i+=2) {
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300434 unsigned int offset_delta, new_offset;
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100435 cum_orig_offset += lnotab[i];
Serhiy Storchakaab874002016-09-11 13:48:15 +0300436 assert(cum_orig_offset % sizeof(_Py_CODEUNIT) == 0);
437 new_offset = blocks[cum_orig_offset / sizeof(_Py_CODEUNIT)] *
438 sizeof(_Py_CODEUNIT);
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100439 offset_delta = new_offset - last_offset;
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300440 assert(offset_delta <= 255);
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100441 lnotab[i] = (unsigned char)offset_delta;
442 last_offset = new_offset;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000443 }
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000444
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000445 /* Remove NOPs and fixup jump targets */
Serhiy Storchakaab874002016-09-11 13:48:15 +0300446 for (op_start = i = h = 0; i < codelen; i++, op_start = i) {
447 j = _Py_OPARG(codestr[i]);
448 while (_Py_OPCODE(codestr[i]) == EXTENDED_ARG) {
449 i++;
450 j = j<<8 | _Py_OPARG(codestr[i]);
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300451 }
Serhiy Storchakaab874002016-09-11 13:48:15 +0300452 opcode = _Py_OPCODE(codestr[i]);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000453 switch (opcode) {
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300454 case NOP:continue;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000455
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000456 case JUMP_ABSOLUTE:
457 case CONTINUE_LOOP:
458 case POP_JUMP_IF_FALSE:
459 case POP_JUMP_IF_TRUE:
460 case JUMP_IF_FALSE_OR_POP:
461 case JUMP_IF_TRUE_OR_POP:
Serhiy Storchakaab874002016-09-11 13:48:15 +0300462 j = blocks[j / sizeof(_Py_CODEUNIT)] * sizeof(_Py_CODEUNIT);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000463 break;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000464
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000465 case FOR_ITER:
466 case JUMP_FORWARD:
467 case SETUP_LOOP:
468 case SETUP_EXCEPT:
469 case SETUP_FINALLY:
470 case SETUP_WITH:
Yury Selivanov75445082015-05-11 22:57:16 -0400471 case SETUP_ASYNC_WITH:
Serhiy Storchakaab874002016-09-11 13:48:15 +0300472 j = blocks[j / sizeof(_Py_CODEUNIT) + i + 1] - blocks[i] - 1;
473 j *= sizeof(_Py_CODEUNIT);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000474 break;
475 }
Serhiy Storchakaab874002016-09-11 13:48:15 +0300476 nexti = i - op_start + 1;
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300477 if (instrsize(j) > nexti)
478 goto exitUnchanged;
479 /* If instrsize(j) < nexti, we'll emit EXTENDED_ARG 0 */
480 write_op_arg(codestr + h, opcode, j, nexti);
481 h += nexti;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000482 }
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300483 assert(h + (Py_ssize_t)nops == codelen);
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000484
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000485 PyMem_Free(blocks);
Serhiy Storchakaab874002016-09-11 13:48:15 +0300486 code = PyBytes_FromStringAndSize((char *)codestr, h * sizeof(_Py_CODEUNIT));
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300487 PyMem_Free(codestr);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000488 return code;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000489
Alexandre Vassalotti6f828182009-07-21 02:51:58 +0000490 exitError:
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000491 code = NULL;
Alexandre Vassalotti6f828182009-07-21 02:51:58 +0000492
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000493 exitUnchanged:
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300494 Py_XINCREF(code);
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100495 PyMem_Free(blocks);
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100496 PyMem_Free(codestr);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000497 return code;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000498}