From cf6cc937efdd3a18884c54bf185882d6eb826ac6 Mon Sep 17 00:00:00 2001 From: xgopilot Date: Tue, 14 Oct 2025 07:04:42 +0000 Subject: [PATCH 1/8] fix: add runtime.rand and runtime.memhash for hash/maphash support - Register hash/maphash in hasAltPkg map in runtime/build.go - Add rand() function that bridges to fastrand64() in runtime overlay - Add memhash() function that bridges to internal memhash() in runtime overlay - Fixes issue where hash/maphash package failed with undefined symbols Fixes #1338 Generated with [codeagent](https://github.com/qbox/codeagent) Co-authored-by: luoliwoshang Co-authored-by: xgopilot --- runtime/build.go | 1 + runtime/internal/lib/runtime/runtime.go | 14 ++++++++++++++ 2 files changed, 15 insertions(+) diff --git a/runtime/build.go b/runtime/build.go index a4ac3753..32bee643 100644 --- a/runtime/build.go +++ b/runtime/build.go @@ -24,6 +24,7 @@ var hasAltPkg = map[string]none{ "crypto/subtle": {}, "go/parser": {}, "hash/crc32": {}, + "hash/maphash": {}, "internal/abi": {}, "internal/bytealg": {}, "internal/chacha8rand": {}, diff --git a/runtime/internal/lib/runtime/runtime.go b/runtime/internal/lib/runtime/runtime.go index 0defce9e..b107c605 100644 --- a/runtime/internal/lib/runtime/runtime.go +++ b/runtime/internal/lib/runtime/runtime.go @@ -56,4 +56,18 @@ func write(fd uintptr, p unsafe.Pointer, n int32) int32 { return int32(c_write(c.Int(fd), p, c.SizeT(n))) } +//go:linkname llgo_fastrand64 github.com/goplus/llgo/runtime/internal/runtime.fastrand64 +func llgo_fastrand64() uint64 + +//go:linkname llgo_memhash github.com/goplus/llgo/runtime/internal/runtime.memhash +func llgo_memhash(p unsafe.Pointer, seed, s uintptr) uintptr + +func rand() uint64 { + return llgo_fastrand64() +} + +func memhash(p unsafe.Pointer, seed, s uintptr) uintptr { + return llgo_memhash(p, seed, s) +} + const heapArenaBytes = 1024 * 1024 From 441b4b15a884638ab8d4362ce8b42e1e9db80216 Mon Sep 17 00:00:00 2001 From: xgopilot Date: Tue, 14 Oct 2025 07:11:17 +0000 Subject: [PATCH 2/8] test: add hash/maphash demo test case Add test case in _demo/go/maphash to verify hash/maphash functionality with the new runtime.rand and runtime.memhash support. Generated with [codeagent](https://github.com/qbox/codeagent) Co-authored-by: luoliwoshang Co-authored-by: xgopilot --- _demo/go/maphash/maphash.go | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 _demo/go/maphash/maphash.go diff --git a/_demo/go/maphash/maphash.go b/_demo/go/maphash/maphash.go new file mode 100644 index 00000000..44524b04 --- /dev/null +++ b/_demo/go/maphash/maphash.go @@ -0,0 +1,26 @@ +package main + +import ( + "fmt" + "hash/maphash" +) + +func main() { + var h maphash.Hash + h.WriteString("hello") + fmt.Printf("0x%x\n", h.Sum64()) + + h.Reset() + h.WriteString("world") + fmt.Printf("0x%x\n", h.Sum64()) + + h.Reset() + h.WriteString("test") + v1 := h.Sum64() + + h.Reset() + h.WriteString("test") + v2 := h.Sum64() + + fmt.Printf("0x%x == 0x%x\n", v1, v2) +} From 8aadfde64a4be4c11c1b3634460fa45e8dfb7e84 Mon Sep 17 00:00:00 2001 From: xgopilot Date: Tue, 14 Oct 2025 07:11:42 +0000 Subject: [PATCH 3/8] style: apply linter fixes to maphash test Generated with [codeagent](https://github.com/qbox/codeagent) Co-authored-by: luoliwoshang Co-authored-by: xgopilot --- _demo/go/maphash/maphash.go | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/_demo/go/maphash/maphash.go b/_demo/go/maphash/maphash.go index 44524b04..93d80032 100644 --- a/_demo/go/maphash/maphash.go +++ b/_demo/go/maphash/maphash.go @@ -8,19 +8,16 @@ import ( func main() { var h maphash.Hash h.WriteString("hello") - fmt.Printf("0x%x\n", h.Sum64()) + hash1 := h.Sum64() + fmt.Printf("0x%x\n", hash1) h.Reset() h.WriteString("world") - fmt.Printf("0x%x\n", h.Sum64()) + hash2 := h.Sum64() + fmt.Printf("0x%x\n", hash2) h.Reset() - h.WriteString("test") - v1 := h.Sum64() - - h.Reset() - h.WriteString("test") - v2 := h.Sum64() - - fmt.Printf("0x%x == 0x%x\n", v1, v2) + h.WriteString("hello") + hash3 := h.Sum64() + fmt.Printf("0x%x == 0x%x\n", hash1, hash3) } From e05c91530eb751e5c44e4cab848cdf04e748a4f6 Mon Sep 17 00:00:00 2001 From: xgopilot Date: Tue, 14 Oct 2025 08:01:10 +0000 Subject: [PATCH 4/8] refactor: move hash/maphash linkname bindings to maphash package Move runtime_rand and runtime_memhash linkname declarations from runtime/internal/lib/runtime/runtime.go to runtime/internal/lib/hash/maphash/maphash.go to avoid polluting the runtime package namespace. Generated with [codeagent](https://github.com/qbox/codeagent) Co-authored-by: luoliwoshang --- runtime/internal/lib/hash/maphash/maphash.go | 28 ++++++++++++++++++++ runtime/internal/lib/runtime/runtime.go | 14 ---------- 2 files changed, 28 insertions(+), 14 deletions(-) create mode 100644 runtime/internal/lib/hash/maphash/maphash.go diff --git a/runtime/internal/lib/hash/maphash/maphash.go b/runtime/internal/lib/hash/maphash/maphash.go new file mode 100644 index 00000000..9e00aca6 --- /dev/null +++ b/runtime/internal/lib/hash/maphash/maphash.go @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package maphash + +import "unsafe" + +// llgo:skipall +type _maphash struct{} + +//go:linkname runtime_rand github.com/goplus/llgo/runtime/internal/runtime.fastrand64 +func runtime_rand() uint64 + +//go:linkname runtime_memhash github.com/goplus/llgo/runtime/internal/runtime.memhash +func runtime_memhash(p unsafe.Pointer, seed, s uintptr) uintptr diff --git a/runtime/internal/lib/runtime/runtime.go b/runtime/internal/lib/runtime/runtime.go index b107c605..0defce9e 100644 --- a/runtime/internal/lib/runtime/runtime.go +++ b/runtime/internal/lib/runtime/runtime.go @@ -56,18 +56,4 @@ func write(fd uintptr, p unsafe.Pointer, n int32) int32 { return int32(c_write(c.Int(fd), p, c.SizeT(n))) } -//go:linkname llgo_fastrand64 github.com/goplus/llgo/runtime/internal/runtime.fastrand64 -func llgo_fastrand64() uint64 - -//go:linkname llgo_memhash github.com/goplus/llgo/runtime/internal/runtime.memhash -func llgo_memhash(p unsafe.Pointer, seed, s uintptr) uintptr - -func rand() uint64 { - return llgo_fastrand64() -} - -func memhash(p unsafe.Pointer, seed, s uintptr) uintptr { - return llgo_memhash(p, seed, s) -} - const heapArenaBytes = 1024 * 1024 From 3ce198f1033ad6463cf3f176f813f18c01bd9829 Mon Sep 17 00:00:00 2001 From: xgopilot Date: Tue, 14 Oct 2025 08:29:26 +0000 Subject: [PATCH 5/8] fix: remove llgo:skipall directive from maphash overlay The llgo:skipall directive was preventing fallback to the standard library, causing undefined symbol errors for functions like WriteString, MakeSeed, etc. The overlay now only defines the two linkname functions, allowing typepatch to handle the rest. Generated with [codeagent](https://github.com/qbox/codeagent) Co-authored-by: luoliwoshang --- runtime/internal/lib/hash/maphash/maphash.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/runtime/internal/lib/hash/maphash/maphash.go b/runtime/internal/lib/hash/maphash/maphash.go index 9e00aca6..a530004c 100644 --- a/runtime/internal/lib/hash/maphash/maphash.go +++ b/runtime/internal/lib/hash/maphash/maphash.go @@ -18,9 +18,6 @@ package maphash import "unsafe" -// llgo:skipall -type _maphash struct{} - //go:linkname runtime_rand github.com/goplus/llgo/runtime/internal/runtime.fastrand64 func runtime_rand() uint64 From e5ebc3258392e5c8b99b282cd0dcc8d103056ce3 Mon Sep 17 00:00:00 2001 From: xgopilot Date: Tue, 14 Oct 2025 09:19:55 +0000 Subject: [PATCH 6/8] fix: add randUint64 wrapper for Go 1.21 compatibility Implement randUint64() directly in the maphash overlay to ensure compatibility across Go versions. Go 1.21's randUint64() calls runtime.fastrand64, while Go 1.22+ calls runtime.rand. The wrapper function bridges to llgo's fastrand64 implementation, avoiding undefined symbol errors on Go 1.21. Generated with [codeagent](https://github.com/qbox/codeagent) Co-authored-by: luoliwoshang --- runtime/internal/lib/hash/maphash/maphash.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/runtime/internal/lib/hash/maphash/maphash.go b/runtime/internal/lib/hash/maphash/maphash.go index a530004c..c590588a 100644 --- a/runtime/internal/lib/hash/maphash/maphash.go +++ b/runtime/internal/lib/hash/maphash/maphash.go @@ -23,3 +23,7 @@ func runtime_rand() uint64 //go:linkname runtime_memhash github.com/goplus/llgo/runtime/internal/runtime.memhash func runtime_memhash(p unsafe.Pointer, seed, s uintptr) uintptr + +func randUint64() uint64 { + return runtime_rand() +} From ed3176a6ccf454683078daabf2c30ef433b91d18 Mon Sep 17 00:00:00 2001 From: xgopilot Date: Tue, 14 Oct 2025 10:18:28 +0000 Subject: [PATCH 7/8] test: expand maphash demo with comprehensive API coverage - Add tests for all major hash/maphash public APIs: * Hash basics (WriteString, Sum64, Reset) * MakeSeed and SetSeed functionality * Write methods (Write, WriteByte, WriteString) * Bytes and String convenience functions - Use panic() for unexpected errors instead of silent failures - Add proper error checking and validation - Document Comparable/WriteComparable limitations in overlay Note: Comparable() and WriteComparable() are not yet supported and will panic with 'intrinsic' error as they require runtime intrinsic support. Generated with [codeagent](https://github.com/qbox/codeagent) Co-authored-by: luoliwoshang --- _demo/go/maphash/maphash.go | 129 +++++++++++++++++-- runtime/internal/lib/hash/maphash/maphash.go | 5 + 2 files changed, 120 insertions(+), 14 deletions(-) diff --git a/_demo/go/maphash/maphash.go b/_demo/go/maphash/maphash.go index 93d80032..62231831 100644 --- a/_demo/go/maphash/maphash.go +++ b/_demo/go/maphash/maphash.go @@ -6,18 +6,119 @@ import ( ) func main() { - var h maphash.Hash - h.WriteString("hello") - hash1 := h.Sum64() - fmt.Printf("0x%x\n", hash1) - - h.Reset() - h.WriteString("world") - hash2 := h.Sum64() - fmt.Printf("0x%x\n", hash2) - - h.Reset() - h.WriteString("hello") - hash3 := h.Sum64() - fmt.Printf("0x%x == 0x%x\n", hash1, hash3) + testHashBasics() + testMakeSeed() + testSetSeed() + testWriteMethods() + testBytes() + testString() +} + +func testHashBasics() { + fmt.Println("=== Test Hash Basics ===") + var h maphash.Hash + n, err := h.WriteString("hello") + if err != nil { + panic(fmt.Sprintf("WriteString failed: %v", err)) + } + if n != 5 { + panic(fmt.Sprintf("WriteString returned %d, expected 5", n)) + } + hash1 := h.Sum64() + fmt.Printf("Hash of 'hello': 0x%x\n", hash1) + + h.Reset() + n, err = h.WriteString("world") + if err != nil { + panic(fmt.Sprintf("WriteString failed: %v", err)) + } + hash2 := h.Sum64() + fmt.Printf("Hash of 'world': 0x%x\n", hash2) + + h.Reset() + n, err = h.WriteString("hello") + if err != nil { + panic(fmt.Sprintf("WriteString failed: %v", err)) + } + hash3 := h.Sum64() + if hash1 != hash3 { + panic(fmt.Sprintf("Hash mismatch: 0x%x != 0x%x", hash1, hash3)) + } + fmt.Printf("Hash consistency verified: 0x%x == 0x%x\n", hash1, hash3) +} + +func testMakeSeed() { + fmt.Println("\n=== Test MakeSeed ===") + seed1 := maphash.MakeSeed() + seed2 := maphash.MakeSeed() + fmt.Printf("Seed 1: %v\n", seed1) + fmt.Printf("Seed 2: %v\n", seed2) + if seed1 == seed2 { + fmt.Println("Warning: Seeds are identical (rare but possible)") + } +} + +func testSetSeed() { + fmt.Println("\n=== Test SetSeed ===") + var h1, h2 maphash.Hash + seed := maphash.MakeSeed() + + h1.SetSeed(seed) + n, err := h1.WriteString("test") + if err != nil { + panic(fmt.Sprintf("WriteString failed: %v", err)) + } + hash1 := h1.Sum64() + + h2.SetSeed(seed) + n, err = h2.WriteString("test") + if err != nil { + panic(fmt.Sprintf("WriteString failed: %v", err)) + } + hash2 := h2.Sum64() + + if hash1 != hash2 { + panic(fmt.Sprintf("Hashes with same seed should match: 0x%x != 0x%x", hash1, hash2)) + } + fmt.Printf("Same seed produces same hash: 0x%x == 0x%x\n", hash1, hash2) +} + +func testWriteMethods() { + fmt.Println("\n=== Test Write Methods ===") + var h maphash.Hash + + data := []byte("hello") + n, err := h.Write(data) + if err != nil { + panic(fmt.Sprintf("Write failed: %v", err)) + } + if n != len(data) { + panic(fmt.Sprintf("Write returned %d, expected %d", n, len(data))) + } + hash1 := h.Sum64() + fmt.Printf("Hash after Write: 0x%x\n", hash1) + + h.Reset() + n, err = h.WriteByte('A') + if err != nil { + panic(fmt.Sprintf("WriteByte failed: %v", err)) + } + hash2 := h.Sum64() + fmt.Printf("Hash after WriteByte('A'): 0x%x\n", hash2) +} + +func testBytes() { + fmt.Println("\n=== Test Bytes Function ===") + seed := maphash.MakeSeed() + data := []byte("test data") + hash := maphash.Bytes(seed, data) + fmt.Printf("Bytes hash: 0x%x\n", hash) +} + +func testString() { + fmt.Println("\n=== Test String Function ===") + seed := maphash.MakeSeed() + str := "test string" + hash := maphash.String(seed, str) + fmt.Printf("String hash: 0x%x\n", hash) } diff --git a/runtime/internal/lib/hash/maphash/maphash.go b/runtime/internal/lib/hash/maphash/maphash.go index c590588a..ed490b83 100644 --- a/runtime/internal/lib/hash/maphash/maphash.go +++ b/runtime/internal/lib/hash/maphash/maphash.go @@ -18,6 +18,11 @@ package maphash import "unsafe" +// NOTE: The following functions are not yet implemented and will panic with "intrinsic": +// - Comparable(seed Seed, v any) uint64 +// - (*Hash).WriteComparable(v any) (int, error) +// These functions require runtime intrinsic support that is not currently available. + //go:linkname runtime_rand github.com/goplus/llgo/runtime/internal/runtime.fastrand64 func runtime_rand() uint64 From 2b92b527e136a8e6cd0fe15ac5a611af724675e0 Mon Sep 17 00:00:00 2001 From: xgopilot Date: Tue, 14 Oct 2025 10:33:30 +0000 Subject: [PATCH 8/8] fix: resolve compilation errors in maphash demo - Fix line 67: Change unused variable 'n' to blank identifier '_' - Fix line 102: Correct WriteByte call to expect only error return value (WriteByte returns only error, not (int, error)) These fixes resolve the compilation errors reported by the CI. Generated with [codeagent](https://github.com/qbox/codeagent) Co-authored-by: luoliwoshang --- _demo/go/maphash/maphash.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/_demo/go/maphash/maphash.go b/_demo/go/maphash/maphash.go index 62231831..a395e0a4 100644 --- a/_demo/go/maphash/maphash.go +++ b/_demo/go/maphash/maphash.go @@ -64,14 +64,14 @@ func testSetSeed() { seed := maphash.MakeSeed() h1.SetSeed(seed) - n, err := h1.WriteString("test") + _, err := h1.WriteString("test") if err != nil { panic(fmt.Sprintf("WriteString failed: %v", err)) } hash1 := h1.Sum64() h2.SetSeed(seed) - n, err = h2.WriteString("test") + _, err = h2.WriteString("test") if err != nil { panic(fmt.Sprintf("WriteString failed: %v", err)) } @@ -99,7 +99,7 @@ func testWriteMethods() { fmt.Printf("Hash after Write: 0x%x\n", hash1) h.Reset() - n, err = h.WriteByte('A') + err = h.WriteByte('A') if err != nil { panic(fmt.Sprintf("WriteByte failed: %v", err)) }