Line data Source code
1 : /* Peephole optimizations for bytecode compiler. */
2 :
3 : #include "Python.h"
4 :
5 : #include "Python-ast.h"
6 : #include "node.h"
7 : #include "ast.h"
8 : #include "code.h"
9 : #include "symtable.h"
10 : #include "opcode.h"
11 :
12 : #define GETARG(arr, i) ((int)((arr[i+2]<<8) + arr[i+1]))
13 : #define UNCONDITIONAL_JUMP(op) (op==JUMP_ABSOLUTE || op==JUMP_FORWARD)
14 : #define CONDITIONAL_JUMP(op) (op==POP_JUMP_IF_FALSE || op==POP_JUMP_IF_TRUE \
15 : || op==JUMP_IF_FALSE_OR_POP || op==JUMP_IF_TRUE_OR_POP)
16 : #define ABSOLUTE_JUMP(op) (op==JUMP_ABSOLUTE || op==CONTINUE_LOOP \
17 : || op==POP_JUMP_IF_FALSE || op==POP_JUMP_IF_TRUE \
18 : || op==JUMP_IF_FALSE_OR_POP || op==JUMP_IF_TRUE_OR_POP)
19 : #define JUMPS_ON_TRUE(op) (op==POP_JUMP_IF_TRUE || op==JUMP_IF_TRUE_OR_POP)
20 : #define GETJUMPTGT(arr, i) (GETARG(arr,i) + (ABSOLUTE_JUMP(arr[i]) ? 0 : i+3))
21 : #define SETARG(arr, i, val) arr[i+2] = val>>8; arr[i+1] = val & 255
22 : #define CODESIZE(op) (HAS_ARG(op) ? 3 : 1)
23 : #define ISBASICBLOCK(blocks, start, bytes) \
24 : (blocks[start]==blocks[start+bytes-1])
25 :
26 :
27 : #define CONST_STACK_CREATE() { \
28 : const_stack_size = 256; \
29 : const_stack = PyMem_New(PyObject *, const_stack_size); \
30 : load_const_stack = PyMem_New(Py_ssize_t, const_stack_size); \
31 : if (!const_stack || !load_const_stack) { \
32 : PyErr_NoMemory(); \
33 : goto exitError; \
34 : } \
35 : }
36 :
37 : #define CONST_STACK_DELETE() do { \
38 : if (const_stack) \
39 : PyMem_Free(const_stack); \
40 : if (load_const_stack) \
41 : PyMem_Free(load_const_stack); \
42 : } while(0)
43 :
44 : #define CONST_STACK_LEN() (const_stack_top + 1)
45 :
46 : #define CONST_STACK_PUSH_OP(i) do { \
47 : PyObject *_x; \
48 : assert(codestr[i] == LOAD_CONST); \
49 : assert(PyList_GET_SIZE(consts) > GETARG(codestr, i)); \
50 : _x = PyList_GET_ITEM(consts, GETARG(codestr, i)); \
51 : if (++const_stack_top >= const_stack_size) { \
52 : const_stack_size *= 2; \
53 : PyMem_Resize(const_stack, PyObject *, const_stack_size); \
54 : PyMem_Resize(load_const_stack, Py_ssize_t, const_stack_size); \
55 : if (!const_stack || !load_const_stack) { \
56 : PyErr_NoMemory(); \
57 : goto exitError; \
58 : } \
59 : } \
60 : load_const_stack[const_stack_top] = i; \
61 : const_stack[const_stack_top] = _x; \
62 : in_consts = 1; \
63 : } while(0)
64 :
65 : #define CONST_STACK_RESET() do { \
66 : const_stack_top = -1; \
67 : } while(0)
68 :
69 : #define CONST_STACK_TOP() \
70 : const_stack[const_stack_top]
71 :
72 : #define CONST_STACK_LASTN(i) \
73 : &const_stack[const_stack_top - i + 1]
74 :
75 : #define CONST_STACK_POP(i) do { \
76 : assert(const_stack_top + 1 >= i); \
77 : const_stack_top -= i; \
78 : } while(0)
79 :
80 : #define CONST_STACK_OP_LASTN(i) \
81 : ((const_stack_top >= i - 1) ? load_const_stack[const_stack_top - i + 1] : -1)
82 :
83 :
84 : /* Replace LOAD_CONST c1. LOAD_CONST c2 ... LOAD_CONST cn BUILD_TUPLE n
85 : with LOAD_CONST (c1, c2, ... cn).
86 : The consts table must still be in list form so that the
87 : new constant (c1, c2, ... cn) can be appended.
88 : Called with codestr pointing to the first LOAD_CONST.
89 : Bails out with no change if one or more of the LOAD_CONSTs is missing.
90 : Also works for BUILD_LIST and BUILT_SET when followed by an "in" or "not in"
91 : test; for BUILD_SET it assembles a frozenset rather than a tuple.
92 : */
93 : static int
94 6 : tuple_of_constants(unsigned char *codestr, Py_ssize_t n,
95 : PyObject *consts, PyObject **objs)
96 : {
97 : PyObject *newconst, *constant;
98 : Py_ssize_t i, len_consts;
99 :
100 : /* Pre-conditions */
101 : assert(PyList_CheckExact(consts));
102 :
103 : /* Buildup new tuple of constants */
104 6 : newconst = PyTuple_New(n);
105 6 : if (newconst == NULL)
106 0 : return 0;
107 6 : len_consts = PyList_GET_SIZE(consts);
108 26 : for (i=0 ; i<n ; i++) {
109 20 : constant = objs[i];
110 20 : Py_INCREF(constant);
111 20 : PyTuple_SET_ITEM(newconst, i, constant);
112 : }
113 :
114 : /* If it's a BUILD_SET, use the PyTuple we just built to create a
115 : PyFrozenSet, and use that as the constant instead: */
116 6 : if (codestr[0] == BUILD_SET) {
117 0 : PyObject *tuple = newconst;
118 0 : newconst = PyFrozenSet_New(tuple);
119 0 : Py_DECREF(tuple);
120 0 : if (newconst == NULL)
121 0 : return 0;
122 : }
123 :
124 : /* Append folded constant onto consts */
125 6 : if (PyList_Append(consts, newconst)) {
126 0 : Py_DECREF(newconst);
127 0 : return 0;
128 : }
129 6 : Py_DECREF(newconst);
130 :
131 : /* Write NOPs over old LOAD_CONSTS and
132 : add a new LOAD_CONST newconst on top of the BUILD_TUPLE n */
133 6 : codestr[0] = LOAD_CONST;
134 6 : SETARG(codestr, 0, len_consts);
135 6 : return 1;
136 : }
137 :
138 : /* Replace LOAD_CONST c1. LOAD_CONST c2 BINOP
139 : with LOAD_CONST binop(c1,c2)
140 : The consts table must still be in list form so that the
141 : new constant can be appended.
142 : Called with codestr pointing to the BINOP.
143 : Abandons the transformation if the folding fails (i.e. 1+'a').
144 : If the new constant is a sequence, only folds when the size
145 : is below a threshold value. That keeps pyc files from
146 : becoming large in the presence of code like: (None,)*1000.
147 : */
148 : static int
149 0 : fold_binops_on_constants(unsigned char *codestr, PyObject *consts, PyObject **objs)
150 : {
151 : PyObject *newconst, *v, *w;
152 : Py_ssize_t len_consts, size;
153 : int opcode;
154 :
155 : /* Pre-conditions */
156 : assert(PyList_CheckExact(consts));
157 :
158 : /* Create new constant */
159 0 : v = objs[0];
160 0 : w = objs[1];
161 0 : opcode = codestr[0];
162 0 : switch (opcode) {
163 : case BINARY_POWER:
164 0 : newconst = PyNumber_Power(v, w, Py_None);
165 0 : break;
166 : case BINARY_MULTIPLY:
167 0 : newconst = PyNumber_Multiply(v, w);
168 0 : break;
169 : case BINARY_TRUE_DIVIDE:
170 0 : newconst = PyNumber_TrueDivide(v, w);
171 0 : break;
172 : case BINARY_FLOOR_DIVIDE:
173 0 : newconst = PyNumber_FloorDivide(v, w);
174 0 : break;
175 : case BINARY_MODULO:
176 0 : newconst = PyNumber_Remainder(v, w);
177 0 : break;
178 : case BINARY_ADD:
179 0 : newconst = PyNumber_Add(v, w);
180 0 : break;
181 : case BINARY_SUBTRACT:
182 0 : newconst = PyNumber_Subtract(v, w);
183 0 : break;
184 : case BINARY_SUBSCR:
185 0 : newconst = PyObject_GetItem(v, w);
186 0 : break;
187 : case BINARY_LSHIFT:
188 0 : newconst = PyNumber_Lshift(v, w);
189 0 : break;
190 : case BINARY_RSHIFT:
191 0 : newconst = PyNumber_Rshift(v, w);
192 0 : break;
193 : case BINARY_AND:
194 0 : newconst = PyNumber_And(v, w);
195 0 : break;
196 : case BINARY_XOR:
197 0 : newconst = PyNumber_Xor(v, w);
198 0 : break;
199 : case BINARY_OR:
200 0 : newconst = PyNumber_Or(v, w);
201 0 : break;
202 : default:
203 : /* Called with an unknown opcode */
204 0 : PyErr_Format(PyExc_SystemError,
205 : "unexpected binary operation %d on a constant",
206 : opcode);
207 0 : return 0;
208 : }
209 0 : if (newconst == NULL) {
210 0 : if(!PyErr_ExceptionMatches(PyExc_KeyboardInterrupt))
211 0 : PyErr_Clear();
212 0 : return 0;
213 : }
214 0 : size = PyObject_Size(newconst);
215 0 : if (size == -1) {
216 0 : if (PyErr_ExceptionMatches(PyExc_KeyboardInterrupt))
217 0 : return 0;
218 0 : PyErr_Clear();
219 0 : } else if (size > 20) {
220 0 : Py_DECREF(newconst);
221 0 : return 0;
222 : }
223 :
224 : /* Append folded constant into consts table */
225 0 : len_consts = PyList_GET_SIZE(consts);
226 0 : if (PyList_Append(consts, newconst)) {
227 0 : Py_DECREF(newconst);
228 0 : return 0;
229 : }
230 0 : Py_DECREF(newconst);
231 :
232 : /* Write NOP NOP NOP NOP LOAD_CONST newconst */
233 0 : codestr[-2] = LOAD_CONST;
234 0 : SETARG(codestr, -2, len_consts);
235 0 : return 1;
236 : }
237 :
238 : static int
239 1 : fold_unaryops_on_constants(unsigned char *codestr, PyObject *consts, PyObject *v)
240 : {
241 : PyObject *newconst;
242 : Py_ssize_t len_consts;
243 : int opcode;
244 :
245 : /* Pre-conditions */
246 : assert(PyList_CheckExact(consts));
247 : assert(codestr[0] == LOAD_CONST);
248 :
249 : /* Create new constant */
250 1 : opcode = codestr[3];
251 1 : switch (opcode) {
252 : case UNARY_NEGATIVE:
253 1 : newconst = PyNumber_Negative(v);
254 1 : break;
255 : case UNARY_INVERT:
256 0 : newconst = PyNumber_Invert(v);
257 0 : break;
258 : case UNARY_POSITIVE:
259 0 : newconst = PyNumber_Positive(v);
260 0 : break;
261 : default:
262 : /* Called with an unknown opcode */
263 0 : PyErr_Format(PyExc_SystemError,
264 : "unexpected unary operation %d on a constant",
265 : opcode);
266 0 : return 0;
267 : }
268 1 : if (newconst == NULL) {
269 0 : if(!PyErr_ExceptionMatches(PyExc_KeyboardInterrupt))
270 0 : PyErr_Clear();
271 0 : return 0;
272 : }
273 :
274 : /* Append folded constant into consts table */
275 1 : len_consts = PyList_GET_SIZE(consts);
276 1 : if (PyList_Append(consts, newconst)) {
277 0 : Py_DECREF(newconst);
278 0 : return 0;
279 : }
280 1 : Py_DECREF(newconst);
281 :
282 : /* Write NOP LOAD_CONST newconst */
283 1 : codestr[0] = NOP;
284 1 : codestr[1] = LOAD_CONST;
285 1 : SETARG(codestr, 1, len_consts);
286 1 : return 1;
287 : }
288 :
289 : static unsigned int *
290 30 : markblocks(unsigned char *code, Py_ssize_t len)
291 : {
292 30 : unsigned int *blocks = (unsigned int *)PyMem_Malloc(len*sizeof(int));
293 30 : int i,j, opcode, blockcnt = 0;
294 :
295 30 : if (blocks == NULL) {
296 0 : PyErr_NoMemory();
297 0 : return NULL;
298 : }
299 30 : memset(blocks, 0, len*sizeof(int));
300 :
301 : /* Mark labels in the first pass */
302 1163 : for (i=0 ; i<len ; i+=CODESIZE(opcode)) {
303 1133 : opcode = code[i];
304 1133 : switch (opcode) {
305 : case FOR_ITER:
306 : case JUMP_FORWARD:
307 : case JUMP_IF_FALSE_OR_POP:
308 : case JUMP_IF_TRUE_OR_POP:
309 : case POP_JUMP_IF_FALSE:
310 : case POP_JUMP_IF_TRUE:
311 : case JUMP_ABSOLUTE:
312 : case CONTINUE_LOOP:
313 : case SETUP_LOOP:
314 : case SETUP_EXCEPT:
315 : case SETUP_FINALLY:
316 : case SETUP_WITH:
317 64 : j = GETJUMPTGT(code, i);
318 64 : blocks[j] = 1;
319 64 : break;
320 : }
321 : }
322 : /* Build block numbers in the second pass */
323 3123 : for (i=0 ; i<len ; i++) {
324 3093 : blockcnt += blocks[i]; /* increment blockcnt over labels */
325 3093 : blocks[i] = blockcnt;
326 : }
327 30 : return blocks;
328 : }
329 :
330 : /* Helper to replace LOAD_NAME None/True/False with LOAD_CONST
331 : Returns: 0 if no change, 1 if change, -1 if error */
332 : static int
333 109 : load_global(unsigned char *codestr, Py_ssize_t i, char *name, PyObject *consts)
334 : {
335 : Py_ssize_t j;
336 : PyObject *obj;
337 109 : if (name == NULL)
338 0 : return 0;
339 109 : if (strcmp(name, "None") == 0)
340 0 : obj = Py_None;
341 109 : else if (strcmp(name, "True") == 0)
342 3 : obj = Py_True;
343 106 : else if (strcmp(name, "False") == 0)
344 2 : obj = Py_False;
345 : else
346 104 : return 0;
347 33 : for (j = 0; j < PyList_GET_SIZE(consts); j++) {
348 29 : if (PyList_GET_ITEM(consts, j) == obj)
349 1 : break;
350 : }
351 5 : if (j == PyList_GET_SIZE(consts)) {
352 4 : if (PyList_Append(consts, obj) < 0)
353 0 : return -1;
354 : }
355 : assert(PyList_GET_ITEM(consts, j) == obj);
356 5 : codestr[i] = LOAD_CONST;
357 5 : SETARG(codestr, i, j);
358 5 : return 1;
359 : }
360 :
361 : /* Perform basic peephole optimizations to components of a code object.
362 : The consts object should still be in list form to allow new constants
363 : to be appended.
364 :
365 : To keep the optimizer simple, it bails out (does nothing) for code that
366 : has a length over 32,700, and does not calculate extended arguments.
367 : That allows us to avoid overflow and sign issues. Likewise, it bails when
368 : the lineno table has complex encoding for gaps >= 255. EXTENDED_ARG can
369 : appear before MAKE_FUNCTION; in this case both opcodes are skipped.
370 : EXTENDED_ARG preceding any other opcode causes the optimizer to bail.
371 :
372 : Optimizations are restricted to simple transformations occuring within a
373 : single basic block. All transformations keep the code size the same or
374 : smaller. For those that reduce size, the gaps are initially filled with
375 : NOPs. Later those NOPs are removed and the jump addresses retargeted in
376 : a single pass. Line numbering is adjusted accordingly. */
377 :
378 : PyObject *
379 30 : PyCode_Optimize(PyObject *code, PyObject* consts, PyObject *names,
380 : PyObject *lineno_obj)
381 : {
382 : Py_ssize_t i, j, codelen;
383 : int nops, h, adj;
384 : int tgt, tgttgt, opcode;
385 30 : unsigned char *codestr = NULL;
386 : unsigned char *lineno;
387 30 : int *addrmap = NULL;
388 : int new_line, cum_orig_line, last_line, tabsiz;
389 30 : PyObject **const_stack = NULL;
390 30 : Py_ssize_t *load_const_stack = NULL;
391 30 : Py_ssize_t const_stack_top = -1;
392 30 : Py_ssize_t const_stack_size = 0;
393 30 : int in_consts = 0; /* whether we are in a LOAD_CONST sequence */
394 30 : unsigned int *blocks = NULL;
395 : char *name;
396 :
397 : /* Bail out if an exception is set */
398 30 : if (PyErr_Occurred())
399 0 : goto exitError;
400 :
401 : /* Bypass optimization when the lineno table is too complex */
402 : assert(PyBytes_Check(lineno_obj));
403 30 : lineno = (unsigned char*)PyBytes_AS_STRING(lineno_obj);
404 30 : tabsiz = PyBytes_GET_SIZE(lineno_obj);
405 30 : if (memchr(lineno, 255, tabsiz) != NULL)
406 0 : goto exitUnchanged;
407 :
408 : /* Avoid situations where jump retargeting could overflow */
409 : assert(PyBytes_Check(code));
410 30 : codelen = PyBytes_GET_SIZE(code);
411 30 : if (codelen > 32700)
412 0 : goto exitUnchanged;
413 :
414 : /* Make a modifiable copy of the code string */
415 30 : codestr = (unsigned char *)PyMem_Malloc(codelen);
416 30 : if (codestr == NULL)
417 0 : goto exitError;
418 60 : codestr = (unsigned char *)memcpy(codestr,
419 30 : PyBytes_AS_STRING(code), codelen);
420 :
421 : /* Verify that RETURN_VALUE terminates the codestring. This allows
422 : the various transformation patterns to look ahead several
423 : instructions without additional checks to make sure they are not
424 : looking beyond the end of the code string.
425 : */
426 30 : if (codestr[codelen-1] != RETURN_VALUE)
427 0 : goto exitUnchanged;
428 :
429 : /* Mapping to new jump targets after NOPs are removed */
430 30 : addrmap = (int *)PyMem_Malloc(codelen * sizeof(int));
431 30 : if (addrmap == NULL)
432 0 : goto exitError;
433 :
434 30 : blocks = markblocks(codestr, codelen);
435 30 : if (blocks == NULL)
436 0 : goto exitError;
437 : assert(PyList_Check(consts));
438 :
439 30 : CONST_STACK_CREATE();
440 :
441 1167 : for (i=0 ; i<codelen ; i += CODESIZE(codestr[i])) {
442 : reoptimize_current:
443 1143 : opcode = codestr[i];
444 :
445 1143 : if (!in_consts) {
446 905 : CONST_STACK_RESET();
447 : }
448 1143 : in_consts = 0;
449 :
450 1143 : switch (opcode) {
451 : /* Replace UNARY_NOT POP_JUMP_IF_FALSE
452 : with POP_JUMP_IF_TRUE */
453 : case UNARY_NOT:
454 0 : if (codestr[i+1] != POP_JUMP_IF_FALSE
455 0 : || !ISBASICBLOCK(blocks,i,4))
456 0 : continue;
457 0 : j = GETARG(codestr, i+1);
458 0 : codestr[i] = POP_JUMP_IF_TRUE;
459 0 : SETARG(codestr, i, j);
460 0 : codestr[i+3] = NOP;
461 0 : goto reoptimize_current;
462 :
463 : /* not a is b --> a is not b
464 : not a in b --> a not in b
465 : not a is not b --> a is b
466 : not a not in b --> a in b
467 : */
468 : case COMPARE_OP:
469 23 : j = GETARG(codestr, i);
470 29 : if (j < 6 || j > 9 ||
471 6 : codestr[i+3] != UNARY_NOT ||
472 0 : !ISBASICBLOCK(blocks,i,4))
473 23 : continue;
474 0 : SETARG(codestr, i, (j^1));
475 0 : codestr[i+3] = NOP;
476 0 : break;
477 :
478 : /* Replace LOAD_GLOBAL/LOAD_NAME None/True/False
479 : with LOAD_CONST None/True/False */
480 : case LOAD_NAME:
481 : case LOAD_GLOBAL:
482 109 : j = GETARG(codestr, i);
483 109 : name = _PyUnicode_AsString(PyTuple_GET_ITEM(names, j));
484 109 : h = load_global(codestr, i, name, consts);
485 109 : if (h < 0)
486 0 : goto exitError;
487 109 : else if (h == 0)
488 104 : continue;
489 5 : CONST_STACK_PUSH_OP(i);
490 5 : break;
491 :
492 : /* Skip over LOAD_CONST trueconst
493 : POP_JUMP_IF_FALSE xx. This improves
494 : "while 1" performance. */
495 : case LOAD_CONST:
496 226 : CONST_STACK_PUSH_OP(i);
497 226 : j = GETARG(codestr, i);
498 226 : if (codestr[i+3] != POP_JUMP_IF_FALSE ||
499 0 : !ISBASICBLOCK(blocks,i,6) ||
500 0 : !PyObject_IsTrue(PyList_GET_ITEM(consts, j)))
501 226 : continue;
502 0 : memset(codestr+i, NOP, 6);
503 0 : CONST_STACK_RESET();
504 0 : break;
505 :
506 : /* Try to fold tuples of constants (includes a case for lists and sets
507 : which are only used for "in" and "not in" tests).
508 : Skip over BUILD_SEQN 1 UNPACK_SEQN 1.
509 : Replace BUILD_SEQN 2 UNPACK_SEQN 2 with ROT2.
510 : Replace BUILD_SEQN 3 UNPACK_SEQN 3 with ROT3 ROT2. */
511 : case BUILD_TUPLE:
512 : case BUILD_LIST:
513 : case BUILD_SET:
514 15 : j = GETARG(codestr, i);
515 15 : if (j == 0)
516 5 : break;
517 10 : h = CONST_STACK_OP_LASTN(j);
518 : assert((h >= 0 || CONST_STACK_LEN() < j));
519 10 : if (h >= 0 && j > 0 && j <= CONST_STACK_LEN() &&
520 6 : ((opcode == BUILD_TUPLE &&
521 6 : ISBASICBLOCK(blocks, h, i-h+3)) ||
522 0 : ((opcode == BUILD_LIST || opcode == BUILD_SET) &&
523 0 : codestr[i+3]==COMPARE_OP &&
524 0 : ISBASICBLOCK(blocks, h, i-h+6) &&
525 0 : (GETARG(codestr,i+3)==6 ||
526 6 : GETARG(codestr,i+3)==7))) &&
527 6 : tuple_of_constants(&codestr[i], j, consts, CONST_STACK_LASTN(j))) {
528 : assert(codestr[i] == LOAD_CONST);
529 6 : memset(&codestr[h], NOP, i - h);
530 6 : CONST_STACK_POP(j);
531 6 : CONST_STACK_PUSH_OP(i);
532 6 : break;
533 : }
534 4 : if (codestr[i+3] != UNPACK_SEQUENCE ||
535 0 : !ISBASICBLOCK(blocks,i,6) ||
536 0 : j != GETARG(codestr, i+3) ||
537 : opcode == BUILD_SET)
538 4 : continue;
539 0 : if (j == 1) {
540 0 : memset(codestr+i, NOP, 6);
541 0 : } else if (j == 2) {
542 0 : codestr[i] = ROT_TWO;
543 0 : memset(codestr+i+1, NOP, 5);
544 0 : CONST_STACK_RESET();
545 0 : } else if (j == 3) {
546 0 : codestr[i] = ROT_THREE;
547 0 : codestr[i+1] = ROT_TWO;
548 0 : memset(codestr+i+2, NOP, 4);
549 0 : CONST_STACK_RESET();
550 : }
551 0 : break;
552 :
553 : /* Fold binary ops on constants.
554 : LOAD_CONST c1 LOAD_CONST c2 BINOP --> LOAD_CONST binop(c1,c2) */
555 : case BINARY_POWER:
556 : case BINARY_MULTIPLY:
557 : case BINARY_TRUE_DIVIDE:
558 : case BINARY_FLOOR_DIVIDE:
559 : case BINARY_MODULO:
560 : case BINARY_ADD:
561 : case BINARY_SUBTRACT:
562 : case BINARY_SUBSCR:
563 : case BINARY_LSHIFT:
564 : case BINARY_RSHIFT:
565 : case BINARY_AND:
566 : case BINARY_XOR:
567 : case BINARY_OR:
568 : /* NOTE: LOAD_CONST is saved at `i-2` since it has an arg
569 : while BINOP hasn't */
570 39 : h = CONST_STACK_OP_LASTN(2);
571 : assert((h >= 0 || CONST_STACK_LEN() < 2));
572 39 : if (h >= 0 &&
573 0 : ISBASICBLOCK(blocks, h, i-h+1) &&
574 0 : fold_binops_on_constants(&codestr[i], consts, CONST_STACK_LASTN(2))) {
575 0 : i -= 2;
576 0 : memset(&codestr[h], NOP, i - h);
577 : assert(codestr[i] == LOAD_CONST);
578 0 : CONST_STACK_POP(2);
579 0 : CONST_STACK_PUSH_OP(i);
580 : }
581 39 : break;
582 :
583 : /* Fold unary ops on constants.
584 : LOAD_CONST c1 UNARY_OP --> LOAD_CONST unary_op(c) */
585 : case UNARY_NEGATIVE:
586 : case UNARY_INVERT:
587 : case UNARY_POSITIVE:
588 1 : h = CONST_STACK_OP_LASTN(1);
589 : assert((h >= 0 || CONST_STACK_LEN() < 1));
590 2 : if (h >= 0 &&
591 2 : ISBASICBLOCK(blocks, h, i-h+1) &&
592 1 : fold_unaryops_on_constants(&codestr[i-3], consts, CONST_STACK_TOP())) {
593 1 : i -= 2;
594 : assert(codestr[i] == LOAD_CONST);
595 1 : CONST_STACK_POP(1);
596 1 : CONST_STACK_PUSH_OP(i);
597 : }
598 1 : break;
599 :
600 : /* Simplify conditional jump to conditional jump where the
601 : result of the first test implies the success of a similar
602 : test or the failure of the opposite test.
603 : Arises in code like:
604 : "if a and b:"
605 : "if a or b:"
606 : "a and b or c"
607 : "(a and b) and c"
608 : x:JUMP_IF_FALSE_OR_POP y y:JUMP_IF_FALSE_OR_POP z
609 : --> x:JUMP_IF_FALSE_OR_POP z
610 : x:JUMP_IF_FALSE_OR_POP y y:JUMP_IF_TRUE_OR_POP z
611 : --> x:POP_JUMP_IF_FALSE y+3
612 : where y+3 is the instruction following the second test.
613 : */
614 : case JUMP_IF_FALSE_OR_POP:
615 : case JUMP_IF_TRUE_OR_POP:
616 6 : tgt = GETJUMPTGT(codestr, i);
617 6 : j = codestr[tgt];
618 6 : if (CONDITIONAL_JUMP(j)) {
619 : /* NOTE: all possible jumps here are
620 : absolute! */
621 6 : if (JUMPS_ON_TRUE(j) == JUMPS_ON_TRUE(opcode)) {
622 : /* The second jump will be
623 : taken iff the first is. */
624 5 : tgttgt = GETJUMPTGT(codestr, tgt);
625 : /* The current opcode inherits
626 : its target's stack behaviour */
627 5 : codestr[i] = j;
628 5 : SETARG(codestr, i, tgttgt);
629 5 : goto reoptimize_current;
630 : } else {
631 : /* The second jump is not taken
632 : if the first is (so jump past
633 : it), and all conditional
634 : jumps pop their argument when
635 : they're not taken (so change
636 : the first jump to pop its
637 : argument when it's taken). */
638 1 : if (JUMPS_ON_TRUE(opcode))
639 1 : codestr[i] = POP_JUMP_IF_TRUE;
640 : else
641 0 : codestr[i] = POP_JUMP_IF_FALSE;
642 1 : SETARG(codestr, i, (tgt + 3));
643 1 : goto reoptimize_current;
644 : }
645 : }
646 : /* Intentional fallthrough */
647 :
648 : /* Replace jumps to unconditional jumps */
649 : case POP_JUMP_IF_FALSE:
650 : case POP_JUMP_IF_TRUE:
651 : case FOR_ITER:
652 : case JUMP_FORWARD:
653 : case JUMP_ABSOLUTE:
654 : case CONTINUE_LOOP:
655 : case SETUP_LOOP:
656 : case SETUP_EXCEPT:
657 : case SETUP_FINALLY:
658 : case SETUP_WITH:
659 62 : tgt = GETJUMPTGT(codestr, i);
660 : /* Replace JUMP_* to a RETURN into just a RETURN */
661 87 : if (UNCONDITIONAL_JUMP(opcode) &&
662 25 : codestr[tgt] == RETURN_VALUE) {
663 0 : codestr[i] = RETURN_VALUE;
664 0 : memset(codestr+i+1, NOP, 2);
665 0 : continue;
666 : }
667 62 : if (!UNCONDITIONAL_JUMP(codestr[tgt]))
668 56 : continue;
669 6 : tgttgt = GETJUMPTGT(codestr, tgt);
670 6 : if (opcode == JUMP_FORWARD) /* JMP_ABS can go backwards */
671 4 : opcode = JUMP_ABSOLUTE;
672 6 : if (!ABSOLUTE_JUMP(opcode))
673 0 : tgttgt -= i + 3; /* Calc relative jump addr */
674 6 : if (tgttgt < 0) /* No backward relative jumps */
675 0 : continue;
676 6 : codestr[i] = opcode;
677 6 : SETARG(codestr, i, tgttgt);
678 6 : break;
679 :
680 : case EXTENDED_ARG:
681 0 : if (codestr[i+3] != MAKE_FUNCTION)
682 0 : goto exitUnchanged;
683 : /* don't visit MAKE_FUNCTION as GETARG will be wrong */
684 0 : i += 3;
685 0 : break;
686 :
687 : /* Replace RETURN LOAD_CONST None RETURN with just RETURN */
688 : /* Remove unreachable JUMPs after RETURN */
689 : case RETURN_VALUE:
690 35 : if (i+4 >= codelen)
691 30 : continue;
692 5 : if (codestr[i+4] == RETURN_VALUE &&
693 0 : ISBASICBLOCK(blocks,i,5))
694 0 : memset(codestr+i+1, NOP, 4);
695 7 : else if (UNCONDITIONAL_JUMP(codestr[i+1]) &&
696 2 : ISBASICBLOCK(blocks,i,4))
697 2 : memset(codestr+i+1, NOP, 3);
698 5 : break;
699 : }
700 : }
701 :
702 : /* Fixup linenotab */
703 1207 : for (i=0, nops=0 ; i<codelen ; i += CODESIZE(codestr[i])) {
704 1177 : addrmap[i] = i - nops;
705 1177 : if (codestr[i] == NOP)
706 67 : nops++;
707 : }
708 30 : cum_orig_line = 0;
709 30 : last_line = 0;
710 213 : for (i=0 ; i < tabsiz ; i+=2) {
711 183 : cum_orig_line += lineno[i];
712 183 : new_line = addrmap[cum_orig_line];
713 : assert (new_line - last_line < 255);
714 183 : lineno[i] =((unsigned char)(new_line - last_line));
715 183 : last_line = new_line;
716 : }
717 :
718 : /* Remove NOPs and fixup jump targets */
719 1237 : for (i=0, h=0 ; i<codelen ; ) {
720 1177 : opcode = codestr[i];
721 1177 : switch (opcode) {
722 : case NOP:
723 67 : i++;
724 67 : continue;
725 :
726 : case JUMP_ABSOLUTE:
727 : case CONTINUE_LOOP:
728 : case POP_JUMP_IF_FALSE:
729 : case POP_JUMP_IF_TRUE:
730 : case JUMP_IF_FALSE_OR_POP:
731 : case JUMP_IF_TRUE_OR_POP:
732 31 : j = addrmap[GETARG(codestr, i)];
733 31 : SETARG(codestr, i, j);
734 31 : break;
735 :
736 : case FOR_ITER:
737 : case JUMP_FORWARD:
738 : case SETUP_LOOP:
739 : case SETUP_EXCEPT:
740 : case SETUP_FINALLY:
741 : case SETUP_WITH:
742 31 : j = addrmap[GETARG(codestr, i) + i + 3] - addrmap[i] - 3;
743 31 : SETARG(codestr, i, j);
744 31 : break;
745 : }
746 1110 : adj = CODESIZE(opcode);
747 5246 : while (adj--)
748 3026 : codestr[h++] = codestr[i++];
749 : }
750 : assert(h + nops == codelen);
751 :
752 30 : code = PyBytes_FromStringAndSize((char *)codestr, h);
753 30 : CONST_STACK_DELETE();
754 30 : PyMem_Free(addrmap);
755 30 : PyMem_Free(codestr);
756 30 : PyMem_Free(blocks);
757 30 : return code;
758 :
759 : exitError:
760 0 : code = NULL;
761 :
762 : exitUnchanged:
763 0 : CONST_STACK_DELETE();
764 0 : if (blocks != NULL)
765 0 : PyMem_Free(blocks);
766 0 : if (addrmap != NULL)
767 0 : PyMem_Free(addrmap);
768 0 : if (codestr != NULL)
769 0 : PyMem_Free(codestr);
770 0 : Py_XINCREF(code);
771 0 : return code;
772 : }
|