diff --git a/include/mimalloc-atomic.h b/include/mimalloc-atomic.h index c8fd2ac1..1b6cb0f4 100644 --- a/include/mimalloc-atomic.h +++ b/include/mimalloc-atomic.h @@ -196,6 +196,11 @@ static inline void mi_atomic_write(volatile uintptr_t* p, uintptr_t x) { asm volatile("yield"); } #endif +#elif defined(__wasi__) + #include + static inline void mi_atomic_yield() { + sched_yield(); + } #else #include static inline void mi_atomic_yield(void) { diff --git a/src/alloc.c b/src/alloc.c index 74159144..da8c69b9 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -441,6 +441,7 @@ char* mi_strndup(const char* s, size_t n) mi_attr_noexcept { return mi_heap_strndup(mi_get_default_heap(),s,n); } +#ifndef __wasi__ // `realpath` using mi_malloc #ifdef _WIN32 #ifndef PATH_MAX @@ -497,6 +498,7 @@ char* mi_heap_realpath(mi_heap_t* heap, const char* fname, char* resolved_name) char* mi_realpath(const char* fname, char* resolved_name) mi_attr_noexcept { return mi_heap_realpath(mi_get_default_heap(),fname,resolved_name); } +#endif /*------------------------------------------------------- C++ new and new_aligned diff --git a/src/init.c b/src/init.c index 8ab520eb..f55b7318 100644 --- a/src/init.c +++ b/src/init.c @@ -148,6 +148,10 @@ uintptr_t _mi_random_shuffle(uintptr_t x) { } uintptr_t _mi_random_init(uintptr_t seed /* can be zero */) { +#ifdef __wasi__ // no ASLR when using WebAssembly, and time granularity may be coarse + uintptr_t x; + arc4random_buf(&x, sizeof x); +#else // Hopefully, ASLR makes our function address random uintptr_t x = (uintptr_t)((void*)&_mi_random_init); x ^= seed; @@ -169,6 +173,7 @@ uintptr_t _mi_random_init(uintptr_t seed /* can be zero */) { for (uintptr_t i = 0; i < max; i++) { x = _mi_random_shuffle(x); } +#endif return x; } @@ -269,7 +274,9 @@ static bool _mi_heap_done(void) { // to set up the thread local keys. // -------------------------------------------------------- -#ifndef _WIN32 +#ifdef __wasi__ +// no pthreads in the WebAssembly Standard Interface +#elif !defined(_WIN32) #define MI_USE_PTHREADS #endif @@ -290,6 +297,8 @@ static bool _mi_heap_done(void) { static void mi_pthread_done(void* value) { if (value!=NULL) mi_thread_done(); } +#elif defined(__wasi__) +// no pthreads in the WebAssembly Standard Interface #else #pragma message("define a way to call mi_thread_done when a thread is done") #endif diff --git a/src/os.c b/src/os.c index 500229f9..d84e33b0 100644 --- a/src/os.c +++ b/src/os.c @@ -16,6 +16,8 @@ terms of the MIT license. A copy of the license can be found in the file #if defined(_WIN32) #include +#elif defined(__wasi__) +// stdlib.h is all we need, and has already been included in mimalloc.h #else #include // mmap #include // sysconf @@ -136,6 +138,11 @@ void _mi_os_init(void) { } } } +#elif defined(__wasi__) +void _mi_os_init() { + os_page_size = 0x10000; // WebAssembly has a fixed page size: 64KB + os_alloc_granularity = 16; +} #else void _mi_os_init() { // get the page size @@ -161,6 +168,8 @@ static bool mi_os_mem_free(void* addr, size_t size, mi_stats_t* stats) bool err = false; #if defined(_WIN32) err = (VirtualFree(addr, 0, MEM_RELEASE) == 0); +#elif defined(__wasi__) + err = 0; // WebAssembly's heap cannot be shrunk #else err = (munmap(addr, size) == -1); #endif @@ -216,6 +225,19 @@ static void* mi_win_virtual_alloc(void* addr, size_t size, size_t try_alignment, return p; } +#elif defined(__wasi__) +static void* mi_wasm_heap_grow(size_t size, size_t try_alignment) { + uintptr_t base = __builtin_wasm_memory_size(0) * os_page_size; + uintptr_t aligned_base = _mi_align_up(base, (uintptr_t) try_alignment); + size_t alloc_size = aligned_base - base + size; + mi_assert(alloc_size >= size); + if (alloc_size < size) return NULL; + if (__builtin_wasm_memory_grow(0, alloc_size / os_page_size) == SIZE_MAX) { + errno = ENOMEM; + return NULL; + } + return (void*) aligned_base; +} #else static void* mi_unix_mmap(size_t size, size_t try_alignment, int protect_flags) { void* p = NULL; @@ -272,6 +294,8 @@ static void* mi_os_mem_alloc(size_t size, size_t try_alignment, bool commit, mi_ int flags = MEM_RESERVE; if (commit) flags |= MEM_COMMIT; p = mi_win_virtual_alloc(NULL, size, try_alignment, flags); +#elif defined(__wasi__) + p = mi_wasm_heap_grow(size, try_alignment); #else int protect_flags = (commit ? (PROT_WRITE | PROT_READ) : PROT_NONE); p = mi_unix_mmap(size, try_alignment, protect_flags); @@ -434,6 +458,8 @@ static bool mi_os_commitx(void* addr, size_t size, bool commit, bool conservativ BOOL ok = VirtualFree(start, csize, MEM_DECOMMIT); err = (ok ? 0 : GetLastError()); } + #elif defined(__wasi__) + // WebAssembly guests can't control memory protection #else err = mprotect(start, csize, (commit ? (PROT_READ | PROT_WRITE) : PROT_NONE)); #endif @@ -496,6 +522,8 @@ static bool mi_os_resetx(void* addr, size_t size, bool reset, mi_stats_t* stats) advice = MADV_DONTNEED; err = madvise(start, csize, advice); } +#elif defined(__wasi__) + int err = 0; #else int err = madvise(start, csize, MADV_DONTNEED); #endif @@ -543,6 +571,8 @@ static bool mi_os_protectx(void* addr, size_t size, bool protect) { DWORD oldprotect = 0; BOOL ok = VirtualProtect(start, csize, protect ? PAGE_NOACCESS : PAGE_READWRITE, &oldprotect); err = (ok ? 0 : GetLastError()); +#elif defined(__wasi__) + err = 0; #else err = mprotect(start, csize, protect ? PROT_NONE : (PROT_READ | PROT_WRITE)); #endif diff --git a/src/stats.c b/src/stats.c index d4c8dade..2b15bf9e 100644 --- a/src/stats.c +++ b/src/stats.c @@ -407,7 +407,11 @@ static void mi_process_info(double* utime, double* stime, size_t* peak_rss, size } #else +#ifndef __wasi__ +// WebAssembly instances are not processes #pragma message("define a way to get process info") +#endif + static void mi_process_info(double* utime, double* stime, size_t* peak_rss, size_t* page_faults, size_t* page_reclaim, size_t* peak_commit) { *peak_rss = 0; *page_faults = 0;