Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[wasm] stop using mmap/munmap #108512

Merged
merged 6 commits into from
Oct 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/mono/browser/browser.proj
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@
<EmccExportedFunction Include="_malloc" />
<EmccExportedFunction Include="_sbrk" />
<EmccExportedFunction Include="_memalign" />
<EmccExportedFunction Include="_posix_memalign" />
<EmccExportedFunction Include="_memset" />
<EmccExportedFunction Include="_ntohs" />
<EmccExportedFunction Include="stackAlloc" />
Expand Down
10 changes: 10 additions & 0 deletions src/mono/mono/sgen/sgen-los.c
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,12 @@ get_los_section_memory (size_t size)
section->next = los_sections;
los_sections = section;

#ifdef HOST_WASM
// on WASM there is no mmap and alignment has large overhead
sgen_los_memory_usage_total += LOS_SECTION_SIZE + LOS_SECTION_SIZE;
#else
sgen_los_memory_usage_total += LOS_SECTION_SIZE;
#endif
++los_num_sections;

goto retry;
Expand Down Expand Up @@ -542,7 +547,12 @@ sgen_los_sweep (void)
sgen_memgov_release_space (LOS_SECTION_SIZE, SPACE_LOS);
section = next;
--los_num_sections;
#ifdef HOST_WASM
// on WASM there is no mmap and alignment has large overhead
sgen_los_memory_usage_total -= LOS_SECTION_SIZE + LOS_SECTION_SIZE;
#else
sgen_los_memory_usage_total -= LOS_SECTION_SIZE;
#endif
continue;
}

Expand Down
9 changes: 6 additions & 3 deletions src/mono/mono/sgen/sgen-marksweep.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,13 @@ static int ms_block_size;
* Don't allocate single blocks, but alloc a contingent of this many
* blocks in one swoop. This must be a power of two.
*/
#ifndef TARGET_WASM
#define MS_BLOCK_ALLOC_NUM 32
#else
// WASM doesn't support partial munmap, so we can't free individual blocks
// we use posix_memalign and free the whole block at once
#define MS_BLOCK_ALLOC_NUM 1
#endif

#define MS_NUM_MARK_WORDS ((ms_block_size / SGEN_ALLOC_ALIGN + sizeof (guint32) * 8 - 1) / (sizeof (guint32) * 8))

Expand Down Expand Up @@ -2140,9 +2146,6 @@ major_free_swept_blocks (size_t section_reserve)
* a VirtualAlloc ()-ed block.
*/
return;
#elif defined(HOST_WASM)
if (!mono_opt_wasm_mmap)
return;
#endif

{
Expand Down
2 changes: 1 addition & 1 deletion src/mono/mono/utils/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ set(utils_arch_sources "${utils_arch_sources};mono-hwcap-riscv.c")
elseif(TARGET_S390X)
set(utils_arch_sources "${utils_arch_sources};mono-hwcap-s390x.c")
elseif(TARGET_WASM)
set(utils_arch_sources "${utils_arch_sources};mono-hwcap-wasm.c;mono-mmap-wasm.c;mono-wasm-pagemgr.c")
set(utils_arch_sources "${utils_arch_sources};mono-hwcap-wasm.c;mono-mmap-wasm.c")
elseif(TARGET_WASI)
set(utils_arch_sources "${utils_arch_sources};mono-hwcap-wasm.c")
elseif(TARGET_POWERPC OR TARGET_POWERPC64)
Expand Down
2 changes: 1 addition & 1 deletion src/mono/mono/utils/lock-free-alloc.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ typedef struct {
} MonoLockFreeAllocator;

#ifdef HOST_WASM
#define LOCK_FREE_ALLOC_SB_MAX_SIZE (mono_opt_wasm_mmap ? 65536 : 16384)
#define LOCK_FREE_ALLOC_SB_MAX_SIZE 16384 * 32
#else
#define LOCK_FREE_ALLOC_SB_MAX_SIZE 16384
#endif
Expand Down
146 changes: 30 additions & 116 deletions src/mono/mono/utils/mono-mmap-wasm.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,6 @@
#include <mono/utils/atomic.h>
#include <mono/utils/options.h>

#include "mono-wasm-pagemgr.h"

#define BEGIN_CRITICAL_SECTION do { \
MonoThreadInfo *__info = mono_thread_info_current_unchecked (); \
if (__info) __info->inside_critical_region = TRUE; \
Expand All @@ -37,22 +35,7 @@
int
mono_pagesize (void)
{
if (mono_opt_wasm_mmap)
return MWPM_PAGE_SIZE;

static int saved_pagesize = 0;

if (saved_pagesize)
return saved_pagesize;

// Prefer sysconf () as it's signal safe.
#if defined (HAVE_SYSCONF) && defined (_SC_PAGESIZE)
saved_pagesize = sysconf (_SC_PAGESIZE);
#else
saved_pagesize = getpagesize ();
#endif

return saved_pagesize;
return 16384;
}

int
Expand Down Expand Up @@ -96,122 +79,50 @@ mono_setmmapjit (int flag)
/* Ignored on HOST_WASM */
}

