Browse Source

compiler,runtime: make keySize and valueSize uintptr

pull/3311/head
Damian Gryski 2 years ago
committed by Ron Evans
parent
commit
0504e4a201
  1. 4
      compiler/map.go
  2. 76
      src/runtime/hashmap.go

4
compiler/map.go

@ -41,8 +41,8 @@ func (b *builder) createMakeMap(expr *ssa.MakeMap) (llvm.Value, error) {
} }
keySize := b.targetData.TypeAllocSize(llvmKeyType) keySize := b.targetData.TypeAllocSize(llvmKeyType)
valueSize := b.targetData.TypeAllocSize(llvmValueType) valueSize := b.targetData.TypeAllocSize(llvmValueType)
llvmKeySize := llvm.ConstInt(b.ctx.Int8Type(), keySize, false) llvmKeySize := llvm.ConstInt(b.uintptrType, keySize, false)
llvmValueSize := llvm.ConstInt(b.ctx.Int32Type(), valueSize, false) llvmValueSize := llvm.ConstInt(b.uintptrType, valueSize, false)
sizeHint := llvm.ConstInt(b.uintptrType, 8, false) sizeHint := llvm.ConstInt(b.uintptrType, 8, false)
algEnum := llvm.ConstInt(b.ctx.Int8Type(), alg, false) algEnum := llvm.ConstInt(b.ctx.Int8Type(), alg, false)
if expr.Reserve != nil { if expr.Reserve != nil {

76
src/runtime/hashmap.go

@ -15,8 +15,8 @@ type hashmap struct {
buckets unsafe.Pointer // pointer to array of buckets buckets unsafe.Pointer // pointer to array of buckets
seed uintptr seed uintptr
count uintptr count uintptr
valueSize uint32 keySize uintptr // maybe this can store the key type as well? E.g. keysize == 5 means string?
keySize uint8 // maybe this can store the key type as well? E.g. keysize == 5 means string? valueSize uintptr
bucketBits uint8 bucketBits uint8
keyEqual func(x, y unsafe.Pointer, n uintptr) bool keyEqual func(x, y unsafe.Pointer, n uintptr) bool
keyHash func(key unsafe.Pointer, size, seed uintptr) uint32 keyHash func(key unsafe.Pointer, size, seed uintptr) uint32
@ -60,14 +60,14 @@ func hashmapTopHash(hash uint32) uint8 {
} }
// Create a new hashmap with the given keySize and valueSize. // Create a new hashmap with the given keySize and valueSize.
func hashmapMake(keySize uint8, valueSize uint32, sizeHint uintptr, alg uint8) *hashmap { func hashmapMake(keySize, valueSize uintptr, sizeHint uintptr, alg uint8) *hashmap {
numBuckets := sizeHint / 8 numBuckets := sizeHint / 8
bucketBits := uint8(0) bucketBits := uint8(0)
for numBuckets != 0 { for numBuckets != 0 {
numBuckets /= 2 numBuckets /= 2
bucketBits++ bucketBits++
} }
bucketBufSize := unsafe.Sizeof(hashmapBucket{}) + uintptr(keySize)*8 + uintptr(valueSize)*8 bucketBufSize := unsafe.Sizeof(hashmapBucket{}) + keySize*8 + valueSize*8
buckets := alloc(bucketBufSize*(1<<bucketBits), nil) buckets := alloc(bucketBufSize*(1<<bucketBits), nil)
keyHash := hashmapKeyHashAlg(hashmapAlgorithm(alg)) keyHash := hashmapKeyHashAlg(hashmapAlgorithm(alg))
@ -155,14 +155,14 @@ func hashmapSet(m *hashmap, key unsafe.Pointer, value unsafe.Pointer, hash uint3
if hashmapShouldGrow(m) { if hashmapShouldGrow(m) {
hashmapGrow(m) hashmapGrow(m)
// seed changed when we grew; rehash key with new seed // seed changed when we grew; rehash key with new seed
hash = m.keyHash(key, uintptr(m.keySize), m.seed) hash = m.keyHash(key, m.keySize, m.seed)
} }
tophash := hashmapTopHash(hash) tophash := hashmapTopHash(hash)
numBuckets := uintptr(1) << m.bucketBits numBuckets := uintptr(1) << m.bucketBits
bucketNumber := (uintptr(hash) & (numBuckets - 1)) bucketNumber := (uintptr(hash) & (numBuckets - 1))
bucketSize := unsafe.Sizeof(hashmapBucket{}) + uintptr(m.keySize)*8 + uintptr(m.valueSize)*8 bucketSize := unsafe.Sizeof(hashmapBucket{}) + m.keySize*8 + m.valueSize*8
bucketAddr := uintptr(m.buckets) + bucketSize*bucketNumber bucketAddr := uintptr(m.buckets) + bucketSize*bucketNumber
bucket := (*hashmapBucket)(unsafe.Pointer(bucketAddr)) bucket := (*hashmapBucket)(unsafe.Pointer(bucketAddr))
var lastBucket *hashmapBucket var lastBucket *hashmapBucket
@ -173,9 +173,9 @@ func hashmapSet(m *hashmap, key unsafe.Pointer, value unsafe.Pointer, hash uint3
var emptySlotTophash *byte var emptySlotTophash *byte
for bucket != nil { for bucket != nil {
for i := uintptr(0); i < 8; i++ { for i := uintptr(0); i < 8; i++ {
slotKeyOffset := unsafe.Sizeof(hashmapBucket{}) + uintptr(m.keySize)*uintptr(i) slotKeyOffset := unsafe.Sizeof(hashmapBucket{}) + m.keySize*uintptr(i)
slotKey := unsafe.Pointer(uintptr(unsafe.Pointer(bucket)) + slotKeyOffset) slotKey := unsafe.Pointer(uintptr(unsafe.Pointer(bucket)) + slotKeyOffset)
slotValueOffset := unsafe.Sizeof(hashmapBucket{}) + uintptr(m.keySize)*8 + uintptr(m.valueSize)*uintptr(i) slotValueOffset := unsafe.Sizeof(hashmapBucket{}) + m.keySize*8 + m.valueSize*uintptr(i)
slotValue := unsafe.Pointer(uintptr(unsafe.Pointer(bucket)) + slotValueOffset) slotValue := unsafe.Pointer(uintptr(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
@ -186,9 +186,9 @@ func hashmapSet(m *hashmap, key unsafe.Pointer, value unsafe.Pointer, hash uint3
} }
if bucket.tophash[i] == tophash { if bucket.tophash[i] == tophash {
// Could be an existing key that's the same. // Could be an existing key that's the same.
if m.keyEqual(key, slotKey, uintptr(m.keySize)) { if m.keyEqual(key, slotKey, m.keySize) {
// found same key, replace it // found same key, replace it
memcpy(slotValue, value, uintptr(m.valueSize)) memcpy(slotValue, value, m.valueSize)
return return
} }
} }
@ -203,24 +203,24 @@ func hashmapSet(m *hashmap, key unsafe.Pointer, value unsafe.Pointer, hash uint3
return return
} }
m.count++ m.count++
memcpy(emptySlotKey, key, uintptr(m.keySize)) memcpy(emptySlotKey, key, m.keySize)
memcpy(emptySlotValue, value, uintptr(m.valueSize)) memcpy(emptySlotValue, value, m.valueSize)
*emptySlotTophash = tophash *emptySlotTophash = tophash
} }
// 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{}) + uintptr(m.keySize)*8 + uintptr(m.valueSize)*8 bucketBufSize := unsafe.Sizeof(hashmapBucket{}) + m.keySize*8 + m.valueSize*8
bucketBuf := alloc(bucketBufSize, nil) bucketBuf := alloc(bucketBufSize, nil)
// 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{}) slotKeyOffset := unsafe.Sizeof(hashmapBucket{})
slotKey := unsafe.Pointer(uintptr(bucketBuf) + slotKeyOffset) slotKey := unsafe.Pointer(uintptr(bucketBuf) + slotKeyOffset)
slotValueOffset := unsafe.Sizeof(hashmapBucket{}) + uintptr(m.keySize)*8 slotValueOffset := unsafe.Sizeof(hashmapBucket{}) + m.keySize*8
slotValue := unsafe.Pointer(uintptr(bucketBuf) + slotValueOffset) slotValue := unsafe.Pointer(uintptr(bucketBuf) + slotValueOffset)
m.count++ m.count++
memcpy(slotKey, key, uintptr(m.keySize)) memcpy(slotKey, key, m.keySize)
memcpy(slotValue, value, uintptr(m.valueSize)) memcpy(slotValue, value, m.valueSize)
bucket := (*hashmapBucket)(bucketBuf) bucket := (*hashmapBucket)(bucketBuf)
bucket.tophash[0] = tophash bucket.tophash[0] = tophash
return bucket return bucket
@ -235,14 +235,14 @@ 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{}) + uintptr(m.keySize)*8 + uintptr(m.valueSize)*8 bucketBufSize := unsafe.Sizeof(hashmapBucket{}) + m.keySize*8 + m.valueSize*8
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
var it hashmapIterator var it hashmapIterator
var key = alloc(uintptr(m.keySize), nil) var key = alloc(m.keySize, nil)
var value = alloc(uintptr(m.valueSize), nil) var value = alloc(m.valueSize, nil)
for hashmapNext(m, &it, key, value) { for hashmapNext(m, &it, key, value) {
h := n.keyHash(key, uintptr(n.keySize), n.seed) h := n.keyHash(key, uintptr(n.keySize), n.seed)
@ -265,7 +265,7 @@ func hashmapGet(m *hashmap, key, value unsafe.Pointer, valueSize uintptr, hash u
} }
numBuckets := uintptr(1) << m.bucketBits numBuckets := uintptr(1) << m.bucketBits
bucketNumber := (uintptr(hash) & (numBuckets - 1)) bucketNumber := (uintptr(hash) & (numBuckets - 1))
bucketSize := unsafe.Sizeof(hashmapBucket{}) + uintptr(m.keySize)*8 + uintptr(m.valueSize)*8 bucketSize := unsafe.Sizeof(hashmapBucket{}) + m.keySize*8 + m.valueSize*8
bucketAddr := uintptr(m.buckets) + bucketSize*bucketNumber bucketAddr := uintptr(m.buckets) + bucketSize*bucketNumber
bucket := (*hashmapBucket)(unsafe.Pointer(bucketAddr)) bucket := (*hashmapBucket)(unsafe.Pointer(bucketAddr))
@ -278,15 +278,15 @@ func hashmapGet(m *hashmap, key, value unsafe.Pointer, valueSize uintptr, hash u
// 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 := uintptr(0); i < 8; i++ {
slotKeyOffset := unsafe.Sizeof(hashmapBucket{}) + uintptr(m.keySize)*uintptr(i) slotKeyOffset := unsafe.Sizeof(hashmapBucket{}) + m.keySize*uintptr(i)
slotKey := unsafe.Pointer(uintptr(unsafe.Pointer(bucket)) + slotKeyOffset) slotKey := unsafe.Pointer(uintptr(unsafe.Pointer(bucket)) + slotKeyOffset)
slotValueOffset := unsafe.Sizeof(hashmapBucket{}) + uintptr(m.keySize)*8 + uintptr(m.valueSize)*uintptr(i) slotValueOffset := unsafe.Sizeof(hashmapBucket{}) + m.keySize*8 + m.valueSize*uintptr(i)
slotValue := unsafe.Pointer(uintptr(unsafe.Pointer(bucket)) + slotValueOffset) slotValue := unsafe.Pointer(uintptr(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, uintptr(m.keySize)) { if m.keyEqual(key, slotKey, m.keySize) {
// Found the key, copy it. // Found the key, copy it.
memcpy(value, slotValue, uintptr(m.valueSize)) memcpy(value, slotValue, m.valueSize)
return true return true
} }
} }
@ -295,7 +295,7 @@ func hashmapGet(m *hashmap, key, value unsafe.Pointer, valueSize uintptr, hash u
} }
// Did not find the key. // Did not find the key.
memzero(value, uintptr(m.valueSize)) memzero(value, m.valueSize)
return false return false
} }
@ -312,7 +312,7 @@ func hashmapDelete(m *hashmap, key unsafe.Pointer, hash uint32) {
} }
numBuckets := uintptr(1) << m.bucketBits numBuckets := uintptr(1) << m.bucketBits
bucketNumber := (uintptr(hash) & (numBuckets - 1)) bucketNumber := (uintptr(hash) & (numBuckets - 1))
bucketSize := unsafe.Sizeof(hashmapBucket{}) + uintptr(m.keySize)*8 + uintptr(m.valueSize)*8 bucketSize := unsafe.Sizeof(hashmapBucket{}) + m.keySize*8 + m.valueSize*8
bucketAddr := uintptr(m.buckets) + bucketSize*bucketNumber bucketAddr := uintptr(m.buckets) + bucketSize*bucketNumber
bucket := (*hashmapBucket)(unsafe.Pointer(bucketAddr)) bucket := (*hashmapBucket)(unsafe.Pointer(bucketAddr))
@ -325,11 +325,11 @@ func hashmapDelete(m *hashmap, key unsafe.Pointer, hash uint32) {
// 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 := uintptr(0); i < 8; i++ {
slotKeyOffset := unsafe.Sizeof(hashmapBucket{}) + uintptr(m.keySize)*uintptr(i) slotKeyOffset := unsafe.Sizeof(hashmapBucket{}) + m.keySize*uintptr(i)
slotKey := unsafe.Pointer(uintptr(unsafe.Pointer(bucket)) + slotKeyOffset) slotKey := unsafe.Pointer(uintptr(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, uintptr(m.keySize)) { if m.keyEqual(key, slotKey, m.keySize) {
// Found the key, delete it. // Found the key, delete it.
bucket.tophash[i] = 0 bucket.tophash[i] = 0
m.count-- m.count--
@ -367,7 +367,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{}) + uintptr(m.keySize)*8 + uintptr(m.valueSize)*8 bucketSize := unsafe.Sizeof(hashmapBucket{}) + m.keySize*8 + m.valueSize*8
bucketAddr := uintptr(it.buckets) + bucketSize*it.bucketNumber bucketAddr := uintptr(it.buckets) + bucketSize*it.bucketNumber
it.bucket = (*hashmapBucket)(unsafe.Pointer(bucketAddr)) it.bucket = (*hashmapBucket)(unsafe.Pointer(bucketAddr))
it.bucketNumber++ // next bucket it.bucketNumber++ // next bucket
@ -379,24 +379,24 @@ func hashmapNext(m *hashmap, it *hashmapIterator, key, value unsafe.Pointer) boo
} }
bucketAddr := uintptr(unsafe.Pointer(it.bucket)) bucketAddr := uintptr(unsafe.Pointer(it.bucket))
slotKeyOffset := unsafe.Sizeof(hashmapBucket{}) + uintptr(m.keySize)*uintptr(it.bucketIndex) slotKeyOffset := unsafe.Sizeof(hashmapBucket{}) + m.keySize*uintptr(it.bucketIndex)
slotKey := unsafe.Pointer(bucketAddr + slotKeyOffset) slotKey := unsafe.Pointer(bucketAddr + slotKeyOffset)
memcpy(key, slotKey, uintptr(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{}) + uintptr(m.keySize)*8 + uintptr(m.valueSize)*uintptr(it.bucketIndex) slotValueOffset := unsafe.Sizeof(hashmapBucket{}) + m.keySize*8 + m.valueSize*uintptr(it.bucketIndex)
slotValue := unsafe.Pointer(bucketAddr + slotValueOffset) slotValue := unsafe.Pointer(bucketAddr + slotValueOffset)
memcpy(value, slotValue, uintptr(m.valueSize)) memcpy(value, slotValue, m.valueSize)
it.bucketIndex++ it.bucketIndex++
} else { } else {
it.bucketIndex++ it.bucketIndex++
// Our view of the buckets doesn't match the parent map. // Our view of the buckets doesn't match the parent map.
// Look up the key in the new buckets and return that value if it exists // Look up the key in the new buckets and return that value if it exists
hash := m.keyHash(key, uintptr(m.keySize), m.seed) hash := m.keyHash(key, m.keySize, m.seed)
ok := hashmapGet(m, key, value, uintptr(m.valueSize), hash) ok := hashmapGet(m, key, value, m.valueSize, hash)
if !ok { if !ok {
// doesn't exist in parent map; try next key // doesn't exist in parent map; try next key
continue continue
@ -414,7 +414,7 @@ func hashmapBinarySet(m *hashmap, key, value unsafe.Pointer) {
if m == nil { if m == nil {
nilMapPanic() nilMapPanic()
} }
hash := hash32(key, uintptr(m.keySize), m.seed) hash := hash32(key, m.keySize, m.seed)
hashmapSet(m, key, value, hash) hashmapSet(m, key, value, hash)
} }
@ -423,7 +423,7 @@ func hashmapBinaryGet(m *hashmap, key, value unsafe.Pointer, valueSize uintptr)
memzero(value, uintptr(valueSize)) memzero(value, uintptr(valueSize))
return false return false
} }
hash := hash32(key, uintptr(m.keySize), m.seed) hash := hash32(key, m.keySize, m.seed)
return hashmapGet(m, key, value, valueSize, hash) return hashmapGet(m, key, value, valueSize, hash)
} }
@ -431,7 +431,7 @@ func hashmapBinaryDelete(m *hashmap, key unsafe.Pointer) {
if m == nil { if m == nil {
return return
} }
hash := hash32(key, uintptr(m.keySize), m.seed) hash := hash32(key, m.keySize, m.seed)
hashmapDelete(m, key, hash) hashmapDelete(m, key, hash)
} }

Loading…
Cancel
Save