CreateStackSizeLoads replaces internal/task.getGoroutineStackSize calls with loads from internal/task.stackSizes that will be updated after linking. This way the stack sizes are loaded from a separate section and can easily be modified after linking.
(mod llvm.Module, config *compileopts.Config)
| 14 | // way the stack sizes are loaded from a separate section and can easily be |
| 15 | // modified after linking. |
| 16 | func CreateStackSizeLoads(mod llvm.Module, config *compileopts.Config) []string { |
| 17 | functionMap := map[llvm.Value][]llvm.Value{} |
| 18 | var functions []llvm.Value // ptrtoint values of functions |
| 19 | var functionNames []string |
| 20 | var functionValues []llvm.Value // direct references to functions |
| 21 | for _, use := range getUses(mod.NamedFunction("internal/task.getGoroutineStackSize")) { |
| 22 | if use.FirstUse().IsNil() { |
| 23 | // Apparently this stack size isn't used. |
| 24 | use.EraseFromParentAsInstruction() |
| 25 | continue |
| 26 | } |
| 27 | ptrtoint := use.Operand(0) |
| 28 | if _, ok := functionMap[ptrtoint]; !ok { |
| 29 | functions = append(functions, ptrtoint) |
| 30 | functionNames = append(functionNames, ptrtoint.Operand(0).Name()) |
| 31 | functionValues = append(functionValues, ptrtoint.Operand(0)) |
| 32 | } |
| 33 | functionMap[ptrtoint] = append(functionMap[ptrtoint], use) |
| 34 | } |
| 35 | |
| 36 | if len(functions) == 0 { |
| 37 | // Nothing to do. |
| 38 | return nil |
| 39 | } |
| 40 | |
| 41 | ctx := mod.Context() |
| 42 | targetData := llvm.NewTargetData(mod.DataLayout()) |
| 43 | defer targetData.Dispose() |
| 44 | uintptrType := ctx.IntType(targetData.PointerSize() * 8) |
| 45 | |
| 46 | // Create the new global with stack sizes, that will be put in a new section |
| 47 | // just for itself. |
| 48 | stackSizesGlobalType := llvm.ArrayType(functions[0].Type(), len(functions)) |
| 49 | stackSizesGlobal := llvm.AddGlobal(mod, stackSizesGlobalType, "internal/task.stackSizes") |
| 50 | stackSizesGlobal.SetSection(".tinygo_stacksizes") |
| 51 | defaultStackSizes := make([]llvm.Value, len(functions)) |
| 52 | defaultStackSize := llvm.ConstInt(functions[0].Type(), config.StackSize(), false) |
| 53 | alignment := targetData.ABITypeAlignment(functions[0].Type()) |
| 54 | for i := range defaultStackSizes { |
| 55 | defaultStackSizes[i] = defaultStackSize |
| 56 | } |
| 57 | stackSizesGlobal.SetInitializer(llvm.ConstArray(functions[0].Type(), defaultStackSizes)) |
| 58 | stackSizesGlobal.SetAlignment(alignment) |
| 59 | // TODO: make this a constant. For some reason, that incrases code size though. |
| 60 | if config.Debug() { |
| 61 | dibuilder := llvm.NewDIBuilder(mod) |
| 62 | dibuilder.CreateCompileUnit(llvm.DICompileUnit{ |
| 63 | Language: 0xb, // DW_LANG_C99 (0xc, off-by-one?) |
| 64 | File: "<unknown>", |
| 65 | Dir: "", |
| 66 | Producer: "TinyGo", |
| 67 | Optimized: true, |
| 68 | }) |
| 69 | ditype := dibuilder.CreateArrayType(llvm.DIArrayType{ |
| 70 | SizeInBits: targetData.TypeAllocSize(stackSizesGlobalType) * 8, |
| 71 | AlignInBits: uint32(alignment * 8), |
| 72 | ElementType: dibuilder.CreateBasicType(llvm.DIBasicType{ |
| 73 | Name: "uintptr", |