1 //:build wasm
2 3 package runtime
4 5 import "unsafe"
6 7 // Arena memory for wasm32 comes from linear memory growth, not mmap.
8 //
9 // The platform files otherwise assume mmap/munmap and the Linux MAP_*/PROT_*
10 // constants; wasm has neither. What the allocator actually needs from a
11 // region is that it is contiguous, zeroed, page-aligned, and stable for the
12 // lifetime of the domain - all of which `memory.grow` provides, because the
13 // new pages are appended past everything already in use (data segments,
14 // stack, and previously handed-out regions) and WebAssembly guarantees fresh
15 // pages are zero-filled.
16 //
17 // Growth is a bump allocation: memory is never given back within a domain.
18 // That matches the arena model, where regions are only released when the
19 // domain exits, and a wasm process has exactly one domain.
20 21 // sysMemBump is the next free offset in linear memory. Zero means "not yet
22 // initialised"; the first call seeds it from the current memory size, since
23 // all memory below that is already spoken for.
24 var sysMemBump uintptr
25 26 // sysMap returns a zeroed, 64 KiB-aligned region of size bytes, or nil if
27 // linear memory could not be grown.
28 func sysMap(size uintptr) unsafe.Pointer {
29 if size == 0 {
30 return nil
31 }
32 size = (size + wasmPageSize - 1) &^ (wasmPageSize - 1)
33 pages := int32(size / wasmPageSize)
34 35 if sysMemBump == 0 {
36 sysMemBump = uintptr(wasm_memory_size(0)) * wasmPageSize
37 }
38 prev := wasm_memory_grow(0, pages)
39 if prev < 0 {
40 return nil
41 }
42 base := sysMemBump
43 sysMemBump = base + size
44 // memory.grow returns the previous page count, so the pages this call
45 // added start exactly at prev*wasmPageSize. A bump cursor that does not
46 // agree means the cursor was seeded after something else already grew
47 // memory, which would hand out overlapping regions - fail loud rather
48 // than corrupt the heap.
49 if uintptr(prev)*wasmPageSize != base {
50 runtimePanic("wasm: memory.grow overtook the region cursor")
51 }
52 return unsafe.Pointer(base)
53 }
54 55 // sysMapShared is sysMap: there is no second address space to share with.
56 // A wasm domain has no fork, so "shared" memory is just memory.
57 func sysMapShared(size uintptr) unsafe.Pointer {
58 return sysMap(size)
59 }
60 61 // sysUnmap is a no-op. Linear memory cannot be returned to the host, and
62 // there is no allocator below us that could reuse it. The arena model only
63 // releases at domain exit, at which point the whole process memory goes away.
64 func sysUnmap(p unsafe.Pointer, size uintptr) {
65 _ = p
66 _ = size
67 }
68 69 // InitCShared initializes the runtime for c-shared mode, where main() never
70 // runs and the first exported function must bring the domain up. The unix
71 // implementation lives in runtime_unix.mx and also sets up epoll and the
72 // secure-allocator lockdown fd, neither of which exists on wasm; the domain
73 // root and package inits are what the exported entry points actually need.
74 var csharedInitDone bool
75 76 func InitCShared() {
77 if csharedInitDone {
78 return
79 }
80 csharedInitDone = true
81 allocateHeap()
82 initRand()
83 initAll()
84 }
85 86 // MoxieWrite has no wasm meaning: it exists so the native compiler and its
87 // forked workers can exchange bytes over a pipe fd, and wasm has neither
88 // fork nor pipe fds. The compiler forces its serial path on wasm, so this is
89 // only here to satisfy the declaration while keeping the build honest about
90 // what happened if anything ever does reach it.
91 func MoxieWrite(fd int32, buf unsafe.Pointer, count int32) int32 {
92 _ = fd
93 _ = buf
94 _ = count
95 return -1
96 }
97 98 // MoxieRead is the counterpart to MoxieWrite; see the note there.
99 func MoxieRead(fd int32, buf unsafe.Pointer, count int32) int32 {
100 _ = fd
101 _ = buf
102 _ = count
103 return -1
104 }
105