From 4b26cdebacdbabbd0be3559ba5d2d26631e63660 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Mon, 20 Oct 2025 00:35:48 +0100 Subject: [PATCH] Handle unstable branches --- Python/bytecodes.c | 2 ++ Python/generated_cases.c.h | 12 ++++++++++++ Python/generated_tracer_cases.c.h | 4 ++++ Python/optimizer.c | 10 +++++++++- 4 files changed, 27 insertions(+), 1 deletion(-) diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 68a8d380643f..42e323e3a418 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -3063,6 +3063,7 @@ dummy_func( assert(PyStackRef_BoolCheck(cond)); int flag = PyStackRef_IsFalse(cond); DEAD(cond); + RECORD_BRANCH_TAKEN(this_instr[1].cache, flag); JUMPBY(flag ? oparg : next_instr->op.code == NOT_TAKEN); } @@ -3070,6 +3071,7 @@ dummy_func( assert(PyStackRef_BoolCheck(cond)); int flag = PyStackRef_IsTrue(cond); DEAD(cond); + RECORD_BRANCH_TAKEN(this_instr[1].cache, flag); JUMPBY(flag ? oparg : next_instr->op.code == NOT_TAKEN); } diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 7b7d10e52650..bd043ae7285d 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -9977,6 +9977,8 @@ int opcode = POP_JUMP_IF_FALSE; (void)(opcode); #endif + _Py_CODEUNIT* const this_instr = next_instr; + (void)this_instr; frame->instr_ptr = next_instr; next_instr += 2; INSTRUCTION_STATS(POP_JUMP_IF_FALSE); @@ -9985,6 +9987,7 @@ cond = stack_pointer[-1]; assert(PyStackRef_BoolCheck(cond)); int flag = PyStackRef_IsFalse(cond); + RECORD_BRANCH_TAKEN(this_instr[1].cache, flag); JUMPBY(flag ? oparg : next_instr->op.code == NOT_TAKEN); stack_pointer += -1; assert(WITHIN_STACK_BOUNDS()); @@ -9996,6 +9999,8 @@ int opcode = POP_JUMP_IF_NONE; (void)(opcode); #endif + _Py_CODEUNIT* const this_instr = next_instr; + (void)this_instr; frame->instr_ptr = next_instr; next_instr += 2; INSTRUCTION_STATS(POP_JUMP_IF_NONE); @@ -10024,6 +10029,7 @@ cond = b; assert(PyStackRef_BoolCheck(cond)); int flag = PyStackRef_IsTrue(cond); + RECORD_BRANCH_TAKEN(this_instr[1].cache, flag); JUMPBY(flag ? oparg : next_instr->op.code == NOT_TAKEN); } stack_pointer += -1; @@ -10036,6 +10042,8 @@ int opcode = POP_JUMP_IF_NOT_NONE; (void)(opcode); #endif + _Py_CODEUNIT* const this_instr = next_instr; + (void)this_instr; frame->instr_ptr = next_instr; next_instr += 2; INSTRUCTION_STATS(POP_JUMP_IF_NOT_NONE); @@ -10064,6 +10072,7 @@ cond = b; assert(PyStackRef_BoolCheck(cond)); int flag = PyStackRef_IsFalse(cond); + RECORD_BRANCH_TAKEN(this_instr[1].cache, flag); JUMPBY(flag ? oparg : next_instr->op.code == NOT_TAKEN); } stack_pointer += -1; @@ -10076,6 +10085,8 @@ int opcode = POP_JUMP_IF_TRUE; (void)(opcode); #endif + _Py_CODEUNIT* const this_instr = next_instr; + (void)this_instr; frame->instr_ptr = next_instr; next_instr += 2; INSTRUCTION_STATS(POP_JUMP_IF_TRUE); @@ -10084,6 +10095,7 @@ cond = stack_pointer[-1]; assert(PyStackRef_BoolCheck(cond)); int flag = PyStackRef_IsTrue(cond); + RECORD_BRANCH_TAKEN(this_instr[1].cache, flag); JUMPBY(flag ? oparg : next_instr->op.code == NOT_TAKEN); stack_pointer += -1; assert(WITHIN_STACK_BOUNDS()); diff --git a/Python/generated_tracer_cases.c.h b/Python/generated_tracer_cases.c.h index 4c5a9c33fb96..75e86d9c76d3 100644 --- a/Python/generated_tracer_cases.c.h +++ b/Python/generated_tracer_cases.c.h @@ -11518,6 +11518,7 @@ cond = stack_pointer[-1]; assert(PyStackRef_BoolCheck(cond)); int flag = PyStackRef_IsFalse(cond); + RECORD_BRANCH_TAKEN(this_instr[1].cache, flag); JUMPBY(flag ? oparg : next_instr->op.code == NOT_TAKEN); stack_pointer += -1; assert(WITHIN_STACK_BOUNDS()); @@ -11567,6 +11568,7 @@ cond = b; assert(PyStackRef_BoolCheck(cond)); int flag = PyStackRef_IsTrue(cond); + RECORD_BRANCH_TAKEN(this_instr[1].cache, flag); JUMPBY(flag ? oparg : next_instr->op.code == NOT_TAKEN); } stack_pointer += -1; @@ -11617,6 +11619,7 @@ cond = b; assert(PyStackRef_BoolCheck(cond)); int flag = PyStackRef_IsFalse(cond); + RECORD_BRANCH_TAKEN(this_instr[1].cache, flag); JUMPBY(flag ? oparg : next_instr->op.code == NOT_TAKEN); } stack_pointer += -1; @@ -11647,6 +11650,7 @@ cond = stack_pointer[-1]; assert(PyStackRef_BoolCheck(cond)); int flag = PyStackRef_IsTrue(cond); + RECORD_BRANCH_TAKEN(this_instr[1].cache, flag); JUMPBY(flag ? oparg : next_instr->op.code == NOT_TAKEN); stack_pointer += -1; assert(WITHIN_STACK_BOUNDS()); diff --git a/Python/optimizer.c b/Python/optimizer.c index a11244d4b54f..c46c23aa1288 100644 --- a/Python/optimizer.c +++ b/Python/optimizer.c @@ -710,11 +710,19 @@ _PyJIT_translate_single_bytecode_to_trace( case POP_JUMP_IF_FALSE: case POP_JUMP_IF_TRUE: { + int counter = target_instr[1].cache; + int bitcount = _Py_popcount32(counter); + int jump_likely = bitcount > 8; _Py_CODEUNIT *computed_next_instr_without_modifiers = target_instr + 1 + _PyOpcode_Caches[_PyOpcode_Deopt[opcode]]; _Py_CODEUNIT *computed_next_instr = computed_next_instr_without_modifiers + (computed_next_instr_without_modifiers->op.code == NOT_TAKEN); _Py_CODEUNIT *computed_jump_instr = computed_next_instr_without_modifiers + oparg; assert(next_instr == computed_next_instr || next_instr == computed_jump_instr); int jump_happened = computed_jump_instr == next_instr; + // Jump is likely but it did not happen this time. Indicates we are likely tracing + // an uncommmon path. Stop the trace early here to prevent trace explosion. + if (jump_likely != jump_happened) { + goto unsupported; + } uint32_t uopcode = BRANCH_TO_GUARD[opcode - POP_JUMP_IF_FALSE][jump_happened]; ADD_TO_TRACE(uopcode, 0, 0, INSTR_IP(jump_happened ? computed_next_instr : computed_jump_instr, old_code)); break; @@ -1226,7 +1234,7 @@ uop_optimize( int curr_stackentries = tstate->interp->jit_state.jit_tracer_initial_stack_depth; int length = interp->jit_state.jit_tracer_code_curr_size; // Trace too short, don't bother. - if (length <= 5) { + if (length <= 20) { return 0; } assert(length > 0); -- 2.47.3