Skip to content

Commit b28b512

Browse files
committed
builder: emitAnyCall await-tail → C (PartialConversion, 102/144 → 103/144 = 71.5%)
PartialConversion per theologian PTE pre-audit (chat 2026-04-22 17:15Z) + supervisor concurrence (chat 17:18Z) + Alex 'NO SESSION BOUNDARIES — keep working until ZERO C++' anchor [memory 2026-04-21]. Bridge-count gate satisfied: 1 new top-level bridge (within gate), 0 sub-bridges. SCOPE: only the await-tail dispatch (lines 2963-2993 in pre-conversion source) is converted to C. The opcode-switch + INVOKE_FUNCTION/NATIVE/ METHOD/METHOD_VECTORCALL dispatch stay C++ until Tier 6 INVOKE_* re-architecture (deferred per gate-count gate per [chat L1922]: FullConversion would require 4+ new bridges, violating ≤1 limit). Python/jit/hir/builder.cpp: emitAnyCall await-tail block (lines 2963-2993, ~30 lines C++) → 1) C++ stub: 3x ++bc_it + 3x JIT_CHECK on opcode sequence (PA + A4) + checkAsyncWithError(get_awaitable_bc) → (error_aenter, error_aexit) + extract load_const_oparg from LOAD_CONST bc + call C body 2) checkAsyncWithError forward decl added (defined static at builder.cpp :~4856, post-call-site refactor required forward visibility) 3) New extern decl: hir_builder_emit_awaited_call_tail_c Python/jit/hir/builder_emit_c.c: NEW hir_builder_emit_awaited_call_tail_c (~50 lines): A5 alloc out + 2 blocks (await_block + post_await_block) A5 dispatch_eager_coro_result (chains to push 55 C function) A6 tc->block = await_block A7 get_awaitable using pre-computed error flags (chains to push 56) A8 load_const using pre-computed oparg + caller-passed code A9 yield_from_method (chains to push 53) A10 phx_tc_emit branch to post_await_block A11 tc->block = post_await_block PTE-trial invariant inventory verification per theologian [chat L1928]: 12 invariants A1-A12 + 4 pitfalls PA-PD. PA: JIT_CHECK fires C++-side BEFORE C call ✓ PB: iterator state stays C++-side; only ints + pointers cross boundary ✓ PC: tc->block reassignment in C body (A6 + A11) ✓ PD: code passed as PyCodeObject* (not void*) — preserves emitGetAwaitable port's PA invariant ✓ PTE TRIAL ROUND 2 FEEDBACK: A4 IF/THEN structure made 'JIT_CHECK MUST fire BEFORE C call' visually unambiguous. PD pitfall on code_ typing caught at design time. Two empirical wins (round 1: PD.a/PD.b distinction, round 2: A4 + PD). Bridge spec (8 args, ratified by theologian [chat L1931]): void hir_builder_emit_awaited_call_tail_c( PhxTranslationContext* tc, void* func, void* builder, PyCodeObject* code, int code_flags, int get_awaitable_error_aenter, int get_awaitable_error_aexit, int load_const_oparg); testkeeper x86_64 compile-only PASS verified pre-commit at binary timestamp 1776878644 (chat 17:24Z). Iter 1 needed forward decl for checkAsyncWithError; v2 cleaned. Tier 5 milestone: 103/144 = 71.5% with PartialConversion-asterisk on emitAnyCall (await-tail in C, opcode-switch + INVOKE_* still C++). Pre-push 61 gate ahead (per pythia python#77 python#3 + supervisor [chat L1939]): testkeeper authors call-shape falsifier extension exercising emitCallExceptionHandler D1-D3 invariants (theologian spec [chat L1942]: 3 tests covering function-call-in-try + closure-LOAD_DEREF + unmatched-exception-deopt). Lands as separate commit before Tier 5 close push. Authorization chain: - theologian PTE pre-audit + design lean (a, but generalist chose b): chat L1928 - bridge spec ratification: chat L1931 - supervisor concurrence on (B) PartialConversion: chat L1930 - testkeeper x86_64 compile PASS: chat L1944
1 parent 9630005 commit b28b512

