diff --git a/libraries/ghc-compact/tests/T18757.stdout-wasm32-unknown-wasi b/libraries/ghc-compact/tests/T18757.stdout-wasm32-unknown-wasi
new file mode 100644
index 0000000000000000000000000000000000000000..ca45db43d2a078243792e18e8ebbcd1fd6be460e
--- /dev/null
+++ b/libraries/ghc-compact/tests/T18757.stdout-wasm32-unknown-wasi
@@ -0,0 +1 @@
+[61420,61420,61420,60388,60132,60132,60132,60132,60132,60132,60132,60132,60132,60132,60132,60132,60132,60132,60132,60132,60132,60132,60132,60132,60132,60132,60132,60132,60132,60132,60132,60132,60132,60132]
diff --git a/rts/include/rts/Constants.h b/rts/include/rts/Constants.h
index e18a2c7bb91b4b3779d436d796a649b80f891602..b3959ef8aecf0ff95562484d31768ae6370de79f 100644
--- a/rts/include/rts/Constants.h
+++ b/rts/include/rts/Constants.h
@@ -170,7 +170,11 @@
 #define BLOCK_SHIFT  12
 
 /* The size of a megablock (2^MBLOCK_SHIFT bytes) */
+#if defined(wasm32_HOST_ARCH)
+#define MBLOCK_SHIFT   16
+#else
 #define MBLOCK_SHIFT   20
+#endif
 
 /* -----------------------------------------------------------------------------
    Bitmap/size fields (used in info tables)
diff --git a/rts/sm/NonMoving.h b/rts/sm/NonMoving.h
index 652ae7a3b0d17961fe71fff09985c2b6a693c2b7..dc9e6864eaaa0f49b9ab38fbe60d278c464948bc 100644
--- a/rts/sm/NonMoving.h
+++ b/rts/sm/NonMoving.h
@@ -17,7 +17,12 @@
 #include "BeginPrivate.h"
 
 // Segments
+#if defined(wasm32_HOST_ARCH)
+#define NONMOVING_SEGMENT_BITS 14ULL   // 2^14 = 16kByte
+#else
 #define NONMOVING_SEGMENT_BITS 15ULL   // 2^15 = 32kByte
+#endif
+
 // Mask to find base of segment
 #define NONMOVING_SEGMENT_MASK (((uintptr_t)1 << NONMOVING_SEGMENT_BITS) - 1)
 // In bytes
diff --git a/rts/wasm/OSMem.c b/rts/wasm/OSMem.c
index ff4217f413e806e89e83c1d6cf4bd5c087689318..d01b3361a0e61b06537b47d912e38f9cbcf62a52 100644
--- a/rts/wasm/OSMem.c
+++ b/rts/wasm/OSMem.c
@@ -32,14 +32,8 @@
 // libc allocator's certain invariants. But dlmalloc permits this
 // behavior!
 //
-// Therefore, we bypass dlmalloc, and directly call memory.grow to
-// allocate megablocks. We even patch dlmalloc in the libc sysroot
-// shipped in our wasi-sdk release, so that whenever dlmalloc calls
-// sbrk(), it extends the linear memory to align to the megablock
-// size, so to avoid space waste as much as possible. Our wasi-libc
-// patch doesn't impact ABI interoperability, and when stock clang
-// compiles code that calls malloc() to wasm objects, those objects
-// would just link fine with our build products.
+// Therefore, we bypass dlmalloc, and directly call sbrk() to
+// allocate megablocks.
 //
 // One remaining question is how to free a megablock. Wasm spec
 // doesn't allow shrinking the linear memory, so the logic of
@@ -49,12 +43,13 @@
 // megablock on Wasm.
 
 #include "Rts.h"
-
-#include "RtsUtils.h"
 #include "sm/OSMem.h"
-#include "rts/storage/HeapAlloc.h"
 
-#include <__macro_PAGESIZE.h>
+#include <unistd.h>
+
+#define PAGESIZE (0x10000)
+
+GHC_STATIC_ASSERT(MBLOCK_SIZE == PAGESIZE, "MBLOCK_SIZE must be equal to wasm page size");
 
 void osMemInit(void)
 {
@@ -63,13 +58,7 @@ void osMemInit(void)
 void *
 osGetMBlocks(uint32_t n)
 {
-  size_t base = __builtin_wasm_memory_size(0) * PAGESIZE;
-  size_t start = MBLOCK_ROUND_UP(base);
-  size_t end = start + (n << MBLOCK_SHIFT);
-  ptrdiff_t delta = (end - base) / PAGESIZE;
-  if (__builtin_wasm_memory_grow(0, delta) == SIZE_MAX)
-    barf("osGetMBlocks failed");
-  return start;
+  return sbrk(PAGESIZE * n);
 }
 
 void osBindMBlocksToNode(