@@ -3487,7 +3487,57 @@ bool os::pd_uncommit_memory(char* addr, size_t bytes) {
3487
3487
}
3488
3488
3489
3489
bool os::pd_release_memory (char * addr, size_t bytes) {
3490
- return virtualFree (addr, 0 , MEM_RELEASE) != 0 ;
3490
+ // Given a range we are to release, we require a mapping to start at the beginning of that range;
3491
+ // if NUMA or LP we allow the range to contain multiple mappings, which have to cover the range
3492
+ // completely; otherwise the range must match an OS mapping exactly.
3493
+ address start = (address)addr;
3494
+ address end = start + bytes;
3495
+ os::win32::mapping_info_t mi;
3496
+ const bool multiple_mappings_allowed = UseLargePagesIndividualAllocation || UseNUMAInterleaving;
3497
+ address p = start;
3498
+ bool first_mapping = true ;
3499
+
3500
+ do {
3501
+ // Find mapping and check it
3502
+ const char * err = NULL ;
3503
+ if (!os::win32::find_mapping (p, &mi)) {
3504
+ err = " no mapping found" ;
3505
+ } else {
3506
+ if (first_mapping) {
3507
+ if (mi.base != start) {
3508
+ err = " base address mismatch" ;
3509
+ }
3510
+ if (multiple_mappings_allowed ? (mi.size > bytes) : (mi.size != bytes)) {
3511
+ err = " size mismatch" ;
3512
+ }
3513
+ } else {
3514
+ assert (p == mi.base && mi.size > 0 , " Sanity" );
3515
+ if (mi.base + mi.size > end) {
3516
+ err = " mapping overlaps end" ;
3517
+ }
3518
+ if (mi.size == 0 ) {
3519
+ err = " zero length mapping?" ; // Should never happen; just to prevent endlessly looping in release.
3520
+ }
3521
+ }
3522
+ }
3523
+ // Handle mapping error. We assert in debug, unconditionally print a warning in release.
3524
+ if (err != NULL ) {
3525
+ log_warning (os)(" bad release: [" PTR_FORMAT " -" PTR_FORMAT " ): %s" , p2i (start), p2i (end), err);
3526
+ #ifdef ASSERT
3527
+ os::print_memory_mappings ((char *)start, bytes, tty);
3528
+ assert (false , " bad release: [" PTR_FORMAT " -" PTR_FORMAT " ): %s" , p2i (start), p2i (end), err);
3529
+ #endif
3530
+ return false ;
3531
+ }
3532
+ // Free this range
3533
+ if (virtualFree (p, 0 , MEM_RELEASE) == FALSE ) {
3534
+ return false ;
3535
+ }
3536
+ first_mapping = false ;
3537
+ p = mi.base + mi.size ;
3538
+ } while (p < end);
3539
+
3540
+ return true ;
3491
3541
}
3492
3542
3493
3543
bool os::pd_create_stack_guard_pages (char * addr, size_t size) {
@@ -5873,3 +5923,151 @@ void os::win32::initialize_thread_ptr_offset() {
5873
5923
bool os::supports_map_sync () {
5874
5924
return false ;
5875
5925
}
5926
+
5927
+ #ifdef ASSERT
5928
+ static void check_meminfo (MEMORY_BASIC_INFORMATION* minfo) {
5929
+ assert (minfo->State == MEM_FREE || minfo->State == MEM_COMMIT || minfo->State == MEM_RESERVE, " Invalid state" );
5930
+ if (minfo->State != MEM_FREE) {
5931
+ assert (minfo->AllocationBase != NULL && minfo->BaseAddress >= minfo->AllocationBase , " Invalid pointers" );
5932
+ assert (minfo->RegionSize > 0 , " Invalid region size" );
5933
+ }
5934
+ }
5935
+ #endif
5936
+
5937
+
5938
+ static bool checkedVirtualQuery (address addr, MEMORY_BASIC_INFORMATION* minfo) {
5939
+ ZeroMemory (minfo, sizeof (MEMORY_BASIC_INFORMATION));
5940
+ if (::VirtualQuery (addr, minfo, sizeof (MEMORY_BASIC_INFORMATION)) == sizeof (MEMORY_BASIC_INFORMATION)) {
5941
+ DEBUG_ONLY (check_meminfo (minfo);)
5942
+ return true ;
5943
+ }
5944
+ return false ;
5945
+ }
5946
+
5947
+ // Given a pointer pointing into an allocation (an area allocated with VirtualAlloc),
5948
+ // return information about that allocation.
5949
+ bool os::win32::find_mapping (address addr, mapping_info_t * mi) {
5950
+ // Query at addr to find allocation base; then, starting at allocation base,
5951
+ // query all regions, until we either find the next allocation or a free area.
5952
+ ZeroMemory (mi, sizeof (mapping_info_t ));
5953
+ MEMORY_BASIC_INFORMATION minfo;
5954
+ address allocation_base = NULL ;
5955
+ address allocation_end = NULL ;
5956
+ bool rc = false ;
5957
+ if (checkedVirtualQuery (addr, &minfo)) {
5958
+ if (minfo.State != MEM_FREE) {
5959
+ allocation_base = (address)minfo.AllocationBase ;
5960
+ allocation_end = allocation_base;
5961
+ // Iterate through all regions in this allocation to find its end. While we are here, also count things.
5962
+ for (;;) {
5963
+ bool rc = checkedVirtualQuery (allocation_end, &minfo);
5964
+ if (rc == false || // VirtualQuery error, end of allocation?
5965
+ minfo.State == MEM_FREE || // end of allocation, free memory follows
5966
+ (address)minfo.AllocationBase != allocation_base) // end of allocation, a new one starts
5967
+ {
5968
+ break ;
5969
+ }
5970
+ const size_t region_size = minfo.RegionSize ;
5971
+ mi->regions ++;
5972
+ if (minfo.State == MEM_COMMIT) {
5973
+ mi->committed_size += minfo.RegionSize ;
5974
+ }
5975
+ allocation_end += region_size;
5976
+ }
5977
+ if (allocation_base != NULL && allocation_end > allocation_base) {
5978
+ mi->base = allocation_base;
5979
+ mi->size = allocation_end - allocation_base;
5980
+ rc = true ;
5981
+ }
5982
+ }
5983
+ }
5984
+ #ifdef ASSERT
5985
+ if (rc) {
5986
+ assert (mi->size > 0 && mi->size >= mi->committed_size , " Sanity" );
5987
+ assert (addr >= mi->base && addr < mi->base + mi->size , " Sanity" );
5988
+ assert (mi->regions > 0 , " Sanity" );
5989
+ }
5990
+ #endif
5991
+ return rc;
5992
+ }
5993
+
5994
+ // Helper function for print_memory_mappings:
5995
+ // Given a MEMORY_BASIC_INFORMATION, containing information about a non-free region:
5996
+ // print out all regions in that allocation. If any of those regions
5997
+ // fall outside the given range [start, end), indicate that in the output.
5998
+ // Return the pointer to the end of the allocation.
5999
+ static address print_one_mapping (MEMORY_BASIC_INFORMATION* minfo, address start, address end, outputStream* st) {
6000
+ assert (start != NULL && end != NULL && end > start, " Sanity" );
6001
+ assert (minfo->State != MEM_FREE, " Not inside an allocation." );
6002
+ address allocation_base = (address)minfo->AllocationBase ;
6003
+ address last_region_end = NULL ;
6004
+ st->print_cr (" AllocationBase: " PTR_FORMAT " :" , allocation_base);
6005
+ #define IS_IN (p ) (p >= start && p < end)
6006
+ for (;;) {
6007
+ address region_start = (address)minfo->BaseAddress ;
6008
+ address region_end = region_start + minfo->RegionSize ;
6009
+ assert (region_end > region_start, " Sanity" );
6010
+ if (region_end <= start) {
6011
+ st->print (" <outside range> " );
6012
+ } else if (region_start >= end) {
6013
+ st->print (" <outside range> " );
6014
+ } else if (!IS_IN (region_start) || !IS_IN (region_end - 1 )) {
6015
+ st->print (" <partly outside range> " );
6016
+ }
6017
+ st->print (" [" PTR_FORMAT " -" PTR_FORMAT " ), state=" , p2i (region_start), p2i (region_end));
6018
+ switch (minfo->State ) {
6019
+ case MEM_COMMIT: st->print (" MEM_COMMIT" ); break ;
6020
+ case MEM_FREE: st->print (" MEM_FREE" ); break ;
6021
+ case MEM_RESERVE: st->print (" MEM_RESERVE" ); break ;
6022
+ default : st->print (" %x?" , (unsigned )minfo->State );
6023
+ }
6024
+ st->print (" , prot=%x, type=" , (unsigned )minfo->AllocationProtect );
6025
+ switch (minfo->Type ) {
6026
+ case MEM_IMAGE: st->print (" MEM_IMAGE" ); break ;
6027
+ case MEM_MAPPED: st->print (" MEM_MAPPED" ); break ;
6028
+ case MEM_PRIVATE: st->print (" MEM_PRIVATE" ); break ;
6029
+ default : st->print (" %x?" , (unsigned )minfo->State );
6030
+ }
6031
+ st->cr ();
6032
+ bool rc = checkedVirtualQuery (region_end, minfo);
6033
+ if (rc == false || // VirtualQuery error, end of allocation?
6034
+ (minfo->State == MEM_FREE) || // end of allocation, free memory follows
6035
+ ((address)minfo->AllocationBase != allocation_base) || // end of allocation, a new one starts
6036
+ (region_end > end)) // end of range to print.
6037
+ {
6038
+ return region_end;
6039
+ }
6040
+ }
6041
+ #undef IS_IN
6042
+ ShouldNotReachHere ();
6043
+ return NULL ;
6044
+ }
6045
+
6046
+ void os::print_memory_mappings (char * addr, size_t bytes, outputStream* st) {
6047
+ MEMORY_BASIC_INFORMATION minfo;
6048
+ address start = (address)addr;
6049
+ address end = start + bytes;
6050
+ address p = start;
6051
+ while (p < end) {
6052
+ // Probe for the next mapping.
6053
+ if (checkedVirtualQuery (p, &minfo)) {
6054
+ if (minfo.State != MEM_FREE) {
6055
+ // Found one. Print it out.
6056
+ address p2 = print_one_mapping (&minfo, start, end, st);
6057
+ assert (p2 > p, " Sanity" );
6058
+ p = p2;
6059
+ } else {
6060
+ // Note: for free regions, most of MEMORY_BASIC_INFORMATION is undefined.
6061
+ // Only region dimensions are not: use those to jump to the end of
6062
+ // the free range.
6063
+ address region_start = (address)minfo.BaseAddress ;
6064
+ address region_end = region_start + minfo.RegionSize ;
6065
+ assert (p >= region_start && p < region_end, " Sanity" );
6066
+ p = region_end;
6067
+ }
6068
+ } else {
6069
+ // advance probe pointer.
6070
+ p += os::vm_allocation_granularity ();
6071
+ }
6072
+ }
6073
+ }
0 commit comments