Home | History | Annotate | Download | only in runtime
      1 // Copyright 2014 The Go Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style
      3 // license that can be found in the LICENSE file.
      4 
      5 package runtime
      6 
      7 import "unsafe"
      8 
      9 const (
     10 	c0 = uintptr((8-ptrSize)/4*2860486313 + (ptrSize-4)/4*33054211828000289)
     11 	c1 = uintptr((8-ptrSize)/4*3267000013 + (ptrSize-4)/4*23344194077549503)
     12 )
     13 
     14 // type algorithms - known to compiler
     15 const (
     16 	alg_MEM = iota
     17 	alg_MEM0
     18 	alg_MEM8
     19 	alg_MEM16
     20 	alg_MEM32
     21 	alg_MEM64
     22 	alg_MEM128
     23 	alg_NOEQ
     24 	alg_NOEQ0
     25 	alg_NOEQ8
     26 	alg_NOEQ16
     27 	alg_NOEQ32
     28 	alg_NOEQ64
     29 	alg_NOEQ128
     30 	alg_STRING
     31 	alg_INTER
     32 	alg_NILINTER
     33 	alg_SLICE
     34 	alg_FLOAT32
     35 	alg_FLOAT64
     36 	alg_CPLX64
     37 	alg_CPLX128
     38 	alg_max
     39 )
     40 
     41 // typeAlg is also copied/used in reflect/type.go.
     42 // keep them in sync.
     43 type typeAlg struct {
     44 	// function for hashing objects of this type
     45 	// (ptr to object, seed) -> hash
     46 	hash func(unsafe.Pointer, uintptr) uintptr
     47 	// function for comparing objects of this type
     48 	// (ptr to object A, ptr to object B) -> ==?
     49 	equal func(unsafe.Pointer, unsafe.Pointer) bool
     50 }
     51 
     52 func memhash0(p unsafe.Pointer, h uintptr) uintptr {
     53 	return h
     54 }
     55 func memhash8(p unsafe.Pointer, h uintptr) uintptr {
     56 	return memhash(p, h, 1)
     57 }
     58 func memhash16(p unsafe.Pointer, h uintptr) uintptr {
     59 	return memhash(p, h, 2)
     60 }
     61 func memhash32(p unsafe.Pointer, h uintptr) uintptr {
     62 	return memhash(p, h, 4)
     63 }
     64 func memhash64(p unsafe.Pointer, h uintptr) uintptr {
     65 	return memhash(p, h, 8)
     66 }
     67 func memhash128(p unsafe.Pointer, h uintptr) uintptr {
     68 	return memhash(p, h, 16)
     69 }
     70 
     71 // memhash_varlen is defined in assembly because it needs access
     72 // to the closure.  It appears here to provide an argument
     73 // signature for the assembly routine.
     74 func memhash_varlen(p unsafe.Pointer, h uintptr) uintptr
     75 
     76 var algarray = [alg_max]typeAlg{
     77 	alg_MEM:      {nil, nil}, // not used
     78 	alg_MEM0:     {memhash0, memequal0},
     79 	alg_MEM8:     {memhash8, memequal8},
     80 	alg_MEM16:    {memhash16, memequal16},
     81 	alg_MEM32:    {memhash32, memequal32},
     82 	alg_MEM64:    {memhash64, memequal64},
     83 	alg_MEM128:   {memhash128, memequal128},
     84 	alg_NOEQ:     {nil, nil},
     85 	alg_NOEQ0:    {nil, nil},
     86 	alg_NOEQ8:    {nil, nil},
     87 	alg_NOEQ16:   {nil, nil},
     88 	alg_NOEQ32:   {nil, nil},
     89 	alg_NOEQ64:   {nil, nil},
     90 	alg_NOEQ128:  {nil, nil},
     91 	alg_STRING:   {strhash, strequal},
     92 	alg_INTER:    {interhash, interequal},
     93 	alg_NILINTER: {nilinterhash, nilinterequal},
     94 	alg_SLICE:    {nil, nil},
     95 	alg_FLOAT32:  {f32hash, f32equal},
     96 	alg_FLOAT64:  {f64hash, f64equal},
     97 	alg_CPLX64:   {c64hash, c64equal},
     98 	alg_CPLX128:  {c128hash, c128equal},
     99 }
    100 
    101 var useAeshash bool
    102 
    103 // in asm_*.s
    104 func aeshash(p unsafe.Pointer, h, s uintptr) uintptr
    105 func aeshash32(p unsafe.Pointer, h uintptr) uintptr
    106 func aeshash64(p unsafe.Pointer, h uintptr) uintptr
    107 func aeshashstr(p unsafe.Pointer, h uintptr) uintptr
    108 
    109 func strhash(a unsafe.Pointer, h uintptr) uintptr {
    110 	x := (*stringStruct)(a)
    111 	return memhash(x.str, h, uintptr(x.len))
    112 }
    113 
    114 // NOTE: Because NaN != NaN, a map can contain any
    115 // number of (mostly useless) entries keyed with NaNs.
    116 // To avoid long hash chains, we assign a random number
    117 // as the hash value for a NaN.
    118 
    119 func f32hash(p unsafe.Pointer, h uintptr) uintptr {
    120 	f := *(*float32)(p)
    121 	switch {
    122 	case f == 0:
    123 		return c1 * (c0 ^ h) // +0, -0
    124 	case f != f:
    125 		return c1 * (c0 ^ h ^ uintptr(fastrand1())) // any kind of NaN
    126 	default:
    127 		return memhash(p, h, 4)
    128 	}
    129 }
    130 
    131 func f64hash(p unsafe.Pointer, h uintptr) uintptr {
    132 	f := *(*float64)(p)
    133 	switch {
    134 	case f == 0:
    135 		return c1 * (c0 ^ h) // +0, -0
    136 	case f != f:
    137 		return c1 * (c0 ^ h ^ uintptr(fastrand1())) // any kind of NaN
    138 	default:
    139 		return memhash(p, h, 8)
    140 	}
    141 }
    142 
    143 func c64hash(p unsafe.Pointer, h uintptr) uintptr {
    144 	x := (*[2]float32)(p)
    145 	return f32hash(unsafe.Pointer(&x[1]), f32hash(unsafe.Pointer(&x[0]), h))
    146 }
    147 
    148 func c128hash(p unsafe.Pointer, h uintptr) uintptr {
    149 	x := (*[2]float64)(p)
    150 	return f64hash(unsafe.Pointer(&x[1]), f64hash(unsafe.Pointer(&x[0]), h))
    151 }
    152 
    153 func interhash(p unsafe.Pointer, h uintptr) uintptr {
    154 	a := (*iface)(p)
    155 	tab := a.tab
    156 	if tab == nil {
    157 		return h
    158 	}
    159 	t := tab._type
    160 	fn := t.alg.hash
    161 	if fn == nil {
    162 		panic(errorString("hash of unhashable type " + *t._string))
    163 	}
    164 	if isDirectIface(t) {
    165 		return c1 * fn(unsafe.Pointer(&a.data), h^c0)
    166 	} else {
    167 		return c1 * fn(a.data, h^c0)
    168 	}
    169 }
    170 
    171 func nilinterhash(p unsafe.Pointer, h uintptr) uintptr {
    172 	a := (*eface)(p)
    173 	t := a._type
    174 	if t == nil {
    175 		return h
    176 	}
    177 	fn := t.alg.hash
    178 	if fn == nil {
    179 		panic(errorString("hash of unhashable type " + *t._string))
    180 	}
    181 	if isDirectIface(t) {
    182 		return c1 * fn(unsafe.Pointer(&a.data), h^c0)
    183 	} else {
    184 		return c1 * fn(a.data, h^c0)
    185 	}
    186 }
    187 
    188 func memequal(p, q unsafe.Pointer, size uintptr) bool {
    189 	if p == q {
    190 		return true
    191 	}
    192 	return memeq(p, q, size)
    193 }
    194 
    195 func memequal0(p, q unsafe.Pointer) bool {
    196 	return true
    197 }
    198 func memequal8(p, q unsafe.Pointer) bool {
    199 	return *(*int8)(p) == *(*int8)(q)
    200 }
    201 func memequal16(p, q unsafe.Pointer) bool {
    202 	return *(*int16)(p) == *(*int16)(q)
    203 }
    204 func memequal32(p, q unsafe.Pointer) bool {
    205 	return *(*int32)(p) == *(*int32)(q)
    206 }
    207 func memequal64(p, q unsafe.Pointer) bool {
    208 	return *(*int64)(p) == *(*int64)(q)
    209 }
    210 func memequal128(p, q unsafe.Pointer) bool {
    211 	return *(*[2]int64)(p) == *(*[2]int64)(q)
    212 }
    213 func f32equal(p, q unsafe.Pointer) bool {
    214 	return *(*float32)(p) == *(*float32)(q)
    215 }
    216 func f64equal(p, q unsafe.Pointer) bool {
    217 	return *(*float64)(p) == *(*float64)(q)
    218 }
    219 func c64equal(p, q unsafe.Pointer) bool {
    220 	return *(*complex64)(p) == *(*complex64)(q)
    221 }
    222 func c128equal(p, q unsafe.Pointer) bool {
    223 	return *(*complex128)(p) == *(*complex128)(q)
    224 }
    225 func strequal(p, q unsafe.Pointer) bool {
    226 	return *(*string)(p) == *(*string)(q)
    227 }
    228 func interequal(p, q unsafe.Pointer) bool {
    229 	return ifaceeq(*(*interface {
    230 		f()
    231 	})(p), *(*interface {
    232 		f()
    233 	})(q))
    234 }
    235 func nilinterequal(p, q unsafe.Pointer) bool {
    236 	return efaceeq(*(*interface{})(p), *(*interface{})(q))
    237 }
    238 func efaceeq(p, q interface{}) bool {
    239 	x := (*eface)(unsafe.Pointer(&p))
    240 	y := (*eface)(unsafe.Pointer(&q))
    241 	t := x._type
    242 	if t != y._type {
    243 		return false
    244 	}
    245 	if t == nil {
    246 		return true
    247 	}
    248 	eq := t.alg.equal
    249 	if eq == nil {
    250 		panic(errorString("comparing uncomparable type " + *t._string))
    251 	}
    252 	if isDirectIface(t) {
    253 		return eq(noescape(unsafe.Pointer(&x.data)), noescape(unsafe.Pointer(&y.data)))
    254 	}
    255 	return eq(x.data, y.data)
    256 }
    257 func ifaceeq(p, q interface {
    258 	f()
    259 }) bool {
    260 	x := (*iface)(unsafe.Pointer(&p))
    261 	y := (*iface)(unsafe.Pointer(&q))
    262 	xtab := x.tab
    263 	if xtab != y.tab {
    264 		return false
    265 	}
    266 	if xtab == nil {
    267 		return true
    268 	}
    269 	t := xtab._type
    270 	eq := t.alg.equal
    271 	if eq == nil {
    272 		panic(errorString("comparing uncomparable type " + *t._string))
    273 	}
    274 	if isDirectIface(t) {
    275 		return eq(noescape(unsafe.Pointer(&x.data)), noescape(unsafe.Pointer(&y.data)))
    276 	}
    277 	return eq(x.data, y.data)
    278 }
    279 
    280 // Testing adapters for hash quality tests (see hash_test.go)
    281 func stringHash(s string, seed uintptr) uintptr {
    282 	return algarray[alg_STRING].hash(noescape(unsafe.Pointer(&s)), seed)
    283 }
    284 
    285 func bytesHash(b []byte, seed uintptr) uintptr {
    286 	s := (*slice)(unsafe.Pointer(&b))
    287 	return memhash(s.array, seed, uintptr(s.len))
    288 }
    289 
    290 func int32Hash(i uint32, seed uintptr) uintptr {
    291 	return algarray[alg_MEM32].hash(noescape(unsafe.Pointer(&i)), seed)
    292 }
    293 
    294 func int64Hash(i uint64, seed uintptr) uintptr {
    295 	return algarray[alg_MEM64].hash(noescape(unsafe.Pointer(&i)), seed)
    296 }
    297 
    298 func efaceHash(i interface{}, seed uintptr) uintptr {
    299 	return algarray[alg_NILINTER].hash(noescape(unsafe.Pointer(&i)), seed)
    300 }
    301 
    302 func ifaceHash(i interface {
    303 	F()
    304 }, seed uintptr) uintptr {
    305 	return algarray[alg_INTER].hash(noescape(unsafe.Pointer(&i)), seed)
    306 }
    307 
    308 // Testing adapter for memclr
    309 func memclrBytes(b []byte) {
    310 	s := (*slice)(unsafe.Pointer(&b))
    311 	memclr(s.array, uintptr(s.len))
    312 }
    313 
    314 const hashRandomBytes = ptrSize / 4 * 64
    315 
    316 // used in asm_{386,amd64}.s to seed the hash function
    317 var aeskeysched [hashRandomBytes]byte
    318 
    319 // used in hash{32,64}.go to seed the hash function
    320 var hashkey [4]uintptr
    321 
    322 func init() {
    323 	// Install aes hash algorithm if we have the instructions we need
    324 	if (GOARCH == "386" || GOARCH == "amd64") &&
    325 		GOOS != "nacl" &&
    326 		cpuid_ecx&(1<<25) != 0 && // aes (aesenc)
    327 		cpuid_ecx&(1<<9) != 0 && // sse3 (pshufb)
    328 		cpuid_ecx&(1<<19) != 0 { // sse4.1 (pinsr{d,q})
    329 		useAeshash = true
    330 		algarray[alg_MEM32].hash = aeshash32
    331 		algarray[alg_MEM64].hash = aeshash64
    332 		algarray[alg_STRING].hash = aeshashstr
    333 		// Initialize with random data so hash collisions will be hard to engineer.
    334 		getRandomData(aeskeysched[:])
    335 		return
    336 	}
    337 	getRandomData((*[len(hashkey) * ptrSize]byte)(unsafe.Pointer(&hashkey))[:])
    338 	hashkey[0] |= 1 // make sure this number is odd
    339 }
    340