mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-08-02 01:57:48 +00:00
105 lines
3.5 KiB
Go
105 lines
3.5 KiB
Go
package compiler
|
|
|
|
import (
|
|
"math/big"
|
|
|
|
"tinygo.org/x/go-llvm"
|
|
)
|
|
|
|
func (c *Compiler) addGlobalsBitmap() {
|
|
if c.mod.NamedGlobal("runtime.trackedGlobalsStart").IsNil() {
|
|
return // nothing to do: no GC in use
|
|
}
|
|
|
|
var trackedGlobals []llvm.Value
|
|
var trackedGlobalTypes []llvm.Type
|
|
for global := c.mod.FirstGlobal(); !global.IsNil(); global = llvm.NextGlobal(global) {
|
|
if global.IsDeclaration() {
|
|
continue
|
|
}
|
|
typ := global.Type().ElementType()
|
|
ptrs := c.getPointerBitmap(typ, global.Name())
|
|
if ptrs.BitLen() == 0 {
|
|
continue
|
|
}
|
|
trackedGlobals = append(trackedGlobals, global)
|
|
trackedGlobalTypes = append(trackedGlobalTypes, typ)
|
|
}
|
|
|
|
//
|
|
globalsBundleType := c.ctx.StructType(trackedGlobalTypes, false)
|
|
globalsBundle := llvm.AddGlobal(c.mod, globalsBundleType, "tinygo.trackedGlobals")
|
|
globalsBundle.SetLinkage(llvm.InternalLinkage)
|
|
globalsBundle.SetUnnamedAddr(true)
|
|
initializer := llvm.Undef(globalsBundleType)
|
|
for i, global := range trackedGlobals {
|
|
initializer = llvm.ConstInsertValue(initializer, global.Initializer(), []uint32{uint32(i)})
|
|
gep := llvm.ConstGEP(globalsBundle, []llvm.Value{
|
|
llvm.ConstInt(c.ctx.Int32Type(), 0, false),
|
|
llvm.ConstInt(c.ctx.Int32Type(), uint64(i), false),
|
|
})
|
|
global.ReplaceAllUsesWith(gep)
|
|
global.EraseFromParentAsGlobal()
|
|
}
|
|
globalsBundle.SetInitializer(initializer)
|
|
|
|
trackedGlobalsStart := llvm.ConstPtrToInt(globalsBundle, c.uintptrType)
|
|
c.mod.NamedGlobal("runtime.trackedGlobalsStart").SetInitializer(trackedGlobalsStart)
|
|
|
|
alignment := c.targetData.PrefTypeAlignment(c.i8ptrType)
|
|
trackedGlobalsLength := llvm.ConstInt(c.uintptrType, c.targetData.TypeAllocSize(globalsBundleType)/uint64(alignment), false)
|
|
c.mod.NamedGlobal("runtime.trackedGlobalsLength").SetInitializer(trackedGlobalsLength)
|
|
|
|
bitmapBytes := c.getPointerBitmap(globalsBundleType, "globals bundle").Bytes()
|
|
bitmapValues := make([]llvm.Value, len(bitmapBytes))
|
|
for i, b := range bitmapBytes {
|
|
bitmapValues[len(bitmapBytes)-i-1] = llvm.ConstInt(c.ctx.Int8Type(), uint64(b), false)
|
|
}
|
|
bitmapArray := llvm.ConstArray(llvm.ArrayType(c.ctx.Int8Type(), len(bitmapBytes)), bitmapValues)
|
|
bitmapNew := llvm.AddGlobal(c.mod, bitmapArray.Type(), "runtime.trackedGlobalsBitmap.tmp")
|
|
bitmapOld := c.mod.NamedGlobal("runtime.trackedGlobalsBitmap")
|
|
bitmapOld.ReplaceAllUsesWith(bitmapNew)
|
|
bitmapNew.SetInitializer(bitmapArray)
|
|
bitmapNew.SetName("runtime.trackedGlobalsBitmap")
|
|
}
|
|
|
|
func (c *Compiler) getPointerBitmap(typ llvm.Type, name string) *big.Int {
|
|
alignment := c.targetData.PrefTypeAlignment(c.i8ptrType)
|
|
switch typ.TypeKind() {
|
|
case llvm.IntegerTypeKind, llvm.FloatTypeKind, llvm.DoubleTypeKind:
|
|
return big.NewInt(0)
|
|
case llvm.PointerTypeKind:
|
|
return big.NewInt(1)
|
|
case llvm.StructTypeKind:
|
|
ptrs := big.NewInt(0)
|
|
for i, subtyp := range typ.StructElementTypes() {
|
|
subptrs := c.getPointerBitmap(subtyp, name)
|
|
if subptrs.BitLen() == 0 {
|
|
continue
|
|
}
|
|
offset := c.targetData.ElementOffset(typ, i)
|
|
if offset%uint64(alignment) != 0 {
|
|
panic("precise GC: global contains unaligned pointer: " + name)
|
|
}
|
|
subptrs.Lsh(subptrs, uint(offset)/uint(alignment))
|
|
ptrs.Or(ptrs, subptrs)
|
|
}
|
|
return ptrs
|
|
case llvm.ArrayTypeKind:
|
|
subtyp := typ.ElementType()
|
|
subptrs := c.getPointerBitmap(subtyp, name)
|
|
ptrs := big.NewInt(0)
|
|
if subptrs.BitLen() == 0 {
|
|
return ptrs
|
|
}
|
|
elementSize := c.targetData.TypeAllocSize(subtyp)
|
|
for i := 0; i < typ.ArrayLength(); i++ {
|
|
ptrs.Lsh(ptrs, uint(elementSize)/uint(alignment))
|
|
ptrs.Or(ptrs, subptrs)
|
|
}
|
|
return ptrs
|
|
default:
|
|
panic("unknown type kind of global: " + name)
|
|
}
|
|
}
|