1
2
3
4
5 package buildcfg
6
7 import (
8 "fmt"
9 "reflect"
10 "strings"
11
12 "internal/goexperiment"
13 )
14
15
16
17 type ExperimentFlags struct {
18 goexperiment.Flags
19 baseline goexperiment.Flags
20 }
21
22
23
24
25
26
27
28
29
30
31 var Experiment ExperimentFlags = func() ExperimentFlags {
32 flags, err := ParseGOEXPERIMENT(GOOS, GOARCH, envOr("GOEXPERIMENT", defaultGOEXPERIMENT))
33 if err != nil {
34 Error = err
35 return ExperimentFlags{}
36 }
37 return *flags
38 }()
39
40
41
42 const DefaultGOEXPERIMENT = defaultGOEXPERIMENT
43
44
45
46
47
48
49
50
51 var FramePointerEnabled = GOARCH == "amd64" || GOARCH == "arm64"
52
53
54
55
56
57
58 func ParseGOEXPERIMENT(goos, goarch, goexp string) (*ExperimentFlags, error) {
59
60
61
62
63 var regabiSupported, regabiAlwaysOn bool
64 switch goarch {
65 case "amd64", "arm64", "loong64", "ppc64le", "ppc64", "riscv64":
66 regabiAlwaysOn = true
67 regabiSupported = true
68 }
69
70 var haveXchg8 bool
71 switch goarch {
72 case "386", "amd64", "arm", "arm64", "ppc64le", "ppc64":
73 haveXchg8 = true
74 }
75
76 baseline := goexperiment.Flags{
77 RegabiWrappers: regabiSupported,
78 RegabiArgs: regabiSupported,
79 CoverageRedesign: true,
80 AliasTypeParams: true,
81 SwissMap: true,
82 SpinbitMutex: haveXchg8,
83 SyncHashTrieMap: true,
84 }
85
86
87 flags := &ExperimentFlags{
88 Flags: baseline,
89 baseline: baseline,
90 }
91
92
93
94
95 if goexp != "" {
96
97 names := make(map[string]func(bool))
98 rv := reflect.ValueOf(&flags.Flags).Elem()
99 rt := rv.Type()
100 for i := 0; i < rt.NumField(); i++ {
101 field := rv.Field(i)
102 names[strings.ToLower(rt.Field(i).Name)] = field.SetBool
103 }
104
105
106
107
108
109 names["regabi"] = func(v bool) {
110 flags.RegabiWrappers = v
111 flags.RegabiArgs = v
112 }
113
114
115 for _, f := range strings.Split(goexp, ",") {
116 if f == "" {
117 continue
118 }
119 if f == "none" {
120
121
122
123 flags.Flags = goexperiment.Flags{}
124 continue
125 }
126 val := true
127 if strings.HasPrefix(f, "no") {
128 f, val = f[2:], false
129 }
130 set, ok := names[f]
131 if !ok {
132 return nil, fmt.Errorf("unknown GOEXPERIMENT %s", f)
133 }
134 set(val)
135 }
136 }
137
138 if regabiAlwaysOn {
139 flags.RegabiWrappers = true
140 flags.RegabiArgs = true
141 }
142
143 if !regabiSupported {
144 flags.RegabiWrappers = false
145 flags.RegabiArgs = false
146 }
147
148 if flags.RegabiArgs && !flags.RegabiWrappers {
149 return nil, fmt.Errorf("GOEXPERIMENT regabiargs requires regabiwrappers")
150 }
151 return flags, nil
152 }
153
154
155
156 func (exp *ExperimentFlags) String() string {
157 return strings.Join(expList(&exp.Flags, &exp.baseline, false), ",")
158 }
159
160
161
162
163
164 func expList(exp, base *goexperiment.Flags, all bool) []string {
165 var list []string
166 rv := reflect.ValueOf(exp).Elem()
167 var rBase reflect.Value
168 if base != nil {
169 rBase = reflect.ValueOf(base).Elem()
170 }
171 rt := rv.Type()
172 for i := 0; i < rt.NumField(); i++ {
173 name := strings.ToLower(rt.Field(i).Name)
174 val := rv.Field(i).Bool()
175 baseVal := false
176 if base != nil {
177 baseVal = rBase.Field(i).Bool()
178 }
179 if all || val != baseVal {
180 if val {
181 list = append(list, name)
182 } else {
183 list = append(list, "no"+name)
184 }
185 }
186 }
187 return list
188 }
189
190
191
192 func (exp *ExperimentFlags) Enabled() []string {
193 return expList(&exp.Flags, nil, false)
194 }
195
196
197
198 func (exp *ExperimentFlags) All() []string {
199 return expList(&exp.Flags, nil, true)
200 }
201
View as plain text