static void*
valloc_impl (void *addr, size_t size, int flags, MonoMemAccountType type)
{
void *ptr;
int mflags = 0;
int prot = prot_from_flags (flags);

if (!mono_valloc_can_alloc (size))
return NULL;

if (size == 0)
/* emscripten throws an exception on 0 length */
return NULL;

mflags |= MAP_ANONYMOUS;
mflags |= MAP_PRIVATE;

BEGIN_CRITICAL_SECTION;
if (mono_opt_wasm_mmap) {
// FIXME: Make this work if the requested address range is free
if ((flags & MONO_MMAP_FIXED) && addr)
return NULL;

ptr = mwpm_alloc_range (size, (flags & MONO_MMAP_NOZERO) == 0);
if (!ptr)
return NULL;
} else
ptr = mmap (addr, size, prot, mflags, -1, 0);
END_CRITICAL_SECTION;

if (ptr == MAP_FAILED)
return NULL;

mono_account_mem (type, (ssize_t)size);

return ptr;
}

void*
mono_valloc (void *addr, size_t size, int flags, MonoMemAccountType type)
mono_valloc (void *addr, size_t length, int flags, MonoMemAccountType type)
{
#if HOST_WASI
// WASI implements mmap using malloc, so the returned address is not page aligned
// and our code depends on it
g_assert (!addr);
return mono_valloc_aligned (size, mono_pagesize (), flags, type);
#else
return valloc_impl (addr, size, flags, type);
#endif
g_assert (addr == NULL);
return mono_valloc_aligned (length, mono_pagesize (), flags, type);
}

static GHashTable *valloc_hash;

typedef struct {
void *addr;
int size;
} VallocInfo;

void*
mono_valloc_aligned (size_t size, size_t alignment, int flags, MonoMemAccountType type)
{
// We don't need padding if the alignment is compatible with the page size
if (mono_opt_wasm_mmap && ((MWPM_PAGE_SIZE % alignment) == 0))
return valloc_impl (NULL, size, flags, type);

/* Allocate twice the memory to be able to put the block on an aligned address */
char *mem = (char *) valloc_impl (NULL, size + alignment, flags, type);
char *aligned;
#ifdef DISABLE_THREADS
void *old_sbrk = NULL;
if ((flags & MONO_MMAP_NOZERO) == 0) {
old_sbrk = sbrk (0);
}
#endif

if (!mem)
void *res = NULL;
if (posix_memalign (&res, alignment, size))
return NULL;

aligned = mono_aligned_address (mem, size, alignment);
#ifdef DISABLE_THREADS
if ((flags & MONO_MMAP_NOZERO) == 0 && old_sbrk > res) {
// this means that we got an old block, not the new block from sbrk
memset (res, 0, size);
}
#else
if ((flags & MONO_MMAP_NOZERO) == 0) {
memset (res, 0, size);
}
#endif

/* The mmap implementation in emscripten cannot unmap parts of regions */
/* Free the other two parts in when 'aligned' is freed */
// FIXME: This doubles the memory usage
if (!valloc_hash)
valloc_hash = g_hash_table_new (NULL, NULL);
VallocInfo *info = g_new0 (VallocInfo, 1);
info->addr = mem;
info->size = size + alignment;
g_hash_table_insert (valloc_hash, aligned, info);
mono_account_mem (type, (ssize_t)size);

return aligned;
return res;
}

int
mono_vfree (void *addr, size_t length, MonoMemAccountType type)
{
VallocInfo *info = (VallocInfo*)(valloc_hash ? g_hash_table_lookup (valloc_hash, addr) : NULL);

if (info) {
/*
* We are passed the aligned address in the middle of the mapping allocated by
* mono_valloc_align (), free the original mapping.
*/
BEGIN_CRITICAL_SECTION;
if (mono_opt_wasm_mmap)
mwpm_free_range (info->addr, info->size);
else
munmap (info->addr, info->size);
END_CRITICAL_SECTION;
g_free (info);
g_hash_table_remove (valloc_hash, addr);
} else {
// FIXME: We could be trying to unmap part of an aligned mapping, in which case the
// hash lookup failed because addr isn't exactly the start of the mapping.
// Ideally if the custom page manager is enabled, we won't have done aligned alloc.
BEGIN_CRITICAL_SECTION;
if (mono_opt_wasm_mmap)
mwpm_free_range (addr, length);
else
munmap (addr, length);
END_CRITICAL_SECTION;
}
// NOTE: this doesn't implement partial freeing like munmap does
// we set MS_BLOCK_ALLOC_NUM to 1 to avoid partial freeing
g_free (addr);

mono_account_mem (type, -(ssize_t)length);

Expand Down Expand Up @@ -267,6 +178,9 @@ mono_file_unmap (void *addr, void *handle)
int
mono_mprotect (void *addr, size_t length, int flags)
{
if (flags & MONO_MMAP_DISCARD) {
memset (addr, 0, length);
}
return 0;
}

Expand Down
Loading
Loading