runtime: put runtime.fastrand back temporarily

Callers should be using math/rand/v2.Uint64 instead,
but there are lots of linkname references to runtime.fastrand
in public code. If we break it all now, that will require people
to use //go:build tags to use rand/v2.Uint64 with Go 1.22
and keep using the linkname for earlier versions.
Instead, leave the linkname working and then we can remove
it in Go 1.24, at which point everyone should be able to use
math/rand/v2.Uint64 unconditionally.

Change-Id: I7287ca4f67c270b009562313661cc28a4c2219a4
Reviewed-on: https://go-review.googlesource.com/c/go/+/548235
Reviewed-by: Michael Pratt <mpratt@google.com>
Reviewed-by: David Chase <drchase@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Cherry Mui <cherryyz@google.com>
Auto-Submit: Russ Cox <rsc@golang.org>
This commit is contained in:
Russ Cox 2023-12-07 11:11:01 -05:00 committed by Gopher Robot
parent e1c0349a7c
commit dca2ef2361
2 changed files with 55 additions and 0 deletions

View file

@ -223,3 +223,25 @@ func cheaprandn(n uint32) uint32 {
// See https://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction/
return uint32((uint64(cheaprand()) * uint64(n)) >> 32)
}
// Too much legacy code has go:linkname references
// to runtime.fastrand and friends, so keep these around for now.
// Code should migrate to math/rand/v2.Uint64,
// which is just as fast, but that's only available in Go 1.22+.
// It would be reasonable to remove these in Go 1.24.
// Do not call these from package runtime.
//go:linkname legacy_fastrand runtime.fastrand
func legacy_fastrand() uint32 {
return uint32(rand())
}
//go:linkname legacy_fastrandn runtime.fastrandn
func legacy_fastrandn(n uint32) uint32 {
return randn(n)
}
//go:linkname legacy_fastrand64 runtime.fastrand64
func legacy_fastrand64() uint64 {
return rand()
}

View file

@ -8,6 +8,7 @@ import (
. "runtime"
"strconv"
"testing"
_ "unsafe" // for go:linkname
)
func TestReadRandom(t *testing.T) {
@ -62,3 +63,35 @@ func BenchmarkFastrandn(b *testing.B) {
})
}
}
//go:linkname fastrand runtime.fastrand
func fastrand() uint32
//go:linkname fastrandn runtime.fastrandn
func fastrandn(uint32) uint32
//go:linkname fastrand64 runtime.fastrand64
func fastrand64() uint64
func TestLegacyFastrand(t *testing.T) {
// Testing mainly that the calls work at all,
// but check that all three don't return the same number (1 in 2^64 chance)
{
x, y, z := fastrand(), fastrand(), fastrand()
if x == y && y == z {
t.Fatalf("fastrand three times = %#x, %#x, %#x, want different numbers", x, y, z)
}
}
{
x, y, z := fastrandn(1e9), fastrandn(1e9), fastrandn(1e9)
if x == y && y == z {
t.Fatalf("fastrandn three times = %#x, %#x, %#x, want different numbers", x, y, z)
}
}
{
x, y, z := fastrand64(), fastrand64(), fastrand64()
if x == y && y == z {
t.Fatalf("fastrand64 three times = %#x, %#x, %#x, want different numbers", x, y, z)
}
}
}