mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-09-11 15:09:32 +00:00
runtime: require explicit GC layouts
This commit is contained in:
@@ -13,6 +13,12 @@ import (
|
||||
|
||||
const hashArrayUnrollLimit = 4
|
||||
|
||||
const (
|
||||
hashmapBucketSlots = 8
|
||||
hashmapMaxKeySize = 128
|
||||
hashmapMaxValueSize = 128
|
||||
)
|
||||
|
||||
// createMakeMap creates a new map object (runtime.hashmap) by allocating and
|
||||
// initializing an appropriately sized object.
|
||||
func (b *builder) createMakeMap(expr *ssa.MakeMap) (llvm.Value, error) {
|
||||
@@ -25,6 +31,8 @@ func (b *builder) createMakeMap(expr *ssa.MakeMap) (llvm.Value, error) {
|
||||
valueSize := b.targetData.TypeAllocSize(llvmValueType)
|
||||
llvmKeySize := llvm.ConstInt(b.uintptrType, keySize, false)
|
||||
llvmValueSize := llvm.ConstInt(b.uintptrType, valueSize, false)
|
||||
mapLayout := b.getHashmapTypeInfo(mapType, expr.Pos())
|
||||
|
||||
sizeHint := llvm.ConstInt(b.uintptrType, 8, false)
|
||||
if expr.Reserve != nil {
|
||||
sizeHint = b.getValue(expr.Reserve, getPos(expr))
|
||||
@@ -54,11 +62,72 @@ func (b *builder) createMakeMap(expr *ssa.MakeMap) (llvm.Value, error) {
|
||||
|
||||
hashmap := b.createRuntimeCall("hashmapMakeGeneric", []llvm.Value{
|
||||
llvmKeySize, llvmValueSize, sizeHint,
|
||||
mapLayout,
|
||||
hashFn, equalFn,
|
||||
}, "")
|
||||
return hashmap, nil
|
||||
}
|
||||
|
||||
func (c *compilerContext) getHashmapTypeInfo(mapType *types.Map, pos token.Pos) llvm.Value {
|
||||
llvmKeyType := c.getLLVMType(mapType.Key().Underlying())
|
||||
llvmValueType := c.getLLVMType(mapType.Elem().Underlying())
|
||||
keySize := c.targetData.TypeAllocSize(llvmKeyType)
|
||||
valueSize := c.targetData.TypeAllocSize(llvmValueType)
|
||||
keyLayout := c.createObjectLayout(llvmKeyType, pos)
|
||||
valueLayout := c.createObjectLayout(llvmValueType, pos)
|
||||
|
||||
llvmKeySlotType := llvmKeyType
|
||||
if keySize > hashmapMaxKeySize {
|
||||
llvmKeySlotType = c.dataPtrType
|
||||
}
|
||||
llvmValueSlotType := llvmValueType
|
||||
if valueSize > hashmapMaxValueSize {
|
||||
llvmValueSlotType = c.dataPtrType
|
||||
}
|
||||
|
||||
// Keep this in sync with runtime.hashmapBucket and
|
||||
// runtime.hashmapBucketHeaderSize.
|
||||
pointerSize := c.targetData.TypeAllocSize(c.dataPtrType)
|
||||
headerSize := (uint64(8) + pointerSize + 7) &^ 7
|
||||
headerPadding := headerSize - uint64(8) - pointerSize
|
||||
bucketFields := []llvm.Type{
|
||||
llvm.ArrayType(c.ctx.Int8Type(), hashmapBucketSlots),
|
||||
c.dataPtrType,
|
||||
}
|
||||
if headerPadding != 0 {
|
||||
bucketFields = append(bucketFields, llvm.ArrayType(c.ctx.Int8Type(), int(headerPadding)))
|
||||
}
|
||||
bucketFields = append(bucketFields,
|
||||
llvm.ArrayType(llvmKeySlotType, hashmapBucketSlots),
|
||||
llvm.ArrayType(llvmValueSlotType, hashmapBucketSlots),
|
||||
)
|
||||
bucketType := c.ctx.StructType(bucketFields, true)
|
||||
bucketSize := headerSize +
|
||||
c.targetData.TypeAllocSize(llvmKeySlotType)*hashmapBucketSlots +
|
||||
c.targetData.TypeAllocSize(llvmValueSlotType)*hashmapBucketSlots
|
||||
if c.targetData.TypeAllocSize(bucketType) != bucketSize {
|
||||
panic("compiler hashmap bucket layout does not match runtime")
|
||||
}
|
||||
bucketLayout := c.createObjectLayout(bucketType, pos)
|
||||
mapLayoutName := "runtime.hashmapType:" +
|
||||
hashmapCanonicalTypeName(mapType.Key()) + ":" +
|
||||
hashmapCanonicalTypeName(mapType.Elem())
|
||||
mapLayout := c.mod.NamedGlobal(mapLayoutName)
|
||||
if mapLayout.IsNil() {
|
||||
initializer := c.ctx.ConstStruct([]llvm.Value{
|
||||
keyLayout,
|
||||
valueLayout,
|
||||
bucketLayout,
|
||||
}, false)
|
||||
mapLayout = llvm.AddGlobal(c.mod, initializer.Type(), mapLayoutName)
|
||||
mapLayout.SetInitializer(initializer)
|
||||
mapLayout.SetGlobalConstant(true)
|
||||
mapLayout.SetUnnamedAddr(true)
|
||||
mapLayout.SetLinkage(llvm.LinkOnceODRLinkage)
|
||||
}
|
||||
return mapLayout
|
||||
}
|
||||
|
||||
// getRuntimeFunctionValue returns a TinyGo function value (with nil context)
|
||||
// for the named runtime function.
|
||||
func (b *builder) getRuntimeFunctionValue(name string, sig *types.Signature) llvm.Value {
|
||||
|
||||
Reference in New Issue
Block a user