# HG changeset patch # User dcubed # Date 1394474985 0 # Node ID cbdd11a54b82eb7731d16abbc6df3c9b4d42c78b # Parent 3f0dff7a9cf590ef3e5d7f2dcf6c8247b65c9d10 8013057: assert(_needs_gc || SafepointSynchronize::is_at_safepoint()) failed: only read at safepoint Summary: Detect mmap() commit failures in Linux and Solaris os::commit_memory() impls and call vm_exit_out_of_memory(). Add os::commit_memory_or_exit(). Also tidy up some NMT accounting and some mmap() return value checking. Reviewed-by: zgu, stefank, dholmes, dsamersoff diff -r 3f0dff7a9cf5 -r cbdd11a54b82 src/os/bsd/vm/os_bsd.cpp --- a/src/os/bsd/vm/os_bsd.cpp Mon Mar 12 13:12:07 2012 -0700 +++ b/src/os/bsd/vm/os_bsd.cpp Mon Mar 10 18:09:45 2014 +0000 @@ -2762,6 +2762,13 @@ } } +static void warn_fail_commit_memory(char* addr, size_t size, bool exec, + int err) { + warning("INFO: os::commit_memory(" PTR_FORMAT ", " SIZE_FORMAT + ", %d) failed; error='%s' (errno=%d)", addr, size, exec, + strerror(err), err); +} + // NOTE: Bsd kernel does not really reserve the pages for us. // All it does is to check if there are enough free pages // left at the time of mmap(). This could be a potential @@ -2770,12 +2777,22 @@ int prot = exec ? PROT_READ|PROT_WRITE|PROT_EXEC : PROT_READ|PROT_WRITE; #ifdef __OpenBSD__ // XXX: Work-around mmap/MAP_FIXED bug temporarily on OpenBSD - return ::mprotect(addr, size, prot) == 0; + if (::mprotect(addr, size, prot) == 0) { + return true; + } #else uintptr_t res = (uintptr_t) ::mmap(addr, size, prot, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0); - return res != (uintptr_t) MAP_FAILED; + if (res != (uintptr_t) MAP_FAILED) { + return true; + } #endif + + // Warn about any commit errors we see in non-product builds just + // in case mmap() doesn't work as described on the man page. + NOT_PRODUCT(warn_fail_commit_memory(addr, size, exec, errno);) + + return false; } #ifndef _ALLBSD_SOURCE @@ -2803,9 +2820,27 @@ } #endif + // alignment_hint is ignored on this OS return commit_memory(addr, size, exec); } +void os::commit_memory_or_exit(char* addr, size_t size, bool exec, + const char* mesg) { + assert(mesg != NULL, "mesg must be specified"); + if (!pd_commit_memory(addr, size, exec)) { + // add extra info in product mode for vm_exit_out_of_memory(): + PRODUCT_ONLY(warn_fail_commit_memory(addr, size, exec, errno);) + vm_exit_out_of_memory(size, mesg); + } +} + +void os::commit_memory_or_exit(char* addr, size_t size, + size_t alignment_hint, bool exec, + const char* mesg) { + // alignment_hint is ignored on this OS + pd_commit_memory_or_exit(addr, size, exec, mesg); +} + void os::realign_memory(char *addr, size_t bytes, size_t alignment_hint) { #ifndef _ALLBSD_SOURCE if (UseHugeTLBFS && alignment_hint > (size_t)vm_page_size()) { @@ -2970,7 +3005,7 @@ } bool os::create_stack_guard_pages(char* addr, size_t size) { - return os::commit_memory(addr, size); + return os::commit_memory(addr, size, !ExecMem); } // If this is a growable mapping, remove the guard pages entirely by @@ -4467,7 +4502,7 @@ if (!UseMembar) { address mem_serialize_page = (address) ::mmap(NULL, Bsd::page_size(), PROT_READ | PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); - guarantee( mem_serialize_page != NULL, "mmap Failed for memory serialize page"); + guarantee( mem_serialize_page != MAP_FAILED, "mmap Failed for memory serialize page"); os::set_memory_serialize_page( mem_serialize_page ); #ifndef PRODUCT diff -r 3f0dff7a9cf5 -r cbdd11a54b82 src/os/bsd/vm/perfMemory_bsd.cpp --- a/src/os/bsd/vm/perfMemory_bsd.cpp Mon Mar 12 13:12:07 2012 -0700 +++ b/src/os/bsd/vm/perfMemory_bsd.cpp Mon Mar 10 18:09:45 2014 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -59,7 +59,7 @@ } // commit memory - if (!os::commit_memory(mapAddress, size)) { + if (!os::commit_memory(mapAddress, size, !ExecMem)) { if (PrintMiscellaneous && Verbose) { warning("Could not commit PerfData memory\n"); } diff -r 3f0dff7a9cf5 -r cbdd11a54b82 src/os/linux/vm/os_linux.cpp --- a/src/os/linux/vm/os_linux.cpp Mon Mar 12 13:12:07 2012 -0700 +++ b/src/os/linux/vm/os_linux.cpp Mon Mar 10 18:09:45 2014 +0000 @@ -2508,11 +2508,49 @@ } } +static bool recoverable_mmap_error(int err) { + // See if the error is one we can let the caller handle. This + // list of errno values comes from JBS-6843484. I can't find a + // Linux man page that documents this specific set of errno + // values so while this list currently matches Solaris, it may + // change as we gain experience with this failure mode. + switch (err) { + case EBADF: + case EINVAL: + case ENOTSUP: + // let the caller deal with these errors + return true; + + default: + // Any remaining errors on this OS can cause our reserved mapping + // to be lost. That can cause confusion where different data + // structures think they have the same memory mapped. The worst + // scenario is if both the VM and a library think they have the + // same memory mapped. + return false; + } +} + +static void warn_fail_commit_memory(char* addr, size_t size, bool exec, + int err) { + warning("INFO: os::commit_memory(" PTR_FORMAT ", " SIZE_FORMAT + ", %d) failed; error='%s' (errno=%d)", addr, size, exec, + strerror(err), err); +} + +static void warn_fail_commit_memory(char* addr, size_t size, + size_t alignment_hint, bool exec, + int err) { + warning("INFO: os::commit_memory(" PTR_FORMAT ", " SIZE_FORMAT + ", " SIZE_FORMAT ", %d) failed; error='%s' (errno=%d)", addr, size, + alignment_hint, exec, strerror(err), err); +} + // NOTE: Linux kernel does not really reserve the pages for us. // All it does is to check if there are enough free pages // left at the time of mmap(). This could be a potential // problem. -bool os::commit_memory(char* addr, size_t size, bool exec) { +int os::Linux::commit_memory_impl(char* addr, size_t size, bool exec) { int prot = exec ? PROT_READ|PROT_WRITE|PROT_EXEC : PROT_READ|PROT_WRITE; uintptr_t res = (uintptr_t) ::mmap(addr, size, prot, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0); @@ -2520,9 +2558,32 @@ if (UseNUMAInterleaving) { numa_make_global(addr, size); } - return true; - } - return false; + return 0; + } + + int err = errno; // save errno from mmap() call above + + if (!recoverable_mmap_error(err)) { + warn_fail_commit_memory(addr, size, exec, err); + vm_exit_out_of_memory(size, "committing reserved memory."); + } + + return err; +} + +bool os::commit_memory(char* addr, size_t size, bool exec) { + return os::Linux::commit_memory_impl(addr, size, exec) == 0; +} + +void os::commit_memory_or_exit(char* addr, size_t size, bool exec, + const char* mesg) { + assert(mesg != NULL, "mesg must be specified"); + int err = os::Linux::commit_memory_impl(addr, size, exec); + if (err != 0) { + // the caller wants all commit errors to exit with the specified mesg: + warn_fail_commit_memory(addr, size, exec, err); + vm_exit_out_of_memory(size, mesg); + } } // Define MAP_HUGETLB here so we can build HotSpot on old systems. @@ -2535,8 +2596,9 @@ #define MADV_HUGEPAGE 14 #endif -bool os::commit_memory(char* addr, size_t size, size_t alignment_hint, - bool exec) { +int os::Linux::commit_memory_impl(char* addr, size_t size, + size_t alignment_hint, bool exec) { + int err; if (UseHugeTLBFS && alignment_hint > (size_t)vm_page_size()) { int prot = exec ? PROT_READ|PROT_WRITE|PROT_EXEC : PROT_READ|PROT_WRITE; uintptr_t res = @@ -2547,16 +2609,45 @@ if (UseNUMAInterleaving) { numa_make_global(addr, size); } - return true; + return 0; + } + + err = errno; // save errno from mmap() call above + + if (!recoverable_mmap_error(err)) { + // However, it is not clear that this loss of our reserved mapping + // happens with large pages on Linux or that we cannot recover + // from the loss. For now, we just issue a warning and we don't + // call vm_exit_out_of_memory(). This issue is being tracked by + // JBS-8007074. + warn_fail_commit_memory(addr, size, alignment_hint, exec, err); +// vm_exit_out_of_memory(size, "committing reserved memory."); } // Fall through and try to use small pages } - if (commit_memory(addr, size, exec)) { + err = os::Linux::commit_memory_impl(addr, size, exec); + if (err == 0) { realign_memory(addr, size, alignment_hint); - return true; - } - return false; + } + return err; +} + +bool os::commit_memory(char* addr, size_t size, size_t alignment_hint, + bool exec) { + return os::Linux::commit_memory_impl(addr, size, alignment_hint, exec) == 0; +} + +void os::commit_memory_or_exit(char* addr, size_t size, + size_t alignment_hint, bool exec, + const char* mesg) { + assert(mesg != NULL, "mesg must be specified"); + int err = os::Linux::commit_memory_impl(addr, size, alignment_hint, exec); + if (err != 0) { + // the caller wants all commit errors to exit with the specified mesg: + warn_fail_commit_memory(addr, size, alignment_hint, exec, err); + vm_exit_out_of_memory(size, mesg); + } } void os::realign_memory(char *addr, size_t bytes, size_t alignment_hint) { @@ -2574,7 +2665,7 @@ // small pages on top of the SHM segment. This method always works for small pages, so we // allow that in any case. if (alignment_hint <= (size_t)os::vm_page_size() || !UseSHM) { - commit_memory(addr, bytes, alignment_hint, false); + commit_memory(addr, bytes, alignment_hint, !ExecMem); } } @@ -2827,7 +2918,7 @@ ::munmap((void*)stack_extent, (uintptr_t)addr - stack_extent); } - return os::commit_memory(addr, size); + return os::commit_memory(addr, size, !ExecMem); } // If this is a growable mapping, remove the guard pages entirely by @@ -2948,7 +3039,7 @@ MAP_ANONYMOUS|MAP_PRIVATE|MAP_HUGETLB, -1, 0); - if (p != (void *) -1) { + if (p != MAP_FAILED) { // We don't know if this really is a huge page or not. FILE *fp = fopen("/proc/self/maps", "r"); if (fp) { @@ -4225,7 +4316,7 @@ if (!UseMembar) { address mem_serialize_page = (address) ::mmap(NULL, Linux::page_size(), PROT_READ | PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); - guarantee( mem_serialize_page != NULL, "mmap Failed for memory serialize page"); + guarantee( mem_serialize_page != MAP_FAILED, "mmap Failed for memory serialize page"); os::set_memory_serialize_page( mem_serialize_page ); #ifndef PRODUCT diff -r 3f0dff7a9cf5 -r cbdd11a54b82 src/os/linux/vm/os_linux.hpp --- a/src/os/linux/vm/os_linux.hpp Mon Mar 12 13:12:07 2012 -0700 +++ b/src/os/linux/vm/os_linux.hpp Mon Mar 10 18:09:45 2014 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -75,6 +75,10 @@ static julong physical_memory() { return _physical_memory; } static void initialize_system_info(); + static int commit_memory_impl(char* addr, size_t bytes, bool exec); + static int commit_memory_impl(char* addr, size_t bytes, + size_t alignment_hint, bool exec); + static void set_glibc_version(const char *s) { _glibc_version = s; } static void set_libpthread_version(const char *s) { _libpthread_version = s; } diff -r 3f0dff7a9cf5 -r cbdd11a54b82 src/os/linux/vm/perfMemory_linux.cpp --- a/src/os/linux/vm/perfMemory_linux.cpp Mon Mar 12 13:12:07 2012 -0700 +++ b/src/os/linux/vm/perfMemory_linux.cpp Mon Mar 10 18:09:45 2014 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -59,7 +59,7 @@ } // commit memory - if (!os::commit_memory(mapAddress, size)) { + if (!os::commit_memory(mapAddress, size, !ExecMem)) { if (PrintMiscellaneous && Verbose) { warning("Could not commit PerfData memory\n"); } diff -r 3f0dff7a9cf5 -r cbdd11a54b82 src/os/solaris/vm/os_solaris.cpp --- a/src/os/solaris/vm/os_solaris.cpp Mon Mar 12 13:12:07 2012 -0700 +++ b/src/os/solaris/vm/os_solaris.cpp Mon Mar 10 18:09:45 2014 +0000 @@ -2769,7 +2769,42 @@ return page_size; } -bool os::commit_memory(char* addr, size_t bytes, bool exec) { +static bool recoverable_mmap_error(int err) { + // See if the error is one we can let the caller handle. This + // list of errno values comes from the Solaris mmap(2) man page. + switch (err) { + case EBADF: + case EINVAL: + case ENOTSUP: + // let the caller deal with these errors + return true; + + default: + // Any remaining errors on this OS can cause our reserved mapping + // to be lost. That can cause confusion where different data + // structures think they have the same memory mapped. The worst + // scenario is if both the VM and a library think they have the + // same memory mapped. + return false; + } +} + +static void warn_fail_commit_memory(char* addr, size_t bytes, bool exec, + int err) { + warning("INFO: os::commit_memory(" PTR_FORMAT ", " SIZE_FORMAT + ", %d) failed; error='%s' (errno=%d)", addr, bytes, exec, + strerror(err), err); +} + +static void warn_fail_commit_memory(char* addr, size_t bytes, + size_t alignment_hint, bool exec, + int err) { + warning("INFO: os::commit_memory(" PTR_FORMAT ", " SIZE_FORMAT + ", " SIZE_FORMAT ", %d) failed; error='%s' (errno=%d)", addr, bytes, + alignment_hint, exec, strerror(err), err); +} + +int os::Solaris::commit_memory_impl(char* addr, size_t bytes, bool exec) { int prot = exec ? PROT_READ|PROT_WRITE|PROT_EXEC : PROT_READ|PROT_WRITE; size_t size = bytes; char *res = Solaris::mmap_chunk(addr, size, MAP_PRIVATE|MAP_FIXED, prot); @@ -2777,14 +2812,38 @@ if (UseNUMAInterleaving) { numa_make_global(addr, bytes); } - return true; - } - return false; -} - -bool os::commit_memory(char* addr, size_t bytes, size_t alignment_hint, - bool exec) { - if (commit_memory(addr, bytes, exec)) { + return 0; + } + + int err = errno; // save errno from mmap() call in mmap_chunk() + + if (!recoverable_mmap_error(err)) { + warn_fail_commit_memory(addr, bytes, exec, err); + vm_exit_out_of_memory(bytes, "committing reserved memory."); + } + + return err; +} + +bool os::commit_memory(char* addr, size_t bytes, bool exec) { + return Solaris::commit_memory_impl(addr, bytes, exec) == 0; +} + +void os::commit_memory_or_exit(char* addr, size_t bytes, bool exec, + const char* mesg) { + assert(mesg != NULL, "mesg must be specified"); + int err = os::Solaris::commit_memory_impl(addr, bytes, exec); + if (err != 0) { + // the caller wants all commit errors to exit with the specified mesg: + warn_fail_commit_memory(addr, bytes, exec, err); + vm_exit_out_of_memory(bytes, mesg); + } +} + +int os::Solaris::commit_memory_impl(char* addr, size_t bytes, + size_t alignment_hint, bool exec) { + int err = Solaris::commit_memory_impl(addr, bytes, exec); + if (err == 0) { if (UseMPSS && alignment_hint > (size_t)vm_page_size()) { // If the large page size has been set and the VM // is using large pages, use the large page size @@ -2806,9 +2865,25 @@ // Since this is a hint, ignore any failures. (void)Solaris::set_mpss_range(addr, bytes, page_size); } - return true; - } - return false; + } + return err; +} + +bool os::commit_memory(char* addr, size_t bytes, size_t alignment_hint, + bool exec) { + return Solaris::commit_memory_impl(addr, bytes, alignment_hint, exec) == 0; +} + +void os::commit_memory_or_exit(char* addr, size_t bytes, + size_t alignment_hint, bool exec, + const char* mesg) { + assert(mesg != NULL, "mesg must be specified"); + int err = os::Solaris::commit_memory_impl(addr, bytes, alignment_hint, exec); + if (err != 0) { + // the caller wants all commit errors to exit with the specified mesg: + warn_fail_commit_memory(addr, bytes, alignment_hint, exec, err); + vm_exit_out_of_memory(bytes, mesg); + } } // Uncommit the pages in a specified region. @@ -2820,7 +2895,7 @@ } bool os::create_stack_guard_pages(char* addr, size_t size) { - return os::commit_memory(addr, size); + return os::commit_memory(addr, size, !ExecMem); } bool os::remove_stack_guard_pages(char* addr, size_t size) { diff -r 3f0dff7a9cf5 -r cbdd11a54b82 src/os/solaris/vm/os_solaris.hpp --- a/src/os/solaris/vm/os_solaris.hpp Mon Mar 12 13:12:07 2012 -0700 +++ b/src/os/solaris/vm/os_solaris.hpp Mon Mar 10 18:09:45 2014 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -166,6 +166,9 @@ static int _dev_zero_fd; static int get_dev_zero_fd() { return _dev_zero_fd; } static void set_dev_zero_fd(int fd) { _dev_zero_fd = fd; } + static int commit_memory_impl(char* addr, size_t bytes, bool exec); + static int commit_memory_impl(char* addr, size_t bytes, + size_t alignment_hint, bool exec); static char* mmap_chunk(char *addr, size_t size, int flags, int prot); static char* anon_mmap(char* requested_addr, size_t bytes, size_t alignment_hint, bool fixed); static bool mpss_sanity_check(bool warn, size_t * page_size); diff -r 3f0dff7a9cf5 -r cbdd11a54b82 src/os/solaris/vm/perfMemory_solaris.cpp --- a/src/os/solaris/vm/perfMemory_solaris.cpp Mon Mar 12 13:12:07 2012 -0700 +++ b/src/os/solaris/vm/perfMemory_solaris.cpp Mon Mar 10 18:09:45 2014 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -61,7 +61,7 @@ } // commit memory - if (!os::commit_memory(mapAddress, size)) { + if (!os::commit_memory(mapAddress, size, !ExecMem)) { if (PrintMiscellaneous && Verbose) { warning("Could not commit PerfData memory\n"); } diff -r 3f0dff7a9cf5 -r cbdd11a54b82 src/os/windows/vm/os_windows.cpp --- a/src/os/windows/vm/os_windows.cpp Mon Mar 12 13:12:07 2012 -0700 +++ b/src/os/windows/vm/os_windows.cpp Mon Mar 10 18:09:45 2014 +0000 @@ -2410,7 +2410,7 @@ addr = (address)((uintptr_t)addr & (~((uintptr_t)os::vm_page_size() - (uintptr_t)1))); os::commit_memory((char *)addr, thread->stack_base() - addr, - false ); + !ExecMem); return EXCEPTION_CONTINUE_EXECUTION; } else @@ -3067,6 +3067,15 @@ void os::print_statistics() { } +static void warn_fail_commit_memory(char* addr, size_t bytes, bool exec) { + int err = os::get_last_error(); + char buf[256]; + size_t buf_len = os::lasterror(buf, sizeof(buf)); + warning("INFO: os::commit_memory(" PTR_FORMAT ", " SIZE_FORMAT + ", %d) failed; error='%s' (DOS error/errno=%d)", addr, bytes, + exec, buf_len != 0 ? buf : "", err); +} + bool os::commit_memory(char* addr, size_t bytes, bool exec) { if (bytes == 0) { // Don't bother the OS with noops. @@ -3081,11 +3090,17 @@ // is always within a reserve covered by a single VirtualAlloc // in that case we can just do a single commit for the requested size if (!UseNUMAInterleaving) { - if (VirtualAlloc(addr, bytes, MEM_COMMIT, PAGE_READWRITE) == NULL) return false; + if (VirtualAlloc(addr, bytes, MEM_COMMIT, PAGE_READWRITE) == NULL) { + NOT_PRODUCT(warn_fail_commit_memory(addr, bytes, exec);) + return false; + } if (exec) { DWORD oldprot; // Windows doc says to use VirtualProtect to get execute permissions - if (!VirtualProtect(addr, bytes, PAGE_EXECUTE_READWRITE, &oldprot)) return false; + if (!VirtualProtect(addr, bytes, PAGE_EXECUTE_READWRITE, &oldprot)) { + NOT_PRODUCT(warn_fail_commit_memory(addr, bytes, exec);) + return false; + } } return true; } else { @@ -3100,12 +3115,20 @@ MEMORY_BASIC_INFORMATION alloc_info; VirtualQuery(next_alloc_addr, &alloc_info, sizeof(alloc_info)); size_t bytes_to_rq = MIN2(bytes_remaining, (size_t)alloc_info.RegionSize); - if (VirtualAlloc(next_alloc_addr, bytes_to_rq, MEM_COMMIT, PAGE_READWRITE) == NULL) + if (VirtualAlloc(next_alloc_addr, bytes_to_rq, MEM_COMMIT, + PAGE_READWRITE) == NULL) { + NOT_PRODUCT(warn_fail_commit_memory(next_alloc_addr, bytes_to_rq, + exec);) return false; + } if (exec) { DWORD oldprot; - if (!VirtualProtect(next_alloc_addr, bytes_to_rq, PAGE_EXECUTE_READWRITE, &oldprot)) + if (!VirtualProtect(next_alloc_addr, bytes_to_rq, + PAGE_EXECUTE_READWRITE, &oldprot)) { + NOT_PRODUCT(warn_fail_commit_memory(next_alloc_addr, bytes_to_rq, + exec);) return false; + } } bytes_remaining -= bytes_to_rq; next_alloc_addr += bytes_to_rq; @@ -3117,9 +3140,26 @@ bool os::commit_memory(char* addr, size_t size, size_t alignment_hint, bool exec) { + // alignment_hint is ignored on this OS return commit_memory(addr, size, exec); } +void os::commit_memory_or_exit(char* addr, size_t size, bool exec, + const char* mesg) { + assert(mesg != NULL, "mesg must be specified"); + if (!pd_commit_memory(addr, size, exec)) { + warn_fail_commit_memory(addr, size, exec); + vm_exit_out_of_memory(size, mesg); + } +} + +void os::commit_memory_or_exit(char* addr, size_t size, + size_t alignment_hint, bool exec, + const char* mesg) { + // alignment_hint is ignored on this OS + pd_commit_memory_or_exit(addr, size, exec, mesg); +} + bool os::uncommit_memory(char* addr, size_t bytes) { if (bytes == 0) { // Don't bother the OS with noops. @@ -3135,7 +3175,7 @@ } bool os::create_stack_guard_pages(char* addr, size_t size) { - return os::commit_memory(addr, size); + return os::commit_memory(addr, size, !ExecMem); } bool os::remove_stack_guard_pages(char* addr, size_t size) { @@ -3159,8 +3199,9 @@ // Strange enough, but on Win32 one can change protection only for committed // memory, not a big deal anyway, as bytes less or equal than 64K - if (!is_committed && !commit_memory(addr, bytes, prot == MEM_PROT_RWX)) { - fatal("cannot commit protection page"); + if (!is_committed) { + commit_memory_or_exit(addr, bytes, prot == MEM_PROT_RWX, + "cannot commit protection page"); } // One cannot use os::guard_memory() here, as on Win32 guard page // have different (one-shot) semantics, from MSDN on PAGE_GUARD: diff -r 3f0dff7a9cf5 -r cbdd11a54b82 src/os/windows/vm/perfMemory_windows.cpp --- a/src/os/windows/vm/perfMemory_windows.cpp Mon Mar 12 13:12:07 2012 -0700 +++ b/src/os/windows/vm/perfMemory_windows.cpp Mon Mar 10 18:09:45 2014 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -57,7 +57,7 @@ } // commit memory - if (!os::commit_memory(mapAddress, size)) { + if (!os::commit_memory(mapAddress, size, !ExecMem)) { if (PrintMiscellaneous && Verbose) { warning("Could not commit PerfData memory\n"); } diff -r 3f0dff7a9cf5 -r cbdd11a54b82 src/share/vm/gc_implementation/parallelScavenge/cardTableExtension.cpp --- a/src/share/vm/gc_implementation/parallelScavenge/cardTableExtension.cpp Mon Mar 12 13:12:07 2012 -0700 +++ b/src/share/vm/gc_implementation/parallelScavenge/cardTableExtension.cpp Mon Mar 10 18:09:45 2014 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -649,11 +649,9 @@ if(new_start_aligned < new_end_for_commit) { MemRegion new_committed = MemRegion(new_start_aligned, new_end_for_commit); - if (!os::commit_memory((char*)new_committed.start(), - new_committed.byte_size())) { - vm_exit_out_of_memory(new_committed.byte_size(), - "card table expansion"); - } + os::commit_memory_or_exit((char*)new_committed.start(), + new_committed.byte_size(), !ExecMem, + "card table expansion"); } result = true; } else if (new_start_aligned > cur_committed.start()) { diff -r 3f0dff7a9cf5 -r cbdd11a54b82 src/share/vm/gc_implementation/parallelScavenge/psVirtualspace.cpp --- a/src/share/vm/gc_implementation/parallelScavenge/psVirtualspace.cpp Mon Mar 12 13:12:07 2012 -0700 +++ b/src/share/vm/gc_implementation/parallelScavenge/psVirtualspace.cpp Mon Mar 10 18:09:45 2014 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -101,7 +101,8 @@ } char* const base_addr = committed_high_addr(); - bool result = special() || os::commit_memory(base_addr, bytes, alignment()); + bool result = special() || + os::commit_memory(base_addr, bytes, alignment(), !ExecMem); if (result) { _committed_high_addr += bytes; } @@ -154,7 +155,7 @@ if (tmp_bytes > 0) { char* const commit_base = committed_high_addr(); if (other_space->special() || - os::commit_memory(commit_base, tmp_bytes, alignment())) { + os::commit_memory(commit_base, tmp_bytes, alignment(), !ExecMem)) { // Reduce the reserved region in the other space. other_space->set_reserved(other_space->reserved_low_addr() + tmp_bytes, other_space->reserved_high_addr(), @@ -269,7 +270,8 @@ } char* const base_addr = committed_low_addr() - bytes; - bool result = special() || os::commit_memory(base_addr, bytes, alignment()); + bool result = special() || + os::commit_memory(base_addr, bytes, alignment(), !ExecMem); if (result) { _committed_low_addr -= bytes; } @@ -322,7 +324,7 @@ if (tmp_bytes > 0) { char* const commit_base = committed_low_addr() - tmp_bytes; if (other_space->special() || - os::commit_memory(commit_base, tmp_bytes, alignment())) { + os::commit_memory(commit_base, tmp_bytes, alignment(), !ExecMem)) { // Reduce the reserved region in the other space. other_space->set_reserved(other_space->reserved_low_addr(), other_space->reserved_high_addr() - tmp_bytes, diff -r 3f0dff7a9cf5 -r cbdd11a54b82 src/share/vm/memory/cardTableModRefBS.cpp --- a/src/share/vm/memory/cardTableModRefBS.cpp Mon Mar 12 13:12:07 2012 -0700 +++ b/src/share/vm/memory/cardTableModRefBS.cpp Mon Mar 10 18:09:45 2014 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -109,10 +109,8 @@ jbyte* guard_card = &_byte_map[_guard_index]; uintptr_t guard_page = align_size_down((uintptr_t)guard_card, _page_size); _guard_region = MemRegion((HeapWord*)guard_page, _page_size); - if (!os::commit_memory((char*)guard_page, _page_size, _page_size)) { - // Do better than this for Merlin - vm_exit_out_of_memory(_page_size, "card table last card"); - } + os::commit_memory_or_exit((char*)guard_page, _page_size, _page_size, + !ExecMem, "card table last card"); *guard_card = last_card; _lowest_non_clean = @@ -283,12 +281,9 @@ MemRegion(cur_committed.end(), new_end_for_commit); assert(!new_committed.is_empty(), "Region should not be empty here"); - if (!os::commit_memory((char*)new_committed.start(), - new_committed.byte_size(), _page_size)) { - // Do better than this for Merlin - vm_exit_out_of_memory(new_committed.byte_size(), - "card table expansion"); - } + os::commit_memory_or_exit((char*)new_committed.start(), + new_committed.byte_size(), _page_size, + !ExecMem, "card table expansion"); // Use new_end_aligned (as opposed to new_end_for_commit) because // the cur_committed region may include the guard region. } else if (new_end_aligned < cur_committed.end()) { diff -r 3f0dff7a9cf5 -r cbdd11a54b82 src/share/vm/runtime/os.cpp --- a/src/share/vm/runtime/os.cpp Mon Mar 12 13:12:07 2012 -0700 +++ b/src/share/vm/runtime/os.cpp Mon Mar 10 18:09:45 2014 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff -r 3f0dff7a9cf5 -r cbdd11a54b82 src/share/vm/runtime/os.hpp --- a/src/share/vm/runtime/os.hpp Mon Mar 12 13:12:07 2012 -0700 +++ b/src/share/vm/runtime/os.hpp Mon Mar 10 18:09:45 2014 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -78,6 +78,10 @@ CriticalPriority = 11 // Critical thread priority }; +// Executable parameter flag for os::commit_memory() and +// os::commit_memory_or_exit(). +const bool ExecMem = true; + // Typedef for structured exception handling support typedef void (*java_call_t)(JavaValue* value, methodHandle* method, JavaCallArguments* args, Thread* thread); @@ -237,10 +241,16 @@ static char* attempt_reserve_memory_at(size_t bytes, char* addr); static void split_reserved_memory(char *base, size_t size, size_t split, bool realloc); - static bool commit_memory(char* addr, size_t bytes, - bool executable = false); + static bool commit_memory(char* addr, size_t bytes, bool executable); static bool commit_memory(char* addr, size_t size, size_t alignment_hint, - bool executable = false); + bool executable); + // Same as commit_memory() that either succeeds or calls + // vm_exit_out_of_memory() with the specified mesg. + static void commit_memory_or_exit(char* addr, size_t bytes, + bool executable, const char* mesg); + static void commit_memory_or_exit(char* addr, size_t size, + size_t alignment_hint, + bool executable, const char* mesg); static bool uncommit_memory(char* addr, size_t bytes); static bool release_memory(char* addr, size_t bytes); diff -r 3f0dff7a9cf5 -r cbdd11a54b82 src/share/vm/runtime/virtualspace.cpp --- a/src/share/vm/runtime/virtualspace.cpp Mon Mar 12 13:12:07 2012 -0700 +++ b/src/share/vm/runtime/virtualspace.cpp Mon Mar 10 18:09:45 2014 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -704,11 +704,13 @@ lower_high() + lower_needs <= lower_high_boundary(), "must not expand beyond region"); if (!os::commit_memory(lower_high(), lower_needs, _executable)) { - debug_only(warning("os::commit_memory failed")); + debug_only(warning("INFO: os::commit_memory(" PTR_FORMAT + ", lower_needs=" SIZE_FORMAT ", %d) failed", + lower_high(), lower_needs, _executable);) return false; } else { _lower_high += lower_needs; - } + } } if (middle_needs > 0) { assert(lower_high_boundary() <= middle_high() && @@ -716,7 +718,10 @@ "must not expand beyond region"); if (!os::commit_memory(middle_high(), middle_needs, middle_alignment(), _executable)) { - debug_only(warning("os::commit_memory failed")); + debug_only(warning("INFO: os::commit_memory(" PTR_FORMAT + ", middle_needs=" SIZE_FORMAT ", " SIZE_FORMAT + ", %d) failed", middle_high(), middle_needs, + middle_alignment(), _executable);) return false; } _middle_high += middle_needs; @@ -726,7 +731,9 @@ upper_high() + upper_needs <= upper_high_boundary(), "must not expand beyond region"); if (!os::commit_memory(upper_high(), upper_needs, _executable)) { - debug_only(warning("os::commit_memory failed")); + debug_only(warning("INFO: os::commit_memory(" PTR_FORMAT + ", upper_needs=" SIZE_FORMAT ", %d) failed", + upper_high(), upper_needs, _executable);) return false; } else { _upper_high += upper_needs;