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