Skip to content

feat(cl): distinguish native linkname exports from placeholder bindings - #2895

Open
cpunion wants to merge 21 commits into
xgo-dev:mainfrom
cpunion:fix/linkname-native-entries-20261021
Open

cpunion wants to merge 21 commits into
xgo-dev:mainfrom
cpunion:fix/linkname-native-entries-20261021

Conversation

@cpunion

@cpunion cpunion commented Oct 20, 2026 •

Copy link
Copy Markdown
Collaborator

Implement the function/ABI rules in #2879, building on #2894.

//go:linkname Entry C.native_entry
func Entry(v int32) int32 { return v + 7 } // native export

//llgo:link Call C.native_entry
func Call(int32) int32 { panic("placeholder") } // external reference
  • A defining go:linkname function with C. or stdcall. gets a native entry with foreign-thread/GC handling; its Go implementation retains the Go ABI. Prototypes remain external references.
  • llgo:link requires a placeholder body, ignores it completely and never exports an implementation. Preserve native callback/storage widths and reject invalid native declarations before registration.
  • Use official goplus/lib v0.7.0 across all module manifests, including older-Go CI; remove fork replacements and restore the six example/tool modules to Go 1.20. The release includes prototype-only Python imports such as py.NewSet.

Rebased on updated #2894 and main 05c2d6b4f. Validation: full SSA suite; targeted compiler/linker and Windows MSVC/MinGW IR tests; gc/LLGo storage, native entries, foreign-thread callbacks and Full LTO execution; C/Python bindings, Python set construction and castdump. Go 1.20.14 dependency/build checks and focused gc/LLGo regressions pass. Windows execution and the remaining matrix run in CI.

Keep shared gc/LLGo cases in test/go, native/placeholder cases in test/llgoext, and binding rules in doc/LLGo-Link.md.

Review corrections: document ignored Python/instruction bodies and lazy non-Windows stdcall diagnostics; clarify symbol-keyed stdcall type metadata. Rebased onto the updated #2894; targeted compiler/SSA/native-link tests pass.

@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

This PR cleanly separates native linkname entries (C. / stdcall.), Go-ABI
placeholder bindings (llgo:link), and shared Go variable storage, and backs it
with a thorough diagnostic/test matrix plus a new doc/linkname.md. The core
behavior change — a bare variable go:linkname target now means Go storage
instead of a C extern — is applied consistently, and the ~20 in-tree bare-symbol
variable bindings were correctly migrated to the explicit C. prefix, so no
production caller silently changes meaning.

Reviewed across code quality, performance, security, and documentation. The
security pass found no issues: symbol-name/prefix parsing is guarded, the
*types.Pointer / *ast.ValueSpec assertions in cl/linkname_native.go are
safe, and the new C test harnesses are memory-safe. InitSharedGo's
zero/nonzero coalescing and the wasm WeakAnyLinkage fallback look correct.

The inline notes below are all minor/low severity — none block merge.

Additional minor note: the "$stdcall" type-callconv suffix is now spelled
as a string literal in three places (cl/import.go initLink,
cl/linkname_native.go collectNativeLinkDefinitions, and nativeVariableType).
A shared constant/helper would keep the three sites from drifting apart.

Findings without inline locations

  • doc/linkname.md:62: The new variable rule (bare target = Go storage; native needs an explicit C./stdcall. prefix) is a breaking change from the prior behavior, where a bare variable target denoted a C extern. This PR had to migrate ~20 in-tree files to the C. prefix to preserve semantics. A one-line migration/compatibility note here would help out-of-tree code that relied on the old meaning.

Comment thread cl/compile.go Outdated
Comment thread ssa/decl.go
Comment thread cl/import.go
Comment thread cl/linkname_native.go Outdated
@codecov

codecov Bot commented Oct 20, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 96.52510% with 9 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
cl/compile.go 94.73% 2 Missing ⚠️
cl/linkname_native.go 96.55% 2 Missing ⚠️
test/llgoext/linkname_native.go 66.66% 2 Missing ⚠️
ssa/native_export.go 95.83% 1 Missing ⚠️
ssa/stdcall.go 75.00% 1 Missing ⚠️
test/llgoext/linkname_stdcall_windows.go 50.00% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

@cpunion

cpunion commented Oct 21, 2026

Copy link
Copy Markdown
Collaborator Author

Addressed all review threads and the reproduced CI failures. The follow-up fixes cover stdcall callback nil/native-pointer assignment, Darwin shared-storage debug addresses, migrated native-variable dependencies, and the removed c/clang package used by castdump.

The latest Ubuntu failure exposed one more migration requirement: py.NewSet had a C.PySet_New linkname with a return nil body. Under the new definition rule it exported a stub over CPython's real function, aborting PyTorch imports. goplus/lib#53 now makes this and three libuv imports bodyless; f02f838 pins that revision in all seven module roots. The failing executable defined PySet_New; the corrected executable no longer defines it and runs the tensor example successfully.

Validation: full local cl and ssa suites; shared/native linkname tests and full LTO; six Windows IR/assembly targets; Darwin debugger tests (293/293); ten Linux foreign-thread callback runs; Python set construction/mutation on Linux and macOS; Linux PyTorch execution and tool installation. Fresh CI is running; Windows runtime validation and final aggregate coverage remain pending.

@cpunion

cpunion commented Oct 21, 2026 •

Copy link
Copy Markdown
Collaborator Author

Fixed the six Windows failures in c87f706.

TestLinknameNativeVariables restored a saved Go funcval into a C callback slot with a two-pointer store. Its nil environment overwrote the adjacent stdcall callback, causing TestLinknameStdcall to panic. Stores now use the actual destination representation and the existing callback conversion/closure checks.

Validation:

  • New adjacent-slot regression fails before the fix and passes afterward on macOS.
  • Full test/llgoext with coverage passes, including rejection of capturing closures.
  • All six Windows MSVC/MinGW targets pass the direct/preloaded IR and assembly checks; added a captured-callback restore assertion.
  • Full go test ./ssa ./cl -count=1 -timeout=45m passes (SSA 18s, frontend 553s); the callback regressions also pass with full LTO.

The earlier macOS Intel artifact failure was a GitHub DNS timeout downloading newlib; the latest-head job now passes.

