Skip to content

Commit 7329403

Browse files
committed
builder: emitCallExceptionHandler → C orchestrator (W27c #2b Cat B)
Per theologian W27c pair-batch design 00:08:52Z + 16:57:48Z APPROVE; supervisor (α) local-accumulate posture. Conversion #2b in the 5-method PARTIAL backlog (now 3 → 2 PARTIAL Cat-B remaining); pair-batch sibling of W27c #2a (7135d94). Cat B residue elimination — pair-batch closure: this commit mirrors W27c #2a emitInlineExceptionMatch's shape and reuses the same C helper build_inline_except_opcode_array_c (introduced in #2a). The pre-resolve loop that previously ran on the C++ side (BytecodeInstruction iteration + PyTuple_GET_ITEM(co_consts) for LOAD_CONST/RETURN_CONST + getBlockAtOff for JUMP_BACKWARD* + the terminator-detection skip-list) is deleted C++-side and replaced with a single helper invocation in the C body. Signature change: hir_builder_emit_call_exception_handler_c drops (opcodes, opcode_count) params; builds opcode array internally from PyCodeObject (via tc->frame.code) + builder block_map + except_body_offset, identical to the #2a entry path. C++ stub shrinks from ~70 lines to ~25. D1 pre-amble (call_instr->setSuppressExceptionDeopt(true) + phx_ptr_arr_pop on tc.frame.stack) stays C++-side because DeoptBase*/Register* are C++-only types — that boundary is intentional and unchanged. D3 ok-block sequence (RefineType in-place SSA-rename + push result back to outer tc stack to undo emitAnyCall's pre-amble pop) preserved verbatim. Bridge-struct elimination (bonus cleanup): with both #2a and #2b now C-side for opcode-array construction, the C++/C bridge struct OpcodeArrayEntry_CXX (+ its static_assert) in builder.cpp has zero remaining references. Deleted entirely. The C-side OpcodeArrayEntry struct in builder_emit_c.c stays (still used by emit_except_match_body_c). This realises the design intent stated in W27c #2a's commit message ("Eliminates OpcodeArrayEntry C++/C bridge struct entirely"). Honest ratio framing per librarian D-1776879377 / D-1776880214: post-conversion 98/100 PURE-CONVERTED + 2 PARTIAL Cat-B remaining (was 97/100 + 3 PARTIAL after W27c #2a). emitCallExceptionHandler is now a delegation stub, not pure-C++-eliminated; same metric reading as the established honest-scope record. Remaining 2 PARTIAL are emitAnyCall (await-tail residue, design-residual per pythia python#128 D-1777029012) and emitLoadMethodStatic (classloader.h _PyType_VTable struct dependency, design-residual per A1 rule). VERIFICATION: deferred to testkeeper full gate cycle (post-reboot fresh verifications per supervisor 16:54:08Z stale-pre-reboot discipline). All pre-reboot results (testkeeper 00:48:33Z + 01:45:23Z + 05:39:16Z) RETIRED. Push 54 batch (W27c python#1 7bfb7d1 + #2a 7135d94 + this commit) gated on: - x86_64 fresh build + JIT smoke + nbody + W-RE-PARSER substrate-stability + Phoenix CPython suite + ABBA 4-bench - ARM64 STRICT verify on 3-commit bundle (devgpu004 connectivity restored 16:53Z post-server-reboot) - gatekeeper APPROVE - supervisor PUSH AUTHORIZED Auth chain: theologian design 00:08:52Z + APPROVE 16:57:48Z; supervisor (α) authorization 00:07:10Z + 16:55:47Z plan; testkeeper standby for fresh full gate (post-reboot discipline).
1 parent 7135d94 commit 7329403

2 files changed

Lines changed: 22 additions & 58 deletions

File tree

Python/jit/hir/builder.cpp

Lines changed: 9 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1326,18 +1326,10 @@ bool HIRBuilder::getSimpleExceptInfo(
13261326
return true;
13271327
}
13281328

1329-
// OpcodeArrayEntry — mirror of the C-side struct in builder_emit_c.c.
1330-
// 5 fields per entry. Layout MUST match (verified via static_assert).
1331-
struct OpcodeArrayEntry_CXX {
1332-
int opcode;
1333-
int oparg;
1334-
int base_offset;
1335-
void* const_obj;
1336-
void* jump_target_block;
1337-
};
1338-
static_assert(sizeof(OpcodeArrayEntry_CXX) <= 64,
1339-
"OpcodeArrayEntry size sanity");
1340-
1329+
// W27c #2a + #2b: OpcodeArrayEntry C++/C bridge struct eliminated. The
1330+
// pre-resolve loop now runs entirely C-side via
1331+
// build_inline_except_opcode_array_c in builder_emit_c.c, sharing the
1332+
// helper between emitInlineExceptionMatch and emitCallExceptionHandler.
13411333
extern "C" void hir_builder_emit_inline_exception_match_c(
13421334
void* tc, void* func, void* builder,
13431335
int bc_base_offset,
@@ -1391,9 +1383,7 @@ extern "C" void hir_builder_emit_call_exception_handler_c(
13911383
int except_body_offset,
13921384
HirType return_type,
13931385
void* result,
1394-
void* match_and_clear_fn,
1395-
const OpcodeArrayEntry_CXX* opcodes,
1396-
size_t opcode_count);
1386+
void* match_and_clear_fn);
13971387

13981388
void HIRBuilder::emitCallExceptionHandler(
13991389
CFG& /*cfg*/,
@@ -1409,46 +1399,12 @@ void HIRBuilder::emitCallExceptionHandler(
14091399
// preserved for Simplify, register allocation, other deopt paths.
14101400
// 2. Pop the result that emitAnyCall pushed onto the stack — the C
14111401
// body's deopt path expects a clean stack at the CALL offset.
1402+
// W27c #2b: pre-resolve opcode array now built C-side via
1403+
// build_inline_except_opcode_array_c (shared with W27c #2a
1404+
// emitInlineExceptionMatch).
14121405
call_instr->setSuppressExceptionDeopt(true);
14131406
static_cast<Register*>(phx_ptr_arr_pop(&tc.frame.stack));
14141407

1415-
// Build OpcodeArray identical-shape to emitInlineExceptionMatch — the
1416-
// dispatch loop in the shared C helper expects this layout. Pre-resolves
1417-
// const_obj (LOAD_CONST/RETURN_CONST) + jump_target_block (JUMP_BACKWARD*)
1418-
// to keep PyCodeObject + getBlockAtOff access on the C++ side.
1419-
std::vector<OpcodeArrayEntry_CXX> opcodes;
1420-
BytecodeInstruction ebc{code_, info.except_body};
1421-
bool emitted_terminator = false;
1422-
while (!emitted_terminator) {
1423-
OpcodeArrayEntry_CXX entry{
1424-
ebc.opcode(),
1425-
ebc.oparg(),
1426-
ebc.baseOffset().value(),
1427-
nullptr,
1428-
nullptr};
1429-
int op = entry.opcode;
1430-
if (op == LOAD_CONST || op == RETURN_CONST) {
1431-
entry.const_obj = PyTuple_GET_ITEM(code_->co_consts, entry.oparg);
1432-
}
1433-
if (op == JUMP_BACKWARD || op == JUMP_BACKWARD_NO_INTERRUPT) {
1434-
entry.jump_target_block =
1435-
static_cast<void*>(getBlockAtOff(ebc.getJumpTarget()));
1436-
}
1437-
if (op == RETURN_VALUE || op == RETURN_CONST
1438-
|| op == JUMP_BACKWARD || op == JUMP_BACKWARD_NO_INTERRUPT) {
1439-
emitted_terminator = true;
1440-
} else if (op != POP_EXCEPT && op != POP_TOP && op != SWAP
1441-
&& op != LOAD_FAST && op != LOAD_FAST_CHECK
1442-
&& op != LOAD_FAST_AND_CLEAR && op != LOAD_CONST
1443-
&& op != STORE_FAST && op != BINARY_OP) {
1444-
emitted_terminator = true;
1445-
}
1446-
opcodes.push_back(entry);
1447-
if (!emitted_terminator) {
1448-
ebc = ebc.nextInstr();
1449-
}
1450-
}
1451-
14521408
hir_builder_emit_call_exception_handler_c(
14531409
static_cast<void*>(&tc),
14541410
static_cast<void*>(current_func_),
@@ -1459,9 +1415,7 @@ void HIRBuilder::emitCallExceptionHandler(
14591415
info.except_body.value(),
14601416
Type::toHirType(preloader_.returnType()),
14611417
static_cast<void*>(result),
1462-
reinterpret_cast<void*>(JITRT_MatchAndClearException),
1463-
opcodes.data(),
1464-
opcodes.size());
1418+
reinterpret_cast<void*>(JITRT_MatchAndClearException));
14651419
}
14661420

14671421
BasicBlock* HIRBuilder::getBlockAtOff(BCOffset off) {

Python/jit/hir/builder_emit_c.c

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3568,15 +3568,23 @@ void hir_builder_emit_call_exception_handler_c(
35683568
int except_body_offset,
35693569
HirType return_type,
35703570
void *result,
3571-
void *match_and_clear_fn,
3572-
const OpcodeArrayEntry *opcodes,
3573-
size_t opcode_count) {
3571+
void *match_and_clear_fn) {
35743572
HirType t_object = HIR_TYPE_OBJECT;
35753573

35763574
/* (D1) Pre-amble (setSuppressExceptionDeopt + pop result) is done on
35773575
* the C++ stub side BEFORE this C body — see builder.cpp emitter.
35783576
* The C body's first action is the ok/exc branch on result. */
35793577

3578+
/* W27c #2b: pre-resolve opcode array C-side (was C++ stub). Shares
3579+
* the helper with hir_builder_emit_inline_exception_match_c (W27c #2a).
3580+
* code accessible via tc->frame.code (set by frame init in
3581+
* hir_builder_state_emit_phase). */
3582+
OpcodeArrayEntry *opcodes = NULL;
3583+
size_t opcode_count = 0;
3584+
build_inline_except_opcode_array_c(
3585+
(PyCodeObject*)tc->frame.code, builder, except_body_offset,
3586+
&opcodes, &opcode_count);
3587+
35803588
void *ok_block = hir_cfg_alloc_block(func);
35813589
void *exc_match_block = hir_cfg_alloc_block(func);
35823590
phx_tc_emit(tc, hir_c_create_cond_branch_cpp(result, ok_block, exc_match_block));
@@ -3597,6 +3605,8 @@ void hir_builder_emit_call_exception_handler_c(
35973605
tc->block = ok_block;
35983606
phx_tc_emit(tc, hir_c_create_refine_type_reg(result, t_object, result));
35993607
phx_ptr_arr_push(&tc->frame.stack, result);
3608+
3609+
PyMem_RawFree(opcodes);
36003610
}
36013611

36023612
/* emitAnyCall full conversion — W26 (theologian L2462+L2466).

0 commit comments

Comments
 (0)