Mercurial > hg > truffle
changeset 4810:50d9b7a0072c
Merge
author | jrose |
---|---|
date | Thu, 19 Jan 2012 18:35:13 -0800 |
parents | db18ca98d237 (diff) 469e0a46f2fe (current diff) |
children | dcc292399a39 53a127075045 |
files | |
diffstat | 69 files changed, 1977 insertions(+), 947 deletions(-) [+] |
line wrap: on
line diff
--- a/.hgtags Thu Jan 19 17:20:39 2012 -0800 +++ b/.hgtags Thu Jan 19 18:35:13 2012 -0800 @@ -207,3 +207,7 @@ a2fef924d8e6f37dac2a887315e3502876cc8e24 hs23-b08 61165f53f1656b9f99e4fb806429bf98b99d59c3 jdk8-b18 4bcf61041217f8677dcec18e90e9196acc945bba hs23-b09 +9232e0ecbc2cec54dcc8f93004fb00c214446460 jdk8-b19 +fe2c8764998112b7fefcd7d41599714813ae4327 jdk8-b20 +9952d1c439d64c5fd4ad1236a63a62bd5a49d4c3 jdk8-b21 +513351373923f74a7c91755748b95c9771e59f96 hs23-b10
--- a/make/Makefile Thu Jan 19 17:20:39 2012 -0800 +++ b/make/Makefile Thu Jan 19 18:35:13 2012 -0800 @@ -367,7 +367,7 @@ $(EXPORT_LIB_DIR)/%.jar: $(GEN_DIR)/%.jar $(install-file) -# Include files (jvmti.h, jvmticmlr.h, jni.h, $(JDK_INCLUDE_SUBDIR)/jni_md.h, jmm.h) +# Include files (jvmti.h, jvmticmlr.h, jni.h, $(JDK_INCLUDE_SUBDIR)/jni_md.h, jmm.h, jfr.h) $(EXPORT_INCLUDE_DIR)/%: $(GEN_DIR)/jvmtifiles/% $(install-file) @@ -384,6 +384,16 @@ $(EXPORT_INCLUDE_DIR)/%: $(HS_SRC_DIR)/share/vm/services/% $(install-file) +JFR_EXISTS=$(shell if [ -d $(HS_ALT_SRC) ]; then echo 1; else echo 0; fi) +# export jfr.h +ifeq ($JFR_EXISTS,1) +$(EXPORT_INCLUDE_DIR)/%: $(HS_ALT_SRC)/share/vm/jfr/agent/% + $(install-file) +else +$(EXPORT_INCLUDE_DIR)/jfr.h: + +endif + # Doc files (jvmti.html) $(EXPORT_DOCS_DIR)/platform/jvmti/%: $(DOCS_DIR)/% $(install-file)
--- a/make/bsd/makefiles/vm.make Thu Jan 19 17:20:39 2012 -0800 +++ b/make/bsd/makefiles/vm.make Thu Jan 19 18:35:13 2012 -0800 @@ -96,6 +96,10 @@ CPPFLAGS += -DDEFAULT_LIBPATH="\"$(DEFAULT_LIBPATH)\"" endif +ifndef JAVASE_EMBEDDED +CFLAGS += -DINCLUDE_TRACE +endif + # CFLAGS_WARN holds compiler options to suppress/enable warnings. CFLAGS += $(CFLAGS_WARN/BYFILE) @@ -147,6 +151,12 @@ SOURCE_PATHS+=$(HS_COMMON_SRC)/cpu/$(Platform_arch)/vm SOURCE_PATHS+=$(HS_COMMON_SRC)/os_cpu/$(Platform_os_arch)/vm +ifndef JAVASE_EMBEDDED +SOURCE_PATHS+=$(shell if [ -d $(HS_ALT_SRC)/share/vm/jfr ]; then \ + find $(HS_ALT_SRC)/share/vm/jfr -type d; \ + fi) +endif + CORE_PATHS=$(foreach path,$(SOURCE_PATHS),$(call altsrc,$(path)) $(path)) CORE_PATHS+=$(GENERATED)/jvmtifiles
--- a/make/defs.make Thu Jan 19 17:20:39 2012 -0800 +++ b/make/defs.make Thu Jan 19 18:35:13 2012 -0800 @@ -294,3 +294,7 @@ EXPORT_LIST += $(EXPORT_INCLUDE_DIR)/jni.h EXPORT_LIST += $(EXPORT_INCLUDE_DIR)/$(JDK_INCLUDE_SUBDIR)/jni_md.h EXPORT_LIST += $(EXPORT_INCLUDE_DIR)/jmm.h + +ifndef JAVASE_EMBEDDED +EXPORT_LIST += $(EXPORT_INCLUDE_DIR)/jfr.h +endif
--- a/make/hotspot_version Thu Jan 19 17:20:39 2012 -0800 +++ b/make/hotspot_version Thu Jan 19 18:35:13 2012 -0800 @@ -35,7 +35,7 @@ HS_MAJOR_VER=23 HS_MINOR_VER=0 -HS_BUILD_NUMBER=10 +HS_BUILD_NUMBER=11 JDK_MAJOR_VER=1 JDK_MINOR_VER=8
--- a/make/linux/makefiles/vm.make Thu Jan 19 17:20:39 2012 -0800 +++ b/make/linux/makefiles/vm.make Thu Jan 19 18:35:13 2012 -0800 @@ -98,6 +98,10 @@ ${JRE_VERSION} \ ${VM_DISTRO} +ifndef JAVASE_EMBEDDED +CFLAGS += -DINCLUDE_TRACE +endif + # CFLAGS_WARN holds compiler options to suppress/enable warnings. CFLAGS += $(CFLAGS_WARN/BYFILE) @@ -143,6 +147,12 @@ SOURCE_PATHS+=$(HS_COMMON_SRC)/cpu/$(Platform_arch)/vm SOURCE_PATHS+=$(HS_COMMON_SRC)/os_cpu/$(Platform_os_arch)/vm +ifndef JAVASE_EMBEDDED +SOURCE_PATHS+=$(shell if [ -d $(HS_ALT_SRC)/share/vm/jfr ]; then \ + find $(HS_ALT_SRC)/share/vm/jfr -type d; \ + fi) +endif + CORE_PATHS=$(foreach path,$(SOURCE_PATHS),$(call altsrc,$(path)) $(path)) CORE_PATHS+=$(GENERATED)/jvmtifiles
--- a/make/solaris/makefiles/vm.make Thu Jan 19 17:20:39 2012 -0800 +++ b/make/solaris/makefiles/vm.make Thu Jan 19 18:35:13 2012 -0800 @@ -93,7 +93,7 @@ CFLAGS += $(CFLAGS/NOEX) # Extra flags from gnumake's invocation or environment -CFLAGS += $(EXTRA_CFLAGS) +CFLAGS += $(EXTRA_CFLAGS) -DINCLUDE_TRACE # Math Library (libm.so), do not use -lm. # There might be two versions of libm.so on the build system: @@ -160,6 +160,10 @@ SOURCE_PATHS+=$(HS_COMMON_SRC)/cpu/$(Platform_arch)/vm SOURCE_PATHS+=$(HS_COMMON_SRC)/os_cpu/$(Platform_os_arch)/vm +SOURCE_PATHS+=$(shell if [ -d $(HS_ALT_SRC)/share/vm/jfr ]; then \ + find $(HS_ALT_SRC)/share/vm/jfr -type d; \ + fi) + CORE_PATHS=$(foreach path,$(SOURCE_PATHS),$(call altsrc,$(path)) $(path)) CORE_PATHS+=$(GENERATED)/jvmtifiles
--- a/make/windows/build.bat Thu Jan 19 17:20:39 2012 -0800 +++ b/make/windows/build.bat Thu Jan 19 18:35:13 2012 -0800 @@ -35,6 +35,8 @@ if %errorlevel% == 0 goto isia64 cl 2>&1 | grep "AMD64" >NUL if %errorlevel% == 0 goto amd64 +cl 2>&1 | grep "x64" >NUL +if %errorlevel% == 0 goto amd64 set ARCH=x86 set BUILDARCH=i486 set Platform_arch=x86
--- a/make/windows/create_obj_files.sh Thu Jan 19 17:20:39 2012 -0800 +++ b/make/windows/create_obj_files.sh Thu Jan 19 18:35:13 2012 -0800 @@ -73,6 +73,13 @@ BASE_PATHS="${BASE_PATHS} ${GENERATED}/jvmtifiles" +if [ -d "${ALTSRC}/share/vm/jfr" ]; then + BASE_PATHS="${BASE_PATHS} ${ALTSRC}/share/vm/jfr/agent" + BASE_PATHS="${BASE_PATHS} ${ALTSRC}/share/vm/jfr/agent/isolated_deps/util" + BASE_PATHS="${BASE_PATHS} ${ALTSRC}/share/vm/jfr/jvm" + BASE_PATHS="${BASE_PATHS} ${ALTSRC}/share/vm/jfr" +fi + CORE_PATHS="${BASE_PATHS}" # shared is already in BASE_PATHS. Should add vm/memory but that one is also in BASE_PATHS. if [ -d "${ALTSRC}/share/vm/gc_implementation" ]; then
--- a/make/windows/makefiles/projectcreator.make Thu Jan 19 17:20:39 2012 -0800 +++ b/make/windows/makefiles/projectcreator.make Thu Jan 19 18:35:13 2012 -0800 @@ -58,7 +58,8 @@ -absoluteInclude $(HOTSPOTBUILDSPACE)/%f/generated \ -ignorePath $(HOTSPOTBUILDSPACE)/%f/generated \ -ignorePath src\share\vm\adlc \ - -ignorePath src\share\vm\shark + -ignorePath src\share\vm\shark \ + -ignorePath posix # This is referenced externally by both the IDE and batch builds ProjectCreatorOptions= @@ -88,7 +89,7 @@ -jdkTargetRoot $(HOTSPOTJDKDIST) \ -define ALIGN_STACK_FRAMES \ -define VM_LITTLE_ENDIAN \ - -prelink "" "Generating vm.def..." "cd $(HOTSPOTBUILDSPACE)\%f\%b set HOTSPOTMKSHOME=$(HOTSPOTMKSHOME) $(HOTSPOTMKSHOME)\sh $(HOTSPOTWORKSPACE)\make\windows\build_vm_def.sh $(LINK_VER)" \ + -prelink "" "Generating vm.def..." "cd $(HOTSPOTBUILDSPACE)\%f\%b set HOTSPOTMKSHOME=$(HOTSPOTMKSHOME) set JAVA_HOME=$(HOTSPOTJDKDIST) $(HOTSPOTMKSHOME)\sh $(HOTSPOTWORKSPACE)\make\windows\build_vm_def.sh $(LINK_VER)" \ -postbuild "" "Building hotspot.exe..." "cd $(HOTSPOTBUILDSPACE)\%f\%b set HOTSPOTMKSHOME=$(HOTSPOTMKSHOME) nmake -f $(HOTSPOTWORKSPACE)\make\windows\projectfiles\common\Makefile LOCAL_MAKE=$(HOTSPOTBUILDSPACE)\%f\local.make JAVA_HOME=$(HOTSPOTJDKDIST) launcher" \ -ignoreFile jsig.c \ -ignoreFile jvmtiEnvRecommended.cpp \
--- a/make/windows/makefiles/vm.make Thu Jan 19 17:20:39 2012 -0800 +++ b/make/windows/makefiles/vm.make Thu Jan 19 18:35:13 2012 -0800 @@ -19,7 +19,7 @@ # 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. -# +# # # Resource file containing VERSIONINFO @@ -30,7 +30,7 @@ COMMONSRC=$(WorkSpace)\src ALTSRC=$(WorkSpace)\src\closed -!ifdef RELEASE +!ifdef RELEASE !ifdef DEVELOP CPP_FLAGS=$(CPP_FLAGS) /D "DEBUG" !else @@ -74,6 +74,10 @@ CPP_FLAGS=$(CPP_FLAGS) /D "HOTSPOT_BUILD_USER=\"$(BuildUser)\"" CPP_FLAGS=$(CPP_FLAGS) /D "HOTSPOT_VM_DISTRO=\"$(HOTSPOT_VM_DISTRO)\"" +!ifndef JAVASE_EMBEDDED +CPP_FLAGS=$(CPP_FLAGS) /D "INCLUDE_TRACE" +!endif + CPP_FLAGS=$(CPP_FLAGS) $(CPP_INCLUDE_DIRS) # Define that so jni.h is on correct side @@ -97,7 +101,7 @@ !endif # If you modify exports below please do the corresponding changes in -# src/share/tools/ProjectCreator/WinGammaPlatformVC7.java +# src/share/tools/ProjectCreator/WinGammaPlatformVC7.java LINK_FLAGS=$(LINK_FLAGS) $(STACK_SIZE) /subsystem:windows /dll /base:0x8000000 \ /export:JNI_GetDefaultJavaVMInitArgs \ /export:JNI_CreateJavaVM \ @@ -170,6 +174,7 @@ VM_PATH=$(VM_PATH);$(WorkSpace)/src/share/vm/prims VM_PATH=$(VM_PATH);$(WorkSpace)/src/share/vm/runtime VM_PATH=$(VM_PATH);$(WorkSpace)/src/share/vm/services +VM_PATH=$(VM_PATH);$(WorkSpace)/src/share/vm/trace VM_PATH=$(VM_PATH);$(WorkSpace)/src/share/vm/utilities VM_PATH=$(VM_PATH);$(WorkSpace)/src/share/vm/libadt VM_PATH=$(VM_PATH);$(WorkSpace)/src/os/windows/vm @@ -177,6 +182,13 @@ VM_PATH=$(VM_PATH);$(WorkSpace)/src/cpu/$(Platform_arch)/vm VM_PATH=$(VM_PATH);$(WorkSpace)/src/share/vm/opto +!if exists($(ALTSRC)\share\vm\jfr) +VM_PATH=$(VM_PATH);$(ALTSRC)/share/vm/jfr/agent +VM_PATH=$(VM_PATH);$(ALTSRC)/share/vm/jfr/agent/isolated_deps/util +VM_PATH=$(VM_PATH);$(ALTSRC)/share/vm/jfr/jvm +VM_PATH=$(VM_PATH);$(ALTSRC)/share/vm/jfr +!endif + VM_PATH={$(VM_PATH)} # Special case files not using precompiled header files. @@ -263,6 +275,9 @@ {$(COMMONSRC)\share\vm\services}.cpp.obj:: $(CPP) $(CPP_FLAGS) $(CPP_USE_PCH) /c $< +{$(COMMONSRC)\share\vm\trace}.cpp.obj:: + $(CPP) $(CPP_FLAGS) $(CPP_USE_PCH) /c $< + {$(COMMONSRC)\share\vm\utilities}.cpp.obj:: $(CPP) $(CPP_FLAGS) $(CPP_USE_PCH) /c $< @@ -340,6 +355,9 @@ {$(ALTSRC)\share\vm\services}.cpp.obj:: $(CPP) $(CPP_FLAGS) $(CPP_USE_PCH) /c $< +{$(ALTSRC)\share\vm\trace}.cpp.obj:: + $(CPP) $(CPP_FLAGS) $(CPP_USE_PCH) /c $< + {$(ALTSRC)\share\vm\utilities}.cpp.obj:: $(CPP) $(CPP_FLAGS) $(CPP_USE_PCH) /c $< @@ -371,6 +389,18 @@ {..\generated\jvmtifiles}.cpp.obj:: $(CPP) $(CPP_FLAGS) $(CPP_USE_PCH) /c $< +{$(ALTSRC)\share\vm\jfr}.cpp.obj:: + $(CPP) $(CPP_FLAGS) $(CPP_USE_PCH) /c $< + +{$(ALTSRC)\share\vm\jfr\agent}.cpp.obj:: + $(CPP) $(CPP_FLAGS) $(CPP_USE_PCH) /c $< + +{$(ALTSRC)\share\vm\jfr\agent\isolated_deps\util}.cpp.obj:: + $(CPP) $(CPP_FLAGS) $(CPP_USE_PCH) /c $< + +{$(ALTSRC)\share\vm\jfr\jvm}.cpp.obj:: + $(CPP) $(CPP_FLAGS) $(CPP_USE_PCH) /c $< + default:: _build_pch_file.obj:
--- a/src/os/bsd/vm/decoder_bsd.cpp Thu Jan 19 17:20:39 2012 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,66 +0,0 @@ -/* - * Copyright (c) 1997, 2010, 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. - * - */ - -#include "prims/jvm.h" -#include "utilities/decoder.hpp" - -#include <cxxabi.h> - -#ifdef __APPLE__ - -void Decoder::initialize() { - _initialized = true; -} - -void Decoder::uninitialize() { - _initialized = false; -} - -bool Decoder::can_decode_C_frame_in_vm() { - return false; -} - -Decoder::decoder_status Decoder::decode(address addr, const char* filepath, char *buf, int buflen, int *offset) { - return symbol_not_found; -} - - -#endif - -bool Decoder::demangle(const char* symbol, char *buf, int buflen) { - int status; - char* result; - size_t size = (size_t)buflen; - - // Don't pass buf to __cxa_demangle. In case of the 'buf' is too small, - // __cxa_demangle will call system "realloc" for additional memory, which - // may use different malloc/realloc mechanism that allocates 'buf'. - if ((result = abi::__cxa_demangle(symbol, NULL, NULL, &status)) != NULL) { - jio_snprintf(buf, buflen, "%s", result); - // call c library's free - ::free(result); - return true; - } - return false; -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/os/bsd/vm/decoder_machO.cpp Thu Jan 19 18:35:13 2012 -0800 @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2011, 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. + * + */ + +#include "precompiled.hpp" + +#ifdef __APPLE__ +#include "decoder_machO.hpp" +#endif + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/os/bsd/vm/decoder_machO.hpp Thu Jan 19 18:35:13 2012 -0800 @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2011, 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. + * + */ + +#ifndef OS_BSD_VM_DECODER_MACHO_HPP +#define OS_BSD_VM_DECODER_MACHO_HPP + +#ifdef __APPLE__ + +#include "utilities/decoder.hpp" + +// Just a placehold for now +class MachODecoder: public NullDecoder { +public: + MachODecoder() { } + ~MachODecoder() { } +}; + +#endif + +#endif // OS_BSD_VM_DECODER_MACHO_HPP +
--- a/src/os/bsd/vm/os_bsd.cpp Thu Jan 19 17:20:39 2012 -0800 +++ b/src/os/bsd/vm/os_bsd.cpp Thu Jan 19 18:35:13 2012 -0800 @@ -1920,7 +1920,7 @@ return true; } else if (dlinfo.dli_fname != NULL && dlinfo.dli_fbase != 0) { if (Decoder::decode((address)(addr - (address)dlinfo.dli_fbase), - dlinfo.dli_fname, buf, buflen, offset) == Decoder::no_error) { + buf, buflen, offset, dlinfo.dli_fname)) { return true; } }
--- a/src/os/linux/vm/decoder_linux.cpp Thu Jan 19 17:20:39 2012 -0800 +++ b/src/os/linux/vm/decoder_linux.cpp Thu Jan 19 18:35:13 2012 -0800 @@ -23,11 +23,11 @@ */ #include "prims/jvm.h" -#include "utilities/decoder.hpp" +#include "utilities/decoder_elf.hpp" #include <cxxabi.h> -bool Decoder::demangle(const char* symbol, char *buf, int buflen) { +bool ElfDecoder::demangle(const char* symbol, char *buf, int buflen) { int status; char* result; size_t size = (size_t)buflen; @@ -43,3 +43,4 @@ } return false; } +
--- a/src/os/linux/vm/os_linux.cpp Thu Jan 19 17:20:39 2012 -0800 +++ b/src/os/linux/vm/os_linux.cpp Thu Jan 19 18:35:13 2012 -0800 @@ -1732,7 +1732,7 @@ return true; } else if (dlinfo.dli_fname != NULL && dlinfo.dli_fbase != 0) { if (Decoder::decode((address)(addr - (address)dlinfo.dli_fbase), - dlinfo.dli_fname, buf, buflen, offset) == Decoder::no_error) { + buf, buflen, offset, dlinfo.dli_fname)) { return true; } }
--- a/src/os/solaris/vm/decoder_solaris.cpp Thu Jan 19 17:20:39 2012 -0800 +++ b/src/os/solaris/vm/decoder_solaris.cpp Thu Jan 19 18:35:13 2012 -0800 @@ -22,10 +22,11 @@ * */ -#include "utilities/decoder.hpp" +#include "utilities/decoder_elf.hpp" #include <demangle.h> -bool Decoder::demangle(const char* symbol, char *buf, int buflen) { +bool ElfDecoder::demangle(const char* symbol, char *buf, int buflen) { return !cplus_demangle(symbol, buf, (size_t)buflen); } +
--- a/src/os/solaris/vm/os_solaris.cpp Thu Jan 19 17:20:39 2012 -0800 +++ b/src/os/solaris/vm/os_solaris.cpp Thu Jan 19 18:35:13 2012 -0800 @@ -1997,7 +1997,7 @@ } if (dlinfo.dli_fname != NULL && dlinfo.dli_fbase != 0) { if (Decoder::decode((address)(addr - (address)dlinfo.dli_fbase), - dlinfo.dli_fname, buf, buflen, offset) == Decoder::no_error) { + buf, buflen, offset, dlinfo.dli_fname)) { return true; } } @@ -2015,7 +2015,7 @@ return true; } else if (dlinfo.dli_fname != NULL && dlinfo.dli_fbase != 0) { if (Decoder::decode((address)(addr - (address)dlinfo.dli_fbase), - dlinfo.dli_fname, buf, buflen, offset) == Decoder::no_error) { + buf, buflen, offset, dlinfo.dli_fname)) { return true; } }
--- a/src/os/windows/vm/decoder_windows.cpp Thu Jan 19 17:20:39 2012 -0800 +++ b/src/os/windows/vm/decoder_windows.cpp Thu Jan 19 18:35:13 2012 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, 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 @@ -24,22 +24,24 @@ #include "precompiled.hpp" #include "prims/jvm.h" -#include "runtime/os.hpp" -#include "utilities/decoder.hpp" +#include "decoder_windows.hpp" + +WindowsDecoder::WindowsDecoder() { + _dbghelp_handle = NULL; + _can_decode_in_vm = false; + _pfnSymGetSymFromAddr64 = NULL; + _pfnUndecorateSymbolName = NULL; -HMODULE Decoder::_dbghelp_handle = NULL; -bool Decoder::_can_decode_in_vm = false; -pfn_SymGetSymFromAddr64 Decoder::_pfnSymGetSymFromAddr64 = NULL; -pfn_UndecorateSymbolName Decoder::_pfnUndecorateSymbolName = NULL; + _decoder_status = no_error; + initialize(); +} -void Decoder::initialize() { - if (!_initialized) { - _initialized = true; - - HINSTANCE handle = os::win32::load_Windows_dll("dbghelp.dll", NULL, 0); +void WindowsDecoder::initialize() { + if (!has_error() && _dbghelp_handle == NULL) { + HMODULE handle = ::LoadLibrary("dbghelp.dll"); if (!handle) { _decoder_status = helper_not_found; - return; + return; } _dbghelp_handle = handle; @@ -70,32 +72,29 @@ // find out if jvm.dll contains private symbols, by decoding // current function and comparing the result - address addr = (address)Decoder::initialize; + address addr = (address)Decoder::decode; char buf[MAX_PATH]; - if (decode(addr, buf, sizeof(buf), NULL) == no_error) { - _can_decode_in_vm = !strcmp(buf, "Decoder::initialize"); + if (decode(addr, buf, sizeof(buf), NULL)) { + _can_decode_in_vm = !strcmp(buf, "Decoder::decode"); } } } -void Decoder::uninitialize() { - assert(_initialized, "Decoder not yet initialized"); +void WindowsDecoder::uninitialize() { _pfnSymGetSymFromAddr64 = NULL; _pfnUndecorateSymbolName = NULL; if (_dbghelp_handle != NULL) { ::FreeLibrary(_dbghelp_handle); } - _initialized = false; + _dbghelp_handle = NULL; } -bool Decoder::can_decode_C_frame_in_vm() { - initialize(); - return _can_decode_in_vm; +bool WindowsDecoder::can_decode_C_frame_in_vm() const { + return (!has_error() && _can_decode_in_vm); } -Decoder::decoder_status Decoder::decode(address addr, char *buf, int buflen, int *offset) { - assert(_initialized, "Decoder not yet initialized"); +bool WindowsDecoder::decode(address addr, char *buf, int buflen, int* offset, const char* modulepath) { if (_pfnSymGetSymFromAddr64 != NULL) { PIMAGEHLP_SYMBOL64 pSymbol; char symbolInfo[MAX_PATH + sizeof(IMAGEHLP_SYMBOL64)]; @@ -105,19 +104,20 @@ DWORD64 displacement; if (_pfnSymGetSymFromAddr64(::GetCurrentProcess(), (DWORD64)addr, &displacement, pSymbol)) { if (buf != NULL) { - if (!demangle(pSymbol->Name, buf, buflen)) { + if (demangle(pSymbol->Name, buf, buflen)) { jio_snprintf(buf, buflen, "%s", pSymbol->Name); } } - if (offset != NULL) *offset = (int)displacement; - return no_error; + if(offset != NULL) *offset = (int)displacement; + return true; } } - return helper_not_found; + if (buf != NULL && buflen > 0) buf[0] = '\0'; + if (offset != NULL) *offset = -1; + return false; } -bool Decoder::demangle(const char* symbol, char *buf, int buflen) { - assert(_initialized, "Decoder not yet initialized"); +bool WindowsDecoder::demangle(const char* symbol, char *buf, int buflen) { return _pfnUndecorateSymbolName != NULL && _pfnUndecorateSymbolName(symbol, buf, buflen, UNDNAME_COMPLETE); }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/os/windows/vm/decoder_windows.hpp Thu Jan 19 18:35:13 2012 -0800 @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2011, 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. + * + */ + +#ifndef OS_WINDOWS_VM_DECODER_WINDOWS_HPP +#define OS_WINDOWS_VM_DECIDER_WINDOWS_HPP + +#include <windows.h> +#include <imagehlp.h> + +#include "utilities/decoder.hpp" + +// functions needed for decoding symbols +typedef DWORD (WINAPI *pfn_SymSetOptions)(DWORD); +typedef BOOL (WINAPI *pfn_SymInitialize)(HANDLE, PCTSTR, BOOL); +typedef BOOL (WINAPI *pfn_SymGetSymFromAddr64)(HANDLE, DWORD64, PDWORD64, PIMAGEHLP_SYMBOL64); +typedef DWORD (WINAPI *pfn_UndecorateSymbolName)(const char*, char*, DWORD, DWORD); + +class WindowsDecoder: public NullDecoder { + +public: + WindowsDecoder(); + ~WindowsDecoder() { uninitialize(); }; + + bool can_decode_C_frame_in_vm() const; + bool demangle(const char* symbol, char *buf, int buflen); + bool decode(address addr, char *buf, int buflen, int* offset, const char* modulepath = NULL); + +private: + void initialize(); + void uninitialize(); + +private: + HMODULE _dbghelp_handle; + bool _can_decode_in_vm; + pfn_SymGetSymFromAddr64 _pfnSymGetSymFromAddr64; + pfn_UndecorateSymbolName _pfnUndecorateSymbolName; +}; + +#endif // OS_WINDOWS_VM_DECODER_WINDOWS_HPP +
--- a/src/os/windows/vm/os_windows.cpp Thu Jan 19 17:20:39 2012 -0800 +++ b/src/os/windows/vm/os_windows.cpp Thu Jan 19 18:35:13 2012 -0800 @@ -1391,7 +1391,7 @@ bool os::dll_address_to_function_name(address addr, char *buf, int buflen, int *offset) { - if (Decoder::decode(addr, buf, buflen, offset) == Decoder::no_error) { + if (Decoder::decode(addr, buf, buflen, offset)) { return true; } if (offset != NULL) *offset = -1;
--- a/src/share/vm/classfile/symbolTable.cpp Thu Jan 19 17:20:39 2012 -0800 +++ b/src/share/vm/classfile/symbolTable.cpp Thu Jan 19 18:35:13 2012 -0800 @@ -204,6 +204,24 @@ return s; } +// Look up the address of the literal in the SymbolTable for this Symbol* +// Do not create any new symbols +// Do not increment the reference count to keep this alive +Symbol** SymbolTable::lookup_symbol_addr(Symbol* sym){ + unsigned int hash = hash_symbol((char*)sym->bytes(), sym->utf8_length()); + int index = the_table()->hash_to_index(hash); + + for (HashtableEntry<Symbol*>* e = the_table()->bucket(index); e != NULL; e = e->next()) { + if (e->hash() == hash) { + Symbol* literal_sym = e->literal(); + if (sym == literal_sym) { + return e->literal_addr(); + } + } + } + return NULL; +} + // Suggestion: Push unicode-based lookup all the way into the hashing // and probing logic, so there is no need for convert_to_utf8 until // an actual new Symbol* is created.
--- a/src/share/vm/classfile/symbolTable.hpp Thu Jan 19 17:20:39 2012 -0800 +++ b/src/share/vm/classfile/symbolTable.hpp Thu Jan 19 18:35:13 2012 -0800 @@ -144,6 +144,9 @@ static void release(Symbol* sym); + // Look up the address of the literal in the SymbolTable for this Symbol* + static Symbol** lookup_symbol_addr(Symbol* sym); + // jchar (utf16) version of lookups static Symbol* lookup_unicode(const jchar* name, int len, TRAPS); static Symbol* lookup_only_unicode(const jchar* name, int len, unsigned int& hash);
--- a/src/share/vm/classfile/systemDictionary.cpp Thu Jan 19 17:20:39 2012 -0800 +++ b/src/share/vm/classfile/systemDictionary.cpp Thu Jan 19 18:35:13 2012 -0800 @@ -2131,6 +2131,12 @@ } } + // Assign a classid if one has not already been assigned. The + // counter does not need to be atomically incremented since this + // is only done while holding the SystemDictionary_lock. + // All loaded classes get a unique ID. + TRACE_INIT_ID(k); + // Check for a placeholder. If there, remove it and make a // new system dictionary entry. placeholders()->find_and_remove(p_index, p_hash, name, class_loader, THREAD);
--- a/src/share/vm/gc_implementation/g1/concurrentMark.cpp Thu Jan 19 17:20:39 2012 -0800 +++ b/src/share/vm/gc_implementation/g1/concurrentMark.cpp Thu Jan 19 18:35:13 2012 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2012, 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 @@ -31,6 +31,7 @@ #include "gc_implementation/g1/g1ErgoVerbose.hpp" #include "gc_implementation/g1/g1OopClosures.inline.hpp" #include "gc_implementation/g1/g1RemSet.hpp" +#include "gc_implementation/g1/heapRegion.inline.hpp" #include "gc_implementation/g1/heapRegionRemSet.hpp" #include "gc_implementation/g1/heapRegionSeq.inline.hpp" #include "gc_implementation/shared/vmGCOperations.hpp" @@ -183,12 +184,11 @@ void CMMarkStack::allocate(size_t size) { _base = NEW_C_HEAP_ARRAY(oop, size); if (_base == NULL) { - vm_exit_during_initialization("Failed to allocate " - "CM region mark stack"); + vm_exit_during_initialization("Failed to allocate CM region mark stack"); } _index = 0; _capacity = (jint) size; - _oops_do_bound = -1; + _saved_index = -1; NOT_PRODUCT(_max_depth = 0); } @@ -283,7 +283,6 @@ } } - CMRegionStack::CMRegionStack() : _base(NULL) {} void CMRegionStack::allocate(size_t size) { @@ -302,6 +301,8 @@ } void CMRegionStack::push_lock_free(MemRegion mr) { + guarantee(false, "push_lock_free(): don't call this any more"); + assert(mr.word_size() > 0, "Precondition"); while (true) { jint index = _index; @@ -325,6 +326,8 @@ // marking / remark phases. Should only be called in tandem with // other lock-free pops. MemRegion CMRegionStack::pop_lock_free() { + guarantee(false, "pop_lock_free(): don't call this any more"); + while (true) { jint index = _index; @@ -390,6 +393,8 @@ #endif bool CMRegionStack::invalidate_entries_into_cset() { + guarantee(false, "invalidate_entries_into_cset(): don't call this any more"); + bool result = false; G1CollectedHeap* g1h = G1CollectedHeap::heap(); for (int i = 0; i < _oops_do_bound; ++i) { @@ -438,14 +443,29 @@ return res; } +void CMMarkStack::note_start_of_gc() { + assert(_saved_index == -1, + "note_start_of_gc()/end_of_gc() bracketed incorrectly"); + _saved_index = _index; +} + +void CMMarkStack::note_end_of_gc() { + // This is intentionally a guarantee, instead of an assert. If we + // accidentally add something to the mark stack during GC, it + // will be a correctness issue so it's better if we crash. we'll + // only check this once per GC anyway, so it won't be a performance + // issue in any way. + guarantee(_saved_index == _index, + err_msg("saved index: %d index: %d", _saved_index, _index)); + _saved_index = -1; +} + void CMMarkStack::oops_do(OopClosure* f) { - if (_index == 0) return; - assert(_oops_do_bound != -1 && _oops_do_bound <= _index, - "Bound must be set."); - for (int i = 0; i < _oops_do_bound; i++) { + assert(_saved_index == _index, + err_msg("saved index: %d index: %d", _saved_index, _index)); + for (int i = 0; i < _index; i += 1) { f->do_oop(&_base[i]); } - _oops_do_bound = -1; } bool ConcurrentMark::not_yet_marked(oop obj) const { @@ -783,7 +803,7 @@ public: bool doHeapRegion(HeapRegion* r) { if (!r->continuesHumongous()) { - r->note_start_of_marking(true); + r->note_start_of_marking(); } return false; } @@ -804,6 +824,10 @@ // Initialise marking structures. This has to be done in a STW phase. reset(); + + // For each region note start of marking. + NoteStartOfMarkHRClosure startcl; + g1h->heap_region_iterate(&startcl); } @@ -818,10 +842,6 @@ // every remark and we'll eventually not need to cause one. force_overflow_stw()->init(); - // For each region note start of marking. - NoteStartOfMarkHRClosure startcl; - g1h->heap_region_iterate(&startcl); - // Start Concurrent Marking weak-reference discovery. ReferenceProcessor* rp = g1h->ref_processor_cm(); // enable ("weak") refs discovery @@ -946,22 +966,9 @@ } #endif // !PRODUCT -void ConcurrentMark::grayRoot(oop p) { - HeapWord* addr = (HeapWord*) p; - // We can't really check against _heap_start and _heap_end, since it - // is possible during an evacuation pause with piggy-backed - // initial-mark that the committed space is expanded during the - // pause without CM observing this change. So the assertions below - // is a bit conservative; but better than nothing. - assert(_g1h->g1_committed().contains(addr), - "address should be within the heap bounds"); - - if (!_nextMarkBitMap->isMarked(addr)) { - _nextMarkBitMap->parMark(addr); - } -} - void ConcurrentMark::grayRegionIfNecessary(MemRegion mr) { + guarantee(false, "grayRegionIfNecessary(): don't call this any more"); + // The objects on the region have already been marked "in bulk" by // the caller. We only need to decide whether to push the region on // the region stack or not. @@ -1007,6 +1014,8 @@ } void ConcurrentMark::markAndGrayObjectIfNecessary(oop p) { + guarantee(false, "markAndGrayObjectIfNecessary(): don't call this any more"); + // The object is not marked by the caller. We need to at least mark // it and maybe push in on the stack. @@ -1224,7 +1233,6 @@ true /* expected_active */); if (VerifyDuringGC) { - HandleMark hm; // handle scope gclog_or_tty->print(" VerifyDuringGC:(after)"); Universe::heap()->prepare_for_verify(); @@ -1879,10 +1887,6 @@ double end = os::elapsedTime(); _cleanup_times.add((end - start) * 1000.0); - // G1CollectedHeap::heap()->print(); - // gclog_or_tty->print_cr("HEAP GC TIME STAMP : %d", - // G1CollectedHeap::heap()->get_gc_time_stamp()); - if (PrintGC || PrintGCDetails) { g1h->print_size_transition(gclog_or_tty, start_used_bytes, @@ -2669,6 +2673,8 @@ } void ConcurrentMark::drainAllSATBBuffers() { + guarantee(false, "drainAllSATBBuffers(): don't call this any more"); + CMGlobalObjectClosure oc(this); SATBMarkQueueSet& satb_mq_set = JavaThread::satb_mark_queue_set(); satb_mq_set.set_closure(&oc); @@ -2687,12 +2693,6 @@ assert(satb_mq_set.completed_buffers_num() == 0, "invariant"); } -void ConcurrentMark::markPrev(oop p) { - // Note we are overriding the read-only view of the prev map here, via - // the cast. - ((CMBitMap*)_prevMarkBitMap)->mark((HeapWord*)p); -} - void ConcurrentMark::clear(oop p) { assert(p != NULL && p->is_oop(), "expected an oop"); HeapWord* addr = (HeapWord*)p; @@ -2702,13 +2702,21 @@ _nextMarkBitMap->clear(addr); } -void ConcurrentMark::clearRangeBothMaps(MemRegion mr) { +void ConcurrentMark::clearRangePrevBitmap(MemRegion mr) { // Note we are overriding the read-only view of the prev map here, via // the cast. ((CMBitMap*)_prevMarkBitMap)->clearRange(mr); +} + +void ConcurrentMark::clearRangeNextBitmap(MemRegion mr) { _nextMarkBitMap->clearRange(mr); } +void ConcurrentMark::clearRangeBothBitmaps(MemRegion mr) { + clearRangePrevBitmap(mr); + clearRangeNextBitmap(mr); +} + HeapRegion* ConcurrentMark::claim_region(int task_num) { // "checkpoint" the finger @@ -2803,6 +2811,9 @@ } bool ConcurrentMark::invalidate_aborted_regions_in_cset() { + guarantee(false, "invalidate_aborted_regions_in_cset(): " + "don't call this any more"); + bool result = false; for (int i = 0; i < (int)_max_task_num; ++i) { CMTask* the_task = _tasks[i]; @@ -2854,24 +2865,135 @@ // ...then over the contents of the all the task queues. queue->oops_do(cl); } - - // Invalidate any entries, that are in the region stack, that - // point into the collection set - if (_regionStack.invalidate_entries_into_cset()) { - // otherwise, any gray objects copied during the evacuation pause - // might not be visited. - assert(_should_gray_objects, "invariant"); +} + +#ifndef PRODUCT +enum VerifyNoCSetOopsPhase { + VerifyNoCSetOopsStack, + VerifyNoCSetOopsQueues, + VerifyNoCSetOopsSATBCompleted, + VerifyNoCSetOopsSATBThread +}; + +class VerifyNoCSetOopsClosure : public OopClosure, public ObjectClosure { +private: + G1CollectedHeap* _g1h; + VerifyNoCSetOopsPhase _phase; + int _info; + + const char* phase_str() { + switch (_phase) { + case VerifyNoCSetOopsStack: return "Stack"; + case VerifyNoCSetOopsQueues: return "Queue"; + case VerifyNoCSetOopsSATBCompleted: return "Completed SATB Buffers"; + case VerifyNoCSetOopsSATBThread: return "Thread SATB Buffers"; + default: ShouldNotReachHere(); + } + return NULL; + } + + void do_object_work(oop obj) { + guarantee(!_g1h->obj_in_cs(obj), + err_msg("obj: "PTR_FORMAT" in CSet, phase: %s, info: %d", + (void*) obj, phase_str(), _info)); + } + +public: + VerifyNoCSetOopsClosure() : _g1h(G1CollectedHeap::heap()) { } + + void set_phase(VerifyNoCSetOopsPhase phase, int info = -1) { + _phase = phase; + _info = info; + } + + virtual void do_oop(oop* p) { + oop obj = oopDesc::load_decode_heap_oop(p); + do_object_work(obj); + } + + virtual void do_oop(narrowOop* p) { + // We should not come across narrow oops while scanning marking + // stacks and SATB buffers. + ShouldNotReachHere(); + } + + virtual void do_object(oop obj) { + do_object_work(obj); + } +}; + +void ConcurrentMark::verify_no_cset_oops(bool verify_stacks, + bool verify_enqueued_buffers, + bool verify_thread_buffers, + bool verify_fingers) { + assert(SafepointSynchronize::is_at_safepoint(), "should be at a safepoint"); + if (!G1CollectedHeap::heap()->mark_in_progress()) { + return; } - // Invalidate any aborted regions, recorded in the individual CM - // tasks, that point into the collection set. - if (invalidate_aborted_regions_in_cset()) { - // otherwise, any gray objects copied during the evacuation pause - // might not be visited. - assert(_should_gray_objects, "invariant"); + VerifyNoCSetOopsClosure cl; + + if (verify_stacks) { + // Verify entries on the global mark stack + cl.set_phase(VerifyNoCSetOopsStack); + _markStack.oops_do(&cl); + + // Verify entries on the task queues + for (int i = 0; i < (int) _max_task_num; i += 1) { + cl.set_phase(VerifyNoCSetOopsQueues, i); + OopTaskQueue* queue = _task_queues->queue(i); + queue->oops_do(&cl); + } + } + + SATBMarkQueueSet& satb_qs = JavaThread::satb_mark_queue_set(); + + // Verify entries on the enqueued SATB buffers + if (verify_enqueued_buffers) { + cl.set_phase(VerifyNoCSetOopsSATBCompleted); + satb_qs.iterate_completed_buffers_read_only(&cl); + } + + // Verify entries on the per-thread SATB buffers + if (verify_thread_buffers) { + cl.set_phase(VerifyNoCSetOopsSATBThread); + satb_qs.iterate_thread_buffers_read_only(&cl); } + if (verify_fingers) { + // Verify the global finger + HeapWord* global_finger = finger(); + if (global_finger != NULL && global_finger < _heap_end) { + // The global finger always points to a heap region boundary. We + // use heap_region_containing_raw() to get the containing region + // given that the global finger could be pointing to a free region + // which subsequently becomes continues humongous. If that + // happens, heap_region_containing() will return the bottom of the + // corresponding starts humongous region and the check below will + // not hold any more. + HeapRegion* global_hr = _g1h->heap_region_containing_raw(global_finger); + guarantee(global_finger == global_hr->bottom(), + err_msg("global finger: "PTR_FORMAT" region: "HR_FORMAT, + global_finger, HR_FORMAT_PARAMS(global_hr))); + } + + // Verify the task fingers + assert(parallel_marking_threads() <= _max_task_num, "sanity"); + for (int i = 0; i < (int) parallel_marking_threads(); i += 1) { + CMTask* task = _tasks[i]; + HeapWord* task_finger = task->finger(); + if (task_finger != NULL && task_finger < _heap_end) { + // See above note on the global finger verification. + HeapRegion* task_hr = _g1h->heap_region_containing_raw(task_finger); + guarantee(task_finger == task_hr->bottom() || + !task_hr->in_collection_set(), + err_msg("task finger: "PTR_FORMAT" region: "HR_FORMAT, + task_finger, HR_FORMAT_PARAMS(task_hr))); + } + } + } } +#endif // PRODUCT void ConcurrentMark::clear_marking_state(bool clear_overflow) { _markStack.setEmpty(); @@ -3080,19 +3202,6 @@ } }; -class SetClaimValuesInCSetHRClosure: public HeapRegionClosure { - jint _claim_value; - -public: - SetClaimValuesInCSetHRClosure(jint claim_value) : - _claim_value(claim_value) { } - - bool doHeapRegion(HeapRegion* hr) { - hr->set_claim_value(_claim_value); - return false; - } -}; - class G1ParCompleteMarkInCSetTask: public AbstractGangTask { protected: G1CollectedHeap* _g1h; @@ -3112,6 +3221,9 @@ }; void ConcurrentMark::complete_marking_in_collection_set() { + guarantee(false, "complete_marking_in_collection_set(): " + "don't call this any more"); + G1CollectedHeap* g1h = G1CollectedHeap::heap(); if (!g1h->mark_in_progress()) { @@ -3135,9 +3247,8 @@ assert(g1h->check_cset_heap_region_claim_values(HeapRegion::CompleteMarkCSetClaimValue), "sanity"); - // Now reset the claim values in the regions in the collection set. - SetClaimValuesInCSetHRClosure set_cv_cl(HeapRegion::InitialClaimValue); - g1h->collection_set_iterate(&set_cv_cl); + // Reset the claim values in the regions in the collection set. + g1h->reset_cset_heap_region_claim_values(); assert(g1h->check_cset_heap_region_claim_values(HeapRegion::InitialClaimValue), "sanity"); @@ -3160,6 +3271,8 @@ // newCSet(). void ConcurrentMark::newCSet() { + guarantee(false, "newCSet(): don't call this any more"); + if (!concurrent_marking_in_progress()) { // nothing to do if marking is not in progress return; @@ -3198,6 +3311,8 @@ } void ConcurrentMark::registerCSetRegion(HeapRegion* hr) { + guarantee(false, "registerCSetRegion(): don't call this any more"); + if (!concurrent_marking_in_progress()) return; HeapWord* region_end = hr->end(); @@ -3209,6 +3324,9 @@ // Resets the region fields of active CMTasks whose values point // into the collection set. void ConcurrentMark::reset_active_task_region_fields_in_cset() { + guarantee(false, "reset_active_task_region_fields_in_cset(): " + "don't call this any more"); + assert(SafepointSynchronize::is_at_safepoint(), "should be in STW"); assert(parallel_marking_threads() <= _max_task_num, "sanity"); @@ -3919,6 +4037,10 @@ } void CMTask::drain_region_stack(BitMapClosure* bc) { + assert(_cm->region_stack_empty(), "region stack should be empty"); + assert(_aborted_region.is_empty(), "aborted region should be empty"); + return; + if (has_aborted()) return; assert(_region_finger == NULL,
--- a/src/share/vm/gc_implementation/g1/concurrentMark.hpp Thu Jan 19 17:20:39 2012 -0800 +++ b/src/share/vm/gc_implementation/g1/concurrentMark.hpp Thu Jan 19 18:35:13 2012 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -166,10 +166,10 @@ // Ideally this should be GrowableArray<> just like MSC's marking stack(s). class CMMarkStack VALUE_OBJ_CLASS_SPEC { ConcurrentMark* _cm; - oop* _base; // bottom of stack - jint _index; // one more than last occupied index - jint _capacity; // max #elements - jint _oops_do_bound; // Number of elements to include in next iteration. + oop* _base; // bottom of stack + jint _index; // one more than last occupied index + jint _capacity; // max #elements + jint _saved_index; // value of _index saved at start of GC NOT_PRODUCT(jint _max_depth;) // max depth plumbed during run bool _overflow; @@ -247,16 +247,12 @@ void setEmpty() { _index = 0; clear_overflow(); } - // Record the current size; a subsequent "oops_do" will iterate only over - // indices valid at the time of this call. - void set_oops_do_bound(jint bound = -1) { - if (bound == -1) { - _oops_do_bound = _index; - } else { - _oops_do_bound = bound; - } - } - jint oops_do_bound() { return _oops_do_bound; } + // Record the current index. + void note_start_of_gc(); + + // Make sure that we have not added any entries to the stack during GC. + void note_end_of_gc(); + // iterate over the oops in the mark stack, up to the bound recorded via // the call above. void oops_do(OopClosure* f); @@ -724,10 +720,9 @@ // G1CollectedHeap // This notifies CM that a root during initial-mark needs to be - // grayed and it's MT-safe. Currently, we just mark it. But, in the - // future, we can experiment with pushing it on the stack and we can - // do this without changing G1CollectedHeap. - void grayRoot(oop p); + // grayed. It is MT-safe. + inline void grayRoot(oop obj, size_t word_size); + // It's used during evacuation pauses to gray a region, if // necessary, and it's MT-safe. It assumes that the caller has // marked any objects on that region. If _should_gray_objects is @@ -735,6 +730,7 @@ // pushed on the region stack, if it is located below the global // finger, otherwise we do nothing. void grayRegionIfNecessary(MemRegion mr); + // It's used during evacuation pauses to mark and, if necessary, // gray a single object and it's MT-safe. It assumes the caller did // not mark the object. If _should_gray_objects is true and we're @@ -791,24 +787,40 @@ // Mark in the previous bitmap. NB: this is usually read-only, so use // this carefully! - void markPrev(oop p); + inline void markPrev(oop p); + inline void markNext(oop p); void clear(oop p); - // Clears marks for all objects in the given range, for both prev and - // next bitmaps. NB: the previous bitmap is usually read-only, so use - // this carefully! - void clearRangeBothMaps(MemRegion mr); + // Clears marks for all objects in the given range, for the prev, + // next, or both bitmaps. NB: the previous bitmap is usually + // read-only, so use this carefully! + void clearRangePrevBitmap(MemRegion mr); + void clearRangeNextBitmap(MemRegion mr); + void clearRangeBothBitmaps(MemRegion mr); - // Record the current top of the mark and region stacks; a - // subsequent oops_do() on the mark stack and - // invalidate_entries_into_cset() on the region stack will iterate - // only over indices valid at the time of this call. - void set_oops_do_bound() { - _markStack.set_oops_do_bound(); - _regionStack.set_oops_do_bound(); + // Notify data structures that a GC has started. + void note_start_of_gc() { + _markStack.note_start_of_gc(); } + + // Notify data structures that a GC is finished. + void note_end_of_gc() { + _markStack.note_end_of_gc(); + } + // Iterate over the oops in the mark stack and all local queues. It // also calls invalidate_entries_into_cset() on the region stack. void oops_do(OopClosure* f); + + // Verify that there are no CSet oops on the stacks (taskqueues / + // global mark stack), enqueued SATB buffers, per-thread SATB + // buffers, and fingers (global / per-task). The boolean parameters + // decide which of the above data structures to verify. If marking + // is not in progress, it's a no-op. + void verify_no_cset_oops(bool verify_stacks, + bool verify_enqueued_buffers, + bool verify_thread_buffers, + bool verify_fingers) PRODUCT_RETURN; + // It is called at the end of an evacuation pause during marking so // that CM is notified of where the new end of the heap is. It // doesn't do anything if concurrent_marking_in_progress() is false, @@ -1166,6 +1178,7 @@ // It keeps picking SATB buffers and processing them until no SATB // buffers are available. void drain_satb_buffers(); + // It keeps popping regions from the region stack and processing // them until the region stack is empty. void drain_region_stack(BitMapClosure* closure);
--- a/src/share/vm/gc_implementation/g1/concurrentMark.inline.hpp Thu Jan 19 17:20:39 2012 -0800 +++ b/src/share/vm/gc_implementation/g1/concurrentMark.inline.hpp Thu Jan 19 18:35:13 2012 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2012, 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 @@ -153,4 +153,46 @@ } } +inline void ConcurrentMark::markPrev(oop p) { + assert(!_prevMarkBitMap->isMarked((HeapWord*) p), "sanity"); + // Note we are overriding the read-only view of the prev map here, via + // the cast. + ((CMBitMap*)_prevMarkBitMap)->mark((HeapWord*) p); +} + +inline void ConcurrentMark::markNext(oop p) { + assert(!_nextMarkBitMap->isMarked((HeapWord*) p), "sanity"); + _nextMarkBitMap->mark((HeapWord*) p); +} + +inline void ConcurrentMark::grayRoot(oop obj, size_t word_size) { + HeapWord* addr = (HeapWord*) obj; + + // Currently we don't do anything with word_size but we will use it + // in the very near future in the liveness calculation piggy-backing + // changes. + +#ifdef ASSERT + HeapRegion* hr = _g1h->heap_region_containing(addr); + assert(hr != NULL, "sanity"); + assert(!hr->is_survivor(), "should not allocate survivors during IM"); + assert(addr < hr->next_top_at_mark_start(), + err_msg("addr: "PTR_FORMAT" hr: "HR_FORMAT" NTAMS: "PTR_FORMAT, + addr, HR_FORMAT_PARAMS(hr), hr->next_top_at_mark_start())); + // We cannot assert that word_size == obj->size() given that obj + // might not be in a consistent state (another thread might be in + // the process of copying it). So the best thing we can do is to + // assert that word_size is under an upper bound which is its + // containing region's capacity. + assert(word_size * HeapWordSize <= hr->capacity(), + err_msg("size: "SIZE_FORMAT" capacity: "SIZE_FORMAT" "HR_FORMAT, + word_size * HeapWordSize, hr->capacity(), + HR_FORMAT_PARAMS(hr))); +#endif // ASSERT + + if (!_nextMarkBitMap->isMarked(addr)) { + _nextMarkBitMap->parMark(addr); + } +} + #endif // SHARE_VM_GC_IMPLEMENTATION_G1_CONCURRENTMARK_INLINE_HPP
--- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Thu Jan 19 17:20:39 2012 -0800 +++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Thu Jan 19 18:35:13 2012 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2012, 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 @@ -32,9 +32,11 @@ #include "gc_implementation/g1/g1CollectedHeap.inline.hpp" #include "gc_implementation/g1/g1CollectorPolicy.hpp" #include "gc_implementation/g1/g1ErgoVerbose.hpp" +#include "gc_implementation/g1/g1EvacFailure.hpp" #include "gc_implementation/g1/g1MarkSweep.hpp" #include "gc_implementation/g1/g1OopClosures.inline.hpp" #include "gc_implementation/g1/g1RemSet.inline.hpp" +#include "gc_implementation/g1/heapRegion.inline.hpp" #include "gc_implementation/g1/heapRegionRemSet.hpp" #include "gc_implementation/g1/heapRegionSeq.inline.hpp" #include "gc_implementation/g1/vm_operations_g1.hpp" @@ -591,17 +593,29 @@ } res = new_region_try_secondary_free_list(); } - if (res == NULL && do_expand) { + if (res == NULL && do_expand && _expand_heap_after_alloc_failure) { + // Currently, only attempts to allocate GC alloc regions set + // do_expand to true. So, we should only reach here during a + // safepoint. If this assumption changes we might have to + // reconsider the use of _expand_heap_after_alloc_failure. + assert(SafepointSynchronize::is_at_safepoint(), "invariant"); + ergo_verbose1(ErgoHeapSizing, "attempt heap expansion", ergo_format_reason("region allocation request failed") ergo_format_byte("allocation request"), word_size * HeapWordSize); if (expand(word_size * HeapWordSize)) { - // Even though the heap was expanded, it might not have reached - // the desired size. So, we cannot assume that the allocation - // will succeed. + // Given that expand() succeeded in expanding the heap, and we + // always expand the heap by an amount aligned to the heap + // region size, the free list should in theory not be empty. So + // it would probably be OK to use remove_head(). But the extra + // check for NULL is unlikely to be a performance issue here (we + // just expanded the heap!) so let's just be conservative and + // use remove_head_or_null(). res = _free_list.remove_head_or_null(); + } else { + _expand_heap_after_alloc_failure = false; } } return res; @@ -1838,6 +1852,7 @@ _young_list(new YoungList(this)), _gc_time_stamp(0), _retained_old_gc_alloc_region(NULL), + _expand_heap_after_alloc_failure(true), _surviving_young_words(NULL), _full_collections_completed(0), _in_cset_fast_test(NULL), @@ -2605,12 +2620,16 @@ } }; -void -G1CollectedHeap::reset_heap_region_claim_values() { +void G1CollectedHeap::reset_heap_region_claim_values() { ResetClaimValuesClosure blk; heap_region_iterate(&blk); } +void G1CollectedHeap::reset_cset_heap_region_claim_values() { + ResetClaimValuesClosure blk; + collection_set_iterate(&blk); +} + #ifdef ASSERT // This checks whether all regions in the heap have the correct claim // value. I also piggy-backed on this a check to ensure that the @@ -3000,14 +3019,20 @@ } else { VerifyObjsInRegionClosure not_dead_yet_cl(r, _vo); r->object_iterate(¬_dead_yet_cl); - if (r->max_live_bytes() < not_dead_yet_cl.live_bytes()) { - gclog_or_tty->print_cr("["PTR_FORMAT","PTR_FORMAT"] " - "max_live_bytes "SIZE_FORMAT" " - "< calculated "SIZE_FORMAT, - r->bottom(), r->end(), - r->max_live_bytes(), + if (_vo != VerifyOption_G1UseNextMarking) { + if (r->max_live_bytes() < not_dead_yet_cl.live_bytes()) { + gclog_or_tty->print_cr("["PTR_FORMAT","PTR_FORMAT"] " + "max_live_bytes "SIZE_FORMAT" " + "< calculated "SIZE_FORMAT, + r->bottom(), r->end(), + r->max_live_bytes(), not_dead_yet_cl.live_bytes()); - _failures = true; + _failures = true; + } + } else { + // When vo == UseNextMarking we cannot currently do a sanity + // check on the live bytes as the calculation has not been + // finalized yet. } } } @@ -3641,25 +3666,6 @@ } perm_gen()->save_marks(); - // We must do this before any possible evacuation that should propagate - // marks. - if (mark_in_progress()) { - double start_time_sec = os::elapsedTime(); - - _cm->drainAllSATBBuffers(); - double finish_mark_ms = (os::elapsedTime() - start_time_sec) * 1000.0; - g1_policy()->record_satb_drain_time(finish_mark_ms); - } - // Record the number of elements currently on the mark stack, so we - // only iterate over these. (Since evacuation may add to the mark - // stack, doing more exposes race conditions.) If no mark is in - // progress, this will be zero. - _cm->set_oops_do_bound(); - - if (mark_in_progress()) { - concurrent_mark()->newCSet(); - } - #if YOUNG_LIST_VERBOSE gclog_or_tty->print_cr("\nBefore choosing collection set.\nYoung_list:"); _young_list->print(); @@ -3668,6 +3674,16 @@ g1_policy()->choose_collection_set(target_pause_time_ms); + _cm->note_start_of_gc(); + // We should not verify the per-thread SATB buffers given that + // we have not filtered them yet (we'll do so during the + // GC). We also call this after choose_collection_set() to + // ensure that the CSet has been finalized. + _cm->verify_no_cset_oops(true /* verify_stacks */, + true /* verify_enqueued_buffers */, + false /* verify_thread_buffers */, + true /* verify_fingers */); + if (_hr_printer.is_active()) { HeapRegion* hr = g1_policy()->collection_set(); while (hr != NULL) { @@ -3684,16 +3700,6 @@ } } - // We have chosen the complete collection set. If marking is - // active then, we clear the region fields of any of the - // concurrent marking tasks whose region fields point into - // the collection set as these values will become stale. This - // will cause the owning marking threads to claim a new region - // when marking restarts. - if (mark_in_progress()) { - concurrent_mark()->reset_active_task_region_fields_in_cset(); - } - #ifdef ASSERT VerifyCSetClosure cl; collection_set_iterate(&cl); @@ -3707,6 +3713,16 @@ // Actually do the work... evacuate_collection_set(); + // We do this to mainly verify the per-thread SATB buffers + // (which have been filtered by now) since we didn't verify + // them earlier. No point in re-checking the stacks / enqueued + // buffers given that the CSet has not changed since last time + // we checked. + _cm->verify_no_cset_oops(false /* verify_stacks */, + false /* verify_enqueued_buffers */, + true /* verify_thread_buffers */, + true /* verify_fingers */); + free_collection_set(g1_policy()->collection_set()); g1_policy()->clear_collection_set(); @@ -3775,6 +3791,8 @@ size_t expand_bytes = g1_policy()->expansion_amount(); if (expand_bytes > 0) { size_t bytes_before = capacity(); + // No need for an ergo verbose message here, + // expansion_amount() does this when it returns a value > 0. if (!expand(expand_bytes)) { // We failed to expand the heap so let's verify that // committed/uncommitted amount match the backing store @@ -3784,6 +3802,14 @@ } } + // We redo the verificaiton but now wrt to the new CSet which + // has just got initialized after the previous CSet was freed. + _cm->verify_no_cset_oops(true /* verify_stacks */, + true /* verify_enqueued_buffers */, + true /* verify_thread_buffers */, + true /* verify_fingers */); + _cm->note_end_of_gc(); + double end_time_sec = os::elapsedTime(); double pause_time_ms = (end_time_sec - start_time_sec) * MILLIUNITS; g1_policy()->record_pause_time_ms(pause_time_ms); @@ -3831,21 +3857,6 @@ // CM reference discovery will be re-enabled if necessary. } - { - size_t expand_bytes = g1_policy()->expansion_amount(); - if (expand_bytes > 0) { - size_t bytes_before = capacity(); - // No need for an ergo verbose message here, - // expansion_amount() does this when it returns a value > 0. - if (!expand(expand_bytes)) { - // We failed to expand the heap so let's verify that - // committed/uncommitted amount match the backing store - assert(capacity() == _g1_storage.committed_size(), "committed size mismatch"); - assert(max_capacity() == _g1_storage.reserved_size(), "reserved size mismatch"); - } - } - } - // We should do this after we potentially expand the heap so // that all the COMMIT events are generated before the end GC // event, and after we retire the GC alloc regions so that all @@ -3949,6 +3960,8 @@ // we allocate to in the region sets. We'll re-add it later, when // it's retired again. _old_set.remove(retained_region); + bool during_im = g1_policy()->during_initial_mark_pause(); + retained_region->note_start_of_copying(during_im); _old_gc_alloc_region.set(retained_region); _hr_printer.reuse(retained_region); } @@ -3985,157 +3998,26 @@ _evac_failure_scan_stack = NULL; } -class UpdateRSetDeferred : public OopsInHeapRegionClosure { -private: - G1CollectedHeap* _g1; - DirtyCardQueue *_dcq; - CardTableModRefBS* _ct_bs; - -public: - UpdateRSetDeferred(G1CollectedHeap* g1, DirtyCardQueue* dcq) : - _g1(g1), _ct_bs((CardTableModRefBS*)_g1->barrier_set()), _dcq(dcq) {} - - virtual void do_oop(narrowOop* p) { do_oop_work(p); } - virtual void do_oop( oop* p) { do_oop_work(p); } - template <class T> void do_oop_work(T* p) { - assert(_from->is_in_reserved(p), "paranoia"); - if (!_from->is_in_reserved(oopDesc::load_decode_heap_oop(p)) && - !_from->is_survivor()) { - size_t card_index = _ct_bs->index_for(p); - if (_ct_bs->mark_card_deferred(card_index)) { - _dcq->enqueue((jbyte*)_ct_bs->byte_for_index(card_index)); - } - } - } -}; - -class RemoveSelfPointerClosure: public ObjectClosure { -private: - G1CollectedHeap* _g1; - ConcurrentMark* _cm; - HeapRegion* _hr; - size_t _prev_marked_bytes; - size_t _next_marked_bytes; - OopsInHeapRegionClosure *_cl; -public: - RemoveSelfPointerClosure(G1CollectedHeap* g1, HeapRegion* hr, - OopsInHeapRegionClosure* cl) : - _g1(g1), _hr(hr), _cm(_g1->concurrent_mark()), _prev_marked_bytes(0), - _next_marked_bytes(0), _cl(cl) {} - - size_t prev_marked_bytes() { return _prev_marked_bytes; } - size_t next_marked_bytes() { return _next_marked_bytes; } - - // <original comment> - // The original idea here was to coalesce evacuated and dead objects. - // However that caused complications with the block offset table (BOT). - // In particular if there were two TLABs, one of them partially refined. - // |----- TLAB_1--------|----TLAB_2-~~~(partially refined part)~~~| - // The BOT entries of the unrefined part of TLAB_2 point to the start - // of TLAB_2. If the last object of the TLAB_1 and the first object - // of TLAB_2 are coalesced, then the cards of the unrefined part - // would point into middle of the filler object. - // The current approach is to not coalesce and leave the BOT contents intact. - // </original comment> - // - // We now reset the BOT when we start the object iteration over the - // region and refine its entries for every object we come across. So - // the above comment is not really relevant and we should be able - // to coalesce dead objects if we want to. - void do_object(oop obj) { - HeapWord* obj_addr = (HeapWord*) obj; - assert(_hr->is_in(obj_addr), "sanity"); - size_t obj_size = obj->size(); - _hr->update_bot_for_object(obj_addr, obj_size); - if (obj->is_forwarded() && obj->forwardee() == obj) { - // The object failed to move. - assert(!_g1->is_obj_dead(obj), "We should not be preserving dead objs."); - _cm->markPrev(obj); - assert(_cm->isPrevMarked(obj), "Should be marked!"); - _prev_marked_bytes += (obj_size * HeapWordSize); - if (_g1->mark_in_progress() && !_g1->is_obj_ill(obj)) { - _cm->markAndGrayObjectIfNecessary(obj); - } - obj->set_mark(markOopDesc::prototype()); - // While we were processing RSet buffers during the - // collection, we actually didn't scan any cards on the - // collection set, since we didn't want to update remebered - // sets with entries that point into the collection set, given - // that live objects fromthe collection set are about to move - // and such entries will be stale very soon. This change also - // dealt with a reliability issue which involved scanning a - // card in the collection set and coming across an array that - // was being chunked and looking malformed. The problem is - // that, if evacuation fails, we might have remembered set - // entries missing given that we skipped cards on the - // collection set. So, we'll recreate such entries now. - obj->oop_iterate(_cl); - assert(_cm->isPrevMarked(obj), "Should be marked!"); - } else { - // The object has been either evacuated or is dead. Fill it with a - // dummy object. - MemRegion mr((HeapWord*)obj, obj_size); - CollectedHeap::fill_with_object(mr); - _cm->clearRangeBothMaps(mr); - } - } -}; - void G1CollectedHeap::remove_self_forwarding_pointers() { - UpdateRSetImmediate immediate_update(_g1h->g1_rem_set()); - DirtyCardQueue dcq(&_g1h->dirty_card_queue_set()); - UpdateRSetDeferred deferred_update(_g1h, &dcq); - OopsInHeapRegionClosure *cl; - if (G1DeferredRSUpdate) { - cl = &deferred_update; + assert(check_cset_heap_region_claim_values(HeapRegion::InitialClaimValue), "sanity"); + assert(g1_policy()->assertMarkedBytesDataOK(), "Should be!"); + + G1ParRemoveSelfForwardPtrsTask rsfp_task(this); + + if (G1CollectedHeap::use_parallel_gc_threads()) { + set_par_threads(); + workers()->run_task(&rsfp_task); + set_par_threads(0); } else { - cl = &immediate_update; - } - HeapRegion* cur = g1_policy()->collection_set(); - while (cur != NULL) { - assert(g1_policy()->assertMarkedBytesDataOK(), "Should be!"); - assert(!cur->isHumongous(), "sanity"); - - if (cur->evacuation_failed()) { - assert(cur->in_collection_set(), "bad CS"); - RemoveSelfPointerClosure rspc(_g1h, cur, cl); - - // In the common case we make sure that this is done when the - // region is freed so that it is "ready-to-go" when it's - // re-allocated. However, when evacuation failure happens, a - // region will remain in the heap and might ultimately be added - // to a CSet in the future. So we have to be careful here and - // make sure the region's RSet is ready for parallel iteration - // whenever this might be required in the future. - cur->rem_set()->reset_for_par_iteration(); - cur->reset_bot(); - cl->set_region(cur); - cur->object_iterate(&rspc); - - // A number of manipulations to make the TAMS be the current top, - // and the marked bytes be the ones observed in the iteration. - if (_g1h->concurrent_mark()->at_least_one_mark_complete()) { - // The comments below are the postconditions achieved by the - // calls. Note especially the last such condition, which says that - // the count of marked bytes has been properly restored. - cur->note_start_of_marking(false); - // _next_top_at_mark_start == top, _next_marked_bytes == 0 - cur->add_to_marked_bytes(rspc.prev_marked_bytes()); - // _next_marked_bytes == prev_marked_bytes. - cur->note_end_of_marking(); - // _prev_top_at_mark_start == top(), - // _prev_marked_bytes == prev_marked_bytes - } - // If there is no mark in progress, we modified the _next variables - // above needlessly, but harmlessly. - if (_g1h->mark_in_progress()) { - cur->note_start_of_marking(false); - // _next_top_at_mark_start == top, _next_marked_bytes == 0 - // _next_marked_bytes == next_marked_bytes. - } - } - cur = cur->next_in_collection_set(); - } + rsfp_task.work(0); + } + + assert(check_cset_heap_region_claim_values(HeapRegion::ParEvacFailureClaimValue), "sanity"); + + // Reset the claim values in the regions in the collection set. + reset_cset_heap_region_claim_values(); + + assert(check_cset_heap_region_claim_values(HeapRegion::InitialClaimValue), "sanity"); assert(g1_policy()->assertMarkedBytesDataOK(), "Should be!"); // Now restore saved marks, if any. @@ -4148,6 +4030,7 @@ markOop m = _preserved_marks_of_objs->at(i); obj->set_mark(m); } + // Delete the preserved marks growable arrays (allocated on the C heap). delete _objs_with_preserved_marks; delete _preserved_marks_of_objs; @@ -4172,8 +4055,7 @@ oop G1CollectedHeap::handle_evacuation_failure_par(OopsInHeapRegionClosure* cl, - oop old, - bool should_mark_root) { + oop old) { assert(obj_in_cs(old), err_msg("obj: "PTR_FORMAT" should still be in the CSet", (HeapWord*) old)); @@ -4182,15 +4064,6 @@ if (forward_ptr == NULL) { // Forward-to-self succeeded. - // should_mark_root will be true when this routine is called - // from a root scanning closure during an initial mark pause. - // In this case the thread that succeeds in self-forwarding the - // object is also responsible for marking the object. - if (should_mark_root) { - assert(!oopDesc::is_null(old), "shouldn't be"); - _cm->grayRoot(old); - } - if (_evac_failure_closure != cl) { MutexLockerEx x(EvacFailureStack_lock, Mutex::_no_safepoint_check_flag); assert(!_drain_in_progress, @@ -4286,30 +4159,8 @@ return NULL; } -#ifndef PRODUCT -bool GCLabBitMapClosure::do_bit(size_t offset) { - HeapWord* addr = _bitmap->offsetToHeapWord(offset); - guarantee(_cm->isMarked(oop(addr)), "it should be!"); - return true; -} -#endif // PRODUCT - G1ParGCAllocBuffer::G1ParGCAllocBuffer(size_t gclab_word_size) : - ParGCAllocBuffer(gclab_word_size), - _should_mark_objects(false), - _bitmap(G1CollectedHeap::heap()->reserved_region().start(), gclab_word_size), - _retired(false) -{ - //_should_mark_objects is set to true when G1ParCopyHelper needs to - // mark the forwarded location of an evacuated object. - // We set _should_mark_objects to true if marking is active, i.e. when we - // need to propagate a mark, or during an initial mark pause, i.e. when we - // need to mark objects immediately reachable by the roots. - if (G1CollectedHeap::heap()->mark_in_progress() || - G1CollectedHeap::heap()->g1_policy()->during_initial_mark_pause()) { - _should_mark_objects = true; - } -} + ParGCAllocBuffer(gclab_word_size), _retired(false) { } G1ParScanThreadState::G1ParScanThreadState(G1CollectedHeap* g1h, int queue_num) : _g1h(g1h), @@ -4323,8 +4174,7 @@ _tenured_alloc_buffer(g1h->desired_plab_sz(GCAllocForTenured)), _age_table(false), _strong_roots_time(0), _term_time(0), - _alloc_buffer_waste(0), _undo_waste(0) -{ + _alloc_buffer_waste(0), _undo_waste(0) { // we allocate G1YoungSurvRateNumRegions plus one entries, since // we "sacrifice" entry 0 to keep track of surviving bytes for // non-young regions (where the age is -1) @@ -4429,35 +4279,53 @@ } while (!refs()->is_empty()); } -G1ParClosureSuper::G1ParClosureSuper(G1CollectedHeap* g1, G1ParScanThreadState* par_scan_state) : +G1ParClosureSuper::G1ParClosureSuper(G1CollectedHeap* g1, + G1ParScanThreadState* par_scan_state) : _g1(g1), _g1_rem(_g1->g1_rem_set()), _cm(_g1->concurrent_mark()), _par_scan_state(par_scan_state), _during_initial_mark(_g1->g1_policy()->during_initial_mark_pause()), _mark_in_progress(_g1->mark_in_progress()) { } -template <class T> void G1ParCopyHelper::mark_object(T* p) { - // This is called from do_oop_work for objects that are not - // in the collection set. Objects in the collection set - // are marked after they have been evacuated. - - T heap_oop = oopDesc::load_heap_oop(p); - if (!oopDesc::is_null(heap_oop)) { - oop obj = oopDesc::decode_heap_oop(heap_oop); - HeapWord* addr = (HeapWord*)obj; - if (_g1->is_in_g1_reserved(addr)) { - _cm->grayRoot(oop(addr)); - } - } -} - -oop G1ParCopyHelper::copy_to_survivor_space(oop old, bool should_mark_root, - bool should_mark_copy) { +void G1ParCopyHelper::mark_object(oop obj) { +#ifdef ASSERT + HeapRegion* hr = _g1->heap_region_containing(obj); + assert(hr != NULL, "sanity"); + assert(!hr->in_collection_set(), "should not mark objects in the CSet"); +#endif // ASSERT + + // We know that the object is not moving so it's safe to read its size. + _cm->grayRoot(obj, (size_t) obj->size()); +} + +void G1ParCopyHelper::mark_forwarded_object(oop from_obj, oop to_obj) { +#ifdef ASSERT + assert(from_obj->is_forwarded(), "from obj should be forwarded"); + assert(from_obj->forwardee() == to_obj, "to obj should be the forwardee"); + assert(from_obj != to_obj, "should not be self-forwarded"); + + HeapRegion* from_hr = _g1->heap_region_containing(from_obj); + assert(from_hr != NULL, "sanity"); + assert(from_hr->in_collection_set(), "from obj should be in the CSet"); + + HeapRegion* to_hr = _g1->heap_region_containing(to_obj); + assert(to_hr != NULL, "sanity"); + assert(!to_hr->in_collection_set(), "should not mark objects in the CSet"); +#endif // ASSERT + + // The object might be in the process of being copied by another + // worker so we cannot trust that its to-space image is + // well-formed. So we have to read its size from its from-space + // image which we know should not be changing. + _cm->grayRoot(to_obj, (size_t) from_obj->size()); +} + +oop G1ParCopyHelper::copy_to_survivor_space(oop old) { size_t word_sz = old->size(); HeapRegion* from_region = _g1->heap_region_containing_raw(old); // +1 to make the -1 indexes valid... int young_index = from_region->young_index_in_cset()+1; - assert( (from_region->is_young() && young_index > 0) || - (!from_region->is_young() && young_index == 0), "invariant" ); + assert( (from_region->is_young() && young_index > 0) || + (!from_region->is_young() && young_index == 0), "invariant" ); G1CollectorPolicy* g1p = _g1->g1_policy(); markOop m = old->mark(); int age = m->has_displaced_mark_helper() ? m->displaced_mark_helper()->age() @@ -4471,7 +4339,7 @@ // This will either forward-to-self, or detect that someone else has // installed a forwarding pointer. OopsInHeapRegionClosure* cl = _par_scan_state->evac_failure_closure(); - return _g1->handle_evacuation_failure_par(cl, old, should_mark_root); + return _g1->handle_evacuation_failure_par(cl, old); } // We're going to allocate linearly, so might as well prefetch ahead. @@ -4507,28 +4375,14 @@ obj->set_mark(m); } - // Mark the evacuated object or propagate "next" mark bit - if (should_mark_copy) { - if (!use_local_bitmaps || - !_par_scan_state->alloc_buffer(alloc_purpose)->mark(obj_ptr)) { - // if we couldn't mark it on the local bitmap (this happens when - // the object was not allocated in the GCLab), we have to bite - // the bullet and do the standard parallel mark - _cm->markAndGrayObjectIfNecessary(obj); - } - - if (_g1->isMarkedNext(old)) { - // Unmark the object's old location so that marking - // doesn't think the old object is alive. - _cm->nextMarkBitMap()->parClear((HeapWord*)old); - } - } - size_t* surv_young_words = _par_scan_state->surviving_young_words(); surv_young_words[young_index] += word_sz; if (obj->is_objArray() && arrayOop(obj)->length() >= ParGCArrayScanChunk) { - arrayOop(old)->set_length(0); + // We keep track of the next start index in the length field of + // the to-space object. The actual length can be found in the + // length field of the from-space object. + arrayOop(obj)->set_length(0); oop* old_p = set_partial_array_mask(old); _par_scan_state->push_on_queue(old_p); } else { @@ -4550,61 +4404,24 @@ ::do_oop_work(T* p) { oop obj = oopDesc::load_decode_heap_oop(p); assert(barrier != G1BarrierRS || obj != NULL, - "Precondition: G1BarrierRS implies obj is nonNull"); - - // Marking: - // If the object is in the collection set, then the thread - // that copies the object should mark, or propagate the - // mark to, the evacuated object. - // If the object is not in the collection set then we - // should call the mark_object() method depending on the - // value of the template parameter do_mark_object (which will - // be true for root scanning closures during an initial mark - // pause). - // The mark_object() method first checks whether the object - // is marked and, if not, attempts to mark the object. + "Precondition: G1BarrierRS implies obj is non-NULL"); // here the null check is implicit in the cset_fast_test() test if (_g1->in_cset_fast_test(obj)) { + oop forwardee; if (obj->is_forwarded()) { - oopDesc::encode_store_heap_oop(p, obj->forwardee()); - // If we are a root scanning closure during an initial - // mark pause (i.e. do_mark_object will be true) then - // we also need to handle marking of roots in the - // event of an evacuation failure. In the event of an - // evacuation failure, the object is forwarded to itself - // and not copied. For root-scanning closures, the - // object would be marked after a successful self-forward - // but an object could be pointed to by both a root and non - // root location and be self-forwarded by a non-root-scanning - // closure. Therefore we also have to attempt to mark the - // self-forwarded root object here. - if (do_mark_object && obj->forwardee() == obj) { - mark_object(p); - } + forwardee = obj->forwardee(); } else { - // During an initial mark pause, objects that are pointed to - // by the roots need to be marked - even in the event of an - // evacuation failure. We pass the template parameter - // do_mark_object (which is true for root scanning closures - // during an initial mark pause) to copy_to_survivor_space - // which will pass it on to the evacuation failure handling - // code. The thread that successfully self-forwards a root - // object to itself is responsible for marking the object. - bool should_mark_root = do_mark_object; - - // We need to mark the copied object if we're a root scanning - // closure during an initial mark pause (i.e. do_mark_object - // will be true), or the object is already marked and we need - // to propagate the mark to the evacuated copy. - bool should_mark_copy = do_mark_object || - _during_initial_mark || - (_mark_in_progress && !_g1->is_obj_ill(obj)); - - oop copy_oop = copy_to_survivor_space(obj, should_mark_root, - should_mark_copy); - oopDesc::encode_store_heap_oop(p, copy_oop); + forwardee = copy_to_survivor_space(obj); } + assert(forwardee != NULL, "forwardee should not be NULL"); + oopDesc::encode_store_heap_oop(p, forwardee); + if (do_mark_object && forwardee != obj) { + // If the object is self-forwarded we don't need to explicitly + // mark it, the evacuation failure protocol will do so. + mark_forwarded_object(obj, forwardee); + } + // When scanning the RS, we only care about objs in CS. if (barrier == G1BarrierRS) { _par_scan_state->update_rs(_from, p, _par_scan_state->queue_num()); @@ -4613,8 +4430,8 @@ // The object is not in collection set. If we're a root scanning // closure during an initial mark pause (i.e. do_mark_object will // be true) then attempt to mark the object. - if (do_mark_object) { - mark_object(p); + if (do_mark_object && _g1->is_in_g1_reserved(obj)) { + mark_object(obj); } } @@ -4632,35 +4449,51 @@ template <class T> void G1ParScanPartialArrayClosure::do_oop_nv(T* p) { assert(has_partial_array_mask(p), "invariant"); - oop old = clear_partial_array_mask(p); - assert(old->is_objArray(), "must be obj array"); - assert(old->is_forwarded(), "must be forwarded"); - assert(Universe::heap()->is_in_reserved(old), "must be in heap."); - - objArrayOop obj = objArrayOop(old->forwardee()); - assert((void*)old != (void*)old->forwardee(), "self forwarding here?"); - // Process ParGCArrayScanChunk elements now - // and push the remainder back onto queue - int start = arrayOop(old)->length(); - int end = obj->length(); - int remainder = end - start; - assert(start <= end, "just checking"); + oop from_obj = clear_partial_array_mask(p); + + assert(Universe::heap()->is_in_reserved(from_obj), "must be in heap."); + assert(from_obj->is_objArray(), "must be obj array"); + objArrayOop from_obj_array = objArrayOop(from_obj); + // The from-space object contains the real length. + int length = from_obj_array->length(); + + assert(from_obj->is_forwarded(), "must be forwarded"); + oop to_obj = from_obj->forwardee(); + assert(from_obj != to_obj, "should not be chunking self-forwarded objects"); + objArrayOop to_obj_array = objArrayOop(to_obj); + // We keep track of the next start index in the length field of the + // to-space object. + int next_index = to_obj_array->length(); + assert(0 <= next_index && next_index < length, + err_msg("invariant, next index: %d, length: %d", next_index, length)); + + int start = next_index; + int end = length; + int remainder = end - start; + // We'll try not to push a range that's smaller than ParGCArrayScanChunk. if (remainder > 2 * ParGCArrayScanChunk) { - // Test above combines last partial chunk with a full chunk end = start + ParGCArrayScanChunk; - arrayOop(old)->set_length(end); - // Push remainder. - oop* old_p = set_partial_array_mask(old); - assert(arrayOop(old)->length() < obj->length(), "Empty push?"); - _par_scan_state->push_on_queue(old_p); + to_obj_array->set_length(end); + // Push the remainder before we process the range in case another + // worker has run out of things to do and can steal it. + oop* from_obj_p = set_partial_array_mask(from_obj); + _par_scan_state->push_on_queue(from_obj_p); } else { - // Restore length so that the heap remains parsable in - // case of evacuation failure. - arrayOop(old)->set_length(end); - } - _scanner.set_region(_g1->heap_region_containing_raw(obj)); - // process our set of indices (include header in first chunk) - obj->oop_iterate_range(&_scanner, start, end); + assert(length == end, "sanity"); + // We'll process the final range for this object. Restore the length + // so that the heap remains parsable in case of evacuation failure. + to_obj_array->set_length(end); + } + _scanner.set_region(_g1->heap_region_containing_raw(to_obj)); + // Process indexes [start,end). It will also process the header + // along with the first chunk (i.e., the chunk with start == 0). + // Note that at this point the length field of to_obj_array is not + // correct given that we are using it to keep track of the next + // start index. oop_iterate_range() (thankfully!) ignores the length + // field and only relies on the start / end parameters. It does + // however return the size of the object which will be incorrect. So + // we have to ignore it even if we wanted to use it. + to_obj_array->oop_iterate_range(&_scanner, start, end); } class G1ParEvacuateFollowersClosure : public VoidClosure { @@ -4893,12 +4726,16 @@ g1_policy()->record_ext_root_scan_time(worker_i, ext_root_time_ms); - // Scan strong roots in mark stack. - if (!_process_strong_tasks->is_task_claimed(G1H_PS_mark_stack_oops_do)) { - concurrent_mark()->oops_do(scan_non_heap_roots); - } - double mark_stack_scan_ms = (os::elapsedTime() - ext_roots_end) * 1000.0; - g1_policy()->record_mark_stack_scan_time(worker_i, mark_stack_scan_ms); + // During conc marking we have to filter the per-thread SATB buffers + // to make sure we remove any oops into the CSet (which will show up + // as implicitly live). + if (!_process_strong_tasks->is_task_claimed(G1H_PS_filter_satb_buffers)) { + if (mark_in_progress()) { + JavaThread::satb_mark_queue_set().filter_thread_buffers(); + } + } + double satb_filtering_ms = (os::elapsedTime() - ext_roots_end) * 1000.0; + g1_policy()->record_satb_filtering_time(worker_i, satb_filtering_ms); // Now scan the complement of the collection set. if (scan_rs != NULL) { @@ -5439,6 +5276,7 @@ } void G1CollectedHeap::evacuate_collection_set() { + _expand_heap_after_alloc_failure = true; set_evacuation_failed(false); g1_rem_set()->prepare_for_oops_into_collection_set_do(); @@ -5516,13 +5354,6 @@ finalize_for_evac_failure(); - // Must do this before clearing the per-region evac-failure flags - // (which is currently done when we free the collection set). - // We also only do this if marking is actually in progress and so - // have to do this before we set the mark_in_progress flag at the - // end of an initial mark pause. - concurrent_mark()->complete_marking_in_collection_set(); - if (evacuation_failed()) { remove_self_forwarding_pointers(); if (PrintGCDetails) { @@ -6179,6 +6010,8 @@ } else { _hr_printer.alloc(new_alloc_region, G1HRPrinter::Old); } + bool during_im = g1_policy()->during_initial_mark_pause(); + new_alloc_region->note_start_of_copying(during_im); return new_alloc_region; } else { g1_policy()->note_alloc_region_limit_reached(ap); @@ -6190,7 +6023,8 @@ void G1CollectedHeap::retire_gc_alloc_region(HeapRegion* alloc_region, size_t allocated_bytes, GCAllocPurpose ap) { - alloc_region->note_end_of_copying(); + bool during_im = g1_policy()->during_initial_mark_pause(); + alloc_region->note_end_of_copying(during_im); g1_policy()->record_bytes_copied_during_gc(allocated_bytes); if (ap == GCAllocForSurvived) { young_list()->add_survivor_region(alloc_region);
--- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp Thu Jan 19 17:20:39 2012 -0800 +++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp Thu Jan 19 18:35:13 2012 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2012, 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 @@ -285,6 +285,14 @@ // Typically, it is not full so we should re-use it during the next GC. HeapRegion* _retained_old_gc_alloc_region; + // It specifies whether we should attempt to expand the heap after a + // region allocation failure. If heap expansion fails we set this to + // false so that we don't re-attempt the heap expansion (it's likely + // that subsequent expansion attempts will also fail if one fails). + // Currently, it is only consulted during GC and it's reset at the + // start of each GC. + bool _expand_heap_after_alloc_failure; + // It resets the mutator alloc region before new allocations can take place. void init_mutator_alloc_region(); @@ -861,8 +869,7 @@ void finalize_for_evac_failure(); // An attempt to evacuate "obj" has failed; take necessary steps. - oop handle_evacuation_failure_par(OopsInHeapRegionClosure* cl, oop obj, - bool should_mark_root); + oop handle_evacuation_failure_par(OopsInHeapRegionClosure* cl, oop obj); void handle_evacuation_failure_common(oop obj, markOop m); // ("Weak") Reference processing support. @@ -954,7 +961,7 @@ unsigned int* _worker_cset_start_region_time_stamp; enum G1H_process_strong_roots_tasks { - G1H_PS_mark_stack_oops_do, + G1H_PS_filter_satb_buffers, G1H_PS_refProcessor_oops_do, // Leave this one last. G1H_PS_NumElements @@ -1305,6 +1312,10 @@ // It resets all the region claim values to the default. void reset_heap_region_claim_values(); + // Resets the claim values of regions in the current + // collection set to the default. + void reset_cset_heap_region_claim_values(); + #ifdef ASSERT bool check_heap_region_claim_values(jint claim_value); @@ -1740,10 +1751,8 @@ _gclab_word_size(gclab_word_size), _real_start_word(NULL), _real_end_word(NULL), - _start_word(NULL) - { - guarantee( size_in_words() >= bitmap_size_in_words(), - "just making sure"); + _start_word(NULL) { + guarantee(false, "GCLabBitMap::GCLabBitmap(): don't call this any more"); } inline unsigned heapWordToOffset(HeapWord* addr) { @@ -1797,6 +1806,8 @@ } void set_buffer(HeapWord* start) { + guarantee(false, "set_buffer(): don't call this any more"); + guarantee(use_local_bitmaps, "invariant"); clear(); @@ -1820,6 +1831,8 @@ #endif // PRODUCT void retire() { + guarantee(false, "retire(): don't call this any more"); + guarantee(use_local_bitmaps, "invariant"); assert(fields_well_formed(), "invariant"); @@ -1853,32 +1866,18 @@ class G1ParGCAllocBuffer: public ParGCAllocBuffer { private: bool _retired; - bool _should_mark_objects; - GCLabBitMap _bitmap; public: G1ParGCAllocBuffer(size_t gclab_word_size); - inline bool mark(HeapWord* addr) { - guarantee(use_local_bitmaps, "invariant"); - assert(_should_mark_objects, "invariant"); - return _bitmap.mark(addr); - } - - inline void set_buf(HeapWord* buf) { - if (use_local_bitmaps && _should_mark_objects) { - _bitmap.set_buffer(buf); - } + void set_buf(HeapWord* buf) { ParGCAllocBuffer::set_buf(buf); _retired = false; } - inline void retire(bool end_of_gc, bool retain) { + void retire(bool end_of_gc, bool retain) { if (_retired) return; - if (use_local_bitmaps && _should_mark_objects) { - _bitmap.retire(); - } ParGCAllocBuffer::retire(end_of_gc, retain); _retired = true; }
--- a/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp Thu Jan 19 17:20:39 2012 -0800 +++ b/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp Thu Jan 19 18:35:13 2012 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2012, 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 @@ -281,7 +281,7 @@ _par_last_gc_worker_start_times_ms = new double[_parallel_gc_threads]; _par_last_ext_root_scan_times_ms = new double[_parallel_gc_threads]; - _par_last_mark_stack_scan_times_ms = new double[_parallel_gc_threads]; + _par_last_satb_filtering_times_ms = new double[_parallel_gc_threads]; _par_last_update_rs_times_ms = new double[_parallel_gc_threads]; _par_last_update_rs_processed_buffers = new double[_parallel_gc_threads]; @@ -905,10 +905,19 @@ gclog_or_tty->print(" (%s)", gcs_are_young() ? "young" : "mixed"); } - // We only need to do this here as the policy will only be applied - // to the GC we're about to start. so, no point is calculating this - // every time we calculate / recalculate the target young length. - update_survivors_policy(); + if (!during_initial_mark_pause()) { + // We only need to do this here as the policy will only be applied + // to the GC we're about to start. so, no point is calculating this + // every time we calculate / recalculate the target young length. + update_survivors_policy(); + } else { + // The marking phase has a "we only copy implicitly live + // objects during marking" invariant. The easiest way to ensure it + // holds is not to allocate any survivor regions and tenure all + // objects. In the future we might change this and handle survivor + // regions specially during marking. + tenure_all_objects(); + } assert(_g1->used() == _g1->recalculate_used(), err_msg("sanity, used: "SIZE_FORMAT" recalculate_used: "SIZE_FORMAT, @@ -939,7 +948,7 @@ for (int i = 0; i < _parallel_gc_threads; ++i) { _par_last_gc_worker_start_times_ms[i] = -1234.0; _par_last_ext_root_scan_times_ms[i] = -1234.0; - _par_last_mark_stack_scan_times_ms[i] = -1234.0; + _par_last_satb_filtering_times_ms[i] = -1234.0; _par_last_update_rs_times_ms[i] = -1234.0; _par_last_update_rs_processed_buffers[i] = -1234.0; _par_last_scan_rs_times_ms[i] = -1234.0; @@ -1227,7 +1236,7 @@ // of the PrintGCDetails output, in the non-parallel case. double ext_root_scan_time = avg_value(_par_last_ext_root_scan_times_ms); - double mark_stack_scan_time = avg_value(_par_last_mark_stack_scan_times_ms); + double satb_filtering_time = avg_value(_par_last_satb_filtering_times_ms); double update_rs_time = avg_value(_par_last_update_rs_times_ms); double update_rs_processed_buffers = sum_of_values(_par_last_update_rs_processed_buffers); @@ -1236,7 +1245,7 @@ double termination_time = avg_value(_par_last_termination_times_ms); double known_time = ext_root_scan_time + - mark_stack_scan_time + + satb_filtering_time + update_rs_time + scan_rs_time + obj_copy_time; @@ -1282,7 +1291,7 @@ body_summary->record_satb_drain_time_ms(_cur_satb_drain_time_ms); body_summary->record_ext_root_scan_time_ms(ext_root_scan_time); - body_summary->record_mark_stack_scan_time_ms(mark_stack_scan_time); + body_summary->record_satb_filtering_time_ms(satb_filtering_time); body_summary->record_update_rs_time_ms(update_rs_time); body_summary->record_scan_rs_time_ms(scan_rs_time); body_summary->record_obj_copy_time_ms(obj_copy_time); @@ -1376,16 +1385,12 @@ (last_pause_included_initial_mark) ? " (initial-mark)" : "", elapsed_ms / 1000.0); - if (print_marking_info) { - print_stats(1, "SATB Drain Time", _cur_satb_drain_time_ms); - } - if (parallel) { print_stats(1, "Parallel Time", _cur_collection_par_time_ms); print_par_stats(2, "GC Worker Start", _par_last_gc_worker_start_times_ms); print_par_stats(2, "Ext Root Scanning", _par_last_ext_root_scan_times_ms); if (print_marking_info) { - print_par_stats(2, "Mark Stack Scanning", _par_last_mark_stack_scan_times_ms); + print_par_stats(2, "SATB Filtering", _par_last_satb_filtering_times_ms); } print_par_stats(2, "Update RS", _par_last_update_rs_times_ms); print_par_sizes(3, "Processed Buffers", _par_last_update_rs_processed_buffers); @@ -1399,7 +1404,7 @@ _par_last_gc_worker_times_ms[i] = _par_last_gc_worker_end_times_ms[i] - _par_last_gc_worker_start_times_ms[i]; double worker_known_time = _par_last_ext_root_scan_times_ms[i] + - _par_last_mark_stack_scan_times_ms[i] + + _par_last_satb_filtering_times_ms[i] + _par_last_update_rs_times_ms[i] + _par_last_scan_rs_times_ms[i] + _par_last_obj_copy_times_ms[i] + @@ -1412,7 +1417,7 @@ } else { print_stats(1, "Ext Root Scanning", ext_root_scan_time); if (print_marking_info) { - print_stats(1, "Mark Stack Scanning", mark_stack_scan_time); + print_stats(1, "SATB Filtering", satb_filtering_time); } print_stats(1, "Update RS", update_rs_time); print_stats(2, "Processed Buffers", (int)update_rs_processed_buffers); @@ -1983,11 +1988,10 @@ if (summary->get_total_seq()->num() > 0) { print_summary_sd(0, "Evacuation Pauses", summary->get_total_seq()); if (body_summary != NULL) { - print_summary(1, "SATB Drain", body_summary->get_satb_drain_seq()); if (parallel) { print_summary(1, "Parallel Time", body_summary->get_parallel_seq()); print_summary(2, "Ext Root Scanning", body_summary->get_ext_root_scan_seq()); - print_summary(2, "Mark Stack Scanning", body_summary->get_mark_stack_scan_seq()); + print_summary(2, "SATB Filtering", body_summary->get_satb_filtering_seq()); print_summary(2, "Update RS", body_summary->get_update_rs_seq()); print_summary(2, "Scan RS", body_summary->get_scan_rs_seq()); print_summary(2, "Object Copy", body_summary->get_obj_copy_seq()); @@ -1996,7 +2000,7 @@ { NumberSeq* other_parts[] = { body_summary->get_ext_root_scan_seq(), - body_summary->get_mark_stack_scan_seq(), + body_summary->get_satb_filtering_seq(), body_summary->get_update_rs_seq(), body_summary->get_scan_rs_seq(), body_summary->get_obj_copy_seq(), @@ -2009,7 +2013,7 @@ } } else { print_summary(1, "Ext Root Scanning", body_summary->get_ext_root_scan_seq()); - print_summary(1, "Mark Stack Scanning", body_summary->get_mark_stack_scan_seq()); + print_summary(1, "SATB Filtering", body_summary->get_satb_filtering_seq()); print_summary(1, "Update RS", body_summary->get_update_rs_seq()); print_summary(1, "Scan RS", body_summary->get_scan_rs_seq()); print_summary(1, "Object Copy", body_summary->get_obj_copy_seq()); @@ -2036,7 +2040,7 @@ body_summary->get_satb_drain_seq(), body_summary->get_update_rs_seq(), body_summary->get_ext_root_scan_seq(), - body_summary->get_mark_stack_scan_seq(), + body_summary->get_satb_filtering_seq(), body_summary->get_scan_rs_seq(), body_summary->get_obj_copy_seq() }; @@ -2433,9 +2437,6 @@ assert(_inc_cset_build_state == Active, "Precondition"); assert(!hr->is_young(), "non-incremental add of young region"); - if (_g1->mark_in_progress()) - _g1->concurrent_mark()->registerCSetRegion(hr); - assert(!hr->in_collection_set(), "should not already be in the CSet"); hr->set_in_collection_set(true); hr->set_next_in_collection_set(_collection_set); @@ -2705,9 +2706,6 @@ // Clear the fields that point to the survivor list - they are all young now. young_list->clear_survivors(); - if (_g1->mark_in_progress()) - _g1->concurrent_mark()->register_collection_set_finger(_inc_cset_max_finger); - _collection_set = _inc_cset_head; _collection_set_bytes_used_before = _inc_cset_bytes_used_before; time_remaining_ms -= _inc_cset_predicted_elapsed_time_ms;
--- a/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp Thu Jan 19 17:20:39 2012 -0800 +++ b/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp Thu Jan 19 18:35:13 2012 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2012, 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 @@ -67,7 +67,7 @@ define_num_seq(satb_drain) // optional define_num_seq(parallel) // parallel only define_num_seq(ext_root_scan) - define_num_seq(mark_stack_scan) + define_num_seq(satb_filtering) define_num_seq(update_rs) define_num_seq(scan_rs) define_num_seq(obj_copy) @@ -215,7 +215,7 @@ double* _par_last_gc_worker_start_times_ms; double* _par_last_ext_root_scan_times_ms; - double* _par_last_mark_stack_scan_times_ms; + double* _par_last_satb_filtering_times_ms; double* _par_last_update_rs_times_ms; double* _par_last_update_rs_processed_buffers; double* _par_last_scan_rs_times_ms; @@ -841,8 +841,8 @@ _par_last_ext_root_scan_times_ms[worker_i] = ms; } - void record_mark_stack_scan_time(int worker_i, double ms) { - _par_last_mark_stack_scan_times_ms[worker_i] = ms; + void record_satb_filtering_time(int worker_i, double ms) { + _par_last_satb_filtering_times_ms[worker_i] = ms; } void record_satb_drain_time(double ms) { @@ -1146,6 +1146,11 @@ _survivor_surv_rate_group->stop_adding_regions(); } + void tenure_all_objects() { + _max_survivor_regions = 0; + _tenuring_threshold = 0; + } + void record_survivor_regions(size_t regions, HeapRegion* head, HeapRegion* tail) {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/gc_implementation/g1/g1EvacFailure.hpp Thu Jan 19 18:35:13 2012 -0800 @@ -0,0 +1,236 @@ +/* + * Copyright (c) 2012, 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. + * + */ + +#ifndef SHARE_VM_GC_IMPLEMENTATION_G1_G1EVACFAILURE_HPP +#define SHARE_VM_GC_IMPLEMENTATION_G1_G1EVACFAILURE_HPP + +#include "gc_implementation/g1/concurrentMark.inline.hpp" +#include "gc_implementation/g1/dirtyCardQueue.hpp" +#include "gc_implementation/g1/g1CollectedHeap.inline.hpp" +#include "gc_implementation/g1/g1_globals.hpp" +#include "gc_implementation/g1/g1OopClosures.inline.hpp" +#include "gc_implementation/g1/heapRegion.hpp" +#include "gc_implementation/g1/heapRegionRemSet.hpp" +#include "utilities/workgroup.hpp" + +// Closures and tasks associated with any self-forwarding pointers +// installed as a result of an evacuation failure. + +class UpdateRSetDeferred : public OopsInHeapRegionClosure { +private: + G1CollectedHeap* _g1; + DirtyCardQueue *_dcq; + CardTableModRefBS* _ct_bs; + +public: + UpdateRSetDeferred(G1CollectedHeap* g1, DirtyCardQueue* dcq) : + _g1(g1), _ct_bs((CardTableModRefBS*)_g1->barrier_set()), _dcq(dcq) {} + + virtual void do_oop(narrowOop* p) { do_oop_work(p); } + virtual void do_oop( oop* p) { do_oop_work(p); } + template <class T> void do_oop_work(T* p) { + assert(_from->is_in_reserved(p), "paranoia"); + if (!_from->is_in_reserved(oopDesc::load_decode_heap_oop(p)) && + !_from->is_survivor()) { + size_t card_index = _ct_bs->index_for(p); + if (_ct_bs->mark_card_deferred(card_index)) { + _dcq->enqueue((jbyte*)_ct_bs->byte_for_index(card_index)); + } + } + } +}; + +class RemoveSelfForwardPtrObjClosure: public ObjectClosure { +private: + G1CollectedHeap* _g1; + ConcurrentMark* _cm; + HeapRegion* _hr; + size_t _marked_bytes; + OopsInHeapRegionClosure *_update_rset_cl; + bool _during_initial_mark; + bool _during_conc_mark; +public: + RemoveSelfForwardPtrObjClosure(G1CollectedHeap* g1, ConcurrentMark* cm, + HeapRegion* hr, + OopsInHeapRegionClosure* update_rset_cl, + bool during_initial_mark, + bool during_conc_mark) : + _g1(g1), _cm(cm), _hr(hr), _marked_bytes(0), + _update_rset_cl(update_rset_cl), + _during_initial_mark(during_initial_mark), + _during_conc_mark(during_conc_mark) { } + + size_t marked_bytes() { return _marked_bytes; } + + // <original comment> + // The original idea here was to coalesce evacuated and dead objects. + // However that caused complications with the block offset table (BOT). + // In particular if there were two TLABs, one of them partially refined. + // |----- TLAB_1--------|----TLAB_2-~~~(partially refined part)~~~| + // The BOT entries of the unrefined part of TLAB_2 point to the start + // of TLAB_2. If the last object of the TLAB_1 and the first object + // of TLAB_2 are coalesced, then the cards of the unrefined part + // would point into middle of the filler object. + // The current approach is to not coalesce and leave the BOT contents intact. + // </original comment> + // + // We now reset the BOT when we start the object iteration over the + // region and refine its entries for every object we come across. So + // the above comment is not really relevant and we should be able + // to coalesce dead objects if we want to. + void do_object(oop obj) { + HeapWord* obj_addr = (HeapWord*) obj; + assert(_hr->is_in(obj_addr), "sanity"); + size_t obj_size = obj->size(); + _hr->update_bot_for_object(obj_addr, obj_size); + + if (obj->is_forwarded() && obj->forwardee() == obj) { + // The object failed to move. + + // We consider all objects that we find self-forwarded to be + // live. What we'll do is that we'll update the prev marking + // info so that they are all under PTAMS and explicitly marked. + _cm->markPrev(obj); + if (_during_initial_mark) { + // For the next marking info we'll only mark the + // self-forwarded objects explicitly if we are during + // initial-mark (since, normally, we only mark objects pointed + // to by roots if we succeed in copying them). By marking all + // self-forwarded objects we ensure that we mark any that are + // still pointed to be roots. During concurrent marking, and + // after initial-mark, we don't need to mark any objects + // explicitly and all objects in the CSet are considered + // (implicitly) live. So, we won't mark them explicitly and + // we'll leave them over NTAMS. + _cm->markNext(obj); + } + _marked_bytes += (obj_size * HeapWordSize); + obj->set_mark(markOopDesc::prototype()); + + // While we were processing RSet buffers during the collection, + // we actually didn't scan any cards on the collection set, + // since we didn't want to update remembered sets with entries + // that point into the collection set, given that live objects + // from the collection set are about to move and such entries + // will be stale very soon. + // This change also dealt with a reliability issue which + // involved scanning a card in the collection set and coming + // across an array that was being chunked and looking malformed. + // The problem is that, if evacuation fails, we might have + // remembered set entries missing given that we skipped cards on + // the collection set. So, we'll recreate such entries now. + obj->oop_iterate(_update_rset_cl); + assert(_cm->isPrevMarked(obj), "Should be marked!"); + } else { + // The object has been either evacuated or is dead. Fill it with a + // dummy object. + MemRegion mr((HeapWord*) obj, obj_size); + CollectedHeap::fill_with_object(mr); + } + } +}; + +class RemoveSelfForwardPtrHRClosure: public HeapRegionClosure { + G1CollectedHeap* _g1h; + ConcurrentMark* _cm; + OopsInHeapRegionClosure *_update_rset_cl; + +public: + RemoveSelfForwardPtrHRClosure(G1CollectedHeap* g1h, + OopsInHeapRegionClosure* update_rset_cl) : + _g1h(g1h), _update_rset_cl(update_rset_cl), + _cm(_g1h->concurrent_mark()) { } + + bool doHeapRegion(HeapRegion *hr) { + bool during_initial_mark = _g1h->g1_policy()->during_initial_mark_pause(); + bool during_conc_mark = _g1h->mark_in_progress(); + + assert(!hr->isHumongous(), "sanity"); + assert(hr->in_collection_set(), "bad CS"); + + if (hr->claimHeapRegion(HeapRegion::ParEvacFailureClaimValue)) { + if (hr->evacuation_failed()) { + RemoveSelfForwardPtrObjClosure rspc(_g1h, _cm, hr, _update_rset_cl, + during_initial_mark, + during_conc_mark); + + MemRegion mr(hr->bottom(), hr->end()); + // We'll recreate the prev marking info so we'll first clear + // the prev bitmap range for this region. We never mark any + // CSet objects explicitly so the next bitmap range should be + // cleared anyway. + _cm->clearRangePrevBitmap(mr); + + hr->note_self_forwarding_removal_start(during_initial_mark, + during_conc_mark); + + // In the common case (i.e. when there is no evacuation + // failure) we make sure that the following is done when + // the region is freed so that it is "ready-to-go" when it's + // re-allocated. However, when evacuation failure happens, a + // region will remain in the heap and might ultimately be added + // to a CSet in the future. So we have to be careful here and + // make sure the region's RSet is ready for parallel iteration + // whenever this might be required in the future. + hr->rem_set()->reset_for_par_iteration(); + hr->reset_bot(); + _update_rset_cl->set_region(hr); + hr->object_iterate(&rspc); + + hr->note_self_forwarding_removal_end(during_initial_mark, + during_conc_mark, + rspc.marked_bytes()); + } + } + return false; + } +}; + +class G1ParRemoveSelfForwardPtrsTask: public AbstractGangTask { +protected: + G1CollectedHeap* _g1h; + +public: + G1ParRemoveSelfForwardPtrsTask(G1CollectedHeap* g1h) : + AbstractGangTask("G1 Remove Self-forwarding Pointers"), + _g1h(g1h) { } + + void work(uint worker_id) { + UpdateRSetImmediate immediate_update(_g1h->g1_rem_set()); + DirtyCardQueue dcq(&_g1h->dirty_card_queue_set()); + UpdateRSetDeferred deferred_update(_g1h, &dcq); + + OopsInHeapRegionClosure *update_rset_cl = &deferred_update; + if (!G1DeferredRSUpdate) { + update_rset_cl = &immediate_update; + } + + RemoveSelfForwardPtrHRClosure rsfp_cl(_g1h, update_rset_cl); + + HeapRegion* hr = _g1h->start_cset_region_for_worker(worker_id); + _g1h->collection_set_iterate_from(hr, &rsfp_cl); + } +}; + +#endif // SHARE_VM_GC_IMPLEMENTATION_G1_G1EVACFAILURE_HPP
--- a/src/share/vm/gc_implementation/g1/g1OopClosures.hpp Thu Jan 19 17:20:39 2012 -0800 +++ b/src/share/vm/gc_implementation/g1/g1OopClosures.hpp Thu Jan 19 18:35:13 2012 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2012, 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 @@ -121,17 +121,25 @@ class G1ParCopyHelper : public G1ParClosureSuper { G1ParScanClosure *_scanner; protected: - template <class T> void mark_object(T* p); - oop copy_to_survivor_space(oop obj, bool should_mark_root, - bool should_mark_copy); + // Mark the object if it's not already marked. This is used to mark + // objects pointed to by roots that are guaranteed not to move + // during the GC (i.e., non-CSet objects). It is MT-safe. + void mark_object(oop obj); + + // Mark the object if it's not already marked. This is used to mark + // objects pointed to by roots that have been forwarded during a + // GC. It is MT-safe. + void mark_forwarded_object(oop from_obj, oop to_obj); + + oop copy_to_survivor_space(oop obj); + public: G1ParCopyHelper(G1CollectedHeap* g1, G1ParScanThreadState* par_scan_state, G1ParScanClosure *scanner) : G1ParClosureSuper(g1, par_scan_state), _scanner(scanner) { } }; -template<bool do_gen_barrier, G1Barrier barrier, - bool do_mark_object> +template <bool do_gen_barrier, G1Barrier barrier, bool do_mark_object> class G1ParCopyClosure : public G1ParCopyHelper { G1ParScanClosure _scanner; @@ -140,9 +148,8 @@ public: G1ParCopyClosure(G1CollectedHeap* g1, G1ParScanThreadState* par_scan_state, ReferenceProcessor* rp) : - _scanner(g1, par_scan_state, rp), - G1ParCopyHelper(g1, par_scan_state, &_scanner) - { + _scanner(g1, par_scan_state, rp), + G1ParCopyHelper(g1, par_scan_state, &_scanner) { assert(_ref_processor == NULL, "sanity"); }
--- a/src/share/vm/gc_implementation/g1/g1_globals.hpp Thu Jan 19 17:20:39 2012 -0800 +++ b/src/share/vm/gc_implementation/g1/g1_globals.hpp Thu Jan 19 18:35:13 2012 -0800 @@ -295,7 +295,7 @@ "Percentage (0-100) of the heap size to use as minimum " \ "young gen size.") \ \ - develop(uintx, G1DefaultMaxNewGenPercent, 50, \ + develop(uintx, G1DefaultMaxNewGenPercent, 80, \ "Percentage (0-100) of the heap size to use as maximum " \ "young gen size.")
--- a/src/share/vm/gc_implementation/g1/heapRegion.cpp Thu Jan 19 17:20:39 2012 -0800 +++ b/src/share/vm/gc_implementation/g1/heapRegion.cpp Thu Jan 19 18:35:13 2012 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2012, 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 @@ -575,6 +575,40 @@ oops_in_mr_iterate(MemRegion(bottom(), saved_mark_word()), cl); } +void HeapRegion::note_self_forwarding_removal_start(bool during_initial_mark, + bool during_conc_mark) { + // We always recreate the prev marking info and we'll explicitly + // mark all objects we find to be self-forwarded on the prev + // bitmap. So all objects need to be below PTAMS. + _prev_top_at_mark_start = top(); + _prev_marked_bytes = 0; + + if (during_initial_mark) { + // During initial-mark, we'll also explicitly mark all objects + // we find to be self-forwarded on the next bitmap. So all + // objects need to be below NTAMS. + _next_top_at_mark_start = top(); + set_top_at_conc_mark_count(bottom()); + _next_marked_bytes = 0; + } else if (during_conc_mark) { + // During concurrent mark, all objects in the CSet (including + // the ones we find to be self-forwarded) are implicitly live. + // So all objects need to be above NTAMS. + _next_top_at_mark_start = bottom(); + set_top_at_conc_mark_count(bottom()); + _next_marked_bytes = 0; + } +} + +void HeapRegion::note_self_forwarding_removal_end(bool during_initial_mark, + bool during_conc_mark, + size_t marked_bytes) { + assert(0 <= marked_bytes && marked_bytes <= used(), + err_msg("marked: "SIZE_FORMAT" used: "SIZE_FORMAT, + marked_bytes, used())); + _prev_marked_bytes = marked_bytes; +} + HeapWord* HeapRegion::object_iterate_mem_careful(MemRegion mr, ObjectClosure* cl) {
--- a/src/share/vm/gc_implementation/g1/heapRegion.hpp Thu Jan 19 17:20:39 2012 -0800 +++ b/src/share/vm/gc_implementation/g1/heapRegion.hpp Thu Jan 19 18:35:13 2012 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2012, 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 @@ -373,7 +373,8 @@ ScrubRemSetClaimValue = 3, ParVerifyClaimValue = 4, RebuildRSClaimValue = 5, - CompleteMarkCSetClaimValue = 6 + CompleteMarkCSetClaimValue = 6, + ParEvacFailureClaimValue = 7 }; inline HeapWord* par_allocate_no_bot_updates(size_t word_size) { @@ -582,37 +583,33 @@ // that the collector is about to start or has finished (concurrently) // marking the heap. - // Note the start of a marking phase. Record the - // start of the unmarked area of the region here. - void note_start_of_marking(bool during_initial_mark) { - init_top_at_conc_mark_count(); - _next_marked_bytes = 0; - if (during_initial_mark && is_young() && !is_survivor()) - _next_top_at_mark_start = bottom(); - else - _next_top_at_mark_start = top(); - } + // Notify the region that concurrent marking is starting. Initialize + // all fields related to the next marking info. + inline void note_start_of_marking(); + + // Notify the region that concurrent marking has finished. Copy the + // (now finalized) next marking info fields into the prev marking + // info fields. + inline void note_end_of_marking(); + + // Notify the region that it will be used as to-space during a GC + // and we are about to start copying objects into it. + inline void note_start_of_copying(bool during_initial_mark); - // Note the end of a marking phase. Install the start of - // the unmarked area that was captured at start of marking. - void note_end_of_marking() { - _prev_top_at_mark_start = _next_top_at_mark_start; - _prev_marked_bytes = _next_marked_bytes; - _next_marked_bytes = 0; + // Notify the region that it ceases being to-space during a GC and + // we will not copy objects into it any more. + inline void note_end_of_copying(bool during_initial_mark); - guarantee(_prev_marked_bytes <= - (size_t) (prev_top_at_mark_start() - bottom()) * HeapWordSize, - "invariant"); - } + // Notify the region that we are about to start processing + // self-forwarded objects during evac failure handling. + void note_self_forwarding_removal_start(bool during_initial_mark, + bool during_conc_mark); - // After an evacuation, we need to update _next_top_at_mark_start - // to be the current top. Note this is only valid if we have only - // ever evacuated into this region. If we evacuate, allocate, and - // then evacuate we are in deep doodoo. - void note_end_of_copying() { - assert(top() >= _next_top_at_mark_start, "Increase only"); - _next_top_at_mark_start = top(); - } + // Notify the region that we have finished processing self-forwarded + // objects during evac failure handling. + void note_self_forwarding_removal_end(bool during_initial_mark, + bool during_conc_mark, + size_t marked_bytes); // Returns "false" iff no object in the region was allocated when the // last mark phase ended.
--- a/src/share/vm/gc_implementation/g1/heapRegion.inline.hpp Thu Jan 19 17:20:39 2012 -0800 +++ b/src/share/vm/gc_implementation/g1/heapRegion.inline.hpp Thu Jan 19 18:35:13 2012 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2012, 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,4 +55,71 @@ return _offsets.block_start_const(p); } +inline void HeapRegion::note_start_of_marking() { + init_top_at_conc_mark_count(); + _next_marked_bytes = 0; + _next_top_at_mark_start = top(); +} + +inline void HeapRegion::note_end_of_marking() { + _prev_top_at_mark_start = _next_top_at_mark_start; + _prev_marked_bytes = _next_marked_bytes; + _next_marked_bytes = 0; + + assert(_prev_marked_bytes <= + (size_t) pointer_delta(prev_top_at_mark_start(), bottom()) * + HeapWordSize, "invariant"); +} + +inline void HeapRegion::note_start_of_copying(bool during_initial_mark) { + if (during_initial_mark) { + if (is_survivor()) { + assert(false, "should not allocate survivors during IM"); + } else { + // During initial-mark we'll explicitly mark any objects on old + // regions that are pointed to by roots. Given that explicit + // marks only make sense under NTAMS it'd be nice if we could + // check that condition if we wanted to. Given that we don't + // know where the top of this region will end up, we simply set + // NTAMS to the end of the region so all marks will be below + // NTAMS. We'll set it to the actual top when we retire this region. + _next_top_at_mark_start = end(); + } + } else { + if (is_survivor()) { + // This is how we always allocate survivors. + assert(_next_top_at_mark_start == bottom(), "invariant"); + } else { + // We could have re-used this old region as to-space over a + // couple of GCs since the start of the concurrent marking + // cycle. This means that [bottom,NTAMS) will contain objects + // copied up to and including initial-mark and [NTAMS, top) + // will contain objects copied during the concurrent marking cycle. + assert(top() >= _next_top_at_mark_start, "invariant"); + } + } +} + +inline void HeapRegion::note_end_of_copying(bool during_initial_mark) { + if (during_initial_mark) { + if (is_survivor()) { + assert(false, "should not allocate survivors during IM"); + } else { + // See the comment for note_start_of_copying() for the details + // on this. + assert(_next_top_at_mark_start == end(), "pre-condition"); + _next_top_at_mark_start = top(); + } + } else { + if (is_survivor()) { + // This is how we always allocate survivors. + assert(_next_top_at_mark_start == bottom(), "invariant"); + } else { + // See the comment for note_start_of_copying() for the details + // on this. + assert(top() >= _next_top_at_mark_start, "invariant"); + } + } +} + #endif // SHARE_VM_GC_IMPLEMENTATION_G1_HEAPREGION_INLINE_HPP
--- a/src/share/vm/gc_implementation/g1/ptrQueue.hpp Thu Jan 19 17:20:39 2012 -0800 +++ b/src/share/vm/gc_implementation/g1/ptrQueue.hpp Thu Jan 19 18:35:13 2012 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2012, 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 @@ -70,7 +70,7 @@ // given PtrQueueSet. PtrQueue(PtrQueueSet* qset, bool perm = false, bool active = false); // Release any contained resources. - void flush(); + virtual void flush(); // Calls flush() when destroyed. ~PtrQueue() { flush(); }
--- a/src/share/vm/gc_implementation/g1/satbQueue.cpp Thu Jan 19 17:20:39 2012 -0800 +++ b/src/share/vm/gc_implementation/g1/satbQueue.cpp Thu Jan 19 18:35:13 2012 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2012, 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 @@ -31,6 +31,14 @@ #include "runtime/thread.hpp" #include "runtime/vmThread.hpp" +void ObjPtrQueue::flush() { + // The buffer might contain refs into the CSet. We have to filter it + // first before we flush it, otherwise we might end up with an + // enqueued buffer with refs into the CSet which breaks our invariants. + filter(); + PtrQueue::flush(); +} + // This method removes entries from an SATB buffer that will not be // useful to the concurrent marking threads. An entry is removed if it // satisfies one of the following conditions: @@ -44,38 +52,27 @@ // process it again). // // The rest of the entries will be retained and are compacted towards -// the top of the buffer. If with this filtering we clear a large -// enough chunk of the buffer we can re-use it (instead of enqueueing -// it) and we can just allow the mutator to carry on executing. - -bool ObjPtrQueue::should_enqueue_buffer() { - assert(_lock == NULL || _lock->owned_by_self(), - "we should have taken the lock before calling this"); +// the top of the buffer. Note that, because we do not allow old +// regions in the CSet during marking, all objects on the CSet regions +// are young (eden or survivors) and therefore implicitly live. So any +// references into the CSet will be removed during filtering. - // A value of 0 means "don't filter SATB buffers". - if (G1SATBBufferEnqueueingThresholdPercent == 0) { - return true; - } - +void ObjPtrQueue::filter() { G1CollectedHeap* g1h = G1CollectedHeap::heap(); - - // This method should only be called if there is a non-NULL buffer - // that is full. - assert(_index == 0, "pre-condition"); - assert(_buf != NULL, "pre-condition"); - void** buf = _buf; size_t sz = _sz; + if (buf == NULL) { + // nothing to do + return; + } + // Used for sanity checking at the end of the loop. debug_only(size_t entries = 0; size_t retained = 0;) size_t i = sz; size_t new_index = sz; - // Given that we are expecting _index == 0, we could have changed - // the loop condition to (i > 0). But we are using _index for - // generality. while (i > _index) { assert(i > 0, "we should have at least one more entry to process"); i -= oopSize; @@ -103,22 +100,58 @@ debug_only(retained += 1;) } } + +#ifdef ASSERT size_t entries_calc = (sz - _index) / oopSize; assert(entries == entries_calc, "the number of entries we counted " "should match the number of entries we calculated"); size_t retained_calc = (sz - new_index) / oopSize; assert(retained == retained_calc, "the number of retained entries we counted " "should match the number of retained entries we calculated"); - size_t perc = retained_calc * 100 / entries_calc; +#endif // ASSERT + + _index = new_index; +} + +// This method will first apply the above filtering to the buffer. If +// post-filtering a large enough chunk of the buffer has been cleared +// we can re-use the buffer (instead of enqueueing it) and we can just +// allow the mutator to carry on executing using the same buffer +// instead of replacing it. + +bool ObjPtrQueue::should_enqueue_buffer() { + assert(_lock == NULL || _lock->owned_by_self(), + "we should have taken the lock before calling this"); + + // Even if G1SATBBufferEnqueueingThresholdPercent == 0 we have to + // filter the buffer given that this will remove any references into + // the CSet as we currently assume that no such refs will appear in + // enqueued buffers. + + // This method should only be called if there is a non-NULL buffer + // that is full. + assert(_index == 0, "pre-condition"); + assert(_buf != NULL, "pre-condition"); + + filter(); + + size_t sz = _sz; + size_t all_entries = sz / oopSize; + size_t retained_entries = (sz - _index) / oopSize; + size_t perc = retained_entries * 100 / all_entries; bool should_enqueue = perc > (size_t) G1SATBBufferEnqueueingThresholdPercent; - _index = new_index; - return should_enqueue; } void ObjPtrQueue::apply_closure(ObjectClosure* cl) { if (_buf != NULL) { apply_closure_to_buffer(cl, _buf, _index, _sz); + } +} + +void ObjPtrQueue::apply_closure_and_empty(ObjectClosure* cl) { + if (_buf != NULL) { + apply_closure_to_buffer(cl, _buf, _index, _sz); _index = _sz; } } @@ -135,6 +168,21 @@ } } +#ifndef PRODUCT +// Helpful for debugging + +void ObjPtrQueue::print(const char* name) { + print(name, _buf, _index, _sz); +} + +void ObjPtrQueue::print(const char* name, + void** buf, size_t index, size_t sz) { + gclog_or_tty->print_cr(" SATB BUFFER [%s] buf: "PTR_FORMAT" " + "index: "SIZE_FORMAT" sz: "SIZE_FORMAT, + name, buf, index, sz); +} +#endif // PRODUCT + #ifdef ASSERT void ObjPtrQueue::verify_oops_in_buffer() { if (_buf == NULL) return; @@ -150,12 +198,9 @@ #pragma warning( disable:4355 ) // 'this' : used in base member initializer list #endif // _MSC_VER - SATBMarkQueueSet::SATBMarkQueueSet() : - PtrQueueSet(), - _closure(NULL), _par_closures(NULL), - _shared_satb_queue(this, true /*perm*/) -{} + PtrQueueSet(), _closure(NULL), _par_closures(NULL), + _shared_satb_queue(this, true /*perm*/) { } void SATBMarkQueueSet::initialize(Monitor* cbl_mon, Mutex* fl_lock, int process_completed_threshold, @@ -167,7 +212,6 @@ } } - void SATBMarkQueueSet::handle_zero_index_for_thread(JavaThread* t) { DEBUG_ONLY(t->satb_mark_queue().verify_oops_in_buffer();) t->satb_mark_queue().handle_zero_index(); @@ -228,6 +272,13 @@ } } +void SATBMarkQueueSet::filter_thread_buffers() { + for(JavaThread* t = Threads::first(); t; t = t->next()) { + t->satb_mark_queue().filter(); + } + shared_satb_queue()->filter(); +} + void SATBMarkQueueSet::set_closure(ObjectClosure* closure) { _closure = closure; } @@ -239,9 +290,9 @@ void SATBMarkQueueSet::iterate_closure_all_threads() { for(JavaThread* t = Threads::first(); t; t = t->next()) { - t->satb_mark_queue().apply_closure(_closure); + t->satb_mark_queue().apply_closure_and_empty(_closure); } - shared_satb_queue()->apply_closure(_closure); + shared_satb_queue()->apply_closure_and_empty(_closure); } void SATBMarkQueueSet::par_iterate_closure_all_threads(int worker) { @@ -250,7 +301,7 @@ for(JavaThread* t = Threads::first(); t; t = t->next()) { if (t->claim_oops_do(true, parity)) { - t->satb_mark_queue().apply_closure(_par_closures[worker]); + t->satb_mark_queue().apply_closure_and_empty(_par_closures[worker]); } } @@ -264,7 +315,7 @@ VMThread* vmt = VMThread::vm_thread(); if (vmt->claim_oops_do(true, parity)) { - shared_satb_queue()->apply_closure(_par_closures[worker]); + shared_satb_queue()->apply_closure_and_empty(_par_closures[worker]); } } @@ -292,6 +343,61 @@ } } +void SATBMarkQueueSet::iterate_completed_buffers_read_only(ObjectClosure* cl) { + assert(SafepointSynchronize::is_at_safepoint(), "Must be at safepoint."); + assert(cl != NULL, "pre-condition"); + + BufferNode* nd = _completed_buffers_head; + while (nd != NULL) { + void** buf = BufferNode::make_buffer_from_node(nd); + ObjPtrQueue::apply_closure_to_buffer(cl, buf, 0, _sz); + nd = nd->next(); + } +} + +void SATBMarkQueueSet::iterate_thread_buffers_read_only(ObjectClosure* cl) { + assert(SafepointSynchronize::is_at_safepoint(), "Must be at safepoint."); + assert(cl != NULL, "pre-condition"); + + for (JavaThread* t = Threads::first(); t; t = t->next()) { + t->satb_mark_queue().apply_closure(cl); + } + shared_satb_queue()->apply_closure(cl); +} + +#ifndef PRODUCT +// Helpful for debugging + +#define SATB_PRINTER_BUFFER_SIZE 256 + +void SATBMarkQueueSet::print_all(const char* msg) { + char buffer[SATB_PRINTER_BUFFER_SIZE]; + assert(SafepointSynchronize::is_at_safepoint(), "Must be at safepoint."); + + gclog_or_tty->cr(); + gclog_or_tty->print_cr("SATB BUFFERS [%s]", msg); + + BufferNode* nd = _completed_buffers_head; + int i = 0; + while (nd != NULL) { + void** buf = BufferNode::make_buffer_from_node(nd); + jio_snprintf(buffer, SATB_PRINTER_BUFFER_SIZE, "Enqueued: %d", i); + ObjPtrQueue::print(buffer, buf, 0, _sz); + nd = nd->next(); + i += 1; + } + + for (JavaThread* t = Threads::first(); t; t = t->next()) { + jio_snprintf(buffer, SATB_PRINTER_BUFFER_SIZE, "Thread: %s", t->name()); + t->satb_mark_queue().print(buffer); + } + + shared_satb_queue()->print("Shared"); + + gclog_or_tty->cr(); +} +#endif // PRODUCT + void SATBMarkQueueSet::abandon_partial_marking() { BufferNode* buffers_to_delete = NULL; { @@ -316,5 +422,5 @@ for (JavaThread* t = Threads::first(); t; t = t->next()) { t->satb_mark_queue().reset(); } - shared_satb_queue()->reset(); + shared_satb_queue()->reset(); }
--- a/src/share/vm/gc_implementation/g1/satbQueue.hpp Thu Jan 19 17:20:39 2012 -0800 +++ b/src/share/vm/gc_implementation/g1/satbQueue.hpp Thu Jan 19 18:35:13 2012 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2012, 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 @@ -29,9 +29,26 @@ class ObjectClosure; class JavaThread; +class SATBMarkQueueSet; // A ptrQueue whose elements are "oops", pointers to object heads. class ObjPtrQueue: public PtrQueue { + friend class SATBMarkQueueSet; + +private: + // Filter out unwanted entries from the buffer. + void filter(); + + // Apply the closure to all elements. + void apply_closure(ObjectClosure* cl); + + // Apply the closure to all elements and empty the buffer; + void apply_closure_and_empty(ObjectClosure* cl); + + // Apply the closure to all elements of "buf", down to "index" (inclusive.) + static void apply_closure_to_buffer(ObjectClosure* cl, + void** buf, size_t index, size_t sz); + public: ObjPtrQueue(PtrQueueSet* qset, bool perm = false) : // SATB queues are only active during marking cycles. We create @@ -41,23 +58,23 @@ // field to true. This is done in JavaThread::initialize_queues(). PtrQueue(qset, perm, false /* active */) { } + // Overrides PtrQueue::flush() so that it can filter the buffer + // before it is flushed. + virtual void flush(); + // Overrides PtrQueue::should_enqueue_buffer(). See the method's // definition for more information. virtual bool should_enqueue_buffer(); - // Apply the closure to all elements, and reset the index to make the - // buffer empty. - void apply_closure(ObjectClosure* cl); - - // Apply the closure to all elements of "buf", down to "index" (inclusive.) - static void apply_closure_to_buffer(ObjectClosure* cl, - void** buf, size_t index, size_t sz); +#ifndef PRODUCT + // Helpful for debugging + void print(const char* name); + static void print(const char* name, void** buf, size_t index, size_t sz); +#endif // PRODUCT void verify_oops_in_buffer() NOT_DEBUG_RETURN; }; - - class SATBMarkQueueSet: public PtrQueueSet { ObjectClosure* _closure; ObjectClosure** _par_closures; // One per ParGCThread. @@ -88,6 +105,9 @@ // set itself, has an active value same as expected_active. void set_active_all_threads(bool b, bool expected_active); + // Filter all the currently-active SATB buffers. + void filter_thread_buffers(); + // Register "blk" as "the closure" for all queues. Only one such closure // is allowed. The "apply_closure_to_completed_buffer" method will apply // this closure to a completed buffer, and "iterate_closure_all_threads" @@ -98,10 +118,9 @@ // closures, one for each parallel GC thread. void set_par_closure(int i, ObjectClosure* closure); - // If there is a registered closure for buffers, apply it to all entries - // in all currently-active buffers. This should only be applied at a - // safepoint. (Currently must not be called in parallel; this should - // change in the future.) + // Apply the registered closure to all entries on each + // currently-active buffer and then empty the buffer. It should only + // be called serially and at a safepoint. void iterate_closure_all_threads(); // Parallel version of the above. void par_iterate_closure_all_threads(int worker); @@ -117,11 +136,21 @@ return apply_closure_to_completed_buffer_work(true, worker); } + // Apply the given closure on enqueued and currently-active buffers + // respectively. Both methods are read-only, i.e., they do not + // modify any of the buffers. + void iterate_completed_buffers_read_only(ObjectClosure* cl); + void iterate_thread_buffers_read_only(ObjectClosure* cl); + +#ifndef PRODUCT + // Helpful for debugging + void print_all(const char* msg); +#endif // PRODUCT + ObjPtrQueue* shared_satb_queue() { return &_shared_satb_queue; } // If a marking is being abandoned, reset any unprocessed log buffers. void abandon_partial_marking(); - }; #endif // SHARE_VM_GC_IMPLEMENTATION_G1_SATBQUEUE_HPP
--- a/src/share/vm/oops/klass.cpp Thu Jan 19 17:20:39 2012 -0800 +++ b/src/share/vm/oops/klass.cpp Thu Jan 19 18:35:13 2012 -0800 @@ -158,6 +158,9 @@ kl->set_next_sibling(NULL); kl->set_alloc_count(0); kl->set_alloc_size(0); +#ifdef TRACE_SET_KLASS_TRACE_ID + TRACE_SET_KLASS_TRACE_ID(kl, 0); +#endif kl->set_prototype_header(markOopDesc::prototype()); kl->set_biased_lock_revocation_count(0);
--- a/src/share/vm/oops/klass.hpp Thu Jan 19 17:20:39 2012 -0800 +++ b/src/share/vm/oops/klass.hpp Thu Jan 19 18:35:13 2012 -0800 @@ -33,6 +33,7 @@ #include "oops/klassPS.hpp" #include "oops/oop.hpp" #include "runtime/orderAccess.hpp" +#include "trace/traceMacros.hpp" #include "utilities/accessFlags.hpp" #ifndef SERIALGC #include "gc_implementation/concurrentMarkSweep/cmsOopClosures.hpp" @@ -80,6 +81,7 @@ // [last_biased_lock_bulk_revocation_time] (64 bits) // [prototype_header] // [biased_lock_revocation_count] +// [trace_id] // Forward declarations. @@ -263,6 +265,9 @@ markOop _prototype_header; // Used when biased locking is both enabled and disabled for this type jint _biased_lock_revocation_count; +#ifdef TRACE_DEFINE_KLASS_TRACE_ID + TRACE_DEFINE_KLASS_TRACE_ID; +#endif public: // returns the enclosing klassOop @@ -683,6 +688,9 @@ jlong last_biased_lock_bulk_revocation_time() { return _last_biased_lock_bulk_revocation_time; } void set_last_biased_lock_bulk_revocation_time(jlong cur_time) { _last_biased_lock_bulk_revocation_time = cur_time; } +#ifdef TRACE_DEFINE_KLASS_METHODS + TRACE_DEFINE_KLASS_METHODS; +#endif // garbage collection support virtual void follow_weak_klass_links(
--- a/src/share/vm/oops/methodKlass.cpp Thu Jan 19 17:20:39 2012 -0800 +++ b/src/share/vm/oops/methodKlass.cpp Thu Jan 19 18:35:13 2012 -0800 @@ -83,6 +83,7 @@ m->set_max_stack(0); m->set_max_locals(0); m->set_intrinsic_id(vmIntrinsics::_none); + m->set_jfr_towrite(false); m->set_method_data(NULL); m->set_interpreter_throwout_count(0); m->set_vtable_index(methodOopDesc::garbage_vtable_index);
--- a/src/share/vm/oops/methodOop.hpp Thu Jan 19 17:20:39 2012 -0800 +++ b/src/share/vm/oops/methodOop.hpp Thu Jan 19 18:35:13 2012 -0800 @@ -77,7 +77,7 @@ // | method_size | max_stack | // | max_locals | size_of_parameters | // |------------------------------------------------------| -// | intrinsic_id, (unused) | throwout_count | +// |intrinsic_id| flags | throwout_count | // |------------------------------------------------------| // | num_breakpoints | (unused) | // |------------------------------------------------------| @@ -124,6 +124,8 @@ u2 _max_locals; // Number of local variables used by this method u2 _size_of_parameters; // size of the parameter block (receiver + arguments) in words u1 _intrinsic_id; // vmSymbols::intrinsic_id (0 == _none) + u1 _jfr_towrite : 1, // Flags + : 7; u2 _interpreter_throwout_count; // Count of times method was exited via exception while interpreting u2 _number_of_breakpoints; // fullspeed debugging support InvocationCounter _invocation_counter; // Incremented before each activation of the method - used to trigger frequency-based optimizations @@ -225,6 +227,7 @@ void clear_number_of_breakpoints() { _number_of_breakpoints = 0; } // index into instanceKlass methods() array + // note: also used by jfr u2 method_idnum() const { return constMethod()->method_idnum(); } void set_method_idnum(u2 idnum) { constMethod()->set_method_idnum(idnum); } @@ -650,6 +653,9 @@ void init_intrinsic_id(); // updates from _none if a match static vmSymbols::SID klass_id_for_intrinsics(klassOop holder); + bool jfr_towrite() { return _jfr_towrite; } + void set_jfr_towrite(bool towrite) { _jfr_towrite = towrite; } + // On-stack replacement support bool has_osr_nmethod(int level, bool match_level) { return instanceKlass::cast(method_holder())->lookup_osr_nmethod(this, InvocationEntryBci, level, match_level) != NULL;
--- a/src/share/vm/prims/jni.cpp Thu Jan 19 17:20:39 2012 -0800 +++ b/src/share/vm/prims/jni.cpp Thu Jan 19 18:35:13 2012 -0800 @@ -48,6 +48,7 @@ #include "oops/typeArrayOop.hpp" #include "prims/jni.h" #include "prims/jniCheck.hpp" +#include "prims/jniExport.hpp" #include "prims/jniFastGetField.hpp" #include "prims/jvm.h" #include "prims/jvm_misc.hpp" @@ -66,6 +67,8 @@ #include "runtime/signature.hpp" #include "runtime/vm_operations.hpp" #include "services/runtimeService.hpp" +#include "trace/tracing.hpp" +#include "trace/traceEventTypes.hpp" #include "utilities/defaultStream.hpp" #include "utilities/dtrace.hpp" #include "utilities/events.hpp" @@ -5139,6 +5142,11 @@ if (JvmtiExport::should_post_thread_life()) { JvmtiExport::post_thread_start(thread); } + + EVENT_BEGIN(TraceEventThreadStart, event); + EVENT_COMMIT(event, + EVENT_SET(event, javalangthread, java_lang_Thread::thread_id(thread->threadObj()))); + // Check if we should compile all classes on bootclasspath NOT_PRODUCT(if (CompileTheWorld) ClassLoader::compile_the_world();) // Since this is not a JVM_ENTRY we have to set the thread state manually before leaving. @@ -5337,6 +5345,10 @@ JvmtiExport::post_thread_start(thread); } + EVENT_BEGIN(TraceEventThreadStart, event); + EVENT_COMMIT(event, + EVENT_SET(event, javalangthread, java_lang_Thread::thread_id(thread->threadObj()))); + *(JNIEnv**)penv = thread->jni_environment(); // Now leaving the VM, so change thread_state. This is normally automatically taken care @@ -5464,8 +5476,7 @@ return ret; } - if (JvmtiExport::is_jvmti_version(version)) { - ret = JvmtiExport::get_jvmti_interface(vm, penv, version); + if (JniExportedInterface::GetExportedInterface(vm, penv, version, &ret)) { return ret; }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/prims/jniExport.hpp Thu Jan 19 18:35:13 2012 -0800 @@ -0,0 +1,42 @@ +/* + * Copyright (c) 1997, 2011, 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. + * + */ + +#ifndef SHARE_VM_PRIMS_JNI_EXPORT_HPP +#define SHARE_VM_PRIMS_JNI_EXPORT_HPP + +#include "prims/jni.h" +#include "prims/jvmtiExport.hpp" + +class JniExportedInterface { + public: + static bool GetExportedInterface(JavaVM* vm, void** penv, jint version, jint* iface) { + if (JvmtiExport::is_jvmti_version(version)) { + *iface = JvmtiExport::get_jvmti_interface(vm, penv, version); + return true; + } + return false; + } +}; + +#endif // SHARE_VM_PRIMS_JNI_EXPORT_HPP
--- a/src/share/vm/runtime/java.cpp Thu Jan 19 17:20:39 2012 -0800 +++ b/src/share/vm/runtime/java.cpp Thu Jan 19 18:35:13 2012 -0800 @@ -57,6 +57,8 @@ #include "runtime/task.hpp" #include "runtime/timer.hpp" #include "runtime/vm_operations.hpp" +#include "trace/tracing.hpp" +#include "trace/traceEventTypes.hpp" #include "utilities/dtrace.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/histogram.hpp" @@ -502,6 +504,11 @@ if (JvmtiExport::should_post_thread_life()) { JvmtiExport::post_thread_end(thread); } + + EVENT_BEGIN(TraceEventThreadEnd, event); + EVENT_COMMIT(event, + EVENT_SET(event, javalangthread, java_lang_Thread::thread_id(thread->threadObj()))); + // Always call even when there are not JVMTI environments yet, since environments // may be attached late and JVMTI must track phases of VM execution JvmtiExport::post_vm_death();
--- a/src/share/vm/runtime/mutexLocker.cpp Thu Jan 19 17:20:39 2012 -0800 +++ b/src/share/vm/runtime/mutexLocker.cpp Thu Jan 19 18:35:13 2012 -0800 @@ -132,7 +132,13 @@ Monitor* GCTaskManager_lock = NULL; Mutex* Management_lock = NULL; -Monitor* Service_lock = NULL; +Monitor* Service_lock = NULL; +Mutex* Stacktrace_lock = NULL; + +Monitor* JfrQuery_lock = NULL; +Monitor* JfrMsg_lock = NULL; +Mutex* JfrBuffer_lock = NULL; +Mutex* JfrStream_lock = NULL; #define MAX_NUM_MUTEX 128 static Monitor * _mutex_array[MAX_NUM_MUTEX]; @@ -207,6 +213,7 @@ def(Patching_lock , Mutex , special, true ); // used for safepointing and code patching. def(ObjAllocPost_lock , Monitor, special, false); def(Service_lock , Monitor, special, true ); // used for service thread operations + def(Stacktrace_lock , Mutex, special, true ); // used for JFR stacktrace database def(JmethodIdCreation_lock , Mutex , leaf, true ); // used for creating jmethodIDs. def(SystemDictionary_lock , Monitor, leaf, true ); // lookups done by VM thread @@ -271,6 +278,11 @@ def(Debug3_lock , Mutex , nonleaf+4, true ); def(ProfileVM_lock , Monitor, nonleaf+4, false); // used for profiling of the VMThread def(CompileThread_lock , Monitor, nonleaf+5, false ); + + def(JfrQuery_lock , Monitor, nonleaf, true); // JFR locks, keep these in consecutive order + def(JfrMsg_lock , Monitor, nonleaf+2, true); + def(JfrBuffer_lock , Mutex, nonleaf+3, true); + def(JfrStream_lock , Mutex, nonleaf+4, true); } GCMutexLocker::GCMutexLocker(Monitor * mutex) {
--- a/src/share/vm/runtime/mutexLocker.hpp Thu Jan 19 17:20:39 2012 -0800 +++ b/src/share/vm/runtime/mutexLocker.hpp Thu Jan 19 18:35:13 2012 -0800 @@ -135,6 +135,12 @@ extern Mutex* Management_lock; // a lock used to serialize JVM management extern Monitor* Service_lock; // a lock used for service thread operation +extern Mutex* Stacktrace_lock; // used to guard access to the stacktrace table + +extern Monitor* JfrQuery_lock; // protects JFR use +extern Monitor* JfrMsg_lock; // protects JFR messaging +extern Mutex* JfrBuffer_lock; // protects JFR buffer operations +extern Mutex* JfrStream_lock; // protects JFR stream access // A MutexLocker provides mutual exclusion with respect to a given mutex // for the scope which contains the locker. The lock is an OS lock, not
--- a/src/share/vm/runtime/os.cpp Thu Jan 19 17:20:39 2012 -0800 +++ b/src/share/vm/runtime/os.cpp Thu Jan 19 18:35:13 2012 -0800 @@ -1101,6 +1101,7 @@ "%/lib/jsse.jar:" "%/lib/jce.jar:" "%/lib/charsets.jar:" + "%/lib/jfr.jar:" #ifdef __APPLE__ "%/lib/JObjC.jar:" #endif
--- a/src/share/vm/runtime/thread.cpp Thu Jan 19 17:20:39 2012 -0800 +++ b/src/share/vm/runtime/thread.cpp Thu Jan 19 18:35:13 2012 -0800 @@ -73,6 +73,7 @@ #include "services/attachListener.hpp" #include "services/management.hpp" #include "services/threadService.hpp" +#include "trace/traceEventTypes.hpp" #include "utilities/defaultStream.hpp" #include "utilities/dtrace.hpp" #include "utilities/events.hpp" @@ -232,6 +233,7 @@ CHECK_UNHANDLED_OOPS_ONLY(_gc_locked_out_count = 0;) _jvmti_env_iteration_count = 0; set_allocated_bytes(0); + set_trace_buffer(NULL); _vm_operation_started_count = 0; _vm_operation_completed_count = 0; _current_pending_monitor = NULL; @@ -1512,6 +1514,10 @@ JvmtiExport::post_thread_start(this); } + EVENT_BEGIN(TraceEventThreadStart, event); + EVENT_COMMIT(event, + EVENT_SET(event, javalangthread, java_lang_Thread::thread_id(this->threadObj()))); + // We call another function to do the rest so we are sure that the stack addresses used // from there will be lower than the stack base just computed thread_main_inner(); @@ -1641,6 +1647,15 @@ } } + // Called before the java thread exit since we want to read info + // from java_lang_Thread object + EVENT_BEGIN(TraceEventThreadEnd, event); + EVENT_COMMIT(event, + EVENT_SET(event, javalangthread, java_lang_Thread::thread_id(this->threadObj()))); + + // Call after last event on thread + EVENT_THREAD_EXIT(this); + // Call Thread.exit(). We try 3 times in case we got another Thread.stop during // the execution of the method. If that is not enough, then we don't really care. Thread.stop // is deprecated anyhow. @@ -3186,6 +3201,11 @@ return status; } + // Must be run after init_ft which initializes ft_enabled + if (TRACE_INITIALIZE() != JNI_OK) { + vm_exit_during_initialization("Failed to initialize tracing backend"); + } + // Should be done after the heap is fully created main_thread->cache_global_variables(); @@ -3423,6 +3443,10 @@ create_vm_init_libraries(); } + if (!TRACE_START()) { + vm_exit_during_initialization(Handle(THREAD, PENDING_EXCEPTION)); + } + // Notify JVMTI agents that VM initialization is complete - nop if no agents. JvmtiExport::post_vm_initialized();
--- a/src/share/vm/runtime/thread.hpp Thu Jan 19 17:20:39 2012 -0800 +++ b/src/share/vm/runtime/thread.hpp Thu Jan 19 18:35:13 2012 -0800 @@ -41,6 +41,7 @@ #include "runtime/stubRoutines.hpp" #include "runtime/threadLocalStorage.hpp" #include "runtime/unhandledOops.hpp" +#include "trace/tracing.hpp" #include "utilities/exceptions.hpp" #include "utilities/top.hpp" #ifndef SERIALGC @@ -246,6 +247,8 @@ jlong _allocated_bytes; // Cumulative number of bytes allocated on // the Java heap + TRACE_BUFFER _trace_buffer; // Thread-local buffer for tracing + int _vm_operation_started_count; // VM_Operation support int _vm_operation_completed_count; // VM_Operation support @@ -414,6 +417,9 @@ return allocated_bytes; } + TRACE_BUFFER trace_buffer() { return _trace_buffer; } + void set_trace_buffer(TRACE_BUFFER buf) { _trace_buffer = buf; } + // VM operation support int vm_operation_ticket() { return ++_vm_operation_started_count; } int vm_operation_completed_count() { return _vm_operation_completed_count; }
--- a/src/share/vm/runtime/vm_operations.hpp Thu Jan 19 17:20:39 2012 -0800 +++ b/src/share/vm/runtime/vm_operations.hpp Thu Jan 19 18:35:13 2012 -0800 @@ -93,6 +93,7 @@ template(HeapWalkOperation) \ template(HeapIterateOperation) \ template(ReportJavaOutOfMemory) \ + template(JFRCheckpoint) \ template(Exit) \ class VM_Operation: public CHeapObj {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/trace/traceEventTypes.hpp Thu Jan 19 18:35:13 2012 -0800 @@ -0,0 +1,30 @@ +/* + * Copyright (c) 1997, 2012, 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. + * + */ + +#ifndef SHARE_VM_TRACE_TRACE_EVENT_TYPES_HPP +#define SHARE_VM_TRACE_TRACE_EVENT_TYPES_HPP + +/* Empty, just a placeholder for tracing events */ + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/trace/traceMacros.hpp Thu Jan 19 18:35:13 2012 -0800 @@ -0,0 +1,43 @@ +/* + * Copyright (c) 1997, 2011, 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. + * + */ + +#ifndef SHARE_VM_TRACE_TRACE_MACRO_HPP +#define SHARE_VM_TRACE_TRACE_MACRO_HPP + +#define EVENT_BEGIN(type, name) +#define EVENT_SET(name, field, value) +#define EVENT_COMMIT(name, ...) +#define EVENT_STARTED(name, time) +#define EVENT_ENDED(name, time) +#define EVENT_THREAD_EXIT(thread) + +#define TRACE_ENABLED 0 + +#define TRACE_INIT_ID(k) +#define TRACE_BUFFER void* + +#define TRACE_START() true +#define TRACE_INITIALIZE() 0 + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/trace/tracing.hpp Thu Jan 19 18:35:13 2012 -0800 @@ -0,0 +1,30 @@ +/* + * Copyright (c) 1997, 2011, 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. + * + */ + +#ifndef SHARE_VM_TRACE_TRACING_HPP +#define SHARE_VM_TRACE_TRACING_HPP + +#include "trace/traceMacros.hpp" + +#endif
--- a/src/share/vm/utilities/decoder.cpp Thu Jan 19 17:20:39 2012 -0800 +++ b/src/share/vm/utilities/decoder.cpp Thu Jan 19 18:35:13 2012 -0800 @@ -24,80 +24,85 @@ #include "precompiled.hpp" #include "prims/jvm.h" +#include "runtime/mutexLocker.hpp" #include "utilities/decoder.hpp" -Decoder::decoder_status Decoder::_decoder_status = Decoder::no_error; -bool Decoder::_initialized = false; - -#if !defined(_WINDOWS) && !defined(__APPLE__) - -// Implementation of common functionalities among Solaris and Linux -#include "utilities/elfFile.hpp" - -ElfFile* Decoder::_opened_elf_files = NULL; - -bool Decoder::can_decode_C_frame_in_vm() { - return true; -} +#if defined(_WINDOWS) + #include "decoder_windows.hpp" +#elif defined(__APPLE__) + #include "decoder_machO.hpp" +#else + #include "decoder_elf.hpp" +#endif -void Decoder::initialize() { - _initialized = true; -} +NullDecoder* Decoder::_decoder = NULL; +NullDecoder Decoder::_do_nothing_decoder; +Mutex* Decoder::_decoder_lock = new Mutex(Mutex::safepoint, + "DecoderLock"); -void Decoder::uninitialize() { - if (_opened_elf_files != NULL) { - delete _opened_elf_files; - _opened_elf_files = NULL; - } - _initialized = false; -} +// _decoder_lock should already acquired before enter this method +NullDecoder* Decoder::get_decoder() { + assert(_decoder_lock != NULL && _decoder_lock->owned_by_self(), + "Require DecoderLock to enter"); -Decoder::decoder_status Decoder::decode(address addr, const char* filepath, char *buf, int buflen, int *offset) { - if (_decoder_status != no_error) { - return _decoder_status; - } - - ElfFile* file = get_elf_file(filepath); - if (_decoder_status != no_error) { - return _decoder_status; + if (_decoder != NULL) { + return _decoder; } - const char* symbol = file->decode(addr, offset); - if (file->get_status() == out_of_memory) { - _decoder_status = out_of_memory; - return _decoder_status; - } else if (symbol != NULL) { - if (!demangle(symbol, buf, buflen)) { - jio_snprintf(buf, buflen, "%s", symbol); + // Decoder is a secondary service. Although, it is good to have, + // but we can live without it. +#if defined(_WINDOWS) + _decoder = new (std::nothrow) WindowsDecoder(); +#elif defined (__APPLE__) + _decoder = new (std::nothrow)MachODecoder(); +#else + _decoder = new (std::nothrow)ElfDecoder(); +#endif + + if (_decoder == NULL || _decoder->has_error()) { + if (_decoder != NULL) { + delete _decoder; } - return no_error; - } else { - return symbol_not_found; + _decoder = &_do_nothing_decoder; } + return _decoder; +} + +bool Decoder::decode(address addr, char* buf, int buflen, int* offset, const char* modulepath) { + assert(_decoder_lock != NULL, "Just check"); + MutexLockerEx locker(_decoder_lock, true); + NullDecoder* decoder = get_decoder(); + assert(decoder != NULL, "null decoder"); + + return decoder->decode(addr, buf, buflen, offset, modulepath); } -ElfFile* Decoder::get_elf_file(const char* filepath) { - if (_decoder_status != no_error) { - return NULL; - } - ElfFile* file = _opened_elf_files; - while (file != NULL) { - if (file->same_elf_file(filepath)) { - return file; - } - file = file->m_next; +bool Decoder::demangle(const char* symbol, char* buf, int buflen) { + assert(_decoder_lock != NULL, "Just check"); + MutexLockerEx locker(_decoder_lock, true); + NullDecoder* decoder = get_decoder(); + assert(decoder != NULL, "null decoder"); + return decoder->demangle(symbol, buf, buflen); +} + +bool Decoder::can_decode_C_frame_in_vm() { + assert(_decoder_lock != NULL, "Just check"); + MutexLockerEx locker(_decoder_lock, true); + NullDecoder* decoder = get_decoder(); + assert(decoder != NULL, "null decoder"); + return decoder->can_decode_C_frame_in_vm(); +} + +// shutdown real decoder and replace it with +// _do_nothing_decoder +void Decoder::shutdown() { + assert(_decoder_lock != NULL, "Just check"); + MutexLockerEx locker(_decoder_lock, true); + + if (_decoder != NULL && _decoder != &_do_nothing_decoder) { + delete _decoder; } - file = new ElfFile(filepath); - if (file == NULL) { - _decoder_status = out_of_memory; - } - if (_opened_elf_files != NULL) { - file->m_next = _opened_elf_files; - } - - _opened_elf_files = file; - return file; + _decoder = &_do_nothing_decoder; } -#endif
--- a/src/share/vm/utilities/decoder.hpp Thu Jan 19 17:20:39 2012 -0800 +++ b/src/share/vm/utilities/decoder.hpp Thu Jan 19 18:35:13 2012 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, 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 @@ -23,83 +23,78 @@ */ -#ifndef __DECODER_HPP -#define __DECODER_HPP +#ifndef SHARE_VM_UTILITIES_DECODER_HPP +#define SHARE_VM_UTILITIES_DECODER_HPP #include "memory/allocation.hpp" - -#ifdef _WINDOWS -#include <windows.h> -#include <imagehlp.h> - -// functions needed for decoding symbols -typedef DWORD (WINAPI *pfn_SymSetOptions)(DWORD); -typedef BOOL (WINAPI *pfn_SymInitialize)(HANDLE, PCTSTR, BOOL); -typedef BOOL (WINAPI *pfn_SymGetSymFromAddr64)(HANDLE, DWORD64, PDWORD64, PIMAGEHLP_SYMBOL64); -typedef DWORD (WINAPI *pfn_UndecorateSymbolName)(const char*, char*, DWORD, DWORD); +#include "runtime/mutex.hpp" -#elif defined(__APPLE__) - -#else - -class ElfFile; - -#endif // _WINDOWS - - -class Decoder: public StackObj { - - public: +class NullDecoder: public CHeapObj { +public: // status code for decoding native C frame enum decoder_status { - no_error, // successfully decoded frames + not_available = -10, // real decoder is not available + no_error = 0, // successfully decoded frames out_of_memory, // out of memory file_invalid, // invalid elf file file_not_found, // could not found symbol file (on windows), such as jvm.pdb or jvm.map helper_not_found, // could not load dbghelp.dll (Windows only) helper_func_error, // decoding functions not found (Windows only) - helper_init_error, // SymInitialize failed (Windows only) - symbol_not_found // could not find the symbol + helper_init_error // SymInitialize failed (Windows only) }; - public: - Decoder() { initialize(); }; - ~Decoder() { uninitialize(); }; + NullDecoder() { + _decoder_status = not_available; + } + + ~NullDecoder() {}; + + virtual bool decode(address pc, char* buf, int buflen, int* offset, + const char* modulepath = NULL) { + return false; + } + + virtual bool demangle(const char* symbol, char* buf, int buflen) { + return false; + } + + virtual bool can_decode_C_frame_in_vm() const { + return false; + } + virtual decoder_status status() const { + return _decoder_status; + } + + virtual bool has_error() const { + return is_error(_decoder_status); + } + + static bool is_error(decoder_status status) { + return (status > 0); + } + +protected: + decoder_status _decoder_status; +}; + + +class Decoder: AllStatic { +public: + static bool decode(address pc, char* buf, int buflen, int* offset, const char* modulepath = NULL); + static bool demangle(const char* symbol, char* buf, int buflen); static bool can_decode_C_frame_in_vm(); - static void initialize(); - static void uninitialize(); - -#ifdef _WINDOWS - static decoder_status decode(address addr, char *buf, int buflen, int *offset); -#else - static decoder_status decode(address addr, const char* filepath, char *buf, int buflen, int *offset); -#endif - - static bool demangle(const char* symbol, char *buf, int buflen); - - static decoder_status get_status() { return _decoder_status; }; + static void shutdown(); +protected: + static NullDecoder* get_decoder(); -#if !defined(_WINDOWS) && !defined(__APPLE__) - private: - static ElfFile* get_elf_file(const char* filepath); -#endif // _WINDOWS - - - private: - static decoder_status _decoder_status; - static bool _initialized; +private: + static NullDecoder* _decoder; + static NullDecoder _do_nothing_decoder; -#ifdef _WINDOWS - static HMODULE _dbghelp_handle; - static bool _can_decode_in_vm; - static pfn_SymGetSymFromAddr64 _pfnSymGetSymFromAddr64; - static pfn_UndecorateSymbolName _pfnUndecorateSymbolName; -#elif __APPLE__ -#else - static ElfFile* _opened_elf_files; -#endif // _WINDOWS +protected: + static Mutex* _decoder_lock; }; -#endif // __DECODER_HPP +#endif // SHARE_VM_UTILITIES_DECODER_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/utilities/decoder_elf.cpp Thu Jan 19 18:35:13 2012 -0800 @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2011, 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. + * + */ + +#include "precompiled.hpp" + +#if !defined(_WINDOWS) && !defined(__APPLE__) +#include "decoder_elf.hpp" + +ElfDecoder::~ElfDecoder() { + if (_opened_elf_files != NULL) { + delete _opened_elf_files; + _opened_elf_files = NULL; + } +} + +bool ElfDecoder::decode(address addr, char *buf, int buflen, int* offset, const char* filepath) { + assert(filepath, "null file path"); + assert(buf != NULL && buflen > 0, "Invalid buffer"); + if (has_error()) return false; + ElfFile* file = get_elf_file(filepath); + if (file == NULL) { + return false; + } + + if (!file->decode(addr, buf, buflen, offset)) { + return false; + } + if (buf[0] != '\0') { + demangle(buf, buf, buflen); + } + return true; +} + +ElfFile* ElfDecoder::get_elf_file(const char* filepath) { + ElfFile* file; + + file = _opened_elf_files; + while (file != NULL) { + if (file->same_elf_file(filepath)) { + return file; + } + file = file->next(); + } + + file = new (std::nothrow)ElfFile(filepath); + if (file != NULL) { + if (_opened_elf_files != NULL) { + file->set_next(_opened_elf_files); + } + _opened_elf_files = file; + } + + return file; +} +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/utilities/decoder_elf.hpp Thu Jan 19 18:35:13 2012 -0800 @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2011, 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. + * + */ + +#ifndef SHARE_VM_UTILITIES_DECODER_ELF_HPP +#define SHARE_VM_UTILITIES_DECODER_ELF_HPP + +#if !defined(_WINDOWS) && !defined(__APPLE__) + +#include "utilities/decoder.hpp" +#include "utilities/elfFile.hpp" + +class ElfDecoder: public NullDecoder { + +public: + ElfDecoder() { + _opened_elf_files = NULL; + _decoder_status = no_error; + } + ~ElfDecoder(); + + bool can_decode_C_frame_in_vm() const { return true; } + + bool demangle(const char* symbol, char *buf, int buflen); + bool decode(address addr, char *buf, int buflen, int* offset, const char* filepath = NULL); + +private: + ElfFile* get_elf_file(const char* filepath); + +private: + ElfFile* _opened_elf_files; +}; + +#endif +#endif // SHARE_VM_UTILITIES_DECODER_ELF_HPP
--- a/src/share/vm/utilities/elfFile.cpp Thu Jan 19 17:20:39 2012 -0800 +++ b/src/share/vm/utilities/elfFile.cpp Thu Jan 19 18:35:13 2012 -0800 @@ -44,7 +44,7 @@ m_string_tables = NULL; m_symbol_tables = NULL; m_next = NULL; - m_status = Decoder::no_error; + m_status = NullDecoder::no_error; int len = strlen(filepath) + 1; m_filepath = (const char*)os::malloc(len * sizeof(char)); @@ -54,10 +54,10 @@ if (m_file != NULL) { load_tables(); } else { - m_status = Decoder::file_not_found; + m_status = NullDecoder::file_not_found; } } else { - m_status = Decoder::out_of_memory; + m_status = NullDecoder::out_of_memory; } } @@ -96,41 +96,41 @@ bool ElfFile::load_tables() { assert(m_file, "file not open"); - assert(m_status == Decoder::no_error, "already in error"); + assert(!NullDecoder::is_error(m_status), "already in error"); // read elf file header if (fread(&m_elfHdr, sizeof(m_elfHdr), 1, m_file) != 1) { - m_status = Decoder::file_invalid; + m_status = NullDecoder::file_invalid; return false; } if (!is_elf_file(m_elfHdr)) { - m_status = Decoder::file_invalid; + m_status = NullDecoder::file_invalid; return false; } // walk elf file's section headers, and load string tables Elf_Shdr shdr; if (!fseek(m_file, m_elfHdr.e_shoff, SEEK_SET)) { - if (m_status != Decoder::no_error) return false; + if (NullDecoder::is_error(m_status)) return false; for (int index = 0; index < m_elfHdr.e_shnum; index ++) { if (fread((void*)&shdr, sizeof(Elf_Shdr), 1, m_file) != 1) { - m_status = Decoder::file_invalid; + m_status = NullDecoder::file_invalid; return false; } // string table if (shdr.sh_type == SHT_STRTAB) { ElfStringTable* table = new (std::nothrow) ElfStringTable(m_file, shdr, index); if (table == NULL) { - m_status = Decoder::out_of_memory; + m_status = NullDecoder::out_of_memory; return false; } add_string_table(table); } else if (shdr.sh_type == SHT_SYMTAB || shdr.sh_type == SHT_DYNSYM) { ElfSymbolTable* table = new (std::nothrow) ElfSymbolTable(m_file, shdr); if (table == NULL) { - m_status = Decoder::out_of_memory; + m_status = NullDecoder::out_of_memory; return false; } add_symbol_table(table); @@ -140,32 +140,33 @@ return true; } -const char* ElfFile::decode(address addr, int* offset) { +bool ElfFile::decode(address addr, char* buf, int buflen, int* offset) { // something already went wrong, just give up - if (m_status != Decoder::no_error) { - return NULL; + if (NullDecoder::is_error(m_status)) { + return false; } - ElfSymbolTable* symbol_table = m_symbol_tables; int string_table_index; int pos_in_string_table; int off = INT_MAX; bool found_symbol = false; while (symbol_table != NULL) { - if (Decoder::no_error == symbol_table->lookup(addr, &string_table_index, &pos_in_string_table, &off)) { + if (symbol_table->lookup(addr, &string_table_index, &pos_in_string_table, &off)) { found_symbol = true; } symbol_table = symbol_table->m_next; } - if (!found_symbol) return NULL; + if (!found_symbol) return false; ElfStringTable* string_table = get_string_table(string_table_index); + if (string_table == NULL) { - m_status = Decoder::file_invalid; - return NULL; + m_status = NullDecoder::file_invalid; + return false; } if (offset) *offset = off; - return string_table->string_at(pos_in_string_table); + + return string_table->string_at(pos_in_string_table, buf, buflen); }
--- a/src/share/vm/utilities/elfFile.hpp Thu Jan 19 17:20:39 2012 -0800 +++ b/src/share/vm/utilities/elfFile.hpp Thu Jan 19 18:35:13 2012 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, 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 @@ -22,8 +22,8 @@ * */ -#ifndef __ELF_FILE_HPP -#define __ELF_FILE_HPP +#ifndef SHARE_VM_UTILITIES_ELF_FILE_HPP +#define SHARE_VM_UTILITIES_ELF_FILE_HPP #if !defined(_WINDOWS) && !defined(__APPLE__) @@ -83,12 +83,12 @@ // part of code to be very defensive, and bait out if anything went wrong. class ElfFile: public CHeapObj { - friend class Decoder; + friend class ElfDecoder; public: ElfFile(const char* filepath); ~ElfFile(); - const char* decode(address addr, int* offset); + bool decode(address addr, char* buf, int buflen, int* offset); const char* filepath() { return m_filepath; } @@ -99,7 +99,7 @@ return (m_filepath && !strcmp(filepath, m_filepath)); } - Decoder::decoder_status get_status() { + NullDecoder::decoder_status get_status() { return m_status; } @@ -119,8 +119,9 @@ // return a string table at specified section index ElfStringTable* get_string_table(int index); - // look up an address and return the nearest symbol - const char* look_up(Elf_Shdr shdr, address addr, int* offset); +protected: + ElfFile* next() const { return m_next; } + void set_next(ElfFile* file) { m_next = file; } protected: ElfFile* m_next; @@ -131,17 +132,17 @@ FILE* m_file; // Elf header - Elf_Ehdr m_elfHdr; + Elf_Ehdr m_elfHdr; // symbol tables - ElfSymbolTable* m_symbol_tables; + ElfSymbolTable* m_symbol_tables; // string tables - ElfStringTable* m_string_tables; + ElfStringTable* m_string_tables; - Decoder::decoder_status m_status; + NullDecoder::decoder_status m_status; }; #endif // _WINDOWS -#endif // __ELF_FILE_HPP +#endif // SHARE_VM_UTILITIES_ELF_FILE_HPP
--- a/src/share/vm/utilities/elfStringTable.cpp Thu Jan 19 17:20:39 2012 -0800 +++ b/src/share/vm/utilities/elfStringTable.cpp Thu Jan 19 18:35:13 2012 -0800 @@ -38,7 +38,7 @@ m_index = index; m_next = NULL; m_file = file; - m_status = Decoder::no_error; + m_status = NullDecoder::no_error; // try to load the string table long cur_offset = ftell(file); @@ -48,7 +48,7 @@ if (fseek(file, shdr.sh_offset, SEEK_SET) || fread((void*)m_table, shdr.sh_size, 1, file) != 1 || fseek(file, cur_offset, SEEK_SET)) { - m_status = Decoder::file_invalid; + m_status = NullDecoder::file_invalid; os::free((void*)m_table); m_table = NULL; } @@ -67,22 +67,23 @@ } } -const char* ElfStringTable::string_at(int pos) { - if (m_status != Decoder::no_error) { - return NULL; +bool ElfStringTable::string_at(int pos, char* buf, int buflen) { + if (NullDecoder::is_error(m_status)) { + return false; } if (m_table != NULL) { - return (const char*)(m_table + pos); + jio_snprintf(buf, buflen, "%s", (const char*)(m_table + pos)); + return true; } else { long cur_pos = ftell(m_file); if (cur_pos == -1 || fseek(m_file, m_shdr.sh_offset + pos, SEEK_SET) || - fread(m_symbol, 1, MAX_SYMBOL_LEN, m_file) <= 0 || + fread(buf, 1, buflen, m_file) <= 0 || fseek(m_file, cur_pos, SEEK_SET)) { - m_status = Decoder::file_invalid; - return NULL; + m_status = NullDecoder::file_invalid; + return false; } - return (const char*)m_symbol; + return true; } }
--- a/src/share/vm/utilities/elfStringTable.hpp Thu Jan 19 17:20:39 2012 -0800 +++ b/src/share/vm/utilities/elfStringTable.hpp Thu Jan 19 18:35:13 2012 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, 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 @@ -22,8 +22,8 @@ * */ -#ifndef __ELF_STRING_TABLE_HPP -#define __ELF_STRING_TABLE_HPP +#ifndef SHARE_VM_UTILITIES_ELF_STRING_TABLE_HPP +#define SHARE_VM_UTILITIES_ELF_STRING_TABLE_HPP #if !defined(_WINDOWS) && !defined(__APPLE__) @@ -35,9 +35,6 @@ // The string table represents a string table section in an elf file. // Whenever there is enough memory, it will load whole string table as // one blob. Otherwise, it will load string from file when requested. - -#define MAX_SYMBOL_LEN 256 - class ElfStringTable: CHeapObj { friend class ElfFile; public: @@ -48,10 +45,10 @@ int index() { return m_index; }; // get string at specified offset - const char* string_at(int offset); + bool string_at(int offset, char* buf, int buflen); // get status code - Decoder::decoder_status get_status() { return m_status; }; + NullDecoder::decoder_status get_status() { return m_status; }; protected: ElfStringTable* m_next; @@ -69,13 +66,10 @@ // section header Elf_Shdr m_shdr; - // buffer for reading individual string - char m_symbol[MAX_SYMBOL_LEN]; - // error code - Decoder::decoder_status m_status; + NullDecoder::decoder_status m_status; }; -#endif // _WINDOWS +#endif // _WINDOWS and _APPLE -#endif // __ELF_STRING_TABLE_HPP +#endif // SHARE_VM_UTILITIES_ELF_STRING_TABLE_HPP
--- a/src/share/vm/utilities/elfSymbolTable.cpp Thu Jan 19 17:20:39 2012 -0800 +++ b/src/share/vm/utilities/elfSymbolTable.cpp Thu Jan 19 18:35:13 2012 -0800 @@ -34,7 +34,7 @@ m_symbols = NULL; m_next = NULL; m_file = file; - m_status = Decoder::no_error; + m_status = NullDecoder::no_error; // try to load the string table long cur_offset = ftell(file); @@ -45,16 +45,16 @@ if (fseek(file, shdr.sh_offset, SEEK_SET) || fread((void*)m_symbols, shdr.sh_size, 1, file) != 1 || fseek(file, cur_offset, SEEK_SET)) { - m_status = Decoder::file_invalid; + m_status = NullDecoder::file_invalid; os::free(m_symbols); m_symbols = NULL; } } - if (m_status == Decoder::no_error) { + if (!NullDecoder::is_error(m_status)) { memcpy(&m_shdr, &shdr, sizeof(Elf_Shdr)); } } else { - m_status = Decoder::file_invalid; + m_status = NullDecoder::file_invalid; } } @@ -68,13 +68,13 @@ } } -Decoder::decoder_status ElfSymbolTable::lookup(address addr, int* stringtableIndex, int* posIndex, int* offset) { +bool ElfSymbolTable::lookup(address addr, int* stringtableIndex, int* posIndex, int* offset) { assert(stringtableIndex, "null string table index pointer"); assert(posIndex, "null string table offset pointer"); assert(offset, "null offset pointer"); - if (m_status != Decoder::no_error) { - return m_status; + if (NullDecoder::is_error(m_status)) { + return false; } address pc = 0; @@ -97,8 +97,8 @@ long cur_pos; if ((cur_pos = ftell(m_file)) == -1 || fseek(m_file, m_shdr.sh_offset, SEEK_SET)) { - m_status = Decoder::file_invalid; - return m_status; + m_status = NullDecoder::file_invalid; + return false; } Elf_Sym sym; @@ -114,13 +114,13 @@ } } } else { - m_status = Decoder::file_invalid; - return m_status; + m_status = NullDecoder::file_invalid; + return false; } } fseek(m_file, cur_pos, SEEK_SET); } - return m_status; + return true; } #endif // _WINDOWS
--- a/src/share/vm/utilities/elfSymbolTable.hpp Thu Jan 19 17:20:39 2012 -0800 +++ b/src/share/vm/utilities/elfSymbolTable.hpp Thu Jan 19 18:35:13 2012 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, 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 @@ -22,8 +22,8 @@ * */ -#ifndef __ELF_SYMBOL_TABLE_HPP -#define __ELF_SYMBOL_TABLE_HPP +#ifndef SHARE_VM_UTILITIES_ELF_SYMBOL_TABLE_HPP +#define SHARE_VM_UTILITIES_ELF_SYMBOL_TABLE_HPP #if !defined(_WINDOWS) && !defined(__APPLE__) @@ -45,9 +45,9 @@ ~ElfSymbolTable(); // search the symbol that is nearest to the specified address. - Decoder::decoder_status lookup(address addr, int* stringtableIndex, int* posIndex, int* offset); + bool lookup(address addr, int* stringtableIndex, int* posIndex, int* offset); - Decoder::decoder_status get_status() { return m_status; }; + NullDecoder::decoder_status get_status() { return m_status; }; protected: ElfSymbolTable* m_next; @@ -62,9 +62,9 @@ // section header Elf_Shdr m_shdr; - Decoder::decoder_status m_status; + NullDecoder::decoder_status m_status; }; -#endif // _WINDOWS +#endif // _WINDOWS and _APPLE -#endif // __ELF_SYMBOL_TABLE_HPP +#endif // SHARE_VM_UTILITIES_ELF_SYMBOL_TABLE_HPP
--- a/src/share/vm/utilities/globalDefinitions.hpp Thu Jan 19 17:20:39 2012 -0800 +++ b/src/share/vm/utilities/globalDefinitions.hpp Thu Jan 19 18:35:13 2012 -0800 @@ -298,6 +298,11 @@ const juint max_juint = (juint)-1; // 0xFFFFFFFF largest juint const julong max_julong = (julong)-1; // 0xFF....FF largest julong +typedef jbyte s1; +typedef jshort s2; +typedef jint s4; +typedef jlong s8; + //---------------------------------------------------------------------------------------------------- // JVM spec restrictions
--- a/src/share/vm/utilities/vmError.cpp Thu Jan 19 17:20:39 2012 -0800 +++ b/src/share/vm/utilities/vmError.cpp Thu Jan 19 18:35:13 2012 -0800 @@ -571,8 +571,6 @@ if (fr.pc()) { st->print_cr("Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)"); - // initialize decoder to decode C frames - Decoder decoder; int count = 0; while (count++ < StackPrintLimit) {