github.com/tinygo-org/tinygo@v0.31.3-0.20240404173401-90b0bf646c27/src/runtime/arch_tinygowasm.go (about)

     1  //go:build tinygo.wasm
     2  
     3  package runtime
     4  
     5  import (
     6  	"unsafe"
     7  )
     8  
     9  const GOARCH = "wasm"
    10  
    11  // The bitness of the CPU (e.g. 8, 32, 64).
    12  const TargetBits = 32
    13  
    14  const deferExtraRegs = 0
    15  
    16  const callInstSize = 1 // unknown and irrelevant (llvm.returnaddress doesn't work), so make something up
    17  
    18  //go:extern __heap_base
    19  var heapStartSymbol [0]byte
    20  
    21  //go:extern __global_base
    22  var globalsStartSymbol [0]byte
    23  
    24  const (
    25  	// wasmMemoryIndex is always zero until the multi-memory feature is used.
    26  	//
    27  	// See https://github.com/WebAssembly/multi-memory
    28  	wasmMemoryIndex = 0
    29  
    30  	// wasmPageSize is the size of a page in WebAssembly's 32-bit memory. This
    31  	// is also its only unit of change.
    32  	//
    33  	// See https://www.w3.org/TR/wasm-core-1/#page-size
    34  	wasmPageSize = 64 * 1024
    35  )
    36  
    37  // wasm_memory_size invokes the "memory.size" instruction, which returns the
    38  // current size to the memory at the given index (always wasmMemoryIndex), in
    39  // pages.
    40  //
    41  //export llvm.wasm.memory.size.i32
    42  func wasm_memory_size(index int32) int32
    43  
    44  // wasm_memory_grow invokes the "memory.grow" instruction, which attempts to
    45  // increase the size of the memory at the given index (always wasmMemoryIndex),
    46  // by the delta (in pages). This returns the previous size on success of -1 on
    47  // failure.
    48  //
    49  //export llvm.wasm.memory.grow.i32
    50  func wasm_memory_grow(index int32, delta int32) int32
    51  
    52  var (
    53  	// heapStart is the current memory offset which starts the heap. The heap
    54  	// extends from this offset until heapEnd (exclusive).
    55  	heapStart = uintptr(unsafe.Pointer(&heapStartSymbol))
    56  
    57  	// heapEnd is the current memory length in bytes.
    58  	heapEnd = uintptr(wasm_memory_size(wasmMemoryIndex) * wasmPageSize)
    59  
    60  	globalsStart = uintptr(unsafe.Pointer(&globalsStartSymbol))
    61  	globalsEnd   = uintptr(unsafe.Pointer(&heapStartSymbol))
    62  
    63  	stackTop = uintptr(unsafe.Pointer(&globalsStartSymbol))
    64  )
    65  
    66  func align(ptr uintptr) uintptr {
    67  	// Align to 16, which is the alignment of max_align_t:
    68  	// https://godbolt.org/z/dYqTsWrGq
    69  	const heapAlign = 16
    70  	return (ptr + heapAlign - 1) &^ (heapAlign - 1)
    71  }
    72  
    73  //export tinygo_getCurrentStackPointer
    74  func getCurrentStackPointer() uintptr
    75  
    76  // growHeap tries to grow the heap size. It returns true if it succeeds, false
    77  // otherwise.
    78  func growHeap() bool {
    79  	// Grow memory by the available size, which means the heap size is doubled.
    80  	memorySize := wasm_memory_size(wasmMemoryIndex)
    81  	result := wasm_memory_grow(wasmMemoryIndex, memorySize)
    82  	if result == -1 {
    83  		// Grow failed.
    84  		return false
    85  	}
    86  
    87  	setHeapEnd(uintptr(wasm_memory_size(wasmMemoryIndex) * wasmPageSize))
    88  
    89  	// Heap has grown successfully.
    90  	return true
    91  }