More feedback. Consolidate KernelBase resolutions in os::init_2()

This commit is contained in:
Robert Toyonaga 2026-04-07 16:24:51 -04:00
parent 6589010eeb
commit e9c629ebd8
4 changed files with 27 additions and 45 deletions

View File

@ -1798,6 +1798,7 @@ char* os::pd_reserve_memory(size_t bytes, bool exec) {
}
}
// mmap(PROT_NONE) allocations are inherently splittable.
os::PlaceholderRegion os::pd_reserve_placeholder_memory(size_t bytes, bool exec, char* addr) {
// Always round to os::vm_page_size(), which may be larger than 4K.
bytes = align_up(bytes, os::vm_page_size());
@ -1819,6 +1820,7 @@ os::PlaceholderRegionPair os::pd_split_memory(PlaceholderRegion& orig, size_t of
assert(base != nullptr, "Region base cannot be null");
assert(offset > 0, "Offset must be positive");
assert(offset < region_size, "Offset must be less than region size");
assert(is_aligned(offset, os::vm_page_size()), "Offset should be page-aligned");
// update vmembk to reflect the split
vmembk_t* const vmi = vmembk_find(base);

View File

@ -544,6 +544,7 @@ char* os::map_memory_to_file_aligned(size_t size, size_t alignment, int file_des
#ifndef AIX
// mmap(PROT_NONE) allocations are inherently splittable.
os::PlaceholderRegion os::pd_reserve_placeholder_memory(size_t bytes, bool exec, char* addr) {
// mmap returns memory that is splittable by default.
char* base;
@ -556,13 +557,14 @@ os::PlaceholderRegion os::pd_reserve_placeholder_memory(size_t bytes, bool exec,
}
os::PlaceholderRegionPair os::pd_split_memory(const PlaceholderRegion& orig, size_t offset) {
// On POSIX, mmap regions are inherently splittable. Just do bookkeeping.
// On POSIX, mmap regions are inherently splittable.
char* base = orig.base();
size_t region_size = orig.size();
assert(base != nullptr, "Region base cannot be null");
assert(offset > 0, "Offset must be positive");
assert(offset < region_size, "Offset must be less than region size");
assert(is_aligned(offset, os::vm_page_size()), "Offset should be page-aligned");
return {PlaceholderRegion(base, offset), PlaceholderRegion(base + offset, region_size - offset)};
}

View File

@ -243,12 +243,6 @@ static LPVOID virtualAllocExNuma(HANDLE hProcess, LPVOID lpAddress, SIZE_T dwSiz
return result;
}
// VirtualAlloc2 (since Windows version 1803). loaded from KernelBase in os::init_2()
os::win32::VirtualAlloc2Fn os::win32::VirtualAlloc2 = nullptr;
// MapViewOfFile3 (since Windows version 1803). loaded from KernelBase in os::init_2()
os::win32::MapViewOfFile3Fn os::win32::MapViewOfFile3 = nullptr;
static void* lookup_kernelbase_library() {
const char* const name = "KernelBase";
char ebuf[1024];
@ -267,22 +261,6 @@ void* os::win32::lookup_kernelbase_symbol(const char* name) {
return os::dll_lookup(handle, name);
}
template <typename Fn>
static void install_kernelbase_symbol(Fn*& fn, const char* name) {
fn = reinterpret_cast<Fn*>(os::win32::lookup_kernelbase_symbol(name));
}
static void initialize_kernelbase_apis() {
install_kernelbase_symbol(os::win32::VirtualAlloc2, "VirtualAlloc2");
log_debug(os)("VirtualAlloc2 is%s available.", os::win32::VirtualAlloc2 == nullptr ? " not" : "");
install_kernelbase_symbol(os::win32::MapViewOfFile3, "MapViewOfFile3");
log_debug(os)("MapViewOfFile3 is%s available.", os::win32::MapViewOfFile3 == nullptr ? " not" : "");
}
static bool is_VirtualAlloc2_supported() {
return os::win32::VirtualAlloc2 != nullptr;
}
// Logging wrapper for MapViewOfFileEx
static LPVOID mapViewOfFileEx(HANDLE hFileMappingObject, DWORD dwDesiredAccess, DWORD dwFileOffsetHigh,
DWORD dwFileOffsetLow, SIZE_T dwNumberOfBytesToMap, LPVOID lpBaseAddress) {
@ -3297,6 +3275,15 @@ char* os::replace_existing_mapping_with_file_mapping(char* base, size_t size, in
return map_memory_to_file(base, size, fd);
}
// VirtualAlloc2 / MapViewOfFile3 (1803+). Resolved in os::init_2() via lookup_kernelbase_symbol.
os::win32::VirtualAlloc2Fn os::win32::VirtualAlloc2 = nullptr;
os::win32::MapViewOfFile3Fn os::win32::MapViewOfFile3 = nullptr;
static bool is_VirtualAlloc2_supported() {
return os::win32::VirtualAlloc2 != nullptr;
}
// Multiple threads can race in this code but it's not possible to unmap small sections of
// virtual space to get requested alignment, like posix-like os's.
// Windows prevents multiple thread from remapping over each other so this loop is thread-safe.
@ -3459,6 +3446,7 @@ char* os::pd_reserve_memory(size_t bytes, bool exec) {
return pd_attempt_reserve_memory_at(nullptr /* addr */, bytes, exec);
}
// This allocates a placeholder via VirtualAlloc2(MEM_RESERVE_PLACEHOLDER).
os::PlaceholderRegion os::pd_reserve_placeholder_memory(size_t bytes, bool exec, char* addr) {
if (!is_VirtualAlloc2_supported()) {
return PlaceholderRegion();
@ -3497,6 +3485,7 @@ os::PlaceholderRegionPair os::pd_split_memory(const PlaceholderRegion& orig, siz
assert(base != nullptr, "Region base cannot be null.");
assert(offset > 0, "Offset must be positive (nothing to split at 0).");
assert(offset < region_size, "Offset must be less than region size.");
assert(is_aligned(offset, os::vm_page_size()), "Offset should be page-aligned");
// VirtualFree with MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER splits the
// placeholder [base, base+region_size) into two placeholders:
@ -3517,6 +3506,7 @@ os::PlaceholderRegionPair os::pd_split_memory(const PlaceholderRegion& orig, siz
return {PlaceholderRegion(base, offset), PlaceholderRegion(base + offset, region_size - offset)};
}
// Replaces the placeholder via VirtualAlloc2(MEM_REPLACE_PLACEHOLDER).
char* os::pd_convert_to_reserved(PlaceholderRegion region) {
return os::win32::convert_placeholder_to_reserved(region);
}
@ -4821,23 +4811,21 @@ jint os::init_2(void) {
// Lookup SetThreadDescription - the docs state we must use runtime-linking of
// kernelbase.dll, so that is what we do.
HINSTANCE _kernelbase = LoadLibrary(TEXT("kernelbase.dll"));
if (_kernelbase != nullptr) {
_SetThreadDescription =
reinterpret_cast<SetThreadDescriptionFnPtr>(
GetProcAddress(_kernelbase,
"SetThreadDescription"));
_SetThreadDescription = reinterpret_cast<SetThreadDescriptionFnPtr>(
os::win32::lookup_kernelbase_symbol("SetThreadDescription"));
#ifdef ASSERT
_GetThreadDescription =
reinterpret_cast<GetThreadDescriptionFnPtr>(
GetProcAddress(_kernelbase,
"GetThreadDescription"));
_GetThreadDescription = reinterpret_cast<GetThreadDescriptionFnPtr>(
os::win32::lookup_kernelbase_symbol("GetThreadDescription"));
#endif
}
log_info(os, thread)("The SetThreadDescription API is%s available.", _SetThreadDescription == nullptr ? " not" : "");
// Prepare KernelBase APIs (VirtualAlloc2, MapViewOfFile3) if available (Windows version 1803).
initialize_kernelbase_apis();
os::win32::VirtualAlloc2 = reinterpret_cast<os::win32::VirtualAlloc2Fn>(
os::win32::lookup_kernelbase_symbol("VirtualAlloc2"));
os::win32::MapViewOfFile3 = reinterpret_cast<os::win32::MapViewOfFile3Fn>(
os::win32::lookup_kernelbase_symbol("MapViewOfFile3"));
log_debug(os)("VirtualAlloc2 is%s available.", os::win32::VirtualAlloc2 == nullptr ? " not" : "");
log_debug(os)("MapViewOfFile3 is%s available.", os::win32::MapViewOfFile3 == nullptr ? " not" : "");
return JNI_OK;
}

View File

@ -242,18 +242,10 @@ class os: AllStatic {
static char* pd_reserve_memory(size_t bytes, bool executable);
// On Windows, this allocates a placeholder via VirtualAlloc2(MEM_RESERVE_PLACEHOLDER).
// On POSIX, this is a normal mmap(PROT_NONE) allocation (inherently splittable).
// If addr is non-null, attempts to place the reservation at that address.
// If the returned PlaceholderRegion is empty, the reservation failed.
static PlaceholderRegion pd_reserve_placeholder_memory(size_t bytes, bool executable, char* addr = nullptr);
// On Windows, splits the placeholder with VirtualFree(MEM_PRESERVE_PLACEHOLDER).
// On POSIX/AIX, bookkeeping only (AIX updates vmembk). 'orig' must not be reused after this call.
static PlaceholderRegionPair pd_split_memory(const PlaceholderRegion& orig, size_t offset);
// On Windows, replaces the placeholder via VirtualAlloc2(MEM_REPLACE_PLACEHOLDER).
// On POSIX, this is just a no-op.
static char* pd_convert_to_reserved(PlaceholderRegion region);
static char* pd_attempt_reserve_memory_at(char* addr, size_t bytes, bool executable);
@ -555,8 +547,6 @@ class os: AllStatic {
// Reserves a virtual memory region that can be split after allocation.
// The returned region must be converted via convert_to_reserved() before committing.
// This can fail recoverably if this is a Windows system that does not support VirtualAlloc2
// (an empty PlaceholderRegion is returned).
// If the returned PlaceholderRegion is empty, the reservation failed.
// If addr is non-null, attempts to place the reservation at that address.
static PlaceholderRegion reserve_placeholder_memory(size_t bytes, MemTag mem_tag, bool executable = false, char* addr = nullptr);