MakeGCStackSlots converts all calls to runtime.trackPointer to explicit stores to stack slots that are scannable by the GC.
(mod llvm.Module)
| 12 | // MakeGCStackSlots converts all calls to runtime.trackPointer to explicit |
| 13 | // stores to stack slots that are scannable by the GC. |
| 14 | func MakeGCStackSlots(mod llvm.Module) bool { |
| 15 | // Check whether there are allocations at all. |
| 16 | alloc := mod.NamedFunction("runtime.alloc") |
| 17 | if alloc.IsNil() { |
| 18 | // Nothing to. Make sure all remaining bits and pieces for stack |
| 19 | // chains are neutralized. |
| 20 | for _, call := range getUses(mod.NamedFunction("runtime.trackPointer")) { |
| 21 | call.EraseFromParentAsInstruction() |
| 22 | } |
| 23 | stackChainStart := mod.NamedGlobal("runtime.stackChainStart") |
| 24 | if !stackChainStart.IsNil() { |
| 25 | stackChainStart.SetLinkage(llvm.InternalLinkage) |
| 26 | stackChainStart.SetInitializer(llvm.ConstNull(stackChainStart.GlobalValueType())) |
| 27 | stackChainStart.SetGlobalConstant(true) |
| 28 | } |
| 29 | return false |
| 30 | } |
| 31 | |
| 32 | trackPointer := mod.NamedFunction("runtime.trackPointer") |
| 33 | if trackPointer.IsNil() || trackPointer.FirstUse().IsNil() { |
| 34 | return false // nothing to do |
| 35 | } |
| 36 | |
| 37 | ctx := mod.Context() |
| 38 | builder := ctx.NewBuilder() |
| 39 | defer builder.Dispose() |
| 40 | targetData := llvm.NewTargetData(mod.DataLayout()) |
| 41 | defer targetData.Dispose() |
| 42 | uintptrType := ctx.IntType(targetData.PointerSize() * 8) |
| 43 | |
| 44 | // All functions that call runtime.alloc needs stack objects. |
| 45 | trackFuncs := map[llvm.Value]struct{}{} |
| 46 | markParentFunctions(trackFuncs, alloc) |
| 47 | |
| 48 | // External functions may indirectly suspend the goroutine or perform a heap allocation. |
| 49 | // Their callers should get stack objects. |
| 50 | memAttr := llvm.AttributeKindID("memory") |
| 51 | for fn := mod.FirstFunction(); !fn.IsNil(); fn = llvm.NextFunction(fn) { |
| 52 | if _, ok := trackFuncs[fn]; ok { |
| 53 | continue // already found |
| 54 | } |
| 55 | if !fn.FirstBasicBlock().IsNil() { |
| 56 | // This is not an external function. |
| 57 | continue |
| 58 | } |
| 59 | if fn == trackPointer { |
| 60 | // Manually exclude trackPointer. |
| 61 | continue |
| 62 | } |
| 63 | |
| 64 | mem := fn.GetEnumFunctionAttribute(memAttr) |
| 65 | if !mem.IsNil() && mem.GetEnumValue()>>shiftExcludeArgMem == 0 { |
| 66 | // This does not access non-argument memory. |
| 67 | // Exclude it. |
| 68 | continue |
| 69 | } |
| 70 | |
| 71 | // The callers need stack objects. |