gitee.com/ks-custle/core-gm@v0.0.0-20230922171213-b83bdd97b62c/internal/buildcfg/exp.go (about) 1 // Copyright 2021 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package buildcfg 6 7 import ( 8 "fmt" 9 "reflect" 10 "strings" 11 12 "gitee.com/ks-custle/core-gm/internal/goexperiment" 13 ) 14 15 // Experiment contains the toolchain experiments enabled for the 16 // current build. 17 // 18 // (This is not necessarily the set of experiments the compiler itself 19 // was built with.) 20 // 21 // experimentBaseline specifies the experiment flags that are enabled by 22 // default in the current toolchain. This is, in effect, the "control" 23 // configuration and any variation from this is an experiment. 24 var Experiment, experimentBaseline = func() (goexperiment.Flags, goexperiment.Flags) { 25 flags, baseline, err := ParseGOEXPERIMENT(GOOS, GOARCH, envOr("GOEXPERIMENT", defaultGOEXPERIMENT)) 26 if err != nil { 27 Error = err 28 } 29 return flags, baseline 30 }() 31 32 const DefaultGOEXPERIMENT = defaultGOEXPERIMENT 33 34 // FramePointerEnabled enables the use of platform conventions for 35 // saving frame pointers. 36 // 37 // This used to be an experiment, but now it's always enabled on 38 // platforms that support it. 39 // 40 // Note: must agree with runtime.framepointer_enabled. 41 var FramePointerEnabled = GOARCH == "amd64" || GOARCH == "arm64" 42 43 // ParseGOEXPERIMENT parses a (GOOS, GOARCH, GOEXPERIMENT) 44 // configuration tuple and returns the enabled and baseline experiment 45 // flag sets. 46 // 47 // TODO(mdempsky): Move to internal/goexperiment. 48 func ParseGOEXPERIMENT(goos, goarch, goexp string) (flags, baseline goexperiment.Flags, err error) { 49 regabiSupported := goarch == "amd64" && (goos == "android" || goos == "linux" || goos == "darwin" || goos == "windows") 50 51 baseline = goexperiment.Flags{ 52 RegabiWrappers: regabiSupported, 53 RegabiG: regabiSupported, 54 RegabiReflect: regabiSupported, 55 RegabiDefer: regabiSupported, 56 RegabiArgs: regabiSupported, 57 } 58 59 // Start with the statically enabled set of experiments. 60 flags = baseline 61 62 // Pick up any changes to the baseline configuration from the 63 // GOEXPERIMENT environment. This can be set at make.bash time 64 // and overridden at build time. 65 if goexp != "" { 66 // Create a map of known experiment names. 67 names := make(map[string]func(bool)) 68 rv := reflect.ValueOf(&flags).Elem() 69 rt := rv.Type() 70 for i := 0; i < rt.NumField(); i++ { 71 field := rv.Field(i) 72 names[strings.ToLower(rt.Field(i).Name)] = field.SetBool 73 } 74 75 // "regabi" is an alias for all working regabi 76 // subexperiments, and not an experiment itself. Doing 77 // this as an alias make both "regabi" and "noregabi" 78 // do the right thing. 79 names["regabi"] = func(v bool) { 80 flags.RegabiWrappers = v 81 flags.RegabiG = v 82 flags.RegabiReflect = v 83 flags.RegabiDefer = v 84 flags.RegabiArgs = v 85 } 86 87 // Parse names. 88 for _, f := range strings.Split(goexp, ",") { 89 if f == "" { 90 continue 91 } 92 if f == "none" { 93 // GOEXPERIMENT=none disables all experiment flags. 94 // This is used by cmd/dist, which doesn't know how 95 // to build with any experiment flags. 96 flags = goexperiment.Flags{} 97 continue 98 } 99 val := true 100 if strings.HasPrefix(f, "no") { 101 f, val = f[2:], false 102 } 103 set, ok := names[f] 104 if !ok { 105 err = fmt.Errorf("unknown GOEXPERIMENT %s", f) 106 return 107 } 108 set(val) 109 } 110 } 111 112 // regabi is only supported on amd64. 113 if goarch != "amd64" { 114 flags.RegabiWrappers = false 115 flags.RegabiG = false 116 flags.RegabiReflect = false 117 flags.RegabiDefer = false 118 flags.RegabiArgs = false 119 } 120 // Check regabi dependencies. 121 if flags.RegabiG && !flags.RegabiWrappers { 122 err = fmt.Errorf("GOEXPERIMENT regabig requires regabiwrappers") 123 } 124 if flags.RegabiArgs && !(flags.RegabiWrappers && flags.RegabiG && flags.RegabiReflect && flags.RegabiDefer) { 125 err = fmt.Errorf("GOEXPERIMENT regabiargs requires regabiwrappers,regabig,regabireflect,regabidefer") 126 } 127 return 128 } 129 130 // expList returns the list of lower-cased experiment names for 131 // experiments that differ from base. base may be nil to indicate no 132 // experiments. If all is true, then include all experiment flags, 133 // regardless of base. 134 func expList(exp, base *goexperiment.Flags, all bool) []string { 135 var list []string 136 rv := reflect.ValueOf(exp).Elem() 137 var rBase reflect.Value 138 if base != nil { 139 rBase = reflect.ValueOf(base).Elem() 140 } 141 rt := rv.Type() 142 for i := 0; i < rt.NumField(); i++ { 143 name := strings.ToLower(rt.Field(i).Name) 144 val := rv.Field(i).Bool() 145 baseVal := false 146 if base != nil { 147 baseVal = rBase.Field(i).Bool() 148 } 149 if all || val != baseVal { 150 if val { 151 list = append(list, name) 152 } else { 153 list = append(list, "no"+name) 154 } 155 } 156 } 157 return list 158 } 159 160 // GOEXPERIMENT is a comma-separated list of enabled or disabled 161 // experiments that differ from the baseline experiment configuration. 162 // GOEXPERIMENT is exactly what a user would set on the command line 163 // to get the set of enabled experiments. 164 func GOEXPERIMENT() string { 165 return strings.Join(expList(&Experiment, &experimentBaseline, false), ",") 166 } 167 168 // EnabledExperiments returns a list of enabled experiments, as 169 // lower-cased experiment names. 170 func EnabledExperiments() []string { 171 return expList(&Experiment, nil, false) 172 } 173 174 // AllExperiments returns a list of all experiment settings. 175 // Disabled experiments appear in the list prefixed by "no". 176 func AllExperiments() []string { 177 return expList(&Experiment, nil, true) 178 } 179 180 // UpdateExperiments updates the Experiment global based on a new GOARCH value. 181 // This is only required for cmd/go, which can change GOARCH after 182 // program startup due to use of "go env -w". 183 func UpdateExperiments(goos, goarch, goexperiment string) { 184 var err error 185 Experiment, experimentBaseline, err = ParseGOEXPERIMENT(goos, goarch, goexperiment) 186 if err != nil { 187 Error = err 188 } 189 }