Merged current upstream main (0578518) in 47141cb to resolve the LLGo-Link.md conflict introduced by #2903. The resolution retains the new upstream document structure, adds the function-placeholder case alongside methods, and preserves the native-entry restrictions, literal-symbol rules, explicit cgo imports and regression references from this PR. This merge changes documentation only. All six focused linkname IR/diagnostic test groups pass, relative documentation links resolve, and embedme verification passes. Final CI validation for 47141cb: all 12 workflow runs have completed, with 115 successful checks and one expected skipped tag-publication job. Native/compiler, Go, browser, all six Windows artifacts, and WinGet candidate validation all pass. The candidate job passed after a job-only retry of its artifact download failure.

@github-actions

github-actions Bot commented Oct 21, 2026 •

Copy link
Copy Markdown

LLGo WebAssembly build benchmarks

235cc7bbfe5f | workflow run | long-term charts

WebAssembly output sizes
Example, profile and compiler Wasm module vs base Generated JS glue vs base
cprintf/j32-emscripten/LLGo 149433 B 0 B / +0.0% 88932 B 0 B / +0.0%
cprintf/j32-goos-js/LLGo 148052 B 0 B / +0.0% 72985 B 0 B / +0.0%
cprintf/j64-emscripten-memory64/LLGo 136735 B 0 B / +0.0% 92103 B 0 B / +0.0%
cprintf/w32-goos-wasip1/LLGo 159625 B 0 B / +0.0% 0 B 0 B / 0.0%
cprintf/w32-wasi/LLGo 160233 B 0 B / +0.0% 0 B 0 B / 0.0%
fmtprintf/j32-emscripten/LLGo 3006613 B 0 B / +0.0% 121159 B 0 B / +0.0%
fmtprintf/j32-goos-js/Go 2526852 B 0 B / +0.0% 0 B 0 B / 0.0%
fmtprintf/j32-goos-js/LLGo 3102763 B 0 B / +0.0% 91831 B 0 B / +0.0%
fmtprintf/j64-emscripten-memory64/LLGo 2770730 B 0 B / +0.0% 125844 B 0 B / +0.0%
fmtprintf/w32-goos-wasip1/Go 2500019 B 0 B / +0.0% 0 B 0 B / 0.0%
fmtprintf/w32-goos-wasip1/LLGo 2377902 B +14 B / +0.0005888% (worse) 0 B 0 B / 0.0%
fmtprintf/w32-wasi/LLGo 2374590 B +17 B / +0.0007159% (worse) 0 B 0 B / 0.0%
j32-emscripten/LLGo 148950 B 0 B / +0.0% 88932 B 0 B / +0.0%
j32-goos-js/Go 1895533 B 0 B / +0.0% 0 B 0 B / 0.0%
j32-goos-js/LLGo 147802 B 0 B / +0.0% 72985 B 0 B / +0.0%
j64-emscripten-memory64/LLGo 136293 B 0 B / +0.0% 92103 B 0 B / +0.0%
reflectcall/j32-emscripten/LLGo 1532913 B 0 B / +0.0% 95808 B 0 B / +0.0%
reflectcall/j32-goos-js/Go 2191221 B 0 B / +0.0% 0 B 0 B / 0.0%
reflectcall/j32-goos-js/LLGo 1585160 B 0 B / +0.0% 79857 B 0 B / +0.0%
reflectcall/j64-emscripten-memory64/LLGo 1413165 B 0 B / +0.0% 99561 B 0 B / +0.0%
reflectcall/w32-goos-wasip1/Go 2205707 B 0 B / +0.0% 0 B 0 B / 0.0%
reflectcall/w32-goos-wasip1/LLGo 1310868 B +4 B / +0.0003051% (worse) 0 B 0 B / 0.0%
reflectcall/w32-wasi/LLGo 1308465 B +4 B / +0.0003057% (worse) 0 B 0 B / 0.0%
w32-goos-wasip1/Go 1909947 B 0 B / +0.0% 0 B 0 B / 0.0%
w32-goos-wasip1/LLGo 159299 B 0 B / +0.0% 0 B 0 B / 0.0%
w32-wasi/LLGo 159907 B 0 B / +0.0% 0 B 0 B / 0.0%
LLGo WebAssembly build measurements
Example and profile Build vs base
j32-emscripten 7.941 s -274.3 ms / -3.3% (better)
j32-goos-js 7.838 s -395.1 ms / -4.8% (better)
j64-emscripten-memory64 6.835 s -342.7 ms / -4.8% (better)
reflectcall/w32-wasi 24.881 s +45.89 ms / +0.2% (worse)
w32-goos-wasip1 4.855 s -290.3 ms / -5.6% (better)
w32-wasi 4.603 s -271 ms / -5.6% (better)

Compared with ed6fbb30d292 measured in the same runner job.

@github-actions

github-actions Bot commented Oct 21, 2026 •

Copy link
Copy Markdown

LLGo baseline benchmarks

