Skip to content

compiler: isolate per-invocation frontend state - #2221

Merged
xushiwei merged 2 commits into
xgo-dev:mainfrom
zhouguangyuan0718:agent/build-isolation-02-compiler-state
Aug 1, 2026
Merged

compiler: isolate per-invocation frontend state#2221
xushiwei merged 2 commits into
xgo-dev:mainfrom
zhouguangyuan0718:agent/build-isolation-02-compiler-state

Conversation

@zhouguangyuan0718

@zhouguangyuan0718 zhouguangyuan0718 commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Summary

  • pass frontend compilation options explicitly for each build invocation instead of changing package-level defaults
  • capture debug info, tracing, export renaming, and shadow-stack behavior in invocation-owned cl.Options
  • initialize LLVM frontend state once and keep compiler-verbose diagnostics build-local without frontend global switches or locks
  • deprecate legacy frontend constructors that still read process-wide defaults
  • verify concurrent invocations can compile with different DWARF/frontend settings under the race detector

Dependency and review boundary

Based on current main, which includes #2246 and its unconditional main-package symbol prefix.

The intended review diff is:

Please review only 8aa41210..c46521e4.

Simplification from the previous version

  • removed the abi.Namer and Program-owned naming policy
  • removed per-Program RewriteMainPrefix state and its dual-policy concurrency tests
  • removed scoped naming wrappers and named-type equivalence plumbing
  • retained only frontend/compiler state that can genuinely vary between build invocations
  • main package naming now follows compiler: always use main symbol prefix #2246 everywhere and is not invocation state

Compatibility boundary

  • existing one-shot frontend constructors remain available, but are deprecated because they read legacy process defaults
  • concurrent build drivers use NewPackageExWithEmbedMetaOptions with explicit cl.Options
  • the build driver no longer calls legacy cl.SetDebug or ssa.SetDebug; compiler-verbose emits a package-level compile marker without process-wide state
  • LLVM executable selection remains process-scoped as established by build: isolate invocation configuration and execution #2212

Tests

  • GOCACHE=/private/tmp/llgo-2221-gocache go test ./internal/build ./cl ./ssa -count=1
  • GOCACHE=/private/tmp/llgo-2221-gocache go test -race ./internal/build -run '^TestConcurrentInvocationsIsolateFrontendOptions$' -count=1
  • GOCACHE=/private/tmp/llgo-2221-gocache go test ./cl -run '^TestFrontendOptions$' -count=1
  • focused atomic coverage: legacyOptions and frontendOptions both 100%; concurrent verbose/non-verbose invocation paths executed without a frontend lock
  • git diff --check

@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: isolate per-build frontend and SSA state

Solid, well-tested refactor. The isolation goal is achieved: every active symbol-generation path in ssa/ and cl/ is migrated to the Program/Namer-scoped naming methods, the def/use pair for method-capability keys (ssa/globaldce.go and ssa/interface.go) both use the scoped PathOf so RewriteMainPrefix cannot silently break DCE, and the concurrent-build story (sync.Once init + frontendDebugMu gating the process-global SetDebug switches) is coherent. Performance is neutral — Program/Builder are pointer aliases and Namer is a one-bool value, so the new method values/closures don't allocate on hot paths. No security regressions; binding LLVM tools to explicit paths instead of mutating the process PATH is a modest improvement.

A few concrete items below. Inline comments carry the diff-line findings; the rest are here.

