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