From: Claude Bot <claude-bot@bun.sh>
Date: Mon, 23 Feb 2026 22:37:55 +0000
Subject: Support Linux ARM64 64KB page size without disabling JIT or libpas

Linux ARM64 kernels can be configured with 4KB, 16KB, or 64KB page
sizes. Previously, the default CeilingOnPageSize for Linux ARM64 was
16KB, which caused an immediate RELEASE_ASSERT crash on systems with
64KB pages (e.g., RHEL aarch64, Oracle Linux, Ubuntu generic-64k).

The existing USE(64KB_PAGE_BLOCK) workaround disables both JIT and
bmalloc/libpas, which is a significant performance regression.

This change raises CeilingOnPageSize to 64KB for all Linux ARM64
builds, and correspondingly updates libpas page/granule sizes to be
at least 64KB on Linux ARM64. This allows Bun and other WebKit
embedders to run on 64KB page kernels with full JIT and libpas
support.

Changes:
- WTF/PageBlock.h: Set CeilingOnPageSize=64KB for Linux ARM64
- libpas/pas_internal_config.h: Raise small page (16KB->64KB),
  small bitfit page (16KB->64KB), medium page (128KB->256KB),
  and granule size (16KB->64KB) for Linux ARM64
- libpas/jit_heap_config.h: Raise JIT small page/granule (16KB->64KB)
  and JIT medium page/granule (128KB->256KB / 16KB->64KB)
- libpas/pas_expendable_memory.h: Raise expendable memory page size
  (16KB->64KB) for Linux ARM64
- bmalloc/BPlatform.h: Add BUSE_PRECOMPUTED_CONSTANTS_VMPAGE64K

These changes propagate correctly through:
- ConfigSizeToProtect (via std::max(CeilingOnPageSize, 16*KB))
- OpcodeConfigSizeToProtect (same pattern)
- MarkedBlock::blockSize (via std::max(16*KB, CeilingOnPageSize))
- All libpas heap configs that use PAS_*_DEFAULT_SIZE constants
- mprotect/mmap calls that use runtime pageSize()

Co-Authored-By: Claude <noreply@anthropic.com>

Bug-Ubuntu: https://launchpad.net/bugs/2156420
Origin: backport, https://github.com/oven-sh/WebKit/pull/176
---
 Source/WTF/wtf/PageBlock.h                            |  9 +++++----
 Source/bmalloc/bmalloc/BPlatform.h                    |  4 ++++
 Source/bmalloc/libpas/src/libpas/jit_heap_config.h    | 10 ++++++++++
 .../bmalloc/libpas/src/libpas/pas_expendable_memory.h |  4 ++++
 .../bmalloc/libpas/src/libpas/pas_internal_config.h   | 19 ++++++++++++++++++-
 5 files changed, 41 insertions(+), 5 deletions(-)

