From f4fd79f7be3694c588cf81d7350f30e5014c7e54 Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Wed, 19 Feb 2025 15:34:18 +0100 Subject: [PATCH] runtime: manually initialize xorshift state This ensures: 1. The xorshift state is initialized during interp. 2. The xorshift state gets initialized to a real random number on hardware that supports it at runtime. This fixes a big binary size regression from the previous commit. It's still not perfect: most programs increase binary size by a few bytes. But it's not nearly as bad as before. --- builder/sizes_test.go | 4 ++-- src/runtime/algorithm.go | 6 +++--- src/runtime/runtime_wasmentry.go | 1 + src/runtime/scheduler_cooperative.go | 1 + src/runtime/scheduler_none.go | 1 + 5 files changed, 8 insertions(+), 5 deletions(-) diff --git a/builder/sizes_test.go b/builder/sizes_test.go index 8c87e2291..2b2b08fe6 100644 --- a/builder/sizes_test.go +++ b/builder/sizes_test.go @@ -43,8 +43,8 @@ func TestBinarySize(t *testing.T) { tests := []sizeTest{ // microcontrollers {"hifive1b", "examples/echo", 4560, 280, 0, 2268}, - {"microbit", "examples/serial", 2908, 388, 8, 2272}, - {"wioterminal", "examples/pininterrupt", 7293, 1487, 116, 6912}, + {"microbit", "examples/serial", 2916, 388, 8, 2272}, + {"wioterminal", "examples/pininterrupt", 7315, 1489, 116, 6912}, // TODO: also check wasm. Right now this is difficult, because // wasm binaries are run through wasm-opt and therefore the diff --git a/src/runtime/algorithm.go b/src/runtime/algorithm.go index 24571498b..d8cd1ca43 100644 --- a/src/runtime/algorithm.go +++ b/src/runtime/algorithm.go @@ -23,13 +23,13 @@ func fastrand() uint32 { return xorshift32State } -func init() { +func initRand() { r, _ := hardwareRand() xorshift64State = uint64(r | 1) // protect against 0 xorshift32State = uint32(xorshift64State) } -var xorshift32State uint32 +var xorshift32State uint32 = 1 func xorshift32(x uint32) uint32 { // Algorithm "xor" from p. 4 of Marsaglia, "Xorshift RNGs". @@ -49,7 +49,7 @@ func fastrand64() uint64 { return xorshift64State } -var xorshift64State uint64 +var xorshift64State uint64 = 1 // 64-bit xorshift multiply rng from http://vigna.di.unimi.it/ftp/papers/xorshift.pdf func xorshiftMult64(x uint64) uint64 { diff --git a/src/runtime/runtime_wasmentry.go b/src/runtime/runtime_wasmentry.go index 1d2cec6ca..807590eb7 100644 --- a/src/runtime/runtime_wasmentry.go +++ b/src/runtime/runtime_wasmentry.go @@ -35,6 +35,7 @@ func wasmEntryReactor() { heapStart = uintptr(unsafe.Pointer(&heapStartSymbol)) heapEnd = uintptr(wasm_memory_size(0) * wasmPageSize) initHeap() + initRand() if hasScheduler { // A package initializer might do funky stuff like start a goroutine and diff --git a/src/runtime/scheduler_cooperative.go b/src/runtime/scheduler_cooperative.go index 91ba86409..9f80e060c 100644 --- a/src/runtime/scheduler_cooperative.go +++ b/src/runtime/scheduler_cooperative.go @@ -247,6 +247,7 @@ func sleep(duration int64) { // With a scheduler, init and the main function are invoked in a goroutine before starting the scheduler. func run() { initHeap() + initRand() go func() { initAll() callMain() diff --git a/src/runtime/scheduler_none.go b/src/runtime/scheduler_none.go index a5acfd430..25bd7eb9c 100644 --- a/src/runtime/scheduler_none.go +++ b/src/runtime/scheduler_none.go @@ -13,6 +13,7 @@ const hasParallelism = false // With the "none" scheduler, init and the main function are invoked directly. func run() { initHeap() + initRand() initAll() callMain() mainExited = true