Skip to content

internal/packages: eliminate //go:linkname and decouple from x/tools internals - #2369

Open
cpunion wants to merge 3 commits into
xgo-dev:mainfrom
cpunion:codex/refactor-packages
Open

internal/packages: eliminate //go:linkname and decouple from x/tools internals#2369
cpunion wants to merge 3 commits into
xgo-dev:mainfrom
cpunion:codex/refactor-packages

Conversation

@cpunion

@cpunion cpunion commented Aug 20, 2026

Copy link
Copy Markdown
Collaborator

Summary

Eliminate all //go:linkname directives and private struct mirroring in internal/packages/load.go, replacing them with standard public golang.org/x/tools/go/packages.Load and a self-contained, post-order go/types.NewChecker typechecker.

This resolves fragility across golang.org/x/tools upgrades (e.g., #2368) and achieves a cleaner import pipeline with reduced binary sizes for compiled programs.

Key Changes

  1. Decouple from x/tools Private Internals:

    • Removed 5 //go:linkname hooks (defaultDriver, newLoader, loadFromExportData, parseFiles, typesinternalSetUsesCgo).
    • Removed mirrored private types (loader, loaderPackage, loadRecursiveEx, refineEx).
    • Standard public packages.Load handles go list driver invocation, module metadata, embed discovery, and file resolution.
  2. Self-Contained Bottom-Up Typechecking:

    • Traverses the dependency DAG post-order via packages.Visit.
    • Uses standard go/types.NewChecker with a custom importerFunc ensuring complete type information across dependencies.
    • Accurately computes target architecture pointer sizes (supporting cross-compilation such as WASM 32-bit via cfg.Env target resolution).
    • Fully preserves:
      • Deduper caching (safely guarded on pkg.Types.Complete()) and preload
      • Custom types.Sizes overrides
      • llgoFiles patch file injection
      • Per-module / global GoVersion propagation (requesting NeedModule)
      • Authoritative syntax error detection vs parser secondary errors
      • Embed error normalization and proper *os.PathError propagation
  3. Binary Size & Dead Code Elimination (DCE) Improvement:

    • Pure source-based typechecking avoids synthetic export data stubs and unneeded export metadata.
    • Yields clean types.Info records, allowing LLGo's backend SSA dead-code elimination and symbol pruning to be more effective.
    • Benchmark measurements show a modest binary size reduction on stdlib-dependent binaries (e.g., fmtprintf: -832 B on Linux, -272 B on macOS) with zero regression in performance.
  4. Code Quality & Maintenance:

    • Net reduction of -355 lines of code.
    • Full GoDoc comments preserved on all exported public APIs (LoadMode, Config, Visit, LoadEx).

Verification

  • go test -v ./internal/packages (PASS)
  • go test -v ./internal/build -run TestWasm (PASS)
  • bash test/buildcache/test.sh (18/18 Native, WASM, ESP32-C3 cache tests PASS)
  • Full GitHub Actions CI Matrix (41/41 jobs PASS)

@cpunion
cpunion force-pushed the codex/refactor-packages branch from 8c00388 to dc4629e Compare August 20, 2026 01:25
@github-actions

github-actions Bot commented Aug 20, 2026

Copy link
Copy Markdown

LLGo baseline benchmarks

adb0bec9da4f | workflow run | long-term charts

Program measurements

Platform Workload File size vs base Build vs base Run vs base
Linux cprintf 19288 B 0 B / +0.0% 330.910 ms -4.327 ms / -1.3% (better) 1.273 ms -12.61 us / -1.0% (better)
Linux fmtprintf 1860152 B 0 B / +0.0% 2.851 s +130.5 ms / +4.8% (worse) 3.321 ms +88.78 us / +2.7% (worse)
Linux println 68776 B 0 B / +0.0% 338.743 ms +10.36 ms / +3.2% (worse) 1.590 ms +32.49 us / +2.1% (worse)
macOS cprintf 84672 B 0 B / +0.0% 581.063 ms +144.7 ms / +33.1% (worse) 3.730 ms +622.3 us / +20.0% (worse)
macOS fmtprintf 1892720 B 0 B / +0.0% 3.648 s +467.3 ms / +14.7% (worse) 17.114 ms +4.577 ms / +36.5% (worse)
macOS println 121360 B 0 B / +0.0% 489.399 ms +115.7 ms / +31.0% (worse) 4.704 ms +621.5 us / +15.2% (worse)
Core language and compiler benchmarks
Platform Benchmark ns/op vs base
Linux BenchmarkLookupPCRandom 13.260 ns/op +0.05 ns/op / +0.4% (worse)
Linux BenchmarkMergeCompilerFlags 150.900 ns/op +0.1 ns/op / +0.1% (worse)
Linux BenchmarkMergeLinkerFlags 94.840 ns/op -1.71 ns/op / -1.8% (better)
Linux BenchmarkChannelBuffered 33.990 ns/op +0.01 ns/op / +0.02943% (worse)
Linux BenchmarkChannelHandoff 27868 ns/op +813 ns/op / +3.0% (worse)
Linux BenchmarkDefer 46.250 ns/op -0.96 ns/op / -2.0% (better)
Linux BenchmarkDirectCall 1.557 ns/op 0 ns/op / +0.0%
Linux BenchmarkGlobalRead 1.557 ns/op 0 ns/op / +0.0%
Linux BenchmarkGlobalWrite 2.482 ns/op +0.001 ns/op / +0.04031% (worse)
Linux BenchmarkGoroutine 32260 ns/op -232 ns/op / -0.7% (better)
Linux BenchmarkInterfaceCall 8.098 ns/op -0.006 ns/op / -0.1% (better)
Linux BenchmarkRuntimeGetG 2.180 ns/op +0.001 ns/op / +0.04589% (worse)
macOS BenchmarkLookupPCRandom 14.050 ns/op -0.97 ns/op / -6.5% (better)
macOS BenchmarkMergeCompilerFlags 187.600 ns/op +32.1 ns/op / +20.6% (worse)
macOS BenchmarkMergeLinkerFlags 111.400 ns/op +21.57 ns/op / +24.0% (worse)
macOS BenchmarkChannelBuffered 27.820 ns/op -3.69 ns/op / -11.7% (better)
macOS BenchmarkChannelHandoff 5873 ns/op -2780 ns/op / -32.1% (better)
macOS BenchmarkDefer 40.400 ns/op -2.87 ns/op / -6.6% (better)
macOS BenchmarkDirectCall 1.324 ns/op -0.002 ns/op / -0.2% (better)
macOS BenchmarkGlobalRead 1.157 ns/op +0.011 ns/op / +1.0% (worse)
macOS BenchmarkGlobalWrite 1.187 ns/op -0.015 ns/op / -1.2% (better)
macOS BenchmarkGoroutine 28182 ns/op -5001 ns/op / -15.1% (better)
macOS BenchmarkInterfaceCall 5.857 ns/op -0.062 ns/op / -1.0% (better)
macOS BenchmarkRuntimeGetG 2.363 ns/op -0.298 ns/op / -11.2% (better)

Compared with bed9d7c4d4c0 measured in the same runner job.

@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: refactor internal/packages to drop //go:linkname internals

This is a solid, well-motivated refactor. It removes the fragile //go:linkname hooks into golang.org/x/tools internals (defaultDriver, newLoader, loadFromExportData, parseFiles, typesinternalSetUsesCgo) and the private loader/loaderPackage types, replacing them with a self-contained driver: call the public packages.Load with an adjusted Mode, then parse + typecheck bottom-up via packages.Visit. This is much less likely to break across x/tools upgrades. internal/packages tests pass locally.

I verified the main worry — that dropping the export-data fallback would break NeedImports-without-NeedDeps loads — and it does not reproduce: the go list driver still returns dependency packages with populated CompiledGoFiles, so packages.Visit reaches and typechecks them from source (confirmed internal/bytealg loads with complete import types, IllTyped=false, 0 errors). So that path is fine.

A few findings below, ordered by impact. The wasm-sizes one (P1) is the only likely functional regression.

Comment thread internal/packages/load.go Outdated
Comment thread internal/packages/load.go
Comment thread internal/packages/load.go
Comment thread internal/packages/load.go
Comment thread internal/packages/load.go

@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 (cont.): one additional finding

Follow-up to the review above — this P1 finding was omitted from the first submission due to a title-length limit. It is the most impactful item.

Comment thread internal/packages/load.go
@codecov

codecov Bot commented Aug 20, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@cpunion
cpunion force-pushed the codex/refactor-packages branch from 11d8b59 to adb0bec Compare August 20, 2026 02:26
@cpunion cpunion changed the title internal/packages: eliminate //go:linkname and mirror structs internal/packages: eliminate //go:linkname and decouple from x/tools internals Aug 20, 2026
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