Create an exported wrapper function for functions with the //go:wasmexport pragma. This wrapper function is quite complex when the scheduler is enabled: it needs to start a new goroutine each time the exported function is called.
()
| 126 | // pragma. This wrapper function is quite complex when the scheduler is enabled: |
| 127 | // it needs to start a new goroutine each time the exported function is called. |
| 128 | func (b *builder) createWasmExport() { |
| 129 | pos := b.info.wasmExportPos |
| 130 | if b.info.exported { |
| 131 | // //export really shouldn't be used anymore when //go:wasmexport is |
| 132 | // available, because //go:wasmexport is much better defined. |
| 133 | b.addError(pos, "cannot use //export and //go:wasmexport at the same time") |
| 134 | return |
| 135 | } |
| 136 | |
| 137 | const suffix = "#wasmexport" |
| 138 | |
| 139 | // Declare the exported function. |
| 140 | paramTypes := b.llvmFnType.ParamTypes() |
| 141 | exportedFnType := llvm.FunctionType(b.llvmFnType.ReturnType(), paramTypes[:len(paramTypes)-1], false) |
| 142 | exportedFn := llvm.AddFunction(b.mod, b.fn.RelString(nil)+suffix, exportedFnType) |
| 143 | b.addStandardAttributes(exportedFn) |
| 144 | llvmutil.AppendToGlobal(b.mod, "llvm.used", exportedFn) |
| 145 | exportedFn.AddFunctionAttr(b.ctx.CreateStringAttribute("wasm-export-name", b.info.wasmExport)) |
| 146 | |
| 147 | // Create a builder for this wrapper function. |
| 148 | builder := newBuilder(b.compilerContext, b.ctx.NewBuilder(), b.fn) |
| 149 | defer builder.Dispose() |
| 150 | |
| 151 | // Define this function as a separate function in DWARF |
| 152 | if b.Debug { |
| 153 | if b.fn.Syntax() != nil { |
| 154 | // Create debug info file if needed. |
| 155 | pos := b.program.Fset.Position(pos) |
| 156 | builder.difunc = builder.attachDebugInfoRaw(b.fn, exportedFn, suffix, pos.Filename, pos.Line) |
| 157 | } |
| 158 | builder.setDebugLocation(pos) |
| 159 | } |
| 160 | |
| 161 | // Create a single basic block inside of it. |
| 162 | bb := llvm.AddBasicBlock(exportedFn, "entry") |
| 163 | builder.SetInsertPointAtEnd(bb) |
| 164 | |
| 165 | // Insert an assertion to make sure this //go:wasmexport function is not |
| 166 | // called at a time when it is not allowed (for example, before the runtime |
| 167 | // is initialized). |
| 168 | builder.createRuntimeCall("wasmExportCheckRun", nil, "") |
| 169 | |
| 170 | if b.Scheduler == "none" { |
| 171 | // When the scheduler has been disabled, this is really trivial: just |
| 172 | // call the function. |
| 173 | params := exportedFn.Params() |
| 174 | params = append(params, llvm.ConstNull(b.dataPtrType)) // context parameter |
| 175 | retval := builder.CreateCall(b.llvmFnType, b.llvmFn, params, "") |
| 176 | if b.fn.Signature.Results() == nil { |
| 177 | builder.CreateRetVoid() |
| 178 | } else { |
| 179 | builder.CreateRet(retval) |
| 180 | } |
| 181 | |
| 182 | } else { |
| 183 | // The scheduler is enabled, so we need to start a new goroutine, wait |
| 184 | // for it to complete, and read the result value. |
| 185 |
no test coverage detected