Change writeBlocks signature to avoid making xxh escape Thanks to @ongardie for the suggestion.
diff --git a/xxhash.go b/xxhash.go index f896bd2..a10d135 100644 --- a/xxhash.go +++ b/xxhash.go
@@ -83,7 +83,8 @@ if len(b) >= 32 { // One or more full blocks left. - b = writeBlocks(x, b) + nw := writeBlocks(x, b) + b = b[nw:] } // Store any remaining partial block.
diff --git a/xxhash_amd64.go b/xxhash_amd64.go index d617652..52b2686 100644 --- a/xxhash_amd64.go +++ b/xxhash_amd64.go
@@ -9,4 +9,5 @@ //go:noescape func Sum64(b []byte) uint64 -func writeBlocks(x *xxh, b []byte) []byte +//go:noescape +func writeBlocks(x *xxh, b []byte) int
diff --git a/xxhash_amd64.s b/xxhash_amd64.s index 757f201..d319fa2 100644 --- a/xxhash_amd64.s +++ b/xxhash_amd64.s
@@ -172,15 +172,14 @@ // writeBlocks uses the same registers as above except that it uses AX to store // the x pointer. -// func writeBlocks(x *xxh, b []byte) []byte -TEXT ·writeBlocks(SB), NOSPLIT, $0-56 +// func writeBlocks(x *xxh, b []byte) int +TEXT ·writeBlocks(SB), NOSPLIT, $0-40 // Load fixed primes needed for round. MOVQ ·prime1v(SB), R13 MOVQ ·prime2v(SB), R14 // Load slice. MOVQ b_base+8(FP), CX - MOVQ CX, ret_base+32(FP) // initialize return base pointer; see NOTE below MOVQ b_len+16(FP), DX LEAQ (CX)(DX*1), BX SUBQ $32, BX @@ -209,25 +208,8 @@ MOVQ R10, 16(AX) MOVQ R11, 24(AX) - // Construct return slice. - // NOTE: It's important that we don't construct a slice that has a base - // pointer off the end of the original slice, as in Go 1.7+ this will - // cause runtime crashes. (See discussion in, for example, - // https://github.com/golang/go/issues/16772.) - // Therefore, we calculate the length/cap first, and if they're zero, we - // keep the old base. This is what the compiler does as well if you - // write code like - // b = b[len(b):] - - // New length is 32 - (CX - BX) -> BX+32 - CX. - ADDQ $32, BX - SUBQ CX, BX - JZ afterSetBase - - MOVQ CX, ret_base+32(FP) - -afterSetBase: - MOVQ BX, ret_len+40(FP) - MOVQ BX, ret_cap+48(FP) // set cap == len + // The number of bytes written is CX minus the old base pointer. + SUBQ b_base+8(FP), CX + MOVQ CX, ret+32(FP) RET
diff --git a/xxhash_other.go b/xxhash_other.go index c68d13f..b16806f 100644 --- a/xxhash_other.go +++ b/xxhash_other.go
@@ -61,8 +61,9 @@ return h } -func writeBlocks(x *xxh, b []byte) []byte { +func writeBlocks(x *xxh, b []byte) int { v1, v2, v3, v4 := x.v1, x.v2, x.v3, x.v4 + n := len(b) for len(b) >= 32 { v1 = round(v1, u64(b[0:8:len(b)])) v2 = round(v2, u64(b[8:16:len(b)])) @@ -71,5 +72,5 @@ b = b[32:len(b):len(b)] } x.v1, x.v2, x.v3, x.v4 = v1, v2, v3, v4 - return b + return n - len(b) }