createGoroutineStartWrapper creates a wrapper for the task-based implementation of goroutines. For example, to call a function like this: func add(x, y int) int { ... } It creates a wrapper like this: func add$gowrapper(ptr *unsafe.Pointer) { args := (*struct{ x, y int })(ptr
(fnType llvm.Type, fn llvm.Value, prefix string, hasContext, isWasmExport bool, pos token.Pos)
| 287 | // false, the parameter bundle is assumed to have no context parameter and undef |
| 288 | // is passed instead. |
| 289 | func (c *compilerContext) createGoroutineStartWrapper(fnType llvm.Type, fn llvm.Value, prefix string, hasContext, isWasmExport bool, pos token.Pos) llvm.Value { |
| 290 | var wrapper llvm.Value |
| 291 | |
| 292 | b := &builder{ |
| 293 | compilerContext: c, |
| 294 | Builder: c.ctx.NewBuilder(), |
| 295 | } |
| 296 | defer b.Dispose() |
| 297 | |
| 298 | var deadlock llvm.Value |
| 299 | var deadlockType llvm.Type |
| 300 | if c.Scheduler == "asyncify" { |
| 301 | deadlockType, deadlock = c.getFunction(c.program.ImportedPackage("runtime").Members["deadlock"].(*ssa.Function)) |
| 302 | } |
| 303 | |
| 304 | if !fn.IsAFunction().IsNil() { |
| 305 | // See whether this wrapper has already been created. If so, return it. |
| 306 | name := fn.Name() |
| 307 | wrapperName := name + "$gowrapper" |
| 308 | if isWasmExport { |
| 309 | wrapperName += "-wasmexport" |
| 310 | } |
| 311 | wrapper = c.mod.NamedFunction(wrapperName) |
| 312 | if !wrapper.IsNil() { |
| 313 | return llvm.ConstPtrToInt(wrapper, c.uintptrType) |
| 314 | } |
| 315 | |
| 316 | // Create the wrapper. |
| 317 | wrapperType := llvm.FunctionType(c.ctx.VoidType(), []llvm.Type{c.dataPtrType}, false) |
| 318 | wrapper = llvm.AddFunction(c.mod, wrapperName, wrapperType) |
| 319 | c.addStandardAttributes(wrapper) |
| 320 | wrapper.SetLinkage(llvm.LinkOnceODRLinkage) |
| 321 | wrapper.SetUnnamedAddr(true) |
| 322 | wrapper.AddAttributeAtIndex(-1, c.ctx.CreateStringAttribute("tinygo-gowrapper", name)) |
| 323 | entry := c.ctx.AddBasicBlock(wrapper, "entry") |
| 324 | b.SetInsertPointAtEnd(entry) |
| 325 | |
| 326 | if c.Debug { |
| 327 | pos := c.program.Fset.Position(pos) |
| 328 | diFuncType := c.dibuilder.CreateSubroutineType(llvm.DISubroutineType{ |
| 329 | File: c.getDIFile(pos.Filename), |
| 330 | Parameters: nil, // do not show parameters in debugger |
| 331 | Flags: 0, // ? |
| 332 | }) |
| 333 | difunc := c.dibuilder.CreateFunction(c.getDIFile(pos.Filename), llvm.DIFunction{ |
| 334 | Name: "<goroutine wrapper>", |
| 335 | File: c.getDIFile(pos.Filename), |
| 336 | Line: pos.Line, |
| 337 | Type: diFuncType, |
| 338 | LocalToUnit: true, |
| 339 | IsDefinition: true, |
| 340 | ScopeLine: 0, |
| 341 | Flags: llvm.FlagPrototyped, |
| 342 | Optimized: true, |
| 343 | }) |
| 344 | wrapper.SetSubprogram(difunc) |
| 345 | b.SetCurrentDebugLocation(uint(pos.Line), uint(pos.Column), difunc, llvm.Metadata{}) |
| 346 | } |
no test coverage detected