diff --git a/compiler/compiler.go b/compiler/compiler.go index 2a024697..6f901ba9 100644 --- a/compiler/compiler.go +++ b/compiler/compiler.go @@ -1425,7 +1425,16 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) { valueSize := c.targetData.TypeAllocSize(llvmValueType) llvmKeySize := llvm.ConstInt(c.ctx.Int8Type(), keySize, false) llvmValueSize := llvm.ConstInt(c.ctx.Int8Type(), valueSize, false) - hashmap := c.createRuntimeCall("hashmapMake", []llvm.Value{llvmKeySize, llvmValueSize}, "") + sizeHint := llvm.ConstInt(c.uintptrType, 8, false) + if expr.Reserve != nil { + sizeHint = c.getValue(frame, expr.Reserve) + var err error + sizeHint, err = c.parseConvert(expr.Reserve.Type(), types.Typ[types.Uintptr], sizeHint, expr.Pos()) + if err != nil { + return llvm.Value{}, err + } + } + hashmap := c.createRuntimeCall("hashmapMake", []llvm.Value{llvmKeySize, llvmValueSize, sizeHint}, "") return hashmap, nil case *ssa.MakeSlice: sliceLen := c.getValue(frame, expr.Len) diff --git a/src/runtime/hashmap.go b/src/runtime/hashmap.go index 6afde9d9..9390cd19 100644 --- a/src/runtime/hashmap.go +++ b/src/runtime/hashmap.go @@ -60,14 +60,20 @@ func hashmapTopHash(hash uint32) uint8 { } // Create a new hashmap with the given keySize and valueSize. -func hashmapMake(keySize, valueSize uint8) *hashmap { +func hashmapMake(keySize, valueSize uint8, sizeHint uintptr) *hashmap { + numBuckets := sizeHint / 8 + bucketBits := uint8(0) + for numBuckets != 0 { + numBuckets /= 2 + bucketBits++ + } bucketBufSize := unsafe.Sizeof(hashmapBucket{}) + uintptr(keySize)*8 + uintptr(valueSize)*8 - bucket := alloc(bucketBufSize) + buckets := alloc(bucketBufSize * (1 << bucketBits)) return &hashmap{ - buckets: bucket, + buckets: buckets, keySize: keySize, valueSize: valueSize, - bucketBits: 0, + bucketBits: bucketBits, } } diff --git a/testdata/map.go b/testdata/map.go index fdf61502..db673efa 100644 --- a/testdata/map.go +++ b/testdata/map.go @@ -47,6 +47,18 @@ func main() { println(testMapArrayKey[arrKey]) testMapArrayKey[arrKey] = 5555 println(testMapArrayKey[arrKey]) + + // test preallocated map + squares := make(map[int]int, 200) + for i := 0; i < 100; i++ { + squares[i] = i*i + for j := 0; j <= i; j++ { + if v := squares[j]; v != j*j { + println("unexpected value read back from squares map:", j, v) + } + } + } + println("tested preallocated map") } func readMap(m map[string]int, key string) { @@ -56,6 +68,7 @@ func readMap(m map[string]int, key string) { println(" ", k, "=", v) } } + func lookup(m map[string]int, key string) { value, ok := m[key] println("lookup with comma-ok:", key, value, ok) diff --git a/testdata/map.txt b/testdata/map.txt index a41522f7..ad525521 100644 --- a/testdata/map.txt +++ b/testdata/map.txt @@ -54,3 +54,4 @@ true false 0 42 4321 5555 +tested preallocated map