235cc7bbfe5f | 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 8336 B 0 B / +0.0% 387 B 0 B / +0.0% 908.756 ms -45.56 ms / -4.8% (better) 1.226 ms -170 us / -12.2% (better)
Linux cprintf-lto 8120 B 0 B / +0.0% 368 B 0 B / +0.0% 936.002 ms -14.45 ms / -1.5% (better) 1.283 ms +27.49 us / +2.2% (worse)
Linux fmtprintf 2563584 B -112 B / -0.004369% (better) 509114 B +16 B / +0.003143% (worse) 5.814 s -149.2 ms / -2.5% (better) 4.299 ms +83.05 us / +2.0% (worse)
Linux fmtprintf-lto 2009072 B -8 B / -0.0003982% (better) 448787 B +8 B / +0.001783% (worse) 25.769 s -177.2 ms / -0.7% (better) 3.618 ms -630.3 us / -14.8% (better)
Linux println 246480 B 0 B / +0.0% 17643 B 0 B / +0.0% 1.050 s +32.39 ms / +3.2% (worse) 1.593 ms -43.89 us / -2.7% (better)
Linux println-lto 96968 B -8 B / -0.008249% (better) 15011 B 0 B / +0.0% 1.660 s -89.32 ms / -5.1% (better) 1.740 ms -227.3 us / -11.6% (better)
macOS cprintf 50672 B 0 B / +0.0% 4413 B +4 B / +0.1% (worse) 879.739 ms -521.1 ms / -37.2% (better) 2.321 ms -2.187 ms / -48.5% (better)
macOS cprintf-lto 50592 B -16 B / -0.03162% (better) 161 B 0 B / +0.0% 833.458 ms -715.1 ms / -46.2% (better) 2.249 ms -7.051 ms / -75.8% (better)
macOS fmtprintf 1903456 B +214672 B / +12.7% (worse) 894616 B +2760 B / +0.3% (worse) 3.510 s -1.123 s / -24.2% (better) 26.347 ms -14.92 ms / -36.2% (better)
macOS fmtprintf-lto 1405872 B +16 B / +0.001138% (worse) 775832 B -4 B / -0.0005156% (better) 6.646 s -2.386 s / -26.4% (better) 50.526 ms -34.66 ms / -40.7% (better)
macOS println 96960 B 0 B / +0.0% 24695 B +72 B / +0.3% (worse) 823.864 ms -499.4 ms / -37.7% (better) 3.701 ms -201.5 us / -5.2% (better)
macOS println-lto 84288 B 0 B / +0.0% 21860 B 0 B / +0.0% 1.545 s +297.6 ms / +23.9% (worse) 6.356 ms +2.457 ms / +63.0% (worse)
Windows MinGW cprintf 716288 B +3584 B / +0.5% (worse) 4406 B 0 B / +0.0% 1.829 s -42.28 ms / -2.3% (better) 3.459 ms +76.6 us / +2.3% (worse)
Windows MinGW cprintf-lto 59904 B 0 B / +0.0% 4358 B 0 B / +0.0% 1.844 s -76.06 ms / -4.0% (better) 3.480 ms -427.7 us / -10.9% (better)
Windows MinGW fmtprintf 5552128 B +4608 B / +0.1% (worse) 606822 B +48 B / +0.007911% (worse) 5.580 s -129.4 ms / -2.3% (better) 11.861 ms +993.4 us / +9.1% (worse)
Windows MinGW fmtprintf-lto 4201984 B 0 B / +0.0% 553974 B 0 B / +0.0% 13.044 s -177.8 ms / -1.3% (better) 10.164 ms -213.7 us / -2.1% (better)
Windows MinGW println 770560 B +1536 B / +0.2% (worse) 25638 B 0 B / +0.0% 1.843 s -13.74 ms / -0.7% (better) 6.826 ms -537.7 us / -7.3% (better)
Windows MinGW println-lto 221696 B 0 B / +0.0% 22198 B 0 B / +0.0% 2.105 s -85.58 ms / -3.9% (better) 6.402 ms -107 us / -1.6% (better)
Windows MinGW 386 cprintf 663552 B +4096 B / +0.6% (worse) 5608 B 0 B / +0.0% 1.754 s -6.418 ms / -0.4% (better) 6.484 ms +1.167 ms / +21.9% (worse)
Windows MinGW 386 cprintf-lto 119296 B 0 B / +0.0% 5112 B 0 B / +0.0% 1.790 s -30.5 ms / -1.7% (better) 4.996 ms -918.6 us / -15.5% (better)
Windows MinGW 386 fmtprintf 4848128 B +5120 B / +0.1% (worse) 474638 B 0 B / +0.0% 5.603 s -5.365 ms / -0.1% (better) 11.976 ms +257.9 us / +2.2% (worse)
Windows MinGW 386 fmtprintf-lto 4206592 B 0 B / +0.0% 453362 B 0 B / +0.0% 12.503 s -58.79 ms / -0.5% (better) 12.391 ms -239 us / -1.9% (better)
Windows MinGW 386 println 714752 B +1536 B / +0.2% (worse) 22180 B 0 B / +0.0% 1.748 s -30.15 ms / -1.7% (better) 8.583 ms -92.7 us / -1.1% (better)
Windows MinGW 386 println-lto 273920 B 0 B / +0.0% 19576 B 0 B / +0.0% 2.019 s -14.6 ms / -0.7% (better) 8.643 ms -7.4 us / -0.1% (better)
Windows MinGW ARM64 cprintf 727552 B +3584 B / +0.5% (worse) 4204 B 0 B / +0.0% 2.078 s -35.15 ms / -1.7% (better) 6.565 ms -6.9 us / -0.1% (better)
Windows MinGW ARM64 cprintf-lto 58880 B 0 B / +0.0% 4156 B 0 B / +0.0% 2.132 s +30.59 ms / +1.5% (worse) 6.687 ms +110.9 us / +1.7% (worse)
Windows MinGW ARM64 fmtprintf 5462528 B +4608 B / +0.1% (worse) 516176 B +112 B / +0.0217% (worse) 5.737 s +56.82 ms / +1.0% (worse) 15.993 ms -205.4 us / -1.3% (better)
Windows MinGW ARM64 fmtprintf-lto 4375552 B 0 B / +0.0% 483956 B 0 B / +0.0% 12.589 s +113 ms / +0.9% (worse) 15.842 ms +822.6 us / +5.5% (worse)
Windows MinGW ARM64 println 777728 B +1536 B / +0.2% (worse) 24256 B 0 B / +0.0% 2.108 s +32.94 ms / +1.6% (worse) 12.304 ms +1.316 ms / +12.0% (worse)
Windows MinGW ARM64 println-lto 229376 B 0 B / +0.0% 21364 B 0 B / +0.0% 2.404 s +52.57 ms / +2.2% (worse) 11.083 ms -724.6 us / -6.1% (better)
Windows MSVC cprintf 960000 B +3584 B / +0.4% (worse) 66003 B 0 B / +0.0% 1.756 s -113.6 ms / -6.1% (better) 3.510 ms -410.1 us / -10.5% (better)
Windows MSVC cprintf-lto 307200 B 0 B / +0.0% 65971 B 0 B / +0.0% 1.734 s -119.3 ms / -6.4% (better) 3.446 ms +55.6 us / +1.6% (worse)
Windows MSVC fmtprintf 5853696 B +4608 B / +0.1% (worse) 702710 B +48 B / +0.006831% (worse) 5.414 s -261.5 ms / -4.6% (better) 11.492 ms -397.5 us / -3.3% (better)
Windows MSVC fmtprintf-lto 4526080 B 0 B / +0.0% 653574 B 0 B / +0.0% 12.046 s -693.8 ms / -5.4% (better) 11.206 ms -2.179 ms / -16.3% (better)
Windows MSVC println 1082880 B +1536 B / +0.1% (worse) 121638 B 0 B / +0.0% 1.719 s -162.2 ms / -8.6% (better) 7.330 ms -1.155 ms / -13.6% (better)
Windows MSVC println-lto 543232 B 0 B / +0.0% 118870 B 0 B / +0.0% 2.247 s +123.8 ms / +5.8% (worse) 6.811 ms -445.1 us / -6.1% (better)
Windows MSVC 386 cprintf 571904 B +3584 B / +0.6% (worse) 3947 B 0 B / +0.0% 1.721 s +587.4 us / +0.03415% (worse) 5.841 ms +190.8 us / +3.4% (worse)
Windows MSVC 386 cprintf-lto 59904 B 0 B / +0.0% 3901 B 0 B / +0.0% 1.767 s +41.88 ms / +2.4% (worse) 5.463 ms -492.9 us / -8.3% (better)
Windows MSVC 386 fmtprintf 4579328 B +5120 B / +0.1% (worse) 458018 B 0 B / +0.0% 5.466 s +114.3 ms / +2.1% (worse) 13.186 ms +113.9 us / +0.9% (worse)
Windows MSVC 386 fmtprintf-lto 3954176 B 0 B / +0.0% 428977 B 0 B / +0.0% 11.539 s -118.7 ms / -1.0% (better) 13.041 ms -354.7 us / -2.6% (better)
Windows MSVC 386 println 626176 B +1536 B / +0.2% (worse) 20780 B 0 B / +0.0% 1.800 s +84.39 ms / +4.9% (worse) 10.060 ms +287.5 us / +2.9% (worse)
Windows MSVC 386 println-lto 212480 B 0 B / +0.0% 18733 B 0 B / +0.0% 2.077 s +81.71 ms / +4.1% (worse) 9.519 ms -798.7 us / -7.7% (better)
Windows MSVC ARM64 cprintf 728064 B +4096 B / +0.6% (worse) 4240 B 0 B / +0.0% 1.858 s -6.104 ms / -0.3% (better) 6.861 ms -236.5 us / -3.3% (better)
Windows MSVC ARM64 cprintf-lto 64512 B 0 B / +0.0% 4140 B 0 B / +0.0% 1.869 s -104 ms / -5.3% (better) 6.952 ms -464.5 us / -6.3% (better)
Windows MSVC ARM64 fmtprintf 5457920 B +4096 B / +0.1% (worse) 516260 B +112 B / +0.0217% (worse) 5.399 s -36.28 ms / -0.7% (better) 17.008 ms -732.6 us / -4.1% (better)
Windows MSVC ARM64 fmtprintf-lto 4383232 B 0 B / +0.0% 484784 B 0 B / +0.0% 12.024 s +99.8 ms / +0.8% (worse) 18.256 ms +510.7 us / +2.9% (worse)
Windows MSVC ARM64 println 780800 B +1536 B / +0.2% (worse) 24532 B 0 B / +0.0% 1.838 s -36.88 ms / -2.0% (better) 12.350 ms -241.4 us / -1.9% (better)
Windows MSVC ARM64 println-lto 235008 B 0 B / +0.0% 21764 B 0 B / +0.0% 2.120 s +19.22 ms / +0.9% (worse) 12.681 ms +179 us / +1.4% (worse)
Core language and compiler benchmarks
Platform Benchmark ns/op vs base
Linux BenchmarkLookupPCRandom 14.630 ns/op +0.15 ns/op / +1.0% (worse)
Linux BenchmarkMergeCompilerFlags 199.500 ns/op -10.7 ns/op / -5.1% (better)
Linux BenchmarkMergeLinkerFlags 137.500 ns/op +9.5 ns/op / +7.4% (worse)
Linux BenchmarkChannelBuffered 57.690 ns/op -0.49 ns/op / -0.8% (better)
Linux BenchmarkChannelHandoff 13091 ns/op -457 ns/op / -3.4% (better)
Linux BenchmarkDefer 50.300 ns/op -2.77 ns/op / -5.2% (better)
Linux BenchmarkDirectCall 1.557 ns/op +0.391 ns/op / +33.5% (worse)
Linux BenchmarkGlobalRead 1.166 ns/op -0.005 ns/op / -0.4% (better)
Linux BenchmarkGlobalWrite 7.762 ns/op -0.037 ns/op / -0.5% (better)
Linux BenchmarkGoroutine 24225 ns/op -1516 ns/op / -5.9% (better)
Linux BenchmarkInterfaceCall 5.832 ns/op -0.054 ns/op / -0.9% (better)
Linux BenchmarkRuntimeGetG 2.891 ns/op +0.173 ns/op / +6.4% (worse)
macOS BenchmarkLookupPCRandom 12.340 ns/op -0.9 ns/op / -6.8% (better)
macOS BenchmarkMergeCompilerFlags 103.100 ns/op -15 ns/op / -12.7% (better)
macOS BenchmarkMergeLinkerFlags 65.690 ns/op -2.1 ns/op / -3.1% (better)
macOS BenchmarkChannelBuffered 26.230 ns/op -0.9 ns/op / -3.3% (better)
macOS BenchmarkChannelHandoff 6795 ns/op -2918 ns/op / -30.0% (better)
macOS BenchmarkDefer 33.400 ns/op +0.82 ns/op / +2.5% (worse)
macOS BenchmarkDirectCall 1.140 ns/op +0.09 ns/op / +8.6% (worse)
macOS BenchmarkGlobalRead 1.296 ns/op +0.183 ns/op / +16.4% (worse)
macOS BenchmarkGlobalWrite 1.147 ns/op +0.036 ns/op / +3.2% (worse)
macOS BenchmarkGoroutine 33092 ns/op +869 ns/op / +2.7% (worse)
macOS BenchmarkInterfaceCall 4.075 ns/op -0.159 ns/op / -3.8% (better)
macOS BenchmarkRuntimeGetG 2.105 ns/op -0.387 ns/op / -15.5% (better)
Windows MinGW BenchmarkLookupPCRandom 13.100 ns/op -0.07 ns/op / -0.5% (better)
Windows MinGW BenchmarkMergeCompilerFlags 615 ns/op -42.6 ns/op / -6.5% (better)
Windows MinGW BenchmarkMergeLinkerFlags 538.700 ns/op -35.5 ns/op / -6.2% (better)
Windows MinGW BenchmarkChannelBuffered 34.110 ns/op +0.84 ns/op / +2.5% (worse)
Windows MinGW BenchmarkChannelHandoff 1253 ns/op -2 ns/op / -0.2% (better)
Windows MinGW BenchmarkDefer 55.940 ns/op +2.15 ns/op / +4.0% (worse)
Windows MinGW BenchmarkDirectCall 1.548 ns/op +0.002 ns/op / +0.1% (worse)
Windows MinGW BenchmarkGlobalRead 1.549 ns/op -0.001 ns/op / -0.1% (better)
Windows MinGW BenchmarkGlobalWrite 2.474 ns/op +0.003 ns/op / +0.1% (worse)
Windows MinGW BenchmarkGoroutine 89477 ns/op +42 ns/op / +0.04696% (worse)
Windows MinGW BenchmarkInterfaceCall 8.076 ns/op +0.007 ns/op / +0.1% (worse)
Windows MinGW BenchmarkRuntimeGetG 2.484 ns/op +0.192 ns/op / +8.4% (worse)
Windows MinGW 386 BenchmarkLookupPCRandom 26.500 ns/op -0.11 ns/op / -0.4% (better)
Windows MinGW 386 BenchmarkMergeCompilerFlags 750.400 ns/op -10.6 ns/op / -1.4% (better)
Windows MinGW 386 BenchmarkMergeLinkerFlags 700.400 ns/op -17.8 ns/op / -2.5% (better)
Windows MinGW 386 BenchmarkChannelBuffered 42.590 ns/op +0.5 ns/op / +1.2% (worse)
Windows MinGW 386 BenchmarkChannelHandoff 903.700 ns/op -3.5 ns/op / -0.4% (better)
Windows MinGW 386 BenchmarkDefer 44.960 ns/op -5.87 ns/op / -11.5% (better)
Windows MinGW 386 BenchmarkDirectCall 1.548 ns/op -0.001 ns/op / -0.1% (better)
Windows MinGW 386 BenchmarkGlobalRead 1.862 ns/op 0 ns/op / +0.0%
Windows MinGW 386 BenchmarkGlobalWrite 7.779 ns/op -0.04 ns/op / -0.5% (better)
Windows MinGW 386 BenchmarkGoroutine 105563 ns/op -1198 ns/op / -1.1% (better)
Windows MinGW 386 BenchmarkInterfaceCall 8.360 ns/op +0.019 ns/op / +0.2% (worse)
Windows MinGW 386 BenchmarkRuntimeGetG 1.927 ns/op 0 ns/op / +0.0%
Windows MinGW ARM64 BenchmarkLookupPCRandom 12.030 ns/op -0.07 ns/op / -0.6% (better)
Windows MinGW ARM64 BenchmarkMergeCompilerFlags 579.100 ns/op +10.5 ns/op / +1.8% (worse)
Windows MinGW ARM64 BenchmarkMergeLinkerFlags 524.500 ns/op -4.5 ns/op / -0.9% (better)
Windows MinGW ARM64 BenchmarkChannelBuffered 38.290 ns/op +0.48 ns/op / +1.3% (worse)
Windows MinGW ARM64 BenchmarkChannelHandoff 3649 ns/op +100 ns/op / +2.8% (worse)
Windows MinGW ARM64 BenchmarkDefer 56.920 ns/op +0.71 ns/op / +1.3% (worse)
Windows MinGW ARM64 BenchmarkDirectCall 0.590 ns/op -0.0001 ns/op / -0.01695% (better)
Windows MinGW ARM64 BenchmarkGlobalRead 0.737 ns/op +0.1475 ns/op / +25.0% (worse)
Windows MinGW ARM64 BenchmarkGlobalWrite 0.663 ns/op -0.0001 ns/op / -0.01507% (better)
Windows MinGW ARM64 BenchmarkGoroutine 61460 ns/op -362 ns/op / -0.6% (better)
Windows MinGW ARM64 BenchmarkInterfaceCall 4.365 ns/op +0.134 ns/op / +3.2% (worse)
Windows MinGW ARM64 BenchmarkRuntimeGetG 1.797 ns/op +0.028 ns/op / +1.6% (worse)
Windows MSVC BenchmarkLookupPCRandom 13.160 ns/op +0.06 ns/op / +0.5% (worse)
Windows MSVC BenchmarkMergeCompilerFlags 655.700 ns/op -6 ns/op / -0.9% (better)
Windows MSVC BenchmarkMergeLinkerFlags 600.500 ns/op -7.1 ns/op / -1.2% (better)
Windows MSVC BenchmarkChannelBuffered 32.860 ns/op -0.3 ns/op / -0.9% (better)
Windows MSVC BenchmarkChannelHandoff 1364 ns/op +44 ns/op / +3.3% (worse)
Windows MSVC BenchmarkDefer 52.710 ns/op -1.04 ns/op / -1.9% (better)
Windows MSVC BenchmarkDirectCall 2.168 ns/op +0.619 ns/op / +40.0% (worse)
Windows MSVC BenchmarkGlobalRead 1.857 ns/op -0.002 ns/op / -0.1% (better)
Windows MSVC BenchmarkGlobalWrite 2.471 ns/op +0.02 ns/op / +0.8% (worse)
Windows MSVC BenchmarkGoroutine 89723 ns/op -271 ns/op / -0.3% (better)
Windows MSVC BenchmarkInterfaceCall 8.378 ns/op -0.312 ns/op / -3.6% (better)
Windows MSVC BenchmarkRuntimeGetG 1.862 ns/op 0 ns/op / +0.0%
Windows MSVC 386 BenchmarkLookupPCRandom 26.510 ns/op +0.05 ns/op / +0.2% (worse)
Windows MSVC 386 BenchmarkMergeCompilerFlags 768.500 ns/op +10.5 ns/op / +1.4% (worse)
Windows MSVC 386 BenchmarkMergeLinkerFlags 670.400 ns/op +7.2 ns/op / +1.1% (worse)
Windows MSVC 386 BenchmarkChannelBuffered 41.720 ns/op -0.63 ns/op / -1.5% (better)
Windows MSVC 386 BenchmarkChannelHandoff 1038 ns/op +11 ns/op / +1.1% (worse)
Windows MSVC 386 BenchmarkDefer 53.360 ns/op +6.91 ns/op / +14.9% (worse)
Windows MSVC 386 BenchmarkDirectCall 1.547 ns/op 0 ns/op / +0.0%
Windows MSVC 386 BenchmarkGlobalRead 2.173 ns/op +0.621 ns/op / +40.0% (worse)
Windows MSVC 386 BenchmarkGlobalWrite 7.795 ns/op +0.003 ns/op / +0.0385% (worse)
Windows MSVC 386 BenchmarkGoroutine 108410 ns/op -714 ns/op / -0.7% (better)
Windows MSVC 386 BenchmarkInterfaceCall 8.385 ns/op +0.242 ns/op / +3.0% (worse)
Windows MSVC 386 BenchmarkRuntimeGetG 2.168 ns/op -0.002 ns/op / -0.1% (better)
Windows MSVC ARM64 BenchmarkLookupPCRandom 12.080 ns/op -0.07 ns/op / -0.6% (better)
Windows MSVC ARM64 BenchmarkMergeCompilerFlags 579.400 ns/op +15.6 ns/op / +2.8% (worse)
Windows MSVC ARM64 BenchmarkMergeLinkerFlags 534.900 ns/op +10.9 ns/op / +2.1% (worse)
Windows MSVC ARM64 BenchmarkChannelBuffered 38.450 ns/op +1.41 ns/op / +3.8% (worse)
Windows MSVC ARM64 BenchmarkChannelHandoff 2436 ns/op -966 ns/op / -28.4% (better)
Windows MSVC ARM64 BenchmarkDefer 64.640 ns/op +1.35 ns/op / +2.1% (worse)
Windows MSVC ARM64 BenchmarkDirectCall 0.590 ns/op +0.0002 ns/op / +0.03392% (worse)
Windows MSVC ARM64 BenchmarkGlobalRead 0.590 ns/op -0.073 ns/op / -11.0% (better)
Windows MSVC ARM64 BenchmarkGlobalWrite 3.796 ns/op 0 ns/op / +0.0%
Windows MSVC ARM64 BenchmarkGoroutine 59806 ns/op +1438 ns/op / +2.5% (worse)
Windows MSVC ARM64 BenchmarkInterfaceCall 4.232 ns/op +0.096 ns/op / +2.3% (worse)
Windows MSVC ARM64 BenchmarkRuntimeGetG 1.794 ns/op +0.024 ns/op / +1.4% (worse)
Timer runtime benchmarks
Platform Operation and runtime ns/op vs base
Linux AfterFuncZeroDelivery/Go 907.800 ns/op -104.2 ns/op / -10.3% (better)
Linux AfterFuncZeroDelivery/LLGo 48387 ns/op +9131 ns/op / +23.3% (worse)
Linux CreateStop/Go 290.700 ns/op -2.7 ns/op / -0.9% (better)
Linux CreateStop/LLGo 1764 ns/op -63 ns/op / -3.4% (better)
Linux RearmStopped/Go 115.900 ns/op -0.1 ns/op / -0.1% (better)
Linux RearmStopped/LLGo 1078 ns/op -269 ns/op / -20.0% (better)
Linux ResetActive/Go 69.430 ns/op +0.81 ns/op / +1.2% (worse)
Linux ResetActive/LLGo 631.900 ns/op -87.1 ns/op / -12.1% (better)
Linux ResetHeap1024/Go 67.280 ns/op -0.19 ns/op / -0.3% (better)
Linux ResetHeap1024/LLGo 166.600 ns/op +0.4 ns/op / +0.2% (worse)
macOS AfterFuncZeroDelivery/Go 387.500 ns/op -50.5 ns/op / -11.5% (better)
macOS AfterFuncZeroDelivery/LLGo 36491 ns/op -1669 ns/op / -4.4% (better)
macOS CreateStop/Go 132.800 ns/op -12.1 ns/op / -8.4% (better)
macOS CreateStop/LLGo 377.900 ns/op -53.7 ns/op / -12.4% (better)
macOS RearmStopped/Go 55.600 ns/op -5.48 ns/op / -9.0% (better)
macOS RearmStopped/LLGo 270.100 ns/op -24.5 ns/op / -8.3% (better)
macOS ResetActive/Go 41.410 ns/op -1.54 ns/op / -3.6% (better)
macOS ResetActive/LLGo 141.600 ns/op -12.4 ns/op / -8.1% (better)
macOS ResetHeap1024/Go 40.090 ns/op -3.09 ns/op / -7.2% (better)
macOS ResetHeap1024/LLGo 75.840 ns/op -7.29 ns/op / -8.8% (better)
Windows MinGW AfterFuncZeroDelivery/Go 564.500 ns/op +17.7 ns/op / +3.2% (worse)
Windows MinGW AfterFuncZeroDelivery/LLGo 182113 ns/op +1870 ns/op / +1.0% (worse)
Windows MinGW CreateStop/Go 123.700 ns/op +7.6 ns/op / +6.5% (worse)
Windows MinGW CreateStop/LLGo 585.200 ns/op -28.7 ns/op / -4.7% (better)
Windows MinGW RearmStopped/Go 31.480 ns/op +0.2 ns/op / +0.6% (worse)
Windows MinGW RearmStopped/LLGo 255.100 ns/op -40.8 ns/op / -13.8% (better)
Windows MinGW ResetActive/Go 20.080 ns/op -0.02 ns/op / -0.1% (better)
Windows MinGW ResetActive/LLGo 177 ns/op +6.1 ns/op / +3.6% (worse)
Windows MinGW ResetHeap1024/Go 20.520 ns/op -0.08 ns/op / -0.4% (better)
Windows MinGW ResetHeap1024/LLGo 121.900 ns/op -1.6 ns/op / -1.3% (better)
Windows MinGW 386 AfterFuncZeroDelivery/Go 936.800 ns/op -10.9 ns/op / -1.2% (better)
Windows MinGW 386 AfterFuncZeroDelivery/LLGo 202125 ns/op +1323 ns/op / +0.7% (worse)
Windows MinGW 386 CreateStop/Go 190 ns/op -0.3 ns/op / -0.2% (better)
Windows MinGW 386 CreateStop/LLGo 523.100 ns/op +52.8 ns/op / +11.2% (worse)
Windows MinGW 386 RearmStopped/Go 68.020 ns/op +4.71 ns/op / +7.4% (worse)
Windows MinGW 386 RearmStopped/LLGo 389.800 ns/op +19.1 ns/op / +5.2% (worse)
Windows MinGW 386 ResetActive/Go 38.970 ns/op +0.01 ns/op / +0.02567% (worse)
Windows MinGW 386 ResetActive/LLGo 1044 ns/op +113.3 ns/op / +12.2% (worse)
Windows MinGW 386 ResetHeap1024/Go 39.500 ns/op +0.15 ns/op / +0.4% (worse)
Windows MinGW 386 ResetHeap1024/LLGo 185.100 ns/op +8.5 ns/op / +4.8% (worse)
Windows MinGW ARM64 AfterFuncZeroDelivery/Go 657.400 ns/op -5.5 ns/op / -0.8% (better)
Windows MinGW ARM64 AfterFuncZeroDelivery/LLGo 148269 ns/op -1852 ns/op / -1.2% (better)
Windows MinGW ARM64 CreateStop/Go 197.600 ns/op -4.3 ns/op / -2.1% (better)
Windows MinGW ARM64 CreateStop/LLGo 356.500 ns/op +2.3 ns/op / +0.6% (worse)
Windows MinGW ARM64 RearmStopped/Go 70.600 ns/op +0.02 ns/op / +0.02834% (worse)
Windows MinGW ARM64 RearmStopped/LLGo 217.100 ns/op +1.7 ns/op / +0.8% (worse)
Windows MinGW ARM64 ResetActive/Go 31.160 ns/op -0.02 ns/op / -0.1% (better)
Windows MinGW ARM64 ResetActive/LLGo 113.700 ns/op -0.7 ns/op / -0.6% (better)
Windows MinGW ARM64 ResetHeap1024/Go 31.170 ns/op +0.02 ns/op / +0.1% (worse)
Windows MinGW ARM64 ResetHeap1024/LLGo 113.200 ns/op -1.5 ns/op / -1.3% (better)
Windows MSVC AfterFuncZeroDelivery/Go 554.700 ns/op -8.9 ns/op / -1.6% (better)
Windows MSVC AfterFuncZeroDelivery/LLGo 178442 ns/op -2161 ns/op / -1.2% (better)
Windows MSVC CreateStop/Go 115.600 ns/op -0.6 ns/op / -0.5% (better)
Windows MSVC CreateStop/LLGo 426.600 ns/op -10.6 ns/op / -2.4% (better)
Windows MSVC RearmStopped/Go 31.660 ns/op +0.14 ns/op / +0.4% (worse)
Windows MSVC RearmStopped/LLGo 232.600 ns/op +3 ns/op / +1.3% (worse)
Windows MSVC ResetActive/Go 20.230 ns/op +0.17 ns/op / +0.8% (worse)
Windows MSVC ResetActive/LLGo 201 ns/op +16.8 ns/op / +9.1% (worse)
Windows MSVC ResetHeap1024/Go 20.540 ns/op +0.12 ns/op / +0.6% (worse)
Windows MSVC ResetHeap1024/LLGo 120 ns/op -5.6 ns/op / -4.5% (better)
Windows MSVC 386 AfterFuncZeroDelivery/Go 960 ns/op +18.1 ns/op / +1.9% (worse)
Windows MSVC 386 AfterFuncZeroDelivery/LLGo 196789 ns/op -3122 ns/op / -1.6% (better)
Windows MSVC 386 CreateStop/Go 191 ns/op -4.4 ns/op / -2.3% (better)
Windows MSVC 386 CreateStop/LLGo 524.100 ns/op +34.7 ns/op / +7.1% (worse)
Windows MSVC 386 RearmStopped/Go 63.270 ns/op -0.02 ns/op / -0.0316% (better)
Windows MSVC 386 RearmStopped/LLGo 312.700 ns/op +2.3 ns/op / +0.7% (worse)
Windows MSVC 386 ResetActive/Go 38.920 ns/op -0.03 ns/op / -0.1% (better)
Windows MSVC 386 ResetActive/LLGo 1017 ns/op +45.4 ns/op / +4.7% (worse)
Windows MSVC 386 ResetHeap1024/Go 39.390 ns/op -0.03 ns/op / -0.1% (better)
Windows MSVC 386 ResetHeap1024/LLGo 164.200 ns/op -1.3 ns/op / -0.8% (better)
Windows MSVC ARM64 AfterFuncZeroDelivery/Go 677.200 ns/op +6.1 ns/op / +0.9% (worse)
Windows MSVC ARM64 AfterFuncZeroDelivery/LLGo 151090 ns/op +929 ns/op / +0.6% (worse)
Windows MSVC ARM64 CreateStop/Go 202.900 ns/op +3.1 ns/op / +1.6% (worse)
Windows MSVC ARM64 CreateStop/LLGo 365.200 ns/op -35.2 ns/op / -8.8% (better)
Windows MSVC ARM64 RearmStopped/Go 71.300 ns/op +0.73 ns/op / +1.0% (worse)
Windows MSVC ARM64 RearmStopped/LLGo 227.100 ns/op -5.4 ns/op / -2.3% (better)
Windows MSVC ARM64 ResetActive/Go 31.060 ns/op -0.08 ns/op / -0.3% (better)
Windows MSVC ARM64 ResetActive/LLGo 115.500 ns/op -6.9 ns/op / -5.6% (better)
Windows MSVC ARM64 ResetHeap1024/Go 31.380 ns/op +0.33 ns/op / +1.1% (worse)
Windows MSVC ARM64 ResetHeap1024/LLGo 119.200 ns/op -0.8 ns/op / -0.7% (better)

