8255978: [windows] os::release_memory may not release the full range
Reviewed-by: iklam, minqi
This commit is contained in:
parent
6702910b74
commit
f626ed6a43
@ -3290,3 +3290,6 @@ int os::compare_file_modified_times(const char* file1, const char* file2) {
|
||||
bool os::supports_map_sync() {
|
||||
return false;
|
||||
}
|
||||
|
||||
void os::print_memory_mappings(char* addr, size_t bytes, outputStream* st) {}
|
||||
|
||||
|
@ -2786,3 +2786,6 @@ bool os::start_debugging(char *buf, int buflen) {
|
||||
}
|
||||
return yes;
|
||||
}
|
||||
|
||||
void os::print_memory_mappings(char* addr, size_t bytes, outputStream* st) {}
|
||||
|
||||
|
@ -5485,6 +5485,35 @@ bool os::supports_map_sync() {
|
||||
return true;
|
||||
}
|
||||
|
||||
void os::print_memory_mappings(char* addr, size_t bytes, outputStream* st) {
|
||||
unsigned long long start = (unsigned long long)addr;
|
||||
unsigned long long end = start + bytes;
|
||||
FILE* f = ::fopen("/proc/self/maps", "r");
|
||||
int num_found = 0;
|
||||
if (f != NULL) {
|
||||
st->print("Range [%llx-%llx) contains: ", start, end);
|
||||
char line[512];
|
||||
while(fgets(line, sizeof(line), f) == line) {
|
||||
unsigned long long a1 = 0;
|
||||
unsigned long long a2 = 0;
|
||||
if (::sscanf(line, "%llx-%llx", &a1, &a2) == 2) {
|
||||
// Lets print out every range which touches ours.
|
||||
if ((a1 >= start && a1 < end) || // left leg in
|
||||
(a2 >= start && a2 < end) || // right leg in
|
||||
(a1 < start && a2 >= end)) { // superimposition
|
||||
num_found ++;
|
||||
st->print("%s", line); // line includes \n
|
||||
}
|
||||
}
|
||||
}
|
||||
::fclose(f);
|
||||
if (num_found == 0) {
|
||||
st->print("nothing.");
|
||||
}
|
||||
st->cr();
|
||||
}
|
||||
}
|
||||
|
||||
/////////////// Unit tests ///////////////
|
||||
|
||||
#ifndef PRODUCT
|
||||
|
@ -3487,7 +3487,57 @@ bool os::pd_uncommit_memory(char* addr, size_t bytes) {
|
||||
}
|
||||
|
||||
bool os::pd_release_memory(char* addr, size_t bytes) {
|
||||
return virtualFree(addr, 0, MEM_RELEASE) != 0;
|
||||
// Given a range we are to release, we require a mapping to start at the beginning of that range;
|
||||
// if NUMA or LP we allow the range to contain multiple mappings, which have to cover the range
|
||||
// completely; otherwise the range must match an OS mapping exactly.
|
||||
address start = (address)addr;
|
||||
address end = start + bytes;
|
||||
os::win32::mapping_info_t mi;
|
||||
const bool multiple_mappings_allowed = UseLargePagesIndividualAllocation || UseNUMAInterleaving;
|
||||
address p = start;
|
||||
bool first_mapping = true;
|
||||
|
||||
do {
|
||||
// Find mapping and check it
|
||||
const char* err = NULL;
|
||||
if (!os::win32::find_mapping(p, &mi)) {
|
||||
err = "no mapping found";
|
||||
} else {
|
||||
if (first_mapping) {
|
||||
if (mi.base != start) {
|
||||
err = "base address mismatch";
|
||||
}
|
||||
if (multiple_mappings_allowed ? (mi.size > bytes) : (mi.size != bytes)) {
|
||||
err = "size mismatch";
|
||||
}
|
||||
} else {
|
||||
assert(p == mi.base && mi.size > 0, "Sanity");
|
||||
if (mi.base + mi.size > end) {
|
||||
err = "mapping overlaps end";
|
||||
}
|
||||
if (mi.size == 0) {
|
||||
err = "zero length mapping?"; // Should never happen; just to prevent endlessly looping in release.
|
||||
}
|
||||
}
|
||||
}
|
||||
// Handle mapping error. We assert in debug, unconditionally print a warning in release.
|
||||
if (err != NULL) {
|
||||
log_warning(os)("bad release: [" PTR_FORMAT "-" PTR_FORMAT "): %s", p2i(start), p2i(end), err);
|
||||
#ifdef ASSERT
|
||||
os::print_memory_mappings((char*)start, bytes, tty);
|
||||
assert(false, "bad release: [" PTR_FORMAT "-" PTR_FORMAT "): %s", p2i(start), p2i(end), err);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
// Free this range
|
||||
if (virtualFree(p, 0, MEM_RELEASE) == FALSE) {
|
||||
return false;
|
||||
}
|
||||
first_mapping = false;
|
||||
p = mi.base + mi.size;
|
||||
} while (p < end);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool os::pd_create_stack_guard_pages(char* addr, size_t size) {
|
||||
@ -5873,3 +5923,151 @@ void os::win32::initialize_thread_ptr_offset() {
|
||||
bool os::supports_map_sync() {
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef ASSERT
|
||||
static void check_meminfo(MEMORY_BASIC_INFORMATION* minfo) {
|
||||
assert(minfo->State == MEM_FREE || minfo->State == MEM_COMMIT || minfo->State == MEM_RESERVE, "Invalid state");
|
||||
if (minfo->State != MEM_FREE) {
|
||||
assert(minfo->AllocationBase != NULL && minfo->BaseAddress >= minfo->AllocationBase, "Invalid pointers");
|
||||
assert(minfo->RegionSize > 0, "Invalid region size");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static bool checkedVirtualQuery(address addr, MEMORY_BASIC_INFORMATION* minfo) {
|
||||
ZeroMemory(minfo, sizeof(MEMORY_BASIC_INFORMATION));
|
||||
if (::VirtualQuery(addr, minfo, sizeof(MEMORY_BASIC_INFORMATION)) == sizeof(MEMORY_BASIC_INFORMATION)) {
|
||||
DEBUG_ONLY(check_meminfo(minfo);)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Given a pointer pointing into an allocation (an area allocated with VirtualAlloc),
|
||||
// return information about that allocation.
|
||||
bool os::win32::find_mapping(address addr, mapping_info_t* mi) {
|
||||
// Query at addr to find allocation base; then, starting at allocation base,
|
||||
// query all regions, until we either find the next allocation or a free area.
|
||||
ZeroMemory(mi, sizeof(mapping_info_t));
|
||||
MEMORY_BASIC_INFORMATION minfo;
|
||||
address allocation_base = NULL;
|
||||
address allocation_end = NULL;
|
||||
bool rc = false;
|
||||
if (checkedVirtualQuery(addr, &minfo)) {
|
||||
if (minfo.State != MEM_FREE) {
|
||||
allocation_base = (address)minfo.AllocationBase;
|
||||
allocation_end = allocation_base;
|
||||
// Iterate through all regions in this allocation to find its end. While we are here, also count things.
|
||||
for (;;) {
|
||||
bool rc = checkedVirtualQuery(allocation_end, &minfo);
|
||||
if (rc == false || // VirtualQuery error, end of allocation?
|
||||
minfo.State == MEM_FREE || // end of allocation, free memory follows
|
||||
(address)minfo.AllocationBase != allocation_base) // end of allocation, a new one starts
|
||||
{
|
||||
break;
|
||||
}
|
||||
const size_t region_size = minfo.RegionSize;
|
||||
mi->regions ++;
|
||||
if (minfo.State == MEM_COMMIT) {
|
||||
mi->committed_size += minfo.RegionSize;
|
||||
}
|
||||
allocation_end += region_size;
|
||||
}
|
||||
if (allocation_base != NULL && allocation_end > allocation_base) {
|
||||
mi->base = allocation_base;
|
||||
mi->size = allocation_end - allocation_base;
|
||||
rc = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef ASSERT
|
||||
if (rc) {
|
||||
assert(mi->size > 0 && mi->size >= mi->committed_size, "Sanity");
|
||||
assert(addr >= mi->base && addr < mi->base + mi->size, "Sanity");
|
||||
assert(mi->regions > 0, "Sanity");
|
||||
}
|
||||
#endif
|
||||
return rc;
|
||||
}
|
||||
|
||||
// Helper function for print_memory_mappings:
|
||||
// Given a MEMORY_BASIC_INFORMATION, containing information about a non-free region:
|
||||
// print out all regions in that allocation. If any of those regions
|
||||
// fall outside the given range [start, end), indicate that in the output.
|
||||
// Return the pointer to the end of the allocation.
|
||||
static address print_one_mapping(MEMORY_BASIC_INFORMATION* minfo, address start, address end, outputStream* st) {
|
||||
assert(start != NULL && end != NULL && end > start, "Sanity");
|
||||
assert(minfo->State != MEM_FREE, "Not inside an allocation.");
|
||||
address allocation_base = (address)minfo->AllocationBase;
|
||||
address last_region_end = NULL;
|
||||
st->print_cr("AllocationBase: " PTR_FORMAT ":", allocation_base);
|
||||
#define IS_IN(p) (p >= start && p < end)
|
||||
for(;;) {
|
||||
address region_start = (address)minfo->BaseAddress;
|
||||
address region_end = region_start + minfo->RegionSize;
|
||||
assert(region_end > region_start, "Sanity");
|
||||
if (region_end <= start) {
|
||||
st->print("<outside range> ");
|
||||
} else if (region_start >= end) {
|
||||
st->print("<outside range> ");
|
||||
} else if (!IS_IN(region_start) || !IS_IN(region_end - 1)) {
|
||||
st->print("<partly outside range> ");
|
||||
}
|
||||
st->print("[" PTR_FORMAT "-" PTR_FORMAT "), state=", p2i(region_start), p2i(region_end));
|
||||
switch (minfo->State) {
|
||||
case MEM_COMMIT: st->print("MEM_COMMIT"); break;
|
||||
case MEM_FREE: st->print("MEM_FREE"); break;
|
||||
case MEM_RESERVE: st->print("MEM_RESERVE"); break;
|
||||
default: st->print("%x?", (unsigned)minfo->State);
|
||||
}
|
||||
st->print(", prot=%x, type=", (unsigned)minfo->AllocationProtect);
|
||||
switch (minfo->Type) {
|
||||
case MEM_IMAGE: st->print("MEM_IMAGE"); break;
|
||||
case MEM_MAPPED: st->print("MEM_MAPPED"); break;
|
||||
case MEM_PRIVATE: st->print("MEM_PRIVATE"); break;
|
||||
default: st->print("%x?", (unsigned)minfo->State);
|
||||
}
|
||||
st->cr();
|
||||
bool rc = checkedVirtualQuery(region_end, minfo);
|
||||
if (rc == false || // VirtualQuery error, end of allocation?
|
||||
(minfo->State == MEM_FREE) || // end of allocation, free memory follows
|
||||
((address)minfo->AllocationBase != allocation_base) || // end of allocation, a new one starts
|
||||
(region_end > end)) // end of range to print.
|
||||
{
|
||||
return region_end;
|
||||
}
|
||||
}
|
||||
#undef IS_IN
|
||||
ShouldNotReachHere();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void os::print_memory_mappings(char* addr, size_t bytes, outputStream* st) {
|
||||
MEMORY_BASIC_INFORMATION minfo;
|
||||
address start = (address)addr;
|
||||
address end = start + bytes;
|
||||
address p = start;
|
||||
while (p < end) {
|
||||
// Probe for the next mapping.
|
||||
if (checkedVirtualQuery(p, &minfo)) {
|
||||
if (minfo.State != MEM_FREE) {
|
||||
// Found one. Print it out.
|
||||
address p2 = print_one_mapping(&minfo, start, end, st);
|
||||
assert(p2 > p, "Sanity");
|
||||
p = p2;
|
||||
} else {
|
||||
// Note: for free regions, most of MEMORY_BASIC_INFORMATION is undefined.
|
||||
// Only region dimensions are not: use those to jump to the end of
|
||||
// the free range.
|
||||
address region_start = (address)minfo.BaseAddress;
|
||||
address region_end = region_start + minfo.RegionSize;
|
||||
assert(p >= region_start && p < region_end, "Sanity");
|
||||
p = region_end;
|
||||
}
|
||||
} else {
|
||||
// advance probe pointer.
|
||||
p += os::vm_allocation_granularity();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -110,6 +110,20 @@ class win32 {
|
||||
struct _EXCEPTION_POINTERS* exceptionInfo,
|
||||
address pc, frame* fr);
|
||||
|
||||
struct mapping_info_t {
|
||||
// Start of allocation (AllocationBase)
|
||||
address base;
|
||||
// Total size of allocation over all regions
|
||||
size_t size;
|
||||
// Total committed size
|
||||
size_t committed_size;
|
||||
// Number of regions
|
||||
int regions;
|
||||
};
|
||||
// Given an address p which points into an area allocated with VirtualAlloc(),
|
||||
// return information about that area.
|
||||
static bool find_mapping(address p, mapping_info_t* mapping_info);
|
||||
|
||||
#ifndef _WIN64
|
||||
// A wrapper to install a structured exception handler for fast JNI accesors.
|
||||
static address fast_jni_accessor_wrapper(BasicType);
|
||||
|
@ -347,6 +347,9 @@ class os: AllStatic {
|
||||
static bool uncommit_memory(char* addr, size_t bytes);
|
||||
static bool release_memory(char* addr, size_t bytes);
|
||||
|
||||
// A diagnostic function to print memory mappings in the given range.
|
||||
static void print_memory_mappings(char* addr, size_t bytes, outputStream* st);
|
||||
|
||||
// Touch memory pages that cover the memory range from start to end (exclusive)
|
||||
// to make the OS back the memory range with actual memory.
|
||||
// Current implementation may not touch the last page if unaligned addresses
|
||||
|
@ -24,7 +24,10 @@
|
||||
#include "precompiled.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "runtime/os.hpp"
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
#include "utilities/macros.hpp"
|
||||
#include "utilities/ostream.hpp"
|
||||
#include "utilities/align.hpp"
|
||||
#include "unittest.hpp"
|
||||
|
||||
static size_t small_page_size() {
|
||||
@ -344,3 +347,240 @@ TEST_VM(os, jio_vsnprintf) {
|
||||
TEST_VM(os, jio_snprintf) {
|
||||
test_snprintf(jio_snprintf, false);
|
||||
}
|
||||
|
||||
// Test that os::release_memory() can deal with areas containing multiple mappings.
|
||||
#define PRINT_MAPPINGS(s) { tty->print_cr("%s", s); os::print_memory_mappings((char*)p, total_range_len, tty); }
|
||||
//#define PRINT_MAPPINGS
|
||||
|
||||
// Reserve an area consisting of multiple mappings
|
||||
// (from multiple calls to os::reserve_memory)
|
||||
static address reserve_multiple(int num_stripes, size_t stripe_len) {
|
||||
assert(is_aligned(stripe_len, os::vm_allocation_granularity()), "Sanity");
|
||||
size_t total_range_len = num_stripes * stripe_len;
|
||||
// Reserve a large contiguous area to get the address space...
|
||||
address p = (address)os::reserve_memory(total_range_len);
|
||||
EXPECT_NE(p, (address)NULL);
|
||||
// .. release it...
|
||||
EXPECT_TRUE(os::release_memory((char*)p, total_range_len));
|
||||
// ... re-reserve in the same spot multiple areas...
|
||||
for (int stripe = 0; stripe < num_stripes; stripe ++) {
|
||||
address q = p + (stripe * stripe_len);
|
||||
q = (address)os::attempt_reserve_memory_at((char*)q, stripe_len);
|
||||
EXPECT_NE(q, (address)NULL);
|
||||
// Commit, alternatingly with or without exec permission,
|
||||
// to prevent kernel from folding these mappings.
|
||||
const bool executable = stripe % 2 == 0;
|
||||
EXPECT_TRUE(os::commit_memory((char*)q, stripe_len, executable));
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
// Reserve an area with a single call to os::reserve_memory,
|
||||
// with multiple committed and uncommitted regions
|
||||
static address reserve_one_commit_multiple(int num_stripes, size_t stripe_len) {
|
||||
assert(is_aligned(stripe_len, os::vm_allocation_granularity()), "Sanity");
|
||||
size_t total_range_len = num_stripes * stripe_len;
|
||||
address p = (address)os::reserve_memory(total_range_len);
|
||||
EXPECT_NE(p, (address)NULL);
|
||||
for (int stripe = 0; stripe < num_stripes; stripe ++) {
|
||||
address q = p + (stripe * stripe_len);
|
||||
if (stripe % 2 == 0) {
|
||||
EXPECT_TRUE(os::commit_memory((char*)q, stripe_len, false));
|
||||
}
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
// Release a range allocated with reserve_multiple carefully, to not trip mapping
|
||||
// asserts on Windows in os::release_memory()
|
||||
static void carefully_release_multiple(address start, int num_stripes, size_t stripe_len) {
|
||||
for (int stripe = 0; stripe < num_stripes; stripe ++) {
|
||||
address q = start + (stripe * stripe_len);
|
||||
EXPECT_TRUE(os::release_memory((char*)q, stripe_len));
|
||||
}
|
||||
}
|
||||
struct NUMASwitcher {
|
||||
const bool _b;
|
||||
NUMASwitcher(bool v): _b(UseNUMAInterleaving) { UseNUMAInterleaving = v; }
|
||||
~NUMASwitcher() { UseNUMAInterleaving = _b; }
|
||||
};
|
||||
#endif
|
||||
|
||||
TEST_VM(os, release_multi_mappings) {
|
||||
// Test that we can release an area created with multiple reservation calls
|
||||
const size_t stripe_len = 4 * M;
|
||||
const int num_stripes = 4;
|
||||
const size_t total_range_len = stripe_len * num_stripes;
|
||||
|
||||
// reserve address space...
|
||||
address p = reserve_multiple(num_stripes, stripe_len);
|
||||
ASSERT_NE(p, (address)NULL);
|
||||
PRINT_MAPPINGS("A");
|
||||
|
||||
// .. release it...
|
||||
{
|
||||
// On Windows, use UseNUMAInterleaving=1 which makes
|
||||
// os::release_memory accept multi-map-ranges.
|
||||
// Otherwise we would assert (see below for death test).
|
||||
WINDOWS_ONLY(NUMASwitcher b(true);)
|
||||
ASSERT_TRUE(os::release_memory((char*)p, total_range_len));
|
||||
}
|
||||
PRINT_MAPPINGS("B");
|
||||
|
||||
// re-reserve it. This should work unless release failed.
|
||||
address p2 = (address)os::attempt_reserve_memory_at((char*)p, total_range_len);
|
||||
ASSERT_EQ(p2, p);
|
||||
PRINT_MAPPINGS("C");
|
||||
|
||||
ASSERT_TRUE(os::release_memory((char*)p, total_range_len));
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
// On Windows, test that we recognize bad ranges.
|
||||
// On debug this would assert. Test that too.
|
||||
// On other platforms, we are unable to recognize bad ranges.
|
||||
#ifdef ASSERT
|
||||
TEST_VM_ASSERT_MSG(os, release_bad_ranges, "bad release") {
|
||||
#else
|
||||
TEST_VM(os, release_bad_ranges) {
|
||||
#endif
|
||||
char* p = os::reserve_memory(4 * M);
|
||||
ASSERT_NE(p, (char*)NULL);
|
||||
// Release part of range
|
||||
ASSERT_FALSE(os::release_memory(p, M));
|
||||
// Release part of range
|
||||
ASSERT_FALSE(os::release_memory(p + M, M));
|
||||
// Release more than the range (explicitly switch off NUMA here
|
||||
// to make os::release_memory() test more strictly and to not
|
||||
// accidentally release neighbors)
|
||||
{
|
||||
NUMASwitcher b(false);
|
||||
ASSERT_FALSE(os::release_memory(p, M * 5));
|
||||
ASSERT_FALSE(os::release_memory(p - M, M * 5));
|
||||
ASSERT_FALSE(os::release_memory(p - M, M * 6));
|
||||
}
|
||||
|
||||
ASSERT_TRUE(os::release_memory(p, 4 * M)); // Release for real
|
||||
ASSERT_FALSE(os::release_memory(p, 4 * M)); // Again, should fail
|
||||
}
|
||||
#endif // _WIN32
|
||||
|
||||
TEST_VM(os, release_one_mapping_multi_commits) {
|
||||
// Test that we can release an area consisting of interleaved
|
||||
// committed and uncommitted regions:
|
||||
const size_t stripe_len = 4 * M;
|
||||
const int num_stripes = 4;
|
||||
const size_t total_range_len = stripe_len * num_stripes;
|
||||
|
||||
// reserve address space...
|
||||
address p = reserve_one_commit_multiple(num_stripes, stripe_len);
|
||||
ASSERT_NE(p, (address)NULL);
|
||||
PRINT_MAPPINGS("A");
|
||||
|
||||
// .. release it...
|
||||
ASSERT_TRUE(os::release_memory((char*)p, total_range_len));
|
||||
PRINT_MAPPINGS("B");
|
||||
|
||||
// re-reserve it. This should work unless release failed.
|
||||
address p2 = (address)os::attempt_reserve_memory_at((char*)p, total_range_len);
|
||||
ASSERT_EQ(p2, p);
|
||||
PRINT_MAPPINGS("C");
|
||||
|
||||
ASSERT_TRUE(os::release_memory((char*)p, total_range_len));
|
||||
PRINT_MAPPINGS("D");
|
||||
}
|
||||
|
||||
TEST_VM(os, show_mappings_1) {
|
||||
// Display an arbitrary large address range. Make this works, does not hang, etc.
|
||||
char dummy[16 * K]; // silent truncation is fine, we don't care.
|
||||
stringStream ss(dummy, sizeof(dummy));
|
||||
os::print_memory_mappings((char*)0x1000, LP64_ONLY(1024) NOT_LP64(3) * G, &ss);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
// Test os::win32::find_mapping
|
||||
TEST_VM(os, find_mapping_simple) {
|
||||
const size_t total_range_len = 4 * M;
|
||||
os::win32::mapping_info_t mapping_info;
|
||||
|
||||
// Some obvious negatives
|
||||
ASSERT_FALSE(os::win32::find_mapping((address)NULL, &mapping_info));
|
||||
ASSERT_FALSE(os::win32::find_mapping((address)4711, &mapping_info));
|
||||
|
||||
// A simple allocation
|
||||
{
|
||||
address p = (address)os::reserve_memory(total_range_len);
|
||||
ASSERT_NE(p, (address)NULL);
|
||||
PRINT_MAPPINGS("A");
|
||||
for (size_t offset = 0; offset < total_range_len; offset += 4711) {
|
||||
ASSERT_TRUE(os::win32::find_mapping(p + offset, &mapping_info));
|
||||
ASSERT_EQ(mapping_info.base, p);
|
||||
ASSERT_EQ(mapping_info.regions, 1);
|
||||
ASSERT_EQ(mapping_info.size, total_range_len);
|
||||
ASSERT_EQ(mapping_info.committed_size, 0);
|
||||
}
|
||||
// Test just outside the allocation
|
||||
if (os::win32::find_mapping(p - 1, &mapping_info)) {
|
||||
ASSERT_NE(mapping_info.base, p);
|
||||
}
|
||||
if (os::win32::find_mapping(p + total_range_len, &mapping_info)) {
|
||||
ASSERT_NE(mapping_info.base, p);
|
||||
}
|
||||
ASSERT_TRUE(os::release_memory((char*)p, total_range_len));
|
||||
PRINT_MAPPINGS("B");
|
||||
ASSERT_FALSE(os::win32::find_mapping(p, &mapping_info));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_VM(os, find_mapping_2) {
|
||||
// A more complex allocation, consisting of multiple regions.
|
||||
const size_t total_range_len = 4 * M;
|
||||
os::win32::mapping_info_t mapping_info;
|
||||
|
||||
const size_t stripe_len = total_range_len / 4;
|
||||
address p = reserve_one_commit_multiple(4, stripe_len);
|
||||
ASSERT_NE(p, (address)NULL);
|
||||
PRINT_MAPPINGS("A");
|
||||
for (size_t offset = 0; offset < total_range_len; offset += 4711) {
|
||||
ASSERT_TRUE(os::win32::find_mapping(p + offset, &mapping_info));
|
||||
ASSERT_EQ(mapping_info.base, p);
|
||||
ASSERT_EQ(mapping_info.regions, 4);
|
||||
ASSERT_EQ(mapping_info.size, total_range_len);
|
||||
ASSERT_EQ(mapping_info.committed_size, total_range_len / 2);
|
||||
}
|
||||
// Test just outside the allocation
|
||||
if (os::win32::find_mapping(p - 1, &mapping_info)) {
|
||||
ASSERT_NE(mapping_info.base, p);
|
||||
}
|
||||
if (os::win32::find_mapping(p + total_range_len, &mapping_info)) {
|
||||
ASSERT_NE(mapping_info.base, p);
|
||||
}
|
||||
ASSERT_TRUE(os::release_memory((char*)p, total_range_len));
|
||||
PRINT_MAPPINGS("B");
|
||||
ASSERT_FALSE(os::win32::find_mapping(p, &mapping_info));
|
||||
}
|
||||
|
||||
TEST_VM(os, find_mapping_3) {
|
||||
const size_t total_range_len = 4 * M;
|
||||
os::win32::mapping_info_t mapping_info;
|
||||
|
||||
// A more complex case, consisting of multiple allocations.
|
||||
{
|
||||
const size_t stripe_len = total_range_len / 4;
|
||||
address p = reserve_multiple(4, stripe_len);
|
||||
ASSERT_NE(p, (address)NULL);
|
||||
PRINT_MAPPINGS("E");
|
||||
for (int stripe = 0; stripe < 4; stripe ++) {
|
||||
ASSERT_TRUE(os::win32::find_mapping(p + (stripe * stripe_len), &mapping_info));
|
||||
ASSERT_EQ(mapping_info.base, p + (stripe * stripe_len));
|
||||
ASSERT_EQ(mapping_info.regions, 1);
|
||||
ASSERT_EQ(mapping_info.size, stripe_len);
|
||||
ASSERT_EQ(mapping_info.committed_size, stripe_len);
|
||||
}
|
||||
carefully_release_multiple(p, 4, stripe_len);
|
||||
PRINT_MAPPINGS("F");
|
||||
ASSERT_FALSE(os::win32::find_mapping(p, &mapping_info));
|
||||
}
|
||||
}
|
||||
#endif // _WIN32
|
||||
|
Loading…
Reference in New Issue
Block a user