1
0
mirror of https://github.com/golang/go synced 2024-11-11 20:50:23 -07:00

internal/goexperiment: consolidate experiment-enabled constants

Currently, we have boolean and integral constants for GOEXPERIMENTs in
various places. Consolidate these into automatically generated
constants in the internal/goexperiment package.

Change-Id: I42a49aba2a3b4c722fedea23a613162cd8a67bee
Reviewed-on: https://go-review.googlesource.com/c/go/+/307818
Trust: Austin Clements <austin@google.com>
Run-TryBot: Austin Clements <austin@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
This commit is contained in:
Austin Clements 2021-04-06 13:35:48 -04:00
parent 6304b401e4
commit b675e52e95
31 changed files with 267 additions and 82 deletions

View File

@ -71,7 +71,7 @@ var depsRules = `
# No dependencies allowed for any of these packages.
NONE
< container/list, container/ring,
internal/cfg, internal/cpu,
internal/cfg, internal/cpu, internal/goexperiment,
internal/goversion, internal/nettrace,
unicode/utf8, unicode/utf16, unicode,
unsafe;
@ -81,7 +81,7 @@ var depsRules = `
< internal/abi;
# RUNTIME is the core runtime group of packages, all of them very light-weight.
internal/abi, internal/cpu, unsafe
internal/abi, internal/cpu, internal/goexperiment, unsafe
< internal/bytealg
< internal/itoa
< internal/unsafeheader

View File

@ -0,0 +1,9 @@
// Code generated by mkconsts.go. DO NOT EDIT.
//go:build !goexperiment.fieldtrack
// +build !goexperiment.fieldtrack
package goexperiment
const FieldTrack = false
const FieldTrackInt = 0

View File

@ -0,0 +1,9 @@
// Code generated by mkconsts.go. DO NOT EDIT.
//go:build goexperiment.fieldtrack
// +build goexperiment.fieldtrack
package goexperiment
const FieldTrack = true
const FieldTrackInt = 1

View File

@ -0,0 +1,9 @@
// Code generated by mkconsts.go. DO NOT EDIT.
//go:build !goexperiment.preemptibleloops
// +build !goexperiment.preemptibleloops
package goexperiment
const PreemptibleLoops = false
const PreemptibleLoopsInt = 0

View File

@ -0,0 +1,9 @@
// Code generated by mkconsts.go. DO NOT EDIT.
//go:build goexperiment.preemptibleloops
// +build goexperiment.preemptibleloops
package goexperiment
const PreemptibleLoops = true
const PreemptibleLoopsInt = 1

View File

@ -0,0 +1,9 @@
// Code generated by mkconsts.go. DO NOT EDIT.
//go:build !goexperiment.regabi
// +build !goexperiment.regabi
package goexperiment
const Regabi = false
const RegabiInt = 0

View File

@ -0,0 +1,9 @@
// Code generated by mkconsts.go. DO NOT EDIT.
//go:build goexperiment.regabi
// +build goexperiment.regabi
package goexperiment
const Regabi = true
const RegabiInt = 1

View File

@ -0,0 +1,9 @@
// Code generated by mkconsts.go. DO NOT EDIT.
//go:build !goexperiment.regabiargs
// +build !goexperiment.regabiargs
package goexperiment
const RegabiArgs = false
const RegabiArgsInt = 0

View File

@ -0,0 +1,9 @@
// Code generated by mkconsts.go. DO NOT EDIT.
//go:build goexperiment.regabiargs
// +build goexperiment.regabiargs
package goexperiment
const RegabiArgs = true
const RegabiArgsInt = 1

View File

@ -0,0 +1,9 @@
// Code generated by mkconsts.go. DO NOT EDIT.
//go:build !goexperiment.regabidefer
// +build !goexperiment.regabidefer
package goexperiment
const RegabiDefer = false
const RegabiDeferInt = 0

View File

@ -0,0 +1,9 @@
// Code generated by mkconsts.go. DO NOT EDIT.
//go:build goexperiment.regabidefer
// +build goexperiment.regabidefer
package goexperiment
const RegabiDefer = true
const RegabiDeferInt = 1

