compiler,runtime: make keySize and valueSize uintptr
Этот коммит содержится в:
родитель
530ca0838d
коммит
0504e4a201
2 изменённых файлов: 40 добавлений и 40 удалений
|
@ -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 {
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче