Go: A Documentary

GOEXPERIMENT lifecycles

GOEXPERIMENT flags are how most large runtime and compiler changes were staged. Each one goes from added (off by default, opt-in), to default-on (added to the baseline in internal/buildcfg/exp.go, so you opt out with GOEXPERIMENT=noX), to flag removed (the old code path is deleted). This table was derived by diffing src/internal/goexperiment/flags.go and the baseline set in internal/buildcfg/exp.go at every cycle boundary. Each transition is attributed to the cycle in which its commit landed on master.

Experiment What it gates Added Default-on Flag removed State at HEAD
RegabiWrappers, RegabiArgs (+ RegabiG, RegabiReflect, RegabiDefer) Register-based calling convention (ABIInternal) 1.16 2b8b06ebbf (one regabi flag); split into sub-experiments 1.17 14dbd6e776; amd64 on linux/darwin/windows default-on in 1.17 (fd3612e433, 9dd71ba913), android 9c12f1b433 amd64, all OSes: 1.18 382c5dd5f7; arm64: 1.18 4d2b528795; ppc64: 1.18 ae83301ab2; riscv64: 1.19 53f13128a7; loong64: 1.22 e5615ad876; s390x: 1.26 89552911b3 RegabiDefer: 1.18 a9de78ac88; RegabiG: 1.18 c93d5d1a52; RegabiReflect: 1.19 3684abbf6c Baseline = regabiSupported; 386, arm, mips*, wasm still use ABI0
PacerRedesign New GC pacer (PI controller over total heap work, including stacks and globals) 1.18 a108b280bc 1.18 961aab26bf 1.19 3334afd760 Old pacer deleted
HeapMinimum512KiB Smaller minimum heap target 1.18 c5c1955077 — — Still an opt-in flag
Unified Unified IR frontend (noder → export data → IR) 1.18 804ecc2581 1.20 833367e98a 1.21 4f467f1082 Only frontend
CoverageRedesign Compiler-instrumented coverage with meta-data/counter files 1.20 a3434b71a3 1.20 9910f8a403 1.25 41298239cf Only implementation
Arenas arena package (manual region allocation) 1.20 e0d01b8467 — — Still opt-in, never enabled
PageTrace Page-allocation tracing 1.20 e4435cb844 — 1.23 97c13cfb25 Deleted
CgoCheck2 cgocheck=2 write-barrier checking moved from GODEBUG to a build-time experiment 1.21 55044288ad — — Opt-in
LoopVar Per-iteration loop variables 1.21 c20d959163 Tied to the module’s Go version (≥1.22) in 1.22 fe1daf2e43, not via the baseline — Flag kept (forces semantics regardless of version)
NewInliner Heuristics-based inliner (inline/inlheur) 1.22 fbf9076ee8 never — Still opt-in
Range → RangeFunc Range-over-func / range-over-int 1.22 (renamed 45320c23f2) Language-version gated in 1.23 d278d5bbdd Range 1.23 d428a63875; RangeFunc 1.26 25816d401c Language feature
AllocHeaders Malloc headers / per-span metadata instead of the heap bitmap 1.22 25867485a7 1.22 e3585c6757 1.23 9f3f4c64db Only implementation
ExecTracer2 New partitioned execution tracer 1.22 43ffe2a892 1.22 41f58b2295 1.23 55e4097cba Only tracer
AliasTypeParams Generic type aliases 1.23 c3591cb30c 1.24 4a1167dfe1 1.26 00a7bdcb55 Language feature
SwissMap Swiss-table map implementation 1.24 057b703407 1.24 99d60c24e2 1.26 2ae059ccaf Only map implementation
SpinbitMutex New runtime-internal mutex (spin bit + waiter list in one word) 1.24 18c2461af3 1.24 fd050b3c6d (where 8-bit Xchg exists); all platforms 1.25 5e98202455 1.25 7a177114df Only implementation
SyncHashTrieMap sync.Map reimplemented over a concurrent hash-trie 1.24 aecb8faa91 1.24 1.26 e15a14c4dd Only implementation
Synctest testing/synctest bubbles 1.24 76e4efdc77 — 1.26 4c0fd3a2b4 (graduated) Package is standard
Dwarf5 DWARF 5 debug info 1.25 bdb4676043 1.25 ca19f987ca — Baseline where supported
GreenTeaGC Span-oriented (“Green Tea”) marking 1.25 f1ebad19bd 1.26 7fbf54bfeb (loong64 c53cb642de) — Default-on, nogreenteagc still available
RandomizedHeapBase64 Randomized heap base address on 64-bit 1.26 6669aa3b14 1.26 72ba117bda — Default-on
SizeSpecializedMalloc Generated per-size-class mallocgc variants 1.26 60c1ee9183 Enabled on master in 1.26 (a7917eed70), but go1.26.0 shipped with it off (release-branch cherry-pick 3604782621; master counterpart 4af8ad24ee); re-enabled 1.27 2a93576965 1.28 4a7645b730 Only implementation (dev tree)
RuntimeFreegc Compiler-directed explicit freeing of heap memory 1.26 5dcaf9a01b off (5a347b775e) — Opt-in
RuntimeSecret runtime/secret (erase secrets from registers/stack/heap) 1.26 a3fb92a710 — — Opt-in
GoroutineLeakProfile GC-based goroutine-leak detection profile 1.26 8c68a1c1ab 1.27 253aa2a12a 1.27 16449179ec / afcf04cb64 Graduated
SIMD simd/archsimd intrinsics package (dev.simd) 1.26 4d2c71ebf9 toggled on the branch; off at merge (1d8711e126, c59ae5c5a7) — Opt-in
GenericMethods Methods with their own type parameters 1.27 aa62c18749 1.27 e212a16d1e 1.27 012d142e78 Language feature
MapSplitGroup Swiss-map group slot layout KKKKVVVV instead of KVKVKVKV 1.27 5560073398 1.28 26c2ec0508 — Default in dev tree
CgoBindings New cgo bindings mechanism 1.28 6bbd163b33 — — Opt-in (dev tree)