Findings not tied to a diff line

  • ssa/type.go:593 — unscoped NameOf straggler. namedTypeEquivalent still calls the package-level NameOf (zero-value Namer, RewriteMainPrefix=false) while its sibling llvmNameOf (ssa/type.go:524) was migrated to p.NameOf. It's self-consistent today (both operands share the unscoped namer), but mixing scoped and unscoped naming in adjacent equivalence code is a maintenance hazard: if main-package named types are compared here under RewriteMainPrefix, the equivalence result could diverge from the scoped symbol used at line 524. Consider threading the Program and using p.NameOf in both comparisons.

  • cl/compile.go — legacy constructors not marked deprecated. EnableDebug/EnableDbgSyms/EnableTrace/EnableExportRename gained // Deprecated: notes, but NewPackage/NewPackageEx/NewPackageExWithEmbed/NewPackageExWithEmbedMeta were not, even though they funnel through legacyOptions() and thus stay unisolated (re-reading process globals + LLGO_SHADOW_STACK). A matching // Deprecated: use NewPackageExWithEmbedMetaOptions note would make the isolation contract discoverable across the whole public surface.

  • New exported Program naming methods lack doc comments (ssa/type.go: NameOf, FullName, PathOf, FuncName, TypeArgs). These are the primary replacement API for the removed process-global path, yet the package-level free functions directly above each are documented and these are not. A one-line comment noting each applies the Program's RewriteMainPrefix policy (vs. the package-level function's zero-value namer) would help. The abi.Namer exported methods are likewise undocumented.

  • xtool/env/llvm/llvm.go tool-bin doc comments for ClangBin/ClangXXBin/LLVMArBin/LLCBin say "returns the <tool> executable from this LLVM installation," but when binDir == "" they return the bare command name for PATH resolution (as BinDir's own comment documents, and as TestToolBinsFallBackToPATHNames asserts). Mirror BinDir's wording about the PATH fallback.

  • internal/build/request.go withEnv silently drops malformed (non-KEY=VALUE) entries from the passthrough environment, a behavior change from the prior append(slices.Clone(os.Environ()), ...). It only feeds go list's env (which rejects such entries anyway), so it's harmless — but the doc comment mentions dropping malformed entries only when replacing, not from the passthrough; worth a word.

View job run

Comment thread internal/build/plan9asm.go Outdated
args = append(args, pkg.PkgPath)

cmd := exec.Command("go", args...)
ctx.configureCommand(cmd)

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.

ctx.configureCommand(cmd) here is dead: it sets cmd.Dir and cmd.Env, but line 415 overwrites cmd.Dir (from ctx.conf.Dir) and lines 421-424 overwrite cmd.Env unconditionally. So this call has no effect.

More notably, this go list invocation ends up using os.Environ() (the live process environment) rather than the build's captured ctx.environ snapshot that the rest of this PR deliberately threads through exec commands. A concurrent build that mutated the process env would leak in here. Either drop the redundant configureCommand call and add a note that this command intentionally uses live env + conf.Dir, or build on top of the ctx.environ snapshot for consistency with the other commands.

@codecov

codecov Bot commented Jul 30, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 96.36364% with 2 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
cl/compile.go 92.59% 1 Missing and 1 partial ⚠️

📢 Thoughts on this report? Let us know!

@zhouguangyuan0718
zhouguangyuan0718 force-pushed the agent/build-isolation-02-compiler-state branch 6 times, most recently from 82f3bf3 to 2e73083 Compare July 30, 2026 14:55
@zhouguangyuan0718 zhouguangyuan0718 changed the title compiler: isolate per-build frontend and SSA state compiler: isolate per-invocation frontend and SSA state Jul 30, 2026
@zhouguangyuan0718
zhouguangyuan0718 force-pushed the agent/build-isolation-02-compiler-state branch from 2e73083 to 05b1efd Compare July 31, 2026 01:50
@github-actions

github-actions Bot commented Jul 31, 2026

Copy link
Copy Markdown

LLGo baseline benchmarks

c46521e493fe | workflow run | long-term charts

Program measurements

Platform Workload File size vs main Build vs main Run vs main
Linux cprintf 18544 B new 347.269 ms new 1.261 ms new
Linux fmtprintf 2217608 B new 3.393 s new 2.609 ms new
Linux println 71504 B new 348.246 ms new 1.604 ms new
macOS cprintf 84672 B new 317.386 ms new 2.423 ms new
macOS fmtprintf 2361520 B new 2.857 s new 19.130 ms new
macOS println 125712 B new 303.054 ms new 3.144 ms new
Core language and compiler benchmarks
Platform Benchmark ns/op vs main
Linux BenchmarkLookupPCRandom 13.340 ns/op new
Linux BenchmarkMergeCompilerFlags 150.200 ns/op new
Linux BenchmarkMergeLinkerFlags 93.860 ns/op new
Linux BenchmarkChannelBuffered 33.980 ns/op new
Linux BenchmarkChannelHandoff 25440 ns/op new
Linux BenchmarkDefer 42.650 ns/op new
Linux BenchmarkDirectCall 1.556 ns/op new
Linux BenchmarkGlobalRead 1.868 ns/op new
Linux BenchmarkGlobalWrite 2.488 ns/op new
Linux BenchmarkGoroutine 32510 ns/op new
Linux BenchmarkInterfaceCall 8.142 ns/op new
Linux BenchmarkRuntimeGetG 1.870 ns/op new
macOS BenchmarkLookupPCRandom 11.870 ns/op new
macOS BenchmarkMergeCompilerFlags 111.400 ns/op new
macOS BenchmarkMergeLinkerFlags 72.820 ns/op new
macOS BenchmarkChannelBuffered 21.950 ns/op new
macOS BenchmarkChannelHandoff 9604 ns/op new
macOS BenchmarkDefer 27.150 ns/op new
macOS BenchmarkDirectCall 1.017 ns/op new
macOS BenchmarkGlobalRead 1.037 ns/op new
macOS BenchmarkGlobalWrite 1.018 ns/op new
macOS BenchmarkGoroutine 28499 ns/op new
macOS BenchmarkInterfaceCall 4.205 ns/op new
macOS BenchmarkRuntimeGetG 2.141 ns/op new

No main baseline exists yet; all metrics are marked new.

Warning

  • The rendered benchmark data could not be pushed.

@zhouguangyuan0718
zhouguangyuan0718 force-pushed the agent/build-isolation-02-compiler-state branch from e018a21 to ef96705 Compare July 31, 2026 15:42
@zhouguangyuan0718 zhouguangyuan0718 changed the title compiler: isolate per-invocation frontend and SSA state compiler: isolate per-invocation frontend state Jul 31, 2026
@zhouguangyuan0718

Copy link
Copy Markdown
Contributor Author

Reworked on top of #2246 (7cbf71fe) and force-updated to ef96705d.

The old SSA naming layer is gone: no abi.Namer, no Program-owned RewriteMainPrefix, no scoped naming wrappers, and no dual main-prefix race test. #2221 now contains only invocation-local frontend/compiler state.

I also addressed the remaining applicable review item by marking the legacy NewPackage* constructors deprecated, and replaced the old naming race test with concurrent builds using opposite DWARF/frontend settings. The new test passes under -race.

Validated locally:

  • go test ./internal/build ./cl ./ssa -count=1
  • go test -race ./internal/build -run '^TestConcurrentInvocationsIsolateFrontendOptions$' -count=1\n- git diff --check\n\nThe other prior review notes about scoped Namer methods and named-type equivalence no longer apply because those APIs were removed from this version.

@zhouguangyuan0718
zhouguangyuan0718 force-pushed the agent/build-isolation-02-compiler-state branch from ef96705 to 8c82142 Compare July 31, 2026 17:14
@zhouguangyuan0718

Copy link
Copy Markdown
Contributor Author

CI follow-up at 8c821427:

  • Fixed codecov/patch by exercising the verbose frontend-debug lock path in the concurrent invocation test and adding focused coverage for explicit, legacy, and nil-context frontend options.
  • Verified TestFrontendOptions passes, TestConcurrentInvocationsIsolateFrontendOptions passes under -race, and focused atomic coverage reports 100% for both legacyOptions and frontendOptions.
  • The prior Ubuntu primary hello failure was an external HTTP 500 while downloading the ESP LLVM prebuilt archive; no source workaround was added. This head update has retriggered that job.

@zhouguangyuan0718
zhouguangyuan0718 force-pushed the agent/build-isolation-02-compiler-state branch from 8c82142 to f60aa0c Compare July 31, 2026 23:00
@xushiwei
xushiwei merged commit 60c30f2 into xgo-dev:main Aug 1, 2026
41 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