1
0
mirror of https://github.com/golang/go synced 2024-10-05 16:41:21 -06:00
go/src/pkg/runtime/alg.go

285 lines
7.1 KiB
Go
Raw Normal View History

// Copyright 2014 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 runtime
import "unsafe"
const (
c0 = uintptr((8-uint64(ptrSize))/4*2860486313 + (uint64(ptrSize)-4)/4*33054211828000289)
c1 = uintptr((8-uint64(ptrSize))/4*3267000013 + (uint64(ptrSize)-4)/4*23344194077549503)
)
const (
alg_MEM = iota
alg_MEM0
alg_MEM8
alg_MEM16
alg_MEM32
alg_MEM64
alg_MEM128
alg_NOEQ
alg_NOEQ0
alg_NOEQ8
alg_NOEQ16
alg_NOEQ32
alg_NOEQ64
alg_NOEQ128
alg_STRING
alg_INTER
alg_NILINTER
alg_SLICE
alg_FLOAT32
alg_FLOAT64
alg_CPLX64
alg_CPLX128
alg_max
)
const nacl = GOOS == "nacl"
var use_aeshash bool
// in asm_*.s
func aeshash(p unsafe.Pointer, s, h uintptr) uintptr
cmd/cc, runtime: convert C compilers to use Go calling convention To date, the C compilers and Go compilers differed only in how values were returned from functions. This made it difficult to call Go from C or C from Go if return values were involved. It also made assembly called from Go and assembly called from C different. This CL changes the C compiler to use the Go conventions, passing results on the stack, after the arguments. [Exception: this does not apply to C ... functions, because you can't know where on the stack the arguments end.] By doing this, the CL makes it possible to rewrite C functions into Go one at a time, without worrying about which languages call that function or which languages it calls. This CL also updates all the assembly files in package runtime to use the new conventions. Argument references of the form 40(SP) have been rewritten to the form name+10(FP) instead, and there are now Go func prototypes for every assembly function called from C or Go. This means that 'go vet runtime' checks effectively every assembly function, and go vet's output was used to automate the bulk of the conversion. Some functions, like seek and nsec on Plan 9, needed to be rewritten. Many assembly routines called from C were reading arguments incorrectly, using MOVL instead of MOVQ or vice versa, especially on the less used systems like openbsd. These were found by go vet and have been corrected too. If we're lucky, this may reduce flakiness on those systems. Tested on: darwin/386 darwin/amd64 linux/arm linux/386 linux/amd64 If this breaks another system, the bug is almost certainly in the sys_$GOOS_$GOARCH.s file, since the rest of the CL is tested by the combination of the above systems. LGTM=dvyukov, iant R=golang-codereviews, 0intro, dave, alex.brainman, dvyukov, iant CC=golang-codereviews, josharian, r https://golang.org/cl/135830043
2014-08-27 09:32:17 -06:00
func aeshash32(p unsafe.Pointer, s, h uintptr) uintptr
func aeshash64(p unsafe.Pointer, s, h uintptr) uintptr
func aeshashstr(p unsafe.Pointer, s, h uintptr) uintptr
func memhash(p unsafe.Pointer, s, h uintptr) uintptr {
if !nacl && use_aeshash {
return aeshash(p, s, h)
}
h ^= c0
for s > 0 {
h = (h ^ uintptr(*(*byte)(p))) * c1
p = add(p, 1)
s--
}
return h
}
func strhash(a *string, s, h uintptr) uintptr {
return memhash((*stringStruct)(unsafe.Pointer(a)).str, uintptr(len(*a)), h)
}
// NOTE: Because NaN != NaN, a map can contain any
// number of (mostly useless) entries keyed with NaNs.
// To avoid long hash chains, we assign a random number
// as the hash value for a NaN.
func f32hash(a *float32, s, h uintptr) uintptr {
f := *a
switch {
case f == 0:
return c1 * (c0 ^ h) // +0, -0
case f != f:
return c1 * (c0 ^ h ^ uintptr(fastrand2())) // any kind of NaN
default:
return memhash(unsafe.Pointer(a), 4, h)
}
}
func f64hash(a *float64, s, h uintptr) uintptr {
f := *a
switch {
case f == 0:
return c1 * (c0 ^ h) // +0, -0
case f != f:
return c1 * (c0 ^ h ^ uintptr(fastrand2())) // any kind of NaN
default:
return memhash(unsafe.Pointer(a), 8, h)
}
}
func c64hash(a *complex64, s, h uintptr) uintptr {
x := (*[2]float32)(unsafe.Pointer(a))
return f32hash(&x[1], 4, f32hash(&x[0], 4, h))
}
func c128hash(a *complex128, s, h uintptr) uintptr {
x := (*[2]float64)(unsafe.Pointer(a))
return f64hash(&x[1], 4, f64hash(&x[0], 4, h))
}
func nohash(a unsafe.Pointer, s, h uintptr) uintptr {
panic(errorString("hash of unhashable type"))
}
func interhash(a *iface, s, h uintptr) uintptr {
tab := a.tab
if tab == nil {
return h
}
t := tab._type
fn := goalg(t.alg).hash
if **(**uintptr)(unsafe.Pointer(&fn)) == nohashcode {
// calling nohash will panic too,
// but we can print a better error.
panic(errorString("hash of unhashable type " + *t._string))
}
if isDirectIface(t) {
return c1 * fn(unsafe.Pointer(&a.data), uintptr(t.size), h^c0)
} else {
return c1 * fn(a.data, uintptr(t.size), h^c0)
}
}
func nilinterhash(a *eface, s, h uintptr) uintptr {
t := a._type
if t == nil {
return h
}
fn := goalg(t.alg).hash
if **(**uintptr)(unsafe.Pointer(&fn)) == nohashcode {
// calling nohash will panic too,
// but we can print a better error.
panic(errorString("hash of unhashable type " + *t._string))
}
if isDirectIface(t) {
return c1 * fn(unsafe.Pointer(&a.data), uintptr(t.size), h^c0)
} else {
return c1 * fn(a.data, uintptr(t.size), h^c0)
}
}
func memequal(p, q unsafe.Pointer, size uintptr) bool {
if p == q {
return true
}
return memeq(p, q, size)
}
func memequal0(p, q unsafe.Pointer, size uintptr) bool {
return true
}
func memequal8(p, q unsafe.Pointer, size uintptr) bool {
return *(*int8)(p) == *(*int8)(q)
}
func memequal16(p, q unsafe.Pointer, size uintptr) bool {
return *(*int16)(p) == *(*int16)(q)
}
func memequal32(p, q unsafe.Pointer, size uintptr) bool {
return *(*int32)(p) == *(*int32)(q)
}
func memequal64(p, q unsafe.Pointer, size uintptr) bool {
return *(*int64)(p) == *(*int64)(q)
}
func memequal128(p, q unsafe.Pointer, size uintptr) bool {
return *(*[2]int64)(p) == *(*[2]int64)(q)
}
func f32equal(p, q unsafe.Pointer, size uintptr) bool {
return *(*float32)(p) == *(*float32)(q)
}
func f64equal(p, q unsafe.Pointer, size uintptr) bool {
return *(*float64)(p) == *(*float64)(q)
}
func c64equal(p, q unsafe.Pointer, size uintptr) bool {
return *(*complex64)(p) == *(*complex64)(q)
}
func c128equal(p, q unsafe.Pointer, size uintptr) bool {
return *(*complex128)(p) == *(*complex128)(q)
}
func strequal(p, q unsafe.Pointer, size uintptr) bool {
return *(*string)(p) == *(*string)(q)
}
func interequal(p, q unsafe.Pointer, size uintptr) bool {
return ifaceeq(*(*interface {
f()
})(p), *(*interface {
f()
})(q))
}
func nilinterequal(p, q unsafe.Pointer, size uintptr) bool {
return efaceeq(*(*interface{})(p), *(*interface{})(q))
}
func efaceeq(p, q interface{}) bool {
x := (*eface)(unsafe.Pointer(&p))
y := (*eface)(unsafe.Pointer(&q))
t := x._type
if t != y._type {
return false
}
if t == nil {
return true
}
eq := goalg(t.alg).equal
if **(**uintptr)(unsafe.Pointer(&eq)) == noequalcode {
// calling noequal will panic too,
// but we can print a better error.
panic(errorString("comparing uncomparable type " + *t._string))
}
if isDirectIface(t) {
return eq(noescape(unsafe.Pointer(&x.data)), noescape(unsafe.Pointer(&y.data)), uintptr(t.size))
}
return eq(x.data, y.data, uintptr(t.size))
}
func ifaceeq(p, q interface {
f()
}) bool {
x := (*iface)(unsafe.Pointer(&p))
y := (*iface)(unsafe.Pointer(&q))
xtab := x.tab
if xtab != y.tab {
return false
}
if xtab == nil {
return true
}
t := xtab._type
eq := goalg(t.alg).equal
if **(**uintptr)(unsafe.Pointer(&eq)) == noequalcode {
// calling noequal will panic too,
// but we can print a better error.
panic(errorString("comparing uncomparable type " + *t._string))
}
if isDirectIface(t) {
return eq(noescape(unsafe.Pointer(&x.data)), noescape(unsafe.Pointer(&y.data)), uintptr(t.size))
}
return eq(x.data, y.data, uintptr(t.size))
}
func noequal(p, q unsafe.Pointer, size uintptr) bool {
panic(errorString("comparing uncomparable types"))
}
// Testing adapters for hash quality tests (see hash_test.go)
func haveGoodHash() bool {
return use_aeshash
}
func stringHash(s string, seed uintptr) uintptr {
return goalg(&algarray[alg_STRING]).hash(noescape(unsafe.Pointer(&s)), unsafe.Sizeof(s), seed)
}
func bytesHash(b []byte, seed uintptr) uintptr {
// TODO: use sliceStruct
return goalg(&algarray[alg_MEM]).hash(*(*unsafe.Pointer)(unsafe.Pointer(&b)), uintptr(len(b)), seed)
}
func int32Hash(i uint32, seed uintptr) uintptr {
return goalg(&algarray[alg_MEM32]).hash(noescape(unsafe.Pointer(&i)), 4, seed)
}
func int64Hash(i uint64, seed uintptr) uintptr {
return goalg(&algarray[alg_MEM64]).hash(noescape(unsafe.Pointer(&i)), 8, seed)
}
func efaceHash(i interface{}, seed uintptr) uintptr {
return goalg(&algarray[alg_NILINTER]).hash(noescape(unsafe.Pointer(&i)), unsafe.Sizeof(i), seed)
}
func ifaceHash(i interface {
F()
}, seed uintptr) uintptr {
return goalg(&algarray[alg_INTER]).hash(noescape(unsafe.Pointer(&i)), unsafe.Sizeof(i), seed)
}
// Testing adapter for memclr
func memclrBytes(b []byte) {
s := (*sliceStruct)(unsafe.Pointer(&b))
memclr(s.array, uintptr(s.len))
}