Compared with ed6fbb30d292 measured in the same runner job.

cpunion added a commit to cpunion/llgo that referenced this pull request Oct 21, 2026
Reuse the callback-store fix from c87f706 in PR xgo-dev#2895 without the unrelated linkname changes. Clearing or restoring a C callback must not write a two-word Go funcval over adjacent native storage.

Add deterministic adjacent-slot and closure-rejection regressions, plus pointer-width IR checks on Linux, Darwin and all six Windows ABI targets.
cpunion added a commit to cpunion/llgo that referenced this pull request Oct 21, 2026
Reuse the callback-store fix from c87f706 in PR xgo-dev#2895 without the unrelated linkname changes. Clearing or restoring a C callback must not write a two-word Go funcval over adjacent native storage.

Add deterministic adjacent-slot and closure-rejection regressions, plus pointer-width IR checks on Linux, Darwin and all six Windows ABI targets.
cpunion added a commit to cpunion/llgo that referenced this pull request Oct 21, 2026
Reuse the callback-store fix from c87f706 in PR xgo-dev#2895 without the unrelated linkname changes. Clearing or restoring a C callback must not write a two-word Go funcval over adjacent native storage.

Add deterministic adjacent-slot and closure-rejection regressions, plus pointer-width IR checks on Linux, Darwin and all six Windows ABI targets.
cpunion added a commit to cpunion/llgo that referenced this pull request Oct 21, 2026
Reuse the callback-store fix from c87f706 in PR xgo-dev#2895 without the unrelated linkname changes. Clearing or restoring a C callback must not write a two-word Go funcval over adjacent native storage.

