Files
tinygo/src/runtime/runtime_wasmentry.go
T
Felipe Gené 31fff2c9a3 runtime: run syscall/js finalizers on wasm without a manual GC (#5545)
* runtime: run syscall/js finalizers on wasm without a manual GC

* runtime: address review feedback on finalizer idle GC

* runtime: clear a finished task's args pointer so its arguments are collectable

* runtime: skip the finalizer scan with a per-block registration bit

* runtime: guard the finalizer registration bitmap with gcLock

* testdata: cover finalizer invariants on every scheduler

* main_test: limit the finalizer scheduler variants to linux and darwin

* testdata: wait for the finalizer queue to drain before asserting

* testdata: make the finalizer counters atomic and wait for a known drain count

* runtime: add finalizer bookkeeping asserts under runtime_asserts

* runtime: address finalizer GC review feedback

* testdata: strengthen blocked stack finalizer test

* runtime: fix finalizer cleanup edge cases

* runtime: decouple wasm export scheduling from finalizers

* runtime: avoid redundant wakeups for re-entrant wasm exports

* runtime: simplify finalizer comments
2026-08-26 20:03:44 +02:00

87 lines
2.5 KiB
Go

//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 (
"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")
}
}