runtime: factor duplicate hashmap snippts to functions

Этот коммит содержится в:
Damian Gryski 2023-03-26 18:39:09 -07:00 коммит произвёл Ron Evans
родитель cb9c6f0074
коммит a3afd4e8ac

Просмотреть файл

@ -153,6 +153,39 @@ func hashmapLenUnsafePointer(m unsafe.Pointer) int {
return hashmapLen((*hashmap)(m)) return hashmapLen((*hashmap)(m))
} }
//go:inline
func hashmapBucketSize(m *hashmap) uintptr {
return unsafe.Sizeof(hashmapBucket{}) + uintptr(m.keySize)*8 + uintptr(m.valueSize)*8
}
//go:inline
func hashmapBucketAddr(m *hashmap, buckets unsafe.Pointer, n uintptr) *hashmapBucket {
bucketSize := hashmapBucketSize(m)
bucket := (*hashmapBucket)(unsafe.Add(buckets, bucketSize*n))
return bucket
}
//go:inline
func hashmapBucketAddrForHash(m *hashmap, hash uint32) *hashmapBucket {
numBuckets := uintptr(1) << m.bucketBits
bucketNumber := (uintptr(hash) & (numBuckets - 1))
return hashmapBucketAddr(m, m.buckets, bucketNumber)
}
//go:inline
func hashmapSlotKey(m *hashmap, bucket *hashmapBucket, slot uint8) unsafe.Pointer {
slotKeyOffset := unsafe.Sizeof(hashmapBucket{}) + uintptr(m.keySize)*uintptr(slot)
slotKey := unsafe.Pointer(uintptr(unsafe.Pointer(bucket)) + slotKeyOffset)
return slotKey
}
//go:inline
func hashmapSlotValue(m *hashmap, bucket *hashmapBucket, slot uint8) unsafe.Pointer {
slotValueOffset := unsafe.Sizeof(hashmapBucket{}) + uintptr(m.keySize)*8 + uintptr(m.valueSize)*uintptr(slot)
slotValue := unsafe.Pointer(uintptr(unsafe.Pointer(bucket)) + slotValueOffset)
return slotValue
}
// Set a specified key to a given value. Grow the map if necessary. // Set a specified key to a given value. Grow the map if necessary.
// //
//go:nobounds //go:nobounds
@ -164,11 +197,7 @@ func hashmapSet(m *hashmap, key unsafe.Pointer, value unsafe.Pointer, hash uint3
} }
tophash := hashmapTopHash(hash) tophash := hashmapTopHash(hash)
bucket := hashmapBucketAddrForHash(m, hash)
numBuckets := uintptr(1) << m.bucketBits
bucketNumber := (uintptr(hash) & (numBuckets - 1))
bucketSize := unsafe.Sizeof(hashmapBucket{}) + m.keySize*8 + m.valueSize*8
bucket := (*hashmapBucket)(unsafe.Add(m.buckets, bucketSize*bucketNumber))
var lastBucket *hashmapBucket var lastBucket *hashmapBucket
// See whether the key already exists somewhere. // See whether the key already exists somewhere.
@ -176,11 +205,9 @@ func hashmapSet(m *hashmap, key unsafe.Pointer, value unsafe.Pointer, hash uint3
var emptySlotValue unsafe.Pointer var emptySlotValue unsafe.Pointer
var emptySlotTophash *byte var emptySlotTophash *byte
for bucket != nil { for bucket != nil {
for i := uintptr(0); i < 8; i++ { for i := uint8(0); i < 8; i++ {
slotKeyOffset := unsafe.Sizeof(hashmapBucket{}) + m.keySize*uintptr(i) slotKey := hashmapSlotKey(m, bucket, i)
slotKey := unsafe.Add(unsafe.Pointer(bucket), slotKeyOffset) slotValue := hashmapSlotValue(m, bucket, i)
slotValueOffset := unsafe.Sizeof(hashmapBucket{}) + m.keySize*8 + m.valueSize*uintptr(i)
slotValue := unsafe.Add(unsafe.Pointer(bucket), slotValueOffset)
if bucket.tophash[i] == 0 && emptySlotKey == nil { if bucket.tophash[i] == 0 && emptySlotKey == nil {
// Found an empty slot, store it for if we couldn't find an // Found an empty slot, store it for if we couldn't find an
// existing slot. // existing slot.
@ -219,17 +246,16 @@ func hashmapSetUnsafePointer(m unsafe.Pointer, key unsafe.Pointer, value unsafe.
// hashmapInsertIntoNewBucket creates a new bucket, inserts the given key and // hashmapInsertIntoNewBucket creates a new bucket, inserts the given key and
// value into the bucket, and returns a pointer to this bucket. // value into the bucket, and returns a pointer to this bucket.
func hashmapInsertIntoNewBucket(m *hashmap, key, value unsafe.Pointer, tophash uint8) *hashmapBucket { func hashmapInsertIntoNewBucket(m *hashmap, key, value unsafe.Pointer, tophash uint8) *hashmapBucket {
bucketBufSize := unsafe.Sizeof(hashmapBucket{}) + m.keySize*8 + m.valueSize*8 bucketBufSize := hashmapBucketSize(m)
bucketBuf := alloc(bucketBufSize, nil) bucketBuf := alloc(bucketBufSize, nil)
bucket := (*hashmapBucket)(bucketBuf)
// Insert into the first slot, which is empty as it has just been allocated. // Insert into the first slot, which is empty as it has just been allocated.
slotKeyOffset := unsafe.Sizeof(hashmapBucket{}) slotKey := hashmapSlotKey(m, bucket, 0)
slotKey := unsafe.Add(bucketBuf, slotKeyOffset) slotValue := hashmapSlotValue(m, bucket, 0)
slotValueOffset := unsafe.Sizeof(hashmapBucket{}) + m.keySize*8
slotValue := unsafe.Add(bucketBuf, slotValueOffset)
m.count++ m.count++
memcpy(slotKey, key, m.keySize) memcpy(slotKey, key, m.keySize)
memcpy(slotValue, value, m.valueSize) memcpy(slotValue, value, m.valueSize)
bucket := (*hashmapBucket)(bucketBuf)
bucket.tophash[0] = tophash bucket.tophash[0] = tophash
return bucket return bucket
} }
@ -243,7 +269,7 @@ func hashmapGrow(m *hashmap) {
// allocate our new buckets twice as big // allocate our new buckets twice as big
n.bucketBits = m.bucketBits + 1 n.bucketBits = m.bucketBits + 1
numBuckets := uintptr(1) << n.bucketBits numBuckets := uintptr(1) << n.bucketBits
bucketBufSize := unsafe.Sizeof(hashmapBucket{}) + m.keySize*8 + m.valueSize*8 bucketBufSize := hashmapBucketSize(m)
n.buckets = alloc(bucketBufSize*numBuckets, nil) n.buckets = alloc(bucketBufSize*numBuckets, nil)
// use a hashmap iterator to go through the old map // use a hashmap iterator to go through the old map
@ -271,24 +297,15 @@ func hashmapGet(m *hashmap, key, value unsafe.Pointer, valueSize uintptr, hash u
memzero(value, uintptr(valueSize)) memzero(value, uintptr(valueSize))
return false return false
} }
numBuckets := uintptr(1) << m.bucketBits
bucketNumber := (uintptr(hash) & (numBuckets - 1))
bucketSize := unsafe.Sizeof(hashmapBucket{}) + m.keySize*8 + m.valueSize*8
bucket := (*hashmapBucket)(unsafe.Add(m.buckets, bucketSize*bucketNumber))
tophash := uint8(hash >> 24) tophash := hashmapTopHash(hash)
if tophash < 1 { bucket := hashmapBucketAddrForHash(m, hash)
// 0 means empty slot, so make it bigger.
tophash += 1
}
// Try to find the key. // Try to find the key.
for bucket != nil { for bucket != nil {
for i := uintptr(0); i < 8; i++ { for i := uint8(0); i < 8; i++ {
slotKeyOffset := unsafe.Sizeof(hashmapBucket{}) + m.keySize*uintptr(i) slotKey := hashmapSlotKey(m, bucket, i)
slotKey := unsafe.Add(unsafe.Pointer(bucket), slotKeyOffset) slotValue := hashmapSlotValue(m, bucket, i)
slotValueOffset := unsafe.Sizeof(hashmapBucket{}) + m.keySize*8 + m.valueSize*uintptr(i)
slotValue := unsafe.Add(unsafe.Pointer(bucket), slotValueOffset)
if bucket.tophash[i] == tophash { if bucket.tophash[i] == tophash {
// This could be the key we're looking for. // This could be the key we're looking for.
if m.keyEqual(key, slotKey, m.keySize) { if m.keyEqual(key, slotKey, m.keySize) {
@ -321,22 +338,14 @@ func hashmapDelete(m *hashmap, key unsafe.Pointer, hash uint32) {
// > no-op. // > no-op.
return return
} }
numBuckets := uintptr(1) << m.bucketBits
bucketNumber := (uintptr(hash) & (numBuckets - 1))
bucketSize := unsafe.Sizeof(hashmapBucket{}) + m.keySize*8 + m.valueSize*8
bucket := (*hashmapBucket)(unsafe.Add(m.buckets, bucketSize*bucketNumber))
tophash := uint8(hash >> 24) tophash := hashmapTopHash(hash)
if tophash < 1 { bucket := hashmapBucketAddrForHash(m, hash)
// 0 means empty slot, so make it bigger.
tophash += 1
}
// Try to find the key. // Try to find the key.
for bucket != nil { for bucket != nil {
for i := uintptr(0); i < 8; i++ { for i := uint8(0); i < 8; i++ {
slotKeyOffset := unsafe.Sizeof(hashmapBucket{}) + m.keySize*uintptr(i) slotKey := hashmapSlotKey(m, bucket, i)
slotKey := unsafe.Add(unsafe.Pointer(bucket), slotKeyOffset)
if bucket.tophash[i] == tophash { if bucket.tophash[i] == tophash {
// This could be the key we're looking for. // This could be the key we're looking for.
if m.keyEqual(key, slotKey, m.keySize) { if m.keyEqual(key, slotKey, m.keySize) {
@ -344,8 +353,7 @@ func hashmapDelete(m *hashmap, key unsafe.Pointer, hash uint32) {
bucket.tophash[i] = 0 bucket.tophash[i] = 0
// Zero out the key and value so garbage collector doesn't pin the allocations. // Zero out the key and value so garbage collector doesn't pin the allocations.
memzero(slotKey, m.keySize) memzero(slotKey, m.keySize)
slotValueOffset := unsafe.Sizeof(hashmapBucket{}) + m.keySize*8 + m.valueSize*uintptr(i) slotValue := hashmapSlotValue(m, bucket, i)
slotValue := unsafe.Add(unsafe.Pointer(bucket), slotValueOffset)
memzero(slotValue, m.valueSize) memzero(slotValue, m.valueSize)
m.count-- m.count--
return return
@ -382,8 +390,7 @@ func hashmapNext(m *hashmap, it *hashmapIterator, key, value unsafe.Pointer) boo
// went through all buckets // went through all buckets
return false return false
} }
bucketSize := unsafe.Sizeof(hashmapBucket{}) + m.keySize*8 + m.valueSize*8 it.bucket = hashmapBucketAddr(m, it.buckets, it.bucketNumber)
it.bucket = (*hashmapBucket)(unsafe.Add(it.buckets, bucketSize*it.bucketNumber))
it.bucketNumber++ // next bucket it.bucketNumber++ // next bucket
} }
if it.bucket.tophash[it.bucketIndex] == 0 { if it.bucket.tophash[it.bucketIndex] == 0 {
@ -392,15 +399,13 @@ func hashmapNext(m *hashmap, it *hashmapIterator, key, value unsafe.Pointer) boo
continue continue
} }
slotKeyOffset := unsafe.Sizeof(hashmapBucket{}) + m.keySize*uintptr(it.bucketIndex) slotKey := hashmapSlotKey(m, it.bucket, it.bucketIndex)
slotKey := unsafe.Add(unsafe.Pointer(it.bucket), slotKeyOffset)
memcpy(key, slotKey, m.keySize) memcpy(key, slotKey, m.keySize)
if it.buckets == m.buckets { if it.buckets == m.buckets {
// Our view of the buckets is the same as the parent map. // Our view of the buckets is the same as the parent map.
// Just copy the value we have // Just copy the value we have
slotValueOffset := unsafe.Sizeof(hashmapBucket{}) + m.keySize*8 + m.valueSize*uintptr(it.bucketIndex) slotValue := hashmapSlotValue(m, it.bucket, it.bucketIndex)
slotValue := unsafe.Add(unsafe.Pointer(it.bucket), slotValueOffset)
memcpy(value, slotValue, m.valueSize) memcpy(value, slotValue, m.valueSize)
it.bucketIndex++ it.bucketIndex++
} else { } else {