View File

@ -0,0 +1,9 @@
// Code generated by mkconsts.go. DO NOT EDIT.
//go:build !goexperiment.regabig
// +build !goexperiment.regabig
package goexperiment
const RegabiG = false
const RegabiGInt = 0

View File

@ -0,0 +1,9 @@
// Code generated by mkconsts.go. DO NOT EDIT.
//go:build goexperiment.regabig
// +build goexperiment.regabig
package goexperiment
const RegabiG = true
const RegabiGInt = 1

View File

@ -0,0 +1,9 @@
// Code generated by mkconsts.go. DO NOT EDIT.
//go:build !goexperiment.regabireflect
// +build !goexperiment.regabireflect
package goexperiment
const RegabiReflect = false
const RegabiReflectInt = 0

View File

@ -0,0 +1,9 @@
// Code generated by mkconsts.go. DO NOT EDIT.
//go:build goexperiment.regabireflect
// +build goexperiment.regabireflect
package goexperiment
const RegabiReflect = true
const RegabiReflectInt = 1

View File

@ -0,0 +1,9 @@
// Code generated by mkconsts.go. DO NOT EDIT.
//go:build !goexperiment.regabiwrappers
// +build !goexperiment.regabiwrappers
package goexperiment
const RegabiWrappers = false
const RegabiWrappersInt = 0

View File

@ -0,0 +1,9 @@
// Code generated by mkconsts.go. DO NOT EDIT.
//go:build goexperiment.regabiwrappers
// +build goexperiment.regabiwrappers
package goexperiment
const RegabiWrappers = true
const RegabiWrappersInt = 1

View File

@ -0,0 +1,9 @@
// Code generated by mkconsts.go. DO NOT EDIT.
//go:build !goexperiment.staticlockranking
// +build !goexperiment.staticlockranking
package goexperiment
const StaticLockRanking = false
const StaticLockRankingInt = 0

View File

@ -0,0 +1,9 @@
// Code generated by mkconsts.go. DO NOT EDIT.
//go:build goexperiment.staticlockranking
// +build goexperiment.staticlockranking
package goexperiment
const StaticLockRanking = true
const StaticLockRankingInt = 1

View File