diff --git a/Source/WTF/wtf/PageBlock.h b/Source/WTF/wtf/PageBlock.h
index c4f9a8b..46a31bf 100644
--- a/Source/WTF/wtf/PageBlock.h
+++ b/Source/WTF/wtf/PageBlock.h
@@ -47,13 +47,14 @@ namespace WTF {
 // On Linux, Power systems normally use 64 KiB pages.
 //
 // aarch64 systems seem to be all over the place. Most Linux distros use 4 KiB, but RHEL uses
-// 64 KiB. Linux on Apple Silicon uses 16KiB for best performance, so use that for Linux on
-// aarch64 by default. USE(64KB_PAGE_BLOCK) allows overriding this.
+// 64 KiB. Since we cannot know the page size at compile time on Linux, use 64 KiB as the ceiling
+// for Linux ARM64 to support all possible page size configurations (4 KiB, 16 KiB, 64 KiB).
+// USE(64KB_PAGE_BLOCK) allows overriding this on other architectures too.
 //
 // Use 64 KiB for any unknown CPUs to be conservative.
-#if OS(DARWIN) || PLATFORM(PLAYSTATION) || CPU(MIPS) || CPU(MIPS64) || CPU(LOONGARCH64) || (OS(LINUX) && CPU(ARM64) && !USE(64KB_PAGE_BLOCK))
+#if OS(DARWIN) || PLATFORM(PLAYSTATION) || CPU(MIPS) || CPU(MIPS64) || CPU(LOONGARCH64)
 constexpr size_t CeilingOnPageSize = 16 * KB;
-#elif USE(64KB_PAGE_BLOCK) || CPU(PPC) || CPU(PPC64) || CPU(PPC64LE) || CPU(UNKNOWN)
+#elif USE(64KB_PAGE_BLOCK) || (OS(LINUX) && CPU(ARM64)) || CPU(PPC) || CPU(PPC64) || CPU(PPC64LE) || CPU(UNKNOWN)
 constexpr size_t CeilingOnPageSize = 64 * KB;
 #elif OS(WINDOWS) || CPU(X86) || CPU(X86_64) || CPU(ARM) || CPU(ARM64) || CPU(RISCV64)
 constexpr size_t CeilingOnPageSize = 4 * KB;
diff --git a/Source/bmalloc/bmalloc/BPlatform.h b/Source/bmalloc/bmalloc/BPlatform.h
index ce799ec..f7527db 100644
--- a/Source/bmalloc/bmalloc/BPlatform.h
+++ b/Source/bmalloc/bmalloc/BPlatform.h
@@ -419,6 +419,10 @@
 #define BUSE_PRECOMPUTED_CONSTANTS_VMPAGE16K 1
 #endif
 
+#if !defined(BUSE_PRECOMPUTED_CONSTANTS_VMPAGE64K)
+#define BUSE_PRECOMPUTED_CONSTANTS_VMPAGE64K 1
+#endif
+
 /* We only export the mallocSize and mallocGoodSize APIs if they're supported by the SystemHeap allocator (currently only Darwin) and the current bmalloc allocator (currently only libpas). */
 #if BUSE(LIBPAS) && BOS(DARWIN)
 #define BENABLE_MALLOC_SIZE 1
diff --git a/Source/bmalloc/libpas/src/libpas/jit_heap_config.h b/Source/bmalloc/libpas/src/libpas/jit_heap_config.h
index 25b3042..96c18e9 100644
--- a/Source/bmalloc/libpas/src/libpas/jit_heap_config.h
+++ b/Source/bmalloc/libpas/src/libpas/jit_heap_config.h
@@ -40,16 +40,26 @@ PAS_BEGIN_EXTERN_C;
 #define JIT_SMALL_SEGREGATED_MIN_ALIGN (1u << JIT_SMALL_SEGREGATED_MIN_ALIGN_SHIFT)
 #define JIT_SMALL_BITFIT_MIN_ALIGN_SHIFT 2u
 #define JIT_SMALL_BITFIT_MIN_ALIGN (1u << JIT_SMALL_BITFIT_MIN_ALIGN_SHIFT)
+#if PAS_ARM64 && PAS_OS(LINUX)
+#define JIT_SMALL_PAGE_SIZE 65536u
+#define JIT_SMALL_GRANULE_SIZE 65536u
+#else
 #define JIT_SMALL_PAGE_SIZE 16384u
 #define JIT_SMALL_GRANULE_SIZE 16384u
+#endif
 #define JIT_MEDIUM_BITFIT_MIN_ALIGN_SHIFT 8u
 #define JIT_MEDIUM_BITFIT_MIN_ALIGN (1u << JIT_MEDIUM_BITFIT_MIN_ALIGN_SHIFT)
+#if PAS_ARM64 && PAS_OS(LINUX)
+#define JIT_MEDIUM_PAGE_SIZE 262144u
+#define JIT_MEDIUM_GRANULE_SIZE 65536u
+#else
 #define JIT_MEDIUM_PAGE_SIZE 131072u
 #if PAS_ARM64
 #define JIT_MEDIUM_GRANULE_SIZE 16384u
 #else
 #define JIT_MEDIUM_GRANULE_SIZE 4096u
 #endif
+#endif
 
 PAS_API void jit_heap_config_activate(void);
 
diff --git a/Source/bmalloc/libpas/src/libpas/pas_expendable_memory.h b/Source/bmalloc/libpas/src/libpas/pas_expendable_memory.h
index 737fe95..5b7418a 100644
--- a/Source/bmalloc/libpas/src/libpas/pas_expendable_memory.h
+++ b/Source/bmalloc/libpas/src/libpas/pas_expendable_memory.h
@@ -51,7 +51,11 @@ struct pas_expendable_memory {
     pas_expendable_memory_state states[1];
 };
 
+#if PAS_ARM64 && PAS_OS(LINUX)
+#define PAS_EXPENDABLE_MEMORY_PAGE_SIZE 65536llu
+#else
 #define PAS_EXPENDABLE_MEMORY_PAGE_SIZE 16384llu
+#endif
 
 PAS_API extern pas_expendable_memory_state_version pas_expendable_memory_version_counter;
 
diff --git a/Source/bmalloc/libpas/src/libpas/pas_internal_config.h b/Source/bmalloc/libpas/src/libpas/pas_internal_config.h
index efafa84..7b822f8 100644
--- a/Source/bmalloc/libpas/src/libpas/pas_internal_config.h
+++ b/Source/bmalloc/libpas/src/libpas/pas_internal_config.h
@@ -35,19 +35,36 @@
 #define PAS_USE_MARGE_BITFIT_OVERRIDE         true
 
 /* The OS may have a smaller page size. That's OK. */
+/* On Linux ARM64, kernels may be configured with 64 KiB pages (e.g. RHEL, Oracle Linux).
+   All page and granule sizes must be at least as large as the system page size, so use
+   64 KiB minimums on Linux ARM64 to support all possible kernel page configurations. */
+#if PAS_ARM64 && PAS_OS(LINUX)
+#define PAS_SMALL_PAGE_DEFAULT_SHIFT     16
+#else
 #define PAS_SMALL_PAGE_DEFAULT_SHIFT     14
+#endif
 #define PAS_SMALL_PAGE_DEFAULT_SIZE      ((size_t)1 << PAS_SMALL_PAGE_DEFAULT_SHIFT)
 
+#if PAS_ARM64 && PAS_OS(LINUX)
+#define PAS_SMALL_BITFIT_PAGE_DEFAULT_SHIFT   16
+#else
 #define PAS_SMALL_BITFIT_PAGE_DEFAULT_SHIFT   14
+#endif
 #define PAS_SMALL_BITFIT_PAGE_DEFAULT_SIZE    ((size_t)1 << PAS_SMALL_BITFIT_PAGE_DEFAULT_SHIFT)
 
+#if PAS_ARM64 && PAS_OS(LINUX)
+#define PAS_MEDIUM_PAGE_DEFAULT_SHIFT    18
+#else
 #define PAS_MEDIUM_PAGE_DEFAULT_SHIFT    17
+#endif
 #define PAS_MEDIUM_PAGE_DEFAULT_SIZE     ((size_t)1 << PAS_MEDIUM_PAGE_DEFAULT_SHIFT)
 
 #define PAS_MARGE_PAGE_DEFAULT_SHIFT     22
 #define PAS_MARGE_PAGE_DEFAULT_SIZE      ((size_t)1 << PAS_MARGE_PAGE_DEFAULT_SHIFT)
 
-#if PAS_ARM64 || PAS_PLATFORM(PLAYSTATION)
+#if PAS_ARM64 && PAS_OS(LINUX)
+#define PAS_GRANULE_DEFAULT_SHIFT        16
+#elif PAS_ARM64 || PAS_PLATFORM(PLAYSTATION)
 #define PAS_GRANULE_DEFAULT_SHIFT        14
 #else
 #define PAS_GRANULE_DEFAULT_SHIFT        12