Add deterministic adjacent-slot and closure-rejection regressions, plus pointer-width IR checks on Linux, Darwin and all six Windows ABI targets.
cpunion added a commit to cpunion/llgo that referenced this pull request Oct 21, 2026
Reuse the callback-store fix from c87f706 in PR xgo-dev#2895 without the unrelated linkname changes. Clearing or restoring a C callback must not write a two-word Go funcval over adjacent native storage.

Add deterministic adjacent-slot and closure-rejection regressions, plus pointer-width IR checks on Linux, Darwin and all six Windows ABI targets.
@cpunion
cpunion marked this pull request as draft October 22, 2026 08:55
@cpunion
cpunion force-pushed the fix/linkname-native-entries-20261021 branch from 47141cb to 235cc7b Compare October 24, 2026 14:45
@cpunion
cpunion marked this pull request as ready for review October 24, 2026 14:50

@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: native linkname entries

Solid, well-scoped change. The core mechanics check out across all four review passes:

  • Correctness — The HasLinknameTarget rewrite from an O(n) scan to the reference-counted linknameTargets map is correct, including the rebind-to-same-target net-zero case and delete-at-zero. Error propagation from compileGlobal → processPkg → newPackageEx is complete and wrapped with source position. The InitSharedGo coalescing path is correctly gated on goVar + LocalityNone, so extern and thread-local storage are not disturbed.
  • Security / robustness — No new defects. The type assertions in nativeVariableType and the *ast.ValueSpec assertions are protected by their enclosing invariants, and every panic site is the project's established panic-as-diagnostic pattern recovered at the package-build boundary.
  • ABI boundary — DefineNativeExport is correctly shared between the package-local and final-link paths, which are mutually exclusive via CExportWrappers; the native wrapper signature is guaranteed non-nil wherever it is consumed.

