Repository: vercel/next.js
Pull request: Turbopack: use mimalloc v3

### What?

* Upgrade to mimalloc 3
* Compute allocations size more accurately (for tracing)

Closes PACK-5160

Changed files:
filename: Cargo.lock
patch: @@ -1748,6 +1748,12 @@ dependencies = [
  "windows-sys 0.52.0",
 ]
 
+[[package]]
+name = "cty"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35"
+
 [[package]]
 name = "darling"
 version = "0.14.4"
@@ -3654,16 +3660,6 @@ dependencies = [
  "windows-sys 0.48.0",
 ]
 
-[[package]]
-name = "libmimalloc-sys"
-version = "0.1.43"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bf88cd67e9de251c1781dbe2f641a1a3ad66eaae831b8a2c38fbdc5ddae16d4d"
-dependencies = [
- "cc",
- "libc",
-]
-
 [[package]]
 name = "libunwind"
 version = "1.3.3"
@@ -4034,12 +4030,12 @@ dependencies = [
 ]
 
 [[package]]
-name = "mimalloc"
-version = "0.1.47"
+name = "mimalloc-rspack"
+version = "0.2.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b1791cbe101e95af5764f06f20f6760521f7158f69dbf9d6baf941ee1bf6bc40"
+checksum = "de20bb33bf95d9c060030d53bcb5d5dc03cbbedfbd1dcda5f6f285b946dae2c0"
 dependencies = [
- "libmimalloc-sys",
+ "rspack-libmimalloc-sys",
 ]
 
 [[package]]
@@ -6091,6 +6087,17 @@ dependencies = [
  "serde",
 ]
 
+[[package]]
+name = "rspack-libmimalloc-sys"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4c741844b1fbe0cfbae8dfeb73b5e5fdc95daf7be58bdd72afb3fd85c86bccdb"
+dependencies = [
+ "cc",
+ "cty",
+ "libc",
+]
+
 [[package]]
 name = "rstest"
 version = "0.16.0"
@@ -9455,7 +9462,8 @@ dependencies = [
 name = "turbo-tasks-malloc"
 version = "0.1.0"
 dependencies = [
- "mimalloc",
+ "mimalloc-rspack",
+ "rspack-libmimalloc-sys",
 ]
 
 [[package]]

filename: turbopack/crates/turbo-tasks-malloc/Cargo.toml
patch: @@ -9,14 +9,22 @@ autobenches = false
 [lib]
 bench = false
 
+[dependencies]
+rspack-libmimalloc-sys = { version = "0.2.4", default-features = false, features = [], optional = true }
+
 [target.'cfg(not(any(target_os = "linux", target_family = "wasm", target_env = "musl")))'.dependencies]
-mimalloc = { version = "0.1.47", features = [], optional = true }
+mimalloc-rspack = { version = "0.2.4", features = [
+  "v3",
+  "extended"
+], optional = true }
 
 [target.'cfg(all(target_os = "linux", not(any(target_family = "wasm", target_env = "musl"))))'.dependencies]
-mimalloc = { version = "0.1.47", features = [
+mimalloc-rspack = { version = "0.2.4", features = [
+  "v3",
+  "extended",
   "local_dynamic_tls",
 ], optional = true }
 
 [features]
-custom_allocator = ["dep:mimalloc"]
+custom_allocator = ["dep:mimalloc-rspack", "dep:rspack-libmimalloc-sys"]
 default = ["custom_allocator"]

filename: turbopack/crates/turbo-tasks-malloc/src/lib.rs
patch: @@ -84,40 +84,61 @@ fn base_alloc() -> &'static impl GlobalAlloc {
         feature = "custom_allocator",
         not(any(target_family = "wasm", target_env = "musl"))
     ))]
-    return &mimalloc::MiMalloc;
+    return &mimalloc_rspack::MiMalloc;
     #[cfg(any(
         not(feature = "custom_allocator"),
         any(target_family = "wasm", target_env = "musl")
     ))]
     return &std::alloc::System;
 }
 
+#[allow(unused_variables)]
+unsafe fn base_alloc_size(ptr: *const u8, layout: Layout) -> usize {
+    #[cfg(all(
+        feature = "custom_allocator",
+        not(any(target_family = "wasm", target_env = "musl"))
+    ))]
+    return unsafe { mimalloc_rspack::MiMalloc.usable_size(ptr) };
+    #[cfg(any(
+        not(feature = "custom_allocator"),
+        any(target_family = "wasm", target_env = "musl")
+    ))]
+    return layout.size();
+}
+
 unsafe impl GlobalAlloc for TurboMalloc {
     unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
         let ret = unsafe { base_alloc().alloc(layout) };
         if !ret.is_null() {
-            add(layout.size());
+            let size = unsafe { base_alloc_size(ret, layout) };
+            add(size);
         }
         ret
     }
 
     unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
+        let size = unsafe { base_alloc_size(ptr, layout) };
         unsafe { base_alloc().dealloc(ptr, layout) };
-        remove(layout.size());
+        remove(size);
     }
 
     unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
         let ret = unsafe { base_alloc().alloc_zeroed(layout) };
         if !ret.is_null() {
-            add(layout.size());
+            let size = unsafe { base_alloc_size(ret, layout) };
+            add(size);
         }
         ret
     }
 
     unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
+        let old_size = unsafe { base_alloc_size(ptr, layout) };
         let ret = unsafe { base_alloc().realloc(ptr, layout, new_size) };
         if !ret.is_null() {
-            let old_size = layout.size();
+            // SAFETY: the caller must ensure that the `new_size` does not overflow.
+            // `layout.align()` comes from a `Layout` and is thus guaranteed to be valid.
+            let new_layout = unsafe { Layout::from_size_align_unchecked(new_size, layout.align()) };
+            let new_size = unsafe { base_alloc_size(ret, new_layout) };
             update(old_size, new_size);
         }
         ret