Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
allendowney
GitHub Repository: allendowney/cpython
Path: blob/main/Python/flowgraph.c
12 views
1
2
#include <stdbool.h>
3
4
#include "Python.h"
5
#include "pycore_flowgraph.h"
6
#include "pycore_compile.h"
7
#include "pycore_pymem.h" // _PyMem_IsPtrFreed()
8
9
#include "pycore_opcode_utils.h"
10
#define NEED_OPCODE_METADATA
11
#include "opcode_metadata.h" // _PyOpcode_opcode_metadata, _PyOpcode_num_popped/pushed
12
#undef NEED_OPCODE_METADATA
13
14
15
#undef SUCCESS
16
#undef ERROR
17
#define SUCCESS 0
18
#define ERROR -1
19
20
#define RETURN_IF_ERROR(X) \
21
if ((X) == -1) { \
22
return ERROR; \
23
}
24
25
#define DEFAULT_BLOCK_SIZE 16
26
27
typedef _PyCompilerSrcLocation location;
28
typedef _PyCfgJumpTargetLabel jump_target_label;
29
typedef _PyCfgBasicblock basicblock;
30
typedef _PyCfgBuilder cfg_builder;
31
typedef _PyCfgInstruction cfg_instr;
32
33
static const jump_target_label NO_LABEL = {-1};
34
35
#define SAME_LABEL(L1, L2) ((L1).id == (L2).id)
36
#define IS_LABEL(L) (!SAME_LABEL((L), (NO_LABEL)))
37
38
39
static inline int
40
is_block_push(cfg_instr *i)
41
{
42
return IS_BLOCK_PUSH_OPCODE(i->i_opcode);
43
}
44
45
static inline int
46
is_jump(cfg_instr *i)
47
{
48
return OPCODE_HAS_JUMP(i->i_opcode);
49
}
50
51
/* One arg*/
52
#define INSTR_SET_OP1(I, OP, ARG) \
53
do { \
54
assert(OPCODE_HAS_ARG(OP)); \
55
_PyCfgInstruction *_instr__ptr_ = (I); \
56
_instr__ptr_->i_opcode = (OP); \
57
_instr__ptr_->i_oparg = (ARG); \
58
} while (0);
59
60
/* No args*/
61
#define INSTR_SET_OP0(I, OP) \
62
do { \
63
assert(!OPCODE_HAS_ARG(OP)); \
64
_PyCfgInstruction *_instr__ptr_ = (I); \
65
_instr__ptr_->i_opcode = (OP); \
66
_instr__ptr_->i_oparg = 0; \
67
} while (0);
68
69
/***** Blocks *****/
70
71
/* Returns the offset of the next instruction in the current block's
72
b_instr array. Resizes the b_instr as necessary.
73
Returns -1 on failure.
74
*/
75
static int
76
basicblock_next_instr(basicblock *b)
77
{
78
assert(b != NULL);
79
RETURN_IF_ERROR(
80
_PyCompile_EnsureArrayLargeEnough(
81
b->b_iused + 1,
82
(void**)&b->b_instr,
83
&b->b_ialloc,
84
DEFAULT_BLOCK_SIZE,
85
sizeof(cfg_instr)));
86
return b->b_iused++;
87
}
88
89
/* Allocate a new block and return a pointer to it.
90
Returns NULL on error.
91
*/
92
93
static basicblock *
94
cfg_builder_new_block(cfg_builder *g)
95
{
96
basicblock *b = (basicblock *)PyObject_Calloc(1, sizeof(basicblock));
97
if (b == NULL) {
98
PyErr_NoMemory();
99
return NULL;
100
}
101
/* Extend the singly linked list of blocks with new block. */
102
b->b_list = g->g_block_list;
103
g->g_block_list = b;
104
b->b_label = NO_LABEL;
105
return b;
106
}
107
108
static int
109
basicblock_addop(basicblock *b, int opcode, int oparg, location loc)
110
{
111
assert(IS_WITHIN_OPCODE_RANGE(opcode));
112
assert(!IS_ASSEMBLER_OPCODE(opcode));
113
assert(OPCODE_HAS_ARG(opcode) || HAS_TARGET(opcode) || oparg == 0);
114
assert(0 <= oparg && oparg < (1 << 30));
115
116
int off = basicblock_next_instr(b);
117
if (off < 0) {
118
return ERROR;
119
}
120
cfg_instr *i = &b->b_instr[off];
121
i->i_opcode = opcode;
122
i->i_oparg = oparg;
123
i->i_target = NULL;
124
i->i_loc = loc;
125
126
return SUCCESS;
127
}
128
129
static inline int
130
basicblock_append_instructions(basicblock *target, basicblock *source)
131
{
132
for (int i = 0; i < source->b_iused; i++) {
133
int n = basicblock_next_instr(target);
134
if (n < 0) {
135
return ERROR;
136
}
137
target->b_instr[n] = source->b_instr[i];
138
}
139
return SUCCESS;
140
}
141
142
static basicblock *
143
copy_basicblock(cfg_builder *g, basicblock *block)
144
{
145
/* Cannot copy a block if it has a fallthrough, since
146
* a block can only have one fallthrough predecessor.
147
*/
148
assert(BB_NO_FALLTHROUGH(block));
149
basicblock *result = cfg_builder_new_block(g);
150
if (result == NULL) {
151
return NULL;
152
}
153
if (basicblock_append_instructions(result, block) < 0) {
154
return NULL;
155
}
156
return result;
157
}
158
159
int
160
_PyBasicblock_InsertInstruction(basicblock *block, int pos, cfg_instr *instr) {
161
RETURN_IF_ERROR(basicblock_next_instr(block));
162
for (int i = block->b_iused - 1; i > pos; i--) {
163
block->b_instr[i] = block->b_instr[i-1];
164
}
165
block->b_instr[pos] = *instr;
166
return SUCCESS;
167
}
168
169
/* For debugging purposes only */
170
#if 0
171
static void
172
dump_instr(cfg_instr *i)
173
{
174
const char *jump = is_jump(i) ? "jump " : "";
175
176
char arg[128];
177
178
*arg = '\0';
179
if (OPCODE_HAS_ARG(i->i_opcode)) {
180
sprintf(arg, "arg: %d ", i->i_oparg);
181
}
182
if (HAS_TARGET(i->i_opcode)) {
183
sprintf(arg, "target: %p [%d] ", i->i_target, i->i_oparg);
184
}
185
fprintf(stderr, "line: %d, opcode: %d %s%s\n",
186
i->i_loc.lineno, i->i_opcode, arg, jump);
187
}
188
189
static inline int
190
basicblock_returns(const basicblock *b) {
191
cfg_instr *last = _PyCfg_BasicblockLastInstr(b);
192
return last && (last->i_opcode == RETURN_VALUE || last->i_opcode == RETURN_CONST);
193
}
194
195
static void
196
dump_basicblock(const basicblock *b)
197
{
198
const char *b_return = basicblock_returns(b) ? "return " : "";
199
fprintf(stderr, "%d: [EH=%d CLD=%d WRM=%d NO_FT=%d %p] used: %d, depth: %d, %s\n",
200
b->b_label.id, b->b_except_handler, b->b_cold, b->b_warm, BB_NO_FALLTHROUGH(b), b, b->b_iused,
201
b->b_startdepth, b_return);
202
if (b->b_instr) {
203
int i;
204
for (i = 0; i < b->b_iused; i++) {
205
fprintf(stderr, " [%02d] ", i);
206
dump_instr(b->b_instr + i);
207
}
208
}
209
}
210
211
void
212
_PyCfgBuilder_DumpGraph(const basicblock *entryblock)
213
{
214
for (const basicblock *b = entryblock; b != NULL; b = b->b_next) {
215
dump_basicblock(b);
216
}
217
}
218
219
#endif
220
221
222
/***** CFG construction and modification *****/
223
224
static basicblock *
225
cfg_builder_use_next_block(cfg_builder *g, basicblock *block)
226
{
227
assert(block != NULL);
228
g->g_curblock->b_next = block;
229
g->g_curblock = block;
230
return block;
231
}
232
233
cfg_instr *
234
_PyCfg_BasicblockLastInstr(const basicblock *b) {
235
assert(b->b_iused >= 0);
236
if (b->b_iused > 0) {
237
assert(b->b_instr != NULL);
238
return &b->b_instr[b->b_iused - 1];
239
}
240
return NULL;
241
}
242
243
static inline int
244
basicblock_exits_scope(const basicblock *b) {
245
cfg_instr *last = _PyCfg_BasicblockLastInstr(b);
246
return last && IS_SCOPE_EXIT_OPCODE(last->i_opcode);
247
}
248
249
static bool
250
cfg_builder_current_block_is_terminated(cfg_builder *g)
251
{
252
cfg_instr *last = _PyCfg_BasicblockLastInstr(g->g_curblock);
253
if (last && IS_TERMINATOR_OPCODE(last->i_opcode)) {
254
return true;
255
}
256
if (IS_LABEL(g->g_current_label)) {
257
if (last || IS_LABEL(g->g_curblock->b_label)) {
258
return true;
259
}
260
else {
261
/* current block is empty, label it */
262
g->g_curblock->b_label = g->g_current_label;
263
g->g_current_label = NO_LABEL;
264
}
265
}
266
return false;
267
}
268
269
static int
270
cfg_builder_maybe_start_new_block(cfg_builder *g)
271
{
272
if (cfg_builder_current_block_is_terminated(g)) {
273
basicblock *b = cfg_builder_new_block(g);
274
if (b == NULL) {
275
return ERROR;
276
}
277
b->b_label = g->g_current_label;
278
g->g_current_label = NO_LABEL;
279
cfg_builder_use_next_block(g, b);
280
}
281
return SUCCESS;
282
}
283
284
#ifndef NDEBUG
285
static bool
286
cfg_builder_check(cfg_builder *g)
287
{
288
assert(g->g_entryblock->b_iused > 0);
289
for (basicblock *block = g->g_block_list; block != NULL; block = block->b_list) {
290
assert(!_PyMem_IsPtrFreed(block));
291
if (block->b_instr != NULL) {
292
assert(block->b_ialloc > 0);
293
assert(block->b_iused >= 0);
294
assert(block->b_ialloc >= block->b_iused);
295
}
296
else {
297
assert (block->b_iused == 0);
298
assert (block->b_ialloc == 0);
299
}
300
}
301
return true;
302
}
303
#endif
304
305
int
306
_PyCfgBuilder_Init(cfg_builder *g)
307
{
308
g->g_block_list = NULL;
309
basicblock *block = cfg_builder_new_block(g);
310
if (block == NULL) {
311
return ERROR;
312
}
313
g->g_curblock = g->g_entryblock = block;
314
g->g_current_label = NO_LABEL;
315
return SUCCESS;
316
}
317
318
void
319
_PyCfgBuilder_Fini(cfg_builder* g)
320
{
321
assert(cfg_builder_check(g));
322
basicblock *b = g->g_block_list;
323
while (b != NULL) {
324
if (b->b_instr) {
325
PyObject_Free((void *)b->b_instr);
326
}
327
basicblock *next = b->b_list;
328
PyObject_Free((void *)b);
329
b = next;
330
}
331
}
332
333
int
334
_PyCfgBuilder_UseLabel(cfg_builder *g, jump_target_label lbl)
335
{
336
g->g_current_label = lbl;
337
return cfg_builder_maybe_start_new_block(g);
338
}
339
340
int
341
_PyCfgBuilder_Addop(cfg_builder *g, int opcode, int oparg, location loc)
342
{
343
RETURN_IF_ERROR(cfg_builder_maybe_start_new_block(g));
344
return basicblock_addop(g->g_curblock, opcode, oparg, loc);
345
}
346
347
348
/***** debugging helpers *****/
349
350
#ifndef NDEBUG
351
static int remove_redundant_nops(basicblock *bb);
352
353
static bool
354
no_redundant_nops(cfg_builder *g) {
355
for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) {
356
if (remove_redundant_nops(b) != 0) {
357
return false;
358
}
359
}
360
return true;
361
}
362
363
static bool
364
no_empty_basic_blocks(cfg_builder *g) {
365
for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) {
366
if (b->b_iused == 0) {
367
return false;
368
}
369
}
370
return true;
371
}
372
373
static bool
374
no_redundant_jumps(cfg_builder *g) {
375
for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) {
376
cfg_instr *last = _PyCfg_BasicblockLastInstr(b);
377
if (last != NULL) {
378
if (IS_UNCONDITIONAL_JUMP_OPCODE(last->i_opcode)) {
379
assert(last->i_target != b->b_next);
380
if (last->i_target == b->b_next) {
381
return false;
382
}
383
}
384
}
385
}
386
return true;
387
}
388
389
#endif
390
391
/***** CFG preprocessing (jump targets and exceptions) *****/
392
393
static int
394
normalize_jumps_in_block(cfg_builder *g, basicblock *b) {
395
cfg_instr *last = _PyCfg_BasicblockLastInstr(b);
396
if (last == NULL || !is_jump(last) ||
397
IS_UNCONDITIONAL_JUMP_OPCODE(last->i_opcode)) {
398
return SUCCESS;
399
}
400
assert(!IS_ASSEMBLER_OPCODE(last->i_opcode));
401
402
bool is_forward = last->i_target->b_visited == 0;
403
if (is_forward) {
404
return SUCCESS;
405
}
406
407
int reversed_opcode = 0;
408
switch(last->i_opcode) {
409
case POP_JUMP_IF_NOT_NONE:
410
reversed_opcode = POP_JUMP_IF_NONE;
411
break;
412
case POP_JUMP_IF_NONE:
413
reversed_opcode = POP_JUMP_IF_NOT_NONE;
414
break;
415
case POP_JUMP_IF_FALSE:
416
reversed_opcode = POP_JUMP_IF_TRUE;
417
break;
418
case POP_JUMP_IF_TRUE:
419
reversed_opcode = POP_JUMP_IF_FALSE;
420
break;
421
}
422
/* transform 'conditional jump T' to
423
* 'reversed_jump b_next' followed by 'jump_backwards T'
424
*/
425
426
basicblock *target = last->i_target;
427
basicblock *backwards_jump = cfg_builder_new_block(g);
428
if (backwards_jump == NULL) {
429
return ERROR;
430
}
431
basicblock_addop(backwards_jump, JUMP, target->b_label.id, NO_LOCATION);
432
backwards_jump->b_instr[0].i_target = target;
433
last->i_opcode = reversed_opcode;
434
last->i_target = b->b_next;
435
436
backwards_jump->b_cold = b->b_cold;
437
backwards_jump->b_next = b->b_next;
438
b->b_next = backwards_jump;
439
return SUCCESS;
440
}
441
442
443
static int
444
normalize_jumps(_PyCfgBuilder *g)
445
{
446
basicblock *entryblock = g->g_entryblock;
447
for (basicblock *b = entryblock; b != NULL; b = b->b_next) {
448
b->b_visited = 0;
449
}
450
for (basicblock *b = entryblock; b != NULL; b = b->b_next) {
451
b->b_visited = 1;
452
RETURN_IF_ERROR(normalize_jumps_in_block(g, b));
453
}
454
return SUCCESS;
455
}
456
457
int
458
_PyCfg_ResolveJumps(_PyCfgBuilder *g)
459
{
460
RETURN_IF_ERROR(normalize_jumps(g));
461
assert(no_redundant_jumps(g));
462
return SUCCESS;
463
}
464
465
static int
466
check_cfg(cfg_builder *g) {
467
for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) {
468
/* Raise SystemError if jump or exit is not last instruction in the block. */
469
for (int i = 0; i < b->b_iused; i++) {
470
int opcode = b->b_instr[i].i_opcode;
471
assert(!IS_ASSEMBLER_OPCODE(opcode));
472
if (IS_TERMINATOR_OPCODE(opcode)) {
473
if (i != b->b_iused - 1) {
474
PyErr_SetString(PyExc_SystemError, "malformed control flow graph.");
475
return ERROR;
476
}
477
}
478
}
479
}
480
return SUCCESS;
481
}
482
483
/* Calculate the actual jump target from the target_label */
484
static int
485
translate_jump_labels_to_targets(basicblock *entryblock)
486
{
487
int max_label = -1;
488
for (basicblock *b = entryblock; b != NULL; b = b->b_next) {
489
if (b->b_label.id > max_label) {
490
max_label = b->b_label.id;
491
}
492
}
493
size_t mapsize = sizeof(basicblock *) * (max_label + 1);
494
basicblock **label2block = (basicblock **)PyMem_Malloc(mapsize);
495
if (!label2block) {
496
PyErr_NoMemory();
497
return ERROR;
498
}
499
memset(label2block, 0, mapsize);
500
for (basicblock *b = entryblock; b != NULL; b = b->b_next) {
501
if (b->b_label.id >= 0) {
502
label2block[b->b_label.id] = b;
503
}
504
}
505
for (basicblock *b = entryblock; b != NULL; b = b->b_next) {
506
for (int i = 0; i < b->b_iused; i++) {
507
cfg_instr *instr = &b->b_instr[i];
508
assert(instr->i_target == NULL);
509
if (HAS_TARGET(instr->i_opcode)) {
510
int lbl = instr->i_oparg;
511
assert(lbl >= 0 && lbl <= max_label);
512
instr->i_target = label2block[lbl];
513
assert(instr->i_target != NULL);
514
assert(instr->i_target->b_label.id == lbl);
515
}
516
}
517
}
518
PyMem_Free(label2block);
519
return SUCCESS;
520
}
521
522
int
523
_PyCfg_JumpLabelsToTargets(basicblock *entryblock)
524
{
525
return translate_jump_labels_to_targets(entryblock);
526
}
527
528
static int
529
mark_except_handlers(basicblock *entryblock) {
530
#ifndef NDEBUG
531
for (basicblock *b = entryblock; b != NULL; b = b->b_next) {
532
assert(!b->b_except_handler);
533
}
534
#endif
535
for (basicblock *b = entryblock; b != NULL; b = b->b_next) {
536
for (int i=0; i < b->b_iused; i++) {
537
cfg_instr *instr = &b->b_instr[i];
538
if (is_block_push(instr)) {
539
instr->i_target->b_except_handler = 1;
540
}
541
}
542
}
543
return SUCCESS;
544
}
545
546
547
typedef _PyCfgExceptStack ExceptStack;
548
549
static basicblock *
550
push_except_block(ExceptStack *stack, cfg_instr *setup) {
551
assert(is_block_push(setup));
552
int opcode = setup->i_opcode;
553
basicblock * target = setup->i_target;
554
if (opcode == SETUP_WITH || opcode == SETUP_CLEANUP) {
555
target->b_preserve_lasti = 1;
556
}
557
stack->handlers[++stack->depth] = target;
558
return target;
559
}
560
561
static basicblock *
562
pop_except_block(ExceptStack *stack) {
563
assert(stack->depth > 0);
564
return stack->handlers[--stack->depth];
565
}
566
567
static basicblock *
568
except_stack_top(ExceptStack *stack) {
569
return stack->handlers[stack->depth];
570
}
571
572
static ExceptStack *
573
make_except_stack(void) {
574
ExceptStack *new = PyMem_Malloc(sizeof(ExceptStack));
575
if (new == NULL) {
576
PyErr_NoMemory();
577
return NULL;
578
}
579
new->depth = 0;
580
new->handlers[0] = NULL;
581
return new;
582
}
583
584
static ExceptStack *
585
copy_except_stack(ExceptStack *stack) {
586
ExceptStack *copy = PyMem_Malloc(sizeof(ExceptStack));
587
if (copy == NULL) {
588
PyErr_NoMemory();
589
return NULL;
590
}
591
memcpy(copy, stack, sizeof(ExceptStack));
592
return copy;
593
}
594
595
static basicblock**
596
make_cfg_traversal_stack(basicblock *entryblock) {
597
int nblocks = 0;
598
for (basicblock *b = entryblock; b != NULL; b = b->b_next) {
599
b->b_visited = 0;
600
nblocks++;
601
}
602
basicblock **stack = (basicblock **)PyMem_Malloc(sizeof(basicblock *) * nblocks);
603
if (!stack) {
604
PyErr_NoMemory();
605
}
606
return stack;
607
}
608
609
Py_LOCAL_INLINE(void)
610
stackdepth_push(basicblock ***sp, basicblock *b, int depth)
611
{
612
assert(b->b_startdepth < 0 || b->b_startdepth == depth);
613
if (b->b_startdepth < depth && b->b_startdepth < 100) {
614
assert(b->b_startdepth < 0);
615
b->b_startdepth = depth;
616
*(*sp)++ = b;
617
}
618
}
619
620
/* Find the flow path that needs the largest stack. We assume that
621
* cycles in the flow graph have no net effect on the stack depth.
622
*/
623
int
624
_PyCfg_Stackdepth(basicblock *entryblock, int code_flags)
625
{
626
for (basicblock *b = entryblock; b != NULL; b = b->b_next) {
627
b->b_startdepth = INT_MIN;
628
}
629
basicblock **stack = make_cfg_traversal_stack(entryblock);
630
if (!stack) {
631
return ERROR;
632
}
633
634
int maxdepth = 0;
635
basicblock **sp = stack;
636
if (code_flags & (CO_GENERATOR | CO_COROUTINE | CO_ASYNC_GENERATOR)) {
637
stackdepth_push(&sp, entryblock, 1);
638
} else {
639
stackdepth_push(&sp, entryblock, 0);
640
}
641
642
while (sp != stack) {
643
basicblock *b = *--sp;
644
int depth = b->b_startdepth;
645
assert(depth >= 0);
646
basicblock *next = b->b_next;
647
for (int i = 0; i < b->b_iused; i++) {
648
cfg_instr *instr = &b->b_instr[i];
649
int effect = PyCompile_OpcodeStackEffectWithJump(instr->i_opcode, instr->i_oparg, 0);
650
if (effect == PY_INVALID_STACK_EFFECT) {
651
PyErr_Format(PyExc_SystemError,
652
"compiler PyCompile_OpcodeStackEffectWithJump(opcode=%d, arg=%i) failed",
653
instr->i_opcode, instr->i_oparg);
654
return ERROR;
655
}
656
int new_depth = depth + effect;
657
assert(new_depth >= 0); /* invalid code or bug in stackdepth() */
658
if (new_depth > maxdepth) {
659
maxdepth = new_depth;
660
}
661
if (HAS_TARGET(instr->i_opcode)) {
662
effect = PyCompile_OpcodeStackEffectWithJump(instr->i_opcode, instr->i_oparg, 1);
663
assert(effect != PY_INVALID_STACK_EFFECT);
664
int target_depth = depth + effect;
665
assert(target_depth >= 0); /* invalid code or bug in stackdepth() */
666
if (target_depth > maxdepth) {
667
maxdepth = target_depth;
668
}
669
stackdepth_push(&sp, instr->i_target, target_depth);
670
}
671
depth = new_depth;
672
assert(!IS_ASSEMBLER_OPCODE(instr->i_opcode));
673
if (IS_UNCONDITIONAL_JUMP_OPCODE(instr->i_opcode) ||
674
IS_SCOPE_EXIT_OPCODE(instr->i_opcode))
675
{
676
/* remaining code is dead */
677
next = NULL;
678
break;
679
}
680
}
681
if (next != NULL) {
682
assert(BB_HAS_FALLTHROUGH(b));
683
stackdepth_push(&sp, next, depth);
684
}
685
}
686
PyMem_Free(stack);
687
return maxdepth;
688
}
689
690
static int
691
label_exception_targets(basicblock *entryblock) {
692
basicblock **todo_stack = make_cfg_traversal_stack(entryblock);
693
if (todo_stack == NULL) {
694
return ERROR;
695
}
696
ExceptStack *except_stack = make_except_stack();
697
if (except_stack == NULL) {
698
PyMem_Free(todo_stack);
699
PyErr_NoMemory();
700
return ERROR;
701
}
702
except_stack->depth = 0;
703
todo_stack[0] = entryblock;
704
entryblock->b_visited = 1;
705
entryblock->b_exceptstack = except_stack;
706
basicblock **todo = &todo_stack[1];
707
basicblock *handler = NULL;
708
while (todo > todo_stack) {
709
todo--;
710
basicblock *b = todo[0];
711
assert(b->b_visited == 1);
712
except_stack = b->b_exceptstack;
713
assert(except_stack != NULL);
714
b->b_exceptstack = NULL;
715
handler = except_stack_top(except_stack);
716
for (int i = 0; i < b->b_iused; i++) {
717
cfg_instr *instr = &b->b_instr[i];
718
if (is_block_push(instr)) {
719
if (!instr->i_target->b_visited) {
720
ExceptStack *copy = copy_except_stack(except_stack);
721
if (copy == NULL) {
722
goto error;
723
}
724
instr->i_target->b_exceptstack = copy;
725
todo[0] = instr->i_target;
726
instr->i_target->b_visited = 1;
727
todo++;
728
}
729
handler = push_except_block(except_stack, instr);
730
}
731
else if (instr->i_opcode == POP_BLOCK) {
732
handler = pop_except_block(except_stack);
733
}
734
else if (is_jump(instr)) {
735
instr->i_except = handler;
736
assert(i == b->b_iused -1);
737
if (!instr->i_target->b_visited) {
738
if (BB_HAS_FALLTHROUGH(b)) {
739
ExceptStack *copy = copy_except_stack(except_stack);
740
if (copy == NULL) {
741
goto error;
742
}
743
instr->i_target->b_exceptstack = copy;
744
}
745
else {
746
instr->i_target->b_exceptstack = except_stack;
747
except_stack = NULL;
748
}
749
todo[0] = instr->i_target;
750
instr->i_target->b_visited = 1;
751
todo++;
752
}
753
}
754
else {
755
if (instr->i_opcode == YIELD_VALUE) {
756
instr->i_oparg = except_stack->depth;
757
}
758
instr->i_except = handler;
759
}
760
}
761
if (BB_HAS_FALLTHROUGH(b) && !b->b_next->b_visited) {
762
assert(except_stack != NULL);
763
b->b_next->b_exceptstack = except_stack;
764
todo[0] = b->b_next;
765
b->b_next->b_visited = 1;
766
todo++;
767
}
768
else if (except_stack != NULL) {
769
PyMem_Free(except_stack);
770
}
771
}
772
#ifdef Py_DEBUG
773
for (basicblock *b = entryblock; b != NULL; b = b->b_next) {
774
assert(b->b_exceptstack == NULL);
775
}
776
#endif
777
PyMem_Free(todo_stack);
778
return SUCCESS;
779
error:
780
PyMem_Free(todo_stack);
781
PyMem_Free(except_stack);
782
return ERROR;
783
}
784
785
/***** CFG optimizations *****/
786
787
static int
788
mark_reachable(basicblock *entryblock) {
789
basicblock **stack = make_cfg_traversal_stack(entryblock);
790
if (stack == NULL) {
791
return ERROR;
792
}
793
basicblock **sp = stack;
794
entryblock->b_predecessors = 1;
795
*sp++ = entryblock;
796
while (sp > stack) {
797
basicblock *b = *(--sp);
798
b->b_visited = 1;
799
if (b->b_next && BB_HAS_FALLTHROUGH(b)) {
800
if (!b->b_next->b_visited) {
801
assert(b->b_next->b_predecessors == 0);
802
*sp++ = b->b_next;
803
}
804
b->b_next->b_predecessors++;
805
}
806
for (int i = 0; i < b->b_iused; i++) {
807
basicblock *target;
808
cfg_instr *instr = &b->b_instr[i];
809
if (is_jump(instr) || is_block_push(instr)) {
810
target = instr->i_target;
811
if (!target->b_visited) {
812
assert(target->b_predecessors == 0 || target == b->b_next);
813
*sp++ = target;
814
}
815
target->b_predecessors++;
816
}
817
}
818
}
819
PyMem_Free(stack);
820
return SUCCESS;
821
}
822
823
static void
824
eliminate_empty_basic_blocks(cfg_builder *g) {
825
/* Eliminate empty blocks */
826
for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) {
827
basicblock *next = b->b_next;
828
while (next && next->b_iused == 0) {
829
next = next->b_next;
830
}
831
b->b_next = next;
832
}
833
while(g->g_entryblock && g->g_entryblock->b_iused == 0) {
834
g->g_entryblock = g->g_entryblock->b_next;
835
}
836
for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) {
837
assert(b->b_iused > 0);
838
for (int i = 0; i < b->b_iused; i++) {
839
cfg_instr *instr = &b->b_instr[i];
840
if (HAS_TARGET(instr->i_opcode)) {
841
basicblock *target = instr->i_target;
842
while (target->b_iused == 0) {
843
target = target->b_next;
844
}
845
instr->i_target = target;
846
assert(instr->i_target && instr->i_target->b_iused > 0);
847
}
848
}
849
}
850
}
851
852
static int
853
remove_redundant_nops(basicblock *bb) {
854
/* Remove NOPs when legal to do so. */
855
int dest = 0;
856
int prev_lineno = -1;
857
for (int src = 0; src < bb->b_iused; src++) {
858
int lineno = bb->b_instr[src].i_loc.lineno;
859
if (bb->b_instr[src].i_opcode == NOP) {
860
/* Eliminate no-op if it doesn't have a line number */
861
if (lineno < 0) {
862
continue;
863
}
864
/* or, if the previous instruction had the same line number. */
865
if (prev_lineno == lineno) {
866
continue;
867
}
868
/* or, if the next instruction has same line number or no line number */
869
if (src < bb->b_iused - 1) {
870
int next_lineno = bb->b_instr[src+1].i_loc.lineno;
871
if (next_lineno == lineno) {
872
continue;
873
}
874
if (next_lineno < 0) {
875
bb->b_instr[src+1].i_loc = bb->b_instr[src].i_loc;
876
continue;
877
}
878
}
879
else {
880
basicblock* next = bb->b_next;
881
while (next && next->b_iused == 0) {
882
next = next->b_next;
883
}
884
/* or if last instruction in BB and next BB has same line number */
885
if (next) {
886
if (lineno == next->b_instr[0].i_loc.lineno) {
887
continue;
888
}
889
}
890
}
891
892
}
893
if (dest != src) {
894
bb->b_instr[dest] = bb->b_instr[src];
895
}
896
dest++;
897
prev_lineno = lineno;
898
}
899
assert(dest <= bb->b_iused);
900
int num_removed = bb->b_iused - dest;
901
bb->b_iused = dest;
902
return num_removed;
903
}
904
905
static int
906
remove_redundant_nops_and_pairs(basicblock *entryblock)
907
{
908
bool done = false;
909
910
while (! done) {
911
done = true;
912
cfg_instr *prev_instr = NULL;
913
cfg_instr *instr = NULL;
914
for (basicblock *b = entryblock; b != NULL; b = b->b_next) {
915
remove_redundant_nops(b);
916
if (IS_LABEL(b->b_label)) {
917
/* this block is a jump target, forget instr */
918
instr = NULL;
919
}
920
for (int i = 0; i < b->b_iused; i++) {
921
prev_instr = instr;
922
instr = &b->b_instr[i];
923
int prev_opcode = prev_instr ? prev_instr->i_opcode : 0;
924
int prev_oparg = prev_instr ? prev_instr->i_oparg : 0;
925
int opcode = instr->i_opcode;
926
bool is_redundant_pair = false;
927
if (opcode == POP_TOP) {
928
if (prev_opcode == LOAD_CONST) {
929
is_redundant_pair = true;
930
}
931
else if (prev_opcode == COPY && prev_oparg == 1) {
932
is_redundant_pair = true;
933
}
934
}
935
if (is_redundant_pair) {
936
INSTR_SET_OP0(prev_instr, NOP);
937
INSTR_SET_OP0(instr, NOP);
938
done = false;
939
}
940
}
941
if ((instr && is_jump(instr)) || !BB_HAS_FALLTHROUGH(b)) {
942
instr = NULL;
943
}
944
}
945
}
946
return SUCCESS;
947
}
948
949
static int
950
remove_redundant_jumps(cfg_builder *g) {
951
/* If a non-empty block ends with a jump instruction, check if the next
952
* non-empty block reached through normal flow control is the target
953
* of that jump. If it is, then the jump instruction is redundant and
954
* can be deleted.
955
*/
956
assert(no_empty_basic_blocks(g));
957
for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) {
958
cfg_instr *last = _PyCfg_BasicblockLastInstr(b);
959
assert(last != NULL);
960
assert(!IS_ASSEMBLER_OPCODE(last->i_opcode));
961
if (IS_UNCONDITIONAL_JUMP_OPCODE(last->i_opcode)) {
962
if (last->i_target == NULL) {
963
PyErr_SetString(PyExc_SystemError, "jump with NULL target");
964
return ERROR;
965
}
966
if (last->i_target == b->b_next) {
967
assert(b->b_next->b_iused);
968
INSTR_SET_OP0(last, NOP);
969
}
970
}
971
}
972
return SUCCESS;
973
}
974
975
/* Maximum size of basic block that should be copied in optimizer */
976
#define MAX_COPY_SIZE 4
977
978
/* If this block ends with an unconditional jump to a small exit block, then
979
* remove the jump and extend this block with the target.
980
* Returns 1 if extended, 0 if no change, and -1 on error.
981
*/
982
static int
983
inline_small_exit_blocks(basicblock *bb) {
984
cfg_instr *last = _PyCfg_BasicblockLastInstr(bb);
985
if (last == NULL) {
986
return 0;
987
}
988
if (!IS_UNCONDITIONAL_JUMP_OPCODE(last->i_opcode)) {
989
return 0;
990
}
991
basicblock *target = last->i_target;
992
if (basicblock_exits_scope(target) && target->b_iused <= MAX_COPY_SIZE) {
993
INSTR_SET_OP0(last, NOP);
994
RETURN_IF_ERROR(basicblock_append_instructions(bb, target));
995
return 1;
996
}
997
return 0;
998
}
999
1000
// Attempt to eliminate jumps to jumps by updating inst to jump to
1001
// target->i_target using the provided opcode. Return whether or not the
1002
// optimization was successful.
1003
static bool
1004
jump_thread(cfg_instr *inst, cfg_instr *target, int opcode)
1005
{
1006
assert(is_jump(inst));
1007
assert(is_jump(target));
1008
// bpo-45773: If inst->i_target == target->i_target, then nothing actually
1009
// changes (and we fall into an infinite loop):
1010
if ((inst->i_loc.lineno == target->i_loc.lineno || target->i_loc.lineno == -1) &&
1011
inst->i_target != target->i_target)
1012
{
1013
inst->i_target = target->i_target;
1014
inst->i_opcode = opcode;
1015
return true;
1016
}
1017
return false;
1018
}
1019
1020
static PyObject*
1021
get_const_value(int opcode, int oparg, PyObject *co_consts)
1022
{
1023
PyObject *constant = NULL;
1024
assert(OPCODE_HAS_CONST(opcode));
1025
if (opcode == LOAD_CONST) {
1026
constant = PyList_GET_ITEM(co_consts, oparg);
1027
}
1028
1029
if (constant == NULL) {
1030
PyErr_SetString(PyExc_SystemError,
1031
"Internal error: failed to get value of a constant");
1032
return NULL;
1033
}
1034
return Py_NewRef(constant);
1035
}
1036
1037
// Steals a reference to newconst.
1038
static int
1039
add_const(PyObject *newconst, PyObject *consts, PyObject *const_cache)
1040
{
1041
if (_PyCompile_ConstCacheMergeOne(const_cache, &newconst) < 0) {
1042
Py_DECREF(newconst);
1043
return -1;
1044
}
1045
1046
Py_ssize_t index;
1047
for (index = 0; index < PyList_GET_SIZE(consts); index++) {
1048
if (PyList_GET_ITEM(consts, index) == newconst) {
1049
break;
1050
}
1051
}
1052
if (index == PyList_GET_SIZE(consts)) {
1053
if ((size_t)index >= (size_t)INT_MAX - 1) {
1054
PyErr_SetString(PyExc_OverflowError, "too many constants");
1055
Py_DECREF(newconst);
1056
return -1;
1057
}
1058
if (PyList_Append(consts, newconst)) {
1059
Py_DECREF(newconst);
1060
return -1;
1061
}
1062
}
1063
Py_DECREF(newconst);
1064
return (int)index;
1065
}
1066
1067
/* Replace LOAD_CONST c1, LOAD_CONST c2 ... LOAD_CONST cn, BUILD_TUPLE n
1068
with LOAD_CONST (c1, c2, ... cn).
1069
The consts table must still be in list form so that the
1070
new constant (c1, c2, ... cn) can be appended.
1071
Called with codestr pointing to the first LOAD_CONST.
1072
*/
1073
static int
1074
fold_tuple_on_constants(PyObject *const_cache,
1075
cfg_instr *inst,
1076
int n, PyObject *consts)
1077
{
1078
/* Pre-conditions */
1079
assert(PyDict_CheckExact(const_cache));
1080
assert(PyList_CheckExact(consts));
1081
assert(inst[n].i_opcode == BUILD_TUPLE);
1082
assert(inst[n].i_oparg == n);
1083
1084
for (int i = 0; i < n; i++) {
1085
if (!OPCODE_HAS_CONST(inst[i].i_opcode)) {
1086
return SUCCESS;
1087
}
1088
}
1089
1090
/* Buildup new tuple of constants */
1091
PyObject *newconst = PyTuple_New(n);
1092
if (newconst == NULL) {
1093
return ERROR;
1094
}
1095
for (int i = 0; i < n; i++) {
1096
int op = inst[i].i_opcode;
1097
int arg = inst[i].i_oparg;
1098
PyObject *constant = get_const_value(op, arg, consts);
1099
if (constant == NULL) {
1100
return ERROR;
1101
}
1102
PyTuple_SET_ITEM(newconst, i, constant);
1103
}
1104
int index = add_const(newconst, consts, const_cache);
1105
if (index < 0) {
1106
return ERROR;
1107
}
1108
for (int i = 0; i < n; i++) {
1109
INSTR_SET_OP0(&inst[i], NOP);
1110
}
1111
INSTR_SET_OP1(&inst[n], LOAD_CONST, index);
1112
return SUCCESS;
1113
}
1114
1115
#define VISITED (-1)
1116
1117
// Replace an arbitrary run of SWAPs and NOPs with an optimal one that has the
1118
// same effect.
1119
static int
1120
swaptimize(basicblock *block, int *ix)
1121
{
1122
// NOTE: "./python -m test test_patma" serves as a good, quick stress test
1123
// for this function. Make sure to blow away cached *.pyc files first!
1124
assert(*ix < block->b_iused);
1125
cfg_instr *instructions = &block->b_instr[*ix];
1126
// Find the length of the current sequence of SWAPs and NOPs, and record the
1127
// maximum depth of the stack manipulations:
1128
assert(instructions[0].i_opcode == SWAP);
1129
int depth = instructions[0].i_oparg;
1130
int len = 0;
1131
int more = false;
1132
int limit = block->b_iused - *ix;
1133
while (++len < limit) {
1134
int opcode = instructions[len].i_opcode;
1135
if (opcode == SWAP) {
1136
depth = Py_MAX(depth, instructions[len].i_oparg);
1137
more = true;
1138
}
1139
else if (opcode != NOP) {
1140
break;
1141
}
1142
}
1143
// It's already optimal if there's only one SWAP:
1144
if (!more) {
1145
return SUCCESS;
1146
}
1147
// Create an array with elements {0, 1, 2, ..., depth - 1}:
1148
int *stack = PyMem_Malloc(depth * sizeof(int));
1149
if (stack == NULL) {
1150
PyErr_NoMemory();
1151
return ERROR;
1152
}
1153
for (int i = 0; i < depth; i++) {
1154
stack[i] = i;
1155
}
1156
// Simulate the combined effect of these instructions by "running" them on
1157
// our "stack":
1158
for (int i = 0; i < len; i++) {
1159
if (instructions[i].i_opcode == SWAP) {
1160
int oparg = instructions[i].i_oparg;
1161
int top = stack[0];
1162
// SWAPs are 1-indexed:
1163
stack[0] = stack[oparg - 1];
1164
stack[oparg - 1] = top;
1165
}
1166
}
1167
// Now we can begin! Our approach here is based on a solution to a closely
1168
// related problem (https://cs.stackexchange.com/a/13938). It's easiest to
1169
// think of this algorithm as determining the steps needed to efficiently
1170
// "un-shuffle" our stack. By performing the moves in *reverse* order,
1171
// though, we can efficiently *shuffle* it! For this reason, we will be
1172
// replacing instructions starting from the *end* of the run. Since the
1173
// solution is optimal, we don't need to worry about running out of space:
1174
int current = len - 1;
1175
for (int i = 0; i < depth; i++) {
1176
// Skip items that have already been visited, or just happen to be in
1177
// the correct location:
1178
if (stack[i] == VISITED || stack[i] == i) {
1179
continue;
1180
}
1181
// Okay, we've found an item that hasn't been visited. It forms a cycle
1182
// with other items; traversing the cycle and swapping each item with
1183
// the next will put them all in the correct place. The weird
1184
// loop-and-a-half is necessary to insert 0 into every cycle, since we
1185
// can only swap from that position:
1186
int j = i;
1187
while (true) {
1188
// Skip the actual swap if our item is zero, since swapping the top
1189
// item with itself is pointless:
1190
if (j) {
1191
assert(0 <= current);
1192
// SWAPs are 1-indexed:
1193
instructions[current].i_opcode = SWAP;
1194
instructions[current--].i_oparg = j + 1;
1195
}
1196
if (stack[j] == VISITED) {
1197
// Completed the cycle:
1198
assert(j == i);
1199
break;
1200
}
1201
int next_j = stack[j];
1202
stack[j] = VISITED;
1203
j = next_j;
1204
}
1205
}
1206
// NOP out any unused instructions:
1207
while (0 <= current) {
1208
INSTR_SET_OP0(&instructions[current--], NOP);
1209
}
1210
PyMem_Free(stack);
1211
*ix += len - 1;
1212
return SUCCESS;
1213
}
1214
1215
1216
// This list is pretty small, since it's only okay to reorder opcodes that:
1217
// - can't affect control flow (like jumping or raising exceptions)
1218
// - can't invoke arbitrary code (besides finalizers)
1219
// - only touch the TOS (and pop it when finished)
1220
#define SWAPPABLE(opcode) \
1221
((opcode) == STORE_FAST || \
1222
(opcode) == STORE_FAST_MAYBE_NULL || \
1223
(opcode) == POP_TOP)
1224
1225
#define STORES_TO(instr) \
1226
(((instr).i_opcode == STORE_FAST || \
1227
(instr).i_opcode == STORE_FAST_MAYBE_NULL) \
1228
? (instr).i_oparg : -1)
1229
1230
static int
1231
next_swappable_instruction(basicblock *block, int i, int lineno)
1232
{
1233
while (++i < block->b_iused) {
1234
cfg_instr *instruction = &block->b_instr[i];
1235
if (0 <= lineno && instruction->i_loc.lineno != lineno) {
1236
// Optimizing across this instruction could cause user-visible
1237
// changes in the names bound between line tracing events!
1238
return -1;
1239
}
1240
if (instruction->i_opcode == NOP) {
1241
continue;
1242
}
1243
if (SWAPPABLE(instruction->i_opcode)) {
1244
return i;
1245
}
1246
return -1;
1247
}
1248
return -1;
1249
}
1250
1251
// Attempt to apply SWAPs statically by swapping *instructions* rather than
1252
// stack items. For example, we can replace SWAP(2), POP_TOP, STORE_FAST(42)
1253
// with the more efficient NOP, STORE_FAST(42), POP_TOP.
1254
static void
1255
apply_static_swaps(basicblock *block, int i)
1256
{
1257
// SWAPs are to our left, and potential swaperands are to our right:
1258
for (; 0 <= i; i--) {
1259
assert(i < block->b_iused);
1260
cfg_instr *swap = &block->b_instr[i];
1261
if (swap->i_opcode != SWAP) {
1262
if (swap->i_opcode == NOP || SWAPPABLE(swap->i_opcode)) {
1263
// Nope, but we know how to handle these. Keep looking:
1264
continue;
1265
}
1266
// We can't reason about what this instruction does. Bail:
1267
return;
1268
}
1269
int j = next_swappable_instruction(block, i, -1);
1270
if (j < 0) {
1271
return;
1272
}
1273
int k = j;
1274
int lineno = block->b_instr[j].i_loc.lineno;
1275
for (int count = swap->i_oparg - 1; 0 < count; count--) {
1276
k = next_swappable_instruction(block, k, lineno);
1277
if (k < 0) {
1278
return;
1279
}
1280
}
1281
// The reordering is not safe if the two instructions to be swapped
1282
// store to the same location, or if any intervening instruction stores
1283
// to the same location as either of them.
1284
int store_j = STORES_TO(block->b_instr[j]);
1285
int store_k = STORES_TO(block->b_instr[k]);
1286
if (store_j >= 0 || store_k >= 0) {
1287
if (store_j == store_k) {
1288
return;
1289
}
1290
for (int idx = j + 1; idx < k; idx++) {
1291
int store_idx = STORES_TO(block->b_instr[idx]);
1292
if (store_idx >= 0 && (store_idx == store_j || store_idx == store_k)) {
1293
return;
1294
}
1295
}
1296
}
1297
1298
// Success!
1299
INSTR_SET_OP0(swap, NOP);
1300
cfg_instr temp = block->b_instr[j];
1301
block->b_instr[j] = block->b_instr[k];
1302
block->b_instr[k] = temp;
1303
}
1304
}
1305
1306
static int
1307
optimize_basic_block(PyObject *const_cache, basicblock *bb, PyObject *consts)
1308
{
1309
assert(PyDict_CheckExact(const_cache));
1310
assert(PyList_CheckExact(consts));
1311
cfg_instr nop;
1312
INSTR_SET_OP0(&nop, NOP);
1313
cfg_instr *target = &nop;
1314
int opcode = 0;
1315
int oparg = 0;
1316
int nextop = 0;
1317
for (int i = 0; i < bb->b_iused; i++) {
1318
cfg_instr *inst = &bb->b_instr[i];
1319
bool is_copy_of_load_const = (opcode == LOAD_CONST &&
1320
inst->i_opcode == COPY &&
1321
inst->i_oparg == 1);
1322
if (! is_copy_of_load_const) {
1323
opcode = inst->i_opcode;
1324
oparg = inst->i_oparg;
1325
if (HAS_TARGET(opcode)) {
1326
assert(inst->i_target->b_iused > 0);
1327
target = &inst->i_target->b_instr[0];
1328
assert(!IS_ASSEMBLER_OPCODE(target->i_opcode));
1329
}
1330
else {
1331
target = &nop;
1332
}
1333
}
1334
nextop = i+1 < bb->b_iused ? bb->b_instr[i+1].i_opcode : 0;
1335
assert(!IS_ASSEMBLER_OPCODE(opcode));
1336
switch (opcode) {
1337
/* Remove LOAD_CONST const; conditional jump */
1338
case LOAD_CONST:
1339
{
1340
PyObject* cnt;
1341
int is_true;
1342
int jump_if_true;
1343
switch(nextop) {
1344
case POP_JUMP_IF_FALSE:
1345
case POP_JUMP_IF_TRUE:
1346
cnt = get_const_value(opcode, oparg, consts);
1347
if (cnt == NULL) {
1348
goto error;
1349
}
1350
is_true = PyObject_IsTrue(cnt);
1351
Py_DECREF(cnt);
1352
if (is_true == -1) {
1353
goto error;
1354
}
1355
INSTR_SET_OP0(inst, NOP);
1356
jump_if_true = nextop == POP_JUMP_IF_TRUE;
1357
if (is_true == jump_if_true) {
1358
bb->b_instr[i+1].i_opcode = JUMP;
1359
}
1360
else {
1361
INSTR_SET_OP0(&bb->b_instr[i + 1], NOP);
1362
}
1363
break;
1364
case IS_OP:
1365
// Fold to POP_JUMP_IF_NONE:
1366
// - LOAD_CONST(None) IS_OP(0) POP_JUMP_IF_TRUE
1367
// - LOAD_CONST(None) IS_OP(1) POP_JUMP_IF_FALSE
1368
// - LOAD_CONST(None) IS_OP(0) TO_BOOL POP_JUMP_IF_TRUE
1369
// - LOAD_CONST(None) IS_OP(1) TO_BOOL POP_JUMP_IF_FALSE
1370
// Fold to POP_JUMP_IF_NOT_NONE:
1371
// - LOAD_CONST(None) IS_OP(0) POP_JUMP_IF_FALSE
1372
// - LOAD_CONST(None) IS_OP(1) POP_JUMP_IF_TRUE
1373
// - LOAD_CONST(None) IS_OP(0) TO_BOOL POP_JUMP_IF_FALSE
1374
// - LOAD_CONST(None) IS_OP(1) TO_BOOL POP_JUMP_IF_TRUE
1375
cnt = get_const_value(opcode, oparg, consts);
1376
if (cnt == NULL) {
1377
goto error;
1378
}
1379
if (!Py_IsNone(cnt)) {
1380
break;
1381
}
1382
Py_DECREF(cnt);
1383
if (bb->b_iused <= i + 2) {
1384
break;
1385
}
1386
cfg_instr *is_instr = &bb->b_instr[i + 1];
1387
cfg_instr *jump_instr = &bb->b_instr[i + 2];
1388
// Get rid of TO_BOOL regardless:
1389
if (jump_instr->i_opcode == TO_BOOL) {
1390
INSTR_SET_OP0(jump_instr, NOP);
1391
if (bb->b_iused <= i + 3) {
1392
break;
1393
}
1394
jump_instr = &bb->b_instr[i + 3];
1395
}
1396
bool invert = is_instr->i_oparg;
1397
if (jump_instr->i_opcode == POP_JUMP_IF_FALSE) {
1398
invert = !invert;
1399
}
1400
else if (jump_instr->i_opcode != POP_JUMP_IF_TRUE) {
1401
break;
1402
}
1403
INSTR_SET_OP0(inst, NOP);
1404
INSTR_SET_OP0(is_instr, NOP);
1405
jump_instr->i_opcode = invert ? POP_JUMP_IF_NOT_NONE
1406
: POP_JUMP_IF_NONE;
1407
break;
1408
case RETURN_VALUE:
1409
INSTR_SET_OP0(inst, NOP);
1410
INSTR_SET_OP1(&bb->b_instr[++i], RETURN_CONST, oparg);
1411
break;
1412
case TO_BOOL:
1413
cnt = get_const_value(opcode, oparg, consts);
1414
if (cnt == NULL) {
1415
goto error;
1416
}
1417
is_true = PyObject_IsTrue(cnt);
1418
Py_DECREF(cnt);
1419
if (is_true == -1) {
1420
goto error;
1421
}
1422
cnt = PyBool_FromLong(is_true);
1423
int index = add_const(cnt, consts, const_cache);
1424
if (index < 0) {
1425
return ERROR;
1426
}
1427
INSTR_SET_OP0(inst, NOP);
1428
INSTR_SET_OP1(&bb->b_instr[i + 1], LOAD_CONST, index);
1429
break;
1430
}
1431
break;
1432
}
1433
/* Try to fold tuples of constants.
1434
Skip over BUILD_TUPLE(1) UNPACK_SEQUENCE(1).
1435
Replace BUILD_TUPLE(2) UNPACK_SEQUENCE(2) with SWAP(2).
1436
Replace BUILD_TUPLE(3) UNPACK_SEQUENCE(3) with SWAP(3). */
1437
case BUILD_TUPLE:
1438
if (nextop == UNPACK_SEQUENCE && oparg == bb->b_instr[i+1].i_oparg) {
1439
switch(oparg) {
1440
case 1:
1441
INSTR_SET_OP0(inst, NOP);
1442
INSTR_SET_OP0(&bb->b_instr[i + 1], NOP);
1443
continue;
1444
case 2:
1445
case 3:
1446
INSTR_SET_OP0(inst, NOP);
1447
bb->b_instr[i+1].i_opcode = SWAP;
1448
continue;
1449
}
1450
}
1451
if (i >= oparg) {
1452
if (fold_tuple_on_constants(const_cache, inst-oparg, oparg, consts)) {
1453
goto error;
1454
}
1455
}
1456
break;
1457
case POP_JUMP_IF_NOT_NONE:
1458
case POP_JUMP_IF_NONE:
1459
switch (target->i_opcode) {
1460
case JUMP:
1461
i -= jump_thread(inst, target, inst->i_opcode);
1462
}
1463
break;
1464
case POP_JUMP_IF_FALSE:
1465
switch (target->i_opcode) {
1466
case JUMP:
1467
i -= jump_thread(inst, target, POP_JUMP_IF_FALSE);
1468
}
1469
break;
1470
case POP_JUMP_IF_TRUE:
1471
switch (target->i_opcode) {
1472
case JUMP:
1473
i -= jump_thread(inst, target, POP_JUMP_IF_TRUE);
1474
}
1475
break;
1476
case JUMP:
1477
switch (target->i_opcode) {
1478
case JUMP:
1479
i -= jump_thread(inst, target, JUMP);
1480
}
1481
break;
1482
case FOR_ITER:
1483
if (target->i_opcode == JUMP) {
1484
/* This will not work now because the jump (at target) could
1485
* be forward or backward and FOR_ITER only jumps forward. We
1486
* can re-enable this if ever we implement a backward version
1487
* of FOR_ITER.
1488
*/
1489
/*
1490
i -= jump_thread(inst, target, FOR_ITER);
1491
*/
1492
}
1493
break;
1494
case STORE_FAST:
1495
if (opcode == nextop &&
1496
oparg == bb->b_instr[i+1].i_oparg &&
1497
bb->b_instr[i].i_loc.lineno == bb->b_instr[i+1].i_loc.lineno) {
1498
bb->b_instr[i].i_opcode = POP_TOP;
1499
bb->b_instr[i].i_oparg = 0;
1500
}
1501
break;
1502
case SWAP:
1503
if (oparg == 1) {
1504
INSTR_SET_OP0(inst, NOP);
1505
}
1506
break;
1507
case KW_NAMES:
1508
break;
1509
case PUSH_NULL:
1510
if (nextop == LOAD_GLOBAL && (inst[1].i_opcode & 1) == 0) {
1511
INSTR_SET_OP0(inst, NOP);
1512
inst[1].i_oparg |= 1;
1513
}
1514
break;
1515
case COMPARE_OP:
1516
if (nextop == TO_BOOL) {
1517
INSTR_SET_OP0(inst, NOP);
1518
INSTR_SET_OP1(&bb->b_instr[i + 1], COMPARE_OP, oparg | 16);
1519
continue;
1520
}
1521
break;
1522
case CONTAINS_OP:
1523
case IS_OP:
1524
if (nextop == TO_BOOL) {
1525
INSTR_SET_OP0(inst, NOP);
1526
INSTR_SET_OP1(&bb->b_instr[i + 1], opcode, oparg);
1527
continue;
1528
}
1529
break;
1530
case TO_BOOL:
1531
if (nextop == TO_BOOL) {
1532
INSTR_SET_OP0(inst, NOP);
1533
continue;
1534
}
1535
break;
1536
case UNARY_NOT:
1537
if (nextop == TO_BOOL) {
1538
INSTR_SET_OP0(inst, NOP);
1539
INSTR_SET_OP0(&bb->b_instr[i + 1], UNARY_NOT);
1540
continue;
1541
}
1542
if (nextop == UNARY_NOT) {
1543
INSTR_SET_OP0(inst, NOP);
1544
INSTR_SET_OP0(&bb->b_instr[i + 1], NOP);
1545
continue;
1546
}
1547
break;
1548
default:
1549
/* All OPCODE_HAS_CONST opcodes should be handled with LOAD_CONST */
1550
assert (!OPCODE_HAS_CONST(inst->i_opcode));
1551
}
1552
}
1553
1554
for (int i = 0; i < bb->b_iused; i++) {
1555
cfg_instr *inst = &bb->b_instr[i];
1556
if (inst->i_opcode == SWAP) {
1557
if (swaptimize(bb, &i) < 0) {
1558
goto error;
1559
}
1560
apply_static_swaps(bb, i);
1561
}
1562
}
1563
return SUCCESS;
1564
error:
1565
return ERROR;
1566
}
1567
1568
1569
/* Perform optimizations on a control flow graph.
1570
The consts object should still be in list form to allow new constants
1571
to be appended.
1572
1573
Code trasnformations that reduce code size initially fill the gaps with
1574
NOPs. Later those NOPs are removed.
1575
*/
1576
static int
1577
optimize_cfg(cfg_builder *g, PyObject *consts, PyObject *const_cache)
1578
{
1579
assert(PyDict_CheckExact(const_cache));
1580
RETURN_IF_ERROR(check_cfg(g));
1581
eliminate_empty_basic_blocks(g);
1582
for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) {
1583
RETURN_IF_ERROR(inline_small_exit_blocks(b));
1584
}
1585
assert(no_empty_basic_blocks(g));
1586
for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) {
1587
RETURN_IF_ERROR(optimize_basic_block(const_cache, b, consts));
1588
assert(b->b_predecessors == 0);
1589
}
1590
RETURN_IF_ERROR(remove_redundant_nops_and_pairs(g->g_entryblock));
1591
for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) {
1592
RETURN_IF_ERROR(inline_small_exit_blocks(b));
1593
}
1594
RETURN_IF_ERROR(mark_reachable(g->g_entryblock));
1595
1596
/* Delete unreachable instructions */
1597
for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) {
1598
if (b->b_predecessors == 0) {
1599
b->b_iused = 0;
1600
}
1601
}
1602
for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) {
1603
remove_redundant_nops(b);
1604
}
1605
eliminate_empty_basic_blocks(g);
1606
assert(no_redundant_nops(g));
1607
RETURN_IF_ERROR(remove_redundant_jumps(g));
1608
return SUCCESS;
1609
}
1610
1611
static void
1612
make_super_instruction(cfg_instr *inst1, cfg_instr *inst2, int super_op)
1613
{
1614
int32_t line1 = inst1->i_loc.lineno;
1615
int32_t line2 = inst2->i_loc.lineno;
1616
/* Skip if instructions are on different lines */
1617
if (line1 >= 0 && line2 >= 0 && line1 != line2) {
1618
return;
1619
}
1620
if (inst1->i_oparg >= 16 || inst2->i_oparg >= 16) {
1621
return;
1622
}
1623
INSTR_SET_OP1(inst1, super_op, (inst1->i_oparg << 4) | inst2->i_oparg);
1624
INSTR_SET_OP0(inst2, NOP);
1625
}
1626
1627
static void
1628
insert_superinstructions(cfg_builder *g)
1629
{
1630
for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) {
1631
1632
for (int i = 0; i < b->b_iused; i++) {
1633
cfg_instr *inst = &b->b_instr[i];
1634
int nextop = i+1 < b->b_iused ? b->b_instr[i+1].i_opcode : 0;
1635
switch(inst->i_opcode) {
1636
case LOAD_FAST:
1637
if (nextop == LOAD_FAST) {
1638
make_super_instruction(inst, &b->b_instr[i + 1], LOAD_FAST_LOAD_FAST);
1639
}
1640
break;
1641
case STORE_FAST:
1642
switch (nextop) {
1643
case LOAD_FAST:
1644
make_super_instruction(inst, &b->b_instr[i + 1], STORE_FAST_LOAD_FAST);
1645
break;
1646
case STORE_FAST:
1647
make_super_instruction(inst, &b->b_instr[i + 1], STORE_FAST_STORE_FAST);
1648
break;
1649
}
1650
break;
1651
}
1652
}
1653
}
1654
for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) {
1655
remove_redundant_nops(b);
1656
}
1657
eliminate_empty_basic_blocks(g);
1658
assert(no_redundant_nops(g));
1659
}
1660
1661
// helper functions for add_checks_for_loads_of_unknown_variables
1662
static inline void
1663
maybe_push(basicblock *b, uint64_t unsafe_mask, basicblock ***sp)
1664
{
1665
// Push b if the unsafe mask is giving us any new information.
1666
// To avoid overflowing the stack, only allow each block once.
1667
// Use b->b_visited=1 to mean that b is currently on the stack.
1668
uint64_t both = b->b_unsafe_locals_mask | unsafe_mask;
1669
if (b->b_unsafe_locals_mask != both) {
1670
b->b_unsafe_locals_mask = both;
1671
// More work left to do.
1672
if (!b->b_visited) {
1673
// not on the stack, so push it.
1674
*(*sp)++ = b;
1675
b->b_visited = 1;
1676
}
1677
}
1678
}
1679
1680
static void
1681
scan_block_for_locals(basicblock *b, basicblock ***sp)
1682
{
1683
// bit i is set if local i is potentially uninitialized
1684
uint64_t unsafe_mask = b->b_unsafe_locals_mask;
1685
for (int i = 0; i < b->b_iused; i++) {
1686
cfg_instr *instr = &b->b_instr[i];
1687
assert(instr->i_opcode != EXTENDED_ARG);
1688
if (instr->i_except != NULL) {
1689
maybe_push(instr->i_except, unsafe_mask, sp);
1690
}
1691
if (instr->i_oparg >= 64) {
1692
continue;
1693
}
1694
assert(instr->i_oparg >= 0);
1695
uint64_t bit = (uint64_t)1 << instr->i_oparg;
1696
switch (instr->i_opcode) {
1697
case DELETE_FAST:
1698
case LOAD_FAST_AND_CLEAR:
1699
case STORE_FAST_MAYBE_NULL:
1700
unsafe_mask |= bit;
1701
break;
1702
case STORE_FAST:
1703
unsafe_mask &= ~bit;
1704
break;
1705
case LOAD_FAST_CHECK:
1706
// If this doesn't raise, then the local is defined.
1707
unsafe_mask &= ~bit;
1708
break;
1709
case LOAD_FAST:
1710
if (unsafe_mask & bit) {
1711
instr->i_opcode = LOAD_FAST_CHECK;
1712
}
1713
unsafe_mask &= ~bit;
1714
break;
1715
}
1716
}
1717
if (b->b_next && BB_HAS_FALLTHROUGH(b)) {
1718
maybe_push(b->b_next, unsafe_mask, sp);
1719
}
1720
cfg_instr *last = _PyCfg_BasicblockLastInstr(b);
1721
if (last && is_jump(last)) {
1722
assert(last->i_target != NULL);
1723
maybe_push(last->i_target, unsafe_mask, sp);
1724
}
1725
}
1726
1727
static int
1728
fast_scan_many_locals(basicblock *entryblock, int nlocals)
1729
{
1730
assert(nlocals > 64);
1731
Py_ssize_t *states = PyMem_Calloc(nlocals - 64, sizeof(Py_ssize_t));
1732
if (states == NULL) {
1733
PyErr_NoMemory();
1734
return ERROR;
1735
}
1736
Py_ssize_t blocknum = 0;
1737
// state[i - 64] == blocknum if local i is guaranteed to
1738
// be initialized, i.e., if it has had a previous LOAD_FAST or
1739
// STORE_FAST within that basicblock (not followed by
1740
// DELETE_FAST/LOAD_FAST_AND_CLEAR/STORE_FAST_MAYBE_NULL).
1741
for (basicblock *b = entryblock; b != NULL; b = b->b_next) {
1742
blocknum++;
1743
for (int i = 0; i < b->b_iused; i++) {
1744
cfg_instr *instr = &b->b_instr[i];
1745
assert(instr->i_opcode != EXTENDED_ARG);
1746
int arg = instr->i_oparg;
1747
if (arg < 64) {
1748
continue;
1749
}
1750
assert(arg >= 0);
1751
switch (instr->i_opcode) {
1752
case DELETE_FAST:
1753
case LOAD_FAST_AND_CLEAR:
1754
case STORE_FAST_MAYBE_NULL:
1755
states[arg - 64] = blocknum - 1;
1756
break;
1757
case STORE_FAST:
1758
states[arg - 64] = blocknum;
1759
break;
1760
case LOAD_FAST:
1761
if (states[arg - 64] != blocknum) {
1762
instr->i_opcode = LOAD_FAST_CHECK;
1763
}
1764
states[arg - 64] = blocknum;
1765
break;
1766
Py_UNREACHABLE();
1767
}
1768
}
1769
}
1770
PyMem_Free(states);
1771
return SUCCESS;
1772
}
1773
1774
static int
1775
remove_unused_consts(basicblock *entryblock, PyObject *consts)
1776
{
1777
assert(PyList_CheckExact(consts));
1778
Py_ssize_t nconsts = PyList_GET_SIZE(consts);
1779
if (nconsts == 0) {
1780
return SUCCESS; /* nothing to do */
1781
}
1782
1783
Py_ssize_t *index_map = NULL;
1784
Py_ssize_t *reverse_index_map = NULL;
1785
int err = ERROR;
1786
1787
index_map = PyMem_Malloc(nconsts * sizeof(Py_ssize_t));
1788
if (index_map == NULL) {
1789
goto end;
1790
}
1791
for (Py_ssize_t i = 1; i < nconsts; i++) {
1792
index_map[i] = -1;
1793
}
1794
// The first constant may be docstring; keep it always.
1795
index_map[0] = 0;
1796
1797
/* mark used consts */
1798
for (basicblock *b = entryblock; b != NULL; b = b->b_next) {
1799
for (int i = 0; i < b->b_iused; i++) {
1800
if (OPCODE_HAS_CONST(b->b_instr[i].i_opcode)) {
1801
int index = b->b_instr[i].i_oparg;
1802
index_map[index] = index;
1803
}
1804
}
1805
}
1806
/* now index_map[i] == i if consts[i] is used, -1 otherwise */
1807
/* condense consts */
1808
Py_ssize_t n_used_consts = 0;
1809
for (int i = 0; i < nconsts; i++) {
1810
if (index_map[i] != -1) {
1811
assert(index_map[i] == i);
1812
index_map[n_used_consts++] = index_map[i];
1813
}
1814
}
1815
if (n_used_consts == nconsts) {
1816
/* nothing to do */
1817
err = SUCCESS;
1818
goto end;
1819
}
1820
1821
/* move all used consts to the beginning of the consts list */
1822
assert(n_used_consts < nconsts);
1823
for (Py_ssize_t i = 0; i < n_used_consts; i++) {
1824
Py_ssize_t old_index = index_map[i];
1825
assert(i <= old_index && old_index < nconsts);
1826
if (i != old_index) {
1827
PyObject *value = PyList_GET_ITEM(consts, index_map[i]);
1828
assert(value != NULL);
1829
PyList_SetItem(consts, i, Py_NewRef(value));
1830
}
1831
}
1832
1833
/* truncate the consts list at its new size */
1834
if (PyList_SetSlice(consts, n_used_consts, nconsts, NULL) < 0) {
1835
goto end;
1836
}
1837
/* adjust const indices in the bytecode */
1838
reverse_index_map = PyMem_Malloc(nconsts * sizeof(Py_ssize_t));
1839
if (reverse_index_map == NULL) {
1840
goto end;
1841
}
1842
for (Py_ssize_t i = 0; i < nconsts; i++) {
1843
reverse_index_map[i] = -1;
1844
}
1845
for (Py_ssize_t i = 0; i < n_used_consts; i++) {
1846
assert(index_map[i] != -1);
1847
assert(reverse_index_map[index_map[i]] == -1);
1848
reverse_index_map[index_map[i]] = i;
1849
}
1850
1851
for (basicblock *b = entryblock; b != NULL; b = b->b_next) {
1852
for (int i = 0; i < b->b_iused; i++) {
1853
if (OPCODE_HAS_CONST(b->b_instr[i].i_opcode)) {
1854
int index = b->b_instr[i].i_oparg;
1855
assert(reverse_index_map[index] >= 0);
1856
assert(reverse_index_map[index] < n_used_consts);
1857
b->b_instr[i].i_oparg = (int)reverse_index_map[index];
1858
}
1859
}
1860
}
1861
1862
err = SUCCESS;
1863
end:
1864
PyMem_Free(index_map);
1865
PyMem_Free(reverse_index_map);
1866
return err;
1867
}
1868
1869
1870
1871
static int
1872
add_checks_for_loads_of_uninitialized_variables(basicblock *entryblock,
1873
int nlocals,
1874
int nparams)
1875
{
1876
if (nlocals == 0) {
1877
return SUCCESS;
1878
}
1879
if (nlocals > 64) {
1880
// To avoid O(nlocals**2) compilation, locals beyond the first
1881
// 64 are only analyzed one basicblock at a time: initialization
1882
// info is not passed between basicblocks.
1883
if (fast_scan_many_locals(entryblock, nlocals) < 0) {
1884
return ERROR;
1885
}
1886
nlocals = 64;
1887
}
1888
basicblock **stack = make_cfg_traversal_stack(entryblock);
1889
if (stack == NULL) {
1890
return ERROR;
1891
}
1892
basicblock **sp = stack;
1893
1894
// First origin of being uninitialized:
1895
// The non-parameter locals in the entry block.
1896
uint64_t start_mask = 0;
1897
for (int i = nparams; i < nlocals; i++) {
1898
start_mask |= (uint64_t)1 << i;
1899
}
1900
maybe_push(entryblock, start_mask, &sp);
1901
1902
// Second origin of being uninitialized:
1903
// There could be DELETE_FAST somewhere, so
1904
// be sure to scan each basicblock at least once.
1905
for (basicblock *b = entryblock; b != NULL; b = b->b_next) {
1906
scan_block_for_locals(b, &sp);
1907
}
1908
// Now propagate the uncertainty from the origins we found: Use
1909
// LOAD_FAST_CHECK for any LOAD_FAST where the local could be undefined.
1910
while (sp > stack) {
1911
basicblock *b = *--sp;
1912
// mark as no longer on stack
1913
b->b_visited = 0;
1914
scan_block_for_locals(b, &sp);
1915
}
1916
PyMem_Free(stack);
1917
return SUCCESS;
1918
}
1919
1920
1921
static int
1922
mark_warm(basicblock *entryblock) {
1923
basicblock **stack = make_cfg_traversal_stack(entryblock);
1924
if (stack == NULL) {
1925
return ERROR;
1926
}
1927
basicblock **sp = stack;
1928
1929
*sp++ = entryblock;
1930
entryblock->b_visited = 1;
1931
while (sp > stack) {
1932
basicblock *b = *(--sp);
1933
assert(!b->b_except_handler);
1934
b->b_warm = 1;
1935
basicblock *next = b->b_next;
1936
if (next && BB_HAS_FALLTHROUGH(b) && !next->b_visited) {
1937
*sp++ = next;
1938
next->b_visited = 1;
1939
}
1940
for (int i=0; i < b->b_iused; i++) {
1941
cfg_instr *instr = &b->b_instr[i];
1942
if (is_jump(instr) && !instr->i_target->b_visited) {
1943
*sp++ = instr->i_target;
1944
instr->i_target->b_visited = 1;
1945
}
1946
}
1947
}
1948
PyMem_Free(stack);
1949
return SUCCESS;
1950
}
1951
1952
static int
1953
mark_cold(basicblock *entryblock) {
1954
for (basicblock *b = entryblock; b != NULL; b = b->b_next) {
1955
assert(!b->b_cold && !b->b_warm);
1956
}
1957
if (mark_warm(entryblock) < 0) {
1958
return ERROR;
1959
}
1960
1961
basicblock **stack = make_cfg_traversal_stack(entryblock);
1962
if (stack == NULL) {
1963
return ERROR;
1964
}
1965
1966
basicblock **sp = stack;
1967
for (basicblock *b = entryblock; b != NULL; b = b->b_next) {
1968
if (b->b_except_handler) {
1969
assert(!b->b_warm);
1970
*sp++ = b;
1971
b->b_visited = 1;
1972
}
1973
}
1974
1975
while (sp > stack) {
1976
basicblock *b = *(--sp);
1977
b->b_cold = 1;
1978
basicblock *next = b->b_next;
1979
if (next && BB_HAS_FALLTHROUGH(b)) {
1980
if (!next->b_warm && !next->b_visited) {
1981
*sp++ = next;
1982
next->b_visited = 1;
1983
}
1984
}
1985
for (int i = 0; i < b->b_iused; i++) {
1986
cfg_instr *instr = &b->b_instr[i];
1987
if (is_jump(instr)) {
1988
assert(i == b->b_iused - 1);
1989
basicblock *target = b->b_instr[i].i_target;
1990
if (!target->b_warm && !target->b_visited) {
1991
*sp++ = target;
1992
target->b_visited = 1;
1993
}
1994
}
1995
}
1996
}
1997
PyMem_Free(stack);
1998
return SUCCESS;
1999
}
2000
2001
2002
static int
2003
push_cold_blocks_to_end(cfg_builder *g, int code_flags) {
2004
basicblock *entryblock = g->g_entryblock;
2005
if (entryblock->b_next == NULL) {
2006
/* single basicblock, no need to reorder */
2007
return SUCCESS;
2008
}
2009
RETURN_IF_ERROR(mark_cold(entryblock));
2010
2011
/* If we have a cold block with fallthrough to a warm block, add */
2012
/* an explicit jump instead of fallthrough */
2013
for (basicblock *b = entryblock; b != NULL; b = b->b_next) {
2014
if (b->b_cold && BB_HAS_FALLTHROUGH(b) && b->b_next && b->b_next->b_warm) {
2015
basicblock *explicit_jump = cfg_builder_new_block(g);
2016
if (explicit_jump == NULL) {
2017
return ERROR;
2018
}
2019
basicblock_addop(explicit_jump, JUMP, b->b_next->b_label.id, NO_LOCATION);
2020
explicit_jump->b_cold = 1;
2021
explicit_jump->b_next = b->b_next;
2022
b->b_next = explicit_jump;
2023
2024
/* set target */
2025
cfg_instr *last = _PyCfg_BasicblockLastInstr(explicit_jump);
2026
last->i_target = explicit_jump->b_next;
2027
}
2028
}
2029
2030
assert(!entryblock->b_cold); /* First block can't be cold */
2031
basicblock *cold_blocks = NULL;
2032
basicblock *cold_blocks_tail = NULL;
2033
2034
basicblock *b = entryblock;
2035
while(b->b_next) {
2036
assert(!b->b_cold);
2037
while (b->b_next && !b->b_next->b_cold) {
2038
b = b->b_next;
2039
}
2040
if (b->b_next == NULL) {
2041
/* no more cold blocks */
2042
break;
2043
}
2044
2045
/* b->b_next is the beginning of a cold streak */
2046
assert(!b->b_cold && b->b_next->b_cold);
2047
2048
basicblock *b_end = b->b_next;
2049
while (b_end->b_next && b_end->b_next->b_cold) {
2050
b_end = b_end->b_next;
2051
}
2052
2053
/* b_end is the end of the cold streak */
2054
assert(b_end && b_end->b_cold);
2055
assert(b_end->b_next == NULL || !b_end->b_next->b_cold);
2056
2057
if (cold_blocks == NULL) {
2058
cold_blocks = b->b_next;
2059
}
2060
else {
2061
cold_blocks_tail->b_next = b->b_next;
2062
}
2063
cold_blocks_tail = b_end;
2064
b->b_next = b_end->b_next;
2065
b_end->b_next = NULL;
2066
}
2067
assert(b != NULL && b->b_next == NULL);
2068
b->b_next = cold_blocks;
2069
2070
if (cold_blocks != NULL) {
2071
RETURN_IF_ERROR(remove_redundant_jumps(g));
2072
}
2073
return SUCCESS;
2074
}
2075
2076
void
2077
_PyCfg_ConvertPseudoOps(basicblock *entryblock)
2078
{
2079
for (basicblock *b = entryblock; b != NULL; b = b->b_next) {
2080
for (int i = 0; i < b->b_iused; i++) {
2081
cfg_instr *instr = &b->b_instr[i];
2082
if (is_block_push(instr) || instr->i_opcode == POP_BLOCK) {
2083
assert(SAME_OPCODE_METADATA(instr->i_opcode, NOP));
2084
INSTR_SET_OP0(instr, NOP);
2085
}
2086
else if (instr->i_opcode == LOAD_CLOSURE) {
2087
assert(SAME_OPCODE_METADATA(LOAD_CLOSURE, LOAD_FAST));
2088
instr->i_opcode = LOAD_FAST;
2089
}
2090
else if (instr->i_opcode == STORE_FAST_MAYBE_NULL) {
2091
assert(SAME_OPCODE_METADATA(STORE_FAST_MAYBE_NULL, STORE_FAST));
2092
instr->i_opcode = STORE_FAST;
2093
}
2094
}
2095
}
2096
for (basicblock *b = entryblock; b != NULL; b = b->b_next) {
2097
remove_redundant_nops(b);
2098
}
2099
}
2100
2101
static inline bool
2102
is_exit_without_lineno(basicblock *b) {
2103
if (!basicblock_exits_scope(b)) {
2104
return false;
2105
}
2106
for (int i = 0; i < b->b_iused; i++) {
2107
if (b->b_instr[i].i_loc.lineno >= 0) {
2108
return false;
2109
}
2110
}
2111
return true;
2112
}
2113
2114
/* PEP 626 mandates that the f_lineno of a frame is correct
2115
* after a frame terminates. It would be prohibitively expensive
2116
* to continuously update the f_lineno field at runtime,
2117
* so we make sure that all exiting instruction (raises and returns)
2118
* have a valid line number, allowing us to compute f_lineno lazily.
2119
* We can do this by duplicating the exit blocks without line number
2120
* so that none have more than one predecessor. We can then safely
2121
* copy the line number from the sole predecessor block.
2122
*/
2123
static int
2124
duplicate_exits_without_lineno(cfg_builder *g)
2125
{
2126
assert(no_empty_basic_blocks(g));
2127
/* Copy all exit blocks without line number that are targets of a jump.
2128
*/
2129
basicblock *entryblock = g->g_entryblock;
2130
for (basicblock *b = entryblock; b != NULL; b = b->b_next) {
2131
cfg_instr *last = _PyCfg_BasicblockLastInstr(b);
2132
assert(last != NULL);
2133
if (is_jump(last)) {
2134
basicblock *target = last->i_target;
2135
if (is_exit_without_lineno(target) && target->b_predecessors > 1) {
2136
basicblock *new_target = copy_basicblock(g, target);
2137
if (new_target == NULL) {
2138
return ERROR;
2139
}
2140
new_target->b_instr[0].i_loc = last->i_loc;
2141
last->i_target = new_target;
2142
target->b_predecessors--;
2143
new_target->b_predecessors = 1;
2144
new_target->b_next = target->b_next;
2145
target->b_next = new_target;
2146
}
2147
}
2148
}
2149
2150
/* Any remaining reachable exit blocks without line number can only be reached by
2151
* fall through, and thus can only have a single predecessor */
2152
for (basicblock *b = entryblock; b != NULL; b = b->b_next) {
2153
if (BB_HAS_FALLTHROUGH(b) && b->b_next && b->b_iused > 0) {
2154
if (is_exit_without_lineno(b->b_next)) {
2155
cfg_instr *last = _PyCfg_BasicblockLastInstr(b);
2156
assert(last != NULL);
2157
b->b_next->b_instr[0].i_loc = last->i_loc;
2158
}
2159
}
2160
}
2161
return SUCCESS;
2162
}
2163
2164
2165
/* If an instruction has no line number, but it's predecessor in the BB does,
2166
* then copy the line number. If a successor block has no line number, and only
2167
* one predecessor, then inherit the line number.
2168
* This ensures that all exit blocks (with one predecessor) receive a line number.
2169
* Also reduces the size of the line number table,
2170
* but has no impact on the generated line number events.
2171
*/
2172
static void
2173
propagate_line_numbers(basicblock *entryblock) {
2174
for (basicblock *b = entryblock; b != NULL; b = b->b_next) {
2175
cfg_instr *last = _PyCfg_BasicblockLastInstr(b);
2176
if (last == NULL) {
2177
continue;
2178
}
2179
2180
location prev_location = NO_LOCATION;
2181
for (int i = 0; i < b->b_iused; i++) {
2182
if (b->b_instr[i].i_loc.lineno < 0) {
2183
b->b_instr[i].i_loc = prev_location;
2184
}
2185
else {
2186
prev_location = b->b_instr[i].i_loc;
2187
}
2188
}
2189
if (BB_HAS_FALLTHROUGH(b) && b->b_next->b_predecessors == 1) {
2190
assert(b->b_next->b_iused);
2191
if (b->b_next->b_instr[0].i_loc.lineno < 0) {
2192
b->b_next->b_instr[0].i_loc = prev_location;
2193
}
2194
}
2195
if (is_jump(last)) {
2196
basicblock *target = last->i_target;
2197
if (target->b_predecessors == 1) {
2198
if (target->b_instr[0].i_loc.lineno < 0) {
2199
target->b_instr[0].i_loc = prev_location;
2200
}
2201
}
2202
}
2203
}
2204
}
2205
2206
/* Make sure that all returns have a line number, even if early passes
2207
* have failed to propagate a correct line number.
2208
* The resulting line number may not be correct according to PEP 626,
2209
* but should be "good enough", and no worse than in older versions. */
2210
static void
2211
guarantee_lineno_for_exits(basicblock *entryblock, int firstlineno) {
2212
int lineno = firstlineno;
2213
assert(lineno > 0);
2214
for (basicblock *b = entryblock; b != NULL; b = b->b_next) {
2215
cfg_instr *last = _PyCfg_BasicblockLastInstr(b);
2216
if (last == NULL) {
2217
continue;
2218
}
2219
if (last->i_loc.lineno < 0) {
2220
if (last->i_opcode == RETURN_VALUE) {
2221
for (int i = 0; i < b->b_iused; i++) {
2222
assert(b->b_instr[i].i_loc.lineno < 0);
2223
2224
b->b_instr[i].i_loc.lineno = lineno;
2225
}
2226
}
2227
}
2228
else {
2229
lineno = last->i_loc.lineno;
2230
}
2231
}
2232
}
2233
2234
static int
2235
resolve_line_numbers(cfg_builder *g, int firstlineno)
2236
{
2237
RETURN_IF_ERROR(duplicate_exits_without_lineno(g));
2238
propagate_line_numbers(g->g_entryblock);
2239
guarantee_lineno_for_exits(g->g_entryblock, firstlineno);
2240
return SUCCESS;
2241
}
2242
2243
int
2244
_PyCfg_OptimizeCodeUnit(cfg_builder *g, PyObject *consts, PyObject *const_cache,
2245
int code_flags, int nlocals, int nparams, int firstlineno)
2246
{
2247
assert(cfg_builder_check(g));
2248
/** Preprocessing **/
2249
/* Map labels to targets and mark exception handlers */
2250
RETURN_IF_ERROR(translate_jump_labels_to_targets(g->g_entryblock));
2251
RETURN_IF_ERROR(mark_except_handlers(g->g_entryblock));
2252
RETURN_IF_ERROR(label_exception_targets(g->g_entryblock));
2253
2254
/** Optimization **/
2255
RETURN_IF_ERROR(optimize_cfg(g, consts, const_cache));
2256
RETURN_IF_ERROR(remove_unused_consts(g->g_entryblock, consts));
2257
RETURN_IF_ERROR(
2258
add_checks_for_loads_of_uninitialized_variables(
2259
g->g_entryblock, nlocals, nparams));
2260
insert_superinstructions(g);
2261
2262
RETURN_IF_ERROR(push_cold_blocks_to_end(g, code_flags));
2263
RETURN_IF_ERROR(resolve_line_numbers(g, firstlineno));
2264
return SUCCESS;
2265
}
2266
2267