Findings below are documentation accuracy and a couple of maintainability nits — none blocking.

Documentation accuracy

The two inline notes flag a doc-vs-code mismatch this PR re-touched: doc/LLGo-Link.md says a py./llgo. function with a body is "rejected with a compile error", but compileFuncDecl returns ignoredFunc for any non-goFunc ftype (cl/compile.go:634), so the body is silently discarded rather than rejected. The enforcement gap is pre-existing, but these doc lines were edited in this PR and still assert rejection.

Minor wording observation (no inline anchor): doc/LLGo-Link.md lines ~92/244 state that a stdcall. linkname on a non-Windows target is rejected "whether or not it has a body" and for variables. Enforcement is actually lazy — the error originates in ssa/stdcall.go stdcallCallConv only when the stdcall ABI is materialized (a call/callback/type construction). A declared-but-unused stdcall symbol on a non-Windows target may not trigger it. Worth confirming whether the doc intends to promise eager rejection.

Maintainability (optional)

  • ssa/package_syntax.go NativeExport: the local is named cc (cc, ok := ...nativeExports[name]) but its type is NativeExportInfo, not CallConv. info would read more clearly. (inline)
  • cl/linkname_native.go nativeVariableType: a fresh types.NewNamed(...+"$stdcall") is built on every call. Correctness holds because the stdcall callconv is keyed by the linkname string (not type identity) and NewVar caches by name, but producing multiple identically-named *types.Named instances is surprising — a one-line comment or memoization would reduce the refactoring hazard. (inline)
  • The stdcall. variable → $stdcall type-callconv registration is implemented in two places (collectNativeLinkDefinitions for the compiled package and initLink for imported packages). Both are needed for their scopes; a cross-reference comment would guard against drift.

