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  

View as plain text