github.com/reiver/go@v0.0.0-20150109200633-1d0c7792f172/src/runtime/alg.go (about)

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