mem_wasm.mx raw

   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