Skip to content

Commit 321d35c

Browse files
Rewind optimizer when out of space
1 parent 161329c commit 321d35c

File tree

2 files changed

+41
-14
lines changed

2 files changed

+41
-14
lines changed

Include/internal/pycore_optimizer.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,16 @@ uop_buffer_last(_PyJitUopBuffer *trace)
6767
return trace->next-1;
6868
}
6969

70+
static inline bool
71+
uop_buffer_rewind(_PyJitUopBuffer *trace)
72+
{
73+
if (trace->next <= trace->start) {
74+
return false;
75+
}
76+
trace->next--;
77+
return true;
78+
}
79+
7080
static inline int
7181
uop_buffer_length(_PyJitUopBuffer *trace)
7282
{

Python/optimizer_analysis.c

Lines changed: 31 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -488,17 +488,9 @@ optimize_uops(
488488
_PyUOpInstruction *this_instr = NULL;
489489
JitOptRef *stack_pointer = ctx->frame->stack_pointer;
490490

491-
for (int i = 0; i < trace_len; i++) {
491+
int i = 0;
492+
for (; i < trace_len && !ctx->done; i++) {
492493
this_instr = &trace[i];
493-
if (ctx->done) {
494-
// Don't do any more optimization, but
495-
// we still need to reach a terminator for corrctness.
496-
*(ctx->out_buffer.next++) = *this_instr;
497-
if (is_terminator_uop(this_instr)) {
498-
break;
499-
}
500-
continue;
501-
}
502494

503495
int oparg = this_instr->oparg;
504496
opcode = this_instr->opcode;
@@ -531,10 +523,6 @@ optimize_uops(
531523
assert(STACK_LEVEL() >= 0);
532524
}
533525
}
534-
if (ctx->out_of_space) {
535-
DPRINTF(3, "\n");
536-
DPRINTF(1, "Out of space in abstract interpreter\n");
537-
}
538526
if (ctx->contradiction) {
539527
// Attempted to push a "bottom" (contradiction) symbol onto the stack.
540528
// This means that the abstract interpreter has optimized to trace
@@ -548,6 +536,35 @@ optimize_uops(
548536
OPT_STAT_INC(optimizer_contradiction);
549537
return 0;
550538
}
539+
if (ctx->out_of_space) {
540+
DPRINTF(3, "\n");
541+
DPRINTF(1, "Out of space in abstract interpreter at length %d\n",
542+
uop_buffer_length(&ctx->out_buffer));
543+
// Rewind to previous instruction and replace with _EXIT_TRACE.
544+
_PyUOpInstruction *curr = uop_buffer_last(&ctx->out_buffer);
545+
while (curr->opcode != _SET_IP) {
546+
if (!uop_buffer_rewind(&ctx->out_buffer)) {
547+
// Reached the start.
548+
return 0;
549+
}
550+
curr = uop_buffer_last(&ctx->out_buffer);
551+
}
552+
assert(curr->opcode == _SET_IP);
553+
int32_t old_target = (int32_t)uop_get_target(curr);
554+
curr->opcode = _EXIT_TRACE;
555+
curr->format = UOP_FORMAT_TARGET;
556+
curr->target = old_target;
557+
DPRINTF(1, "Rewound to length %d\n", uop_buffer_length(&ctx->out_buffer));
558+
}
559+
else {
560+
// Don't do any more optimization, but
561+
// we still need to reach a terminator for correctness.
562+
while (!is_terminator_uop(uop_buffer_last(&ctx->out_buffer))) {
563+
this_instr = &trace[i];
564+
*(ctx->out_buffer.next++) = *this_instr;
565+
i++;
566+
}
567+
}
551568

552569
/* Either reached the end or cannot optimize further, but there
553570
* would be no benefit in retrying later */

0 commit comments

Comments
 (0)