Skip to content
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
25 changes: 19 additions & 6 deletions src/mono/browser/runtime/memory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { VoidPtr, CharPtr } from "./types/emscripten";
import cwraps, { I52Error } from "./cwraps";
import { Module, mono_assert, runtimeHelpers } from "./globals";
import { utf8ToString } from "./strings";
import { mono_log_warn } from "./logging";
import { mono_log_warn, mono_log_error } from "./logging";

const alloca_stack: Array<VoidPtr> = [];
const alloca_buffer_size = 32 * 1024;
Expand Down Expand Up @@ -327,6 +327,10 @@ export function withStackAlloc<T1, T2, T3, TResult> (bytesWanted: number, f: (pt
export function mono_wasm_load_bytes_into_heap (bytes: Uint8Array): VoidPtr {
// pad sizes by 16 bytes for simd
const memoryOffset = Module._malloc(bytes.length + 16);
if (<any>memoryOffset <= 0) {
mono_log_error(`malloc failed to allocate ${(bytes.length + 16)} bytes.`);
throw new Error("Out of memory");
}
const heapBytes = new Uint8Array(localHeapViewU8().buffer, <any>memoryOffset, bytes.length);
heapBytes.set(bytes);
return memoryOffset;
Expand All @@ -338,11 +342,20 @@ export function mono_wasm_load_bytes_into_heap (bytes: Uint8Array): VoidPtr {
export function mono_wasm_load_bytes_into_heap_persistent (bytes: Uint8Array): VoidPtr {
// pad sizes by 16 bytes for simd
const desiredSize = bytes.length + 16;
// wasm memory page size is 64kb. allocations smaller than that are probably best
// serviced by malloc
const memoryOffset = (desiredSize < (64 * 1024))
? Module._malloc(desiredSize)
: Module._sbrk(desiredSize);
// sbrk doesn't allocate whole pages so we can ask it for as many bytes as we want.
let memoryOffset = Module._sbrk(desiredSize);
if (<any>memoryOffset <= 0) {
// sbrk failed. Due to identical bugs in v8 and spidermonkey, this isn't guaranteed to be OOM.
// We use this function early during startup, when OOM shouldn't be possible anyway!
// Log a warning, then retry.
memoryOffset = Module._sbrk(desiredSize);
if (<any>memoryOffset <= 0) {
mono_log_error(`sbrk failed to allocate ${desiredSize} bytes, and failed upon retry.`);
throw new Error("Out of memory");
} else {
mono_log_warn(`sbrk failed to allocate ${desiredSize} bytes, but succeeded upon retry!`);
}
}
const heapBytes = new Uint8Array(localHeapViewU8().buffer, <any>memoryOffset, bytes.length);
heapBytes.set(bytes);
return memoryOffset;
Expand Down
16 changes: 12 additions & 4 deletions src/mono/mono/utils/mono-wasm-pagemgr.c
Original file line number Diff line number Diff line change
Expand Up @@ -237,16 +237,24 @@ acquire_new_pages_initialized (uint32_t page_count) {

// We know that on WASM, sbrk grows the heap as necessary in order to return,
// a region of N zeroed bytes, which isn't necessarily aligned or page-sized
uint8_t *allocation = sbrk ((uint32_t)bytes),
*allocation_end = allocation + bytes;
uint8_t *allocation = sbrk ((uint32_t)bytes);

if (allocation == (uint8_t *)-1) {
// HACK: It is theoretically possible for sbrk to fail in a non-OOM condition
// due to identical bugs in v8 and spidermonkey, so retry exactly once.
allocation = sbrk ((uint32_t)bytes);
if (allocation == (uint8_t *)-1) {
#ifdef MWPM_LOGGING
g_print ("mwpm failed to acquire memory\n");
g_print ("mwpm failed to acquire memory\n");
#endif
return NULL;
return NULL;
} else {
g_print ("MWPM WARNING: sbrk() failed once, then succeeded. Continuing.\n");
}
}

uint8_t *allocation_end = allocation + bytes;

g_assert (allocation_end != allocation);

// If nobody else has called sbrk since we did, stitch the allocations together
Expand Down