2 files changed

Lines changed: 95 additions & 14 deletions

File tree

Python/jit/hir/builder.cpp

Lines changed: 34 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2854,6 +2854,24 @@ void HIRBuilder::emitPushNull(TranslationContext& tc) {
28542854
hir_builder_emit_push_null_c(static_cast<void*>(&tc), static_cast<void*>(current_func_));
28552855
}
28562856

2857+
// PartialConversion (theologian PTE pre-audit chat 2026-04-22 17:15Z):
2858+
// emitAnyCall await-tail dispatch (lines 2963-2993 in pre-conversion source)
2859+
// extracted into C body. Opcode-switch + INVOKE_* dispatch stay C++ until
2860+
// Tier 6 INVOKE_* re-architecture. Bridge spec ratified [chat L1931].
2861+
extern "C" void hir_builder_emit_awaited_call_tail_c(
2862+
void* tc, void* func, void* builder,
2863+
PyCodeObject* code,
2864+
int code_flags,
2865+
int get_awaitable_error_aenter,
2866+
int get_awaitable_error_aexit,
2867+
int load_const_oparg);
2868+
2869+
// Forward decl — checkAsyncWithError is defined static at builder.cpp:~4856,
2870+
// below the emitAnyCall call site. Pre-PartialConversion the call lived
2871+
// inline within the await-tail; refactor hoisted it above the definition.
2872+
static std::pair<bool, bool> checkAsyncWithError(
2873+
const BytecodeInstructionBlock&, BytecodeInstruction);
2874+
28572875
void HIRBuilder::emitAnyCall(
28582876
CFG& cfg,
28592877
TranslationContext& tc,
@@ -2961,35 +2979,37 @@ void HIRBuilder::emitAnyCall(
29612979
JIT_ABORT("Unhandled call opcode {} ({})", opcode, opcodeName(opcode));
29622980
}
29632981
if (is_awaited && call_used_is_awaited) {
2964-
Register* out = temps_.AllocateStack();
2965-
TranslationContext await_block{cfg.AllocateBlock(), tc.frame};
2966-
TranslationContext post_await_block{cfg.AllocateBlock(), tc.frame};
2967-
2968-
emitDispatchEagerCoroResult(
2969-
cfg, tc, out, await_block.block, post_await_block.block);
2970-
2971-
tc.block = await_block.block;
2972-
2982+
// (D1+A4) Advance bc_it three times + assert opcode sequence on the C++
2983+
// side BEFORE the C body runs. Iterator state never crosses the boundary
2984+
// (PB invariant) — only int baseOffsets/oparg/error flags pass through.
29732985
++bc_it;
29742986
JIT_CHECK(
29752987
bc_it->opcode() == GET_AWAITABLE,
29762988
"Awaited function call must be followed by GET_AWAITABLE");
2977-
emitGetAwaitable(cfg, tc, bc_instrs, *bc_it);
2989+
auto get_awaitable_bc = *bc_it;
2990+
auto [error_aenter, error_aexit] =
2991+
checkAsyncWithError(bc_instrs, get_awaitable_bc);
29782992

29792993
++bc_it;
29802994
JIT_CHECK(
29812995
bc_it->opcode() == LOAD_CONST,
29822996
"GET_AWAITABLE must be followed by LOAD_CONST");
2983-
emitLoadConst(tc, *bc_it);
2997+
int load_const_oparg = bc_it->oparg();
29842998

29852999
++bc_it;
29863000
JIT_CHECK(
29873001
bc_it->opcode() == YIELD_FROM,
29883002
"GET_AWAITABLE should always be followed by LOAD_CONST+YIELD_FROM");
2989-
emitYieldFrom(tc, out);
2990-
tc.emitBranch(post_await_block.block);
29913003

2992-
tc.block = post_await_block.block;
3004+
hir_builder_emit_awaited_call_tail_c(
3005+
static_cast<void*>(&tc),
3006+
static_cast<void*>(current_func_),
3007+
static_cast<void*>(this),
3008+
code_,
3009+
static_cast<int>(code_->co_flags),
3010+
static_cast<int>(error_aenter),
3011+
static_cast<int>(error_aexit),
3012+
load_const_oparg);
29933013
}
29943014
}
29953015