Default-on experiments as actually shipped. This is the baseline in each release tag. It can differ from master at the end of the cycle when the release branch changes a default.

Tag Default-on experiments
go1.18 RegabiWrappers, RegabiReflect, RegabiArgs (where supported), PacerRedesign
go1.19 RegabiWrappers, RegabiArgs
go1.20 Regabi*, Unified, CoverageRedesign
go1.21.0 Regabi*, CoverageRedesign
go1.22.0 Regabi*, CoverageRedesign, AllocHeaders, ExecTracer2
go1.23.0 Regabi*, CoverageRedesign
go1.24.0 Regabi*, CoverageRedesign, AliasTypeParams, SwissMap, SpinbitMutex (where 8-bit Xchg exists), SyncHashTrieMap
go1.25.0 Regabi*, AliasTypeParams, SwissMap, SyncHashTrieMap, Dwarf5
go1.26.0 Regabi*, Dwarf5, RandomizedHeapBase64, GreenTeaGC
go1.27.0 Regabi*, Dwarf5, RandomizedHeapBase64, GreenTeaGC, JSONv2, SizeSpecializedMalloc
HEAD (1.28-dev) Regabi*, Dwarf5, RandomizedHeapBase64, GreenTeaGC, JSONv2, MapSplitGroup, GoListExportNewFormat

A flag that drops out of this list without being disabled was removed: the feature became the only implementation. Examples are PacerRedesign after 1.18, AllocHeaders and ExecTracer2 after 1.22, and SwissMap after 1.25.

The same history also records these non-experiment knobs (GODEBUG settings and environment variables): GOAMD64 microarchitecture levels (1.18, b1bedc0774), GODEBUG=harddecommit (1.18, f063e0da28), GOPPC64=power10 (1.20, 0eb56ca468), GODEBUG=dontfreezetheworld (1.21, 5f882d8266), GODEBUG=disablethp (1.22, c915215af6), GORISCV64 (1.23, b4e7d630bc; rva23u64 added in 1.25, 664aebab7d), GOARM64 (1.23, e8b5bc63be), GODEBUG=decoratemappings (1.25, c40a3731f4), and GOWASM=stackswitch (1.28, 5408ea597b).

Before 1.18: experiments as a table inside the toolchain

Before Go 1.17 there was no baseline. An experiment was an entry in a table compiled into the toolchain, and it was off unless GOEXPERIMENT named it when the toolchain was built. The table lived in src/cmd/gc/lex.c up to Go 1.4. For Go 1.5 it moved to src/cmd/internal/obj/go.go, and dba9eb3369 re-implemented GOEXPERIMENT in the runtime and liblink for the frame-pointer experiment. From Go 1.9 the table lived in src/cmd/internal/objabi/util.go. In Go 1.17, 6304b401e4 consolidated the experiments into internal/goexperiment, a8e55538af made GOEXPERIMENT a diff against per-platform defaults (the baseline used in the table above), and 5159c83641 added the active set to runtime.Version(). This table was derived by reading the experiment table at every release tag from go1 to go1.17. Each transition is attributed to the first release tag that contains its commit.

Experiment What it gates Added Default-on Flag removed State at HEAD
rune32 rune as an alias of int32 instead of int 1.0 (2011-10) 6ed3fa6553 1.0 (2011-12) 012798a325: rune is always int32 and the table entry is commented out the commented-out entry disappeared with lex.c —
fieldtrack Struct field tracking: fields tagged go:"track" are reported by the linker when used 1.1 3d40062c68 never — Still opt-in (FieldTrack)
precisestack Fully precise stack-frame scanning (no reads of uninitialised pointer slots) 1.2 30ecb4cd05: call-site bitmaps were not ready, so it shipped opt-in 1.3 53061193f1 (first attempt ecf700b5ee was undone by aad23e708c) 1.4 15b76ad94b, together with copystack Assumed everywhere
framepointer Saving BP frame pointers on amd64 1.5 3c0fee10db 1.7 7fdec6216c (amd64) 1.16 5c2c6d3fbf (hard-coded on) buildcfg.FramePointerEnabled (amd64, arm64)
preemptibleloops Reschedule checks on loop back edges 1.8 7f1ff65c39 never — Still opt-in (PreemptibleLoops)
clobberdead Clobbering dead pointer slots at safepoints, to debug liveness maps 1.9 1e72bf6218 never 1.12 57c8eb92b7 —
debugcpu GODEBUGCPU for disabling CPU features 1.11 f045ddc624 — 1.12 a5248acd91 (GODEBUGCPU available in every build) —
staticlockranking Static lock-rank checking in the runtime 1.15 0a820007e7 never — Still opt-in (StaticLockRanking)
regabi Register-based calling convention 1.16 2b8b06ebbf see the table above split in 1.17 14dbd6e776 see the table above