# HG changeset patch # User nloodin # Date 1371658432 -7200 # Node ID 726d2d4913fc773d878818fb21b36b4d2d93b0af # Parent f9709e27a87644e554ede4374172a41f5716f874# Parent cd54c7e92908ea618e03c8187d747b2399630475 Merge diff -r f9709e27a876 -r 726d2d4913fc make/linux/makefiles/gcc.make --- a/make/linux/makefiles/gcc.make Fri Jun 14 07:27:22 2013 -0700 +++ b/make/linux/makefiles/gcc.make Wed Jun 19 18:13:52 2013 +0200 @@ -214,7 +214,7 @@ WARNINGS_ARE_ERRORS += -Wno-return-type -Wno-empty-body endif -WARNING_FLAGS = -Wpointer-arith -Wsign-compare -Wundef -Wunused-function +WARNING_FLAGS = -Wpointer-arith -Wsign-compare -Wundef -Wunused-function -Wunused-value ifeq ($(USE_CLANG),) # Since GCC 4.3, -Wconversion has changed its meanings to warn these implicit diff -r f9709e27a876 -r 726d2d4913fc src/cpu/x86/vm/globals_x86.hpp --- a/src/cpu/x86/vm/globals_x86.hpp Fri Jun 14 07:27:22 2013 -0700 +++ b/src/cpu/x86/vm/globals_x86.hpp Wed Jun 19 18:13:52 2013 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2012, 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 @@ -55,7 +55,7 @@ define_pd_global(intx, InlineFrequencyCount, 100); define_pd_global(intx, InlineSmallCode, 1000); -define_pd_global(intx, StackYellowPages, 2); +define_pd_global(intx, StackYellowPages, NOT_WINDOWS(2) WINDOWS_ONLY(3)); define_pd_global(intx, StackRedPages, 1); #ifdef AMD64 // Very large C++ stack frames using solaris-amd64 optimized builds diff -r f9709e27a876 -r 726d2d4913fc src/cpu/x86/vm/stubGenerator_x86_32.cpp --- a/src/cpu/x86/vm/stubGenerator_x86_32.cpp Fri Jun 14 07:27:22 2013 -0700 +++ b/src/cpu/x86/vm/stubGenerator_x86_32.cpp Wed Jun 19 18:13:52 2013 +0200 @@ -83,7 +83,7 @@ private: #ifdef PRODUCT -#define inc_counter_np(counter) (0) +#define inc_counter_np(counter) ((void)0) #else void inc_counter_np_(int& counter) { __ incrementl(ExternalAddress((address)&counter)); diff -r f9709e27a876 -r 726d2d4913fc src/cpu/x86/vm/stubGenerator_x86_64.cpp --- a/src/cpu/x86/vm/stubGenerator_x86_64.cpp Fri Jun 14 07:27:22 2013 -0700 +++ b/src/cpu/x86/vm/stubGenerator_x86_64.cpp Wed Jun 19 18:13:52 2013 +0200 @@ -81,7 +81,7 @@ private: #ifdef PRODUCT -#define inc_counter_np(counter) (0) +#define inc_counter_np(counter) ((void)0) #else void inc_counter_np_(int& counter) { // This can destroy rscratch1 if counter is far from the code cache diff -r f9709e27a876 -r 726d2d4913fc src/os/bsd/dtrace/jvm_dtrace.c --- a/src/os/bsd/dtrace/jvm_dtrace.c Fri Jun 14 07:27:22 2013 -0700 +++ b/src/os/bsd/dtrace/jvm_dtrace.c Wed Jun 19 18:13:52 2013 +0200 @@ -122,9 +122,7 @@ } static int file_close(int fd) { - int ret; - RESTARTABLE(close(fd), ret); - return ret; + return close(fd); } static int file_read(int fd, char* buf, int len) { diff -r f9709e27a876 -r 726d2d4913fc src/os/bsd/vm/attachListener_bsd.cpp --- a/src/os/bsd/vm/attachListener_bsd.cpp Fri Jun 14 07:27:22 2013 -0700 +++ b/src/os/bsd/vm/attachListener_bsd.cpp Wed Jun 19 18:13:52 2013 +0200 @@ -199,7 +199,7 @@ ::unlink(initial_path); int res = ::bind(listener, (struct sockaddr*)&addr, sizeof(addr)); if (res == -1) { - RESTARTABLE(::close(listener), res); + ::close(listener); return -1; } @@ -217,7 +217,7 @@ } } if (res == -1) { - RESTARTABLE(::close(listener), res); + ::close(listener); ::unlink(initial_path); return -1; } @@ -345,24 +345,21 @@ uid_t puid; gid_t pgid; if (::getpeereid(s, &puid, &pgid) != 0) { - int res; - RESTARTABLE(::close(s), res); + ::close(s); continue; } uid_t euid = geteuid(); gid_t egid = getegid(); if (puid != euid || pgid != egid) { - int res; - RESTARTABLE(::close(s), res); + ::close(s); continue; } // peer credential look okay so we read the request BsdAttachOperation* op = read_request(s); if (op == NULL) { - int res; - RESTARTABLE(::close(s), res); + ::close(s); continue; } else { return op; @@ -413,7 +410,7 @@ } // done - RESTARTABLE(::close(this->socket()), rc); + ::close(this->socket()); // were we externally suspended while we were waiting? thread->check_and_wait_while_suspended(); diff -r f9709e27a876 -r 726d2d4913fc src/os/bsd/vm/os_bsd.cpp --- a/src/os/bsd/vm/os_bsd.cpp Fri Jun 14 07:27:22 2013 -0700 +++ b/src/os/bsd/vm/os_bsd.cpp Wed Jun 19 18:13:52 2013 +0200 @@ -2074,6 +2074,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 @@ -2082,18 +2089,45 @@ 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; } - bool os::pd_commit_memory(char* addr, size_t size, size_t alignment_hint, bool exec) { - return commit_memory(addr, size, exec); + // alignment_hint is ignored on this OS + return pd_commit_memory(addr, size, exec); +} + +void os::pd_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, OOM_MMAP_ERROR, mesg); + } +} + +void os::pd_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::pd_realign_memory(char *addr, size_t bytes, size_t alignment_hint) { @@ -2148,7 +2182,7 @@ } bool os::pd_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 @@ -2320,21 +2354,20 @@ } // The memory is committed - address pc = CALLER_PC; - MemTracker::record_virtual_memory_reserve((address)addr, bytes, pc); - MemTracker::record_virtual_memory_commit((address)addr, bytes, pc); + MemTracker::record_virtual_memory_reserve_and_commit((address)addr, bytes, mtNone, CALLER_PC); return addr; } bool os::release_memory_special(char* base, size_t bytes) { + MemTracker::Tracker tkr = MemTracker::get_virtual_memory_release_tracker(); // detaching the SHM segment will also delete it, see reserve_memory_special() int rslt = shmdt(base); if (rslt == 0) { - MemTracker::record_virtual_memory_uncommit((address)base, bytes); - MemTracker::record_virtual_memory_release((address)base, bytes); + tkr.record((address)base, bytes); return true; } else { + tkr.discard(); return false; } @@ -3512,7 +3545,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 f9709e27a876 -r 726d2d4913fc src/os/bsd/vm/os_bsd.inline.hpp --- a/src/os/bsd/vm/os_bsd.inline.hpp Fri Jun 14 07:27:22 2013 -0700 +++ b/src/os/bsd/vm/os_bsd.inline.hpp Wed Jun 19 18:13:52 2013 +0200 @@ -178,11 +178,11 @@ } inline int os::close(int fd) { - RESTARTABLE_RETURN_INT(::close(fd)); + return ::close(fd); } inline int os::socket_close(int fd) { - RESTARTABLE_RETURN_INT(::close(fd)); + return ::close(fd); } inline int os::socket(int domain, int type, int protocol) { diff -r f9709e27a876 -r 726d2d4913fc src/os/bsd/vm/perfMemory_bsd.cpp --- a/src/os/bsd/vm/perfMemory_bsd.cpp Fri Jun 14 07:27:22 2013 -0700 +++ b/src/os/bsd/vm/perfMemory_bsd.cpp Wed Jun 19 18:13:52 2013 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2012, 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 @@ -60,7 +60,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"); } @@ -120,7 +120,7 @@ addr += result; } - RESTARTABLE(::close(fd), result); + result = ::close(fd); if (PrintMiscellaneous && Verbose) { if (result == OS_ERR) { warning("Could not close %s: %s\n", destfile, strerror(errno)); @@ -632,7 +632,7 @@ if (PrintMiscellaneous && Verbose) { warning("could not set shared memory file size: %s\n", strerror(errno)); } - RESTARTABLE(::close(fd), result); + ::close(fd); return -1; } @@ -656,7 +656,7 @@ if (result != -1) { return fd; } else { - RESTARTABLE(::close(fd), result); + ::close(fd); return -1; } } @@ -734,9 +734,7 @@ mapAddress = (char*)::mmap((char*)0, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); - // attempt to close the file - restart it if it was interrupted, - // but ignore other failures - RESTARTABLE(::close(fd), result); + result = ::close(fd); assert(result != OS_ERR, "could not close file"); if (mapAddress == MAP_FAILED) { @@ -755,8 +753,7 @@ (void)::memset((void*) mapAddress, 0, size); // it does not go through os api, the operation has to record from here - MemTracker::record_virtual_memory_reserve((address)mapAddress, size, CURRENT_PC); - MemTracker::record_virtual_memory_type((address)mapAddress, mtInternal); + MemTracker::record_virtual_memory_reserve((address)mapAddress, size, mtInternal, CURRENT_PC); return mapAddress; } @@ -909,7 +906,7 @@ // attempt to close the file - restart if it gets interrupted, // but ignore other failures - RESTARTABLE(::close(fd), result); + result = ::close(fd); assert(result != OS_ERR, "could not close file"); if (mapAddress == MAP_FAILED) { @@ -921,8 +918,7 @@ } // it does not go through os api, the operation has to record from here - MemTracker::record_virtual_memory_reserve((address)mapAddress, size, CURRENT_PC); - MemTracker::record_virtual_memory_type((address)mapAddress, mtInternal); + MemTracker::record_virtual_memory_reserve((address)mapAddress, size, mtInternal, CURRENT_PC); *addr = mapAddress; *sizep = size; diff -r f9709e27a876 -r 726d2d4913fc src/os/linux/vm/attachListener_linux.cpp --- a/src/os/linux/vm/attachListener_linux.cpp Fri Jun 14 07:27:22 2013 -0700 +++ b/src/os/linux/vm/attachListener_linux.cpp Wed Jun 19 18:13:52 2013 +0200 @@ -199,7 +199,7 @@ ::unlink(initial_path); int res = ::bind(listener, (struct sockaddr*)&addr, sizeof(addr)); if (res == -1) { - RESTARTABLE(::close(listener), res); + ::close(listener); return -1; } @@ -212,7 +212,7 @@ } } if (res == -1) { - RESTARTABLE(::close(listener), res); + ::close(listener); ::unlink(initial_path); return -1; } @@ -340,24 +340,21 @@ struct ucred cred_info; socklen_t optlen = sizeof(cred_info); if (::getsockopt(s, SOL_SOCKET, SO_PEERCRED, (void*)&cred_info, &optlen) == -1) { - int res; - RESTARTABLE(::close(s), res); + ::close(s); continue; } uid_t euid = geteuid(); gid_t egid = getegid(); if (cred_info.uid != euid || cred_info.gid != egid) { - int res; - RESTARTABLE(::close(s), res); + ::close(s); continue; } // peer credential look okay so we read the request LinuxAttachOperation* op = read_request(s); if (op == NULL) { - int res; - RESTARTABLE(::close(s), res); + ::close(s); continue; } else { return op; @@ -408,7 +405,7 @@ } // done - RESTARTABLE(::close(this->socket()), rc); + ::close(this->socket()); // were we externally suspended while we were waiting? thread->check_and_wait_while_suspended(); diff -r f9709e27a876 -r 726d2d4913fc src/os/linux/vm/os_linux.cpp --- a/src/os/linux/vm/os_linux.cpp Fri Jun 14 07:27:22 2013 -0700 +++ b/src/os/linux/vm/os_linux.cpp Wed Jun 19 18:13:52 2013 +0200 @@ -2612,11 +2612,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::pd_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); @@ -2624,9 +2662,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, OOM_MMAP_ERROR, "committing reserved memory."); + } + + return err; +} + +bool os::pd_commit_memory(char* addr, size_t size, bool exec) { + return os::Linux::commit_memory_impl(addr, size, exec) == 0; +} + +void os::pd_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, OOM_MMAP_ERROR, mesg); + } } // Define MAP_HUGETLB here so we can build HotSpot on old systems. @@ -2639,8 +2700,9 @@ #define MADV_HUGEPAGE 14 #endif -bool os::pd_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 = @@ -2651,16 +2713,46 @@ 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, OOM_MMAP_ERROR, +// "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::pd_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::pd_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, OOM_MMAP_ERROR, mesg); + } } void os::pd_realign_memory(char *addr, size_t bytes, size_t alignment_hint) { @@ -2678,7 +2770,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); } } @@ -2931,7 +3023,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 @@ -3053,7 +3145,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) { @@ -3271,22 +3363,21 @@ } // The memory is committed - address pc = CALLER_PC; - MemTracker::record_virtual_memory_reserve((address)addr, bytes, pc); - MemTracker::record_virtual_memory_commit((address)addr, bytes, pc); + MemTracker::record_virtual_memory_reserve_and_commit((address)addr, bytes, mtNone, CALLER_PC); return addr; } bool os::release_memory_special(char* base, size_t bytes) { + MemTracker::Tracker tkr = MemTracker::get_virtual_memory_release_tracker(); // detaching the SHM segment will also delete it, see reserve_memory_special() int rslt = shmdt(base); if (rslt == 0) { - MemTracker::record_virtual_memory_uncommit((address)base, bytes); - MemTracker::record_virtual_memory_release((address)base, bytes); + tkr.record((address)base, bytes); return true; } else { - return false; + tkr.discard(); + return false; } } @@ -4393,7 +4484,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 f9709e27a876 -r 726d2d4913fc src/os/linux/vm/os_linux.hpp --- a/src/os/linux/vm/os_linux.hpp Fri Jun 14 07:27:22 2013 -0700 +++ b/src/os/linux/vm/os_linux.hpp Wed Jun 19 18:13:52 2013 +0200 @@ -76,6 +76,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 f9709e27a876 -r 726d2d4913fc src/os/linux/vm/perfMemory_linux.cpp --- a/src/os/linux/vm/perfMemory_linux.cpp Fri Jun 14 07:27:22 2013 -0700 +++ b/src/os/linux/vm/perfMemory_linux.cpp Wed Jun 19 18:13:52 2013 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2012, 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 @@ -60,7 +60,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"); } @@ -120,7 +120,7 @@ addr += result; } - RESTARTABLE(::close(fd), result); + result = ::close(fd); if (PrintMiscellaneous && Verbose) { if (result == OS_ERR) { warning("Could not close %s: %s\n", destfile, strerror(errno)); @@ -632,7 +632,7 @@ if (PrintMiscellaneous && Verbose) { warning("could not set shared memory file size: %s\n", strerror(errno)); } - RESTARTABLE(::close(fd), result); + ::close(fd); return -1; } @@ -656,7 +656,7 @@ if (result != -1) { return fd; } else { - RESTARTABLE(::close(fd), result); + ::close(fd); return -1; } } @@ -734,9 +734,7 @@ mapAddress = (char*)::mmap((char*)0, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); - // attempt to close the file - restart it if it was interrupted, - // but ignore other failures - RESTARTABLE(::close(fd), result); + result = ::close(fd); assert(result != OS_ERR, "could not close file"); if (mapAddress == MAP_FAILED) { @@ -755,8 +753,7 @@ (void)::memset((void*) mapAddress, 0, size); // it does not go through os api, the operation has to record from here - MemTracker::record_virtual_memory_reserve((address)mapAddress, size, CURRENT_PC); - MemTracker::record_virtual_memory_type((address)mapAddress, mtInternal); + MemTracker::record_virtual_memory_reserve((address)mapAddress, size, mtInternal, CURRENT_PC); return mapAddress; } @@ -907,9 +904,7 @@ mapAddress = (char*)::mmap((char*)0, size, mmap_prot, MAP_SHARED, fd, 0); - // attempt to close the file - restart if it gets interrupted, - // but ignore other failures - RESTARTABLE(::close(fd), result); + result = ::close(fd); assert(result != OS_ERR, "could not close file"); if (mapAddress == MAP_FAILED) { @@ -921,8 +916,7 @@ } // it does not go through os api, the operation has to record from here - MemTracker::record_virtual_memory_reserve((address)mapAddress, size, CURRENT_PC); - MemTracker::record_virtual_memory_type((address)mapAddress, mtInternal); + MemTracker::record_virtual_memory_reserve((address)mapAddress, size, mtInternal, CURRENT_PC); *addr = mapAddress; *sizep = size; diff -r f9709e27a876 -r 726d2d4913fc src/os/solaris/dtrace/jvm_dtrace.c --- a/src/os/solaris/dtrace/jvm_dtrace.c Fri Jun 14 07:27:22 2013 -0700 +++ b/src/os/solaris/dtrace/jvm_dtrace.c Wed Jun 19 18:13:52 2013 +0200 @@ -122,9 +122,7 @@ } static int file_close(int fd) { - int ret; - RESTARTABLE(close(fd), ret); - return ret; + return close(fd); } static int file_read(int fd, char* buf, int len) { diff -r f9709e27a876 -r 726d2d4913fc src/os/solaris/vm/attachListener_solaris.cpp --- a/src/os/solaris/vm/attachListener_solaris.cpp Fri Jun 14 07:27:22 2013 -0700 +++ b/src/os/solaris/vm/attachListener_solaris.cpp Wed Jun 19 18:13:52 2013 +0200 @@ -392,7 +392,7 @@ return -1; } assert(fd >= 0, "bad file descriptor"); - RESTARTABLE(::close(fd), res); + ::close(fd); // attach the door descriptor to the file if ((res = ::fattach(dd, initial_path)) == -1) { @@ -410,7 +410,7 @@ // rename file so that clients can attach if (dd >= 0) { if (::rename(initial_path, door_path) == -1) { - RESTARTABLE(::close(dd), res); + ::close(dd); ::fdetach(initial_path); dd = -1; } @@ -549,7 +549,7 @@ } // close socket and we're done - RESTARTABLE(::close(this->socket()), rc); + ::close(this->socket()); // were we externally suspended while we were waiting? thread->check_and_wait_while_suspended(); diff -r f9709e27a876 -r 726d2d4913fc src/os/solaris/vm/os_solaris.cpp --- a/src/os/solaris/vm/os_solaris.cpp Fri Jun 14 07:27:22 2013 -0700 +++ b/src/os/solaris/vm/os_solaris.cpp Wed Jun 19 18:13:52 2013 +0200 @@ -2784,7 +2784,42 @@ return page_size; } -bool os::pd_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); @@ -2792,14 +2827,38 @@ if (UseNUMAInterleaving) { numa_make_global(addr, bytes); } - return true; - } - return false; -} - -bool os::pd_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, OOM_MMAP_ERROR, "committing reserved memory."); + } + + return err; +} + +bool os::pd_commit_memory(char* addr, size_t bytes, bool exec) { + return Solaris::commit_memory_impl(addr, bytes, exec) == 0; +} + +void os::pd_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, OOM_MMAP_ERROR, 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 @@ -2821,9 +2880,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::pd_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::pd_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, OOM_MMAP_ERROR, mesg); + } } // Uncommit the pages in a specified region. @@ -2835,7 +2910,7 @@ } bool os::pd_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) { @@ -3457,22 +3532,21 @@ } // The memory is committed - address pc = CALLER_PC; - MemTracker::record_virtual_memory_reserve((address)retAddr, size, pc); - MemTracker::record_virtual_memory_commit((address)retAddr, size, pc); + MemTracker::record_virtual_memory_reserve_and_commit((address)retAddr, size, mtNone, CURRENT_PC); return retAddr; } bool os::release_memory_special(char* base, size_t bytes) { + MemTracker::Tracker tkr = MemTracker::get_virtual_memory_release_tracker(); // detaching the SHM segment will also delete it, see reserve_memory_special() int rslt = shmdt(base); if (rslt == 0) { - MemTracker::record_virtual_memory_uncommit((address)base, bytes); - MemTracker::record_virtual_memory_release((address)base, bytes); + tkr.record((address)base, bytes); return true; } else { - return false; + tkr.discard(); + return false; } } @@ -6604,11 +6678,11 @@ } int os::close(int fd) { - RESTARTABLE_RETURN_INT(::close(fd)); + return ::close(fd); } int os::socket_close(int fd) { - RESTARTABLE_RETURN_INT(::close(fd)); + return ::close(fd); } int os::recv(int fd, char* buf, size_t nBytes, uint flags) { diff -r f9709e27a876 -r 726d2d4913fc src/os/solaris/vm/os_solaris.hpp --- a/src/os/solaris/vm/os_solaris.hpp Fri Jun 14 07:27:22 2013 -0700 +++ b/src/os/solaris/vm/os_solaris.hpp Wed Jun 19 18:13:52 2013 +0200 @@ -168,6 +168,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 f9709e27a876 -r 726d2d4913fc src/os/solaris/vm/perfMemory_solaris.cpp --- a/src/os/solaris/vm/perfMemory_solaris.cpp Fri Jun 14 07:27:22 2013 -0700 +++ b/src/os/solaris/vm/perfMemory_solaris.cpp Wed Jun 19 18:13:52 2013 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2012, 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 @@ -62,7 +62,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"); } @@ -122,7 +122,7 @@ addr += result; } - RESTARTABLE(::close(fd), result); + result = ::close(fd); if (PrintMiscellaneous && Verbose) { if (result == OS_ERR) { warning("Could not close %s: %s\n", destfile, strerror(errno)); @@ -437,7 +437,7 @@ addr+=result; } - RESTARTABLE(::close(fd), result); + ::close(fd); // get the user name for the effective user id of the process char* user_name = get_user_name(psinfo.pr_euid); @@ -669,7 +669,7 @@ if (PrintMiscellaneous && Verbose) { warning("could not set shared memory file size: %s\n", strerror(errno)); } - RESTARTABLE(::close(fd), result); + ::close(fd); return -1; } @@ -749,9 +749,7 @@ mapAddress = (char*)::mmap((char*)0, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); - // attempt to close the file - restart it if it was interrupted, - // but ignore other failures - RESTARTABLE(::close(fd), result); + result = ::close(fd); assert(result != OS_ERR, "could not close file"); if (mapAddress == MAP_FAILED) { @@ -770,8 +768,7 @@ (void)::memset((void*) mapAddress, 0, size); // it does not go through os api, the operation has to record from here - MemTracker::record_virtual_memory_reserve((address)mapAddress, size, CURRENT_PC); - MemTracker::record_virtual_memory_type((address)mapAddress, mtInternal); + MemTracker::record_virtual_memory_reserve((address)mapAddress, size, mtInternal, CURRENT_PC); return mapAddress; } @@ -922,9 +919,7 @@ mapAddress = (char*)::mmap((char*)0, size, mmap_prot, MAP_SHARED, fd, 0); - // attempt to close the file - restart if it gets interrupted, - // but ignore other failures - RESTARTABLE(::close(fd), result); + result = ::close(fd); assert(result != OS_ERR, "could not close file"); if (mapAddress == MAP_FAILED) { @@ -936,8 +931,7 @@ } // it does not go through os api, the operation has to record from here - MemTracker::record_virtual_memory_reserve((address)mapAddress, size, CURRENT_PC); - MemTracker::record_virtual_memory_type((address)mapAddress, mtInternal); + MemTracker::record_virtual_memory_reserve((address)mapAddress, size, mtInternal, CURRENT_PC); *addr = mapAddress; *sizep = size; diff -r f9709e27a876 -r 726d2d4913fc src/os/windows/vm/os_windows.cpp --- a/src/os/windows/vm/os_windows.cpp Fri Jun 14 07:27:22 2013 -0700 +++ b/src/os/windows/vm/os_windows.cpp Wed Jun 19 18:13:52 2013 +0200 @@ -2524,7 +2524,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 @@ -2875,7 +2875,7 @@ PAGE_READWRITE); // If reservation failed, return NULL if (p_buf == NULL) return NULL; - MemTracker::record_virtual_memory_reserve((address)p_buf, size_of_reserve, CALLER_PC); + MemTracker::record_virtual_memory_reserve((address)p_buf, size_of_reserve, mtNone, CALLER_PC); os::release_memory(p_buf, bytes + chunk_size); // we still need to round up to a page boundary (in case we are using large pages) @@ -2941,7 +2941,7 @@ // need to create a dummy 'reserve' record to match // the release. MemTracker::record_virtual_memory_reserve((address)p_buf, - bytes_to_release, CALLER_PC); + bytes_to_release, mtNone, CALLER_PC); os::release_memory(p_buf, bytes_to_release); } #ifdef ASSERT @@ -2961,9 +2961,10 @@ // Although the memory is allocated individually, it is returned as one. // NMT records it as one block. address pc = CALLER_PC; - MemTracker::record_virtual_memory_reserve((address)p_buf, bytes, pc); if ((flags & MEM_COMMIT) != 0) { - MemTracker::record_virtual_memory_commit((address)p_buf, bytes, pc); + MemTracker::record_virtual_memory_reserve_and_commit((address)p_buf, bytes, mtNone, pc); + } else { + MemTracker::record_virtual_memory_reserve((address)p_buf, bytes, mtNone, pc); } // made it this far, success @@ -3154,8 +3155,7 @@ char * res = (char *)VirtualAlloc(NULL, bytes, flag, prot); if (res != NULL) { address pc = CALLER_PC; - MemTracker::record_virtual_memory_reserve((address)res, bytes, pc); - MemTracker::record_virtual_memory_commit((address)res, bytes, pc); + MemTracker::record_virtual_memory_reserve_and_commit((address)res, bytes, mtNone, pc); } return res; @@ -3164,14 +3164,21 @@ bool os::release_memory_special(char* base, size_t bytes) { assert(base != NULL, "Sanity check"); - // Memory allocated via reserve_memory_special() is committed - MemTracker::record_virtual_memory_uncommit((address)base, bytes); return release_memory(base, bytes); } 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::pd_commit_memory(char* addr, size_t bytes, bool exec) { if (bytes == 0) { // Don't bother the OS with noops. @@ -3186,11 +3193,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 { @@ -3205,12 +3218,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; @@ -3222,7 +3243,24 @@ bool os::pd_commit_memory(char* addr, size_t size, size_t alignment_hint, bool exec) { - return commit_memory(addr, size, exec); + // alignment_hint is ignored on this OS + return pd_commit_memory(addr, size, exec); +} + +void os::pd_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, OOM_MMAP_ERROR, mesg); + } +} + +void os::pd_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::pd_uncommit_memory(char* addr, size_t bytes) { @@ -3240,7 +3278,7 @@ } bool os::pd_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) { @@ -3264,8 +3302,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 f9709e27a876 -r 726d2d4913fc src/os/windows/vm/perfMemory_windows.cpp --- a/src/os/windows/vm/perfMemory_windows.cpp Fri Jun 14 07:27:22 2013 -0700 +++ b/src/os/windows/vm/perfMemory_windows.cpp Wed Jun 19 18:13:52 2013 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2012, 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 @@ -58,7 +58,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"); } @@ -1498,8 +1498,7 @@ (void)memset(mapAddress, '\0', size); // it does not go through os api, the operation has to record from here - MemTracker::record_virtual_memory_reserve((address)mapAddress, size, CURRENT_PC); - MemTracker::record_virtual_memory_type((address)mapAddress, mtInternal); + MemTracker::record_virtual_memory_reserve((address)mapAddress, size, mtInternal, CURRENT_PC); return (char*) mapAddress; } @@ -1681,8 +1680,7 @@ } // it does not go through os api, the operation has to record from here - MemTracker::record_virtual_memory_reserve((address)mapAddress, size, CURRENT_PC); - MemTracker::record_virtual_memory_type((address)mapAddress, mtInternal); + MemTracker::record_virtual_memory_reserve((address)mapAddress, size, mtInternal, CURRENT_PC); *addrp = (char*)mapAddress; @@ -1836,9 +1834,10 @@ return; } + MemTracker::Tracker tkr = MemTracker::get_virtual_memory_release_tracker(); remove_file_mapping(addr); // it does not go through os api, the operation has to record from here - MemTracker::record_virtual_memory_release((address)addr, bytes); + tkr.record((address)addr, bytes); } char* PerfMemory::backing_store_filename() { diff -r f9709e27a876 -r 726d2d4913fc src/share/vm/c1/c1_IR.cpp --- a/src/share/vm/c1/c1_IR.cpp Fri Jun 14 07:27:22 2013 -0700 +++ b/src/share/vm/c1/c1_IR.cpp Wed Jun 19 18:13:52 2013 +0200 @@ -506,7 +506,7 @@ _loop_map(0, 0), // initialized later with correct size _compilation(c) { - TRACE_LINEAR_SCAN(2, "***** computing linear-scan block order"); + TRACE_LINEAR_SCAN(2, tty->print_cr("***** computing linear-scan block order")); init_visited(); count_edges(start_block, NULL); @@ -683,7 +683,7 @@ } void ComputeLinearScanOrder::assign_loop_depth(BlockBegin* start_block) { - TRACE_LINEAR_SCAN(3, "----- computing loop-depth and weight"); + TRACE_LINEAR_SCAN(3, tty->print_cr("----- computing loop-depth and weight")); init_visited(); assert(_work_list.is_empty(), "work list must be empty before processing"); @@ -868,7 +868,7 @@ } void ComputeLinearScanOrder::compute_order(BlockBegin* start_block) { - TRACE_LINEAR_SCAN(3, "----- computing final block order"); + TRACE_LINEAR_SCAN(3, tty->print_cr("----- computing final block order")); // the start block is always the first block in the linear scan order _linear_scan_order = new BlockList(_num_blocks); diff -r f9709e27a876 -r 726d2d4913fc src/share/vm/ci/ciUtilities.hpp --- a/src/share/vm/ci/ciUtilities.hpp Fri Jun 14 07:27:22 2013 -0700 +++ b/src/share/vm/ci/ciUtilities.hpp Wed Jun 19 18:13:52 2013 +0200 @@ -96,7 +96,7 @@ CLEAR_PENDING_EXCEPTION; \ return (result); \ } \ - (0 + (void)(0 #define KILL_COMPILE_ON_ANY \ THREAD); \ @@ -104,7 +104,7 @@ fatal("unhandled ci exception"); \ CLEAR_PENDING_EXCEPTION; \ } \ -(0 +(void)(0 inline const char* bool_to_str(bool b) { diff -r f9709e27a876 -r 726d2d4913fc src/share/vm/classfile/genericSignatures.cpp --- a/src/share/vm/classfile/genericSignatures.cpp Fri Jun 14 07:27:22 2013 -0700 +++ b/src/share/vm/classfile/genericSignatures.cpp Wed Jun 19 18:13:52 2013 +0200 @@ -124,7 +124,7 @@ fatal(STREAM->parse_error()); \ } \ return NULL; \ - } 0 + } (void)0 #define READ() STREAM->read(); CHECK_FOR_PARSE_ERROR() #define PEEK() STREAM->peek(); CHECK_FOR_PARSE_ERROR() @@ -133,7 +133,7 @@ #define EXPECTED(c, ch) STREAM->assert_char(c, ch); CHECK_FOR_PARSE_ERROR() #define EXPECT_END() STREAM->expect_end(); CHECK_FOR_PARSE_ERROR() -#define CHECK_STREAM STREAM); CHECK_FOR_PARSE_ERROR(); (0 +#define CHECK_STREAM STREAM); CHECK_FOR_PARSE_ERROR(); ((void)0 #ifndef PRODUCT void Identifier::print_on(outputStream* str) const { diff -r f9709e27a876 -r 726d2d4913fc src/share/vm/classfile/verifier.hpp --- a/src/share/vm/classfile/verifier.hpp Fri Jun 14 07:27:22 2013 -0700 +++ b/src/share/vm/classfile/verifier.hpp Wed Jun 19 18:13:52 2013 +0200 @@ -86,9 +86,9 @@ // These macros are used similarly to CHECK macros but also check // the status of the verifier and return if that has an error. #define CHECK_VERIFY(verifier) \ - CHECK); if ((verifier)->has_error()) return; (0 + CHECK); if ((verifier)->has_error()) return; ((void)0 #define CHECK_VERIFY_(verifier, result) \ - CHECK_(result)); if ((verifier)->has_error()) return (result); (0 + CHECK_(result)); if ((verifier)->has_error()) return (result); ((void)0 class TypeOrigin VALUE_OBJ_CLASS_SPEC { private: diff -r f9709e27a876 -r 726d2d4913fc src/share/vm/code/dependencies.cpp --- a/src/share/vm/code/dependencies.cpp Fri Jun 14 07:27:22 2013 -0700 +++ b/src/share/vm/code/dependencies.cpp Wed Jun 19 18:13:52 2013 +0200 @@ -989,7 +989,7 @@ assert(changes.involves_context(context_type), "irrelevant dependency"); Klass* new_type = changes.new_type(); - count_find_witness_calls(); + (void)count_find_witness_calls(); NOT_PRODUCT(deps_find_witness_singles++); // Current thread must be in VM (not native mode, as in CI): diff -r f9709e27a876 -r 726d2d4913fc src/share/vm/code/nmethod.cpp --- a/src/share/vm/code/nmethod.cpp Fri Jun 14 07:27:22 2013 -0700 +++ b/src/share/vm/code/nmethod.cpp Wed Jun 19 18:13:52 2013 +0200 @@ -2615,7 +2615,8 @@ relocation_begin()-1+ip[1]); for (; ip < index_end; ip++) tty->print_cr(" (%d ?)", ip[0]); - tty->print_cr(" @" INTPTR_FORMAT ": index_size=%d", ip, *ip++); + tty->print_cr(" @" INTPTR_FORMAT ": index_size=%d", ip, *ip); + ip++; tty->print_cr("reloc_end @" INTPTR_FORMAT ":", ip); } } diff -r f9709e27a876 -r 726d2d4913fc src/share/vm/gc_implementation/parallelScavenge/cardTableExtension.cpp --- a/src/share/vm/gc_implementation/parallelScavenge/cardTableExtension.cpp Fri Jun 14 07:27:22 2013 -0700 +++ b/src/share/vm/gc_implementation/parallelScavenge/cardTableExtension.cpp Wed Jun 19 18:13:52 2013 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2012, 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 @@ -565,11 +565,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(), OOM_MMAP_ERROR, - "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 f9709e27a876 -r 726d2d4913fc src/share/vm/gc_implementation/parallelScavenge/psVirtualspace.cpp --- a/src/share/vm/gc_implementation/parallelScavenge/psVirtualspace.cpp Fri Jun 14 07:27:22 2013 -0700 +++ b/src/share/vm/gc_implementation/parallelScavenge/psVirtualspace.cpp Wed Jun 19 18:13:52 2013 +0200 @@ -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 f9709e27a876 -r 726d2d4913fc src/share/vm/memory/allocation.hpp --- a/src/share/vm/memory/allocation.hpp Fri Jun 14 07:27:22 2013 -0700 +++ b/src/share/vm/memory/allocation.hpp Wed Jun 19 18:13:52 2013 +0200 @@ -635,8 +635,15 @@ #define NEW_RESOURCE_ARRAY_IN_THREAD(thread, type, size)\ (type*) resource_allocate_bytes(thread, (size) * sizeof(type)) +#define NEW_RESOURCE_ARRAY_IN_THREAD_RETURN_NULL(thread, type, size)\ + (type*) resource_allocate_bytes(thread, (size) * sizeof(type), AllocFailStrategy::RETURN_NULL) + #define REALLOC_RESOURCE_ARRAY(type, old, old_size, new_size)\ - (type*) resource_reallocate_bytes((char*)(old), (old_size) * sizeof(type), (new_size) * sizeof(type) ) + (type*) resource_reallocate_bytes((char*)(old), (old_size) * sizeof(type), (new_size) * sizeof(type)) + +#define REALLOC_RESOURCE_ARRAY_RETURN_NULL(type, old, old_size, new_size)\ + (type*) resource_reallocate_bytes((char*)(old), (old_size) * sizeof(type),\ + (new_size) * sizeof(type), AllocFailStrategy::RETURN_NULL) #define FREE_RESOURCE_ARRAY(type, old, size)\ resource_free_bytes((char*)(old), (size) * sizeof(type)) @@ -647,28 +654,40 @@ #define NEW_RESOURCE_OBJ(type)\ NEW_RESOURCE_ARRAY(type, 1) +#define NEW_RESOURCE_OBJ_RETURN_NULL(type)\ + NEW_RESOURCE_ARRAY_RETURN_NULL(type, 1) + +#define NEW_C_HEAP_ARRAY3(type, size, memflags, pc, allocfail)\ + (type*) AllocateHeap(size * sizeof(type), memflags, pc, allocfail) + +#define NEW_C_HEAP_ARRAY2(type, size, memflags, pc)\ + (type*) (AllocateHeap((size) * sizeof(type), memflags, pc)) + #define NEW_C_HEAP_ARRAY(type, size, memflags)\ (type*) (AllocateHeap((size) * sizeof(type), memflags)) +#define NEW_C_HEAP_ARRAY2_RETURN_NULL(type, size, memflags, pc)\ + NEW_C_HEAP_ARRAY3(type, size, memflags, pc, AllocFailStrategy::RETURN_NULL) + +#define NEW_C_HEAP_ARRAY_RETURN_NULL(type, size, memflags)\ + NEW_C_HEAP_ARRAY3(type, size, memflags, (address)0, AllocFailStrategy::RETURN_NULL) + #define REALLOC_C_HEAP_ARRAY(type, old, size, memflags)\ (type*) (ReallocateHeap((char*)old, (size) * sizeof(type), memflags)) +#define REALLOC_C_HEAP_ARRAY_RETURN_NULL(type, old, size, memflags)\ + (type*) (ReallocateHeap((char*)old, (size) * sizeof(type), memflags, AllocFailStrategy::RETURN_NULL)) + #define FREE_C_HEAP_ARRAY(type, old, memflags) \ FreeHeap((char*)(old), memflags) -#define NEW_C_HEAP_ARRAY2(type, size, memflags, pc)\ - (type*) (AllocateHeap((size) * sizeof(type), memflags, pc)) - -#define REALLOC_C_HEAP_ARRAY2(type, old, size, memflags, pc)\ - (type*) (ReallocateHeap((char*)old, (size) * sizeof(type), memflags, pc)) - -#define NEW_C_HEAP_ARRAY3(type, size, memflags, pc, allocfail) \ - (type*) AllocateHeap(size * sizeof(type), memflags, pc, allocfail) - // allocate type in heap without calling ctor #define NEW_C_HEAP_OBJ(type, memflags)\ NEW_C_HEAP_ARRAY(type, 1, memflags) +#define NEW_C_HEAP_OBJ_RETURN_NULL(type, memflags)\ + NEW_C_HEAP_ARRAY_RETURN_NULL(type, 1, memflags) + // deallocate obj of type in heap without calling dtor #define FREE_C_HEAP_OBJ(objname, memflags)\ FreeHeap((char*)objname, memflags); diff -r f9709e27a876 -r 726d2d4913fc src/share/vm/memory/allocation.inline.hpp --- a/src/share/vm/memory/allocation.inline.hpp Fri Jun 14 07:27:22 2013 -0700 +++ b/src/share/vm/memory/allocation.inline.hpp Wed Jun 19 18:13:52 2013 +0200 @@ -146,10 +146,7 @@ vm_exit_out_of_memory(_size, OOM_MMAP_ERROR, "Allocator (reserve)"); } - bool success = os::commit_memory(_addr, _size, false /* executable */); - if (!success) { - vm_exit_out_of_memory(_size, OOM_MMAP_ERROR, "Allocator (commit)"); - } + os::commit_memory_or_exit(_addr, _size, !ExecMem, "Allocator (commit)"); return (E*)_addr; } diff -r f9709e27a876 -r 726d2d4913fc src/share/vm/memory/cardTableModRefBS.cpp --- a/src/share/vm/memory/cardTableModRefBS.cpp Fri Jun 14 07:27:22 2013 -0700 +++ b/src/share/vm/memory/cardTableModRefBS.cpp Wed Jun 19 18:13:52 2013 +0200 @@ -110,11 +110,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, OOM_MMAP_ERROR, "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 = @@ -312,12 +309,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(), OOM_MMAP_ERROR, - "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()) { @@ -418,7 +412,7 @@ } // Touch the last card of the covered region to show that it // is committed (or SEGV). - debug_only(*byte_for(_covered[ind].last());) + debug_only((void) (*byte_for(_covered[ind].last()));) debug_only(verify_guard();) } diff -r f9709e27a876 -r 726d2d4913fc src/share/vm/memory/universe.cpp --- a/src/share/vm/memory/universe.cpp Fri Jun 14 07:27:22 2013 -0700 +++ b/src/share/vm/memory/universe.cpp Wed Jun 19 18:13:52 2013 +0200 @@ -529,7 +529,9 @@ if (vt) vt->initialize_vtable(false, CHECK); if (ko->oop_is_instance()) { InstanceKlass* ik = (InstanceKlass*)ko; - for (KlassHandle s_h(THREAD, ik->subklass()); s_h() != NULL; s_h = (THREAD, s_h()->next_sibling())) { + for (KlassHandle s_h(THREAD, ik->subklass()); + s_h() != NULL; + s_h = KlassHandle(THREAD, s_h()->next_sibling())) { reinitialize_vtable_of(s_h, CHECK); } } diff -r f9709e27a876 -r 726d2d4913fc src/share/vm/opto/memnode.cpp --- a/src/share/vm/opto/memnode.cpp Fri Jun 14 07:27:22 2013 -0700 +++ b/src/share/vm/opto/memnode.cpp Wed Jun 19 18:13:52 2013 +0200 @@ -4384,7 +4384,7 @@ } } #else // !ASSERT -#define verify_memory_slice(m,i,n) (0) // PRODUCT version is no-op +#define verify_memory_slice(m,i,n) (void)(0) // PRODUCT version is no-op #endif diff -r f9709e27a876 -r 726d2d4913fc src/share/vm/prims/forte.cpp --- a/src/share/vm/prims/forte.cpp Fri Jun 14 07:27:22 2013 -0700 +++ b/src/share/vm/prims/forte.cpp Wed Jun 19 18:13:52 2013 +0200 @@ -619,7 +619,7 @@ void* null_argument_3); #pragma weak collector_func_load #define collector_func_load(x0,x1,x2,x3,x4,x5,x6) \ - ( collector_func_load ? collector_func_load(x0,x1,x2,x3,x4,x5,x6),0 : 0 ) + ( collector_func_load ? collector_func_load(x0,x1,x2,x3,x4,x5,x6),(void)0 : (void)0 ) #endif // __APPLE__ #endif // !_WINDOWS diff -r f9709e27a876 -r 726d2d4913fc src/share/vm/prims/jvmti.xml --- a/src/share/vm/prims/jvmti.xml Fri Jun 14 07:27:22 2013 -0700 +++ b/src/share/vm/prims/jvmti.xml Wed Jun 19 18:13:52 2013 +0200 @@ -1897,7 +1897,7 @@ - + jvmtiMonitorStackDepthInfo diff -r f9709e27a876 -r 726d2d4913fc src/share/vm/prims/whitebox.cpp --- a/src/share/vm/prims/whitebox.cpp Fri Jun 14 07:27:22 2013 -0700 +++ b/src/share/vm/prims/whitebox.cpp Wed Jun 19 18:13:52 2013 +0200 @@ -159,7 +159,7 @@ WB_ENTRY(void, WB_NMTCommitMemory(JNIEnv* env, jobject o, jlong addr, jlong size)) - os::commit_memory((char *)(uintptr_t)addr, size); + os::commit_memory((char *)(uintptr_t)addr, size, !ExecMem); MemTracker::record_virtual_memory_type((address)(uintptr_t)addr, mtTest); WB_END diff -r f9709e27a876 -r 726d2d4913fc src/share/vm/runtime/os.cpp --- a/src/share/vm/runtime/os.cpp Fri Jun 14 07:27:22 2013 -0700 +++ b/src/share/vm/runtime/os.cpp Wed Jun 19 18:13:52 2013 +0200 @@ -647,10 +647,13 @@ #ifndef ASSERT NOT_PRODUCT(inc_stat_counter(&num_mallocs, 1)); NOT_PRODUCT(inc_stat_counter(&alloc_bytes, size)); + MemTracker::Tracker tkr = MemTracker::get_realloc_tracker(); void* ptr = ::realloc(memblock, size); if (ptr != NULL) { - MemTracker::record_realloc((address)memblock, (address)ptr, size, memflags, + tkr.record((address)memblock, (address)ptr, size, memflags, caller == 0 ? CALLER_PC : caller); + } else { + tkr.discard(); } return ptr; #else @@ -1456,7 +1459,7 @@ char* os::reserve_memory(size_t bytes, char* addr, size_t alignment_hint) { char* result = pd_reserve_memory(bytes, addr, alignment_hint); if (result != NULL) { - MemTracker::record_virtual_memory_reserve((address)result, bytes, CALLER_PC); + MemTracker::record_virtual_memory_reserve((address)result, bytes, mtNone, CALLER_PC); } return result; @@ -1466,7 +1469,7 @@ MEMFLAGS flags) { char* result = pd_reserve_memory(bytes, addr, alignment_hint); if (result != NULL) { - MemTracker::record_virtual_memory_reserve((address)result, bytes, CALLER_PC); + MemTracker::record_virtual_memory_reserve((address)result, bytes, mtNone, CALLER_PC); MemTracker::record_virtual_memory_type((address)result, flags); } @@ -1476,7 +1479,7 @@ char* os::attempt_reserve_memory_at(size_t bytes, char* addr) { char* result = pd_attempt_reserve_memory_at(bytes, addr); if (result != NULL) { - MemTracker::record_virtual_memory_reserve((address)result, bytes, CALLER_PC); + MemTracker::record_virtual_memory_reserve((address)result, bytes, mtNone, CALLER_PC); } return result; } @@ -1503,18 +1506,36 @@ return res; } +void os::commit_memory_or_exit(char* addr, size_t bytes, bool executable, + const char* mesg) { + pd_commit_memory_or_exit(addr, bytes, executable, mesg); + MemTracker::record_virtual_memory_commit((address)addr, bytes, CALLER_PC); +} + +void os::commit_memory_or_exit(char* addr, size_t size, size_t alignment_hint, + bool executable, const char* mesg) { + os::pd_commit_memory_or_exit(addr, size, alignment_hint, executable, mesg); + MemTracker::record_virtual_memory_commit((address)addr, size, CALLER_PC); +} + bool os::uncommit_memory(char* addr, size_t bytes) { + MemTracker::Tracker tkr = MemTracker::get_virtual_memory_uncommit_tracker(); bool res = pd_uncommit_memory(addr, bytes); if (res) { - MemTracker::record_virtual_memory_uncommit((address)addr, bytes); + tkr.record((address)addr, bytes); + } else { + tkr.discard(); } return res; } bool os::release_memory(char* addr, size_t bytes) { + MemTracker::Tracker tkr = MemTracker::get_virtual_memory_release_tracker(); bool res = pd_release_memory(addr, bytes); if (res) { - MemTracker::record_virtual_memory_release((address)addr, bytes); + tkr.record((address)addr, bytes); + } else { + tkr.discard(); } return res; } @@ -1525,8 +1546,7 @@ bool allow_exec) { char* result = pd_map_memory(fd, file_name, file_offset, addr, bytes, read_only, allow_exec); if (result != NULL) { - MemTracker::record_virtual_memory_reserve((address)result, bytes, CALLER_PC); - MemTracker::record_virtual_memory_commit((address)result, bytes, CALLER_PC); + MemTracker::record_virtual_memory_reserve_and_commit((address)result, bytes, mtNone, CALLER_PC); } return result; } @@ -1539,10 +1559,12 @@ } bool os::unmap_memory(char *addr, size_t bytes) { + MemTracker::Tracker tkr = MemTracker::get_virtual_memory_release_tracker(); bool result = pd_unmap_memory(addr, bytes); if (result) { - MemTracker::record_virtual_memory_uncommit((address)addr, bytes); - MemTracker::record_virtual_memory_release((address)addr, bytes); + tkr.record((address)addr, bytes); + } else { + tkr.discard(); } return result; } diff -r f9709e27a876 -r 726d2d4913fc src/share/vm/runtime/os.hpp --- a/src/share/vm/runtime/os.hpp Fri Jun 14 07:27:22 2013 -0700 +++ b/src/share/vm/runtime/os.hpp Wed Jun 19 18:13:52 2013 +0200 @@ -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); @@ -104,9 +108,16 @@ static char* pd_attempt_reserve_memory_at(size_t bytes, char* addr); static void pd_split_reserved_memory(char *base, size_t size, size_t split, bool realloc); - static bool pd_commit_memory(char* addr, size_t bytes, bool executable = false); + static bool pd_commit_memory(char* addr, size_t bytes, bool executable); static bool pd_commit_memory(char* addr, size_t size, size_t alignment_hint, - bool executable = false); + bool executable); + // Same as pd_commit_memory() that either succeeds or calls + // vm_exit_out_of_memory() with the specified mesg. + static void pd_commit_memory_or_exit(char* addr, size_t bytes, + bool executable, const char* mesg); + static void pd_commit_memory_or_exit(char* addr, size_t size, + size_t alignment_hint, + bool executable, const char* mesg); static bool pd_uncommit_memory(char* addr, size_t bytes); static bool pd_release_memory(char* addr, size_t bytes); @@ -261,9 +272,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 f9709e27a876 -r 726d2d4913fc src/share/vm/runtime/sharedRuntime.cpp --- a/src/share/vm/runtime/sharedRuntime.cpp Fri Jun 14 07:27:22 2013 -0700 +++ b/src/share/vm/runtime/sharedRuntime.cpp Wed Jun 19 18:13:52 2013 +0200 @@ -2731,7 +2731,7 @@ // ResourceObject, so do not put any ResourceMarks in here. char *s = sig->as_C_string(); int len = (int)strlen(s); - *s++; len--; // Skip opening paren + s++; len--; // Skip opening paren char *t = s+len; while( *(--t) != ')' ) ; // Find close paren diff -r f9709e27a876 -r 726d2d4913fc src/share/vm/runtime/virtualspace.cpp --- a/src/share/vm/runtime/virtualspace.cpp Fri Jun 14 07:27:22 2013 -0700 +++ b/src/share/vm/runtime/virtualspace.cpp Wed Jun 19 18:13:52 2013 +0200 @@ -533,11 +533,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() && @@ -545,7 +547,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; @@ -555,7 +560,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; diff -r f9709e27a876 -r 726d2d4913fc src/share/vm/services/diagnosticArgument.cpp --- a/src/share/vm/services/diagnosticArgument.cpp Fri Jun 14 07:27:22 2013 -0700 +++ b/src/share/vm/services/diagnosticArgument.cpp Wed Jun 19 18:13:52 2013 +0200 @@ -247,7 +247,7 @@ } else { _value._time = 0; _value._nanotime = 0; - strcmp(_value._unit, "ns"); + strcpy(_value._unit, "ns"); } } diff -r f9709e27a876 -r 726d2d4913fc src/share/vm/services/memBaseline.cpp --- a/src/share/vm/services/memBaseline.cpp Fri Jun 14 07:27:22 2013 -0700 +++ b/src/share/vm/services/memBaseline.cpp Wed Jun 19 18:13:52 2013 +0200 @@ -130,7 +130,7 @@ if (malloc_ptr->is_arena_record()) { // see if arena memory record present MemPointerRecord* next_malloc_ptr = (MemPointerRecordEx*)malloc_itr.peek_next(); - if (next_malloc_ptr->is_arena_memory_record()) { + if (next_malloc_ptr != NULL && next_malloc_ptr->is_arena_memory_record()) { assert(next_malloc_ptr->is_memory_record_of_arena(malloc_ptr), "Arena records do not match"); size = next_malloc_ptr->size(); diff -r f9709e27a876 -r 726d2d4913fc src/share/vm/services/memPtr.hpp --- a/src/share/vm/services/memPtr.hpp Fri Jun 14 07:27:22 2013 -0700 +++ b/src/share/vm/services/memPtr.hpp Wed Jun 19 18:13:52 2013 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -457,9 +457,8 @@ public: SeqMemPointerRecord(): _seq(0){ } - SeqMemPointerRecord(address addr, MEMFLAGS flags, size_t size) - : MemPointerRecord(addr, flags, size) { - _seq = SequenceGenerator::next(); + SeqMemPointerRecord(address addr, MEMFLAGS flags, size_t size, jint seq) + : MemPointerRecord(addr, flags, size), _seq(seq) { } SeqMemPointerRecord(const SeqMemPointerRecord& copy_from) @@ -488,8 +487,8 @@ SeqMemPointerRecordEx(): _seq(0) { } SeqMemPointerRecordEx(address addr, MEMFLAGS flags, size_t size, - address pc): MemPointerRecordEx(addr, flags, size, pc) { - _seq = SequenceGenerator::next(); + jint seq, address pc): + MemPointerRecordEx(addr, flags, size, pc), _seq(seq) { } SeqMemPointerRecordEx(const SeqMemPointerRecordEx& copy_from) diff -r f9709e27a876 -r 726d2d4913fc src/share/vm/services/memRecorder.cpp --- a/src/share/vm/services/memRecorder.cpp Fri Jun 14 07:27:22 2013 -0700 +++ b/src/share/vm/services/memRecorder.cpp Wed Jun 19 18:13:52 2013 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -69,10 +69,11 @@ if (_pointer_records != NULL) { // recode itself + address pc = CURRENT_PC; record((address)this, (MemPointerRecord::malloc_tag()|mtNMT|otNMTRecorder), - sizeof(MemRecorder), CALLER_PC); + sizeof(MemRecorder), SequenceGenerator::next(), pc); record((address)_pointer_records, (MemPointerRecord::malloc_tag()|mtNMT|otNMTRecorder), - _pointer_records->instance_size(),CURRENT_PC); + _pointer_records->instance_size(), SequenceGenerator::next(), pc); } } @@ -116,7 +117,8 @@ } } -bool MemRecorder::record(address p, MEMFLAGS flags, size_t size, address pc) { +bool MemRecorder::record(address p, MEMFLAGS flags, size_t size, jint seq, address pc) { + assert(seq > 0, "No sequence number"); #ifdef ASSERT if (MemPointerRecord::is_virtual_memory_record(flags)) { assert((flags & MemPointerRecord::tag_masks) != 0, "bad virtual memory record"); @@ -133,11 +135,11 @@ #endif if (MemTracker::track_callsite()) { - SeqMemPointerRecordEx ap(p, flags, size, pc); + SeqMemPointerRecordEx ap(p, flags, size, seq, pc); debug_only(check_dup_seq(ap.seq());) return _pointer_records->append(&ap); } else { - SeqMemPointerRecord ap(p, flags, size); + SeqMemPointerRecord ap(p, flags, size, seq); debug_only(check_dup_seq(ap.seq());) return _pointer_records->append(&ap); } diff -r f9709e27a876 -r 726d2d4913fc src/share/vm/services/memRecorder.hpp --- a/src/share/vm/services/memRecorder.hpp Fri Jun 14 07:27:22 2013 -0700 +++ b/src/share/vm/services/memRecorder.hpp Wed Jun 19 18:13:52 2013 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -220,7 +220,7 @@ ~MemRecorder(); // record a memory operation - bool record(address addr, MEMFLAGS flags, size_t size, address caller_pc = 0); + bool record(address addr, MEMFLAGS flags, size_t size, jint seq, address caller_pc = 0); // linked list support inline void set_next(MemRecorder* rec) { diff -r f9709e27a876 -r 726d2d4913fc src/share/vm/services/memReporter.cpp --- a/src/share/vm/services/memReporter.cpp Fri Jun 14 07:27:22 2013 -0700 +++ b/src/share/vm/services/memReporter.cpp Wed Jun 19 18:13:52 2013 +0200 @@ -190,17 +190,18 @@ while (cur_malloc_callsite != NULL || prev_malloc_callsite != NULL) { if (prev_malloc_callsite == NULL || cur_malloc_callsite->addr() < prev_malloc_callsite->addr()) { + // this is a new callsite _outputer.diff_malloc_callsite(cur_malloc_callsite->addr(), amount_in_current_scale(cur_malloc_callsite->amount()), cur_malloc_callsite->count(), diff_in_current_scale(cur_malloc_callsite->amount(), 0), diff(cur_malloc_callsite->count(), 0)); cur_malloc_callsite = (MallocCallsitePointer*)cur_malloc_itr.next(); - } else if (prev_malloc_callsite == NULL || + } else if (cur_malloc_callsite == NULL || cur_malloc_callsite->addr() > prev_malloc_callsite->addr()) { - _outputer.diff_malloc_callsite(cur_malloc_callsite->addr(), - amount_in_current_scale(prev_malloc_callsite->amount()), - prev_malloc_callsite->count(), + // this callsite is already gone + _outputer.diff_malloc_callsite(prev_malloc_callsite->addr(), + amount_in_current_scale(0), 0, diff_in_current_scale(0, prev_malloc_callsite->amount()), diff(0, prev_malloc_callsite->count())); prev_malloc_callsite = (MallocCallsitePointer*)prev_malloc_itr.next(); @@ -222,6 +223,7 @@ VMCallsitePointer* prev_vm_callsite = (VMCallsitePointer*)prev_vm_itr.current(); while (cur_vm_callsite != NULL || prev_vm_callsite != NULL) { if (prev_vm_callsite == NULL || cur_vm_callsite->addr() < prev_vm_callsite->addr()) { + // this is a new callsite _outputer.diff_virtual_memory_callsite(cur_vm_callsite->addr(), amount_in_current_scale(cur_vm_callsite->reserved_amount()), amount_in_current_scale(cur_vm_callsite->committed_amount()), @@ -229,9 +231,10 @@ diff_in_current_scale(cur_vm_callsite->committed_amount(), 0)); cur_vm_callsite = (VMCallsitePointer*)cur_vm_itr.next(); } else if (cur_vm_callsite == NULL || cur_vm_callsite->addr() > prev_vm_callsite->addr()) { + // this callsite is already gone _outputer.diff_virtual_memory_callsite(prev_vm_callsite->addr(), - amount_in_current_scale(prev_vm_callsite->reserved_amount()), - amount_in_current_scale(prev_vm_callsite->committed_amount()), + amount_in_current_scale(0), + amount_in_current_scale(0), diff_in_current_scale(0, prev_vm_callsite->reserved_amount()), diff_in_current_scale(0, prev_vm_callsite->committed_amount())); prev_vm_callsite = (VMCallsitePointer*)prev_vm_itr.next(); diff -r f9709e27a876 -r 726d2d4913fc src/share/vm/services/memTracker.cpp --- a/src/share/vm/services/memTracker.cpp Fri Jun 14 07:27:22 2013 -0700 +++ b/src/share/vm/services/memTracker.cpp Wed Jun 19 18:13:52 2013 +0200 @@ -69,6 +69,7 @@ volatile jint MemTracker::_pooled_recorder_count = 0; volatile unsigned long MemTracker::_processing_generation = 0; volatile bool MemTracker::_worker_thread_idle = false; +volatile jint MemTracker::_pending_op_count = 0; volatile bool MemTracker::_slowdown_calling_thread = false; debug_only(intx MemTracker::_main_thread_tid = 0;) NOT_PRODUCT(volatile jint MemTracker::_pending_recorder_count = 0;) @@ -337,92 +338,14 @@ Atomic::inc(&_pooled_recorder_count); } -/* - * This is the most important method in whole nmt implementation. - * - * Create a memory record. - * 1. When nmt is in single-threaded bootstrapping mode, no lock is needed as VM - * still in single thread mode. - * 2. For all threads other than JavaThread, ThreadCritical is needed - * to write to recorders to global recorder. - * 3. For JavaThreads that are not longer visible by safepoint, also - * need to take ThreadCritical and records are written to global - * recorders, since these threads are NOT walked by Threads.do_thread(). - * 4. JavaThreads that are running in native state, have to transition - * to VM state before writing to per-thread recorders. - * 5. JavaThreads that are running in VM state do not need any lock and - * records are written to per-thread recorders. - * 6. For a thread has yet to attach VM 'Thread', they need to take - * ThreadCritical to write to global recorder. - * - * Important note: - * NO LOCK should be taken inside ThreadCritical lock !!! - */ -void MemTracker::create_memory_record(address addr, MEMFLAGS flags, - size_t size, address pc, Thread* thread) { - assert(addr != NULL, "Sanity check"); - if (!shutdown_in_progress()) { - // single thread, we just write records direct to global recorder,' - // with any lock - if (_state == NMT_bootstrapping_single_thread) { - assert(_main_thread_tid == os::current_thread_id(), "wrong thread"); - thread = NULL; - } else { - if (thread == NULL) { - // don't use Thread::current(), since it is possible that - // the calling thread has yet to attach to VM 'Thread', - // which will result assertion failure - thread = ThreadLocalStorage::thread(); - } - } - - if (thread != NULL) { - // slow down all calling threads except NMT worker thread, so it - // can catch up. - if (_slowdown_calling_thread && thread != _worker_thread) { - os::yield_all(); - } - - if (thread->is_Java_thread() && ((JavaThread*)thread)->is_safepoint_visible()) { - JavaThread* java_thread = (JavaThread*)thread; - JavaThreadState state = java_thread->thread_state(); - if (SafepointSynchronize::safepoint_safe(java_thread, state)) { - // JavaThreads that are safepoint safe, can run through safepoint, - // so ThreadCritical is needed to ensure no threads at safepoint create - // new records while the records are being gathered and the sequence number is changing - ThreadCritical tc; - create_record_in_recorder(addr, flags, size, pc, java_thread); - } else { - create_record_in_recorder(addr, flags, size, pc, java_thread); - } - } else { - // other threads, such as worker and watcher threads, etc. need to - // take ThreadCritical to write to global recorder - ThreadCritical tc; - create_record_in_recorder(addr, flags, size, pc, NULL); - } - } else { - if (_state == NMT_bootstrapping_single_thread) { - // single thread, no lock needed - create_record_in_recorder(addr, flags, size, pc, NULL); - } else { - // for thread has yet to attach VM 'Thread', we can not use VM mutex. - // use native thread critical instead - ThreadCritical tc; - create_record_in_recorder(addr, flags, size, pc, NULL); - } - } - } -} - // write a record to proper recorder. No lock can be taken from this method // down. -void MemTracker::create_record_in_recorder(address addr, MEMFLAGS flags, - size_t size, address pc, JavaThread* thread) { +void MemTracker::write_tracking_record(address addr, MEMFLAGS flags, + size_t size, jint seq, address pc, JavaThread* thread) { MemRecorder* rc = get_thread_recorder(thread); if (rc != NULL) { - rc->record(addr, flags, size, pc); + rc->record(addr, flags, size, seq, pc); } } @@ -487,39 +410,43 @@ return; } } - _sync_point_skip_count = 0; { // This method is running at safepoint, with ThreadCritical lock, // it should guarantee that NMT is fully sync-ed. ThreadCritical tc; - SequenceGenerator::reset(); + // We can NOT execute NMT sync-point if there are pending tracking ops. + if (_pending_op_count == 0) { + SequenceGenerator::reset(); + _sync_point_skip_count = 0; - // walk all JavaThreads to collect recorders - SyncThreadRecorderClosure stc; - Threads::threads_do(&stc); + // walk all JavaThreads to collect recorders + SyncThreadRecorderClosure stc; + Threads::threads_do(&stc); + + _thread_count = stc.get_thread_count(); + MemRecorder* pending_recorders = get_pending_recorders(); - _thread_count = stc.get_thread_count(); - MemRecorder* pending_recorders = get_pending_recorders(); + if (_global_recorder != NULL) { + _global_recorder->set_next(pending_recorders); + pending_recorders = _global_recorder; + _global_recorder = NULL; + } - if (_global_recorder != NULL) { - _global_recorder->set_next(pending_recorders); - pending_recorders = _global_recorder; - _global_recorder = NULL; + // see if NMT has too many outstanding recorder instances, it usually + // means that worker thread is lagging behind in processing them. + if (!AutoShutdownNMT) { + _slowdown_calling_thread = (MemRecorder::_instance_count > MAX_RECORDER_THREAD_RATIO * _thread_count); + } + + // check _worker_thread with lock to avoid racing condition + if (_worker_thread != NULL) { + _worker_thread->at_sync_point(pending_recorders, InstanceKlass::number_of_instance_classes()); + } + assert(SequenceGenerator::peek() == 1, "Should not have memory activities during sync-point"); + } else { + _sync_point_skip_count ++; } - - // see if NMT has too many outstanding recorder instances, it usually - // means that worker thread is lagging behind in processing them. - if (!AutoShutdownNMT) { - _slowdown_calling_thread = (MemRecorder::_instance_count > MAX_RECORDER_THREAD_RATIO * _thread_count); - } - - // check _worker_thread with lock to avoid racing condition - if (_worker_thread != NULL) { - _worker_thread->at_sync_point(pending_recorders, InstanceKlass::number_of_instance_classes()); - } - - assert(SequenceGenerator::peek() == 1, "Should not have memory activities during sync-point"); } } @@ -708,3 +635,243 @@ } #endif + +// Tracker Implementation + +/* + * Create a tracker. + * This is a fairly complicated constructor, as it has to make two important decisions: + * 1) Does it need to take ThreadCritical lock to write tracking record + * 2) Does it need to pre-reserve a sequence number for the tracking record + * + * The rules to determine if ThreadCritical is needed: + * 1. When nmt is in single-threaded bootstrapping mode, no lock is needed as VM + * still in single thread mode. + * 2. For all threads other than JavaThread, ThreadCritical is needed + * to write to recorders to global recorder. + * 3. For JavaThreads that are no longer visible by safepoint, also + * need to take ThreadCritical and records are written to global + * recorders, since these threads are NOT walked by Threads.do_thread(). + * 4. JavaThreads that are running in safepoint-safe states do not stop + * for safepoints, ThreadCritical lock should be taken to write + * memory records. + * 5. JavaThreads that are running in VM state do not need any lock and + * records are written to per-thread recorders. + * 6. For a thread has yet to attach VM 'Thread', they need to take + * ThreadCritical to write to global recorder. + * + * The memory operations that need pre-reserve sequence numbers: + * The memory operations that "release" memory blocks and the + * operations can fail, need to pre-reserve sequence number. They + * are realloc, uncommit and release. + * + * The reason for pre-reserve sequence number, is to prevent race condition: + * Thread 1 Thread 2 + * + * + * + * + * if Thread 2 happens to obtain the memory address Thread 1 just released, + * then NMT can mistakenly report the memory is free. + * + * Noticeably, free() does not need pre-reserve sequence number, because the call + * does not fail, so we can alway write "release" record before the memory is actaully + * freed. + * + * For realloc, uncommit and release, following coding pattern should be used: + * + * MemTracker::Tracker tkr = MemTracker::get_realloc_tracker(); + * ptr = ::realloc(...); + * if (ptr == NULL) { + * tkr.record(...) + * } else { + * tkr.discard(); + * } + * + * MemTracker::Tracker tkr = MemTracker::get_virtual_memory_uncommit_tracker(); + * if (uncommit(...)) { + * tkr.record(...); + * } else { + * tkr.discard(); + * } + * + * MemTracker::Tracker tkr = MemTracker::get_virtual_memory_release_tracker(); + * if (release(...)) { + * tkr.record(...); + * } else { + * tkr.discard(); + * } + * + * Since pre-reserved sequence number is only good for the generation that it is acquired, + * when there is pending Tracker that reserved sequence number, NMT sync-point has + * to be skipped to prevent from advancing generation. This is done by inc and dec + * MemTracker::_pending_op_count, when MemTracker::_pending_op_count > 0, NMT sync-point is skipped. + * Not all pre-reservation of sequence number will increment pending op count. For JavaThreads + * that honor safepoints, safepoint can not occur during the memory operations, so the + * pre-reserved sequence number won't cross the generation boundry. + */ +MemTracker::Tracker::Tracker(MemoryOperation op, Thread* thr) { + _op = NoOp; + _seq = 0; + if (MemTracker::is_on()) { + _java_thread = NULL; + _op = op; + + // figure out if ThreadCritical lock is needed to write this operation + // to MemTracker + if (MemTracker::is_single_threaded_bootstrap()) { + thr = NULL; + } else if (thr == NULL) { + // don't use Thread::current(), since it is possible that + // the calling thread has yet to attach to VM 'Thread', + // which will result assertion failure + thr = ThreadLocalStorage::thread(); + } + + if (thr != NULL) { + // Check NMT load + MemTracker::check_NMT_load(thr); + + if (thr->is_Java_thread() && ((JavaThread*)thr)->is_safepoint_visible()) { + _java_thread = (JavaThread*)thr; + JavaThreadState state = _java_thread->thread_state(); + // JavaThreads that are safepoint safe, can run through safepoint, + // so ThreadCritical is needed to ensure no threads at safepoint create + // new records while the records are being gathered and the sequence number is changing + _need_thread_critical_lock = + SafepointSynchronize::safepoint_safe(_java_thread, state); + } else { + _need_thread_critical_lock = true; + } + } else { + _need_thread_critical_lock + = !MemTracker::is_single_threaded_bootstrap(); + } + + // see if we need to pre-reserve sequence number for this operation + if (_op == Realloc || _op == Uncommit || _op == Release) { + if (_need_thread_critical_lock) { + ThreadCritical tc; + MemTracker::inc_pending_op_count(); + _seq = SequenceGenerator::next(); + } else { + // for the threads that honor safepoints, no safepoint can occur + // during the lifespan of tracker, so we don't need to increase + // pending op count. + _seq = SequenceGenerator::next(); + } + } + } +} + +void MemTracker::Tracker::discard() { + if (MemTracker::is_on() && _seq != 0) { + if (_need_thread_critical_lock) { + ThreadCritical tc; + MemTracker::dec_pending_op_count(); + } + _seq = 0; + } +} + + +void MemTracker::Tracker::record(address old_addr, address new_addr, size_t size, + MEMFLAGS flags, address pc) { + assert(old_addr != NULL && new_addr != NULL, "Sanity check"); + assert(_op == Realloc || _op == NoOp, "Wrong call"); + if (MemTracker::is_on() && NMT_CAN_TRACK(flags) && _op != NoOp) { + assert(_seq > 0, "Need pre-reserve sequence number"); + if (_need_thread_critical_lock) { + ThreadCritical tc; + // free old address, use pre-reserved sequence number + MemTracker::write_tracking_record(old_addr, MemPointerRecord::free_tag(), + 0, _seq, pc, _java_thread); + MemTracker::write_tracking_record(new_addr, flags | MemPointerRecord::malloc_tag(), + size, SequenceGenerator::next(), pc, _java_thread); + // decrement MemTracker pending_op_count + MemTracker::dec_pending_op_count(); + } else { + // free old address, use pre-reserved sequence number + MemTracker::write_tracking_record(old_addr, MemPointerRecord::free_tag(), + 0, _seq, pc, _java_thread); + MemTracker::write_tracking_record(new_addr, flags | MemPointerRecord::malloc_tag(), + size, SequenceGenerator::next(), pc, _java_thread); + } + _seq = 0; + } +} + +void MemTracker::Tracker::record(address addr, size_t size, MEMFLAGS flags, address pc) { + // OOM already? + if (addr == NULL) return; + + if (MemTracker::is_on() && NMT_CAN_TRACK(flags) && _op != NoOp) { + bool pre_reserved_seq = (_seq != 0); + address pc = CALLER_CALLER_PC; + MEMFLAGS orig_flags = flags; + + // or the tagging flags + switch(_op) { + case Malloc: + flags |= MemPointerRecord::malloc_tag(); + break; + case Free: + flags = MemPointerRecord::free_tag(); + break; + case Realloc: + fatal("Use the other Tracker::record()"); + break; + case Reserve: + case ReserveAndCommit: + flags |= MemPointerRecord::virtual_memory_reserve_tag(); + break; + case Commit: + flags = MemPointerRecord::virtual_memory_commit_tag(); + break; + case Type: + flags |= MemPointerRecord::virtual_memory_type_tag(); + break; + case Uncommit: + assert(pre_reserved_seq, "Need pre-reserve sequence number"); + flags = MemPointerRecord::virtual_memory_uncommit_tag(); + break; + case Release: + assert(pre_reserved_seq, "Need pre-reserve sequence number"); + flags = MemPointerRecord::virtual_memory_release_tag(); + break; + case ArenaSize: + // a bit of hack here, add a small postive offset to arena + // address for its size record, so the size record is sorted + // right after arena record. + flags = MemPointerRecord::arena_size_tag(); + addr += sizeof(void*); + break; + case StackRelease: + flags = MemPointerRecord::virtual_memory_release_tag(); + break; + default: + ShouldNotReachHere(); + } + + // write memory tracking record + if (_need_thread_critical_lock) { + ThreadCritical tc; + if (_seq == 0) _seq = SequenceGenerator::next(); + MemTracker::write_tracking_record(addr, flags, size, _seq, pc, _java_thread); + if (_op == ReserveAndCommit) { + MemTracker::write_tracking_record(addr, orig_flags | MemPointerRecord::virtual_memory_commit_tag(), + size, SequenceGenerator::next(), pc, _java_thread); + } + if (pre_reserved_seq) MemTracker::dec_pending_op_count(); + } else { + if (_seq == 0) _seq = SequenceGenerator::next(); + MemTracker::write_tracking_record(addr, flags, size, _seq, pc, _java_thread); + if (_op == ReserveAndCommit) { + MemTracker::write_tracking_record(addr, orig_flags | MemPointerRecord::virtual_memory_commit_tag(), + size, SequenceGenerator::next(), pc, _java_thread); + } + } + _seq = 0; + } +} + diff -r f9709e27a876 -r 726d2d4913fc src/share/vm/services/memTracker.hpp --- a/src/share/vm/services/memTracker.hpp Fri Jun 14 07:27:22 2013 -0700 +++ b/src/share/vm/services/memTracker.hpp Wed Jun 19 18:13:52 2013 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -54,6 +54,18 @@ NMT_sequence_overflow // overflow the sequence number }; + class Tracker { + public: + void discard() { } + + void record(address addr, size_t size = 0, MEMFLAGS flags = mtNone, address pc = NULL) { } + void record(address old_addr, address new_addr, size_t size, + MEMFLAGS flags, address pc = NULL) { } + }; + + private: + static Tracker _tkr; + public: static inline void init_tracking_options(const char* option_line) { } @@ -68,19 +80,18 @@ static inline void record_malloc(address addr, size_t size, MEMFLAGS flags, address pc = 0, Thread* thread = NULL) { } static inline void record_free(address addr, MEMFLAGS flags, Thread* thread = NULL) { } - static inline void record_realloc(address old_addr, address new_addr, size_t size, - MEMFLAGS flags, address pc = 0, Thread* thread = NULL) { } static inline void record_arena_size(address addr, size_t size) { } static inline void record_virtual_memory_reserve(address addr, size_t size, - address pc = 0, Thread* thread = NULL) { } + MEMFLAGS flags, address pc = 0, Thread* thread = NULL) { } + static inline void record_virtual_memory_reserve_and_commit(address addr, size_t size, + MEMFLAGS flags, address pc = 0, Thread* thread = NULL) { } static inline void record_virtual_memory_commit(address addr, size_t size, address pc = 0, Thread* thread = NULL) { } - static inline void record_virtual_memory_uncommit(address addr, size_t size, - Thread* thread = NULL) { } - static inline void record_virtual_memory_release(address addr, size_t size, - Thread* thread = NULL) { } static inline void record_virtual_memory_type(address base, MEMFLAGS flags, Thread* thread = NULL) { } + static inline Tracker get_realloc_tracker() { return _tkr; } + static inline Tracker get_virtual_memory_uncommit_tracker() { return _tkr; } + static inline Tracker get_virtual_memory_release_tracker() { return _tkr; } static inline bool baseline() { return false; } static inline bool has_baseline() { return false; } @@ -165,6 +176,45 @@ }; public: + class Tracker : public StackObj { + friend class MemTracker; + public: + enum MemoryOperation { + NoOp, // no op + Malloc, // malloc + Realloc, // realloc + Free, // free + Reserve, // virtual memory reserve + Commit, // virtual memory commit + ReserveAndCommit, // virtual memory reserve and commit + StackAlloc = ReserveAndCommit, // allocate thread stack + Type, // assign virtual memory type + Uncommit, // virtual memory uncommit + Release, // virtual memory release + ArenaSize, // set arena size + StackRelease // release thread stack + }; + + + protected: + Tracker(MemoryOperation op, Thread* thr = NULL); + + public: + void discard(); + + void record(address addr, size_t size = 0, MEMFLAGS flags = mtNone, address pc = NULL); + void record(address old_addr, address new_addr, size_t size, + MEMFLAGS flags, address pc = NULL); + + private: + bool _need_thread_critical_lock; + JavaThread* _java_thread; + MemoryOperation _op; // memory operation + jint _seq; // reserved sequence number + }; + + + public: // native memory tracking level enum NMTLevel { NMT_off, // native memory tracking is off @@ -276,109 +326,74 @@ // record a 'malloc' call static inline void record_malloc(address addr, size_t size, MEMFLAGS flags, address pc = 0, Thread* thread = NULL) { - if (is_on() && NMT_CAN_TRACK(flags)) { - assert(size > 0, "Sanity check"); - create_memory_record(addr, (flags|MemPointerRecord::malloc_tag()), size, pc, thread); - } + Tracker tkr(Tracker::Malloc, thread); + tkr.record(addr, size, flags, pc); } // record a 'free' call static inline void record_free(address addr, MEMFLAGS flags, Thread* thread = NULL) { - if (is_on() && NMT_CAN_TRACK(flags)) { - create_memory_record(addr, MemPointerRecord::free_tag(), 0, 0, thread); - } - } - // record a 'realloc' call - static inline void record_realloc(address old_addr, address new_addr, size_t size, - MEMFLAGS flags, address pc = 0, Thread* thread = NULL) { - if (is_on() && NMT_CAN_TRACK(flags)) { - assert(size > 0, "Sanity check"); - record_free(old_addr, flags, thread); - record_malloc(new_addr, size, flags, pc, thread); - } + Tracker tkr(Tracker::Free, thread); + tkr.record(addr, 0, flags, DEBUG_CALLER_PC); } - // record arena memory size static inline void record_arena_size(address addr, size_t size) { - // we add a positive offset to arena address, so we can have arena memory record - // sorted after arena record - if (is_on() && !UseMallocOnly) { - assert(addr != NULL, "Sanity check"); - create_memory_record((addr + sizeof(void*)), MemPointerRecord::arena_size_tag(), size, - DEBUG_CALLER_PC, NULL); - } + Tracker tkr(Tracker::ArenaSize); + tkr.record(addr, size); } // record a virtual memory 'reserve' call static inline void record_virtual_memory_reserve(address addr, size_t size, - address pc = 0, Thread* thread = NULL) { - if (is_on()) { - assert(size > 0, "Sanity check"); - create_memory_record(addr, MemPointerRecord::virtual_memory_reserve_tag(), - size, pc, thread); - } + MEMFLAGS flags, address pc = 0, Thread* thread = NULL) { + assert(size > 0, "Sanity check"); + Tracker tkr(Tracker::Reserve, thread); + tkr.record(addr, size, flags, pc); } static inline void record_thread_stack(address addr, size_t size, Thread* thr, address pc = 0) { - if (is_on()) { - assert(size > 0 && thr != NULL, "Sanity check"); - create_memory_record(addr, MemPointerRecord::virtual_memory_reserve_tag() | mtThreadStack, - size, pc, thr); - create_memory_record(addr, MemPointerRecord::virtual_memory_commit_tag() | mtThreadStack, - size, pc, thr); - } + Tracker tkr(Tracker::StackAlloc, thr); + tkr.record(addr, size, mtThreadStack, pc); } static inline void release_thread_stack(address addr, size_t size, Thread* thr) { - if (is_on()) { - assert(size > 0 && thr != NULL, "Sanity check"); - assert(!thr->is_Java_thread(), "too early"); - create_memory_record(addr, MemPointerRecord::virtual_memory_uncommit_tag() | mtThreadStack, - size, DEBUG_CALLER_PC, thr); - create_memory_record(addr, MemPointerRecord::virtual_memory_release_tag() | mtThreadStack, - size, DEBUG_CALLER_PC, thr); - } + Tracker tkr(Tracker::StackRelease, thr); + tkr.record(addr, size, mtThreadStack, DEBUG_CALLER_PC); } // record a virtual memory 'commit' call static inline void record_virtual_memory_commit(address addr, size_t size, address pc, Thread* thread = NULL) { - if (is_on()) { - assert(size > 0, "Sanity check"); - create_memory_record(addr, MemPointerRecord::virtual_memory_commit_tag(), - size, pc, thread); - } + Tracker tkr(Tracker::Commit, thread); + tkr.record(addr, size, mtNone, pc); } - // record a virtual memory 'uncommit' call - static inline void record_virtual_memory_uncommit(address addr, size_t size, - Thread* thread = NULL) { - if (is_on()) { - assert(size > 0, "Sanity check"); - create_memory_record(addr, MemPointerRecord::virtual_memory_uncommit_tag(), - size, DEBUG_CALLER_PC, thread); - } + static inline void record_virtual_memory_reserve_and_commit(address addr, size_t size, + MEMFLAGS flags, address pc, Thread* thread = NULL) { + Tracker tkr(Tracker::ReserveAndCommit, thread); + tkr.record(addr, size, flags, pc); } - // record a virtual memory 'release' call - static inline void record_virtual_memory_release(address addr, size_t size, - Thread* thread = NULL) { - if (is_on()) { - assert(size > 0, "Sanity check"); - create_memory_record(addr, MemPointerRecord::virtual_memory_release_tag(), - size, DEBUG_CALLER_PC, thread); - } - } // record memory type on virtual memory base address static inline void record_virtual_memory_type(address base, MEMFLAGS flags, Thread* thread = NULL) { - if (is_on()) { - assert(base > 0, "wrong base address"); - assert((flags & (~mt_masks)) == 0, "memory type only"); - create_memory_record(base, (flags | MemPointerRecord::virtual_memory_type_tag()), - 0, DEBUG_CALLER_PC, thread); - } + Tracker tkr(Tracker::Type); + tkr.record(base, 0, flags); + } + + // Get memory trackers for memory operations that can result race conditions. + // The memory tracker has to be obtained before realloc, virtual memory uncommit + // and virtual memory release, and call tracker.record() method if operation + // succeeded, or tracker.discard() to abort the tracking. + static inline Tracker get_realloc_tracker() { + return Tracker(Tracker::Realloc); + } + + static inline Tracker get_virtual_memory_uncommit_tracker() { + return Tracker(Tracker::Uncommit); + } + + static inline Tracker get_virtual_memory_release_tracker() { + return Tracker(Tracker::Release); } @@ -444,6 +459,31 @@ static MemRecorder* get_pending_recorders(); static void delete_all_pending_recorders(); + // write a memory tracking record in recorder + static void write_tracking_record(address addr, MEMFLAGS type, + size_t size, jint seq, address pc, JavaThread* thread); + + static bool is_single_threaded_bootstrap() { + return _state == NMT_bootstrapping_single_thread; + } + + static void check_NMT_load(Thread* thr) { + assert(thr != NULL, "Sanity check"); + if (_slowdown_calling_thread && thr != _worker_thread) { + os::yield_all(); + } + } + + static void inc_pending_op_count() { + Atomic::inc(&_pending_op_count); + } + + static void dec_pending_op_count() { + Atomic::dec(&_pending_op_count); + assert(_pending_op_count >= 0, "Sanity check"); + } + + private: // retrieve a pooled memory record or create new one if there is not // one available @@ -522,6 +562,12 @@ // if NMT should slow down calling thread to allow // worker thread to catch up static volatile bool _slowdown_calling_thread; + + // pending memory op count. + // Certain memory ops need to pre-reserve sequence number + // before memory operation can happen to avoid race condition. + // See MemTracker::Tracker for detail + static volatile jint _pending_op_count; }; #endif // !INCLUDE_NMT diff -r f9709e27a876 -r 726d2d4913fc src/share/vm/services/threadService.cpp --- a/src/share/vm/services/threadService.cpp Fri Jun 14 07:27:22 2013 -0700 +++ b/src/share/vm/services/threadService.cpp Wed Jun 19 18:13:52 2013 +0200 @@ -327,27 +327,30 @@ while (waitingToLockMonitor != NULL || waitingToLockBlocker != NULL) { cycle->add_thread(currentThread); if (waitingToLockMonitor != NULL) { - currentThread = Threads::owning_thread_from_monitor_owner( - (address)waitingToLockMonitor->owner(), - false /* no locking needed */); - if (currentThread == NULL) { - // This function is called at a safepoint so the JavaThread - // that owns waitingToLockMonitor should be findable, but - // if it is not findable, then the previous currentThread is - // blocked permanently. We record this as a deadlock. - num_deadlocks++; + address currentOwner = (address)waitingToLockMonitor->owner(); + if (currentOwner != NULL) { + currentThread = Threads::owning_thread_from_monitor_owner( + currentOwner, + false /* no locking needed */); + if (currentThread == NULL) { + // This function is called at a safepoint so the JavaThread + // that owns waitingToLockMonitor should be findable, but + // if it is not findable, then the previous currentThread is + // blocked permanently. We record this as a deadlock. + num_deadlocks++; - cycle->set_deadlock(true); + cycle->set_deadlock(true); - // add this cycle to the deadlocks list - if (deadlocks == NULL) { - deadlocks = cycle; - } else { - last->set_next(cycle); + // add this cycle to the deadlocks list + if (deadlocks == NULL) { + deadlocks = cycle; + } else { + last->set_next(cycle); + } + last = cycle; + cycle = new DeadlockCycle(); + break; } - last = cycle; - cycle = new DeadlockCycle(); - break; } } else { if (concurrent_locks) { diff -r f9709e27a876 -r 726d2d4913fc src/share/vm/utilities/exceptions.hpp --- a/src/share/vm/utilities/exceptions.hpp Fri Jun 14 07:27:22 2013 -0700 +++ b/src/share/vm/utilities/exceptions.hpp Wed Jun 19 18:13:52 2013 +0200 @@ -194,15 +194,15 @@ #define HAS_PENDING_EXCEPTION (((ThreadShadow*)THREAD)->has_pending_exception()) #define CLEAR_PENDING_EXCEPTION (((ThreadShadow*)THREAD)->clear_pending_exception()) -#define CHECK THREAD); if (HAS_PENDING_EXCEPTION) return ; (0 -#define CHECK_(result) THREAD); if (HAS_PENDING_EXCEPTION) return result; (0 +#define CHECK THREAD); if (HAS_PENDING_EXCEPTION) return ; (void)(0 +#define CHECK_(result) THREAD); if (HAS_PENDING_EXCEPTION) return result; (void)(0 #define CHECK_0 CHECK_(0) #define CHECK_NH CHECK_(Handle()) #define CHECK_NULL CHECK_(NULL) #define CHECK_false CHECK_(false) -#define CHECK_AND_CLEAR THREAD); if (HAS_PENDING_EXCEPTION) { CLEAR_PENDING_EXCEPTION; return; } (0 -#define CHECK_AND_CLEAR_(result) THREAD); if (HAS_PENDING_EXCEPTION) { CLEAR_PENDING_EXCEPTION; return result; } (0 +#define CHECK_AND_CLEAR THREAD); if (HAS_PENDING_EXCEPTION) { CLEAR_PENDING_EXCEPTION; return; } (void)(0 +#define CHECK_AND_CLEAR_(result) THREAD); if (HAS_PENDING_EXCEPTION) { CLEAR_PENDING_EXCEPTION; return result; } (void)(0 #define CHECK_AND_CLEAR_0 CHECK_AND_CLEAR_(0) #define CHECK_AND_CLEAR_NH CHECK_AND_CLEAR_(Handle()) #define CHECK_AND_CLEAR_NULL CHECK_AND_CLEAR_(NULL) @@ -282,7 +282,7 @@ CLEAR_PENDING_EXCEPTION; \ ex->print(); \ ShouldNotReachHere(); \ - } (0 + } (void)(0 // ExceptionMark is a stack-allocated helper class for local exception handling. // It is used with the EXCEPTION_MARK macro. diff -r f9709e27a876 -r 726d2d4913fc src/share/vm/utilities/taskqueue.hpp --- a/src/share/vm/utilities/taskqueue.hpp Fri Jun 14 07:27:22 2013 -0700 +++ b/src/share/vm/utilities/taskqueue.hpp Wed Jun 19 18:13:52 2013 +0200 @@ -340,8 +340,12 @@ if (dirty_n_elems == N - 1) { // Actually means 0, so do the push. uint localBot = _bottom; - // g++ complains if the volatile result of the assignment is unused. - const_cast(_elems[localBot] = t); + // g++ complains if the volatile result of the assignment is + // unused, so we cast the volatile away. We cannot cast directly + // to void, because gcc treats that as not using the result of the + // assignment. However, casting to E& means that we trigger an + // unused-value warning. So, we cast the E& to void. + (void)const_cast(_elems[localBot] = t); OrderAccess::release_store(&_bottom, increment_index(localBot)); TASKQUEUE_STATS_ONLY(stats.record_push()); return true; @@ -397,7 +401,12 @@ return false; } - const_cast(t = _elems[oldAge.top()]); + // g++ complains if the volatile result of the assignment is + // unused, so we cast the volatile away. We cannot cast directly + // to void, because gcc treats that as not using the result of the + // assignment. However, casting to E& means that we trigger an + // unused-value warning. So, we cast the E& to void. + (void) const_cast(t = _elems[oldAge.top()]); Age newAge(oldAge); newAge.increment(); Age resAge = _age.cmpxchg(newAge, oldAge); @@ -640,8 +649,12 @@ uint dirty_n_elems = dirty_size(localBot, top); assert(dirty_n_elems < N, "n_elems out of range."); if (dirty_n_elems < max_elems()) { - // g++ complains if the volatile result of the assignment is unused. - const_cast(_elems[localBot] = t); + // g++ complains if the volatile result of the assignment is + // unused, so we cast the volatile away. We cannot cast directly + // to void, because gcc treats that as not using the result of the + // assignment. However, casting to E& means that we trigger an + // unused-value warning. So, we cast the E& to void. + (void) const_cast(_elems[localBot] = t); OrderAccess::release_store(&_bottom, increment_index(localBot)); TASKQUEUE_STATS_ONLY(stats.record_push()); return true; @@ -665,7 +678,12 @@ // This is necessary to prevent any read below from being reordered // before the store just above. OrderAccess::fence(); - const_cast(t = _elems[localBot]); + // g++ complains if the volatile result of the assignment is + // unused, so we cast the volatile away. We cannot cast directly + // to void, because gcc treats that as not using the result of the + // assignment. However, casting to E& means that we trigger an + // unused-value warning. So, we cast the E& to void. + (void) const_cast(t = _elems[localBot]); // This is a second read of "age"; the "size()" above is the first. // If there's still at least one element in the queue, based on the // "_bottom" and "age" we've read, then there can be no interference with diff -r f9709e27a876 -r 726d2d4913fc test/runtime/CommandLine/CompilerConfigFileWarning.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/CommandLine/CompilerConfigFileWarning.java Wed Jun 19 18:13:52 2013 +0200 @@ -0,0 +1,50 @@ +/* + * Copyright (c) 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 7167142 + * @summary Warn if unused .hotspot_compiler file is present + * @library /testlibrary + */ + +import java.io.PrintWriter; +import com.oracle.java.testlibrary.*; + +public class CompilerConfigFileWarning { + public static void main(String[] args) throws Exception { + String vmVersion = System.getProperty("java.vm.version"); + if (vmVersion.toLowerCase().contains("debug") || vmVersion.toLowerCase().contains("jvmg")) { + System.out.println("Skip on debug builds since we'll always read the file there"); + return; + } + + PrintWriter pw = new PrintWriter(".hotspot_compiler"); + pw.println("aa"); + pw.close(); + + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-version"); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldContain("warning: .hotspot_compiler file is present but has been ignored. Run with -XX:CompileCommandFile=.hotspot_compiler to load the file."); + } +} diff -r f9709e27a876 -r 726d2d4913fc test/runtime/CommandLine/ConfigFileWarning.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/CommandLine/ConfigFileWarning.java Wed Jun 19 18:13:52 2013 +0200 @@ -0,0 +1,50 @@ +/* + * Copyright (c) 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 7167142 + * @summary Warn if unused .hotspot_rc file is present + * @library /testlibrary + */ + +import java.io.PrintWriter; +import com.oracle.java.testlibrary.*; + +public class ConfigFileWarning { + public static void main(String[] args) throws Exception { + String vmVersion = System.getProperty("java.vm.version"); + if (vmVersion.toLowerCase().contains("debug") || vmVersion.toLowerCase().contains("jvmg")) { + System.out.println("Skip on debug builds since we'll always read the file there"); + return; + } + + PrintWriter pw = new PrintWriter(".hotspotrc"); + pw.println("aa"); + pw.close(); + + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-version"); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldContain("warning: .hotspotrc file is present but has been ignored. Run with -XX:Flags=.hotspotrc to load the file."); + } +} diff -r f9709e27a876 -r 726d2d4913fc test/runtime/SharedArchiveFile/CdsDifferentObjectAlignment.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/SharedArchiveFile/CdsDifferentObjectAlignment.java Wed Jun 19 18:13:52 2013 +0200 @@ -0,0 +1,88 @@ +/* + * Copyright (c) 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test CdsDifferentObjectAlignment + * @summary Testing CDS (class data sharing) using varying object alignment. + * Using different object alignment for each dump/load pair. + * This is a negative test; using object alignment for loading that + * is different from object alignment for creating a CDS file + * should fail when loading. + * @library /testlibrary + */ + +import com.oracle.java.testlibrary.*; + +public class CdsDifferentObjectAlignment { + public static void main(String[] args) throws Exception { + String nativeWordSize = System.getProperty("sun.arch.data.model"); + if (!Platform.is64bit()) { + System.out.println("ObjectAlignmentInBytes for CDS is only " + + "supported on 64bit platforms; this plaform is " + + nativeWordSize); + System.out.println("Skipping the test"); + } else { + createAndLoadSharedArchive(16, 64); + createAndLoadSharedArchive(64, 32); + } + } + + + // Parameters are object alignment expressed in bytes + private static void + createAndLoadSharedArchive(int createAlignment, int loadAlignment) + throws Exception { + String createAlignmentArgument = "-XX:ObjectAlignmentInBytes=" + + createAlignment; + String loadAlignmentArgument = "-XX:ObjectAlignmentInBytes=" + + loadAlignment; + + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-XX:+UnlockDiagnosticVMOptions", + "-XX:SharedArchiveFile=./sample.jsa", + "-Xshare:dump", + createAlignmentArgument); + + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldContain("Loading classes to share"); + output.shouldHaveExitValue(0); + + pb = ProcessTools.createJavaProcessBuilder( + "-XX:+UnlockDiagnosticVMOptions", + "-XX:SharedArchiveFile=./sample.jsa", + "-Xshare:on", + loadAlignmentArgument, + "-version"); + + output = new OutputAnalyzer(pb.start()); + String expectedErrorMsg = + String.format( + "The shared archive file's ObjectAlignmentInBytes of %d " + + "does not equal the current ObjectAlignmentInBytes of %d", + createAlignment, + loadAlignment); + + output.shouldContain(expectedErrorMsg); + output.shouldHaveExitValue(1); + } +} diff -r f9709e27a876 -r 726d2d4913fc test/runtime/SharedArchiveFile/CdsSameObjectAlignment.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/SharedArchiveFile/CdsSameObjectAlignment.java Wed Jun 19 18:13:52 2013 +0200 @@ -0,0 +1,92 @@ +/* + * Copyright (c) 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test CdsSameObjectAlignment + * @summary Testing CDS (class data sharing) using varying object alignment. + * Using same object alignment for each dump/load pair + * @library /testlibrary + */ + +import com.oracle.java.testlibrary.*; + +public class CdsSameObjectAlignment { + public static void main(String[] args) throws Exception { + String nativeWordSize = System.getProperty("sun.arch.data.model"); + if (!Platform.is64bit()) { + System.out.println("ObjectAlignmentInBytes for CDS is only " + + "supported on 64bit platforms; this plaform is " + + nativeWordSize); + System.out.println("Skipping the test"); + } else { + dumpAndLoadSharedArchive(8); + dumpAndLoadSharedArchive(16); + dumpAndLoadSharedArchive(32); + dumpAndLoadSharedArchive(64); + } + } + + private static void + dumpAndLoadSharedArchive(int objectAlignmentInBytes) throws Exception { + String objectAlignmentArg = "-XX:ObjectAlignmentInBytes=" + + objectAlignmentInBytes; + System.out.println("dumpAndLoadSharedArchive(): objectAlignmentInBytes = " + + objectAlignmentInBytes); + + // create shared archive + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-XX:+UnlockDiagnosticVMOptions", + "-XX:SharedArchiveFile=./sample.jsa", + "-Xshare:dump", + objectAlignmentArg); + + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldContain("Loading classes to share"); + output.shouldHaveExitValue(0); + + + // run using the shared archive + pb = ProcessTools.createJavaProcessBuilder( + "-XX:+UnlockDiagnosticVMOptions", + "-XX:SharedArchiveFile=./sample.jsa", + "-Xshare:on", + objectAlignmentArg, + "-version"); + + output = new OutputAnalyzer(pb.start()); + + try { + output.shouldContain("sharing"); + output.shouldHaveExitValue(0); + } catch (RuntimeException e) { + // CDS uses absolute addresses for performance. + // It will try to reserve memory at a specific address; + // there is a chance such reservation will fail + // If it does, it is NOT considered a failure of the feature, + // rather a possible expected outcome, though not likely + output.shouldContain( + "Unable to reserve shared space at required address"); + output.shouldHaveExitValue(1); + } + } +} diff -r f9709e27a876 -r 726d2d4913fc test/serviceability/threads/TestFalseDeadLock.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/serviceability/threads/TestFalseDeadLock.java Wed Jun 19 18:13:52 2013 +0200 @@ -0,0 +1,95 @@ +/* + * Copyright (c) 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.lang.management.ManagementFactory; +import java.lang.management.ThreadMXBean; +import java.util.Random; + +/* + * @test + * @bug 8016304 + * @summary Make sure no deadlock is reported for this program which has no deadlocks. + * @run main/othervm TestFalseDeadLock + */ + +/* + * This test will not provoke the bug every time it is run since the bug is intermittent. + * The test has a fixed running time of 5 seconds. + */ + +public class TestFalseDeadLock { + private static ThreadMXBean bean; + private static volatile boolean running = true; + private static volatile boolean found = false; + + public static void main(String[] args) throws Exception { + bean = ManagementFactory.getThreadMXBean(); + Thread[] threads = new Thread[500]; + for (int i = 0; i < threads.length; i++) { + Test t = new Test(); + threads[i] = new Thread(t); + threads[i].start(); + } + try { + Thread.sleep(5000); + } catch (InterruptedException ex) { + } + running = false; + for (Thread t : threads) { + t.join(); + } + if (found) { + throw new Exception("Deadlock reported, but there is no deadlock."); + } + } + + public static class Test implements Runnable { + public void run() { + Random r = new Random(); + while (running) { + try { + synchronized (this) { + wait(r.nextInt(1000) + 1); + } + } catch (InterruptedException ex) { + } + recurse(2000); + } + if (bean.findDeadlockedThreads() != null) { + System.out.println("FOUND!"); + found = true; + } + } + + private void recurse(int i) { + if (!running) { + // It is important for the test to call println here + // since there are locks inside that path. + System.out.println("Hullo"); + } + else if (i > 0) { + recurse(i - 1); + } + } + } +} diff -r f9709e27a876 -r 726d2d4913fc test/testlibrary/com/oracle/java/testlibrary/Platform.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/testlibrary/com/oracle/java/testlibrary/Platform.java Wed Jun 19 18:13:52 2013 +0200 @@ -0,0 +1,62 @@ +/* + * Copyright (c) 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.oracle.java.testlibrary; + +public class Platform { + private static final String osName = System.getProperty("os.name"); + private static final String dataModel = System.getProperty("sun.arch.data.model"); + private static final String vmVersion = System.getProperty("java.vm.version"); + + public static boolean is64bit() { + return dataModel.equals("64"); + } + + public static boolean isSolaris() { + return osName.toLowerCase().startsWith("sunos"); + } + + public static boolean isWindows() { + return osName.toLowerCase().startsWith("win"); + } + + public static boolean isOSX() { + return osName.toLowerCase().startsWith("mac"); + } + + public static boolean isLinux() { + return osName.toLowerCase().startsWith("linux"); + } + + public static String getOsName() { + return osName; + } + + public static boolean isDebugBuild() { + return vmVersion.toLowerCase().contains("debug"); + } + + public static String getVMVersion() { + return vmVersion; + } +} diff -r f9709e27a876 -r 726d2d4913fc test/testlibrary/com/oracle/java/testlibrary/ProcessTools.java --- a/test/testlibrary/com/oracle/java/testlibrary/ProcessTools.java Fri Jun 14 07:27:22 2013 -0700 +++ b/test/testlibrary/com/oracle/java/testlibrary/ProcessTools.java Wed Jun 19 18:13:52 2013 +0200 @@ -112,10 +112,8 @@ * @return String[] with platform specific arguments, empty if there are none */ public static String[] getPlatformSpecificVMArgs() { - String osName = System.getProperty("os.name"); - String dataModel = System.getProperty("sun.arch.data.model"); - if (osName.equals("SunOS") && dataModel.equals("64")) { + if (Platform.is64bit() && Platform.isSolaris()) { return new String[] { "-d64" }; }