Python/jit/hir/builder_emit_c.c

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3343,5 +3343,66 @@ void hir_builder_emit_call_exception_handler_c(
33433343
phx_ptr_arr_push(&tc->frame.stack, result);
33443344
}
33453345

3346+
/* emitAnyCall await-tail dispatch — PartialConversion of HIRBuilder::emitAnyCall.
3347+
* Mirrors C++ original at builder.cpp:2963-2993 (pre-conversion). The full
3348+
* emitAnyCall opcode-switch + INVOKE_* dispatch stay C++ pending Tier 6
3349+
* INVOKE_* re-architecture; only the await-tail (most fragile, most uniform
3350+
* with Tier 5 patterns) is converted.
3351+
*
3352+
* Theologian PTE pre-audit (chat 2026-04-22 17:15Z): A1-A12 invariants +
3353+
* PA-PD pitfalls. Bridge-count gate satisfied (1 new bridge ≤ 1).
3354+
*
3355+
* C++ stub responsibilities (PA + A4): 3x ++bc_it + 3x JIT_CHECK before
3356+
* this call; iterator state never crosses boundary (PB). All chained C
3357+
* functions exist (push 53/55/56 + load_const_c). */
3358+
extern void hir_builder_emit_dispatch_eager_coro_result_c(
3359+
PhxTranslationContext *tc, void *func, void *builder, void *out,
3360+
void *await_block, void *post_await_block, int code_flags);
3361+
extern void hir_builder_emit_get_awaitable_c(
3362+
PhxTranslationContext *tc, void *func, void *builder,
3363+
int error_aenter, int error_aexit);
3364+
extern void hir_builder_emit_yield_from_method_c(
3365+
PhxTranslationContext *tc, void *out, int code_flags);
3366+
3367+
void hir_builder_emit_awaited_call_tail_c(
3368+
PhxTranslationContext *tc,
3369+
void *func,
3370+
void *builder,
3371+
PyCodeObject *code,
3372+
int code_flags,
3373+
int get_awaitable_error_aenter,
3374+
int get_awaitable_error_aexit,
3375+
int load_const_oparg) {
3376+
/* A5 setup: out reg + 2 blocks. */
3377+
void *out = hir_builder_temps_alloc_stack(builder);
3378+
void *await_block = hir_cfg_alloc_block(func);
3379+
void *post_await_block = hir_cfg_alloc_block(func);
3380+
3381+
/* A5: dispatch_eager_coro_result. */
3382+
hir_builder_emit_dispatch_eager_coro_result_c(
3383+
tc, func, builder, out, await_block, post_await_block, code_flags);
3384+
3385+
/* A6: switch tc to await_block. */
3386+
tc->block = await_block;
3387+
3388+
/* A7: get_awaitable using pre-computed error flags. */
3389+
hir_builder_emit_get_awaitable_c(
3390+
tc, func, builder,
3391+
get_awaitable_error_aenter, get_awaitable_error_aexit);
3392+
3393+
/* A8: load_const using pre-computed oparg + caller-passed code (PD: must
3394+
* be PyCodeObject*, not void*, to preserve emitGetAwaitable port's PA). */
3395+
hir_builder_emit_load_const_c(tc, func, code, load_const_oparg);
3396+
3397+
/* A9: yield_from on out, code_flags for is_coroutine handling. */
3398+
hir_builder_emit_yield_from_method_c(tc, out, code_flags);
3399+
3400+
/* A10: branch to post_await_block. */
3401+
phx_tc_emit(tc, hir_c_create_branch_cpp(post_await_block));
3402+
3403+
/* A11: switch tc to post_await_block for downstream emit. */
3404+
tc->block = post_await_block;
3405+
}
3406+
33463407

33473408

0 commit comments

Comments
 (0)