MCPcopy
hub / github.com/tinygo-org/tinygo / MakeGCStackSlots

Function MakeGCStackSlots

transform/gc.go:14–286  ·  view source on GitHub ↗

MakeGCStackSlots converts all calls to runtime.trackPointer to explicit stores to stack slots that are scannable by the GC.

(mod llvm.Module)

Source from the content-addressed store, hash-verified

12// MakeGCStackSlots converts all calls to runtime.trackPointer to explicit
13// stores to stack slots that are scannable by the GC.
14func 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.

Callers 2

TestMakeGCStackSlotsFunction · 0.92
OptimizeFunction · 0.85

Calls 6

getUsesFunction · 0.85
markParentFunctionsFunction · 0.85
stripPointerCastsFunction · 0.85
IsNilMethod · 0.80
ContextMethod · 0.65
TypeMethod · 0.45

Tested by 1

TestMakeGCStackSlotsFunction · 0.74