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 }