From 8b0915631dd82ea508fa9bc3aa2e74e2f06c2d85 Mon Sep 17 00:00:00 2001
From: Ian Davis <ian.f.davis@microsoft.com>
Date: Sat, 9 Mar 2024 16:09:05 -0800
Subject: [PATCH 01/14] Native libraries use mimalloc as global allocator

---
 .gitignore                      |  2 ++
 Cargo.lock                      | 22 ++++++++++++++++++++++
 Cargo.toml                      |  1 +
 compiler/qsc/Cargo.toml         |  3 +++
 compiler/qsc/benches/eval.rs    |  4 ++++
 compiler/qsc/benches/large.rs   |  4 ++++
 compiler/qsc/benches/library.rs |  4 ++++
 compiler/qsc/src/bin/qsc.rs     |  4 ++++
 compiler/qsc/src/bin/qsi.rs     |  4 ++++
 fuzz/Cargo.toml                 |  3 +++
 fuzz/fuzz_targets/compile.rs    |  4 ++++
 pip/Cargo.toml                  |  3 +++
 pip/src/lib.rs                  |  4 ++++
 13 files changed, 62 insertions(+)

diff --git a/.gitignore b/.gitignore
index 1b35b03118..8cbb2b6615 100644
--- a/.gitignore
+++ b/.gitignore
@@ -15,3 +15,5 @@ __pycache__/
 /fuzz/artifacts
 /fuzz/coverage
 /fuzz/Cargo.lock
+.mypy_cache/
+.pytest_cache/
diff --git a/Cargo.lock b/Cargo.lock
index 829b025fe2..dcce91fc84 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -435,6 +435,7 @@ name = "fuzz"
 version = "0.0.0"
 dependencies = [
  "libfuzzer-sys",
+ "mimalloc",
  "qsc",
 ]
 
@@ -577,6 +578,16 @@ version = "0.2.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058"
 
+[[package]]
+name = "libmimalloc-sys"
+version = "0.1.35"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3979b5c37ece694f1f5e51e7ecc871fdb0f517ed04ee45f88d15d6d553cb9664"
+dependencies = [
+ "cc",
+ "libc",
+]
+
 [[package]]
 name = "library"
 version = "0.0.0"
@@ -660,6 +671,15 @@ dependencies = [
  "syn",
 ]
 
+[[package]]
+name = "mimalloc"
+version = "0.1.39"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fa01922b5ea280a911e323e4d2fd24b7fe5cc4042e0d2cda3c40775cdc4bdc9c"
+dependencies = [
+ "libmimalloc-sys",
+]
+
 [[package]]
 name = "miniz_oxide"
 version = "0.7.2"
@@ -898,6 +918,7 @@ dependencies = [
  "indoc",
  "log",
  "miette",
+ "mimalloc",
  "num-bigint",
  "num-complex",
  "qsc_ast",
@@ -1097,6 +1118,7 @@ name = "qsharp"
 version = "0.0.0"
 dependencies = [
  "miette",
+ "mimalloc",
  "num-bigint",
  "num-complex",
  "pyo3",
diff --git a/Cargo.toml b/Cargo.toml
index 1c51a58ac8..4e1ed2f0a8 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -47,6 +47,7 @@ libfuzzer-sys = "0.4"
 log = "0.4"
 miette = "5.10"
 thiserror = "1.0"
+mimalloc = { version = "0.1.39", default-features = false }
 num-bigint = "0.4"
 num-complex = "0.4"
 num-traits = "0.2"
diff --git a/compiler/qsc/Cargo.toml b/compiler/qsc/Cargo.toml
index 35d09eb087..2d208b03dc 100644
--- a/compiler/qsc/Cargo.toml
+++ b/compiler/qsc/Cargo.toml
@@ -29,6 +29,9 @@ qsc_project = { path = "../qsc_project", features = ["fs"] }
 rustc-hash = { workspace = true }
 thiserror = { workspace = true }
 
+[target.'cfg(not(any(target_family = "wasm")))'.dependencies]
+mimalloc = { workspace = true }
+
 [dev-dependencies]
 criterion = { workspace = true, features = ["cargo_bench_support"] }
 expect-test = { workspace = true }
diff --git a/compiler/qsc/benches/eval.rs b/compiler/qsc/benches/eval.rs
index b2698de3b2..ca3f42c75a 100644
--- a/compiler/qsc/benches/eval.rs
+++ b/compiler/qsc/benches/eval.rs
@@ -1,6 +1,10 @@
 // Copyright (c) Microsoft Corporation.
 // Licensed under the MIT License.
 
+#[cfg(not(target_family = "wasm"))]
+#[global_allocator]
+static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc;
+
 use criterion::{criterion_group, criterion_main, Criterion};
 use indoc::indoc;
 use qsc::{interpret::Interpreter, PackageType};
diff --git a/compiler/qsc/benches/large.rs b/compiler/qsc/benches/large.rs
index 1d3ca57eb5..e454307ea2 100644
--- a/compiler/qsc/benches/large.rs
+++ b/compiler/qsc/benches/large.rs
@@ -1,6 +1,10 @@
 // Copyright (c) Microsoft Corporation.
 // Licensed under the MIT License.
 
+#[cfg(not(target_family = "wasm"))]
+#[global_allocator]
+static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc;
+
 use criterion::{criterion_group, criterion_main, Criterion};
 use qsc::compile::{self, compile};
 use qsc_data_structures::language_features::LanguageFeatures;
diff --git a/compiler/qsc/benches/library.rs b/compiler/qsc/benches/library.rs
index c60ceeb6fc..5d8bcacaeb 100644
--- a/compiler/qsc/benches/library.rs
+++ b/compiler/qsc/benches/library.rs
@@ -1,6 +1,10 @@
 // Copyright (c) Microsoft Corporation.
 // Licensed under the MIT License.
 
+#[cfg(not(target_family = "wasm"))]
+#[global_allocator]
+static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc;
+
 use criterion::{criterion_group, criterion_main, Criterion};
 use qsc::compile;
 use qsc_frontend::compile::{PackageStore, RuntimeCapabilityFlags};
diff --git a/compiler/qsc/src/bin/qsc.rs b/compiler/qsc/src/bin/qsc.rs
index 9b47d8f039..3ebd68a614 100644
--- a/compiler/qsc/src/bin/qsc.rs
+++ b/compiler/qsc/src/bin/qsc.rs
@@ -1,6 +1,10 @@
 // Copyright (c) Microsoft Corporation.
 // Licensed under the MIT License.
 
+#[cfg(not(target_family = "wasm"))]
+#[global_allocator]
+static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc;
+
 use clap::{crate_version, ArgGroup, Parser, ValueEnum};
 use log::info;
 use miette::{Context, IntoDiagnostic, Report};
diff --git a/compiler/qsc/src/bin/qsi.rs b/compiler/qsc/src/bin/qsi.rs
index 5e6d2dbfef..f6df5e61dd 100644
--- a/compiler/qsc/src/bin/qsi.rs
+++ b/compiler/qsc/src/bin/qsi.rs
@@ -1,6 +1,10 @@
 // Copyright (c) Microsoft Corporation.
 // Licensed under the MIT License.
 
+#[cfg(not(target_family = "wasm"))]
+#[global_allocator]
+static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc;
+
 use clap::{crate_version, Parser};
 use miette::{Context, IntoDiagnostic, Report, Result};
 use num_bigint::BigUint;
diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml
index 16dc9292a7..3936633180 100644
--- a/fuzz/Cargo.toml
+++ b/fuzz/Cargo.toml
@@ -16,6 +16,9 @@ cargo-fuzz = true
 libfuzzer-sys = { workspace = true, optional = true }
 qsc = { path = "../compiler/qsc" }
 
+[target.'cfg(not(any(target_family = "wasm")))'.dependencies]
+mimalloc = { workspace = true }
+
 [features]
 do_fuzz = [ "dep:libfuzzer-sys" ]
 
diff --git a/fuzz/fuzz_targets/compile.rs b/fuzz/fuzz_targets/compile.rs
index 05c5ee7f55..c1842a83ac 100644
--- a/fuzz/fuzz_targets/compile.rs
+++ b/fuzz/fuzz_targets/compile.rs
@@ -3,6 +3,10 @@
 
 #![no_main]
 
+#[cfg(not(target_family = "wasm"))]
+#[global_allocator]
+static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc;
+
 #[cfg(feature = "do_fuzz")]
 use libfuzzer_sys::fuzz_target;
 use qsc::{hir::PackageId, target::Profile, LanguageFeatures, PackageStore, SourceMap};
diff --git a/pip/Cargo.toml b/pip/Cargo.toml
index 369a679b62..11e1bb08ba 100644
--- a/pip/Cargo.toml
+++ b/pip/Cargo.toml
@@ -20,6 +20,9 @@ rustc-hash = { workspace = true }
 [lints]
 workspace = true
 
+[target.'cfg(not(any(target_family = "wasm")))'.dependencies]
+mimalloc = { workspace = true }
+
 [target.'cfg(not(any(target_os = "windows")))'.dependencies]
 pyo3 = { workspace = true, features = ["abi3-py37", "extension-module", "num-bigint"] }
 
diff --git a/pip/src/lib.rs b/pip/src/lib.rs
index f126254403..d9114c03d2 100644
--- a/pip/src/lib.rs
+++ b/pip/src/lib.rs
@@ -1,6 +1,10 @@
 // Copyright (c) Microsoft Corporation.
 // Licensed under the MIT License.
 
+#[cfg(not(target_family = "wasm"))]
+#[global_allocator]
+static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc;
+
 mod displayable_output;
 mod fs;
 mod interpreter;

From 9d669d6927898a02787b8f49058699980991dafa Mon Sep 17 00:00:00 2001
From: Ian Davis <ian.f.davis@microsoft.com>
Date: Tue, 12 Mar 2024 10:48:51 -0700
Subject: [PATCH 02/14] Implementing mimalloc-sys crate and dynamic mimalloc
 compilation

---
 Cargo.lock                            | 41 ++++++++------
 Cargo.toml                            |  3 +-
 allocator/Cargo.toml                  | 15 +++++
 allocator/mimalloc-sys/CMakeLists.txt | 42 ++++++++++++++
 allocator/mimalloc-sys/Cargo.toml     | 20 +++++++
 allocator/mimalloc-sys/build.rs       | 49 +++++++++++++++++
 allocator/mimalloc-sys/src/lib.rs     | 48 ++++++++++++++++
 allocator/src/lib.rs                  | 79 +++++++++++++++++++++++++++
 compiler/qsc/Cargo.toml               |  2 +-
 compiler/qsc/benches/eval.rs          |  2 +-
 compiler/qsc/benches/large.rs         |  2 +-
 compiler/qsc/benches/library.rs       |  2 +-
 compiler/qsc/src/bin/qsc.rs           |  2 +-
 compiler/qsc/src/bin/qsi.rs           |  2 +-
 fuzz/Cargo.toml                       |  2 +-
 fuzz/fuzz_targets/compile.rs          |  2 +-
 pip/Cargo.toml                        |  2 +-
 pip/src/lib.rs                        |  2 +-
 18 files changed, 288 insertions(+), 29 deletions(-)
 create mode 100644 allocator/Cargo.toml
 create mode 100644 allocator/mimalloc-sys/CMakeLists.txt
 create mode 100644 allocator/mimalloc-sys/Cargo.toml
 create mode 100644 allocator/mimalloc-sys/build.rs
 create mode 100644 allocator/mimalloc-sys/src/lib.rs
 create mode 100644 allocator/src/lib.rs

diff --git a/Cargo.lock b/Cargo.lock
index dcce91fc84..e1d142a86a 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -26,6 +26,13 @@ dependencies = [
  "memchr",
 ]
 
+[[package]]
+name = "allocator"
+version = "0.0.0"
+dependencies = [
+ "mimalloc-sys",
+]
+
 [[package]]
 name = "anes"
 version = "0.1.6"
@@ -234,6 +241,15 @@ version = "0.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce"
 
+[[package]]
+name = "cmake"
+version = "0.1.50"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a31c789563b815f77f4250caee12365734369f942439b7defd71e18a48197130"
+dependencies = [
+ "cc",
+]
+
 [[package]]
 name = "colorchoice"
 version = "1.0.0"
@@ -434,8 +450,8 @@ dependencies = [
 name = "fuzz"
 version = "0.0.0"
 dependencies = [
+ "allocator",
  "libfuzzer-sys",
- "mimalloc",
  "qsc",
 ]
 
@@ -578,16 +594,6 @@ version = "0.2.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058"
 
-[[package]]
-name = "libmimalloc-sys"
-version = "0.1.35"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3979b5c37ece694f1f5e51e7ecc871fdb0f517ed04ee45f88d15d6d553cb9664"
-dependencies = [
- "cc",
- "libc",
-]
-
 [[package]]
 name = "library"
 version = "0.0.0"
@@ -672,12 +678,11 @@ dependencies = [
 ]
 
 [[package]]
-name = "mimalloc"
-version = "0.1.39"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fa01922b5ea280a911e323e4d2fd24b7fe5cc4042e0d2cda3c40775cdc4bdc9c"
+name = "mimalloc-sys"
+version = "0.0.0"
 dependencies = [
- "libmimalloc-sys",
+ "cc",
+ "cmake",
 ]
 
 [[package]]
@@ -911,6 +916,7 @@ dependencies = [
 name = "qsc"
 version = "0.0.0"
 dependencies = [
+ "allocator",
  "clap",
  "criterion",
  "env_logger",
@@ -918,7 +924,6 @@ dependencies = [
  "indoc",
  "log",
  "miette",
- "mimalloc",
  "num-bigint",
  "num-complex",
  "qsc_ast",
@@ -1117,8 +1122,8 @@ dependencies = [
 name = "qsharp"
 version = "0.0.0"
 dependencies = [
+ "allocator",
  "miette",
- "mimalloc",
  "num-bigint",
  "num-complex",
  "pyo3",
diff --git a/Cargo.toml b/Cargo.toml
index 4e1ed2f0a8..5e96d1009d 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,5 +1,7 @@
 [workspace]
 members = [
+    "allocator",
+    "allocator/mimalloc-sys",
     "compiler/qsc",
     "compiler/qsc_ast",
     "compiler/qsc_codegen",
@@ -47,7 +49,6 @@ libfuzzer-sys = "0.4"
 log = "0.4"
 miette = "5.10"
 thiserror = "1.0"
-mimalloc = { version = "0.1.39", default-features = false }
 num-bigint = "0.4"
 num-complex = "0.4"
 num-traits = "0.2"
diff --git a/allocator/Cargo.toml b/allocator/Cargo.toml
new file mode 100644
index 0000000000..e75459172f
--- /dev/null
+++ b/allocator/Cargo.toml
@@ -0,0 +1,15 @@
+[package]
+name = "allocator"
+authors.workspace = true
+homepage.workspace = true
+repository.workspace = true
+edition.workspace = true
+license.workspace = true
+version.workspace = true
+
+[dependencies]
+mimalloc-sys = { path = "./mimalloc-sys" }
+
+[lints]
+workspace = true
+
diff --git a/allocator/mimalloc-sys/CMakeLists.txt b/allocator/mimalloc-sys/CMakeLists.txt
new file mode 100644
index 0000000000..bbfa8aa8a5
--- /dev/null
+++ b/allocator/mimalloc-sys/CMakeLists.txt
@@ -0,0 +1,42 @@
+# Copyright (c) Microsoft Corporation.
+# Licensed under the MIT License.
+
+cmake_minimum_required(VERSION 3.10.0)
+
+# Copy the command line arguments to a cache variable so that they can be used
+# with the inner project. This is needed because the inner project
+# needs to use the same configuration and the command line arguments are not
+# passed to the inner project.
+# This also manifests itself in apple silicon systems where the inner project
+# defaults to x86_64 even if the outer project is arm64.
+# This needs to be done before the project command is called.
+if (NOT ALLOCATOR_CMAKE_CL_ARGS)
+  # get all cache variables
+  get_cmake_property(vars CACHE_VARIABLES)
+  foreach(var ${vars})
+    get_property(currentHelpString CACHE "${var}" PROPERTY HELPSTRING)
+    # only add the cache variable to the list if it is set on the command line
+    if("${currentHelpString}" MATCHES "No help, variable specified on the command line." OR "${currentHelpString}" STREQUAL "")
+      message ("${var} = [${${var}}]  --  ${currentHelpString}")
+      list(APPEND ALLOCATOR_CMAKE_CL_ARGS "-D${var}=${${var}}")
+    endif()
+  endforeach()
+  # cache the command line arguments
+  set(ALLOCATOR_CMAKE_CL_ARGS ${ALLOCATOR_CMAKE_CL_ARGS} CACHE STRING "comment")
+endif ()
+
+project(allocator_external)
+include(ExternalProject)
+
+ExternalProject_Add(mimalloc
+  GIT_REPOSITORY    https://github.com/microsoft/mimalloc.git
+  GIT_TAG           $ENV{ALLOCATOR_MIMALLOC_TAG}
+  GIT_SHALLOW       TRUE
+  GIT_PROGRESS      TRUE
+  CMAKE_ARGS        ${ALLOCATOR_CMAKE_CL_ARGS}
+  BUILD_COMMAND     ninja
+  USES_TERMINAL_DOWNLOAD  TRUE
+  USES_TERMINAL_CONFIGURE TRUE
+  USES_TERMINAL_BUILD     TRUE
+  USES_TERMINAL_INSTALL   TRUE
+)
diff --git a/allocator/mimalloc-sys/Cargo.toml b/allocator/mimalloc-sys/Cargo.toml
new file mode 100644
index 0000000000..cbf2546887
--- /dev/null
+++ b/allocator/mimalloc-sys/Cargo.toml
@@ -0,0 +1,20 @@
+[package]
+name = "mimalloc-sys"
+build = "build.rs"
+links = "mimalloc"
+authors.workspace = true
+homepage.workspace = true
+repository.workspace = true
+edition.workspace = true
+license.workspace = true
+version.workspace = true
+
+[dependencies]
+
+[lints]
+workspace = true
+
+[build-dependencies]
+cmake = "0.1"
+cc = "1.0"
+
diff --git a/allocator/mimalloc-sys/build.rs b/allocator/mimalloc-sys/build.rs
new file mode 100644
index 0000000000..d976efaa2a
--- /dev/null
+++ b/allocator/mimalloc-sys/build.rs
@@ -0,0 +1,49 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+use std::boxed::Box;
+use std::env;
+use std::error::Error;
+use std::fs;
+use std::path::PathBuf;
+
+use cmake::Config;
+
+// 1.8.2
+//static ALLOCATOR_MIMALLOC_TAG: &str = "b66e3214d8a104669c2ec05ae91ebc26a8f5ab78";
+// 2.1.2
+static ALLOCATOR_MIMALLOC_TAG: &str = "43ce4bd7fd34bcc730c1c7471c99995597415488";
+
+fn main() -> Result<(), Box<dyn Error>> {
+    println!("cargo:rerun-if-changed=build.rs");
+    println!("cargo:rerun-if-changed=CMakeLists.txt");
+
+    compile_mimalloc()?;
+
+    Ok(())
+}
+
+fn compile_mimalloc() -> Result<(), Box<dyn Error>> {
+    let build_dir = get_build_dir()?;
+    let mut config = Config::new(build_dir);
+
+    config
+        .generator("Ninja")
+        .define("CMAKE_BUILD_TYPE", "MinSizeRel")
+        .define("MI_INSTALL_TOPLEVEL", "ON")
+        .build_target("mimalloc-prefix/src/mimalloc-stamp/mimalloc-install")
+        .env("ALLOCATOR_MIMALLOC_TAG", ALLOCATOR_MIMALLOC_TAG);
+
+    let dst = config.build();
+    println!("cargo:rustc-link-search=native={}/lib", dst.display());
+    println!("cargo:rustc-link-lib=static=mimalloc");
+
+    Ok(())
+}
+
+fn get_build_dir() -> Result<PathBuf, Box<dyn Error>> {
+    let manifest_dir = env::var("CARGO_MANIFEST_DIR")?;
+    let build_dir = PathBuf::from(manifest_dir.as_str());
+    let normalized_build_dir = fs::canonicalize(build_dir)?;
+    Ok(normalized_build_dir)
+}
diff --git a/allocator/mimalloc-sys/src/lib.rs b/allocator/mimalloc-sys/src/lib.rs
new file mode 100644
index 0000000000..528ba7ef2e
--- /dev/null
+++ b/allocator/mimalloc-sys/src/lib.rs
@@ -0,0 +1,48 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+use core::ffi::c_void;
+pub static MI_ALIGNMENT_MAX: usize = 1024 * 1024; // 1 MiB
+
+extern "C" {
+    /// Allocate size bytes aligned by alignment.
+    /// size: the number of bytes to allocate
+    /// alignment: the minimal alignment of the allocated memory. Must be less than MI_ALIGNMENT_MAX
+    /// returns: a pointer to the allocated memory, or null if out of memory. The returned pointer is aligned by alignment
+    pub fn mi_malloc_aligned(size: usize, alignment: usize) -> *mut c_void;
+    pub fn mi_zalloc_aligned(size: usize, alignment: usize) -> *mut c_void;
+
+    /// Free previously allocated memory.
+    /// The pointer p must have been allocated before (or be nullptr).
+    /// p: the pointer to the memory to free or nullptr
+    pub fn mi_free(p: *mut c_void);
+    pub fn mi_realloc_aligned(p: *mut c_void, newsize: usize, alignment: usize) -> *mut c_void;
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn memory_can_be_allocated_and_freed() {
+        let ptr = unsafe { mi_malloc_aligned(8, 8) }.cast::<u8>();
+        assert!(!ptr.cast::<c_void>().is_null());
+        unsafe { mi_free(ptr.cast::<c_void>()) };
+    }
+
+    #[test]
+    fn memory_can_be_allocated_zeroed_and_freed() {
+        let ptr = unsafe { mi_zalloc_aligned(8, 8) }.cast::<u8>();
+        assert!(!ptr.cast::<c_void>().is_null());
+        unsafe { mi_free(ptr.cast::<c_void>()) };
+    }
+
+    #[test]
+    fn memory_can_be_reallocated_and_freed() {
+        let ptr = unsafe { mi_malloc_aligned(8, 8) }.cast::<u8>();
+        assert!(!ptr.cast::<c_void>().is_null());
+        let realloc_ptr = unsafe { mi_realloc_aligned(ptr.cast::<c_void>(), 8, 8) }.cast::<u8>();
+        assert!(!realloc_ptr.cast::<c_void>().is_null());
+        unsafe { mi_free(ptr.cast::<c_void>()) };
+    }
+}
diff --git a/allocator/src/lib.rs b/allocator/src/lib.rs
new file mode 100644
index 0000000000..f76418cb9e
--- /dev/null
+++ b/allocator/src/lib.rs
@@ -0,0 +1,79 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+use core::alloc::{GlobalAlloc, Layout};
+use core::ffi::c_void;
+
+use mimalloc_sys::{mi_free, mi_malloc_aligned, mi_realloc_aligned, mi_zalloc_aligned};
+
+pub struct Mimalloc;
+
+unsafe impl GlobalAlloc for Mimalloc {
+    #[inline]
+    unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
+        debug_assert!(layout.align() < mimalloc_sys::MI_ALIGNMENT_MAX);
+        mi_malloc_aligned(layout.size(), layout.align()).cast::<u8>()
+    }
+
+    #[inline]
+    unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
+        mi_free(ptr.cast::<c_void>());
+    }
+
+    #[inline]
+    unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
+        debug_assert!(layout.align() < mimalloc_sys::MI_ALIGNMENT_MAX);
+        mi_zalloc_aligned(layout.size(), layout.align()).cast::<u8>()
+    }
+
+    #[inline]
+    unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
+        debug_assert!(layout.align() < mimalloc_sys::MI_ALIGNMENT_MAX);
+        mi_realloc_aligned(ptr.cast::<c_void>(), new_size, layout.align()).cast::<u8>()
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use std::error::Error;
+
+    #[test]
+    fn memory_can_be_allocated_and_freed() -> Result<(), Box<dyn Error>> {
+        let layout = Layout::from_size_align(8, 8)?;
+        let alloc = Mimalloc;
+
+        unsafe {
+            let ptr = alloc.alloc(layout);
+            assert!(!ptr.cast::<c_void>().is_null());
+            alloc.dealloc(ptr, layout);
+        }
+        Ok(())
+    }
+
+    #[test]
+    fn memory_can_be_alloc_zeroed_and_freed() -> Result<(), Box<dyn Error>> {
+        let layout = Layout::from_size_align(8, 8)?;
+        let alloc = Mimalloc;
+
+        unsafe {
+            let ptr = alloc.alloc_zeroed(layout);
+            assert!(!ptr.cast::<c_void>().is_null());
+            alloc.dealloc(ptr, layout);
+        }
+        Ok(())
+    }
+
+    #[test]
+    fn large_chunks_of_memory_can_be_allocated_and_freed() -> Result<(), Box<dyn Error>> {
+        let layout = Layout::from_size_align(2 * 1024 * 1024 * 1024, 8)?;
+        let alloc = Mimalloc;
+
+        unsafe {
+            let ptr = alloc.alloc(layout);
+            assert!(!ptr.cast::<c_void>().is_null());
+            alloc.dealloc(ptr, layout);
+        }
+        Ok(())
+    }
+}
diff --git a/compiler/qsc/Cargo.toml b/compiler/qsc/Cargo.toml
index 2d208b03dc..37698069f5 100644
--- a/compiler/qsc/Cargo.toml
+++ b/compiler/qsc/Cargo.toml
@@ -30,7 +30,7 @@ rustc-hash = { workspace = true }
 thiserror = { workspace = true }
 
 [target.'cfg(not(any(target_family = "wasm")))'.dependencies]
-mimalloc = { workspace = true }
+allocator = { path = "../../allocator" }
 
 [dev-dependencies]
 criterion = { workspace = true, features = ["cargo_bench_support"] }
diff --git a/compiler/qsc/benches/eval.rs b/compiler/qsc/benches/eval.rs
index ca3f42c75a..558f1b5059 100644
--- a/compiler/qsc/benches/eval.rs
+++ b/compiler/qsc/benches/eval.rs
@@ -3,7 +3,7 @@
 
 #[cfg(not(target_family = "wasm"))]
 #[global_allocator]
-static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc;
+static GLOBAL: allocator::Mimalloc = allocator::Mimalloc;
 
 use criterion::{criterion_group, criterion_main, Criterion};
 use indoc::indoc;
diff --git a/compiler/qsc/benches/large.rs b/compiler/qsc/benches/large.rs
index e454307ea2..75ceb0679f 100644
--- a/compiler/qsc/benches/large.rs
+++ b/compiler/qsc/benches/large.rs
@@ -3,7 +3,7 @@
 
 #[cfg(not(target_family = "wasm"))]
 #[global_allocator]
-static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc;
+static GLOBAL: allocator::Mimalloc = allocator::Mimalloc;
 
 use criterion::{criterion_group, criterion_main, Criterion};
 use qsc::compile::{self, compile};
diff --git a/compiler/qsc/benches/library.rs b/compiler/qsc/benches/library.rs
index 5d8bcacaeb..8af3d5e6dd 100644
--- a/compiler/qsc/benches/library.rs
+++ b/compiler/qsc/benches/library.rs
@@ -3,7 +3,7 @@
 
 #[cfg(not(target_family = "wasm"))]
 #[global_allocator]
-static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc;
+static GLOBAL: allocator::Mimalloc = allocator::Mimalloc;
 
 use criterion::{criterion_group, criterion_main, Criterion};
 use qsc::compile;
diff --git a/compiler/qsc/src/bin/qsc.rs b/compiler/qsc/src/bin/qsc.rs
index 3ebd68a614..4507b6d112 100644
--- a/compiler/qsc/src/bin/qsc.rs
+++ b/compiler/qsc/src/bin/qsc.rs
@@ -3,7 +3,7 @@
 
 #[cfg(not(target_family = "wasm"))]
 #[global_allocator]
-static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc;
+static GLOBAL: allocator::Mimalloc = allocator::Mimalloc;
 
 use clap::{crate_version, ArgGroup, Parser, ValueEnum};
 use log::info;
diff --git a/compiler/qsc/src/bin/qsi.rs b/compiler/qsc/src/bin/qsi.rs
index f6df5e61dd..2a4c61f729 100644
--- a/compiler/qsc/src/bin/qsi.rs
+++ b/compiler/qsc/src/bin/qsi.rs
@@ -3,7 +3,7 @@
 
 #[cfg(not(target_family = "wasm"))]
 #[global_allocator]
-static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc;
+static GLOBAL: allocator::Mimalloc = allocator::Mimalloc;
 
 use clap::{crate_version, Parser};
 use miette::{Context, IntoDiagnostic, Report, Result};
diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml
index 3936633180..34b9ba6609 100644
--- a/fuzz/Cargo.toml
+++ b/fuzz/Cargo.toml
@@ -17,7 +17,7 @@ libfuzzer-sys = { workspace = true, optional = true }
 qsc = { path = "../compiler/qsc" }
 
 [target.'cfg(not(any(target_family = "wasm")))'.dependencies]
-mimalloc = { workspace = true }
+allocator = { path = "../allocator" }
 
 [features]
 do_fuzz = [ "dep:libfuzzer-sys" ]
diff --git a/fuzz/fuzz_targets/compile.rs b/fuzz/fuzz_targets/compile.rs
index c1842a83ac..6e5d06a6ae 100644
--- a/fuzz/fuzz_targets/compile.rs
+++ b/fuzz/fuzz_targets/compile.rs
@@ -5,7 +5,7 @@
 
 #[cfg(not(target_family = "wasm"))]
 #[global_allocator]
-static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc;
+static GLOBAL: allocator::Mimalloc = allocator::Mimalloc;
 
 #[cfg(feature = "do_fuzz")]
 use libfuzzer_sys::fuzz_target;
diff --git a/pip/Cargo.toml b/pip/Cargo.toml
index 11e1bb08ba..fe4467e44d 100644
--- a/pip/Cargo.toml
+++ b/pip/Cargo.toml
@@ -21,7 +21,7 @@ rustc-hash = { workspace = true }
 workspace = true
 
 [target.'cfg(not(any(target_family = "wasm")))'.dependencies]
-mimalloc = { workspace = true }
+allocator = { path = "../allocator" }
 
 [target.'cfg(not(any(target_os = "windows")))'.dependencies]
 pyo3 = { workspace = true, features = ["abi3-py37", "extension-module", "num-bigint"] }
diff --git a/pip/src/lib.rs b/pip/src/lib.rs
index d9114c03d2..1ba3fb619e 100644
--- a/pip/src/lib.rs
+++ b/pip/src/lib.rs
@@ -3,7 +3,7 @@
 
 #[cfg(not(target_family = "wasm"))]
 #[global_allocator]
-static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc;
+static GLOBAL: allocator::Mimalloc = allocator::Mimalloc;
 
 mod displayable_output;
 mod fs;

From 8aba7d21fb83e1ebab37b54fb9173e3f945b8449 Mon Sep 17 00:00:00 2001
From: Ian Davis <ian.f.davis@microsoft.com>
Date: Tue, 12 Mar 2024 11:10:36 -0700
Subject: [PATCH 03/14] Remove ninja dep

---
 allocator/mimalloc-sys/CMakeLists.txt | 1 -
 allocator/mimalloc-sys/build.rs       | 3 +--
 2 files changed, 1 insertion(+), 3 deletions(-)

diff --git a/allocator/mimalloc-sys/CMakeLists.txt b/allocator/mimalloc-sys/CMakeLists.txt
index bbfa8aa8a5..2088ee1161 100644
--- a/allocator/mimalloc-sys/CMakeLists.txt
+++ b/allocator/mimalloc-sys/CMakeLists.txt
@@ -34,7 +34,6 @@ ExternalProject_Add(mimalloc
   GIT_SHALLOW       TRUE
   GIT_PROGRESS      TRUE
   CMAKE_ARGS        ${ALLOCATOR_CMAKE_CL_ARGS}
-  BUILD_COMMAND     ninja
   USES_TERMINAL_DOWNLOAD  TRUE
   USES_TERMINAL_CONFIGURE TRUE
   USES_TERMINAL_BUILD     TRUE
diff --git a/allocator/mimalloc-sys/build.rs b/allocator/mimalloc-sys/build.rs
index d976efaa2a..a6dc0d5e34 100644
--- a/allocator/mimalloc-sys/build.rs
+++ b/allocator/mimalloc-sys/build.rs
@@ -28,10 +28,9 @@ fn compile_mimalloc() -> Result<(), Box<dyn Error>> {
     let mut config = Config::new(build_dir);
 
     config
-        .generator("Ninja")
         .define("CMAKE_BUILD_TYPE", "MinSizeRel")
         .define("MI_INSTALL_TOPLEVEL", "ON")
-        .build_target("mimalloc-prefix/src/mimalloc-stamp/mimalloc-install")
+        .build_target("mimalloc")
         .env("ALLOCATOR_MIMALLOC_TAG", ALLOCATOR_MIMALLOC_TAG);
 
     let dst = config.build();

From 10933e4d3cb96bc5259b5467d4f907bee4423275 Mon Sep 17 00:00:00 2001
From: Ian Davis <ian.f.davis@microsoft.com>
Date: Tue, 12 Mar 2024 11:34:12 -0700
Subject: [PATCH 04/14] Static linking crt

---
 allocator/mimalloc-sys/build.rs | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/allocator/mimalloc-sys/build.rs b/allocator/mimalloc-sys/build.rs
index a6dc0d5e34..b7b37778c5 100644
--- a/allocator/mimalloc-sys/build.rs
+++ b/allocator/mimalloc-sys/build.rs
@@ -28,10 +28,12 @@ fn compile_mimalloc() -> Result<(), Box<dyn Error>> {
     let mut config = Config::new(build_dir);
 
     config
+        .build_target("mimalloc")
         .define("CMAKE_BUILD_TYPE", "MinSizeRel")
         .define("MI_INSTALL_TOPLEVEL", "ON")
-        .build_target("mimalloc")
-        .env("ALLOCATOR_MIMALLOC_TAG", ALLOCATOR_MIMALLOC_TAG);
+        .env("ALLOCATOR_MIMALLOC_TAG", ALLOCATOR_MIMALLOC_TAG)
+        .static_crt(true)
+        .very_verbose(true);
 
     let dst = config.build();
     println!("cargo:rustc-link-search=native={}/lib", dst.display());

From 9618cda7f461509883564d0c52063c88031bf9f1 Mon Sep 17 00:00:00 2001
From: Ian Davis <ian.f.davis@microsoft.com>
Date: Tue, 12 Mar 2024 12:10:59 -0700
Subject: [PATCH 05/14] Adding some verbosity and clean path

---
 allocator/mimalloc-sys/build.rs | 9 ++++++++-
 build.py                        | 1 +
 2 files changed, 9 insertions(+), 1 deletion(-)

diff --git a/allocator/mimalloc-sys/build.rs b/allocator/mimalloc-sys/build.rs
index b7b37778c5..84029a4934 100644
--- a/allocator/mimalloc-sys/build.rs
+++ b/allocator/mimalloc-sys/build.rs
@@ -36,7 +36,14 @@ fn compile_mimalloc() -> Result<(), Box<dyn Error>> {
         .very_verbose(true);
 
     let dst = config.build();
-    println!("cargo:rustc-link-search=native={}/lib", dst.display());
+    println!(
+        "cargo:rustc-link-search=native={}",
+        dst.join("lib").display()
+    );
+    println!(
+        "cargo:rustc-link-search=static={}",
+        dst.join("lib").display()
+    );
     println!("cargo:rustc-link-lib=static=mimalloc");
 
     Ok(())
diff --git a/build.py b/build.py
index 25c8d25b88..5d974ffac9 100755
--- a/build.py
+++ b/build.py
@@ -403,6 +403,7 @@ def use_python_env(folder):
         "-m",
         "pip",
         "wheel",
+        "--verbose",
         "--wheel-dir",
         wheels_dir,
         jupyterlab_src,

From b0d95425696f3e0a45c9a2f5b4d38a7262a33d2e Mon Sep 17 00:00:00 2001
From: Ian Davis <ian.f.davis@microsoft.com>
Date: Tue, 12 Mar 2024 12:29:34 -0700
Subject: [PATCH 06/14] Seeing if windows crash is due to 2.x

---
 allocator/mimalloc-sys/build.rs | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/allocator/mimalloc-sys/build.rs b/allocator/mimalloc-sys/build.rs
index 84029a4934..1a32a6ec46 100644
--- a/allocator/mimalloc-sys/build.rs
+++ b/allocator/mimalloc-sys/build.rs
@@ -10,9 +10,9 @@ use std::path::PathBuf;
 use cmake::Config;
 
 // 1.8.2
-//static ALLOCATOR_MIMALLOC_TAG: &str = "b66e3214d8a104669c2ec05ae91ebc26a8f5ab78";
+static ALLOCATOR_MIMALLOC_TAG: &str = "b66e3214d8a104669c2ec05ae91ebc26a8f5ab78";
 // 2.1.2
-static ALLOCATOR_MIMALLOC_TAG: &str = "43ce4bd7fd34bcc730c1c7471c99995597415488";
+//static ALLOCATOR_MIMALLOC_TAG: &str = "43ce4bd7fd34bcc730c1c7471c99995597415488";
 
 fn main() -> Result<(), Box<dyn Error>> {
     println!("cargo:rerun-if-changed=build.rs");

From 86facfed0689d325c21bc0de005e0327597537cc Mon Sep 17 00:00:00 2001
From: Ian Davis <ian.f.davis@microsoft.com>
Date: Tue, 12 Mar 2024 13:12:15 -0700
Subject: [PATCH 07/14] Trying more windows flags.

---
 allocator/mimalloc-sys/build.rs | 13 ++++++-------
 1 file changed, 6 insertions(+), 7 deletions(-)

diff --git a/allocator/mimalloc-sys/build.rs b/allocator/mimalloc-sys/build.rs
index 1a32a6ec46..ee160b9259 100644
--- a/allocator/mimalloc-sys/build.rs
+++ b/allocator/mimalloc-sys/build.rs
@@ -10,9 +10,9 @@ use std::path::PathBuf;
 use cmake::Config;
 
 // 1.8.2
-static ALLOCATOR_MIMALLOC_TAG: &str = "b66e3214d8a104669c2ec05ae91ebc26a8f5ab78";
+//static ALLOCATOR_MIMALLOC_TAG: &str = "b66e3214d8a104669c2ec05ae91ebc26a8f5ab78";
 // 2.1.2
-//static ALLOCATOR_MIMALLOC_TAG: &str = "43ce4bd7fd34bcc730c1c7471c99995597415488";
+static ALLOCATOR_MIMALLOC_TAG: &str = "43ce4bd7fd34bcc730c1c7471c99995597415488";
 
 fn main() -> Result<(), Box<dyn Error>> {
     println!("cargo:rerun-if-changed=build.rs");
@@ -28,9 +28,12 @@ fn compile_mimalloc() -> Result<(), Box<dyn Error>> {
     let mut config = Config::new(build_dir);
 
     config
-        .build_target("mimalloc")
+        //.build_target("mimalloc")
+        .no_build_target(true)
         .define("CMAKE_BUILD_TYPE", "MinSizeRel")
         .define("MI_INSTALL_TOPLEVEL", "ON")
+        .define("MI_OVERRIDE", "OFF")
+        .define("MI_WIN_REDIRECT", "OFF")
         .env("ALLOCATOR_MIMALLOC_TAG", ALLOCATOR_MIMALLOC_TAG)
         .static_crt(true)
         .very_verbose(true);
@@ -40,10 +43,6 @@ fn compile_mimalloc() -> Result<(), Box<dyn Error>> {
         "cargo:rustc-link-search=native={}",
         dst.join("lib").display()
     );
-    println!(
-        "cargo:rustc-link-search=static={}",
-        dst.join("lib").display()
-    );
     println!("cargo:rustc-link-lib=static=mimalloc");
 
     Ok(())

From 21e1eb54efcd781d74d251fb18ac2253f2f92786 Mon Sep 17 00:00:00 2001
From: Ian Davis <ian.f.davis@microsoft.com>
Date: Tue, 12 Mar 2024 15:43:15 -0700
Subject: [PATCH 08/14] Simplifying compilation.

---
 allocator/mimalloc-sys/CMakeLists.txt | 26 ++-----------
 allocator/mimalloc-sys/build.rs       | 54 +++++++++++++++++++--------
 2 files changed, 42 insertions(+), 38 deletions(-)

diff --git a/allocator/mimalloc-sys/CMakeLists.txt b/allocator/mimalloc-sys/CMakeLists.txt
index 2088ee1161..7004d3905c 100644
--- a/allocator/mimalloc-sys/CMakeLists.txt
+++ b/allocator/mimalloc-sys/CMakeLists.txt
@@ -3,27 +3,6 @@
 
 cmake_minimum_required(VERSION 3.10.0)
 
-# Copy the command line arguments to a cache variable so that they can be used
-# with the inner project. This is needed because the inner project
-# needs to use the same configuration and the command line arguments are not
-# passed to the inner project.
-# This also manifests itself in apple silicon systems where the inner project
-# defaults to x86_64 even if the outer project is arm64.
-# This needs to be done before the project command is called.
-if (NOT ALLOCATOR_CMAKE_CL_ARGS)
-  # get all cache variables
-  get_cmake_property(vars CACHE_VARIABLES)
-  foreach(var ${vars})
-    get_property(currentHelpString CACHE "${var}" PROPERTY HELPSTRING)
-    # only add the cache variable to the list if it is set on the command line
-    if("${currentHelpString}" MATCHES "No help, variable specified on the command line." OR "${currentHelpString}" STREQUAL "")
-      message ("${var} = [${${var}}]  --  ${currentHelpString}")
-      list(APPEND ALLOCATOR_CMAKE_CL_ARGS "-D${var}=${${var}}")
-    endif()
-  endforeach()
-  # cache the command line arguments
-  set(ALLOCATOR_CMAKE_CL_ARGS ${ALLOCATOR_CMAKE_CL_ARGS} CACHE STRING "comment")
-endif ()
 
 project(allocator_external)
 include(ExternalProject)
@@ -33,7 +12,10 @@ ExternalProject_Add(mimalloc
   GIT_TAG           $ENV{ALLOCATOR_MIMALLOC_TAG}
   GIT_SHALLOW       TRUE
   GIT_PROGRESS      TRUE
-  CMAKE_ARGS        ${ALLOCATOR_CMAKE_CL_ARGS}
+  CONFIGURE_COMMAND ""
+  BUILD_COMMAND ""
+  INSTALL_COMMAND ""
+  TEST_COMMAND ""
   USES_TERMINAL_DOWNLOAD  TRUE
   USES_TERMINAL_CONFIGURE TRUE
   USES_TERMINAL_BUILD     TRUE
diff --git a/allocator/mimalloc-sys/build.rs b/allocator/mimalloc-sys/build.rs
index ee160b9259..ab5433f4a3 100644
--- a/allocator/mimalloc-sys/build.rs
+++ b/allocator/mimalloc-sys/build.rs
@@ -5,7 +5,7 @@ use std::boxed::Box;
 use std::env;
 use std::error::Error;
 use std::fs;
-use std::path::PathBuf;
+use std::path::{Path, PathBuf};
 
 use cmake::Config;
 
@@ -15,37 +15,59 @@ use cmake::Config;
 static ALLOCATOR_MIMALLOC_TAG: &str = "43ce4bd7fd34bcc730c1c7471c99995597415488";
 
 fn main() -> Result<(), Box<dyn Error>> {
+    let dst = download_mimalloc()?;
+    compile_mimalloc(&dst);
     println!("cargo:rerun-if-changed=build.rs");
     println!("cargo:rerun-if-changed=CMakeLists.txt");
+    Ok(())
+}
 
-    compile_mimalloc()?;
+// Compile mimalloc source code and link it to the crate.
+// The cc crate is used to compile the source code into a static library.
+// The cmake crate is used to download the source code and stage it in the build directory.
+// We don't use the cmake crate to compile the source code because the mimalloc build system
+// loads extra libraries, changes the name and path around, and does other things that are
+// difficult to handle. The cc crate is much simpler and more predictable.
+fn compile_mimalloc(dst: &Path) {
+    let src_dir = dst
+        .join("build")
+        .join("mimalloc-prefix")
+        .join("src")
+        .join("mimalloc");
 
-    Ok(())
+    let mut build = cc::Build::new();
+
+    build.include(src_dir.join("include"));
+    build.include(src_dir.join("src"));
+    build.file(src_dir.join("src/static.c"));
+
+    if build.get_compiler().is_like_msvc() {
+        build.cpp(true);
+    }
+
+    build.compile("mimalloc");
+
+    println!(
+        "cargo:rustc-link-search=native={}",
+        dst.join("lib").display()
+    );
+    println!("cargo:rustc-link-lib=static=mimalloc");
 }
 
-fn compile_mimalloc() -> Result<(), Box<dyn Error>> {
+// Use cmake to download mimallloc source code and stage
+// it in the build directory.
+fn download_mimalloc() -> Result<PathBuf, Box<dyn Error>> {
     let build_dir = get_build_dir()?;
     let mut config = Config::new(build_dir);
 
     config
-        //.build_target("mimalloc")
         .no_build_target(true)
-        .define("CMAKE_BUILD_TYPE", "MinSizeRel")
-        .define("MI_INSTALL_TOPLEVEL", "ON")
-        .define("MI_OVERRIDE", "OFF")
-        .define("MI_WIN_REDIRECT", "OFF")
         .env("ALLOCATOR_MIMALLOC_TAG", ALLOCATOR_MIMALLOC_TAG)
-        .static_crt(true)
         .very_verbose(true);
 
     let dst = config.build();
-    println!(
-        "cargo:rustc-link-search=native={}",
-        dst.join("lib").display()
-    );
-    println!("cargo:rustc-link-lib=static=mimalloc");
 
-    Ok(())
+    Ok(dst)
 }
 
 fn get_build_dir() -> Result<PathBuf, Box<dyn Error>> {

From db58fff2943f8e10b8195e45fb7dc562b84223dd Mon Sep 17 00:00:00 2001
From: Ian Davis <ian.f.davis@microsoft.com>
Date: Tue, 12 Mar 2024 16:46:11 -0700
Subject: [PATCH 09/14] Optimizing perf and setting up windows crt

---
 allocator/mimalloc-sys/build.rs | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/allocator/mimalloc-sys/build.rs b/allocator/mimalloc-sys/build.rs
index ab5433f4a3..955fdb2683 100644
--- a/allocator/mimalloc-sys/build.rs
+++ b/allocator/mimalloc-sys/build.rs
@@ -43,7 +43,13 @@ fn compile_mimalloc(dst: &Path) {
 
     if build.get_compiler().is_like_msvc() {
         build.cpp(true);
+        build.static_crt(true);
     }
+    // turn off debug mode
+    build.define("MI_DEBUG", "0");
+
+    // turning on optimizations doesn't seem to make a difference
+    //build.opt_level(3);
 
     build.compile("mimalloc");
 

From a8a4dcdd8c0b94f40d9990c7d860e54354402604 Mon Sep 17 00:00:00 2001
From: Ian Davis <ian.f.davis@microsoft.com>
Date: Wed, 13 Mar 2024 10:37:47 -0700
Subject: [PATCH 10/14] Updating building instructions

---
 README.md | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/README.md b/README.md
index 113ce041c6..341f27a229 100644
--- a/README.md
+++ b/README.md
@@ -23,12 +23,13 @@ Code from this repository powers the Q# development experience on <https://quant
 
 ## Building
 
-To build this repository there are 4 dependencies that need to be installed. These are:
+To build this repository there are dependencies that need to be installed. These are:
 
 - Python (<https://python.org>)
 - Rust (<https://www.rust-lang.org/tools/install>)
 - Node.js (<https://nodejs.org/>)
 - wasm-pack (<https://rustwasm.github.io/wasm-pack/installer/>)
+- cmake (<https://cmake.org/>) and a C compiler
 
 The build script will check these dependencies and their versions and fail if not met. (Or run
 `python ./prereqs.py` directly to check if the minimum required versions are installed).

From 3f46b509fbaf75641073cd0837b97dff742f4dc8 Mon Sep 17 00:00:00 2001
From: Ian Davis <ian.f.davis@microsoft.com>
Date: Wed, 13 Mar 2024 15:35:15 -0700
Subject: [PATCH 11/14] Cleaning up

---
 allocator/mimalloc-sys/CMakeLists.txt | 3 ---
 build.py                              | 1 -
 2 files changed, 4 deletions(-)

diff --git a/allocator/mimalloc-sys/CMakeLists.txt b/allocator/mimalloc-sys/CMakeLists.txt
index 7004d3905c..0d745774a4 100644
--- a/allocator/mimalloc-sys/CMakeLists.txt
+++ b/allocator/mimalloc-sys/CMakeLists.txt
@@ -17,7 +17,4 @@ ExternalProject_Add(mimalloc
   INSTALL_COMMAND ""
   TEST_COMMAND ""
   USES_TERMINAL_DOWNLOAD  TRUE
-  USES_TERMINAL_CONFIGURE TRUE
-  USES_TERMINAL_BUILD     TRUE
-  USES_TERMINAL_INSTALL   TRUE
 )
diff --git a/build.py b/build.py
index 5d974ffac9..25c8d25b88 100755
--- a/build.py
+++ b/build.py
@@ -403,7 +403,6 @@ def use_python_env(folder):
         "-m",
         "pip",
         "wheel",
-        "--verbose",
         "--wheel-dir",
         wheels_dir,
         jupyterlab_src,

From 516b407b12502d6aa5cff291f60397b102d77ea8 Mon Sep 17 00:00:00 2001
From: Ian Davis <ian.f.davis@microsoft.com>
Date: Wed, 13 Mar 2024 16:16:50 -0700
Subject: [PATCH 12/14] Move allocator asignement into macro.

---
 allocator/src/lib.rs            | 86 +++++----------------------------
 allocator/src/mimalloc.rs       | 79 ++++++++++++++++++++++++++++++
 compiler/qsc/benches/eval.rs    |  4 +-
 compiler/qsc/benches/large.rs   |  4 +-
 compiler/qsc/benches/library.rs |  4 +-
 compiler/qsc/src/bin/qsc.rs     |  4 +-
 compiler/qsc/src/bin/qsi.rs     |  4 +-
 fuzz/fuzz_targets/compile.rs    |  4 +-
 pip/src/lib.rs                  |  4 +-
 9 files changed, 97 insertions(+), 96 deletions(-)
 create mode 100644 allocator/src/mimalloc.rs

diff --git a/allocator/src/lib.rs b/allocator/src/lib.rs
index f76418cb9e..8e6c5cae64 100644
--- a/allocator/src/lib.rs
+++ b/allocator/src/lib.rs
@@ -1,79 +1,15 @@
 // Copyright (c) Microsoft Corporation.
 // Licensed under the MIT License.
 
-use core::alloc::{GlobalAlloc, Layout};
-use core::ffi::c_void;
-
-use mimalloc_sys::{mi_free, mi_malloc_aligned, mi_realloc_aligned, mi_zalloc_aligned};
-
-pub struct Mimalloc;
-
-unsafe impl GlobalAlloc for Mimalloc {
-    #[inline]
-    unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
-        debug_assert!(layout.align() < mimalloc_sys::MI_ALIGNMENT_MAX);
-        mi_malloc_aligned(layout.size(), layout.align()).cast::<u8>()
-    }
-
-    #[inline]
-    unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
-        mi_free(ptr.cast::<c_void>());
-    }
-
-    #[inline]
-    unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
-        debug_assert!(layout.align() < mimalloc_sys::MI_ALIGNMENT_MAX);
-        mi_zalloc_aligned(layout.size(), layout.align()).cast::<u8>()
-    }
-
-    #[inline]
-    unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
-        debug_assert!(layout.align() < mimalloc_sys::MI_ALIGNMENT_MAX);
-        mi_realloc_aligned(ptr.cast::<c_void>(), new_size, layout.align()).cast::<u8>()
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-    use std::error::Error;
-
-    #[test]
-    fn memory_can_be_allocated_and_freed() -> Result<(), Box<dyn Error>> {
-        let layout = Layout::from_size_align(8, 8)?;
-        let alloc = Mimalloc;
-
-        unsafe {
-            let ptr = alloc.alloc(layout);
-            assert!(!ptr.cast::<c_void>().is_null());
-            alloc.dealloc(ptr, layout);
-        }
-        Ok(())
-    }
-
-    #[test]
-    fn memory_can_be_alloc_zeroed_and_freed() -> Result<(), Box<dyn Error>> {
-        let layout = Layout::from_size_align(8, 8)?;
-        let alloc = Mimalloc;
-
-        unsafe {
-            let ptr = alloc.alloc_zeroed(layout);
-            assert!(!ptr.cast::<c_void>().is_null());
-            alloc.dealloc(ptr, layout);
-        }
-        Ok(())
-    }
-
-    #[test]
-    fn large_chunks_of_memory_can_be_allocated_and_freed() -> Result<(), Box<dyn Error>> {
-        let layout = Layout::from_size_align(2 * 1024 * 1024 * 1024, 8)?;
-        let alloc = Mimalloc;
-
-        unsafe {
-            let ptr = alloc.alloc(layout);
-            assert!(!ptr.cast::<c_void>().is_null());
-            alloc.dealloc(ptr, layout);
-        }
-        Ok(())
-    }
+#[cfg(not(target_family = "wasm"))]
+pub mod mimalloc;
+
+/// Declare a global allocator if the platform supports it.
+#[macro_export]
+macro_rules! assign_global {
+    () => {
+        #[cfg(not(target_family = "wasm"))]
+        #[global_allocator]
+        static GLOBAL: allocator::mimalloc::Mimalloc = allocator::mimalloc::Mimalloc;
+    };
 }
diff --git a/allocator/src/mimalloc.rs b/allocator/src/mimalloc.rs
new file mode 100644
index 0000000000..f76418cb9e
--- /dev/null
+++ b/allocator/src/mimalloc.rs
@@ -0,0 +1,79 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+use core::alloc::{GlobalAlloc, Layout};
+use core::ffi::c_void;
+
+use mimalloc_sys::{mi_free, mi_malloc_aligned, mi_realloc_aligned, mi_zalloc_aligned};
+
+pub struct Mimalloc;
+
+unsafe impl GlobalAlloc for Mimalloc {
+    #[inline]
+    unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
+        debug_assert!(layout.align() < mimalloc_sys::MI_ALIGNMENT_MAX);
+        mi_malloc_aligned(layout.size(), layout.align()).cast::<u8>()
+    }
+
+    #[inline]
+    unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
+        mi_free(ptr.cast::<c_void>());
+    }
+
+    #[inline]
+    unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
+        debug_assert!(layout.align() < mimalloc_sys::MI_ALIGNMENT_MAX);
+        mi_zalloc_aligned(layout.size(), layout.align()).cast::<u8>()
+    }
+
+    #[inline]
+    unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
+        debug_assert!(layout.align() < mimalloc_sys::MI_ALIGNMENT_MAX);
+        mi_realloc_aligned(ptr.cast::<c_void>(), new_size, layout.align()).cast::<u8>()
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use std::error::Error;
+
+    #[test]
+    fn memory_can_be_allocated_and_freed() -> Result<(), Box<dyn Error>> {
+        let layout = Layout::from_size_align(8, 8)?;
+        let alloc = Mimalloc;
+
+        unsafe {
+            let ptr = alloc.alloc(layout);
+            assert!(!ptr.cast::<c_void>().is_null());
+            alloc.dealloc(ptr, layout);
+        }
+        Ok(())
+    }
+
+    #[test]
+    fn memory_can_be_alloc_zeroed_and_freed() -> Result<(), Box<dyn Error>> {
+        let layout = Layout::from_size_align(8, 8)?;
+        let alloc = Mimalloc;
+
+        unsafe {
+            let ptr = alloc.alloc_zeroed(layout);
+            assert!(!ptr.cast::<c_void>().is_null());
+            alloc.dealloc(ptr, layout);
+        }
+        Ok(())
+    }
+
+    #[test]
+    fn large_chunks_of_memory_can_be_allocated_and_freed() -> Result<(), Box<dyn Error>> {
+        let layout = Layout::from_size_align(2 * 1024 * 1024 * 1024, 8)?;
+        let alloc = Mimalloc;
+
+        unsafe {
+            let ptr = alloc.alloc(layout);
+            assert!(!ptr.cast::<c_void>().is_null());
+            alloc.dealloc(ptr, layout);
+        }
+        Ok(())
+    }
+}
diff --git a/compiler/qsc/benches/eval.rs b/compiler/qsc/benches/eval.rs
index 558f1b5059..3dbee4548d 100644
--- a/compiler/qsc/benches/eval.rs
+++ b/compiler/qsc/benches/eval.rs
@@ -1,9 +1,7 @@
 // Copyright (c) Microsoft Corporation.
 // Licensed under the MIT License.
 
-#[cfg(not(target_family = "wasm"))]
-#[global_allocator]
-static GLOBAL: allocator::Mimalloc = allocator::Mimalloc;
+allocator::assign_global!();
 
 use criterion::{criterion_group, criterion_main, Criterion};
 use indoc::indoc;
diff --git a/compiler/qsc/benches/large.rs b/compiler/qsc/benches/large.rs
index 75ceb0679f..0102d1a5d9 100644
--- a/compiler/qsc/benches/large.rs
+++ b/compiler/qsc/benches/large.rs
@@ -1,9 +1,7 @@
 // Copyright (c) Microsoft Corporation.
 // Licensed under the MIT License.
 
-#[cfg(not(target_family = "wasm"))]
-#[global_allocator]
-static GLOBAL: allocator::Mimalloc = allocator::Mimalloc;
+allocator::assign_global!();
 
 use criterion::{criterion_group, criterion_main, Criterion};
 use qsc::compile::{self, compile};
diff --git a/compiler/qsc/benches/library.rs b/compiler/qsc/benches/library.rs
index 8af3d5e6dd..a1da2bdc98 100644
--- a/compiler/qsc/benches/library.rs
+++ b/compiler/qsc/benches/library.rs
@@ -1,9 +1,7 @@
 // Copyright (c) Microsoft Corporation.
 // Licensed under the MIT License.
 
-#[cfg(not(target_family = "wasm"))]
-#[global_allocator]
-static GLOBAL: allocator::Mimalloc = allocator::Mimalloc;
+allocator::assign_global!();
 
 use criterion::{criterion_group, criterion_main, Criterion};
 use qsc::compile;
diff --git a/compiler/qsc/src/bin/qsc.rs b/compiler/qsc/src/bin/qsc.rs
index 4507b6d112..ee7a6c50d0 100644
--- a/compiler/qsc/src/bin/qsc.rs
+++ b/compiler/qsc/src/bin/qsc.rs
@@ -1,9 +1,7 @@
 // Copyright (c) Microsoft Corporation.
 // Licensed under the MIT License.
 
-#[cfg(not(target_family = "wasm"))]
-#[global_allocator]
-static GLOBAL: allocator::Mimalloc = allocator::Mimalloc;
+allocator::assign_global!();
 
 use clap::{crate_version, ArgGroup, Parser, ValueEnum};
 use log::info;
diff --git a/compiler/qsc/src/bin/qsi.rs b/compiler/qsc/src/bin/qsi.rs
index 2a4c61f729..6f3c8649b1 100644
--- a/compiler/qsc/src/bin/qsi.rs
+++ b/compiler/qsc/src/bin/qsi.rs
@@ -1,9 +1,7 @@
 // Copyright (c) Microsoft Corporation.
 // Licensed under the MIT License.
 
-#[cfg(not(target_family = "wasm"))]
-#[global_allocator]
-static GLOBAL: allocator::Mimalloc = allocator::Mimalloc;
+allocator::assign_global!();
 
 use clap::{crate_version, Parser};
 use miette::{Context, IntoDiagnostic, Report, Result};
diff --git a/fuzz/fuzz_targets/compile.rs b/fuzz/fuzz_targets/compile.rs
index 6e5d06a6ae..feb9901fbd 100644
--- a/fuzz/fuzz_targets/compile.rs
+++ b/fuzz/fuzz_targets/compile.rs
@@ -3,9 +3,7 @@
 
 #![no_main]
 
-#[cfg(not(target_family = "wasm"))]
-#[global_allocator]
-static GLOBAL: allocator::Mimalloc = allocator::Mimalloc;
+allocator::assign_global!();
 
 #[cfg(feature = "do_fuzz")]
 use libfuzzer_sys::fuzz_target;
diff --git a/pip/src/lib.rs b/pip/src/lib.rs
index 1ba3fb619e..88fcd735df 100644
--- a/pip/src/lib.rs
+++ b/pip/src/lib.rs
@@ -1,9 +1,7 @@
 // Copyright (c) Microsoft Corporation.
 // Licensed under the MIT License.
 
-#[cfg(not(target_family = "wasm"))]
-#[global_allocator]
-static GLOBAL: allocator::Mimalloc = allocator::Mimalloc;
+allocator::assign_global!();
 
 mod displayable_output;
 mod fs;

From 625fadc50acd556b7fc2cf35cb088b2e8da77612 Mon Sep 17 00:00:00 2001
From: Ian Davis <ian.f.davis@microsoft.com>
Date: Thu, 14 Mar 2024 11:14:54 -0700
Subject: [PATCH 13/14] Fix typo and add prereq check for cmake

---
 allocator/mimalloc-sys/build.rs |  2 +-
 prereqs.py                      | 25 +++++++++++++++++++++++++
 2 files changed, 26 insertions(+), 1 deletion(-)

diff --git a/allocator/mimalloc-sys/build.rs b/allocator/mimalloc-sys/build.rs
index 955fdb2683..1cbba80827 100644
--- a/allocator/mimalloc-sys/build.rs
+++ b/allocator/mimalloc-sys/build.rs
@@ -60,7 +60,7 @@ fn compile_mimalloc(dst: &Path) {
     println!("cargo:rustc-link-lib=static=mimalloc");
 }
 
-// Use cmake to download mimallloc source code and stage
+// Use cmake to download mimalloc source code and stage
 // it in the build directory.
 fn download_mimalloc() -> Result<PathBuf, Box<dyn Error>> {
     let build_dir = get_build_dir()?;
diff --git a/prereqs.py b/prereqs.py
index 548cd42ed0..772a21aa72 100755
--- a/prereqs.py
+++ b/prereqs.py
@@ -19,6 +19,7 @@
     17,
 )
 wasmpack_ver = (0, 12, 1)  # Latest tested wasm-pack version
+cmake_ver = (3, 10)  # Ensure CMake version 3.10 or later is installed
 rust_fmt_ver = (1, 7, 0)  # Current version when Rust 1.76 shipped
 clippy_ver = (0, 1, 76)
 
@@ -181,6 +182,30 @@ def check_prereqs(install=False):
     else:
         print("Unable to determine the wasm-pack version")
 
+    ### Check the cmake version ###
+    try:
+        cmake_version = subprocess.check_output(["cmake", "--version"])
+    except FileNotFoundError:
+        print("CMake not found. Install from https://cmake.org/")
+        exit(1)
+
+    version_match = re.search(
+        r"cmake version\s(\d+)\.(\d+).\d+", cmake_version.decode()
+    )
+    if version_match:
+        cmake_major = int(version_match.group(1))
+        cmake_minor = int(version_match.group(2))
+        print(f"Detected CMake version: {cmake_major}.{cmake_minor}")
+        if cmake_major < cmake_ver[0] or (
+            cmake_major == cmake_ver[0] and cmake_minor < cmake_ver[1]
+        ):
+            print(
+                f"CMake v{cmake_ver[0]}.{cmake_ver[1]} or later is required. Please update."
+            )
+            exit(1)
+    else:
+        raise Exception("Unable to determine the CMake version.")
+
 
 if __name__ == "__main__":
     if len(sys.argv) > 1 and sys.argv[1] == "--install":

From d73a7110744171807d56cc42351d61b7268137bb Mon Sep 17 00:00:00 2001
From: Ian Davis <ian.f.davis@microsoft.com>
Date: Thu, 14 Mar 2024 11:28:42 -0700
Subject: [PATCH 14/14] Updating dev container to support c compilation.

---
 .devcontainer/devcontainer.json | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json
index 7f88f3f6ce..6fcc35a587 100644
--- a/.devcontainer/devcontainer.json
+++ b/.devcontainer/devcontainer.json
@@ -1,9 +1,10 @@
 // For format details, see https://aka.ms/devcontainer.json. For config options, see the
-// README at: https://github.com/devcontainers/templates/tree/main/src/rust
+// README at: https://github.com/devcontainers/templates/tree/main/src/cpp
 {
 	"name": "qsharp",
-	"image": "mcr.microsoft.com/devcontainers/python:3",
+	"image": "mcr.microsoft.com/devcontainers/cpp",
 	"features": {
+		"ghcr.io/devcontainers/features/python:1": {},
 		"ghcr.io/devcontainers/features/node:1": {
 			"nodeGypDependencies": true,
 			"version": "lts"