@ -17,11 +17,12 @@
// - Build tag goexperiment.x is set if experiment x (lower case) is
// enabled.
//
// - For each experiment x (in camel case), this package contains a
// boolean constant x and an integer constant xInt.
//
// - In runtime assembly, the macro GOEXPERIMENT_x is defined if
// experiment x (lower case) is enabled.
//
// - TODO(austin): More to come.
//
// In the toolchain, the set of experiments enabled for the current
// build should be accessed via objabi.Experiment.
//
@ -29,11 +30,15 @@
// go doc internal/experiment.Flags.
package goexperiment
//go:generate go run mkconsts.go
// Flags is the set of experiments that can be enabled or disabled in
// the current toolchain.
//
// When specified in the GOEXPERIMENT environment variable or as build
// tags, experiments use the strings.ToLower of their field name.
//
// If you change this struct definition, run "go generate".
type Flags struct {
FieldTrack bool
PreemptibleLoops bool

View File

@ -0,0 +1,74 @@
// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build ignore
// +build ignore
// mkconsts generates const definition files for each GOEXPERIMENT.
package main
import (
"bytes"
"fmt"
"internal/goexperiment"
"log"
"os"
"reflect"
"strings"
)
func main() {
// Delete existing experiment constant files.
ents, err := os.ReadDir(".")
if err != nil {
log.Fatal(err)
}
for _, ent := range ents {
name := ent.Name()
if !strings.HasPrefix(name, "exp_") {
continue
}
// Check that this is definitely a generated file.
data, err := os.ReadFile(name)
if err != nil {
log.Fatalf("reading %s: %v", name, err)
}
if !bytes.Contains(data, []byte("Code generated by mkconsts")) {
log.Fatalf("%s: expected generated file", name)
}
if err := os.Remove(name); err != nil {
log.Fatal(err)
}
}
// Generate new experiment constant files.
rt := reflect.TypeOf(&goexperiment.Flags{}).Elem()
for i := 0; i < rt.NumField(); i++ {
f := rt.Field(i).Name
buildTag := "goexperiment." + strings.ToLower(f)
for _, val := range []bool{false, true} {
name := fmt.Sprintf("exp_%s_%s.go", strings.ToLower(f), pick(val, "off", "on"))
data := fmt.Sprintf(`// Code generated by mkconsts.go. DO NOT EDIT.
//go:build %s%s
// +build %s%s
package goexperiment
const %s = %v
const %sInt = %s
`, pick(val, "!", ""), buildTag, pick(val, "!", ""), buildTag, f, val, f, pick(val, "0", "1"))
if err := os.WriteFile(name, []byte(data), 0666); err != nil {
log.Fatalf("writing %s: %v", name, err)
}
}
}
}
func pick(v bool, f, t string) string {
if v {
return t
}
return f
}

View File

@ -6,6 +6,7 @@ package reflect
import (
"internal/abi"
"internal/goexperiment"
"unsafe"
)
@ -28,9 +29,9 @@ import (
// commented out there should be the actual values once
// we're ready to use the register ABI everywhere.
var (
intArgRegs = abi.IntArgRegs * experimentRegabiArgs
floatArgRegs = abi.FloatArgRegs * experimentRegabiArgs
floatRegSize = uintptr(abi.EffectiveFloatRegSize * experimentRegabiArgs)
intArgRegs = abi.IntArgRegs * goexperiment.RegabiArgsInt
floatArgRegs = abi.FloatArgRegs * goexperiment.RegabiArgsInt
floatRegSize = uintptr(abi.EffectiveFloatRegSize * goexperiment.RegabiArgsInt)
)
// abiStep represents an ABI "instruction." Each instruction

View File

@ -1,10 +0,0 @@
// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build !goexperiment.regabiargs
// +build !goexperiment.regabiargs
package reflect
const experimentRegabiArgs = 0

View File

@ -1,10 +0,0 @@
// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build goexperiment.regabiargs
// +build goexperiment.regabiargs
package reflect
const experimentRegabiArgs = 1

View File

@ -6,6 +6,7 @@ package runtime
import (
"internal/abi"
"internal/goexperiment"
"runtime/internal/atomic"
"runtime/internal/sys"
"unsafe"
@ -228,7 +229,7 @@ func deferproc(siz int32, fn *funcval) { // arguments of fn follow fn
throw("defer on system stack")
}
if experimentRegabiDefer && siz != 0 {
if goexperiment.RegabiDefer && siz != 0 {
// TODO: Make deferproc just take a func().
throw("defer with non-empty frame")
}
@ -285,7 +286,7 @@ func deferprocStack(d *_defer) {
// go code on the system stack can't defer
throw("defer on system stack")
}
if experimentRegabiDefer && d.siz != 0 {
if goexperiment.RegabiDefer && d.siz != 0 {
throw("defer with non-empty frame")
}
// siz and fn are already set.
@ -387,8 +388,8 @@ func deferArgs(d *_defer) unsafe.Pointer {
// that experiment, we should change the type of d.fn.
//go:nosplit
func deferFunc(d *_defer) func() {
if !experimentRegabiDefer {
throw("requires experimentRegabiDefer")
if !goexperiment.RegabiDefer {
throw("requires GOEXPERIMENT=regabidefer")
}
var fn func()
*(**funcval)(unsafe.Pointer(&fn)) = d.fn
@ -648,7 +649,7 @@ func Goexit() {
addOneOpenDeferFrame(gp, 0, nil)
}
} else {
if experimentRegabiDefer {
if goexperiment.RegabiDefer {
// Save the pc/sp in deferCallSave(), so we can "recover" back to this
// loop if necessary.
deferCallSave(&p, deferFunc(d))
@ -850,7 +851,7 @@ func runOpenDeferFrame(gp *g, d *_defer) bool {
argWidth, fd = readvarintUnsafe(fd)
closureOffset, fd = readvarintUnsafe(fd)
nArgs, fd = readvarintUnsafe(fd)
if experimentRegabiDefer && argWidth != 0 {
if goexperiment.RegabiDefer && argWidth != 0 {
throw("defer with non-empty frame")
}
if deferBits&(1<<i) == 0 {
@ -878,7 +879,7 @@ func runOpenDeferFrame(gp *g, d *_defer) bool {
deferBits = deferBits &^ (1 << i)
*(*uint8)(unsafe.Pointer(d.varp - uintptr(deferBitsOffset))) = deferBits
p := d._panic
if experimentRegabiDefer {
if goexperiment.RegabiDefer {
deferCallSave(p, deferFunc(d))
} else {
reflectcallSave(p, unsafe.Pointer(closure), deferArgs, argWidth)
@ -906,8 +907,8 @@ func runOpenDeferFrame(gp *g, d *_defer) bool {
// This is marked as a wrapper by the compiler so it doesn't appear in
// tracebacks.
func reflectcallSave(p *_panic, fn, arg unsafe.Pointer, argsize uint32) {
if experimentRegabiDefer {
throw("not allowed with experimentRegabiDefer")
if goexperiment.RegabiDefer {
throw("not allowed with GOEXPERIMENT=regabidefer")
}
if p != nil {
p.argp = unsafe.Pointer(getargp(0))
@ -932,8 +933,8 @@ func reflectcallSave(p *_panic, fn, arg unsafe.Pointer, argsize uint32) {
// This is marked as a wrapper by the compiler so it doesn't appear in
// tracebacks.
func deferCallSave(p *_panic, fn func()) {
if !experimentRegabiDefer {
throw("only allowed with experimentRegabiDefer")
if !goexperiment.RegabiDefer {
throw("only allowed with GOEXPERIMENT=regabidefer")
}
if p != nil {
p.argp = unsafe.Pointer(getargp(0))
@ -1035,7 +1036,7 @@ func gopanic(e interface{}) {
} else {
p.argp = unsafe.Pointer(getargp(0))
if experimentRegabiDefer {
if goexperiment.RegabiDefer {
fn := deferFunc(d)
fn()
} else {

View File

@ -6,6 +6,7 @@ package runtime
import (
"internal/cpu"
"internal/goexperiment"
"runtime/internal/atomic"
"runtime/internal/sys"
"unsafe"
@ -4021,8 +4022,8 @@ func malg(stacksize int32) *g {
//
//go:nosplit
func newproc(siz int32, fn *funcval) {
if experimentRegabiDefer && siz != 0 {
// TODO: When we commit to experimentRegabiDefer,
if goexperiment.RegabiDefer && siz != 0 {
// TODO: When we commit to GOEXPERIMENT=regabidefer,
// rewrite newproc's comment, since it will no longer
// have a funny stack layout or need to be nosplit.
throw("go with non-empty frame")

View File

@ -1,10 +0,0 @@
// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build !goexperiment.regabiargs
// +build !goexperiment.regabiargs
package runtime
const experimentRegabiArgs = 0

View File

@ -1,10 +0,0 @@
// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build goexperiment.regabiargs
// +build goexperiment.regabiargs
package runtime
const experimentRegabiArgs = 1

View File

@ -1,10 +0,0 @@
// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build !goexperiment.regabidefer
// +build !goexperiment.regabidefer
package runtime
const experimentRegabiDefer = false

View File

@ -1,10 +0,0 @@
// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build goexperiment.regabidefer
// +build goexperiment.regabidefer
package runtime
const experimentRegabiDefer = true

View File

@ -6,6 +6,7 @@ package runtime
import (
"internal/abi"
"internal/goexperiment"
"unsafe"
)
@ -423,4 +424,4 @@ func sigpanic0()
// everywhere.
//
// Protected by finlock.
var intArgRegs = abi.IntArgRegs * experimentRegabiArgs
var intArgRegs = abi.IntArgRegs * goexperiment.RegabiArgsInt