]> Cypherpunks.ru repositories - gostls13.git/blob - src/cmd/internal/objabi/exp.go
3371c6c8f86751a307dbbb8f009e95e451ef4ce0
[gostls13.git] / src / cmd / internal / objabi / exp.go
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 objabi
6
7 import (
8         "fmt"
9         "os"
10         "reflect"
11         "strings"
12
13         "internal/goexperiment"
14 )
15
16 // Experiment contains the toolchain experiments enabled for the
17 // current build.
18 //
19 // (This is not necessarily the set of experiments the compiler itself
20 // was built with.)
21 var Experiment goexperiment.Flags = parseExperiments()
22
23 // experimentBaseline specifies the experiment flags that are enabled by
24 // default in the current toolchain. This is, in effect, the "control"
25 // configuration and any variation from this is an experiment.
26 var experimentBaseline goexperiment.Flags
27
28 // FramePointerEnabled enables the use of platform conventions for
29 // saving frame pointers.
30 //
31 // This used to be an experiment, but now it's always enabled on
32 // platforms that support it.
33 //
34 // Note: must agree with runtime.framepointer_enabled.
35 var FramePointerEnabled = GOARCH == "amd64" || GOARCH == "arm64"
36
37 func parseExperiments() goexperiment.Flags {
38         // Start with the statically enabled set of experiments.
39         flags := experimentBaseline
40
41         // Pick up any changes to the baseline configuration from the
42         // GOEXPERIMENT environment. This can be set at make.bash time
43         // and overridden at build time.
44         env := envOr("GOEXPERIMENT", defaultGOEXPERIMENT)
45
46         if env != "" {
47                 // Create a map of known experiment names.
48                 names := make(map[string]reflect.Value)
49                 rv := reflect.ValueOf(&flags).Elem()
50                 rt := rv.Type()
51                 for i := 0; i < rt.NumField(); i++ {
52                         field := rv.Field(i)
53                         names[strings.ToLower(rt.Field(i).Name)] = field
54                 }
55
56                 // Parse names.
57                 for _, f := range strings.Split(env, ",") {
58                         if f == "" {
59                                 continue
60                         }
61                         if f == "none" {
62                                 // GOEXPERIMENT=none disables all experiment flags.
63                                 // This is used by cmd/dist, which doesn't know how
64                                 // to build with any experiment flags.
65                                 flags = goexperiment.Flags{}
66                                 continue
67                         }
68                         val := true
69                         if strings.HasPrefix(f, "no") {
70                                 f, val = f[2:], false
71                         }
72                         field, ok := names[f]
73                         if !ok {
74                                 fmt.Printf("unknown experiment %s\n", f)
75                                 os.Exit(2)
76                         }
77                         field.SetBool(val)
78                 }
79         }
80
81         // regabi is only supported on amd64.
82         if GOARCH != "amd64" {
83                 flags.Regabi = false
84                 flags.RegabiWrappers = false
85                 flags.RegabiG = false
86                 flags.RegabiReflect = false
87                 flags.RegabiDefer = false
88                 flags.RegabiArgs = false
89         }
90         // Setting regabi sets working sub-experiments.
91         if flags.Regabi {
92                 flags.RegabiWrappers = true
93                 flags.RegabiG = true
94                 flags.RegabiReflect = true
95                 flags.RegabiDefer = true
96                 // Not ready yet:
97                 //flags.RegabiArgs = true
98         }
99         // Check regabi dependencies.
100         if flags.RegabiG && !flags.RegabiWrappers {
101                 panic("GOEXPERIMENT regabig requires regabiwrappers")
102         }
103         if flags.RegabiArgs && !(flags.RegabiWrappers && flags.RegabiG && flags.RegabiReflect && flags.RegabiDefer) {
104                 panic("GOEXPERIMENT regabiargs requires regabiwrappers,regabig,regabireflect,regabidefer")
105         }
106         return flags
107 }
108
109 // expList returns the list of lower-cased experiment names for
110 // experiments that differ from base. base may be nil to indicate no
111 // experiments. If all is true, then include all experiment flags,
112 // regardless of base.
113 func expList(exp, base *goexperiment.Flags, all bool) []string {
114         var list []string
115         rv := reflect.ValueOf(exp).Elem()
116         var rBase reflect.Value
117         if base != nil {
118                 rBase = reflect.ValueOf(base).Elem()
119         }
120         rt := rv.Type()
121         for i := 0; i < rt.NumField(); i++ {
122                 name := strings.ToLower(rt.Field(i).Name)
123                 val := rv.Field(i).Bool()
124                 baseVal := false
125                 if base != nil {
126                         baseVal = rBase.Field(i).Bool()
127                 }
128                 if all || val != baseVal {
129                         if val {
130                                 list = append(list, name)
131                         } else {
132                                 list = append(list, "no"+name)
133                         }
134                 }
135         }
136         return list
137 }
138
139 // GOEXPERIMENT is a comma-separated list of enabled or disabled
140 // experiments that differ from the baseline experiment configuration.
141 // GOEXPERIMENT is exactly what a user would set on the command line
142 // to get the set of enabled experiments.
143 func GOEXPERIMENT() string {
144         return strings.Join(expList(&Experiment, &experimentBaseline, false), ",")
145 }
146
147 // EnabledExperiments returns a list of enabled experiments, as
148 // lower-cased experiment names.
149 func EnabledExperiments() []string {
150         return expList(&Experiment, nil, false)
151 }