Performance (informational)

No regressions — HasLinknameTarget is now a genuine improvement. The new passes in ParsePkgSyntaxWithOptions are all linear in source size. The only opportunistic cleanup worth noting: ParsePkgSyntaxWithOptions now sweeps file.Comments several separate times (validateInternalDirectives, collectPackageLinknames, and the new //go:cgo_import_* loop), and collectNativeLinkDefinitions recomputes astFuncName per decl and takes the packageSyntax lock twice even on the common no-linkname path. Constant-factor only; fold if compile time of comment-heavy/cgo packages ever shows up in a profile.

Comment thread doc/LLGo-Link.md Outdated
Comment thread doc/LLGo-Link.md Outdated
Comment thread ssa/package_syntax.go Outdated
Comment thread cl/linkname_native.go
@cpunion
cpunion force-pushed the fix/linkname-native-entries-20261021 branch from 235cc7b to ebd2b8a Compare October 25, 2026 00:55
@cpunion

cpunion commented Oct 25, 2026

Copy link
Copy Markdown
Collaborator Author

Full compiler testing after rebase caught main's new interface-kind predicate fixtures using bodyless llgo:link declarations. Updated only those fixtures with the required placeholder bodies in d541938, retaining the lowering checks and every invalid-argument diagnostic. The two failing tests now pass; the complete compiler suite is being rerun.

@cpunion

cpunion commented Oct 25, 2026

Copy link
Copy Markdown
Collaborator Author

The complete compiler suite now passes (321.144s), including the interface-kind placeholder fixtures and reflection metadata cases; the complete SSA suite also passed. The isolated local failure was a shared in-process test cache archive from the other ABI branch; rerunning with the incompatible archive isolated resolved it without changing compiler behavior.

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