diff options
| author | Austin Clements <austin@google.com> | 2021-04-06 08:25:01 -0400 |
|---|---|---|
| committer | Austin Clements <austin@google.com> | 2021-04-08 02:17:16 +0000 |
| commit | 6304b401e4bcfc1d61dd687bb5b7df13fd71033b (patch) | |
| tree | 7f9e87d47b4a1baf3809f12e18bcc1d5a1248e9f /src/cmd/internal/objabi | |
| parent | 0c4a08cb74abe026260a224a2b553c1f77a1172a (diff) | |
| download | go-6304b401e4bcfc1d61dd687bb5b7df13fd71033b.tar.xz | |
internal/goexperiment,cmd: consolidate GOEXPERIMENTs into a new package
Currently there's knowledge about the list of GOEXPERIMENTs in a few
different places. This CL introduces a new package and consolidates
the list into one place: the internal/goexperiment.Flags struct type.
This package gives us a central place to document the experiments as
well as the GOEXPERIMENT environment variable itself. It will also
give us a place to put built-time constants derived from the enabled
experiments.
Now the objabi package constructs experiment names by reflecting over
this struct type rather than having a separate list of these names
(this is similar to how the compiler handles command-line flags and
debug options). We also expose a better-typed API to the toolchain for
propagating enabled experiments.
Change-Id: I06e026712b59fe2bd7cd11a869aedb48ffe5a4b7
Reviewed-on: https://go-review.googlesource.com/c/go/+/307817
Trust: Austin Clements <austin@google.com>
Run-TryBot: Austin Clements <austin@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
Diffstat (limited to 'src/cmd/internal/objabi')
| -rw-r--r-- | src/cmd/internal/objabi/exp.go | 132 | ||||
| -rw-r--r-- | src/cmd/internal/objabi/util.go | 179 |
2 files changed, 132 insertions, 179 deletions
diff --git a/src/cmd/internal/objabi/exp.go b/src/cmd/internal/objabi/exp.go new file mode 100644 index 0000000000..21a70d5dfe --- /dev/null +++ b/src/cmd/internal/objabi/exp.go @@ -0,0 +1,132 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package objabi + +import ( + "fmt" + "os" + "reflect" + "strings" + + "internal/goexperiment" +) + +// Experiment contains the toolchain experiments enabled for the +// current build. +// +// (This is not necessarily the set of experiments the compiler itself +// was built with.) +var Experiment goexperiment.Flags + +var defaultExpstring string // Set by package init + +// FramePointerEnabled enables the use of platform conventions for +// saving frame pointers. +// +// This used to be an experiment, but now it's always enabled on +// platforms that support it. +// +// Note: must agree with runtime.framepointer_enabled. +var FramePointerEnabled = GOARCH == "amd64" || GOARCH == "arm64" + +func init() { + // Capture "default" experiments. + defaultExpstring = Expstring() + + goexperiment := envOr("GOEXPERIMENT", defaultGOEXPERIMENT) + + // GOEXPERIMENT=none overrides all experiments enabled at dist time. + if goexperiment != "none" { + // Create a map of known experiment names. + names := make(map[string]reflect.Value) + rv := reflect.ValueOf(&Experiment).Elem() + rt := rv.Type() + for i := 0; i < rt.NumField(); i++ { + field := rv.Field(i) + names[strings.ToLower(rt.Field(i).Name)] = field + } + + // Parse names. + for _, f := range strings.Split(goexperiment, ",") { + if f == "" { + continue + } + val := true + if strings.HasPrefix(f, "no") { + f, val = f[2:], false + } + field, ok := names[f] + if !ok { + fmt.Printf("unknown experiment %s\n", f) + os.Exit(2) + } + field.SetBool(val) + } + } + + // regabi is only supported on amd64. + if GOARCH != "amd64" { + Experiment.Regabi = false + Experiment.RegabiWrappers = false + Experiment.RegabiG = false + Experiment.RegabiReflect = false + Experiment.RegabiDefer = false + Experiment.RegabiArgs = false + } + // Setting regabi sets working sub-experiments. + if Experiment.Regabi { + Experiment.RegabiWrappers = true + Experiment.RegabiG = true + Experiment.RegabiReflect = true + Experiment.RegabiDefer = true + // Not ready yet: + //Experiment.RegabiArgs = true + } + // Check regabi dependencies. + if Experiment.RegabiG && !Experiment.RegabiWrappers { + panic("GOEXPERIMENT regabig requires regabiwrappers") + } + if Experiment.RegabiArgs && !(Experiment.RegabiWrappers && Experiment.RegabiG && Experiment.RegabiReflect && Experiment.RegabiDefer) { + panic("GOEXPERIMENT regabiargs requires regabiwrappers,regabig,regabireflect,regabidefer") + } +} + +// expList returns the list of enabled GOEXPERIMENTs names. +func expList(flags *goexperiment.Flags) []string { + var list []string + rv := reflect.ValueOf(&Experiment).Elem() + rt := rv.Type() + for i := 0; i < rt.NumField(); i++ { + val := rv.Field(i).Bool() + if val { + field := rt.Field(i) + list = append(list, strings.ToLower(field.Name)) + } + } + return list +} + +// Expstring returns the GOEXPERIMENT string that should appear in Go +// version signatures. This always starts with "X:". +func Expstring() string { + list := expList(&Experiment) + if len(list) == 0 { + return "X:none" + } + return "X:" + strings.Join(list, ",") +} + +// GOEXPERIMENT returns a comma-separated list of enabled experiments. +// This is derived from the GOEXPERIMENT environment variable if set, +// or the value of GOEXPERIMENT when make.bash was run if not. +func GOEXPERIMENT() string { + return strings.Join(expList(&Experiment), ",") +} + +// EnabledExperiments returns a list of enabled experiments, as +// lower-cased experiment names. +func EnabledExperiments() []string { + return expList(&Experiment) +} diff --git a/src/cmd/internal/objabi/util.go b/src/cmd/internal/objabi/util.go index ca3d3fc1a3..76c56dab27 100644 --- a/src/cmd/internal/objabi/util.go +++ b/src/cmd/internal/objabi/util.go @@ -5,7 +5,6 @@ package objabi import ( - "fmt" "log" "os" "strings" @@ -32,12 +31,6 @@ var ( GOWASM = gowasm() GO_LDSO = defaultGO_LDSO Version = version - - // GOEXPERIMENT is a comma-separated list of enabled - // experiments. This is derived from the GOEXPERIMENT - // environment variable if set, or the value of GOEXPERIMENT - // when make.bash was run if not. - GOEXPERIMENT string // Set by package init ) const ( @@ -128,175 +121,3 @@ func gowasm() (f gowasmFeatures) { func Getgoextlinkenabled() string { return envOr("GO_EXTLINK_ENABLED", defaultGO_EXTLINK_ENABLED) } - -func init() { - // Capture "default" experiments. - defaultExpstring = Expstring() - - goexperiment := envOr("GOEXPERIMENT", defaultGOEXPERIMENT) - - // GOEXPERIMENT=none overrides all experiments enabled at dist time. - if goexperiment != "none" { - for _, f := range strings.Split(goexperiment, ",") { - if f != "" { - addexp(f) - } - } - } - - // regabi is only supported on amd64. - if GOARCH != "amd64" { - Experiment.regabi = false - Experiment.RegabiWrappers = false - Experiment.RegabiG = false - Experiment.RegabiReflect = false - Experiment.RegabiDefer = false - Experiment.RegabiArgs = false - } - // Setting regabi sets working sub-experiments. - if Experiment.regabi { - Experiment.RegabiWrappers = true - Experiment.RegabiG = true - Experiment.RegabiReflect = true - Experiment.RegabiDefer = true - // Not ready yet: - //Experiment.RegabiArgs = true - } - // Check regabi dependencies. - if Experiment.RegabiG && !Experiment.RegabiWrappers { - panic("GOEXPERIMENT regabig requires regabiwrappers") - } - if Experiment.RegabiArgs && !(Experiment.RegabiWrappers && Experiment.RegabiG && Experiment.RegabiReflect && Experiment.RegabiDefer) { - panic("GOEXPERIMENT regabiargs requires regabiwrappers,regabig,regabireflect,regabidefer") - } - - // Set GOEXPERIMENT to the parsed and canonicalized set of experiments. - GOEXPERIMENT = expList() -} - -// FramePointerEnabled enables the use of platform conventions for -// saving frame pointers. -// -// This used to be an experiment, but now it's always enabled on -// platforms that support it. -// -// Note: must agree with runtime.framepointer_enabled. -var FramePointerEnabled = GOARCH == "amd64" || GOARCH == "arm64" - -func addexp(s string) { - // We could do general integer parsing here, but there's no need yet. - v, vb := 1, true - name := s - if len(name) > 2 && name[:2] == "no" { - v, vb = 0, false - name = name[2:] - } - for i := 0; i < len(exper); i++ { - if exper[i].name == name { - switch val := exper[i].val.(type) { - case *int: - *val = v - case *bool: - *val = vb - default: - panic("bad GOEXPERIMENT type for " + s) - } - return - } - } - - fmt.Printf("unknown experiment %s\n", s) - os.Exit(2) -} - -// Experiment contains flags for GOEXPERIMENTs. -var Experiment = ExpFlags{} - -type ExpFlags struct { - FieldTrack bool - PreemptibleLoops bool - StaticLockRanking bool - - // regabi is split into several sub-experiments that can be - // enabled individually. GOEXPERIMENT=regabi implies the - // subset that are currently "working". Not all combinations work. - regabi bool - // RegabiWrappers enables ABI wrappers for calling between - // ABI0 and ABIInternal functions. Without this, the ABIs are - // assumed to be identical so cross-ABI calls are direct. - RegabiWrappers bool - // RegabiG enables dedicated G and zero registers in - // ABIInternal. - // - // Requires wrappers because it makes the ABIs incompatible. - RegabiG bool - // RegabiReflect enables the register-passing paths in - // reflection calls. This is also gated by intArgRegs in - // reflect and runtime (which are disabled by default) so it - // can be used in targeted tests. - RegabiReflect bool - // RegabiDefer enables desugaring defer and go calls - // into argument-less closures. - RegabiDefer bool - // RegabiArgs enables register arguments/results in all - // compiled Go functions. - // - // Requires wrappers (to do ABI translation), g (because - // runtime assembly that's been ported to ABIInternal uses the - // G register), reflect (so reflection calls use registers), - // and defer (because the runtime doesn't support passing - // register arguments to defer/go). - RegabiArgs bool -} - -// Toolchain experiments. -// These are controlled by the GOEXPERIMENT environment -// variable recorded when the toolchain is built. -var exper = []struct { - name string - val interface{} // Must be *int or *bool -}{ - {"fieldtrack", &Experiment.FieldTrack}, - {"preemptibleloops", &Experiment.PreemptibleLoops}, - {"staticlockranking", &Experiment.StaticLockRanking}, - {"regabi", &Experiment.regabi}, - {"regabiwrappers", &Experiment.RegabiWrappers}, - {"regabig", &Experiment.RegabiG}, - {"regabireflect", &Experiment.RegabiReflect}, - {"regabidefer", &Experiment.RegabiDefer}, - {"regabiargs", &Experiment.RegabiArgs}, -} - -var defaultExpstring string - -// expList returns the list of enabled GOEXPERIMENTS as a -// commas-separated list. -func expList() string { - buf := "" - for i := range exper { - switch val := exper[i].val.(type) { - case *int: - if *val != 0 { - buf += "," + exper[i].name - } - case *bool: - if *val { - buf += "," + exper[i].name - } - } - } - if len(buf) == 0 { - return "" - } - return buf[1:] -} - -// Expstring returns the GOEXPERIMENT string that should appear in Go -// version signatures. This always starts with "X:". -func Expstring() string { - list := expList() - if list == "" { - return "X:none" - } - return "X:" + list -} |
