From e9c629ebd84296aac2fb92a376b802825d2b2f8a Mon Sep 17 00:00:00 2001 From: Robert Toyonaga Date: Tue, 7 Apr 2026 16:24:51 -0400 Subject: [PATCH] More feedback. Consolidate KernelBase resolutions in os::init_2() --- src/hotspot/os/aix/os_aix.cpp | 2 + src/hotspot/os/posix/os_posix.cpp | 4 +- src/hotspot/os/windows/os_windows.cpp | 56 +++++++++++---------------- src/hotspot/share/runtime/os.hpp | 10 ----- 4 files changed, 27 insertions(+), 45 deletions(-) diff --git a/src/hotspot/os/aix/os_aix.cpp b/src/hotspot/os/aix/os_aix.cpp index 6f962cce716..e5d935aafca 100644 --- a/src/hotspot/os/aix/os_aix.cpp +++ b/src/hotspot/os/aix/os_aix.cpp @@ -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); diff --git a/src/hotspot/os/posix/os_posix.cpp b/src/hotspot/os/posix/os_posix.cpp index 203df878055..7463a955d66 100644 --- a/src/hotspot/os/posix/os_posix.cpp +++ b/src/hotspot/os/posix/os_posix.cpp @@ -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)}; } diff --git a/src/hotspot/os/windows/os_windows.cpp b/src/hotspot/os/windows/os_windows.cpp index 02eb6921c83..8806a4d3f7f 100644 --- a/src/hotspot/os/windows/os_windows.cpp +++ b/src/hotspot/os/windows/os_windows.cpp @@ -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 -static void install_kernelbase_symbol(Fn*& fn, const char* name) { - fn = reinterpret_cast(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( - GetProcAddress(_kernelbase, - "SetThreadDescription")); + _SetThreadDescription = reinterpret_cast( + os::win32::lookup_kernelbase_symbol("SetThreadDescription")); #ifdef ASSERT - _GetThreadDescription = - reinterpret_cast( - GetProcAddress(_kernelbase, - "GetThreadDescription")); + _GetThreadDescription = reinterpret_cast( + 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::lookup_kernelbase_symbol("VirtualAlloc2")); + os::win32::MapViewOfFile3 = reinterpret_cast( + 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; } diff --git a/src/hotspot/share/runtime/os.hpp b/src/hotspot/share/runtime/os.hpp index 07056da09f8..1e674a01922 100644 --- a/src/hotspot/share/runtime/os.hpp +++ b/src/hotspot/share/runtime/os.hpp @@ -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);