github.com/goplusjs/gopherjs@v1.2.6-0.20211206034512-f187917453b8/compiler/natives/src/runtime/go114_runtime.go (about)

     1  // +build js
     2  // +build go1.14
     3  
     4  package runtime
     5  
     6  import (
     7  	"runtime/internal/sys"
     8  	"unsafe"
     9  
    10  	"github.com/gopherjs/gopherjs/js"
    11  )
    12  
    13  const (
    14  	// Constants for multiplication: four random odd 32-bit numbers.
    15  	m1 = 3168982561
    16  	m2 = 3339683297
    17  	m3 = 832293441
    18  	m4 = 2336365089
    19  )
    20  
    21  func memhash(p unsafe.Pointer, seed, s uintptr) uintptr {
    22  	h := uint32(seed + s*hashkey[0])
    23  tail:
    24  	switch {
    25  	case s == 0:
    26  	case s < 4:
    27  		data := js.InternalObject(p).Interface().([]byte)
    28  		h ^= uint32(data[0])
    29  		h ^= uint32(data[1]) << 8
    30  		h ^= uint32(data[2]) << 16
    31  		h = rotl_15(h*m1) * m2
    32  	case s == 4:
    33  		h ^= readUnaligned32(p)
    34  		h = rotl_15(h*m1) * m2
    35  	case s <= 8:
    36  		h ^= readUnaligned32(p)
    37  		h = rotl_15(h*m1) * m2
    38  		h ^= readUnaligned32(add(p, s-4))
    39  		h = rotl_15(h*m1) * m2
    40  	case s <= 16:
    41  		h ^= readUnaligned32(p)
    42  		h = rotl_15(h*m1) * m2
    43  		h ^= readUnaligned32(add(p, 4))
    44  		h = rotl_15(h*m1) * m2
    45  		h ^= readUnaligned32(add(p, s-8))
    46  		h = rotl_15(h*m1) * m2
    47  		h ^= readUnaligned32(add(p, s-4))
    48  		h = rotl_15(h*m1) * m2
    49  	default:
    50  		v1 := h
    51  		v2 := uint32(seed * hashkey[1])
    52  		v3 := uint32(seed * hashkey[2])
    53  		v4 := uint32(seed * hashkey[3])
    54  		for s >= 16 {
    55  			v1 ^= readUnaligned32(p)
    56  			v1 = rotl_15(v1*m1) * m2
    57  			p = add(p, 4)
    58  			v2 ^= readUnaligned32(p)
    59  			v2 = rotl_15(v2*m2) * m3
    60  			p = add(p, 4)
    61  			v3 ^= readUnaligned32(p)
    62  			v3 = rotl_15(v3*m3) * m4
    63  			p = add(p, 4)
    64  			v4 ^= readUnaligned32(p)
    65  			v4 = rotl_15(v4*m4) * m1
    66  			p = add(p, 4)
    67  			s -= 16
    68  		}
    69  		h = v1 ^ v2 ^ v3 ^ v4
    70  		goto tail
    71  	}
    72  	h ^= h >> 17
    73  	h *= m3
    74  	h ^= h >> 13
    75  	h *= m4
    76  	h ^= h >> 16
    77  	return uintptr(h)
    78  }
    79  
    80  // Note: These routines perform the read with a native endianness.
    81  func readUnaligned32(p unsafe.Pointer) uint32 {
    82  	q := (*[4]byte)(p)
    83  	if sys.BigEndian {
    84  		return uint32(q[3]) | uint32(q[2])<<8 | uint32(q[1])<<16 | uint32(q[0])<<24
    85  	}
    86  	return uint32(q[0]) | uint32(q[1])<<8 | uint32(q[2])<<16 | uint32(q[3])<<24
    87  }
    88  
    89  // Note: in order to get the compiler to issue rotl instructions, we
    90  // need to constant fold the shift amount by hand.
    91  // TODO: convince the compiler to issue rotl instructions after inlining.
    92  func rotl_15(x uint32) uint32 {
    93  	return (x << 15) | (x >> (32 - 15))
    94  }
    95  
    96  // Should be a built-in for unsafe.Pointer?
    97  //go:nosplit
    98  func add(p unsafe.Pointer, x uintptr) unsafe.Pointer {
    99  	data := js.InternalObject(p).Interface().([]byte)
   100  	return unsafe.Pointer(js.InternalObject(data[x:]).Unsafe())
   101  }
   102  
   103  // used in hash{32,64}.go to seed the hash function
   104  var hashkey [4]uintptr
   105  
   106  var memhash_has_init bool
   107  
   108  func memhash_init() {
   109  	if memhash_has_init {
   110  		return
   111  	}
   112  	memhash_has_init = true
   113  	var hash [16]byte
   114  	getRandomData(hash[:])
   115  	obj := js.NewArrayBuffer(hash[:])
   116  	v := js.Global.Get("Uint32Array").New(obj)
   117  	for i := 0; i < v.Length(); i++ {
   118  		hashkey[i] = v.Index(i).Unsafe()
   119  	}
   120  	hashkey[0] |= 1 // make sure these numbers are odd
   121  	hashkey[1] |= 1
   122  	hashkey[2] |= 1
   123  	hashkey[3] |= 1
   124  }
   125  
   126  //go:nosplit
   127  func getRandomData(r []byte) {
   128  	extendRandom(r, 0)
   129  }
   130  
   131  // extendRandom extends the random numbers in r[:n] to the whole slice r.
   132  // Treats n<0 as n==0.
   133  func extendRandom(r []byte, n int) {
   134  	if n < 0 {
   135  		n = 0
   136  	}
   137  	for n < len(r) {
   138  		// Extend random bits using hash function & time seed
   139  		w := n
   140  		if w > 16 {
   141  			w = 16
   142  		}
   143  		seed := js.Global.Get("Date").New().Call("getTime").Unsafe()
   144  		h := memhash(unsafe.Pointer(&r[n-w]), seed, uintptr(w))
   145  		for i := 0; i < sys.PtrSize && n < len(r); i++ {
   146  			r[n] = byte(h)
   147  			n++
   148  			h >>= 8
   149  		}
   150  	}
   151  }
   152  
   153  func nanotime() int64 {
   154  	return js.Global.Get("Date").New().Call("getTime").Int64() * 1e6
   155  }