Source file src/runtime/mem_js.go

     1  // Copyright 2018 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 js && wasm
     6  
     7  package runtime
     8  
     9  import (
    10  	"unsafe"
    11  )
    12  
    13  // Don't split the stack as this function may be invoked without a valid G,
    14  // which prevents us from allocating more stack.
    15  //go:nosplit
    16  func sysAlloc(n uintptr, sysStat *sysMemStat) unsafe.Pointer {
    17  	p := sysReserve(nil, n)
    18  	sysMap(p, n, sysStat)
    19  	return p
    20  }
    21  
    22  func sysUnused(v unsafe.Pointer, n uintptr) {
    23  }
    24  
    25  func sysUsed(v unsafe.Pointer, n uintptr) {
    26  }
    27  
    28  func sysHugePage(v unsafe.Pointer, n uintptr) {
    29  }
    30  
    31  // Don't split the stack as this function may be invoked without a valid G,
    32  // which prevents us from allocating more stack.
    33  //go:nosplit
    34  func sysFree(v unsafe.Pointer, n uintptr, sysStat *sysMemStat) {
    35  	sysStat.add(-int64(n))
    36  }
    37  
    38  func sysFault(v unsafe.Pointer, n uintptr) {
    39  }
    40  
    41  var reserveEnd uintptr
    42  
    43  func sysReserve(v unsafe.Pointer, n uintptr) unsafe.Pointer {
    44  	// TODO(neelance): maybe unify with mem_plan9.go, depending on how https://github.com/WebAssembly/design/blob/master/FutureFeatures.md#finer-grained-control-over-memory turns out
    45  
    46  	if v != nil {
    47  		// The address space of WebAssembly's linear memory is contiguous,
    48  		// so requesting specific addresses is not supported. We could use
    49  		// a different address, but then mheap.sysAlloc discards the result
    50  		// right away and we don't reuse chunks passed to sysFree.
    51  		return nil
    52  	}
    53  
    54  	// Round up the initial reserveEnd to 64 KiB so that
    55  	// reservations are always aligned to the page size.
    56  	initReserveEnd := alignUp(lastmoduledatap.end, physPageSize)
    57  	if reserveEnd < initReserveEnd {
    58  		reserveEnd = initReserveEnd
    59  	}
    60  	v = unsafe.Pointer(reserveEnd)
    61  	reserveEnd += alignUp(n, physPageSize)
    62  
    63  	current := currentMemory()
    64  	// reserveEnd is always at a page boundary.
    65  	needed := int32(reserveEnd / physPageSize)
    66  	if current < needed {
    67  		if growMemory(needed-current) == -1 {
    68  			return nil
    69  		}
    70  		resetMemoryDataView()
    71  	}
    72  
    73  	return v
    74  }
    75  
    76  func currentMemory() int32
    77  func growMemory(pages int32) int32
    78  
    79  // resetMemoryDataView signals the JS front-end that WebAssembly's memory.grow instruction has been used.
    80  // This allows the front-end to replace the old DataView object with a new one.
    81  func resetMemoryDataView()
    82  
    83  func sysMap(v unsafe.Pointer, n uintptr, sysStat *sysMemStat) {
    84  	sysStat.add(int64(n))
    85  }
    86  

View as plain text