@@ -3274,48 +3274,105 @@ bool os::can_execute_large_page_memory() {
32743274 return true ;
32753275}
32763276
3277- char * os::pd_reserve_memory_special (size_t bytes, size_t alignment, size_t page_size, char * addr,
3278- bool exec) {
3279- assert (UseLargePages, " only for large pages" );
3280- assert (page_size == os::large_page_size (), " Currently only support one large page size on Windows" );
3277+ static char * reserve_large_pages_individually (size_t size, char * req_addr, bool exec) {
3278+ log_debug (pagesize)(" Reserving large pages individually." );
3279+
3280+ const DWORD prot = exec ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE;
3281+ const DWORD flags = MEM_RESERVE | MEM_COMMIT | MEM_LARGE_PAGES;
32813282
3282- if (!is_aligned (bytes, page_size) || alignment > page_size) {
3283- return NULL ; // Fallback to small pages.
3283+ char * p_buf = allocate_pages_individually (size, req_addr, flags, prot, LargePagesIndividualAllocationInjectError);
3284+ if (p_buf == NULL ) {
3285+ // give an appropriate warning message
3286+ if (UseNUMAInterleaving) {
3287+ warning (" NUMA large page allocation failed, UseLargePages flag ignored" );
3288+ }
3289+ if (UseLargePagesIndividualAllocation) {
3290+ warning (" Individually allocated large pages failed, "
3291+ " use -XX:-UseLargePagesIndividualAllocation to turn off" );
3292+ }
3293+ return NULL ;
32843294 }
3295+ return p_buf;
3296+ }
3297+
3298+ static char * reserve_large_pages_single_range (size_t size, char * req_addr, bool exec) {
3299+ log_debug (pagesize)(" Reserving large pages in a single large chunk." );
32853300
32863301 const DWORD prot = exec ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE;
32873302 const DWORD flags = MEM_RESERVE | MEM_COMMIT | MEM_LARGE_PAGES;
32883303
3304+ return (char *) virtualAlloc (req_addr, size, flags, prot);
3305+ }
3306+
3307+ static char * reserve_large_pages (size_t size, char * req_addr, bool exec) {
32893308 // with large pages, there are two cases where we need to use Individual Allocation
32903309 // 1) the UseLargePagesIndividualAllocation flag is set (set by default on WS2003)
32913310 // 2) NUMA Interleaving is enabled, in which case we use a different node for each page
32923311 if (UseLargePagesIndividualAllocation || UseNUMAInterleaving) {
3293- log_debug (pagesize)(" Reserving large pages individually." );
3312+ return reserve_large_pages_individually (size, req_addr, exec);
3313+ }
3314+ return reserve_large_pages_single_range (size, req_addr, exec);
3315+ }
32943316
3295- char * p_buf = allocate_pages_individually (bytes, addr, flags, prot, LargePagesIndividualAllocationInjectError);
3296- if (p_buf == NULL ) {
3297- // give an appropriate warning message
3298- if (UseNUMAInterleaving) {
3299- warning (" NUMA large page allocation failed, UseLargePages flag ignored" );
3300- }
3301- if (UseLargePagesIndividualAllocation) {
3302- warning (" Individually allocated large pages failed, "
3303- " use -XX:-UseLargePagesIndividualAllocation to turn off" );
3304- }
3305- return NULL ;
3317+ static char * find_aligned_address (size_t size, size_t alignment) {
3318+ // Temporary reserve memory large enough to ensure we can get the requested
3319+ // alignment and still fit the reservation.
3320+ char * addr = (char *) virtualAlloc (NULL , size + alignment, MEM_RESERVE, PAGE_NOACCESS);
3321+ // Align the address to the requested alignment.
3322+ char * aligned_addr = align_up (addr, alignment);
3323+ // Free the temporary reservation.
3324+ virtualFree (addr, 0 , MEM_RELEASE);
3325+
3326+ return aligned_addr;
3327+ }
3328+
3329+ static char * reserve_large_pages_aligned (size_t size, size_t alignment, bool exec) {
3330+ log_debug (pagesize)(" Reserving large pages at an aligned address, alignment=" SIZE_FORMAT " %s" ,
3331+ byte_size_in_exact_unit (alignment), exact_unit_for_byte_size (alignment));
3332+
3333+ // Will try to find a suitable address at most 20 times. The reason we need to try
3334+ // multiple times is that between finding the aligned address and trying to commit
3335+ // the large pages another thread might have reserved an overlapping region.
3336+ const int attempts_limit = 20 ;
3337+ for (int attempts = 0 ; attempts < attempts_limit; attempts++) {
3338+ // Find aligned address.
3339+ char * aligned_address = find_aligned_address (size, alignment);
3340+
3341+ // Try to do the large page reservation using the aligned address.
3342+ aligned_address = reserve_large_pages (size, aligned_address, exec);
3343+ if (aligned_address != NULL ) {
3344+ // Reservation at the aligned address succeeded.
3345+ guarantee (is_aligned (aligned_address, alignment), " Must be aligned" );
3346+ return aligned_address;
33063347 }
3348+ }
33073349
3308- return p_buf;
3350+ log_debug (pagesize)(" Failed reserving large pages at aligned address" );
3351+ return NULL ;
3352+ }
33093353
3310- } else {
3311- log_debug (pagesize)(" Reserving large pages in a single large chunk." );
3354+ char * os::pd_reserve_memory_special (size_t bytes, size_t alignment, size_t page_size, char * addr,
3355+ bool exec) {
3356+ assert (UseLargePages, " only for large pages" );
3357+ assert (page_size == os::large_page_size (), " Currently only support one large page size on Windows" );
3358+ assert (is_aligned (addr, alignment), " Must be" );
3359+ assert (is_aligned (addr, page_size), " Must be" );
33123360
3313- // normal policy just allocate it all at once
3314- DWORD flag = MEM_RESERVE | MEM_COMMIT | MEM_LARGE_PAGES;
3315- char * res = (char *)virtualAlloc (addr, bytes, flag, prot);
3361+ if (!is_aligned (bytes, page_size)) {
3362+ // Fallback to small pages, Windows does not support mixed mappings.
3363+ return NULL ;
3364+ }
33163365
3317- return res;
3366+ // The requested alignment can be larger than the page size, for example with G1
3367+ // the alignment is bound to the heap region size. So this reservation needs to
3368+ // ensure that the requested alignment is met. When there is a requested address
3369+ // this solves it self, since it must be properly aligned already.
3370+ if (addr == NULL && alignment > page_size) {
3371+ return reserve_large_pages_aligned (bytes, alignment, exec);
33183372 }
3373+
3374+ // No additional requirements, just reserve the large pages.
3375+ return reserve_large_pages (bytes, addr, exec);
33193376}
33203377
33213378bool os::pd_release_memory_special (char * base, size_t bytes) {
0 commit comments