Source file src/runtime/stackswitch_wasm.go
1 // Copyright 2026 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 //go:build wasm.stackswitch 6 7 // Continuation table for WebAssembly stack switching (GOWASM=stackswitch). 8 // 9 // With stack switching, a g's WebAssembly execution stack is a continuation, 10 // a reference of type (ref null $cont). Reference values are opaque and 11 // cannot be stored in linear memory, so they cannot live in a g. Instead the 12 // linker declares a continuation table, wasm table wasmContTable, and every 13 // g owns one slot of it, recorded in g.wasmCont.index. A slot holds the g's 14 // suspended continuation, or null if the g has not started yet. 15 // 16 // m0.g0 is allocated statically rather than by malg, so its index is the zero 17 // value: slot wasmContG0Slot belongs to it. malg gives every other g a slot 18 // of its own, starting at 1, which the g and its continuation keep for their 19 // existence, including while the g is on a free list. Like the g's 20 // themselves, slots are never freed, so the table grows to the number of g's 21 // ever allocated. 22 // 23 // wasm runs a single thread, so the allocation state below needs no locking. 24 25 package runtime 26 27 const ( 28 // wasmContTable is the index of the continuation table among the 29 // module's wasm tables. It must match cmd/link/internal/wasm's 30 // writeTableSec, which declares it with an initial size of 31 // contTableInitialSize. Assembly refers to it as $const_wasmContTable. 32 wasmContTable = 1 33 34 // wasmContG0Slot is m0.g0's slot in the continuation table. 35 // Assembly refers to it as $const_wasmContG0Slot. 36 wasmContG0Slot = 0 37 ) 38 39 // wasmContPerG is the per-g state of WebAssembly stack switching. 40 type wasmContPerG struct { 41 // index is the g's slot in the continuation table: wasmContG0Slot for 42 // m0.g0, and a slot of its own, assigned by malg, for every other g. 43 index int32 44 } 45 46 var ( 47 wasmContLast int32 // the highest slot assigned by wasmContAlloc so far 48 wasmContSize int32 // the continuation table's size, as last read or grown 49 ) 50 51 // wasmContAlloc gives gp, which malg just allocated, the next unused slot of 52 // the continuation table, growing the table if the slot does not fit. 53 func wasmContAlloc(gp *g) { 54 slot := wasmContLast + 1 55 if slot >= wasmContSize { 56 wasmContGrow(slot) 57 } 58 wasmContLast = slot 59 gp.wasmCont.index = slot 60 } 61 62 // wasmContGrow grows the continuation table so that it has slot n. It at 63 // least doubles the table and does not depend on the table's initial 64 // size, which the linker sets. 65 func wasmContGrow(n int32) { 66 size := wasmContTableSize() 67 if n >= size { 68 delta := max(size, n+1-size) 69 if wasmContTableGrow(delta) < 0 { 70 throw("runtime: cannot grow WebAssembly continuation table") 71 } 72 size += delta 73 } 74 wasmContSize = size 75 } 76 77 // Implemented in stackswitch_wasm.s. 78 79 // wasmContTableSize returns the size of the continuation table (table.size). 80 func wasmContTableSize() int32 81 82 // wasmContTableGrow appends delta null slots to the continuation table and 83 // returns its previous size, or -1 if it cannot grow (table.grow). 84 func wasmContTableGrow(delta int32) int32 85