Skip to content

windows: integrate OS and standard-library support (R6) - #2418

Merged
xushiwei merged 113 commits into
xgo-dev:mainfrom
cpunion:codex/windows-r6-stdlib-20260826
Aug 27, 2026
Merged

windows: integrate OS and standard-library support (R6)#2418
xushiwei merged 113 commits into
xgo-dev:mainfrom
cpunion:codex/windows-r6-stdlib-20260826

Conversation

@cpunion

@cpunion cpunion commented Aug 26, 2026

Copy link
Copy Markdown
Collaborator

Summary

This is R6 of the Windows support series tracked by #2325. It integrates the Windows OS and standard-library layer while preserving the existing macOS and Linux paths.

  • reuse and bridge the pinned Go Windows runtime and standard-library implementation
  • support files, processes, console signals, testing hooks, CPU profiling, and IOCP networking
  • add Windows language, extension, test/std, demo, symbol, and GOROOT coverage
  • finish the Windows ABI/runtime/test fixes found by the complete coverage run

Base and dependency boundary

This PR was rebased onto xgo-dev/llgo:main at a91a36b5be53, which contains R4 (#2404), R5 (#2405), and #2416. Its effective diff is therefore limited to the R6 OS and standard-library layer plus its CI dependency fix.

#2417 remains a separate contribution and is not duplicated here. In particular, the invalid receiver diagnostic remains owned by that PR.

The staging PR for this exact R6 work is cpunion#188.

Validation

The complete staging CI for cpunion#188 is green, including:

  • Windows native PE/COFF tests
  • Windows standard-library coverage
  • Linux and macOS build and test matrices
  • benchmarks and compatibility jobs

Native Windows ARM64 validation used Go 1.26.5 in Parallels. All 32 GOROOT coverage shards were exercised; this was not a sampled run.

The rebased upstream CI and coverage completed before merge.

Binary-size analysis

The benchmark compared 6886993dc80f with base a91a36b5be53. The reported growth is small and has two distinct causes: pre-DCE function metadata for newly added shared-runtime functions, and reachable runtime.Cleanup support pulled in by fmt through os/internal/poll. It is not caused by Windows-only code being compiled on Linux or macOS.

Platform Workload File delta Reported text delta Actual cause
Linux cprintf / LTO +288 B 0 B +288 B read-only function metadata
Linux println / LTO +320 B / +288 B +30 B / +32 B metadata plus a small mexit startup-root release path
Linux fmtprintf / LTO +2896 B / +2304 B +846 B / +764 B reachable Cleanup/poller code plus metadata and ELF bookkeeping/alignment
macOS cprintf / LTO 0 B +288 B 0 B machine code, +288 B __TEXT,__const metadata
macOS println / LTO 0 B +304 B +16 B machine code, +288 B metadata
macOS fmtprintf +16416 B +992 B +16 B machine code, +976 B metadata; the payload crosses one 16 KiB Mach-O segment boundary
macOS fmtprintf-lto 0 B +1008 B +32 B machine code and +976 B metadata; it remains within the existing segment allocation

On Mach-O, the benchmark's “text” metric includes every section in __TEXT, including read-only __const; it is therefore not a machine-code-only measurement.

The fixed 288 B increase is 18 net-new symbol-index entries at 16 B each. These entries cover shared runtime support added by this PR: cancellable Cleanup handling, proc-pin linkname bridges, goroutine state reporting, startup-root release, and fat map lookup.

For fmtprintf, the complete function-info table grows by 14 net records:

record table      14 × 28 B = 392 B
string pool                    292 B
string offsets    17 × 4 B  =  68 B
symbol index      14 × 16 B = 224 B
total                          976 B

LLGo currently collects function-info records before linker DCE and calls prepareFuncInfoTableRecords(..., nil), so no post-DCE live-symbol set is available to remove metadata for discarded functions. This explains why even cprintf, which does not execute the new runtime paths, still gains 288 B of metadata.

The larger Linux fmtprintf executable-code delta is dominated by the Go-compatible, pointer-free and cancellable Cleanup implementation (newCancelableCleanup, registerCleanupPtr, freeCleanupSlot, StopCleanupPtr, and the expanded finalizer), with smaller contributions from the Linux poll-descriptor check and goroutine startup-root release. These paths are reachable through the standard library and cannot be treated as Windows-only code.

A future post-DCE live-symbol filter for function metadata is the highest-leverage size optimization: it can remove the fixed 288 B from small programs and most of the 976 B metadata increase in fmtprintf. On the current macOS non-LTO layout, removing that metadata would also likely move fmtprintf back below the 16 KiB segment boundary, although that file-size cliff is alignment-dependent.

Benchmark details: #2418 (comment)

@cpunion

cpunion commented Aug 26, 2026

Copy link
Copy Markdown
Collaborator Author

@fennoai /review

@codecov

codecov Bot commented Aug 26, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 95.44160% with 16 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
internal/build/build.go 93.24% 3 Missing and 2 partials ⚠️
internal/build/plan9asm.go 80.00% 3 Missing and 2 partials ⚠️
internal/abi/large.go 95.91% 1 Missing and 1 partial ⚠️
internal/build/cgo.go 90.47% 1 Missing and 1 partial ⚠️
ssa/decl.go 92.59% 1 Missing and 1 partial ⚠️

📢 Thoughts on this report? Let us know!

@fennoai fennoai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review: Windows stdlib/runtime support

Reviewed the fixed range 6fe8bab...4e52fc7 (~15k lines, 381 files) across code-quality, performance, security, and documentation dimensions. This is a large, well-engineered addition of Windows support to the llgo runtime and toolchain. The new C/asm bridges (syscall_windows.S, fault_windows.c, profile_windows.c, thread_windows.c) are consistent across arches, free their handles/allocations on all paths, bound all PC-buffer writes, and the fault handler is defensively guarded (re-entrancy guard, null checks, parameter_count bounds). The SyscallN bridge enforces windowsSyscallMaxArgs before the call, print wrappers clamp chunk sizes against UINT32_MAX, and the build-time command construction uses exec.Command (no shell injection). Security review found nothing actionable.

One correctness finding is worth addressing (inline). A few minor/low-confidence items are listed below.

Minor / low-confidence (non-blocking):

  • runtime/internal/sync/_wrap/sync_windows.c:14#pragma comment(lib, "synchronization.lib") is an MSVC-only linker directive that clang with a GNU-style driver ignores; linking is already handled by sync_windows.go (LLGoPackage = "link: -lsynchronization"). It's redundant and slightly misleading; consider removing it.
  • Build-tag inconsistency for a hypothetical windows && baremetal build: thread_windows_gc.go uses //go:build windows && !nogc while foreign_thread_gc_windows.go uses //go:build llgo && windows && !nogc && !baremetal. A windows+baremetal build would select the GC thread backend but the stub foreign-thread side. Not a shipped config today, but the guards should be made consistent.
  • runtime/internal/runtime/z_print_write_windows.go:35-47PrintString re-queries c_printStderrIsConsole() (two syscalls: GetStdHandle+GetConsoleMode) on every non-ASCII print. Console-ness is fixed for process lifetime; caching it once (e.g. sync.Once) would match upstream Go. Bounded to the print/diagnostic path.
  • The 386 fault-context variant (fault_context_windows_386.go) lacks the compile-time size/offset assertions that the amd64/arm64 variants have; adding parallel [N-size]byte guards would make the three self-checking.

Comment thread runtime/internal/lib/runtime/poll_windows_llgo.go
@github-actions

github-actions Bot commented Aug 26, 2026

Copy link
Copy Markdown

LLGo baseline benchmarks

6886993dc80f | workflow run | long-term charts

Program measurements

Platform Workload File size vs base Text size vs base Build vs base Run vs base
Linux cprintf 19432 B +288 B / +1.5% (worse) 387 B 0 B / +0.0% 341.761 ms +9.857 ms / +3.0% (worse) 1.302 ms +37 us / +2.9% (worse)
Linux cprintf-lto 19264 B +288 B / +1.5% (worse) 368 B 0 B / +0.0% 340.970 ms +5.361 ms / +1.6% (worse) 1.300 ms -7.887 us / -0.6% (better)
Linux fmtprintf 1652152 B +2896 B / +0.2% (worse) 501874 B +846 B / +0.2% (worse) 2.553 s +20.34 ms / +0.8% (worse) 3.267 ms -6.733 us / -0.2% (better)
Linux fmtprintf-lto 1524104 B +2304 B / +0.2% (worse) 460334 B +764 B / +0.2% (worse) 8.631 s -65.87 ms / -0.8% (better) 3.091 ms -41.51 us / -1.3% (better)
Linux println 62264 B +320 B / +0.5% (worse) 15286 B +30 B / +0.2% (worse) 336.798 ms -717.7 us / -0.2% (better) 1.582 ms -120.1 us / -7.1% (better)
Linux println-lto 54096 B +288 B / +0.5% (worse) 12914 B +32 B / +0.2% (worse) 518.625 ms +2.749 ms / +0.5% (worse) 1.584 ms -16.68 us / -1.0% (better)
macOS cprintf 84480 B 0 B / +0.0% 16669 B +288 B / +1.8% (worse) 362.654 ms -33.85 ms / -8.5% (better) 2.317 ms -176.7 us / -7.1% (better)
macOS cprintf-lto 100704 B 0 B / +0.0% 16649 B +288 B / +1.8% (worse) 332.595 ms -85.83 ms / -20.5% (better) 2.212 ms -239.1 us / -9.8% (better)
macOS fmtprintf 1512800 B +16416 B / +1.1% (worse) 882808 B +992 B / +0.1% (worse) 1.790 s -840.8 ms / -32.0% (better) 4.651 ms -2.86 ms / -38.1% (better)
macOS fmtprintf-lto 1208464 B 0 B / +0.0% 875848 B +1008 B / +0.1% (worse) 4.851 s -1.582 s / -24.6% (better) 5.053 ms -1.699 ms / -25.2% (better)
macOS println 114784 B 0 B / +0.0% 35101 B +304 B / +0.9% (worse) 306.927 ms -69.97 ms / -18.6% (better) 3.311 ms -91.17 us / -2.7% (better)
macOS println-lto 118656 B 0 B / +0.0% 32753 B +304 B / +0.9% (worse) 420.655 ms -138.1 ms / -24.7% (better) 3.002 ms -142.5 us / -4.5% (better)
Core language and compiler benchmarks
Platform Benchmark ns/op vs base
Linux BenchmarkLookupPCRandom 13.140 ns/op -0.11 ns/op / -0.8% (better)
Linux BenchmarkMergeCompilerFlags 153.300 ns/op +1.8 ns/op / +1.2% (worse)
Linux BenchmarkMergeLinkerFlags 95.290 ns/op -0.23 ns/op / -0.2% (better)
Linux BenchmarkChannelBuffered 36.500 ns/op +0.35 ns/op / +1.0% (worse)
Linux BenchmarkChannelHandoff 26741 ns/op -1145 ns/op / -4.1% (better)
Linux BenchmarkDefer 45.570 ns/op -5.01 ns/op / -9.9% (better)
Linux BenchmarkDirectCall 1.867 ns/op +0.311 ns/op / +20.0% (worse)
Linux BenchmarkGlobalRead 1.868 ns/op +0.31 ns/op / +19.9% (worse)
Linux BenchmarkGlobalWrite 2.488 ns/op +0.02 ns/op / +0.8% (worse)
Linux BenchmarkGoroutine 42378 ns/op +10574 ns/op / +33.2% (worse)
Linux BenchmarkInterfaceCall 7.786 ns/op +0.306 ns/op / +4.1% (worse)
Linux BenchmarkRuntimeGetG 1.868 ns/op 0 ns/op / +0.0%
macOS BenchmarkLookupPCRandom 10.720 ns/op -0.89 ns/op / -7.7% (better)
macOS BenchmarkMergeCompilerFlags 111.500 ns/op -44.8 ns/op / -28.7% (better)
macOS BenchmarkMergeLinkerFlags 67.420 ns/op -22.2 ns/op / -24.8% (better)
macOS BenchmarkChannelBuffered 21.410 ns/op -1.74 ns/op / -7.5% (better)
macOS BenchmarkChannelHandoff 6510 ns/op -45 ns/op / -0.7% (better)
macOS BenchmarkDefer 28.430 ns/op +0.2 ns/op / +0.7% (worse)
macOS BenchmarkDirectCall 0.944 ns/op -0.0015 ns/op / -0.2% (better)
macOS BenchmarkGlobalRead 0.943 ns/op -0.0002 ns/op / -0.0212% (better)
macOS BenchmarkGlobalWrite 0.944 ns/op +0.0009 ns/op / +0.1% (worse)
macOS BenchmarkGoroutine 29137 ns/op -5175 ns/op / -15.1% (better)
macOS BenchmarkInterfaceCall 4.176 ns/op +0.092 ns/op / +2.3% (worse)
macOS BenchmarkRuntimeGetG 1.884 ns/op -0.001 ns/op / -0.1% (better)

Compared with a91a36b5be53 measured in the same runner job.

@fennoai

fennoai Bot commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

FennoAI is processing your request, please wait a moment...

@cpunion

cpunion commented Aug 26, 2026

Copy link
Copy Markdown
Collaborator Author

Review follow-up in 99f5edde0:

  • removed the redundant MSVC-only #pragma comment;
  • aligned Windows GC/nogc thread build tags with the existing baremetal split;
  • added compile-time Windows/386 CONTEXT-prefix size and PC/SP/FP offset assertions;
  • documented why canceled overlapped I/O must remain pinned until its IOCP completion (details in the inline reply).

I did not cache the stderr console probe: Go 1.26's runtime.write1 also re-runs GetStdHandle/GetConsoleMode for each non-ASCII write, which preserves behavior when the process changes or redirects its standard handles at runtime.

Validation for the follow-up: all three Windows MSVC C targets passed syntax checking, the Windows/386 runtime package compiled, and the Windows baremetal tag selects the nogc thread backend as intended. The unrelated local fixture edits visible in another worktree were not included.

@fennoai fennoai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review summary

R6 Windows OS/standard-library integration. This is a large PR (381 files); I focused the review on the core runtime, SSA, internal/build, internal/abi/internal/cabi, and the C wrappers, skipping test fixtures and demos.

Overall the implementation is careful and high quality: platform build-tag partitions are correct and non-overlapping, hot paths avoid per-call allocation/locks (per-M state, cached callback closures, memoized symbolization), and doc comments accurately describe the platform-specific behavior. Several higher-risk spots I specifically scrutinized checked out correct — surrogate-pair encoding in the console writer, windowsSyscallMaxArgs = 42 fitting exactly within the amd64/arm64 assembly stack reservations, the PC-site record layout matching emitted asm across 386/amd64/arm64, and the intentional double processExitLock.Lock() teardown freeze (mirrors Go issue #18253).

The main item worth attention is the Windows runtime random source (see inline P1). The remaining findings are low-severity clarity/robustness notes.

No blocking issues. This is a COMMENT (non-blocking) review.

Additional findings

  • internal/build/cgo_pragmas.go:64: [P3] goCgoLinkArgs ignores its goos parameter: goCgoLinkArgs(goos string, files []*ast.File) never uses goos; it just forwards files to collectGoCgoPragmas and returns the ldflags. Both callers in build.go pass ctx.buildConf.Goos, which suggests GOOS-conditional #cgo LDFLAGS blocks were meant to be filtered here. If GOOS filtering is intended, this is a latent correctness gap (ldflags from non-matching platforms would leak into link args); if not, drop the unused parameter for clarity. Worth confirming against how darwin/linux ldflags are gathered.

Comment thread runtime/internal/runtime/rand_windows.go Outdated
Comment thread runtime/internal/runtime/fault_handler_windows.go
@cpunion

cpunion commented Aug 26, 2026

Copy link
Copy Markdown
Collaborator Author

Second review follow-up is in ddff7126e:

  • seed the Windows runtime/map fast RNG from the system-preferred BCrypt CSPRNG;
  • exercise that CSPRNG directly in the native Windows runtime smoke;
  • simplify the fault handler's currentG nil test;
  • remove the unused goos parameter from goCgoLinkArgs and both callers. The AST list is already filtered by the package loader for the configured target, so this is a clarity cleanup without changing #cgo selection semantics.

Focused validation passed for all three Windows architectures and the affected internal/build tests. Fresh upstream CI is running on this head.

@cpunion

cpunion commented Aug 26, 2026

Copy link
Copy Markdown
Collaborator Author

Windows native CI exposed a dual-build representation missed by the P3 cleanup. 03d99cea2 restores the portable current-G check and adds its invariant; the exact failing Windows setjmp/SSA tests now pass locally under the bounded test run. Fresh CI is starting on that head.

@cpunion
cpunion force-pushed the codex/windows-r6-stdlib-20260826 branch from b067676 to 9f9d8f7 Compare August 27, 2026 04:53
@cpunion cpunion changed the title windows: integrate OS and standard-library support (R6, depends on #2405) windows: integrate OS and standard-library support (R6) Aug 27, 2026
cpunion added 27 commits August 27, 2026 17:28
@cpunion
cpunion force-pushed the codex/windows-r6-stdlib-20260826 branch from 9f9d8f7 to 4db20e0 Compare August 27, 2026 09:29
@xushiwei
xushiwei merged commit ff9bad8 into xgo-dev:main Aug 27, 2026
43 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.

2 participants