Automatic tail-call optimization (auto-TCO) in StaticOptimizer#694
Draft
He-Pin wants to merge 1 commit intodatabricks:masterfrom
Draft
Automatic tail-call optimization (auto-TCO) in StaticOptimizer#694He-Pin wants to merge 1 commit intodatabricks:masterfrom
He-Pin wants to merge 1 commit intodatabricks:masterfrom
Conversation
Detect self-recursive calls in tail position during static optimization and mark them for the TailCall trampoline, eliminating JVM stack overflow on deep recursion without requiring users to annotate call sites with 'tailstrict'. Key design: introduce TailstrictModeAutoTCO — a third TailstrictMode that enables the trampoline (like TailstrictModeEnabled) but does NOT force eager argument evaluation (unlike explicit tailstrict). This preserves Jsonnet's standard lazy evaluation semantics for auto-TCO'd calls. Implementation: - StaticOptimizer.transformBind: detects self-recursive function bindings - hasNonRecursiveExit: safety check ensuring at least one non-recursive code path exists (prevents infinite trampoline on trivially infinite functions like f(x) = f(x)) - markTailCalls: walks the AST marking self-recursive tail calls with tailstrict=true, autoTCO=true - Expr: adds isAutoTCO/autoTCO field to Apply0-3 and Apply case classes - Val: adds TailstrictModeAutoTCO, TailCall.autoTCO flag, restores @tailrec on TailCall.resolve - Evaluator: visitExprWithTailCallSupport uses visitAsLazy for auto-TCO args; visitApply* defensively handles auto-TCO for future-proofing Test: auto_tco.jsonnet with 6 patterns including lazy semantics regression test (error in auto-TCO'd args is NOT eagerly evaluated). Upstream: databricks#623
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.
Motivation
Jsonnet supports
tailstrictkeyword for explicit tail-call optimization, but users must manually annotate functions. Many naturally tail-recursive functions miss this optimization because users don't addtailstrict.Key Design Decision
Automatically detect tail-recursive function calls in the StaticOptimizer and convert them to use the tail-call trampoline. This makes tail-call optimization transparent — users get the performance benefit without code changes.
Modification
tailstrictsemantics when safeBenchmark Results
JMH (JVM, 3 iterations warmup + 3 measurement)
Analysis
All benchmarks show consistent improvement. The reverse benchmark (-11.1%) directly benefits from auto-TCO as
std.reverseuses recursion. The broader improvements suggest that many internal stdlib functions and user code patterns have tail-recursive structures that now benefit from the trampoline. This is a significant usability improvement — users no longer need to manually addtailstrict.References
tailstrictkeywordResult
All 7 tests pass. All benchmarks positive across all 4 benchmarks tested, no regressions.