Skip to content

feat(coro): add runnable stackless scheduler and panic prototype - #23

Merged
cpunion merged 32 commits into
llvm-corofrom
coro/phase14-plain-dispatch
Jul 16, 2026
Merged

feat(coro): add runnable stackless scheduler and panic prototype#23
cpunion merged 32 commits into
llvm-corofrom
coro/phase14-plain-dispatch

Conversation

@cpunion

@cpunion cpunion commented Jul 16, 2026

Copy link
Copy Markdown
Owner

Summary

  • keep one primary body per statically known function and use descriptors only for genuinely dynamic consumers
  • lower multi-block LLVM coroutines with aggregate/PHI transport, transparent child await, compiler safepoint preemption, and caller-frame park/wake
  • lower exact closed-static go f(args) through compiler-owned begin/initial-suspend/commit, with no runtime user callback or TLS lookup
  • cancel ready spawned Gs safely when command main returns normally, destroying LLVM frames deepest-to-root and reclaiming each task once
  • lower a strict terminal-only ExplicitStatus panic subset through SuspendPanic and a no-TLS runtime handoff
  • link and execute native+nogc scheduler islands for both static spawn/shutdown and a three-frame terminal panic
  • support LLVM 19 through 22 via llvm: sync complete upstream LLVM 22 support llvm#5
  • link and execute freestanding wasip2 and wasm-unknown core modules without libuv or BDWGC

Scope and current boundary

This is an incremental integration PR for xgo-dev#1546, not a claim that the complete Go runtime is already supported.

Static spawn is deliberately fail-closed: only top-level, non-capturing, non-generic, non-variadic, zero-result targets are accepted; owner and target use one preemptible DirectCoro primary. Command shutdown currently accepts only YieldOnly|AwaitStructured spawned trees and rejects non-empty wait sets.

llgo.coro.panic.explicit-status.v0 is identity-wired. The compiler now accepts only cleanup-free PhysicalABIV1 bodies whose explicit panic is an empty-interface concrete pointer backed by typed nil or package-global storage. It publishes SuspendPanic/FinalSuspended, calls __llgo_coro_panic_prepare_v1(g, handle, header, typeWord, dataWord), and branches to the same LLVM final suspend as normal completion. The runtime retains the two-word record, destroys the active frame and suspended-await ancestors without resuming them, and returns PanicComplete.

The production internal/build capability gate remains closed. Dynamic interface/scalar/local/parameter payloads, managed plain unwinds, defer/recover/Goexit/implicit faults, dynamic error.Error/Stringer reporting, and final printer/exit ownership are not implemented.

The runnable native smokes are deliberately closed scheduler islands with bounded init no-ops and fail-stop libc/allocation stubs. They prove real compiler/runtime linkage and execution without claiming full standard-library runtime startup.

Other remaining blockers include stable wait-producer unregister/cancellation, real tick/event sources, channel/timer/netpoll/syscall producers, precise suspended-frame GC, dynamic/closure/method spawn, and multi-P scheduling.

All coroutine frames are LLVM stackless coroutine frames; this branch does not add per-G pthread, ucontext, native, or RTOS stacks.

Validation

  • LLVM 19/20/21/22 pre- and post-CoroSplit verification and object emission
  • native64 and wasm32 compiler tests for explicit panic state publication, a shared final suspend, and absence of legacy runtime.Panic/Rethrow
  • native final link/run for nested static spawn and command-main cancellation (Before=1, After=0, Leaf=0)
  • native final link/run for bootstrap → main → panicChild, proving three distinct handles are destroyed once, ancestors do not resume, and the task-local panic record survives
  • target-neutral scheduler race/shuffle tests for once publication, deepest-to-root destruction, ready-child shutdown, and terminal scheduling races
  • native and JS/WASM runtime adapter tests
  • actual llgo build -target=wasip2 and -target=wasm-unknown link/symbol closure smoke; wasmtime execution when available
  • final symbol audits requiring production scheduler/panic core while excluding legacy Panic/Rethrow/TracePanic/printany

Dependency

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review

This pull request introduces significant enhancements to the coroutine lowering and runtime ABI, including support for plain Go function value dispatching (EnableCoroPlainDispatch), a pure SSA operation auditor for coroutines, and a five-stage heterogeneous startup program (ValidateRunnableProgramV2). It also adds freestanding WebAssembly target support (wasip2, wasm-unknown) with a leaking GC profile and the llgo.coroPark intrinsic. Feedback on the changes highlights a potential loss of debuggability due to the removal of p.debugParams during the refactoring of compileCoroPhysicalBody.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread cl/coro_abi.go
Comment on lines +522 to 533
func (p *context) compileCoroPhysicalBody(b llssa.Builder, fn *ssa.Function, abi coroPhysicalABI, isInit bool) {
oldBase := p.sourceParamBase
oldCoro := p.currentCoro
oldSourceBlocks := p.coroSourceBlocks
p.sourceParamBase = 2
defer func() {
p.sourceParamBase = oldBase
p.currentCoro = oldCoro
p.coroSourceBlocks = oldSourceBlocks
}()

b.SetBlock(p.fn.Block(0))

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The call to p.debugParams(b, fn) seems to have been removed during the refactoring of compileCoroPhysicalBody. This function is responsible for emitting debug information for the coroutine's parameters, which is crucial for debugging. Its removal will likely result in a loss of debuggability for coroutines. Was this intentional? If not, please consider reintroducing it.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

It was moved, not dropped. compileCoroPhysicalBody now installs the explicit source-block map and then routes block 0 through compileBlock; that existing path calls p.debugParams after the initial suspend, in the logical source block where parameter locations dominate source instructions. Emitting it in the old physical ramp would use the wrong block mapping. Commit 1734c3a strengthens TestCoroLeafPhysicalABIGlobalDebug to require both DILocalVariable(name: "value", arg: 1) and an actual dbg value/declare location record, so this is now covered explicitly.

@cpunion cpunion changed the title feat(coro): advance stackless scheduler prototype feat(coro): add stackless scheduler and static goroutine prototype Jul 16, 2026
@cpunion cpunion changed the title feat(coro): add stackless scheduler and static goroutine prototype feat(coro): add runnable stackless scheduler prototype Jul 16, 2026
@cpunion cpunion changed the title feat(coro): add runnable stackless scheduler prototype feat(coro): add runnable stackless scheduler and panic prototype Jul 16, 2026
@cpunion
cpunion merged commit 1c84c1d into llvm-coro Jul 16, 2026
6 checks passed
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