Skip to content

Add stack-safe async loop support with trampoline pattern#1905

Open
vbabanin wants to merge 5 commits intomongodb:mainfrom
vbabanin:JAVA-6120
Open

Add stack-safe async loop support with trampoline pattern#1905
vbabanin wants to merge 5 commits intomongodb:mainfrom
vbabanin:JAVA-6120

Conversation

@vbabanin
Copy link
Member

@vbabanin vbabanin commented Mar 4, 2026

  • Add AsyncTrampoline class to prevent stack overflow in loops by converting callback recursion into iterative execution
  • Add thenRunWhileLoop method to AsyncRunnable to support while-loop semantics where condition is checked before body execution
  • Integrate trampoline into AsyncCallbackLoop by making LoopingCallback implement Runnable to avoid per-iteration lambda allocation

JAVA-6120

- Add AsyncTrampoline class to prevent stack overflow in loops by converting callback recursion into iterative execution
- Add thenRunWhileLoop method to AsyncRunnable to support while-loop semantics where condition is checked before body execution
- Integrate trampoline into AsyncCallbackLoop by making LoopingCallback implement Runnable to avoid per-iteration lambda allocation

JAVA-6120
@vbabanin vbabanin self-assigned this Mar 4, 2026

LoopingCallback(final SingleResultCallback<Void> callback) {
wrapped = callback;
nextIteration = () -> body.run(this);
Copy link
Member Author

@vbabanin vbabanin Mar 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The nextIteration is reused to avoid creation of extra objects via LambdaMetafactory as we have the capturing lambda.

bounce.work = task is a write to a heap object's field, which can be considered an automatic escape in the JIT's analysis. Even if the Bounce object is short-lived, the JIT sees "object written to another object's field" and should give up.

The AsyncCallbackLoop JMH GC profiling (OpenJDK 17.0.10 LTS, 64-bit Server VM, mixed mode with compressed oops).

Metric Runnable (this) Lambda
Alloc rate 0.039 MB/sec 96.924 MB/sec
Alloc per op 64 B/op 160,048 B/op
GC count ~ 0 10
GC time 0 ms 9 ms

For Lambda case:
Per iteration: 1 lambda * 16 bytes = 16 B

  • Per op (10,000 iterations): 10,000 * 16 = 160,000 B
  • Plus one-time objects ~ 48 B

@vbabanin vbabanin marked this pull request as ready for review March 7, 2026 00:13
@vbabanin vbabanin requested a review from a team as a code owner March 7, 2026 00:13
@vbabanin vbabanin requested review from nhachicha, stIncMale and strogiyotec and removed request for nhachicha March 7, 2026 00:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant