Skip to content
Open
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
12 changes: 11 additions & 1 deletion .github/scripts/ci-common.sh
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,12 @@ init_non_exclusive_features() {
IFS='='; feature=($line); unset IFS;
if [[ ! -z "$feature" ]]; then
# Trim whitespaces
features[i]=$(echo $feature)
feature_name=$(echo $feature)
# jemalloc does not support Windows
if [[ $os == "windows" && $feature_name == "malloc_jemalloc" ]]; then
continue
fi
features[i]=$feature_name
let "i++"
fi
fi
Expand Down Expand Up @@ -118,6 +123,11 @@ init_exclusive_features() {
if [[ ! -z "$feature" ]]; then
# Trim whitespaces
features[i]=$(echo $feature)
# jemalloc does not support Windows
if [[ $os == "windows" && $feature_name == "malloc_jemalloc" ]]; then
continue
fi
features[i]=$feature_name
let "i++"
fi
fi
Expand Down
Empty file.
10 changes: 10 additions & 0 deletions .github/workflows/minimal-tests-core.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,16 @@ jobs:
- { os: ubuntu-22.04, triple: x86_64-unknown-linux-gnu }
- { os: ubuntu-22.04, triple: i686-unknown-linux-gnu }
- { os: macos-15, triple: x86_64-apple-darwin }
- { os: windows-latest, triple: x86_64-pc-windows-msvc }
rust: ${{ fromJson(needs.setup-test-matrix.outputs.rust )}}

name: minimal-tests-core/${{ matrix.target.triple }}/${{ matrix.rust }}
runs-on: ${{ matrix.target.os }}

defaults:
run:
shell: bash

env:
# This determines the default target which cargo-build, cargo-test, etc. use.
CARGO_BUILD_TARGET: "${{ matrix.target.triple }}"
Expand Down Expand Up @@ -88,11 +93,16 @@ jobs:
- { os: ubuntu-22.04, triple: x86_64-unknown-linux-gnu }
- { os: ubuntu-22.04, triple: i686-unknown-linux-gnu }
- { os: macos-15, triple: x86_64-apple-darwin }
- { os: windows-latest, triple: x86_64-pc-windows-msvc }
rust: ${{ fromJson(needs.setup-test-matrix.outputs.rust )}}

name: style-check/${{ matrix.target.triple }}/${{ matrix.rust }}
runs-on: ${{ matrix.target.os }}

defaults:
run:
shell: bash

env:
# This determines the default target which cargo-build, cargo-test, etc. use.
CARGO_BUILD_TARGET: "${{ matrix.target.triple }}"
Expand Down
9 changes: 9 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,15 @@ strum = "0.27.1"
strum_macros = "0.27.1"
sysinfo = "0.33.1"

[target.'cfg(windows)'.dependencies]
windows-sys = { version = "0.61", features = [
"Win32_Foundation",
"Win32_System_Memory",
"Win32_System_SystemInformation",
"Win32_System_Threading",
"Win32_System_Diagnostics_Debug",
] }

[dev-dependencies]
paste = "1.0.8"
rand = "0.9.0"
Expand Down
17 changes: 8 additions & 9 deletions src/policy/copyspace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ use crate::util::object_forwarding;
use crate::util::{copy::*, object_enum};
use crate::util::{Address, ObjectReference};
use crate::vm::*;
use libc::{mprotect, PROT_EXEC, PROT_NONE, PROT_READ, PROT_WRITE};
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;

Expand Down Expand Up @@ -293,8 +292,8 @@ impl<VM: VMBinding> CopySpace<VM> {
}
let start = self.common().start;
let extent = self.common().extent;
unsafe {
mprotect(start.to_mut_ptr(), extent, PROT_NONE);
if let Err(e) = crate::util::memory::mprotect(start, extent) {
panic!("Failed to protect memory: {:?}", e);
}
trace!("Protect {:x} {:x}", start, start + extent);
}
Expand All @@ -308,12 +307,12 @@ impl<VM: VMBinding> CopySpace<VM> {
}
let start = self.common().start;
let extent = self.common().extent;
unsafe {
mprotect(
start.to_mut_ptr(),
extent,
PROT_READ | PROT_WRITE | PROT_EXEC,
);
if let Err(e) = crate::util::memory::munprotect(
start,
extent,
crate::util::memory::MmapProtection::ReadWriteExec,
) {
panic!("Failed to unprotect memory: {:?}", e);
}
trace!("Unprotect {:x} {:x}", start, start + extent);
}
Expand Down
42 changes: 39 additions & 3 deletions src/scheduler/affinity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,17 @@ pub fn get_total_num_cpus() -> u16 {
}
}

#[cfg(not(target_os = "linux"))]
#[cfg(target_os = "windows")]
/// Return the total number of cores allocated to the program.
pub fn get_total_num_cpus() -> u16 {
unsafe {
windows_sys::Win32::System::Threading::GetActiveProcessorCount(
windows_sys::Win32::System::Threading::ALL_PROCESSOR_GROUPS,
) as u16
}
}

#[cfg(not(any(target_os = "linux", target_os = "windows")))]
/// Return the total number of cores allocated to the program.
pub fn get_total_num_cpus() -> u16 {
unimplemented!()
Expand Down Expand Up @@ -59,7 +69,18 @@ fn bind_current_thread_to_core(cpu: CoreId) {
}
}

#[cfg(not(target_os = "linux"))]
#[cfg(target_os = "windows")]
/// Bind the current thread to the specified core.
fn bind_current_thread_to_core(cpu: CoreId) {
unsafe {
windows_sys::Win32::System::Threading::SetThreadAffinityMask(
windows_sys::Win32::System::Threading::GetCurrentThread(),
1 << cpu,
);
}
}

#[cfg(not(any(target_os = "linux", target_os = "windows")))]
/// Bind the current thread to the specified core.
fn bind_current_thread_to_core(_cpu: CoreId) {
unimplemented!()
Expand All @@ -79,7 +100,22 @@ fn bind_current_thread_to_cpuset(cpuset: &[CoreId]) {
}
}

#[cfg(not(any(target_os = "linux", target_os = "android")))]
#[cfg(target_os = "windows")]
/// Bind the current thread to the specified core.
fn bind_current_thread_to_cpuset(cpuset: &[CoreId]) {
let mut mask = 0;
for cpu in cpuset {
mask |= 1 << cpu;
}
unsafe {
windows_sys::Win32::System::Threading::SetThreadAffinityMask(
windows_sys::Win32::System::Threading::GetCurrentThread(),
mask,
);
}
}

#[cfg(not(any(target_os = "linux", target_os = "android", target_os = "windows")))]
/// Bind the current thread to the specified core.
fn bind_current_thread_to_cpuset(_cpuset: &[CoreId]) {
unimplemented!()
Expand Down
54 changes: 52 additions & 2 deletions src/util/malloc/library.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,18 @@

#[cfg(feature = "malloc_jemalloc")]
pub use self::jemalloc::*;
#[cfg(not(any(feature = "malloc_jemalloc", feature = "malloc_mimalloc",)))]
#[cfg(all(
not(target_os = "windows"),
not(any(feature = "malloc_jemalloc", feature = "malloc_mimalloc"))
))]
pub use self::libc_malloc::*;
#[cfg(feature = "malloc_mimalloc")]
pub use self::mimalloc::*;
#[cfg(all(
target_os = "windows",
not(any(feature = "malloc_jemalloc", feature = "malloc_mimalloc"))
))]
pub use self::win_malloc::*;

/// When we count page usage of library malloc, we assume they allocate in pages. For some malloc implementations,
/// they may use a larger page (e.g. mimalloc's 64K page). For libraries that we are not sure, we assume they use
Expand Down Expand Up @@ -43,7 +51,10 @@ mod mimalloc {
}

/// If no malloc lib is specified, use the libc implementation
#[cfg(not(any(feature = "malloc_jemalloc", feature = "malloc_mimalloc",)))]
#[cfg(all(
not(target_os = "windows"),
not(any(feature = "malloc_jemalloc", feature = "malloc_mimalloc"))
))]
mod libc_malloc {
// Normal 4K page
pub const LOG_BYTES_IN_MALLOC_PAGE: u8 = crate::util::constants::LOG_BYTES_IN_PAGE;
Expand All @@ -61,3 +72,42 @@ mod libc_malloc {
#[cfg(target_os = "macos")]
pub use self::malloc_size as malloc_usable_size;
}

/// Windows malloc implementation using HeapAlloc
#[cfg(all(
target_os = "windows",
not(any(feature = "malloc_jemalloc", feature = "malloc_mimalloc"))
))]
mod win_malloc {
// Normal 4K page
pub const LOG_BYTES_IN_MALLOC_PAGE: u8 = crate::util::constants::LOG_BYTES_IN_PAGE;

use std::ffi::c_void;
use windows_sys::Win32::System::Memory::*;

pub unsafe fn malloc(size: usize) -> *mut c_void {
HeapAlloc(GetProcessHeap(), 0, size)
}

pub unsafe fn free(ptr: *mut c_void) {
if !ptr.is_null() {
HeapFree(GetProcessHeap(), 0, ptr);
}
}

pub unsafe fn calloc(nmemb: usize, size: usize) -> *mut c_void {
let total = nmemb * size;
HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, total)
}

pub unsafe fn realloc(ptr: *mut c_void, size: usize) -> *mut c_void {
if ptr.is_null() {
return malloc(size);
}
HeapReAlloc(GetProcessHeap(), 0, ptr, size)
}

pub unsafe fn malloc_usable_size(ptr: *const c_void) -> usize {
HeapSize(GetProcessHeap(), 0, ptr)
}
}
63 changes: 41 additions & 22 deletions src/util/malloc/malloc_ms_util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ use crate::util::Address;
use crate::vm::VMBinding;

/// Allocate with alignment. This also guarantees the memory is zero initialized.
/// This uses posix_memalign, which is not available on Windows.
/// This would somehow affect `MallocMarkSweep` performance on Windows.
#[cfg(all(
not(target_os = "windows"),
not(any(feature = "malloc_jemalloc", feature = "malloc_mimalloc"))
))]
pub fn align_alloc(size: usize, align: usize) -> Address {
let mut ptr = std::ptr::null_mut::<libc::c_void>();
let ptr_ptr = std::ptr::addr_of_mut!(ptr);
Expand Down Expand Up @@ -71,28 +77,41 @@ pub fn alloc<VM: VMBinding>(size: usize, align: usize, offset: usize) -> (Addres
let mut is_offset_malloc = false;
// malloc returns 16 bytes aligned address.
// So if the alignment is smaller than 16 bytes, we do not need to align.
if align <= 16 && offset == 0 {
let raw = unsafe { calloc(1, size) };
address = Address::from_mut_ptr(raw);
debug_assert!(address.is_aligned_to(align));
} else if align > 16 && offset == 0 {
address = align_alloc(size, align);
debug_assert!(
address.is_aligned_to(align),
"Address: {:x} is not aligned to the given alignment: {}",
address,
align
);
} else {
address = align_offset_alloc::<VM>(size, align, offset);
is_offset_malloc = true;
debug_assert!(
(address + offset).is_aligned_to(align),
"Address: {:x} is not aligned to the given alignment: {} at offset: {}",
address,
align,
offset
);

match (align, offset) {
(a, 0) if a <= 16 => {
let raw = unsafe { calloc(1, size) };
address = Address::from_mut_ptr(raw);
debug_assert!(address.is_aligned_to(align));
}
#[cfg(all(
not(target_os = "windows"),
not(any(feature = "malloc_jemalloc", feature = "malloc_mimalloc"))
))]
// On non-Windows platforms with posix_memalign, we can use align_alloc for alignments > 16
// However, on Windows, there is no equivalent function.
// The memory alloc by `align_alloc` may not be freed correctly by `free`.
// So we use offset allocation for all alignments > 16 on Windows.
(a, 0) if a > 16 => {
address = align_alloc(size, align);
debug_assert!(
address.is_aligned_to(align),
"Address: {:x} is not aligned to the given alignment: {}",
address,
align
);
}
_ => {
address = align_offset_alloc::<VM>(size, align, offset);
is_offset_malloc = true;
debug_assert!(
(address + offset).is_aligned_to(align),
"Address: {:x} is not aligned to the given alignment: {} at offset: {}",
address,
align,
offset
);
}
}
(address, is_offset_malloc)
}
Loading
Loading