//go:build tinygo.wasm package runtime // Entry points for WebAssembly modules, and runtime support for // //go:wasmexport: runtime.wasmExport* function calls are inserted by the // compiler for //go:wasmexport support. import ( "internal/task" "unsafe" ) // This is the _start entry point, when using -buildmode=default. func wasmEntryCommand() { // These need to be initialized early so that the heap can be initialized. initializeCalled = true heapStart = uintptr(unsafe.Pointer(&heapStartSymbol)) heapEnd = uintptr(wasm_memory_size(0) * wasmPageSize) run() if mainExited { // To make sure wasm_exec.js knows that we've exited, exit explicitly. mainReturnExit() } } // This is the _initialize entry point, when using -buildmode=c-shared. func wasmEntryReactor() { // This function is called before any //go:wasmexport functions are called // to initialize everything. It must not block. initializeCalled = true // Initialize the heap. heapStart = uintptr(unsafe.Pointer(&heapStartSymbol)) heapEnd = uintptr(wasm_memory_size(0) * wasmPageSize) initHeap() initRand() if hasScheduler { // A package initializer might do funky stuff like start a goroutine and // wait until it completes, so we have to run package initializers in a // goroutine. go func() { initAll() }() scheduler(true) } else { // There are no goroutines (except for the main one, if you can call it // that), so we can just run all the package initializers. initAll() } } // This is the _start entry point, when using -buildmode=wasi-legacy. func wasmEntryLegacy() { // These need to be initialized early so that the heap can be initialized. initializeCalled = true heapStart = uintptr(unsafe.Pointer(&heapStartSymbol)) heapEnd = uintptr(wasm_memory_size(0) * wasmPageSize) run() } // Whether the runtime was initialized by a call to _initialize or _start. var initializeCalled bool func wasmExportCheckRun() { switch { case !initializeCalled: runtimePanic("//go:wasmexport function called before runtime initialization") case mainExited: runtimePanic("//go:wasmexport function called after main.main returned") } } // Called from within a //go:wasmexport wrapper (the one that's exported from // the wasm module) after the goroutine has been queued. Just run the scheduler, // and check that the goroutine finished when the scheduler is idle (as required // by the //go:wasmexport proposal). // // This function is not called when the scheduler is disabled. func wasmExportRun(done *bool) { scheduler(true) if !*done { runtimePanic("//go:wasmexport function did not finish") } } // Called from the goroutine wrapper for the //go:wasmexport function. It just // signals to the runtime that the //go:wasmexport call has finished, and can // switch back to the wasmExportRun function. // // This function is not called when the scheduler is disabled. func wasmExportExit() { // Signal to the scheduler that it should return, since this call to a // //go:wasmexport function has exited. schedulerExit = true task.Pause() // TODO: we could cache the allocated stack so we don't have to keep // allocating a new stack on every //go:wasmexport call. }