Repository navigation
Python calls run on the machine instead of recursing in C - #16
Merged
Merged
Conversation
A function body that holds a call, and is not a generator, compiles to machine steps; its calls of such functions push a frame on the context's call stack and the same run_machine loop continues. A recursion is bounded by the recursion limit, not by the C stack: sys.setrecursionlimit(200000) then a 100000-deep recursion now returns, as on CPython, where it raised "Stack overflow" before. Calls C makes into Python still nest. Found on the way: an error raised by __exit__ during a machine unwind got no __context__, and the machine reported try/except bookkeeping as trace line events. make test: all green (spec 419/419, std 176/176 probes, api, oom, threads). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Bq79MgongGBn3NvB5dYBoj
Calls in a function body run as BC_CALLF (operands at hand), BC_CALLN (arguments on the stack) or BC_CALL, out of line; a call's frame lives on its machine, and entering, returning and unwinding share one switch. The statements after a body's last call are one walker step. A generator's call steps never enter a flat call. SpyCalls models the call stack. make test: green, spec 419/419. M2, mean over 8 layouts, main -> this: fib 31.0 -> 33.5 ms (instructions -12%), classes 86.2 -> 88.7 ms, generators +0.6%, nbody -0.7%, loop +0.7%, others within 1%. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Bq79MgongGBn3NvB5dYBoj
Returning and entering switch machines through the Call at hand rather than reloading c->calls, so the next step's dispatch waits on one load. make test: green, spec 419/419. M2, mean over 8 layouts, main -> this: fib 31.7 -> 31.0 ms (-2.4%, 96.5M cycles against 99M), generators -0.4%, classes +2.2%, nbody, loop, sort, strings within 0.4%. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Bq79MgongGBn3NvB5dYBoj
call_function keeps its walker path as it was; call_machine holds the inlined call_enter, run_machine and call_leave. make test: green, spec 419/419. M2, mean over 8 layouts, main -> this (cycles): fib 98.0M -> 95.8M (-2.2%), classes 276.2M -> 281.8M (+2.0%), generators -0.1%, nbody +0.3%. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Bq79MgongGBn3NvB5dYBoj
An annotation or type alias value function's body is one N_ANNOTATIONS statement, which the machine compiled as a class statement and crashed on. Entering and ending a finally on the machine no longer reset the frame's line to the try's. Docs: manual, ROADMAP and optimization.md describe calls on the machine with their measurements. make test: green, spec 419/419; make test-tla (Linux container): every model passes, Annotations, TypeAliases and Tracebacks among them; make coverage: every engine line runs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Bq79MgongGBn3NvB5dYBoj
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Python-to-Python calls no longer recurse in C. A function body that holds a call and cannot suspend compiles to machine steps (
Node.flat). When such a body calls another such function, the call pushes aCallon the context's call stack and the samerun_machineloop goes on. A return pops the call and dispatches the caller's next step. Deep recursion is now bounded by the recursion limit alone:tests/apiruns a 50,000-deep recursion in a 64 KiB C stack.Calls that C makes still enter a new
run_machineand keep the C stack guard. These come from the walker, special methods, host callbacks and trace functions.BC_CALLFwhen its arguments are operators of literals and names, computed in place, orBC_CALLNwhen its arguments are on the stack. Keyword calls stay onBC_CALL. All three run out of line, so generators, which share the loop, keep their registers.ifandreturnare machine steps inside such bodies. Aforwhose only call is its iterable stays a walker statement. The statements after a body's last call form one walker step (BC_BLOCK).withbody whose__exit__raised lost its error context;finallyreset the frame's line to thetry's line;tests/tla/SpyCallsmodels the call stack:Performance
M2, cycles averaged over 8 code layouts, main → this branch:
classes is still 2% slower on the M2. On Linux clang, callgrind counts about 1% fewer instructions on classes than main, so the gap comes from Apple clang's code generation. It is still open.
Test plan
make test: green, spec 419/419make test-tlain a Linux container: every model passes, SpyCalls includedmake coverage: every engine line runs (spy.c 25916/25916)tools/run_workflow.py: test job with clang and gcc (sanitize included)tools/run_workflow.py: packages and archive🤖 Generated with Claude Code
https://claude.ai/code/session_01Bq79MgongGBn3NvB5dYBoj