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 baseline := goexperiment.Flags{
71 RegabiWrappers: regabiSupported,
72 RegabiArgs: regabiSupported,
73 CoverageRedesign: true,
74 AliasTypeParams: true,
75 SwissMap: true,
76 }
77
78
79 flags := &ExperimentFlags{
80 Flags: baseline,
81 baseline: baseline,
82 }
83
84
85
86
87 if goexp != "" {
88
89 names := make(map[string]func(bool))
90 rv := reflect.ValueOf(&flags.Flags).Elem()
91 rt := rv.Type()
92 for i := 0; i < rt.NumField(); i++ {
93 field := rv.Field(i)
94 names[strings.ToLower(rt.Field(i).Name)] = field.SetBool
95 }
96
97
98
99
100
101 names["regabi"] = func(v bool) {
102 flags.RegabiWrappers = v
103 flags.RegabiArgs = v
104 }
105
106
107 for _, f := range strings.Split(goexp, ",") {
108 if f == "" {
109 continue
110 }
111 if f == "none" {
112
113
114
115 flags.Flags = goexperiment.Flags{}
116 continue
117 }
118 val := true
119 if strings.HasPrefix(f, "no") {
120 f, val = f[2:], false
121 }
122 set, ok := names[f]
123 if !ok {
124 return nil, fmt.Errorf("unknown GOEXPERIMENT %s", f)
125 }
126 set(val)
127 }
128 }
129
130 if regabiAlwaysOn {
131 flags.RegabiWrappers = true
132 flags.RegabiArgs = true
133 }
134
135 if !regabiSupported {
136 flags.RegabiWrappers = false
137 flags.RegabiArgs = false
138 }
139
140 if flags.RegabiArgs && !flags.RegabiWrappers {
141 return nil, fmt.Errorf("GOEXPERIMENT regabiargs requires regabiwrappers")
142 }
143 return flags, nil
144 }
145
146
147
148 func (exp *ExperimentFlags) String() string {
149 return strings.Join(expList(&exp.Flags, &exp.baseline, false), ",")
150 }
151
152
153
154
155
156 func expList(exp, base *goexperiment.Flags, all bool) []string {
157 var list []string
158 rv := reflect.ValueOf(exp).Elem()
159 var rBase reflect.Value
160 if base != nil {
161 rBase = reflect.ValueOf(base).Elem()
162 }
163 rt := rv.Type()
164 for i := 0; i < rt.NumField(); i++ {
165 name := strings.ToLower(rt.Field(i).Name)
166 val := rv.Field(i).Bool()
167 baseVal := false
168 if base != nil {
169 baseVal = rBase.Field(i).Bool()
170 }
171 if all || val != baseVal {
172 if val {
173 list = append(list, name)
174 } else {
175 list = append(list, "no"+name)
176 }
177 }
178 }
179 return list
180 }
181
182
183
184 func (exp *ExperimentFlags) Enabled() []string {
185 return expList(&exp.Flags, nil, false)
186 }
187
188
189
190 func (exp *ExperimentFlags) All() []string {
191 return expList(&exp.Flags, nil, true)
192 }
193
View as plain text