diff options
author | Ian Lance Taylor <iant@golang.org> | 2021-07-30 14:28:58 -0700 |
---|---|---|
committer | Ian Lance Taylor <iant@golang.org> | 2021-08-12 20:23:07 -0700 |
commit | c5b21c3f4c17b0649155035d2f9aa97b2da8a813 (patch) | |
tree | c6d3a68b503ba5b16182acbb958e3e5dbc95a43b /libgo/go/internal | |
parent | 72be20e20299ec57b4bc9ba03d5b7d6bf10e97cc (diff) | |
download | gcc-c5b21c3f4c17b0649155035d2f9aa97b2da8a813.zip gcc-c5b21c3f4c17b0649155035d2f9aa97b2da8a813.tar.gz gcc-c5b21c3f4c17b0649155035d2f9aa97b2da8a813.tar.bz2 |
libgo: update to Go1.17rc2
Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/341629
Diffstat (limited to 'libgo/go/internal')
113 files changed, 1224 insertions, 186 deletions
diff --git a/libgo/go/internal/buildcfg/cfg.go b/libgo/go/internal/buildcfg/cfg.go new file mode 100644 index 0000000..4bf418e --- /dev/null +++ b/libgo/go/internal/buildcfg/cfg.go @@ -0,0 +1,136 @@ +// 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. + +// Package buildcfg provides access to the build configuration +// described by the current environment. It is for use by build tools +// such as cmd/go or cmd/compile and for setting up go/build's Default context. +// +// Note that it does NOT provide access to the build configuration used to +// build the currently-running binary. For that, use runtime.GOOS etc +// as well as internal/goexperiment. +package buildcfg + +import ( + "fmt" + "os" + "path/filepath" + "strings" +) + +var ( + defaultGOROOT = defaultGOROOTValue() + + GOROOT = envOr("GOROOT", defaultGOROOT) + GOARCH = envOr("GOARCH", defaultGOARCH) + GOOS = envOr("GOOS", defaultGOOS) + GO386 = envOr("GO386", defaultGO386) + GOARM = goarm() + GOMIPS = gomips() + GOMIPS64 = gomips64() + GOPPC64 = goppc64() + GOWASM = gowasm() + GO_LDSO = defaultGO_LDSO + Version = version +) + +// Error is one of the errors found (if any) in the build configuration. +var Error error + +// Check exits the program with a fatal error if Error is non-nil. +func Check() { + if Error != nil { + fmt.Fprintf(os.Stderr, "%s: %v\n", filepath.Base(os.Args[0]), Error) + os.Exit(2) + } +} + +func envOr(key, value string) string { + if x := os.Getenv(key); x != "" { + return x + } + return value +} + +func goarm() int { + def := defaultGOARM + if GOOS == "android" && GOARCH == "arm" { + // Android arm devices always support GOARM=7. + def = "7" + } + switch v := envOr("GOARM", def); v { + case "5": + return 5 + case "6": + return 6 + case "7": + return 7 + } + Error = fmt.Errorf("invalid GOARM: must be 5, 6, 7") + return int(def[0] - '0') +} + +func gomips() string { + switch v := envOr("GOMIPS", defaultGOMIPS); v { + case "hardfloat", "softfloat": + return v + } + Error = fmt.Errorf("invalid GOMIPS: must be hardfloat, softfloat") + return defaultGOMIPS +} + +func gomips64() string { + switch v := envOr("GOMIPS64", defaultGOMIPS64); v { + case "hardfloat", "softfloat": + return v + } + Error = fmt.Errorf("invalid GOMIPS64: must be hardfloat, softfloat") + return defaultGOMIPS64 +} + +func goppc64() int { + switch v := envOr("GOPPC64", defaultGOPPC64); v { + case "power8": + return 8 + case "power9": + return 9 + } + Error = fmt.Errorf("invalid GOPPC64: must be power8, power9") + return int(defaultGOPPC64[len("power")] - '0') +} + +type gowasmFeatures struct { + SignExt bool + SatConv bool +} + +func (f gowasmFeatures) String() string { + var flags []string + if f.SatConv { + flags = append(flags, "satconv") + } + if f.SignExt { + flags = append(flags, "signext") + } + return strings.Join(flags, ",") +} + +func gowasm() (f gowasmFeatures) { + for _, opt := range strings.Split(envOr("GOWASM", ""), ",") { + switch opt { + case "satconv": + f.SatConv = true + case "signext": + f.SignExt = true + case "": + // ignore + default: + Error = fmt.Errorf("invalid GOWASM: no such feature %q", opt) + } + } + return +} + +func Getgoextlinkenabled() string { + return envOr("GO_EXTLINK_ENABLED", defaultGO_EXTLINK_ENABLED) +} diff --git a/libgo/go/internal/buildcfg/exp.go b/libgo/go/internal/buildcfg/exp.go new file mode 100644 index 0000000..736c080 --- /dev/null +++ b/libgo/go/internal/buildcfg/exp.go @@ -0,0 +1,189 @@ +// 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. + +package buildcfg + +import ( + "fmt" + "reflect" + "strings" + + "internal/goexperiment" +) + +// Experiment contains the toolchain experiments enabled for the +// current build. +// +// (This is not necessarily the set of experiments the compiler itself +// was built with.) +// +// experimentBaseline specifies the experiment flags that are enabled by +// default in the current toolchain. This is, in effect, the "control" +// configuration and any variation from this is an experiment. +var Experiment, experimentBaseline = func() (goexperiment.Flags, goexperiment.Flags) { + flags, baseline, err := ParseGOEXPERIMENT(GOOS, GOARCH, envOr("GOEXPERIMENT", defaultGOEXPERIMENT)) + if err != nil { + Error = err + } + return flags, baseline +}() + +const DefaultGOEXPERIMENT = defaultGOEXPERIMENT + +// FramePointerEnabled enables the use of platform conventions for +// saving frame pointers. +// +// This used to be an experiment, but now it's always enabled on +// platforms that support it. +// +// Note: must agree with runtime.framepointer_enabled. +var FramePointerEnabled = GOARCH == "amd64" || GOARCH == "arm64" + +// ParseGOEXPERIMENT parses a (GOOS, GOARCH, GOEXPERIMENT) +// configuration tuple and returns the enabled and baseline experiment +// flag sets. +// +// TODO(mdempsky): Move to internal/goexperiment. +func ParseGOEXPERIMENT(goos, goarch, goexp string) (flags, baseline goexperiment.Flags, err error) { + regabiSupported := false + + baseline = goexperiment.Flags{ + RegabiWrappers: regabiSupported, + RegabiG: regabiSupported, + RegabiReflect: regabiSupported, + RegabiDefer: regabiSupported, + RegabiArgs: regabiSupported, + } + + // Start with the statically enabled set of experiments. + flags = baseline + + // Pick up any changes to the baseline configuration from the + // GOEXPERIMENT environment. This can be set at make.bash time + // and overridden at build time. + if goexp != "" { + // Create a map of known experiment names. + names := make(map[string]func(bool)) + rv := reflect.ValueOf(&flags).Elem() + rt := rv.Type() + for i := 0; i < rt.NumField(); i++ { + field := rv.Field(i) + names[strings.ToLower(rt.Field(i).Name)] = field.SetBool + } + + // "regabi" is an alias for all working regabi + // subexperiments, and not an experiment itself. Doing + // this as an alias make both "regabi" and "noregabi" + // do the right thing. + names["regabi"] = func(v bool) { + flags.RegabiWrappers = v + flags.RegabiG = v + flags.RegabiReflect = v + flags.RegabiDefer = v + flags.RegabiArgs = v + } + + // Parse names. + for _, f := range strings.Split(goexp, ",") { + if f == "" { + continue + } + if f == "none" { + // GOEXPERIMENT=none disables all experiment flags. + // This is used by cmd/dist, which doesn't know how + // to build with any experiment flags. + flags = goexperiment.Flags{} + continue + } + val := true + if strings.HasPrefix(f, "no") { + f, val = f[2:], false + } + set, ok := names[f] + if !ok { + err = fmt.Errorf("unknown GOEXPERIMENT %s", f) + return + } + set(val) + } + } + + // regabi is only supported on amd64. + if goarch != "amd64" { + flags.RegabiWrappers = false + flags.RegabiG = false + flags.RegabiReflect = false + flags.RegabiDefer = false + flags.RegabiArgs = false + } + // Check regabi dependencies. + if flags.RegabiG && !flags.RegabiWrappers { + err = fmt.Errorf("GOEXPERIMENT regabig requires regabiwrappers") + } + if flags.RegabiArgs && !(flags.RegabiWrappers && flags.RegabiG && flags.RegabiReflect && flags.RegabiDefer) { + err = fmt.Errorf("GOEXPERIMENT regabiargs requires regabiwrappers,regabig,regabireflect,regabidefer") + } + return +} + +// expList returns the list of lower-cased experiment names for +// experiments that differ from base. base may be nil to indicate no +// experiments. If all is true, then include all experiment flags, +// regardless of base. +func expList(exp, base *goexperiment.Flags, all bool) []string { + var list []string + rv := reflect.ValueOf(exp).Elem() + var rBase reflect.Value + if base != nil { + rBase = reflect.ValueOf(base).Elem() + } + rt := rv.Type() + for i := 0; i < rt.NumField(); i++ { + name := strings.ToLower(rt.Field(i).Name) + val := rv.Field(i).Bool() + baseVal := false + if base != nil { + baseVal = rBase.Field(i).Bool() + } + if all || val != baseVal { + if val { + list = append(list, name) + } else { + list = append(list, "no"+name) + } + } + } + return list +} + +// GOEXPERIMENT is a comma-separated list of enabled or disabled +// experiments that differ from the baseline experiment configuration. +// GOEXPERIMENT is exactly what a user would set on the command line +// to get the set of enabled experiments. +func GOEXPERIMENT() string { + return strings.Join(expList(&Experiment, &experimentBaseline, false), ",") +} + +// EnabledExperiments returns a list of enabled experiments, as +// lower-cased experiment names. +func EnabledExperiments() []string { + return expList(&Experiment, nil, false) +} + +// AllExperiments returns a list of all experiment settings. +// Disabled experiments appear in the list prefixed by "no". +func AllExperiments() []string { + return expList(&Experiment, nil, true) +} + +// UpdateExperiments updates the Experiment global based on a new GOARCH value. +// This is only required for cmd/go, which can change GOARCH after +// program startup due to use of "go env -w". +func UpdateExperiments(goos, goarch, goexperiment string) { + var err error + Experiment, experimentBaseline, err = ParseGOEXPERIMENT(goos, goarch, goexperiment) + if err != nil { + Error = err + } +} diff --git a/libgo/go/internal/bytealg/bytealg.go b/libgo/go/internal/bytealg/bytealg.go index 58efb95..68de560 100644 --- a/libgo/go/internal/bytealg/bytealg.go +++ b/libgo/go/internal/bytealg/bytealg.go @@ -17,6 +17,8 @@ const ( offsetX86HasPOPCNT = unsafe.Offsetof(cpu.X86.HasPOPCNT) offsetS390xHasVX = unsafe.Offsetof(cpu.S390X.HasVX) + + offsetPPC64HasPOWER9 = unsafe.Offsetof(cpu.PPC64.IsPOWER9) ) // MaxLen is the maximum length of the string to be searched for (argument b) in Index. diff --git a/libgo/go/internal/bytealg/compare_generic.go b/libgo/go/internal/bytealg/compare_generic.go index a29e8e7..45e6a02 100644 --- a/libgo/go/internal/bytealg/compare_generic.go +++ b/libgo/go/internal/bytealg/compare_generic.go @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build ignore_for_gccgo -// +build !386,!amd64,!s390x,!arm,!arm64,!ppc64,!ppc64le,!mips,!mipsle,!wasm,!mips64,!mips64le +//go:build ignore +// +build ignore package bytealg diff --git a/libgo/go/internal/bytealg/compare_native.go b/libgo/go/internal/bytealg/compare_native.go index b189998..629e858 100644 --- a/libgo/go/internal/bytealg/compare_native.go +++ b/libgo/go/internal/bytealg/compare_native.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//-go:build 386 || amd64 || s390x || arm || arm64 || ppc64 || ppc64le || mips || mipsle || wasm || mips64 || mips64le // -build 386 amd64 s390x arm arm64 ppc64 ppc64le mips mipsle wasm mips64 mips64le package bytealg diff --git a/libgo/go/internal/bytealg/count_generic.go b/libgo/go/internal/bytealg/count_generic.go index 7e4510c..d0e1c3b 100644 --- a/libgo/go/internal/bytealg/count_generic.go +++ b/libgo/go/internal/bytealg/count_generic.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//-go:build !amd64 && !arm && !arm64 && !ppc64le && !ppc64 && !riscv64 && !s390x // -build !amd64,!arm,!arm64,!ppc64le,!ppc64,!riscv64,!s390x package bytealg diff --git a/libgo/go/internal/bytealg/count_native.go b/libgo/go/internal/bytealg/count_native.go index a0151a0..efb782f 100644 --- a/libgo/go/internal/bytealg/count_native.go +++ b/libgo/go/internal/bytealg/count_native.go @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build ignore_for_gccgo -// +build amd64 arm arm64 ppc64le ppc64 riscv64 s390x +//go:build ignore +// +build ignore package bytealg diff --git a/libgo/go/internal/bytealg/index_amd64.go b/libgo/go/internal/bytealg/index_amd64.go index dd6a6cf..7208118 100644 --- a/libgo/go/internal/bytealg/index_amd64.go +++ b/libgo/go/internal/bytealg/index_amd64.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ignore_for_gccgo // +build ignore_for_gccgo package bytealg diff --git a/libgo/go/internal/bytealg/index_generic.go b/libgo/go/internal/bytealg/index_generic.go index c595c23..a880eb3 100644 --- a/libgo/go/internal/bytealg/index_generic.go +++ b/libgo/go/internal/bytealg/index_generic.go @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build ignore_for_gccgo -// +build !amd64,!arm64,!s390x +//go:build ignore +// +build ignore package bytealg diff --git a/libgo/go/internal/bytealg/index_native.go b/libgo/go/internal/bytealg/index_native.go index 26f4769..7086940 100644 --- a/libgo/go/internal/bytealg/index_native.go +++ b/libgo/go/internal/bytealg/index_native.go @@ -2,7 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// -build amd64 arm64 s390x +//-go:build amd64 || arm64 || s390x || ppc64le || ppc64 +// -build amd64 arm64 s390x ppc64le ppc64 package bytealg diff --git a/libgo/go/internal/bytealg/index_ppc64x.go b/libgo/go/internal/bytealg/index_ppc64x.go new file mode 100644 index 0000000..f8f8f50 --- /dev/null +++ b/libgo/go/internal/bytealg/index_ppc64x.go @@ -0,0 +1,27 @@ +// 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_for_gccgo +// +build ignore_for_gccgo + +package bytealg + +import "internal/cpu" + +const MaxBruteForce = 16 + +var SupportsPower9 = cpu.PPC64.IsPOWER9 + +func init() { + MaxLen = 32 +} + +// Cutover reports the number of failures of IndexByte we should tolerate +// before switching over to Index. +// n is the number of bytes processed so far. +// See the bytes.Index implementation for details. +func Cutover(n int) int { + // 1 error per 8 characters, plus a few slop to start. + return (n + 16) / 8 +} diff --git a/libgo/go/internal/bytealg/indexbyte_generic.go b/libgo/go/internal/bytealg/indexbyte_generic.go index 46325dd..09a6615 100644 --- a/libgo/go/internal/bytealg/indexbyte_generic.go +++ b/libgo/go/internal/bytealg/indexbyte_generic.go @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build ignore_for_gccgo -// +build !386,!amd64,!s390x,!arm,!arm64,!ppc64,!ppc64le,!mips,!mipsle,!mips64,!mips64le,!riscv,!riscv64,!wasm +//go:build ignore +// +build ignore package bytealg diff --git a/libgo/go/internal/bytealg/indexbyte_native.go b/libgo/go/internal/bytealg/indexbyte_native.go index c427e66..2cc118c 100644 --- a/libgo/go/internal/bytealg/indexbyte_native.go +++ b/libgo/go/internal/bytealg/indexbyte_native.go @@ -2,7 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// -build 386 amd64 s390x arm arm64 ppc64 ppc64le mips mipsle mips64 mips64le riscv riscv64 wasm +//-go:build 386 || amd64 || s390x || arm || arm64 || ppc64 || ppc64le || mips || mipsle || mips64 || mips64le || riscv64 || wasm +// -build 386 amd64 s390x arm arm64 ppc64 ppc64le mips mipsle mips64 mips64le riscv64 wasm package bytealg diff --git a/libgo/go/internal/cfg/cfg.go b/libgo/go/internal/cfg/cfg.go index 5530213..815994b 100644 --- a/libgo/go/internal/cfg/cfg.go +++ b/libgo/go/internal/cfg/cfg.go @@ -39,6 +39,7 @@ const KnownEnv = ` GOCACHE GOENV GOEXE + GOEXPERIMENT GOFLAGS GOGCCFLAGS GOHOSTARCH diff --git a/libgo/go/internal/cpu/cpu_arm64_android.go b/libgo/go/internal/cpu/cpu_arm64_android.go index 3c9e57c..ac6eee5 100644 --- a/libgo/go/internal/cpu/cpu_arm64_android.go +++ b/libgo/go/internal/cpu/cpu_arm64_android.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build arm64 // +build arm64 package cpu diff --git a/libgo/go/internal/cpu/cpu_arm64_darwin.go b/libgo/go/internal/cpu/cpu_arm64_darwin.go index e094b97..ce1b250 100644 --- a/libgo/go/internal/cpu/cpu_arm64_darwin.go +++ b/libgo/go/internal/cpu/cpu_arm64_darwin.go @@ -2,9 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build arm64 -// +build darwin -// +build !ios +//go:build arm64 && darwin && !ios +// +build arm64,darwin,!ios package cpu diff --git a/libgo/go/internal/cpu/cpu_arm64_freebsd.go b/libgo/go/internal/cpu/cpu_arm64_freebsd.go index 9de2005..8c48137 100644 --- a/libgo/go/internal/cpu/cpu_arm64_freebsd.go +++ b/libgo/go/internal/cpu/cpu_arm64_freebsd.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build arm64 // +build arm64 package cpu diff --git a/libgo/go/internal/cpu/cpu_arm64_hwcap.go b/libgo/go/internal/cpu/cpu_arm64_hwcap.go index fdaf43e..8ac04fd 100644 --- a/libgo/go/internal/cpu/cpu_arm64_hwcap.go +++ b/libgo/go/internal/cpu/cpu_arm64_hwcap.go @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build arm64 -// +build linux +//go:build arm64 && linux +// +build arm64,linux package cpu diff --git a/libgo/go/internal/cpu/cpu_arm64_linux.go b/libgo/go/internal/cpu/cpu_arm64_linux.go index 2f7411f..c3a3f9a 100644 --- a/libgo/go/internal/cpu/cpu_arm64_linux.go +++ b/libgo/go/internal/cpu/cpu_arm64_linux.go @@ -2,9 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build arm64 -// +build linux -// +build !android +//go:build arm64 && linux && !android +// +build arm64,linux,!android package cpu diff --git a/libgo/go/internal/cpu/cpu_arm64_other.go b/libgo/go/internal/cpu/cpu_arm64_other.go index f191db2..e8b5d529 100644 --- a/libgo/go/internal/cpu/cpu_arm64_other.go +++ b/libgo/go/internal/cpu/cpu_arm64_other.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build arm64 && !linux && !freebsd && !android && (!darwin || ios) // +build arm64 // +build !linux // +build !freebsd diff --git a/libgo/go/internal/cpu/cpu_mips64x.go b/libgo/go/internal/cpu/cpu_mips64x.go index 58fbd3d..c660403 100644 --- a/libgo/go/internal/cpu/cpu_mips64x.go +++ b/libgo/go/internal/cpu/cpu_mips64x.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build mips64 || mips64le // +build mips64 mips64le package cpu diff --git a/libgo/go/internal/cpu/cpu_no_name.go b/libgo/go/internal/cpu/cpu_no_name.go index f028a92..8e636d5 100644 --- a/libgo/go/internal/cpu/cpu_no_name.go +++ b/libgo/go/internal/cpu/cpu_no_name.go @@ -2,9 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build !386 -// +build !amd64 -// +build !amd64p32 +//go:build !386 && !amd64 && !amd64p32 +// +build !386,!amd64,!amd64p32 package cpu diff --git a/libgo/go/internal/cpu/cpu_ppc64x.go b/libgo/go/internal/cpu/cpu_ppc64x.go index 0a48f6a..1c7c39f 100644 --- a/libgo/go/internal/cpu/cpu_ppc64x.go +++ b/libgo/go/internal/cpu/cpu_ppc64x.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ppc || ppc64 || ppc64le // +build ppc ppc64 ppc64le package cpu diff --git a/libgo/go/internal/cpu/cpu_ppc64x_aix.go b/libgo/go/internal/cpu/cpu_ppc64x_aix.go index e2422a6..c7e47b2 100644 --- a/libgo/go/internal/cpu/cpu_ppc64x_aix.go +++ b/libgo/go/internal/cpu/cpu_ppc64x_aix.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ppc || ppc64 || ppc64le // +build ppc ppc64 ppc64le package cpu diff --git a/libgo/go/internal/cpu/cpu_ppc64x_linux.go b/libgo/go/internal/cpu/cpu_ppc64x_linux.go index 068a799..0c89f3b 100644 --- a/libgo/go/internal/cpu/cpu_ppc64x_linux.go +++ b/libgo/go/internal/cpu/cpu_ppc64x_linux.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ppc || ppc64 || ppc64le // +build ppc ppc64 ppc64le package cpu diff --git a/libgo/go/internal/cpu/cpu_x86.go b/libgo/go/internal/cpu/cpu_x86.go index 338d909..6182532 100644 --- a/libgo/go/internal/cpu/cpu_x86.go +++ b/libgo/go/internal/cpu/cpu_x86.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build 386 || amd64 || amd64p32 // +build 386 amd64 amd64p32 package cpu diff --git a/libgo/go/internal/cpu/cpu_x86_test.go b/libgo/go/internal/cpu/cpu_x86_test.go index 61db93b..e3e16cc 100644 --- a/libgo/go/internal/cpu/cpu_x86_test.go +++ b/libgo/go/internal/cpu/cpu_x86_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build 386 || amd64 // +build 386 amd64 package cpu_test diff --git a/libgo/go/internal/execabs/execabs_test.go b/libgo/go/internal/execabs/execabs_test.go index b714585..97a3f39 100644 --- a/libgo/go/internal/execabs/execabs_test.go +++ b/libgo/go/internal/execabs/execabs_test.go @@ -8,7 +8,6 @@ import ( "context" "fmt" "internal/testenv" - "io/ioutil" "os" "os/exec" "path/filepath" @@ -42,8 +41,8 @@ func TestCommand(t *testing.T) { if runtime.GOOS == "windows" { executable += ".exe" } - if err := ioutil.WriteFile(filepath.Join(tmpDir, executable), []byte{1, 2, 3}, 0111); err != nil { - t.Fatalf("ioutil.WriteFile failed: %s", err) + if err := os.WriteFile(filepath.Join(tmpDir, executable), []byte{1, 2, 3}, 0111); err != nil { + t.Fatalf("os.WriteFile failed: %s", err) } cwd, err := os.Getwd() if err != nil { @@ -77,8 +76,8 @@ func TestLookPath(t *testing.T) { if runtime.GOOS == "windows" { executable += ".exe" } - if err := ioutil.WriteFile(filepath.Join(tmpDir, executable), []byte{1, 2, 3}, 0111); err != nil { - t.Fatalf("ioutil.WriteFile failed: %s", err) + if err := os.WriteFile(filepath.Join(tmpDir, executable), []byte{1, 2, 3}, 0111); err != nil { + t.Fatalf("os.WriteFile failed: %s", err) } cwd, err := os.Getwd() if err != nil { diff --git a/libgo/go/internal/goexperiment/exp_fieldtrack_off.go b/libgo/go/internal/goexperiment/exp_fieldtrack_off.go new file mode 100644 index 0000000..e5e1326 --- /dev/null +++ b/libgo/go/internal/goexperiment/exp_fieldtrack_off.go @@ -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 diff --git a/libgo/go/internal/goexperiment/exp_fieldtrack_on.go b/libgo/go/internal/goexperiment/exp_fieldtrack_on.go new file mode 100644 index 0000000..0d8c447 --- /dev/null +++ b/libgo/go/internal/goexperiment/exp_fieldtrack_on.go @@ -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 diff --git a/libgo/go/internal/goexperiment/exp_preemptibleloops_off.go b/libgo/go/internal/goexperiment/exp_preemptibleloops_off.go new file mode 100644 index 0000000..7a26088 --- /dev/null +++ b/libgo/go/internal/goexperiment/exp_preemptibleloops_off.go @@ -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 diff --git a/libgo/go/internal/goexperiment/exp_preemptibleloops_on.go b/libgo/go/internal/goexperiment/exp_preemptibleloops_on.go new file mode 100644 index 0000000..a9ca28c --- /dev/null +++ b/libgo/go/internal/goexperiment/exp_preemptibleloops_on.go @@ -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 diff --git a/libgo/go/internal/goexperiment/exp_regabi_off.go b/libgo/go/internal/goexperiment/exp_regabi_off.go new file mode 100644 index 0000000..5d88238 --- /dev/null +++ b/libgo/go/internal/goexperiment/exp_regabi_off.go @@ -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 diff --git a/libgo/go/internal/goexperiment/exp_regabi_on.go b/libgo/go/internal/goexperiment/exp_regabi_on.go new file mode 100644 index 0000000..c08d58e --- /dev/null +++ b/libgo/go/internal/goexperiment/exp_regabi_on.go @@ -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 diff --git a/libgo/go/internal/goexperiment/exp_regabiargs_off.go b/libgo/go/internal/goexperiment/exp_regabiargs_off.go new file mode 100644 index 0000000..31a139b --- /dev/null +++ b/libgo/go/internal/goexperiment/exp_regabiargs_off.go @@ -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 diff --git a/libgo/go/internal/goexperiment/exp_regabiargs_on.go b/libgo/go/internal/goexperiment/exp_regabiargs_on.go new file mode 100644 index 0000000..9b26f3c --- /dev/null +++ b/libgo/go/internal/goexperiment/exp_regabiargs_on.go @@ -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 diff --git a/libgo/go/internal/goexperiment/exp_regabidefer_off.go b/libgo/go/internal/goexperiment/exp_regabidefer_off.go new file mode 100644 index 0000000..b47c0c2 --- /dev/null +++ b/libgo/go/internal/goexperiment/exp_regabidefer_off.go @@ -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 diff --git a/libgo/go/internal/goexperiment/exp_regabidefer_on.go b/libgo/go/internal/goexperiment/exp_regabidefer_on.go new file mode 100644 index 0000000..bbf2f6c --- /dev/null +++ b/libgo/go/internal/goexperiment/exp_regabidefer_on.go @@ -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 diff --git a/libgo/go/internal/goexperiment/exp_regabig_off.go b/libgo/go/internal/goexperiment/exp_regabig_off.go new file mode 100644 index 0000000..1b37d45 --- /dev/null +++ b/libgo/go/internal/goexperiment/exp_regabig_off.go @@ -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 diff --git a/libgo/go/internal/goexperiment/exp_regabig_on.go b/libgo/go/internal/goexperiment/exp_regabig_on.go new file mode 100644 index 0000000..7e5b162 --- /dev/null +++ b/libgo/go/internal/goexperiment/exp_regabig_on.go @@ -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 diff --git a/libgo/go/internal/goexperiment/exp_regabireflect_off.go b/libgo/go/internal/goexperiment/exp_regabireflect_off.go new file mode 100644 index 0000000..515f4a5 --- /dev/null +++ b/libgo/go/internal/goexperiment/exp_regabireflect_off.go @@ -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 diff --git a/libgo/go/internal/goexperiment/exp_regabireflect_on.go b/libgo/go/internal/goexperiment/exp_regabireflect_on.go new file mode 100644 index 0000000..e8a3e9c --- /dev/null +++ b/libgo/go/internal/goexperiment/exp_regabireflect_on.go @@ -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 diff --git a/libgo/go/internal/goexperiment/exp_regabiwrappers_off.go b/libgo/go/internal/goexperiment/exp_regabiwrappers_off.go new file mode 100644 index 0000000..bfa0fa3 --- /dev/null +++ b/libgo/go/internal/goexperiment/exp_regabiwrappers_off.go @@ -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 diff --git a/libgo/go/internal/goexperiment/exp_regabiwrappers_on.go b/libgo/go/internal/goexperiment/exp_regabiwrappers_on.go new file mode 100644 index 0000000..11ffffb --- /dev/null +++ b/libgo/go/internal/goexperiment/exp_regabiwrappers_on.go @@ -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 diff --git a/libgo/go/internal/goexperiment/exp_staticlockranking_off.go b/libgo/go/internal/goexperiment/exp_staticlockranking_off.go new file mode 100644 index 0000000..3d546c0 --- /dev/null +++ b/libgo/go/internal/goexperiment/exp_staticlockranking_off.go @@ -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 diff --git a/libgo/go/internal/goexperiment/exp_staticlockranking_on.go b/libgo/go/internal/goexperiment/exp_staticlockranking_on.go new file mode 100644 index 0000000..78188fb --- /dev/null +++ b/libgo/go/internal/goexperiment/exp_staticlockranking_on.go @@ -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 diff --git a/libgo/go/internal/goexperiment/flags.go b/libgo/go/internal/goexperiment/flags.go new file mode 100644 index 0000000..cd4c178 --- /dev/null +++ b/libgo/go/internal/goexperiment/flags.go @@ -0,0 +1,93 @@ +// 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. + +// Package goexperiment implements support for toolchain experiments. +// +// Toolchain experiments are controlled by the GOEXPERIMENT +// environment variable. GOEXPERIMENT is a comma-separated list of +// experiment names. GOEXPERIMENT can be set at make.bash time, which +// sets the default experiments for binaries built with the tool +// chain; or it can be set at build time. GOEXPERIMENT can also be set +// to "none", which disables any experiments that were enabled at +// make.bash time. +// +// Experiments are exposed to the build in the following ways: +// +// - 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. +// +// In the toolchain, the set of experiments enabled for the current +// build should be accessed via objabi.Experiment. +// +// The set of experiments is included in the output of runtime.Version() +// and "go version <binary>" if it differs from the default experiments. +// +// For the set of experiments supported by the current toolchain, see +// "go doc goexperiment.Flags". +// +// Note that this package defines the set of experiments (in Flags) +// and records the experiments that were enabled when the package +// was compiled (as boolean and integer constants). +// +// Note especially that this package does not itself change behavior +// at run time based on the GOEXPERIMENT variable. +// The code used in builds to interpret the GOEXPERIMENT variable +// is in the separate package internal/buildcfg. +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. +// +// For the baseline experimental configuration, see +// objabi.experimentBaseline. +// +// If you change this struct definition, run "go generate". +type Flags struct { + FieldTrack bool + PreemptibleLoops bool + StaticLockRanking bool + + // Regabi is split into several sub-experiments that can be + // enabled individually. Not all combinations work. + // The "regabi" GOEXPERIMENT is an alias for all "working" + // subexperiments. + + // RegabiWrappers enables ABI wrappers for calling between + // ABI0 and ABIInternal functions. Without this, the ABIs are + // assumed to be identical so cross-ABI calls are direct. + RegabiWrappers bool + // RegabiG enables dedicated G and zero registers in + // ABIInternal. + // + // Requires wrappers because it makes the ABIs incompatible. + RegabiG bool + // RegabiReflect enables the register-passing paths in + // reflection calls. This is also gated by intArgRegs in + // reflect and runtime (which are disabled by default) so it + // can be used in targeted tests. + RegabiReflect bool + // RegabiDefer enables desugaring defer and go calls + // into argument-less closures. + RegabiDefer bool + // RegabiArgs enables register arguments/results in all + // compiled Go functions. + // + // Requires wrappers (to do ABI translation), g (because + // runtime assembly that's been ported to ABIInternal uses the + // G register), reflect (so reflection calls use registers), + // and defer (because the runtime doesn't support passing + // register arguments to defer/go). + RegabiArgs bool +} diff --git a/libgo/go/internal/goexperiment/mkconsts.go b/libgo/go/internal/goexperiment/mkconsts.go new file mode 100644 index 0000000..204ca9d --- /dev/null +++ b/libgo/go/internal/goexperiment/mkconsts.go @@ -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 +} diff --git a/libgo/go/internal/goroot/gc.go b/libgo/go/internal/goroot/gc.go index ce72bc3..2338b78 100644 --- a/libgo/go/internal/goroot/gc.go +++ b/libgo/go/internal/goroot/gc.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build gc // +build gc package goroot diff --git a/libgo/go/internal/goroot/gccgo.go b/libgo/go/internal/goroot/gccgo.go index 3530e59..b1041da 100644 --- a/libgo/go/internal/goroot/gccgo.go +++ b/libgo/go/internal/goroot/gccgo.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build gccgo // +build gccgo package goroot diff --git a/libgo/go/internal/goversion/goversion.go b/libgo/go/internal/goversion/goversion.go index 513be45..4cc1568 100644 --- a/libgo/go/internal/goversion/goversion.go +++ b/libgo/go/internal/goversion/goversion.go @@ -9,4 +9,4 @@ package goversion // // It should be updated at the start of each development cycle to be // the version of the next Go 1.x release. See golang.org/issue/40705. -const Version = 16 +const Version = 17 diff --git a/libgo/go/internal/itoa/itoa.go b/libgo/go/internal/itoa/itoa.go new file mode 100644 index 0000000..c6062d9 --- /dev/null +++ b/libgo/go/internal/itoa/itoa.go @@ -0,0 +1,33 @@ +// 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. + +// Simple conversions to avoid depending on strconv. + +package itoa + +// Itoa converts val to a decimal string. +func Itoa(val int) string { + if val < 0 { + return "-" + Uitoa(uint(-val)) + } + return Uitoa(uint(val)) +} + +// Uitoa converts val to a decimal string. +func Uitoa(val uint) string { + if val == 0 { // avoid string allocation + return "0" + } + var buf [20]byte // big enough for 64bit value base 10 + i := len(buf) - 1 + for val >= 10 { + q := val / 10 + buf[i] = byte('0' + val - q*10) + i-- + val = q + } + // val < 10 + buf[i] = byte('0' + val) + return string(buf[i:]) +} diff --git a/libgo/go/internal/itoa/itoa_test.go b/libgo/go/internal/itoa/itoa_test.go new file mode 100644 index 0000000..71931c1 --- /dev/null +++ b/libgo/go/internal/itoa/itoa_test.go @@ -0,0 +1,40 @@ +// 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. + +package itoa_test + +import ( + "fmt" + "internal/itoa" + "math" + "testing" +) + +var ( + minInt64 int64 = math.MinInt64 + maxInt64 int64 = math.MaxInt64 + maxUint64 uint64 = math.MaxUint64 +) + +func TestItoa(t *testing.T) { + tests := []int{int(minInt64), math.MinInt32, -999, -100, -1, 0, 1, 100, 999, math.MaxInt32, int(maxInt64)} + for _, tt := range tests { + got := itoa.Itoa(tt) + want := fmt.Sprint(tt) + if want != got { + t.Fatalf("Itoa(%d) = %s, want %s", tt, got, want) + } + } +} + +func TestUitoa(t *testing.T) { + tests := []uint{0, 1, 100, 999, math.MaxUint32, uint(maxUint64)} + for _, tt := range tests { + got := itoa.Uitoa(tt) + want := fmt.Sprint(tt) + if want != got { + t.Fatalf("Uitoa(%d) = %s, want %s", tt, got, want) + } + } +} diff --git a/libgo/go/internal/poll/copy_file_range_linux.go b/libgo/go/internal/poll/copy_file_range_linux.go index 01b242a..5b9e5d4 100644 --- a/libgo/go/internal/poll/copy_file_range_linux.go +++ b/libgo/go/internal/poll/copy_file_range_linux.go @@ -78,7 +78,7 @@ func CopyFileRange(dst, src *FD, remain int64) (written int64, handled bool, err // Go supports Linux >= 2.6.33, so the system call // may not be present. // - // If we see ENOSYS, we have certainly not transfered + // If we see ENOSYS, we have certainly not transferred // any data, so we can tell the caller that we // couldn't handle the transfer and let them fall // back to more generic code. @@ -91,13 +91,13 @@ func CopyFileRange(dst, src *FD, remain int64) (written int64, handled bool, err // Prior to Linux 5.3, it was not possible to // copy_file_range across file systems. Similarly to // the ENOSYS case above, if we see EXDEV, we have - // not transfered any data, and we can let the caller + // not transferred any data, and we can let the caller // fall back to generic code. // // As for EINVAL, that is what we see if, for example, // dst or src refer to a pipe rather than a regular // file. This is another case where no data has been - // transfered, so we consider it unhandled. + // transferred, so we consider it unhandled. // // If src and dst are on CIFS, we can see EIO. // See issue #42334. diff --git a/libgo/go/internal/poll/errno_unix.go b/libgo/go/internal/poll/errno_unix.go index 922230b..d03a2d2 100644 --- a/libgo/go/internal/poll/errno_unix.go +++ b/libgo/go/internal/poll/errno_unix.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || hurd || linux || netbsd || openbsd || solaris // +build aix darwin dragonfly freebsd hurd linux netbsd openbsd solaris package poll diff --git a/libgo/go/internal/poll/errno_windows.go b/libgo/go/internal/poll/errno_windows.go index e3bddb4..c55f5f0 100644 --- a/libgo/go/internal/poll/errno_windows.go +++ b/libgo/go/internal/poll/errno_windows.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build windows // +build windows package poll diff --git a/libgo/go/internal/poll/error_stub_test.go b/libgo/go/internal/poll/error_stub_test.go index c40ffcd..bcc25dd 100644 --- a/libgo/go/internal/poll/error_stub_test.go +++ b/libgo/go/internal/poll/error_stub_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !linux // +build !linux package poll_test diff --git a/libgo/go/internal/poll/export_linux_test.go b/libgo/go/internal/poll/export_linux_test.go new file mode 100644 index 0000000..7fba793 --- /dev/null +++ b/libgo/go/internal/poll/export_linux_test.go @@ -0,0 +1,22 @@ +// 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. + +// Export guts for testing on linux. +// Since testing imports os and os imports internal/poll, +// the internal/poll tests can not be in package poll. + +package poll + +var ( + GetPipe = getPipe + PutPipe = putPipe + NewPipe = newPipe + DestroyPipe = destroyPipe +) + +func GetPipeFds(p *SplicePipe) (int, int) { + return p.rfd, p.wfd +} + +type SplicePipe = splicePipe diff --git a/libgo/go/internal/poll/export_posix_test.go b/libgo/go/internal/poll/export_posix_test.go index 8ab4fd6..1e714cd 100644 --- a/libgo/go/internal/poll/export_posix_test.go +++ b/libgo/go/internal/poll/export_posix_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || hurd || linux || netbsd || openbsd || solaris || windows // +build aix darwin dragonfly freebsd hurd linux netbsd openbsd solaris windows // Export guts for testing on posix. diff --git a/libgo/go/internal/poll/export_test.go b/libgo/go/internal/poll/export_test.go index 02664d9..e1125cb 100644 --- a/libgo/go/internal/poll/export_test.go +++ b/libgo/go/internal/poll/export_test.go @@ -33,3 +33,5 @@ func (mu *FDMutex) RWLock(read bool) bool { func (mu *FDMutex) RWUnlock(read bool) bool { return mu.rwunlock(read) } + +var Fcntl = fcntl diff --git a/libgo/go/internal/poll/fcntl_js.go b/libgo/go/internal/poll/fcntl_js.go index 120fc11..7bf0ddc 100644 --- a/libgo/go/internal/poll/fcntl_js.go +++ b/libgo/go/internal/poll/fcntl_js.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build js && wasm // +build js,wasm package poll diff --git a/libgo/go/internal/poll/fcntl_libc.go b/libgo/go/internal/poll/fcntl_libc.go index ed00f76..e9a98e3 100644 --- a/libgo/go/internal/poll/fcntl_libc.go +++ b/libgo/go/internal/poll/fcntl_libc.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || solaris // +build aix darwin solaris package poll diff --git a/libgo/go/internal/poll/fcntl_syscall.go b/libgo/go/internal/poll/fcntl_syscall.go index fb82b9b..cd0061f 100644 --- a/libgo/go/internal/poll/fcntl_syscall.go +++ b/libgo/go/internal/poll/fcntl_syscall.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build dragonfly || freebsd || hurd || linux || netbsd || openbsd // +build dragonfly freebsd hurd linux netbsd openbsd package poll diff --git a/libgo/go/internal/poll/fd.go b/libgo/go/internal/poll/fd.go index b72ea3d..69a9005 100644 --- a/libgo/go/internal/poll/fd.go +++ b/libgo/go/internal/poll/fd.go @@ -13,11 +13,22 @@ import ( "errors" ) -// ErrNetClosing is returned when a network descriptor is used after -// it has been closed. Keep this string consistent because of issue -// #4373: since historically programs have not been able to detect +// errNetClosing is the type of the variable ErrNetClosing. +// This is used to implement the net.Error interface. +type errNetClosing struct{} + +// Error returns the error message for ErrNetClosing. +// Keep this string consistent because of issue #4373: +// since historically programs have not been able to detect // this error, they look for the string. -var ErrNetClosing = errors.New("use of closed network connection") +func (e errNetClosing) Error() string { return "use of closed network connection" } + +func (e errNetClosing) Timeout() bool { return false } +func (e errNetClosing) Temporary() bool { return false } + +// ErrNetClosing is returned when a network descriptor is used after +// it has been closed. +var ErrNetClosing = errNetClosing{} // ErrFileClosing is returned when a file descriptor is used after it // has been closed. diff --git a/libgo/go/internal/poll/fd_fsync_posix.go b/libgo/go/internal/poll/fd_fsync_posix.go index 9be0f54..21f1de4 100644 --- a/libgo/go/internal/poll/fd_fsync_posix.go +++ b/libgo/go/internal/poll/fd_fsync_posix.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || dragonfly || freebsd || hurd || (js && wasm) || linux || netbsd || openbsd || solaris // +build aix dragonfly freebsd hurd js,wasm linux netbsd openbsd solaris package poll diff --git a/libgo/go/internal/poll/fd_io_plan9.go b/libgo/go/internal/poll/fd_io_plan9.go index 287d11b..3205ac8 100644 --- a/libgo/go/internal/poll/fd_io_plan9.go +++ b/libgo/go/internal/poll/fd_io_plan9.go @@ -5,6 +5,7 @@ package poll import ( + "internal/itoa" "runtime" "sync" "syscall" @@ -71,7 +72,7 @@ func (aio *asyncIO) Cancel() { if aio.pid == -1 { return } - f, e := syscall.Open("/proc/"+itoa(aio.pid)+"/note", syscall.O_WRONLY) + f, e := syscall.Open("/proc/"+itoa.Itoa(aio.pid)+"/note", syscall.O_WRONLY) if e != nil { return } diff --git a/libgo/go/internal/poll/fd_poll_js.go b/libgo/go/internal/poll/fd_poll_js.go index d6b28e5..760e248 100644 --- a/libgo/go/internal/poll/fd_poll_js.go +++ b/libgo/go/internal/poll/fd_poll_js.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build js && wasm // +build js,wasm package poll diff --git a/libgo/go/internal/poll/fd_poll_runtime.go b/libgo/go/internal/poll/fd_poll_runtime.go index 55aa304..f40b845 100644 --- a/libgo/go/internal/poll/fd_poll_runtime.go +++ b/libgo/go/internal/poll/fd_poll_runtime.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || hurd || linux || netbsd || openbsd || windows || solaris // +build aix darwin dragonfly freebsd hurd linux netbsd openbsd windows solaris package poll @@ -38,10 +39,6 @@ func (pd *pollDesc) init(fd *FD) error { serverInit.Do(runtime_pollServerInit) ctx, errno := runtime_pollOpen(uintptr(fd.Sysfd)) if errno != 0 { - if ctx != 0 { - runtime_pollUnblock(ctx) - runtime_pollClose(ctx) - } return errnoErr(syscall.Errno(errno)) } pd.runtimeCtx = ctx diff --git a/libgo/go/internal/poll/fd_posix.go b/libgo/go/internal/poll/fd_posix.go index 16c2e50..fd64e53 100644 --- a/libgo/go/internal/poll/fd_posix.go +++ b/libgo/go/internal/poll/fd_posix.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || hurd || (js && wasm) || linux || netbsd || openbsd || solaris || windows // +build aix darwin dragonfly freebsd hurd js,wasm linux netbsd openbsd solaris windows package poll diff --git a/libgo/go/internal/poll/fd_posix_test.go b/libgo/go/internal/poll/fd_posix_test.go index dfcfd5c..1dc3f0f 100644 --- a/libgo/go/internal/poll/fd_posix_test.go +++ b/libgo/go/internal/poll/fd_posix_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || hurd || linux || netbsd || openbsd || solaris || windows // +build aix darwin dragonfly freebsd hurd linux netbsd openbsd solaris windows package poll_test diff --git a/libgo/go/internal/poll/fd_unix.go b/libgo/go/internal/poll/fd_unix.go index 013b7e5..d8861de 100644 --- a/libgo/go/internal/poll/fd_unix.go +++ b/libgo/go/internal/poll/fd_unix.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || hurd || (js && wasm) || linux || netbsd || openbsd || solaris // +build aix darwin dragonfly freebsd hurd js,wasm linux netbsd openbsd solaris package poll @@ -230,7 +231,7 @@ func (fd *FD) ReadFrom(p []byte) (int, syscall.Sockaddr, error) { } // ReadMsg wraps the recvmsg network call. -func (fd *FD) ReadMsg(p []byte, oob []byte) (int, int, int, syscall.Sockaddr, error) { +func (fd *FD) ReadMsg(p []byte, oob []byte, flags int) (int, int, int, syscall.Sockaddr, error) { if err := fd.readLock(); err != nil { return 0, 0, 0, nil, err } @@ -239,7 +240,7 @@ func (fd *FD) ReadMsg(p []byte, oob []byte) (int, int, int, syscall.Sockaddr, er return 0, 0, 0, nil, err } for { - n, oobn, flags, sa, err := syscall.Recvmsg(fd.Sysfd, p, oob, 0) + n, oobn, sysflags, sa, err := syscall.Recvmsg(fd.Sysfd, p, oob, flags) if err != nil { if err == syscall.EINTR { continue @@ -252,7 +253,7 @@ func (fd *FD) ReadMsg(p []byte, oob []byte) (int, int, int, syscall.Sockaddr, er } } err = fd.eofError(n, err) - return n, oobn, flags, sa, err + return n, oobn, sysflags, sa, err } } diff --git a/libgo/go/internal/poll/fd_windows.go b/libgo/go/internal/poll/fd_windows.go index d8c834f..4a51695 100644 --- a/libgo/go/internal/poll/fd_windows.go +++ b/libgo/go/internal/poll/fd_windows.go @@ -1013,7 +1013,7 @@ func sockaddrToRaw(sa syscall.Sockaddr) (unsafe.Pointer, int32, error) { } // ReadMsg wraps the WSARecvMsg network call. -func (fd *FD) ReadMsg(p []byte, oob []byte) (int, int, int, syscall.Sockaddr, error) { +func (fd *FD) ReadMsg(p []byte, oob []byte, flags int) (int, int, int, syscall.Sockaddr, error) { if err := fd.readLock(); err != nil { return 0, 0, 0, nil, err } @@ -1028,6 +1028,7 @@ func (fd *FD) ReadMsg(p []byte, oob []byte) (int, int, int, syscall.Sockaddr, er o.rsa = new(syscall.RawSockaddrAny) o.msg.Name = (syscall.Pointer)(unsafe.Pointer(o.rsa)) o.msg.Namelen = int32(unsafe.Sizeof(*o.rsa)) + o.msg.Flags = uint32(flags) n, err := execIO(o, func(o *operation) error { return windows.WSARecvMsg(o.fd.Sysfd, &o.msg, &o.qty, &o.o, nil) }) diff --git a/libgo/go/internal/poll/fd_writev_darwin.go b/libgo/go/internal/poll/fd_writev_darwin.go index e202447..805fa2c 100644 --- a/libgo/go/internal/poll/fd_writev_darwin.go +++ b/libgo/go/internal/poll/fd_writev_darwin.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build darwin // +build darwin package poll diff --git a/libgo/go/internal/poll/fd_writev_illumos.go b/libgo/go/internal/poll/fd_writev_illumos.go index 1fa47ab..a0b11ed 100644 --- a/libgo/go/internal/poll/fd_writev_illumos.go +++ b/libgo/go/internal/poll/fd_writev_illumos.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build illumos // +build illumos package poll diff --git a/libgo/go/internal/poll/fd_writev_unix.go b/libgo/go/internal/poll/fd_writev_unix.go index daeec96..87f284a 100644 --- a/libgo/go/internal/poll/fd_writev_unix.go +++ b/libgo/go/internal/poll/fd_writev_unix.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build dragonfly || freebsd || linux || netbsd || openbsd // +build dragonfly freebsd linux netbsd openbsd package poll diff --git a/libgo/go/internal/poll/hook_cloexec.go b/libgo/go/internal/poll/hook_cloexec.go index b8ce58d..18b445a 100644 --- a/libgo/go/internal/poll/hook_cloexec.go +++ b/libgo/go/internal/poll/hook_cloexec.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build dragonfly || freebsd || hurd || illumos || linux || netbsd || openbsd // +build dragonfly freebsd hurd illumos linux netbsd openbsd package poll diff --git a/libgo/go/internal/poll/hook_unix.go b/libgo/go/internal/poll/hook_unix.go index 7bb6f88..5223fb7 100644 --- a/libgo/go/internal/poll/hook_unix.go +++ b/libgo/go/internal/poll/hook_unix.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || hurd || (js && wasm) || linux || netbsd || openbsd || solaris // +build aix darwin dragonfly freebsd hurd js,wasm linux netbsd openbsd solaris package poll diff --git a/libgo/go/internal/poll/iovec_illumos.go b/libgo/go/internal/poll/iovec_illumos.go index 0570674..f4058b2 100644 --- a/libgo/go/internal/poll/iovec_illumos.go +++ b/libgo/go/internal/poll/iovec_illumos.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build illumos // +build illumos package poll diff --git a/libgo/go/internal/poll/iovec_unix.go b/libgo/go/internal/poll/iovec_unix.go index 6f98947..6fd5d86 100644 --- a/libgo/go/internal/poll/iovec_unix.go +++ b/libgo/go/internal/poll/iovec_unix.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd // +build darwin dragonfly freebsd linux netbsd openbsd package poll diff --git a/libgo/go/internal/poll/sendfile_bsd.go b/libgo/go/internal/poll/sendfile_bsd.go index 66005a9..3ba30a2 100644 --- a/libgo/go/internal/poll/sendfile_bsd.go +++ b/libgo/go/internal/poll/sendfile_bsd.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build dragonfly || freebsd // +build dragonfly freebsd package poll @@ -22,7 +23,7 @@ func SendFile(dstFD *FD, src int, pos, remain int64) (int64, error) { return 0, err } - dst := int(dstFD.Sysfd) + dst := dstFD.Sysfd var written int64 var err error for remain > 0 { diff --git a/libgo/go/internal/poll/sendfile_solaris.go b/libgo/go/internal/poll/sendfile_solaris.go index 748c851..0a88430 100644 --- a/libgo/go/internal/poll/sendfile_solaris.go +++ b/libgo/go/internal/poll/sendfile_solaris.go @@ -24,7 +24,7 @@ func SendFile(dstFD *FD, src int, pos, remain int64) (int64, error) { return 0, err } - dst := int(dstFD.Sysfd) + dst := dstFD.Sysfd var written int64 var err error for remain > 0 { diff --git a/libgo/go/internal/poll/sock_cloexec.go b/libgo/go/internal/poll/sock_cloexec.go index 09bc4b6..7daa11e 100644 --- a/libgo/go/internal/poll/sock_cloexec.go +++ b/libgo/go/internal/poll/sock_cloexec.go @@ -2,9 +2,10 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// This file implements sysSocket and accept for platforms that -// provide a fast path for setting SetNonblock and CloseOnExec. +// This file implements accept for platforms that provide a fast path for +// setting SetNonblock and CloseOnExec. +//go:build dragonfly || freebsd || hurd || illumos || linux || netbsd || openbsd // +build dragonfly freebsd hurd illumos linux netbsd openbsd package poll diff --git a/libgo/go/internal/poll/sockopt.go b/libgo/go/internal/poll/sockopt.go index 2c6b68b..975f84b 100644 --- a/libgo/go/internal/poll/sockopt.go +++ b/libgo/go/internal/poll/sockopt.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || hurd || linux || netbsd || openbsd || solaris || windows // +build aix darwin dragonfly freebsd hurd linux netbsd openbsd solaris windows package poll diff --git a/libgo/go/internal/poll/sockopt_unix.go b/libgo/go/internal/poll/sockopt_unix.go index ef266d0..02a7859 100644 --- a/libgo/go/internal/poll/sockopt_unix.go +++ b/libgo/go/internal/poll/sockopt_unix.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || hurd || linux || netbsd || openbsd || solaris // +build aix darwin dragonfly freebsd hurd linux netbsd openbsd solaris package poll diff --git a/libgo/go/internal/poll/sockoptip.go b/libgo/go/internal/poll/sockoptip.go index fc476bd..bcefa6b 100644 --- a/libgo/go/internal/poll/sockoptip.go +++ b/libgo/go/internal/poll/sockoptip.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || hurd || linux || netbsd || openbsd || solaris || windows // +build aix darwin dragonfly freebsd hurd linux netbsd openbsd solaris windows package poll diff --git a/libgo/go/internal/poll/splice_linux.go b/libgo/go/internal/poll/splice_linux.go index ca772e9..c7114f2 100644 --- a/libgo/go/internal/poll/splice_linux.go +++ b/libgo/go/internal/poll/splice_linux.go @@ -5,6 +5,8 @@ package poll import ( + "runtime" + "sync" "sync/atomic" "syscall" "unsafe" @@ -22,23 +24,23 @@ const ( // Splice transfers at most remain bytes of data from src to dst, using the // splice system call to minimize copies of data from and to userspace. // -// Splice creates a temporary pipe, to serve as a buffer for the data transfer. +// Splice gets a pipe buffer from the pool or creates a new one if needed, to serve as a buffer for the data transfer. // src and dst must both be stream-oriented sockets. // // If err != nil, sc is the system call which caused the error. func Splice(dst, src *FD, remain int64) (written int64, handled bool, sc string, err error) { - prfd, pwfd, sc, err := newTempPipe() + p, sc, err := getPipe() if err != nil { return 0, false, sc, err } - defer destroyTempPipe(prfd, pwfd) + defer putPipe(p) var inPipe, n int for err == nil && remain > 0 { max := maxSpliceSize if int64(max) > remain { max = int(remain) } - inPipe, err = spliceDrain(pwfd, src, max) + inPipe, err = spliceDrain(p.wfd, src, max) // The operation is considered handled if splice returns no // error, or an error other than EINVAL. An EINVAL means the // kernel does not support splice for the socket type of src. @@ -51,13 +53,16 @@ func Splice(dst, src *FD, remain int64) (written int64, handled bool, sc string, // If inPipe == 0 && err == nil, src is at EOF, and the // transfer is complete. handled = handled || (err != syscall.EINVAL) - if err != nil || (inPipe == 0 && err == nil) { + if err != nil || inPipe == 0 { break } - n, err = splicePump(dst, prfd, inPipe) + p.data += inPipe + + n, err = splicePump(dst, p.rfd, inPipe) if n > 0 { written += int64(n) remain -= int64(n) + p.data -= n } } if err != nil { @@ -148,13 +153,58 @@ func splice(out int, in int, max int, flags int) (int, error) { return int(n), err } +type splicePipe struct { + rfd int + wfd int + data int +} + +// splicePipePool caches pipes to avoid high-frequency construction and destruction of pipe buffers. +// The garbage collector will free all pipes in the sync.Pool periodically, thus we need to set up +// a finalizer for each pipe to close its file descriptors before the actual GC. +var splicePipePool = sync.Pool{New: newPoolPipe} + +func newPoolPipe() interface{} { + // Discard the error which occurred during the creation of pipe buffer, + // redirecting the data transmission to the conventional way utilizing read() + write() as a fallback. + p := newPipe() + if p == nil { + return nil + } + runtime.SetFinalizer(p, destroyPipe) + return p +} + +// getPipe tries to acquire a pipe buffer from the pool or create a new one with newPipe() if it gets nil from the cache. +// +// Note that it may fail to create a new pipe buffer by newPipe(), in which case getPipe() will return a generic error +// and system call name splice in a string as the indication. +func getPipe() (*splicePipe, string, error) { + v := splicePipePool.Get() + if v == nil { + return nil, "splice", syscall.EINVAL + } + return v.(*splicePipe), "", nil +} + +func putPipe(p *splicePipe) { + // If there is still data left in the pipe, + // then close and discard it instead of putting it back into the pool. + if p.data != 0 { + runtime.SetFinalizer(p, nil) + destroyPipe(p) + return + } + splicePipePool.Put(p) +} + var disableSplice unsafe.Pointer -// newTempPipe sets up a temporary pipe for a splice operation. -func newTempPipe() (prfd, pwfd int, sc string, err error) { +// newPipe sets up a pipe for a splice operation. +func newPipe() (sp *splicePipe) { p := (*bool)(atomic.LoadPointer(&disableSplice)) if p != nil && *p { - return -1, -1, "splice", syscall.EINVAL + return nil } var fds [2]int @@ -164,9 +214,11 @@ func newTempPipe() (prfd, pwfd int, sc string, err error) { // closed. const flags = syscall.O_CLOEXEC | syscall.O_NONBLOCK if err := syscall.Pipe2(fds[:], flags); err != nil { - return -1, -1, "pipe2", err + return nil } + sp = &splicePipe{rfd: fds[0], wfd: fds[1]} + if p == nil { p = new(bool) defer atomic.StorePointer(&disableSplice, unsafe.Pointer(p)) @@ -174,25 +226,21 @@ func newTempPipe() (prfd, pwfd int, sc string, err error) { // F_GETPIPE_SZ was added in 2.6.35, which does not have the -EAGAIN bug. if syscall.F_GETPIPE_SZ == 0 { *p = true - destroyTempPipe(fds[0], fds[1]) - return -1, -1, "fcntl", syscall.EINVAL + destroyPipe(sp) + return nil } if _, err := fcntl(fds[0], syscall.F_GETPIPE_SZ, 0); err != nil { *p = true - destroyTempPipe(fds[0], fds[1]) - return -1, -1, "fcntl", err + destroyPipe(sp) + return nil } } - return fds[0], fds[1], "", nil + return } -// destroyTempPipe destroys a temporary pipe. -func destroyTempPipe(prfd, pwfd int) error { - err := CloseFunc(prfd) - err1 := CloseFunc(pwfd) - if err == nil { - return err1 - } - return err +// destroyPipe destroys a pipe. +func destroyPipe(p *splicePipe) { + CloseFunc(p.rfd) + CloseFunc(p.wfd) } diff --git a/libgo/go/internal/poll/splice_linux_test.go b/libgo/go/internal/poll/splice_linux_test.go new file mode 100644 index 0000000..206a027 --- /dev/null +++ b/libgo/go/internal/poll/splice_linux_test.go @@ -0,0 +1,122 @@ +// 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. + +package poll_test + +import ( + "internal/poll" + "runtime" + "syscall" + "testing" + "time" +) + +// checkPipes returns true if all pipes are closed properly, false otherwise. +func checkPipes(fds []int) bool { + for _, fd := range fds { + // Check if each pipe fd has been closed. + _, err := poll.Fcntl(fd, syscall.F_GETPIPE_SZ, 0) + if err == nil { + return false + } + } + return true +} + +func TestSplicePipePool(t *testing.T) { + if runtime.Compiler == "gccgo" { + t.Skip("gofrontend conservative stack collection causes this test to fail") + } + + const N = 64 + var ( + p *poll.SplicePipe + ps []*poll.SplicePipe + fds []int + err error + ) + for i := 0; i < N; i++ { + p, _, err = poll.GetPipe() + if err != nil { + t.Skip("failed to create pipe, skip this test") + } + _, pwfd := poll.GetPipeFds(p) + fds = append(fds, pwfd) + ps = append(ps, p) + } + for _, p = range ps { + poll.PutPipe(p) + } + ps = nil + p = nil + + // Exploit the timeout of "go test" as a timer for the subsequent verification. + timeout := 5 * time.Minute + if deadline, ok := t.Deadline(); ok { + timeout = deadline.Sub(time.Now()) + timeout -= timeout / 10 // Leave 10% headroom for cleanup. + } + expiredTime := time.NewTimer(timeout) + defer expiredTime.Stop() + + // Trigger garbage collection repeatedly, waiting for all pipes in sync.Pool + // to either be deallocated and closed, or to time out. + for { + runtime.GC() + time.Sleep(10 * time.Millisecond) + if checkPipes(fds) { + break + } + select { + case <-expiredTime.C: + t.Fatal("at least one pipe is still open") + default: + } + } +} + +func BenchmarkSplicePipe(b *testing.B) { + b.Run("SplicePipeWithPool", func(b *testing.B) { + for i := 0; i < b.N; i++ { + p, _, err := poll.GetPipe() + if err != nil { + continue + } + poll.PutPipe(p) + } + }) + b.Run("SplicePipeWithoutPool", func(b *testing.B) { + for i := 0; i < b.N; i++ { + p := poll.NewPipe() + if p == nil { + b.Skip("newPipe returned nil") + } + poll.DestroyPipe(p) + } + }) +} + +func BenchmarkSplicePipePoolParallel(b *testing.B) { + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + p, _, err := poll.GetPipe() + if err != nil { + continue + } + poll.PutPipe(p) + } + }) +} + +func BenchmarkSplicePipeNativeParallel(b *testing.B) { + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + p := poll.NewPipe() + if p == nil { + b.Skip("newPipe returned nil") + } + poll.DestroyPipe(p) + } + }) +} diff --git a/libgo/go/internal/poll/strconv.go b/libgo/go/internal/poll/strconv.go index 21cb40d..c98332d 100644 --- a/libgo/go/internal/poll/strconv.go +++ b/libgo/go/internal/poll/strconv.go @@ -2,38 +2,11 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build plan9 // +build plan9 -// Simple conversions to avoid depending on strconv. - package poll -// Convert integer to decimal string -func itoa(val int) string { - if val < 0 { - return "-" + uitoa(uint(-val)) - } - return uitoa(uint(val)) -} - -// Convert unsigned integer to decimal string -func uitoa(val uint) string { - if val == 0 { // avoid string allocation - return "0" - } - var buf [20]byte // big enough for 64bit value base 10 - i := len(buf) - 1 - for val >= 10 { - q := val / 10 - buf[i] = byte('0' + val - q*10) - i-- - val = q - } - // val < 10 - buf[i] = byte('0' + val) - return string(buf[i:]) -} - // stringsHasSuffix is strings.HasSuffix. It reports whether s ends in // suffix. func stringsHasSuffix(s, suffix string) bool { diff --git a/libgo/go/internal/poll/sys_cloexec.go b/libgo/go/internal/poll/sys_cloexec.go index 4b3c642..7e6d422 100644 --- a/libgo/go/internal/poll/sys_cloexec.go +++ b/libgo/go/internal/poll/sys_cloexec.go @@ -2,9 +2,10 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// This file implements sysSocket and accept for platforms that do not -// provide a fast path for setting SetNonblock and CloseOnExec. +// This file implements accept for platforms that do not provide a fast path for +// setting SetNonblock and CloseOnExec. +//go:build aix || darwin || (js && wasm) || (solaris && !illumos) // +build aix darwin js,wasm solaris,!illumos package poll diff --git a/libgo/go/internal/poll/writev.go b/libgo/go/internal/poll/writev.go index 0123fc3..824de75 100644 --- a/libgo/go/internal/poll/writev.go +++ b/libgo/go/internal/poll/writev.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build darwin || dragonfly || freebsd || illumos || linux || netbsd || openbsd // +build darwin dragonfly freebsd illumos linux netbsd openbsd package poll diff --git a/libgo/go/internal/race/norace.go b/libgo/go/internal/race/norace.go index d83c016..67b1305 100644 --- a/libgo/go/internal/race/norace.go +++ b/libgo/go/internal/race/norace.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !race // +build !race package race diff --git a/libgo/go/internal/race/race.go b/libgo/go/internal/race/race.go index 2e7d97b..40f2c99 100644 --- a/libgo/go/internal/race/race.go +++ b/libgo/go/internal/race/race.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build race // +build race package race diff --git a/libgo/go/internal/reflectlite/all_test.go b/libgo/go/internal/reflectlite/all_test.go index 2ea28e0..e15f364 100644 --- a/libgo/go/internal/reflectlite/all_test.go +++ b/libgo/go/internal/reflectlite/all_test.go @@ -982,21 +982,6 @@ func TestNames(t *testing.T) { } } -type embed struct { - EmbedWithUnexpMeth -} - -/* -func TestNameBytesAreAligned(t *testing.T) { - typ := TypeOf(embed{}) - b := FirstMethodNameBytes(typ) - v := uintptr(unsafe.Pointer(b)) - if v%unsafe.Alignof((*byte)(nil)) != 0 { - t.Errorf("reflect.name.bytes pointer is not aligned: %x", v) - } -} -*/ - // TestUnaddressableField tests that the reflect package will not allow // a type from another package to be used as a named type with an // unexported field. diff --git a/libgo/go/internal/reflectlite/type.go b/libgo/go/internal/reflectlite/type.go index 0c1b994..db1469d 100644 --- a/libgo/go/internal/reflectlite/type.go +++ b/libgo/go/internal/reflectlite/type.go @@ -67,7 +67,7 @@ type Type interface { } /* - * These data structures are known to the compiler (../../cmd/internal/gc/reflect.go). + * These data structures are known to the compiler (../../cmd/internal/reflectdata/reflect.go). * A few are known to ../runtime/type.go to convey to debuggers. * They are also known to ../runtime/type.go. */ diff --git a/libgo/go/internal/syscall/execenv/execenv_default.go b/libgo/go/internal/syscall/execenv/execenv_default.go index 4bdbb55..73289f1 100644 --- a/libgo/go/internal/syscall/execenv/execenv_default.go +++ b/libgo/go/internal/syscall/execenv/execenv_default.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !windows // +build !windows package execenv diff --git a/libgo/go/internal/syscall/execenv/execenv_windows.go b/libgo/go/internal/syscall/execenv/execenv_windows.go index b50029c..6c06549 100644 --- a/libgo/go/internal/syscall/execenv/execenv_windows.go +++ b/libgo/go/internal/syscall/execenv/execenv_windows.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build windows // +build windows package execenv diff --git a/libgo/go/internal/syscall/unix/at.go b/libgo/go/internal/syscall/unix/at.go index a602d3a..5059af3 100644 --- a/libgo/go/internal/syscall/unix/at.go +++ b/libgo/go/internal/syscall/unix/at.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//-go:build linux || openbsd || netbsd || dragonfly // -build linux openbsd netbsd dragonfly package unix diff --git a/libgo/go/internal/syscall/unix/getentropy_darwin.go b/libgo/go/internal/syscall/unix/getentropy_darwin.go new file mode 100644 index 0000000..e1a410a --- /dev/null +++ b/libgo/go/internal/syscall/unix/getentropy_darwin.go @@ -0,0 +1,30 @@ +// 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. + +package unix + +import ( + "internal/abi" + "syscall" + "unsafe" +) + +//go:cgo_import_dynamic libc_getentropy getentropy "/usr/lib/libSystem.B.dylib" + +func libc_getentropy_trampoline() + +// GetEntropy calls the macOS getentropy system call. +func GetEntropy(p []byte) error { + _, _, errno := syscall_syscall(abi.FuncPCABI0(libc_getentropy_trampoline), + uintptr(unsafe.Pointer(&p[0])), + uintptr(len(p)), + 0) + if errno != 0 { + return errno + } + return nil +} + +//go:linkname syscall_syscall syscall.syscall +func syscall_syscall(fn, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) diff --git a/libgo/go/internal/syscall/unix/getrandom.go b/libgo/go/internal/syscall/unix/getrandom.go new file mode 100644 index 0000000..d2c58c0 --- /dev/null +++ b/libgo/go/internal/syscall/unix/getrandom.go @@ -0,0 +1,40 @@ +// 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 dragonfly || freebsd || linux +// +build dragonfly freebsd linux + +package unix + +import ( + "sync/atomic" + "syscall" + "unsafe" +) + +var getrandomUnsupported int32 // atomic + +// GetRandomFlag is a flag supported by the getrandom system call. +type GetRandomFlag uintptr + +// GetRandom calls the getrandom system call. +func GetRandom(p []byte, flags GetRandomFlag) (n int, err error) { + if len(p) == 0 { + return 0, nil + } + if atomic.LoadInt32(&getrandomUnsupported) != 0 { + return 0, syscall.ENOSYS + } + r1, _, errno := syscall.Syscall(getrandomTrap, + uintptr(unsafe.Pointer(&p[0])), + uintptr(len(p)), + uintptr(flags)) + if errno != 0 { + if errno == syscall.ENOSYS { + atomic.StoreInt32(&getrandomUnsupported, 1) + } + return 0, errno + } + return int(r1), nil +} diff --git a/libgo/go/internal/syscall/unix/getrandom_dragonfly.go b/libgo/go/internal/syscall/unix/getrandom_dragonfly.go new file mode 100644 index 0000000..fbf78f9 --- /dev/null +++ b/libgo/go/internal/syscall/unix/getrandom_dragonfly.go @@ -0,0 +1,16 @@ +// 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. + +package unix + +// DragonFlyBSD getrandom system call number. +const getrandomTrap uintptr = 550 + +const ( + // GRND_RANDOM is only set for portability purpose, no-op on DragonFlyBSD. + GRND_RANDOM GetRandomFlag = 0x0001 + + // GRND_NONBLOCK means return EAGAIN rather than blocking. + GRND_NONBLOCK GetRandomFlag = 0x0002 +) diff --git a/libgo/go/internal/syscall/unix/getrandom_freebsd.go b/libgo/go/internal/syscall/unix/getrandom_freebsd.go index f1ba573..8c4f3df 100644 --- a/libgo/go/internal/syscall/unix/getrandom_freebsd.go +++ b/libgo/go/internal/syscall/unix/getrandom_freebsd.go @@ -4,19 +4,8 @@ package unix -import ( - "sync/atomic" - "syscall" - "unsafe" -) - -var randomUnsupported int32 // atomic - // FreeBSD getrandom system call number. -const randomTrap uintptr = 563 - -// GetRandomFlag is a flag supported by the getrandom system call. -type GetRandomFlag uintptr +const getrandomTrap uintptr = 563 const ( // GRND_NONBLOCK means return EAGAIN rather than blocking. @@ -25,24 +14,3 @@ const ( // GRND_RANDOM is only set for portability purpose, no-op on FreeBSD. GRND_RANDOM GetRandomFlag = 0x0002 ) - -// GetRandom calls the FreeBSD getrandom system call. -func GetRandom(p []byte, flags GetRandomFlag) (n int, err error) { - if len(p) == 0 { - return 0, nil - } - if atomic.LoadInt32(&randomUnsupported) != 0 { - return 0, syscall.ENOSYS - } - r1, _, errno := syscall.Syscall(randomTrap, - uintptr(unsafe.Pointer(&p[0])), - uintptr(len(p)), - uintptr(flags)) - if errno != 0 { - if errno == syscall.ENOSYS { - atomic.StoreInt32(&randomUnsupported, 1) - } - return 0, errno - } - return int(r1), nil -} diff --git a/libgo/go/internal/syscall/unix/getrandom_linux.go b/libgo/go/internal/syscall/unix/getrandom_linux.go index 490d516..8ccd8d3 100644 --- a/libgo/go/internal/syscall/unix/getrandom_linux.go +++ b/libgo/go/internal/syscall/unix/getrandom_linux.go @@ -4,17 +4,6 @@ package unix -import ( - "sync/atomic" - "syscall" - "unsafe" -) - -var randomUnsupported int32 // atomic - -// GetRandomFlag is a flag supported by the getrandom system call. -type GetRandomFlag uintptr - const ( // GRND_NONBLOCK means return EAGAIN rather than blocking. GRND_NONBLOCK GetRandomFlag = 0x0001 @@ -22,25 +11,3 @@ const ( // GRND_RANDOM means use the /dev/random pool instead of /dev/urandom. GRND_RANDOM GetRandomFlag = 0x0002 ) - -// GetRandom calls the Linux getrandom system call. -// See https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=c6e9d6f38894798696f23c8084ca7edbf16ee895 -func GetRandom(p []byte, flags GetRandomFlag) (n int, err error) { - if len(p) == 0 { - return 0, nil - } - if atomic.LoadInt32(&randomUnsupported) != 0 { - return 0, syscall.ENOSYS - } - r1, _, errno := syscall.Syscall(getrandomTrap, - uintptr(unsafe.Pointer(&p[0])), - uintptr(len(p)), - uintptr(flags)) - if errno != 0 { - if errno == syscall.ENOSYS { - atomic.StoreInt32(&randomUnsupported, 1) - } - return 0, errno - } - return int(r1), nil -} diff --git a/libgo/go/internal/syscall/unix/getrandom_solaris.go b/libgo/go/internal/syscall/unix/getrandom_solaris.go new file mode 100644 index 0000000..caf9b60 --- /dev/null +++ b/libgo/go/internal/syscall/unix/getrandom_solaris.go @@ -0,0 +1,46 @@ +// 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. + +package unix + +import ( + "sync/atomic" + "syscall" + "unsafe" +) + +//extern getrandom +func libc_getrandom(*byte, uintptr, uint32) uintptr + +// GetRandomFlag is a flag supported by the getrandom system call. +type GetRandomFlag uintptr + +const ( + // GRND_NONBLOCK means return EAGAIN rather than blocking. + GRND_NONBLOCK GetRandomFlag = 0x0001 + + // GRND_RANDOM means use the /dev/random pool instead of /dev/urandom. + GRND_RANDOM GetRandomFlag = 0x0002 +) + +// GetRandom calls the getrandom system call. +func GetRandom(p []byte, flags GetRandomFlag) (n int, err error) { + if len(p) == 0 { + return 0, nil + } + if atomic.LoadInt32(&getrandomUnsupported) != 0 { + return 0, syscall.ENOSYS + } + syscall.Entersyscall() + r1 := libc_getrandom(&p[0], uintptr(len(p)), uint32(flags)) + syscall.Exitsyscall() + if r1 == 0 { + errno := syscall.GetErrno() + if errno == syscall.ENOSYS { + atomic.StoreInt32(&getrandomUnsupported, 1) + } + return 0, errno + } + return int(r1), nil +} diff --git a/libgo/go/internal/syscall/unix/nonblocking.go b/libgo/go/internal/syscall/unix/nonblocking.go index 1734cdc..dc2e107 100644 --- a/libgo/go/internal/syscall/unix/nonblocking.go +++ b/libgo/go/internal/syscall/unix/nonblocking.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build dragonfly || freebsd || hurd || linux || netbsd || openbsd // +build dragonfly freebsd hurd linux netbsd openbsd package unix diff --git a/libgo/go/internal/syscall/unix/nonblocking_js.go b/libgo/go/internal/syscall/unix/nonblocking_js.go index a360b53..a5a5080 100644 --- a/libgo/go/internal/syscall/unix/nonblocking_js.go +++ b/libgo/go/internal/syscall/unix/nonblocking_js.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build js && wasm // +build js,wasm package unix diff --git a/libgo/go/internal/syscall/unix/nonblocking_libc.go b/libgo/go/internal/syscall/unix/nonblocking_libc.go index 464314d..876fb16 100644 --- a/libgo/go/internal/syscall/unix/nonblocking_libc.go +++ b/libgo/go/internal/syscall/unix/nonblocking_libc.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || solaris // +build aix darwin solaris package unix diff --git a/libgo/go/internal/syscall/unix/sysnum_linux_generic.go b/libgo/go/internal/syscall/unix/sysnum_linux_generic.go index 3d34fdb..d8db1bb 100644 --- a/libgo/go/internal/syscall/unix/sysnum_linux_generic.go +++ b/libgo/go/internal/syscall/unix/sysnum_linux_generic.go @@ -2,8 +2,9 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build linux && (arm64 || riscv64 || arm64be || nios2 || riscv) // +build linux -// +build arm64 arm64be nios2 riscv riscv64 +// +build arm64 riscv64 arm64be nios2 riscv package unix diff --git a/libgo/go/internal/syscall/unix/sysnum_linux_mips64x.go b/libgo/go/internal/syscall/unix/sysnum_linux_mips64x.go index 6680942..f353d4d 100644 --- a/libgo/go/internal/syscall/unix/sysnum_linux_mips64x.go +++ b/libgo/go/internal/syscall/unix/sysnum_linux_mips64x.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build mips64 || mips64le // +build mips64 mips64le package unix diff --git a/libgo/go/internal/syscall/unix/sysnum_linux_mipsx.go b/libgo/go/internal/syscall/unix/sysnum_linux_mipsx.go index 185d832..4ed4715 100644 --- a/libgo/go/internal/syscall/unix/sysnum_linux_mipsx.go +++ b/libgo/go/internal/syscall/unix/sysnum_linux_mipsx.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build mips || mipsle // +build mips mipsle package unix diff --git a/libgo/go/internal/syscall/unix/sysnum_linux_ppc64x.go b/libgo/go/internal/syscall/unix/sysnum_linux_ppc64x.go index aa2e81a..5befa08 100644 --- a/libgo/go/internal/syscall/unix/sysnum_linux_ppc64x.go +++ b/libgo/go/internal/syscall/unix/sysnum_linux_ppc64x.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ppc || ppc64 || ppc64le // +build ppc ppc64 ppc64le package unix diff --git a/libgo/go/internal/testenv/testenv_cgo.go b/libgo/go/internal/testenv/testenv_cgo.go index e3d4d16..02f08f5 100644 --- a/libgo/go/internal/testenv/testenv_cgo.go +++ b/libgo/go/internal/testenv/testenv_cgo.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build cgo // +build cgo package testenv diff --git a/libgo/go/internal/testenv/testenv_notwin.go b/libgo/go/internal/testenv/testenv_notwin.go index ccb5d55..846ec93 100644 --- a/libgo/go/internal/testenv/testenv_notwin.go +++ b/libgo/go/internal/testenv/testenv_notwin.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !windows // +build !windows package testenv diff --git a/libgo/go/internal/trace/parser.go b/libgo/go/internal/trace/parser.go index c371ff3..254f201 100644 --- a/libgo/go/internal/trace/parser.go +++ b/libgo/go/internal/trace/parser.go @@ -1042,8 +1042,8 @@ const ( EvGoSysBlock = 30 // syscall blocks [timestamp] EvGoWaiting = 31 // denotes that goroutine is blocked when tracing starts [timestamp, goroutine id] EvGoInSyscall = 32 // denotes that goroutine is in syscall when tracing starts [timestamp, goroutine id] - EvHeapAlloc = 33 // memstats.heap_live change [timestamp, heap_alloc] - EvNextGC = 34 // memstats.next_gc change [timestamp, next_gc] + EvHeapAlloc = 33 // gcController.heapLive change [timestamp, heap live bytes] + EvHeapGoal = 34 // gcController.heapGoal change [timestamp, heap goal bytes] EvTimerGoroutine = 35 // denotes timer goroutine [timer goroutine id] EvFutileWakeup = 36 // denotes that the previous wakeup of this goroutine was futile [timestamp] EvString = 37 // string dictionary entry [ID, length, string] @@ -1102,7 +1102,7 @@ var EventDescriptions = [EvCount]struct { EvGoWaiting: {"GoWaiting", 1005, false, []string{"g"}, nil}, EvGoInSyscall: {"GoInSyscall", 1005, false, []string{"g"}, nil}, EvHeapAlloc: {"HeapAlloc", 1005, false, []string{"mem"}, nil}, - EvNextGC: {"NextGC", 1005, false, []string{"mem"}, nil}, + EvHeapGoal: {"HeapGoal", 1005, false, []string{"mem"}, nil}, EvTimerGoroutine: {"TimerGoroutine", 1005, false, []string{"g"}, nil}, // in 1.5 format it was {"g", "unused"} EvFutileWakeup: {"FutileWakeup", 1005, false, []string{}, nil}, EvString: {"String", 1007, false, []string{}, nil}, |