OpenJDK / aarch32-port / jdk8u / hotspot
changeset 6007:b5c8a61d7fa0
Merge
author | kvn |
---|---|
date | Fri, 21 Jun 2013 15:56:24 -0700 |
parents | d2907f74462e aaa45012be98 |
children | f4f6ae481e1a |
files | make/Makefile src/os/bsd/vm/os_bsd.cpp src/os/linux/vm/os_linux.cpp src/share/vm/compiler/compileBroker.cpp src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.inline.hpp src/share/vm/opto/compile.cpp src/share/vm/opto/matcher.cpp src/share/vm/runtime/deoptimization.cpp src/share/vm/runtime/frame.cpp src/share/vm/runtime/frame.hpp src/share/vm/runtime/globals.hpp src/share/vm/runtime/sharedRuntime.cpp src/share/vm/runtime/sharedRuntime.hpp src/share/vm/runtime/stubRoutines.hpp src/share/vm/runtime/vmStructs.cpp src/share/vm/trace/traceEventTypes.hpp src/share/vm/utilities/macros.hpp |
diffstat | 297 files changed, 10884 insertions(+), 2418 deletions(-) [+] |
line wrap: on
line diff
--- a/.hgtags Thu Jun 20 16:30:44 2013 -0700 +++ b/.hgtags Fri Jun 21 15:56:24 2013 -0700 @@ -347,3 +347,8 @@ 38da9f4f67096745f851318d792d6468aa1f6cf8 hs25-b34 092018493d3bbeb1c24278fd8c40ff3d76e1fed7 jdk8-b92 573d86d412cd9d3df7912194c1a540be50e9544e jdk8-b93 +b786c04b7be15194febe88dc1f0c9443e737a84b hs25-b35 +3c78a14da19d26d6937af5f98b97e2a21c653b04 hs25-b36 +1beed1f6f9edefe47ba8ed1355fbd3e7606b8288 jdk8-b94 +69689078dff8b21e6df30870464f5d736eebdf72 hs25-b37 +5d65c078cd0ac455aa5e58a09844c7acce54b487 jdk8-b95
--- a/agent/src/share/classes/sun/jvm/hotspot/memory/DictionaryEntry.java Thu Jun 20 16:30:44 2013 -0700 +++ b/agent/src/share/classes/sun/jvm/hotspot/memory/DictionaryEntry.java Fri Jun 21 15:56:24 2013 -0700 @@ -96,9 +96,10 @@ public boolean containsProtectionDomain(Oop protectionDomain) { InstanceKlass ik = (InstanceKlass) klass(); - if (protectionDomain.equals(ik.getProtectionDomain())) { - return true; // Succeeds trivially - } + // Currently unimplemented and not used. + // if (protectionDomain.equals(ik.getJavaMirror().getProtectionDomain())) { + // return true; // Succeeds trivially + // } for (ProtectionDomainEntry current = pdSet(); current != null; current = current.next()) { if (protectionDomain.equals(current.protectionDomain())) {
--- a/agent/src/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java Thu Jun 20 16:30:44 2013 -0700 +++ b/agent/src/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java Fri Jun 21 15:56:24 2013 -0700 @@ -75,8 +75,6 @@ javaFieldsCount = new CIntField(type.getCIntegerField("_java_fields_count"), 0); constants = new MetadataField(type.getAddressField("_constants"), 0); classLoaderData = type.getAddressField("_class_loader_data"); - protectionDomain = new OopField(type.getOopField("_protection_domain"), 0); - signers = new OopField(type.getOopField("_signers"), 0); sourceFileName = type.getAddressField("_source_file_name"); sourceDebugExtension = type.getAddressField("_source_debug_extension"); innerClasses = type.getAddressField("_inner_classes"); @@ -136,8 +134,6 @@ private static CIntField javaFieldsCount; private static MetadataField constants; private static AddressField classLoaderData; - private static OopField protectionDomain; - private static OopField signers; private static AddressField sourceFileName; private static AddressField sourceDebugExtension; private static AddressField innerClasses; @@ -350,8 +346,6 @@ public ConstantPool getConstants() { return (ConstantPool) constants.getValue(this); } public ClassLoaderData getClassLoaderData() { return ClassLoaderData.instantiateWrapperFor(classLoaderData.getValue(getAddress())); } public Oop getClassLoader() { return getClassLoaderData().getClassLoader(); } - public Oop getProtectionDomain() { return protectionDomain.getValue(this); } - public ObjArray getSigners() { return (ObjArray) signers.getValue(this); } public Symbol getSourceFileName() { return getSymbol(sourceFileName); } public String getSourceDebugExtension(){ return CStringUtilities.getString(sourceDebugExtension.getValue(getAddress())); } public long getNonstaticFieldSize() { return nonstaticFieldSize.getValue(this); } @@ -541,8 +535,6 @@ // visitor.doOop(methods, true); // visitor.doOop(localInterfaces, true); // visitor.doOop(transitiveInterfaces, true); - visitor.doOop(protectionDomain, true); - visitor.doOop(signers, true); visitor.doCInt(nonstaticFieldSize, true); visitor.doCInt(staticFieldSize, true); visitor.doCInt(staticOopFieldCount, true);
--- a/agent/src/share/classes/sun/jvm/hotspot/utilities/HeapGXLWriter.java Thu Jun 20 16:30:44 2013 -0700 +++ b/agent/src/share/classes/sun/jvm/hotspot/utilities/HeapGXLWriter.java Fri Jun 21 15:56:24 2013 -0700 @@ -204,13 +204,13 @@ Oop loader = ik.getClassLoader(); writeEdge(instance, loader, "loaded-by"); - // write signers - Oop signers = ik.getSigners(); - writeEdge(instance, signers, "signed-by"); + // write signers NYI + // Oop signers = ik.getJavaMirror().getSigners(); + writeEdge(instance, null, "signed-by"); - // write protection domain - Oop protectionDomain = ik.getProtectionDomain(); - writeEdge(instance, protectionDomain, "protection-domain"); + // write protection domain NYI + // Oop protectionDomain = ik.getJavaMirror().getProtectionDomain(); + writeEdge(instance, null, "protection-domain"); // write edges for static reference fields from this class for (Iterator itr = refFields.iterator(); itr.hasNext();) {
--- a/agent/src/share/classes/sun/jvm/hotspot/utilities/HeapHprofBinWriter.java Thu Jun 20 16:30:44 2013 -0700 +++ b/agent/src/share/classes/sun/jvm/hotspot/utilities/HeapHprofBinWriter.java Fri Jun 21 15:56:24 2013 -0700 @@ -477,8 +477,8 @@ if (k instanceof InstanceKlass) { InstanceKlass ik = (InstanceKlass) k; writeObjectID(ik.getClassLoader()); - writeObjectID(ik.getSigners()); - writeObjectID(ik.getProtectionDomain()); + writeObjectID(null); // ik.getJavaMirror().getSigners()); + writeObjectID(null); // ik.getJavaMirror().getProtectionDomain()); // two reserved id fields writeObjectID(null); writeObjectID(null); @@ -516,8 +516,8 @@ if (bottomKlass instanceof InstanceKlass) { InstanceKlass ik = (InstanceKlass) bottomKlass; writeObjectID(ik.getClassLoader()); - writeObjectID(ik.getSigners()); - writeObjectID(ik.getProtectionDomain()); + writeObjectID(null); // ik.getJavaMirror().getSigners()); + writeObjectID(null); // ik.getJavaMirror().getProtectionDomain()); } else { writeObjectID(null); writeObjectID(null);
--- a/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaInstanceKlass.java Thu Jun 20 16:30:44 2013 -0700 +++ b/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaInstanceKlass.java Fri Jun 21 15:56:24 2013 -0700 @@ -47,8 +47,6 @@ private static final int FIELD_IS_SYNTHETIC = 13; private static final int FIELD_IS_INTERFACE = 14; private static final int FIELD_CLASS_LOADER = 15; - private static final int FIELD_PROTECTION_DOMAIN = 16; - private static final int FIELD_SIGNERS = 17; private static final int FIELD_STATICS = 18; private static final int FIELD_UNDEFINED = -1; @@ -100,10 +98,6 @@ return Boolean.valueOf(ik.isInterface()); case FIELD_CLASS_LOADER: return factory.newJSJavaObject(ik.getClassLoader()); - case FIELD_PROTECTION_DOMAIN: - return factory.newJSJavaObject(ik.getProtectionDomain()); - case FIELD_SIGNERS: - return factory.newJSJavaObject(ik.getSigners()); case FIELD_STATICS: return getStatics(); case FIELD_UNDEFINED: @@ -246,8 +240,6 @@ addField("isSynthetic", FIELD_IS_SYNTHETIC); addField("isInterface", FIELD_IS_INTERFACE); addField("classLoader", FIELD_CLASS_LOADER); - addField("protectionDomain", FIELD_PROTECTION_DOMAIN); - addField("signers", FIELD_SIGNERS); addField("statics", FIELD_STATICS); }
--- a/make/Makefile Thu Jun 20 16:30:44 2013 -0700 +++ b/make/Makefile Fri Jun 21 15:56:24 2013 -0700 @@ -535,7 +535,7 @@ 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/% +$(EXPORT_INCLUDE_DIR)/%: $(HS_ALT_SRC)/share/vm/jfr/% $(install-file) else $(EXPORT_INCLUDE_DIR)/jfr.h:
--- a/make/bsd/makefiles/adlc.make Thu Jun 20 16:30:44 2013 -0700 +++ b/make/bsd/makefiles/adlc.make Fri Jun 21 15:56:24 2013 -0700 @@ -69,7 +69,7 @@ # CFLAGS_WARN holds compiler options to suppress/enable warnings. # Compiler warnings are treated as errors ifneq ($(COMPILER_WARNINGS_FATAL),false) - CFLAGS_WARN = -Werror + CFLAGS_WARN = $(WARNINGS_ARE_ERRORS) endif CFLAGS += $(CFLAGS_WARN)
--- a/make/bsd/makefiles/buildtree.make Thu Jun 20 16:30:44 2013 -0700 +++ b/make/bsd/makefiles/buildtree.make Fri Jun 21 15:56:24 2013 -0700 @@ -47,6 +47,7 @@ # flags.make - with macro settings # vm.make - to support making "$(MAKE) -v vm.make" in makefiles # adlc.make - +# trace.make - generate tracing event and type definitions # jvmti.make - generate JVMTI bindings from the spec (JSR-163) # sa.make - generate SA jar file and natives # @@ -119,6 +120,7 @@ $(PLATFORM_DIR)/generated/dependencies \ $(PLATFORM_DIR)/generated/adfiles \ $(PLATFORM_DIR)/generated/jvmtifiles \ + $(PLATFORM_DIR)/generated/tracefiles \ $(PLATFORM_DIR)/generated/dtracefiles TARGETS = debug fastdebug optimized product @@ -128,7 +130,7 @@ BUILDTREE_MAKE = $(GAMMADIR)/make/$(OS_FAMILY)/makefiles/buildtree.make # dtrace.make is used on BSD versions that implement Dtrace (like MacOS X) -BUILDTREE_TARGETS = Makefile flags.make flags_vm.make vm.make adlc.make jvmti.make sa.make dtrace.make +BUILDTREE_TARGETS = Makefile flags.make flags_vm.make vm.make adlc.make jvmti.make trace.make sa.make dtrace.make BUILDTREE_VARS = GAMMADIR=$(GAMMADIR) OS_FAMILY=$(OS_FAMILY) \ SRCARCH=$(SRCARCH) BUILDARCH=$(BUILDARCH) LIBARCH=$(LIBARCH) VARIANT=$(VARIANT) @@ -331,6 +333,16 @@ echo "include \$$(GAMMADIR)/make/$(OS_FAMILY)/makefiles/$(@F)"; \ ) > $@ +trace.make: $(BUILDTREE_MAKE) + @echo Creating $@ ... + $(QUIETLY) ( \ + $(BUILDTREE_COMMENT); \ + echo; \ + echo include flags.make; \ + echo; \ + echo "include \$$(GAMMADIR)/make/$(OS_FAMILY)/makefiles/$(@F)"; \ + ) > $@ + sa.make: $(BUILDTREE_MAKE) @echo Creating $@ ... $(QUIETLY) ( \
--- a/make/bsd/makefiles/gcc.make Thu Jun 20 16:30:44 2013 -0700 +++ b/make/bsd/makefiles/gcc.make Fri Jun 21 15:56:24 2013 -0700 @@ -71,6 +71,11 @@ CC = $(CC32) endif + ifeq ($(USE_CLANG), true) + CXX = clang++ + CC = clang + endif + HOSTCXX = $(CXX) HOSTCC = $(CC) endif @@ -79,21 +84,79 @@ endif -# -dumpversion in gcc-2.91 shows "egcs-2.91.66". In later version, it only -# prints the numbers (e.g. "2.95", "3.2.1") -CC_VER_MAJOR := $(shell $(CC) -dumpversion | sed 's/egcs-//' | cut -d'.' -f1) -CC_VER_MINOR := $(shell $(CC) -dumpversion | sed 's/egcs-//' | cut -d'.' -f2) - -# check for precompiled headers support -ifneq "$(shell expr \( $(CC_VER_MAJOR) \> 3 \) \| \( \( $(CC_VER_MAJOR) = 3 \) \& \( $(CC_VER_MINOR) \>= 4 \) \))" "0" -# Allow the user to turn off precompiled headers from the command line. -ifneq ($(USE_PRECOMPILED_HEADER),0) -PRECOMPILED_HEADER_DIR=. -PRECOMPILED_HEADER_SRC=$(GAMMADIR)/src/share/vm/precompiled/precompiled.hpp -PRECOMPILED_HEADER=$(PRECOMPILED_HEADER_DIR)/precompiled.hpp.gch -endif +ifeq ($(USE_CLANG), true) + CC_VER_MAJOR := $(shell $(CC) -v 2>&1 | grep version | sed "s/.*version \([0-9]*\.[0-9]*\).*/\1/" | cut -d'.' -f1) + CC_VER_MINOR := $(shell $(CC) -v 2>&1 | grep version | sed "s/.*version \([0-9]*\.[0-9]*\).*/\1/" | cut -d'.' -f2) +else + # -dumpversion in gcc-2.91 shows "egcs-2.91.66". In later version, it only + # prints the numbers (e.g. "2.95", "3.2.1") + CC_VER_MAJOR := $(shell $(CC) -dumpversion | sed 's/egcs-//' | cut -d'.' -f1) + CC_VER_MINOR := $(shell $(CC) -dumpversion | sed 's/egcs-//' | cut -d'.' -f2) endif +ifeq ($(USE_CLANG), true) + # clang has precompiled headers support by default, but the user can switch + # it off by using 'USE_PRECOMPILED_HEADER=0'. + ifdef LP64 + ifeq ($(USE_PRECOMPILED_HEADER),) + USE_PRECOMPILED_HEADER=1 + endif + else + # We don't support precompiled headers on 32-bit builds because there some files are + # compiled with -fPIC while others are compiled without (see 'NONPIC_OBJ_FILES' rules.make) + # Clang produces an error if the PCH file was compiled with other options than the actual compilation unit. + USE_PRECOMPILED_HEADER=0 + endif + + ifeq ($(USE_PRECOMPILED_HEADER),1) + + ifndef LP64 + $(error " Precompiled Headers only supported on 64-bit platforms!") + endif + + PRECOMPILED_HEADER_DIR=. + PRECOMPILED_HEADER_SRC=$(GAMMADIR)/src/share/vm/precompiled/precompiled.hpp + PRECOMPILED_HEADER=$(PRECOMPILED_HEADER_DIR)/precompiled.hpp.pch + + PCH_FLAG = -include precompiled.hpp + PCH_FLAG/DEFAULT = $(PCH_FLAG) + PCH_FLAG/NO_PCH = -DNO_PCH + PCH_FLAG/BY_FILE = $(PCH_FLAG/$@)$(PCH_FLAG/DEFAULT$(PCH_FLAG/$@)) + + VM_PCH_FLAG/LIBJVM = $(PCH_FLAG/BY_FILE) + VM_PCH_FLAG/AOUT = + VM_PCH_FLAG = $(VM_PCH_FLAG/$(LINK_INTO)) + + # We only use precompiled headers for the JVM build + CFLAGS += $(VM_PCH_FLAG) + + # There are some files which don't like precompiled headers + # The following files are build with 'OPT_CFLAGS/NOOPT' (-O0) in the opt build. + # But Clang doesn't support a precompiled header which was compiled with -O3 + # to be used in a compilation unit which uses '-O0'. We could also prepare an + # extra '-O0' PCH file for the opt build and use it here, but it's probably + # not worth the effort as long as only two files need this special handling. + PCH_FLAG/loopTransform.o = $(PCH_FLAG/NO_PCH) + PCH_FLAG/sharedRuntimeTrig.o = $(PCH_FLAG/NO_PCH) + PCH_FLAG/sharedRuntimeTrans.o = $(PCH_FLAG/NO_PCH) + + endif +else # ($(USE_CLANG), true) + # check for precompiled headers support + ifneq "$(shell expr \( $(CC_VER_MAJOR) \> 3 \) \| \( \( $(CC_VER_MAJOR) = 3 \) \& \( $(CC_VER_MINOR) \>= 4 \) \))" "0" + # Allow the user to turn off precompiled headers from the command line. + ifneq ($(USE_PRECOMPILED_HEADER),0) + PRECOMPILED_HEADER_DIR=. + PRECOMPILED_HEADER_SRC=$(GAMMADIR)/src/share/vm/precompiled/precompiled.hpp + PRECOMPILED_HEADER=$(PRECOMPILED_HEADER_DIR)/precompiled.hpp.gch + endif + endif +endif + +# -DDONT_USE_PRECOMPILED_HEADER will exclude all includes in precompiled.hpp. +ifeq ($(USE_PRECOMPILED_HEADER),0) + CFLAGS += -DDONT_USE_PRECOMPILED_HEADER +endif #------------------------------------------------------------------------ # Compiler flags @@ -115,17 +178,31 @@ CFLAGS += $(VM_PICFLAG) CFLAGS += -fno-rtti CFLAGS += -fno-exceptions -CFLAGS += -pthread -CFLAGS += -fcheck-new -# version 4 and above support fvisibility=hidden (matches jni_x86.h file) -# except 4.1.2 gives pointless warnings that can't be disabled (afaik) -ifneq "$(shell expr \( $(CC_VER_MAJOR) \> 4 \) \| \( \( $(CC_VER_MAJOR) = 4 \) \& \( $(CC_VER_MINOR) \>= 3 \) \))" "0" -CFLAGS += -fvisibility=hidden +ifeq ($(USE_CLANG),) + CFLAGS += -pthread + CFLAGS += -fcheck-new + # version 4 and above support fvisibility=hidden (matches jni_x86.h file) + # except 4.1.2 gives pointless warnings that can't be disabled (afaik) + ifneq "$(shell expr \( $(CC_VER_MAJOR) \> 4 \) \| \( \( $(CC_VER_MAJOR) = 4 \) \& \( $(CC_VER_MINOR) \>= 3 \) \))" "0" + CFLAGS += -fvisibility=hidden + endif +else + CFLAGS += -fvisibility=hidden +endif + +ifeq ($(USE_CLANG), true) + # Before Clang 3.1, we had to pass the stack alignment specification directly to llvm with the help of '-mllvm' + # Starting with version 3.1, Clang understands the '-mstack-alignment' (and rejects '-mllvm -stack-alignment') + ifneq "$(shell expr \( $(CC_VER_MAJOR) \> 3 \) \| \( \( $(CC_VER_MAJOR) = 3 \) \& \( $(CC_VER_MINOR) \>= 1 \) \))" "0" + STACK_ALIGNMENT_OPT = -mno-omit-leaf-frame-pointer -mstack-alignment=16 + else + STACK_ALIGNMENT_OPT = -mno-omit-leaf-frame-pointer -mllvm -stack-alignment=16 + endif endif ARCHFLAG = $(ARCHFLAG/$(BUILDARCH)) ARCHFLAG/i486 = -m32 -march=i586 -ARCHFLAG/amd64 = -m64 +ARCHFLAG/amd64 = -m64 $(STACK_ALIGNMENT_OPT) ARCHFLAG/ia64 = ARCHFLAG/sparc = -m32 -mcpu=v9 ARCHFLAG/sparcv9 = -m64 -mcpu=v9 @@ -163,14 +240,25 @@ WARNINGS_ARE_ERRORS = -Werror endif -# Except for a few acceptable ones -# Since GCC 4.3, -Wconversion has changed its meanings to warn these implicit -# conversions which might affect the values. To avoid that, we need to turn -# it off explicitly. -ifneq "$(shell expr \( $(CC_VER_MAJOR) \> 4 \) \| \( \( $(CC_VER_MAJOR) = 4 \) \& \( $(CC_VER_MINOR) \>= 3 \) \))" "0" +ifeq ($(USE_CLANG), true) + # However we need to clean the code up before we can unrestrictedly enable this option with Clang + WARNINGS_ARE_ERRORS += -Wno-unused-value -Wno-logical-op-parentheses -Wno-parentheses-equality -Wno-parentheses + WARNINGS_ARE_ERRORS += -Wno-switch -Wno-tautological-compare +# Not yet supported by clang in Xcode 4.6.2 +# WARNINGS_ARE_ERRORS += -Wno-tautological-constant-out-of-range-compare + WARNINGS_ARE_ERRORS += -Wno-delete-non-virtual-dtor -Wno-deprecated -Wno-format -Wno-dynamic-class-memaccess + WARNINGS_ARE_ERRORS += -Wno-return-type -Wno-empty-body +endif + WARNING_FLAGS = -Wpointer-arith -Wsign-compare -Wundef -else -WARNING_FLAGS = -Wpointer-arith -Wconversion -Wsign-compare -Wundef + +ifeq "$(shell expr \( $(CC_VER_MAJOR) \> 4 \) \| \( \( $(CC_VER_MAJOR) = 4 \) \& \( $(CC_VER_MINOR) \>= 3 \) \))" "0" + # Since GCC 4.3, -Wconversion has changed its meanings to warn these implicit + # conversions which might affect the values. Only enable it in earlier versions. + WARNING_FLAGS = -Wunused-function + ifeq ($(USE_CLANG),) + WARNINGS_FLAGS += -Wconversion + endif endif CFLAGS_WARN/DEFAULT = $(WARNINGS_ARE_ERRORS) $(WARNING_FLAGS) @@ -214,14 +302,24 @@ OPT_CFLAGS/NOOPT=-O0 -# 6835796. Problem in GCC 4.3.0 with mulnode.o optimized compilation. -ifneq "$(shell expr \( \( $(CC_VER_MAJOR) = 4 \) \& \( $(CC_VER_MINOR) = 3 \) \))" "0" -OPT_CFLAGS/mulnode.o += -O0 +# Work around some compiler bugs. +ifeq ($(USE_CLANG), true) + ifeq ($(shell expr $(CC_VER_MAJOR) = 4 \& $(CC_VER_MINOR) = 2), 1) + OPT_CFLAGS/loopTransform.o += $(OPT_CFLAGS/NOOPT) + endif +else + # 6835796. Problem in GCC 4.3.0 with mulnode.o optimized compilation. + ifeq ($(shell expr $(CC_VER_MAJOR) = 4 \& $(CC_VER_MINOR) = 3), 1) + OPT_CFLAGS/mulnode.o += $(OPT_CFLAGS/NOOPT) + endif endif # Flags for generating make dependency flags. -ifneq ("${CC_VER_MAJOR}", "2") -DEPFLAGS = -fpch-deps -MMD -MP -MF $(DEP_DIR)/$(@:%=%.d) +DEPFLAGS = -MMD -MP -MF $(DEP_DIR)/$(@:%=%.d) +ifeq ($(USE_CLANG),) + ifneq ($(CC_VER_MAJOR), 2) + DEPFLAGS += -fpch-deps + endif endif # -DDONT_USE_PRECOMPILED_HEADER will exclude all includes in precompiled.hpp. @@ -249,13 +347,15 @@ # statically link libstdc++.so, work with gcc but ignored by g++ STATIC_STDCXX = -Wl,-Bstatic -lstdc++ -Wl,-Bdynamic -# statically link libgcc and/or libgcc_s, libgcc does not exist before gcc-3.x. -ifneq ("${CC_VER_MAJOR}", "2") -STATIC_LIBGCC += -static-libgcc -endif +ifeq ($(USE_CLANG),) + # statically link libgcc and/or libgcc_s, libgcc does not exist before gcc-3.x. + ifneq ("${CC_VER_MAJOR}", "2") + STATIC_LIBGCC += -static-libgcc + endif -ifeq ($(BUILDARCH), ia64) -LFLAGS += -Wl,-relax + ifeq ($(BUILDARCH), ia64) + LFLAGS += -Wl,-relax + endif endif # Use $(MAPFLAG:FILENAME=real_file_name) to specify a map file. @@ -296,25 +396,31 @@ #------------------------------------------------------------------------ # Debug flags -# Use the stabs format for debugging information (this is the default -# on gcc-2.91). It's good enough, has all the information about line -# numbers and local variables, and libjvm.so is only about 16M. -# Change this back to "-g" if you want the most expressive format. -# (warning: that could easily inflate libjvm.so to 150M!) -# Note: The Itanium gcc compiler crashes when using -gstabs. -DEBUG_CFLAGS/ia64 = -g -DEBUG_CFLAGS/amd64 = -g -DEBUG_CFLAGS/arm = -g -DEBUG_CFLAGS/ppc = -g -DEBUG_CFLAGS += $(DEBUG_CFLAGS/$(BUILDARCH)) -ifeq ($(DEBUG_CFLAGS/$(BUILDARCH)),) -DEBUG_CFLAGS += -gstabs +ifeq ($(USE_CLANG), true) + # Restrict the debug information created by Clang to avoid + # too big object files and speed the build up a little bit + # (see http://llvm.org/bugs/show_bug.cgi?id=7554) + CFLAGS += -flimit-debug-info endif -# DEBUG_BINARIES overrides everything, use full -g debug information +# DEBUG_BINARIES uses full -g debug information for all configs ifeq ($(DEBUG_BINARIES), true) - DEBUG_CFLAGS = -g - CFLAGS += $(DEBUG_CFLAGS) + CFLAGS += -g +else + # Use the stabs format for debugging information (this is the default + # on gcc-2.91). It's good enough, has all the information about line + # numbers and local variables, and libjvm.so is only about 16M. + # Change this back to "-g" if you want the most expressive format. + # (warning: that could easily inflate libjvm.so to 150M!) + # Note: The Itanium gcc compiler crashes when using -gstabs. + DEBUG_CFLAGS/ia64 = -g + DEBUG_CFLAGS/amd64 = -g + DEBUG_CFLAGS/arm = -g + DEBUG_CFLAGS/ppc = -g + DEBUG_CFLAGS += $(DEBUG_CFLAGS/$(BUILDARCH)) + ifeq ($(DEBUG_CFLAGS/$(BUILDARCH)),) + DEBUG_CFLAGS += -gstabs + endif endif # If we are building HEADLESS, pass on to VM
--- a/make/bsd/makefiles/minimal1.make Thu Jun 20 16:30:44 2013 -0700 +++ b/make/bsd/makefiles/minimal1.make Fri Jun 21 15:56:24 2013 -0700 @@ -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. -# +# # TYPE=MINIMAL1 @@ -32,6 +32,7 @@ INCLUDE_MANAGEMENT ?= false INCLUDE_ALL_GCS ?= false INCLUDE_NMT ?= false +INCLUDE_TRACE ?= false INCLUDE_CDS ?= false CXXFLAGS += -DMINIMAL_JVM -DCOMPILER1 -DVMTYPE=\"Minimal\"
--- a/make/bsd/makefiles/top.make Thu Jun 20 16:30:44 2013 -0700 +++ b/make/bsd/makefiles/top.make Fri Jun 21 15:56:24 2013 -0700 @@ -1,5 +1,5 @@ # -# Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -80,7 +80,7 @@ @echo All done. # This is an explicit dependency for the sake of parallel makes. -vm_build_preliminaries: checks $(Cached_plat) $(AD_Files_If_Required) jvmti_stuff sa_stuff dtrace_stuff +vm_build_preliminaries: checks $(Cached_plat) $(AD_Files_If_Required) jvmti_stuff trace_stuff sa_stuff dtrace_stuff @# We need a null action here, so implicit rules don't get consulted. $(Cached_plat): $(Plat_File) @@ -94,6 +94,10 @@ jvmti_stuff: $(Cached_plat) $(adjust-mflags) @$(MAKE) -f jvmti.make $(MFLAGS-adjusted) +# generate trace files +trace_stuff: jvmti_stuff $(Cached_plat) $(adjust-mflags) + @$(MAKE) -f trace.make $(MFLAGS-adjusted) + ifeq ($(OS_VENDOR), Darwin) # generate dtrace header files dtrace_stuff: $(Cached_plat) $(adjust-mflags)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/make/bsd/makefiles/trace.make Fri Jun 21 15:56:24 2013 -0700 @@ -0,0 +1,121 @@ +# +# Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# 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. +# +# + +# This makefile (trace.make) is included from the trace.make in the +# build directories. +# +# It knows how to build and run the tools to generate trace files. + +include $(GAMMADIR)/make/bsd/makefiles/rules.make +include $(GAMMADIR)/make/altsrc.make + +# ######################################################################### + +HAS_ALT_SRC:=$(shell if [ -d $(HS_ALT_SRC)/share/vm/trace ]; then \ + echo "true"; else echo "false";\ + fi) + +TOPDIR = $(shell echo `pwd`) +GENERATED = $(TOPDIR)/../generated +JvmtiOutDir = $(GENERATED)/jvmtifiles +TraceOutDir = $(GENERATED)/tracefiles + +TraceAltSrcDir = $(HS_ALT_SRC)/share/vm/trace +TraceSrcDir = $(HS_COMMON_SRC)/share/vm/trace + +# set VPATH so make knows where to look for source files +Src_Dirs_V += $(TraceSrcDir) $(TraceAltSrcDir) +VPATH += $(Src_Dirs_V:%=%:) + +TraceGeneratedNames = \ + traceEventClasses.hpp \ + traceEventIds.hpp \ + traceTypes.hpp + +ifeq ($(HAS_ALT_SRC), true) +TraceGeneratedNames += \ + traceRequestables.hpp \ + traceEventControl.hpp + +ifneq ($(INCLUDE_TRACE), false) +TraceGeneratedNames += traceProducer.cpp +endif + +endif + + +TraceGeneratedFiles = $(TraceGeneratedNames:%=$(TraceOutDir)/%) + +XSLT = $(REMOTE) $(RUN.JAVA) -classpath $(JvmtiOutDir) jvmtiGen + +XML_DEPS = $(TraceSrcDir)/trace.xml $(TraceSrcDir)/tracetypes.xml \ + $(TraceSrcDir)/trace.dtd $(TraceSrcDir)/xinclude.mod +ifeq ($(HAS_ALT_SRC), true) + XML_DEPS += $(TraceAltSrcDir)/traceevents.xml +endif + +.PHONY: all clean cleanall + +# ######################################################################### + +all: $(TraceGeneratedFiles) + +GENERATE_CODE= \ + $(QUIETLY) echo Generating $@; \ + $(XSLT) -IN $(word 1,$^) -XSL $(word 2,$^) -OUT $@; \ + test -f $@ + +$(TraceOutDir)/traceEventIds.hpp: $(TraceSrcDir)/trace.xml $(TraceSrcDir)/traceEventIds.xsl $(XML_DEPS) + $(GENERATE_CODE) + +$(TraceOutDir)/traceTypes.hpp: $(TraceSrcDir)/trace.xml $(TraceSrcDir)/traceTypes.xsl $(XML_DEPS) + $(GENERATE_CODE) + +ifeq ($(HAS_ALT_SRC), false) + +$(TraceOutDir)/traceEventClasses.hpp: $(TraceSrcDir)/trace.xml $(TraceSrcDir)/traceEventClasses.xsl $(XML_DEPS) + $(GENERATE_CODE) + +else + +$(TraceOutDir)/traceEventClasses.hpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir)/traceEventClasses.xsl $(XML_DEPS) + $(GENERATE_CODE) + +$(TraceOutDir)/traceProducer.cpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir)/traceProducer.xsl $(XML_DEPS) + $(GENERATE_CODE) + +$(TraceOutDir)/traceRequestables.hpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir)/traceRequestables.xsl $(XML_DEPS) + $(GENERATE_CODE) + +$(TraceOutDir)/traceEventControl.hpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir)/traceEventControl.xsl $(XML_DEPS) + $(GENERATE_CODE) + +endif + +# ######################################################################### + + +clean cleanall: + rm $(TraceGeneratedFiles) +
--- a/make/bsd/makefiles/vm.make Thu Jun 20 16:30:44 2013 -0700 +++ b/make/bsd/makefiles/vm.make Fri Jun 21 15:56:24 2013 -0700 @@ -1,5 +1,5 @@ # -# Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -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. -# +# # # Rules to build JVM and related libraries, included from vm.make in the build @@ -52,7 +52,7 @@ # Src_Dirs_V is everything in src/share/vm/*, plus the right os/*/vm and cpu/*/vm # The adfiles directory contains ad_<arch>.[ch]pp. # The jvmtifiles directory contains jvmti*.[ch]pp -Src_Dirs_V += $(GENERATED)/adfiles $(GENERATED)/jvmtifiles +Src_Dirs_V += $(GENERATED)/adfiles $(GENERATED)/jvmtifiles $(GENERATED)/tracefiles VPATH += $(Src_Dirs_V:%=%:) # set INCLUDES for C preprocessor. @@ -66,7 +66,7 @@ SYMFLAG = endif -# HOTSPOT_RELEASE_VERSION and HOTSPOT_BUILD_VERSION are defined +# HOTSPOT_RELEASE_VERSION and HOTSPOT_BUILD_VERSION are defined # in $(GAMMADIR)/make/defs.make ifeq ($(HOTSPOT_BUILD_VERSION),) BUILD_VERSION = -DHOTSPOT_RELEASE_VERSION="\"$(HOTSPOT_RELEASE_VERSION)\"" @@ -93,7 +93,7 @@ # This is VERY important! The version define must only be supplied to vm_version.o # If not, ccache will not re-use the cache at all, since the version string might contain -# a time and date. +# a time and date. CXXFLAGS/vm_version.o += ${JRE_VERSION} CXXFLAGS/BYFILE = $(CXXFLAGS/$@) @@ -105,10 +105,6 @@ CXXFLAGS += -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) @@ -126,7 +122,11 @@ LFLAGS += -Xlinker -z -Xlinker noexecstack endif -LIBS += -lm -pthread +LIBS += -lm + +ifeq ($(USE_CLANG),) + LIBS += -pthread +endif # By default, link the *.o into the library, not the executable. LINK_INTO$(LINK_INTO) = LIBJVM @@ -161,15 +161,15 @@ 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 \ +CORE_PATHS=$(foreach path,$(SOURCE_PATHS),$(call altsrc,$(path)) $(path)) +CORE_PATHS+=$(GENERATED)/jvmtifiles $(GENERATED)/tracefiles + +ifneq ($(INCLUDE_TRACE), false) +CORE_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 - COMPILER1_PATHS := $(call altsrc,$(HS_COMMON_SRC)/share/vm/c1) COMPILER1_PATHS += $(HS_COMMON_SRC)/share/vm/c1
--- a/make/defs.make Thu Jun 20 16:30:44 2013 -0700 +++ b/make/defs.make Fri Jun 21 15:56:24 2013 -0700 @@ -1,5 +1,5 @@ # -# Copyright (c) 2006, 2012, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2006, 2013, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -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. -# +# # # The common definitions for hotspot builds. @@ -236,7 +236,7 @@ JDK_IMAGE_DIR=$(ALT_JDK_IMAGE_DIR) endif -# The platform dependent defs.make defines platform specific variable such +# The platform dependent defs.make defines platform specific variable such # as ARCH, EXPORT_LIST etc. We must place the include here after BOOTDIR is defined. include $(GAMMADIR)/make/$(OSNAME)/makefiles/defs.make @@ -258,7 +258,7 @@ # LIBARCH - directory name in JDK/JRE # Use uname output for SRCARCH, but deal with platform differences. If ARCH - # is not explicitly listed below, it is treated as x86. + # is not explicitly listed below, it is treated as x86. SRCARCH = $(ARCH/$(filter sparc sparc64 ia64 amd64 x86_64 arm ppc zero,$(ARCH))) ARCH/ = x86 ARCH/sparc = sparc @@ -337,8 +337,5 @@ 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 +.PHONY: $(HS_ALT_MAKE)/defs.make -.PHONY: $(HS_ALT_MAKE)/defs.make
--- a/make/excludeSrc.make Thu Jun 20 16:30:44 2013 -0700 +++ b/make/excludeSrc.make Fri Jun 21 15:56:24 2013 -0700 @@ -19,13 +19,13 @@ # 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. -# +# # ifeq ($(INCLUDE_JVMTI), false) CXXFLAGS += -DINCLUDE_JVMTI=0 CFLAGS += -DINCLUDE_JVMTI=0 - Src_Files_EXCLUDE += jvmtiGetLoadedClasses.cpp forte.cpp jvmtiThreadState.cpp jvmtiExtensions.cpp \ + Src_Files_EXCLUDE += jvmtiGetLoadedClasses.cpp jvmtiThreadState.cpp jvmtiExtensions.cpp \ jvmtiImpl.cpp jvmtiManageCapabilities.cpp jvmtiRawMonitor.cpp jvmtiUtil.cpp jvmtiTrace.cpp \ jvmtiCodeBlobEvents.cpp jvmtiEnv.cpp jvmtiRedefineClasses.cpp jvmtiEnvBase.cpp jvmtiEnvThreadState.cpp \ jvmtiTagMap.cpp jvmtiEventController.cpp evmCompat.cpp jvmtiEnter.xsl jvmtiExport.cpp \ @@ -87,7 +87,7 @@ g1BlockOffsetTable.cpp g1CardCounts.cpp g1CollectedHeap.cpp g1CollectorPolicy.cpp \ g1ErgoVerbose.cpp g1GCPhaseTimes.cpp g1HRPrinter.cpp g1HotCardCache.cpp g1Log.cpp \ g1MMUTracker.cpp g1MarkSweep.cpp g1MemoryPool.cpp g1MonitoringSupport.cpp \ - g1RemSet.cpp g1SATBCardTableModRefBS.cpp g1_globals.cpp heapRegion.cpp \ + g1RemSet.cpp g1RemSetSummary.cpp g1SATBCardTableModRefBS.cpp g1_globals.cpp heapRegion.cpp \ heapRegionRemSet.cpp heapRegionSeq.cpp heapRegionSet.cpp heapRegionSets.cpp \ ptrQueue.cpp satbQueue.cpp sparsePRT.cpp survRateGroup.cpp vm_operations_g1.cpp \ adjoiningGenerations.cpp adjoiningVirtualSpaces.cpp asPSOldGen.cpp asPSYoungGen.cpp \ @@ -100,7 +100,7 @@ parCardTableModRefBS.cpp parGCAllocBuffer.cpp parNewGeneration.cpp mutableSpace.cpp \ gSpaceCounters.cpp allocationStats.cpp spaceCounters.cpp gcAdaptivePolicyCounters.cpp \ mutableNUMASpace.cpp immutableSpace.cpp yieldingWorkGroup.cpp -endif +endif ifeq ($(INCLUDE_NMT), false) CXXFLAGS += -DINCLUDE_NMT=0 @@ -110,3 +110,5 @@ memBaseline.cpp memPtr.cpp memRecorder.cpp memReporter.cpp memSnapshot.cpp memTrackWorker.cpp \ memTracker.cpp nmtDCmd.cpp endif + +-include $(HS_ALT_MAKE)/excludeSrc.make
--- a/make/hotspot_version Thu Jun 20 16:30:44 2013 -0700 +++ b/make/hotspot_version Fri Jun 21 15:56:24 2013 -0700 @@ -35,7 +35,7 @@ HS_MAJOR_VER=25 HS_MINOR_VER=0 -HS_BUILD_NUMBER=34 +HS_BUILD_NUMBER=37 JDK_MAJOR_VER=1 JDK_MINOR_VER=8
--- a/make/linux/makefiles/adlc.make Thu Jun 20 16:30:44 2013 -0700 +++ b/make/linux/makefiles/adlc.make Fri Jun 21 15:56:24 2013 -0700 @@ -68,7 +68,7 @@ # CFLAGS_WARN holds compiler options to suppress/enable warnings. # Compiler warnings are treated as errors -CFLAGS_WARN = -Werror +CFLAGS_WARN = $(WARNINGS_ARE_ERRORS) CFLAGS += $(CFLAGS_WARN) OBJECTNAMES = \
--- a/make/linux/makefiles/buildtree.make Thu Jun 20 16:30:44 2013 -0700 +++ b/make/linux/makefiles/buildtree.make Fri Jun 21 15:56:24 2013 -0700 @@ -47,6 +47,7 @@ # flags.make - with macro settings # vm.make - to support making "$(MAKE) -v vm.make" in makefiles # adlc.make - +# trace.make - generate tracing event and type definitions # jvmti.make - generate JVMTI bindings from the spec (JSR-163) # sa.make - generate SA jar file and natives # @@ -114,7 +115,8 @@ SIMPLE_DIRS = \ $(PLATFORM_DIR)/generated/dependencies \ $(PLATFORM_DIR)/generated/adfiles \ - $(PLATFORM_DIR)/generated/jvmtifiles + $(PLATFORM_DIR)/generated/jvmtifiles \ + $(PLATFORM_DIR)/generated/tracefiles TARGETS = debug fastdebug optimized product SUBMAKE_DIRS = $(addprefix $(PLATFORM_DIR)/,$(TARGETS)) @@ -122,7 +124,7 @@ # For dependencies and recursive makes. BUILDTREE_MAKE = $(GAMMADIR)/make/$(OS_FAMILY)/makefiles/buildtree.make -BUILDTREE_TARGETS = Makefile flags.make flags_vm.make vm.make adlc.make jvmti.make sa.make +BUILDTREE_TARGETS = Makefile flags.make flags_vm.make vm.make adlc.make jvmti.make trace.make sa.make BUILDTREE_VARS = GAMMADIR=$(GAMMADIR) OS_FAMILY=$(OS_FAMILY) \ SRCARCH=$(SRCARCH) BUILDARCH=$(BUILDARCH) LIBARCH=$(LIBARCH) VARIANT=$(VARIANT) @@ -269,6 +271,8 @@ echo && \ echo "HOTSPOT_EXTRA_SYSDEFS\$$(HOTSPOT_EXTRA_SYSDEFS) = $(HOTSPOT_EXTRA_SYSDEFS)" && \ echo "SYSDEFS += \$$(HOTSPOT_EXTRA_SYSDEFS)"; \ + [ -n "$(INCLUDE_TRACE)" ] && \ + echo && echo "INCLUDE_TRACE = $(INCLUDE_TRACE)"; \ echo; \ [ -n "$(SPEC)" ] && \ echo "include $(SPEC)"; \ @@ -337,6 +341,16 @@ echo "include \$$(GAMMADIR)/make/$(OS_FAMILY)/makefiles/$(@F)"; \ ) > $@ +trace.make: $(BUILDTREE_MAKE) + @echo Creating $@ ... + $(QUIETLY) ( \ + $(BUILDTREE_COMMENT); \ + echo; \ + echo include flags.make; \ + echo; \ + echo "include \$$(GAMMADIR)/make/$(OS_FAMILY)/makefiles/$(@F)"; \ + ) > $@ + sa.make: $(BUILDTREE_MAKE) @echo Creating $@ ... $(QUIETLY) ( \
--- a/make/linux/makefiles/gcc.make Thu Jun 20 16:30:44 2013 -0700 +++ b/make/linux/makefiles/gcc.make Fri Jun 21 15:56:24 2013 -0700 @@ -36,8 +36,14 @@ HOSTCC = gcc STRIP = $(ALT_COMPILER_PATH)/strip else - CXX = g++ - CC = gcc + ifeq ($(USE_CLANG), true) + CXX = clang++ + CC = clang + else + CXX = g++ + CC = gcc + endif + HOSTCXX = $(CXX) HOSTCC = $(CC) STRIP = strip @@ -46,19 +52,79 @@ endif -# -dumpversion in gcc-2.91 shows "egcs-2.91.66". In later version, it only -# prints the numbers (e.g. "2.95", "3.2.1") -CC_VER_MAJOR := $(shell $(CC) -dumpversion | sed 's/egcs-//' | cut -d'.' -f1) -CC_VER_MINOR := $(shell $(CC) -dumpversion | sed 's/egcs-//' | cut -d'.' -f2) +ifeq ($(USE_CLANG), true) + CC_VER_MAJOR := $(shell $(CC) -v 2>&1 | grep version | sed "s/.*version \([0-9]*\.[0-9]*\).*/\1/" | cut -d'.' -f1) + CC_VER_MINOR := $(shell $(CC) -v 2>&1 | grep version | sed "s/.*version \([0-9]*\.[0-9]*\).*/\1/" | cut -d'.' -f2) +else + # -dumpversion in gcc-2.91 shows "egcs-2.91.66". In later version, it only + # prints the numbers (e.g. "2.95", "3.2.1") + CC_VER_MAJOR := $(shell $(CC) -dumpversion | sed 's/egcs-//' | cut -d'.' -f1) + CC_VER_MINOR := $(shell $(CC) -dumpversion | sed 's/egcs-//' | cut -d'.' -f2) +endif -# check for precompiled headers support -ifneq "$(shell expr \( $(CC_VER_MAJOR) \> 3 \) \| \( \( $(CC_VER_MAJOR) = 3 \) \& \( $(CC_VER_MINOR) \>= 4 \) \))" "0" -# Allow the user to turn off precompiled headers from the command line. -ifneq ($(USE_PRECOMPILED_HEADER),0) -PRECOMPILED_HEADER_DIR=. -PRECOMPILED_HEADER_SRC=$(GAMMADIR)/src/share/vm/precompiled/precompiled.hpp -PRECOMPILED_HEADER=$(PRECOMPILED_HEADER_DIR)/precompiled.hpp.gch + +ifeq ($(USE_CLANG), true) + # Clang has precompiled headers support by default, but the user can switch + # it off by using 'USE_PRECOMPILED_HEADER=0'. + ifdef LP64 + ifeq ($(USE_PRECOMPILED_HEADER),) + USE_PRECOMPILED_HEADER=1 + endif + else + # We don't support precompiled headers on 32-bit builds because there some files are + # compiled with -fPIC while others are compiled without (see 'NONPIC_OBJ_FILES' rules.make) + # Clang produces an error if the PCH file was compiled with other options than the actual compilation unit. + USE_PRECOMPILED_HEADER=0 + endif + + ifeq ($(USE_PRECOMPILED_HEADER),1) + + ifndef LP64 + $(error " Precompiled Headers only supported on 64-bit platforms!") + endif + + PRECOMPILED_HEADER_DIR=. + PRECOMPILED_HEADER_SRC=$(GAMMADIR)/src/share/vm/precompiled/precompiled.hpp + PRECOMPILED_HEADER=$(PRECOMPILED_HEADER_DIR)/precompiled.hpp.pch + + PCH_FLAG = -include precompiled.hpp + PCH_FLAG/DEFAULT = $(PCH_FLAG) + PCH_FLAG/NO_PCH = -DNO_PCH + PCH_FLAG/BY_FILE = $(PCH_FLAG/$@)$(PCH_FLAG/DEFAULT$(PCH_FLAG/$@)) + + VM_PCH_FLAG/LIBJVM = $(PCH_FLAG/BY_FILE) + VM_PCH_FLAG/AOUT = + VM_PCH_FLAG = $(VM_PCH_FLAG/$(LINK_INTO)) + + # We only use precompiled headers for the JVM build + CFLAGS += $(VM_PCH_FLAG) + + # There are some files which don't like precompiled headers + # The following files are build with 'OPT_CFLAGS/NOOPT' (-O0) in the opt build. + # But Clang doesn't support a precompiled header which was compiled with -O3 + # to be used in a compilation unit which uses '-O0'. We could also prepare an + # extra '-O0' PCH file for the opt build and use it here, but it's probably + # not worth the effoert as long as only two files need this special handling. + PCH_FLAG/loopTransform.o = $(PCH_FLAG/NO_PCH) + PCH_FLAG/sharedRuntimeTrig.o = $(PCH_FLAG/NO_PCH) + PCH_FLAG/sharedRuntimeTrans.o = $(PCH_FLAG/NO_PCH) + + endif +else # ($(USE_CLANG), true) + # check for precompiled headers support + ifneq "$(shell expr \( $(CC_VER_MAJOR) \> 3 \) \| \( \( $(CC_VER_MAJOR) = 3 \) \& \( $(CC_VER_MINOR) \>= 4 \) \))" "0" + # Allow the user to turn off precompiled headers from the command line. + ifneq ($(USE_PRECOMPILED_HEADER),0) + PRECOMPILED_HEADER_DIR=. + PRECOMPILED_HEADER_SRC=$(GAMMADIR)/src/share/vm/precompiled/precompiled.hpp + PRECOMPILED_HEADER=$(PRECOMPILED_HEADER_DIR)/precompiled.hpp.gch + endif + endif endif + +# -DDONT_USE_PRECOMPILED_HEADER will exclude all includes in precompiled.hpp. +ifeq ($(USE_PRECOMPILED_HEADER),0) + CFLAGS += -DDONT_USE_PRECOMPILED_HEADER endif @@ -83,16 +149,30 @@ CFLAGS += -fno-rtti CFLAGS += -fno-exceptions CFLAGS += -D_REENTRANT -CFLAGS += -fcheck-new -# version 4 and above support fvisibility=hidden (matches jni_x86.h file) -# except 4.1.2 gives pointless warnings that can't be disabled (afaik) -ifneq "$(shell expr \( $(CC_VER_MAJOR) \> 4 \) \| \( \( $(CC_VER_MAJOR) = 4 \) \& \( $(CC_VER_MINOR) \>= 3 \) \))" "0" -CFLAGS += -fvisibility=hidden +ifeq ($(USE_CLANG),) + CFLAGS += -fcheck-new + # version 4 and above support fvisibility=hidden (matches jni_x86.h file) + # except 4.1.2 gives pointless warnings that can't be disabled (afaik) + ifneq "$(shell expr \( $(CC_VER_MAJOR) \> 4 \) \| \( \( $(CC_VER_MAJOR) = 4 \) \& \( $(CC_VER_MINOR) \>= 3 \) \))" "0" + CFLAGS += -fvisibility=hidden + endif +else + CFLAGS += -fvisibility=hidden +endif + +ifeq ($(USE_CLANG), true) + # Before Clang 3.1, we had to pass the stack alignment specification directly to llvm with the help of '-mllvm' + # Starting with version 3.1, Clang understands the '-mstack-alignment' (and rejects '-mllvm -stack-alignment') + ifneq "$(shell expr \( $(CC_VER_MAJOR) \> 3 \) \| \( \( $(CC_VER_MAJOR) = 3 \) \& \( $(CC_VER_MINOR) \>= 1 \) \))" "0" + STACK_ALIGNMENT_OPT = -mno-omit-leaf-frame-pointer -mstack-alignment=16 + else + STACK_ALIGNMENT_OPT = -mno-omit-leaf-frame-pointer -mllvm -stack-alignment=16 + endif endif ARCHFLAG = $(ARCHFLAG/$(BUILDARCH)) ARCHFLAG/i486 = -m32 -march=i586 -ARCHFLAG/amd64 = -m64 +ARCHFLAG/amd64 = -m64 $(STACK_ALIGNMENT_OPT) ARCHFLAG/ia64 = ARCHFLAG/sparc = -m32 -mcpu=v9 ARCHFLAG/sparcv9 = -m64 -mcpu=v9 @@ -126,12 +206,22 @@ # Compiler warnings are treated as errors WARNINGS_ARE_ERRORS = -Werror +ifeq ($(USE_CLANG), true) + # However we need to clean the code up before we can unrestrictedly enable this option with Clang + WARNINGS_ARE_ERRORS += -Wno-unused-value -Wno-logical-op-parentheses -Wno-parentheses-equality -Wno-parentheses + WARNINGS_ARE_ERRORS += -Wno-switch -Wno-tautological-constant-out-of-range-compare -Wno-tautological-compare + WARNINGS_ARE_ERRORS += -Wno-delete-non-virtual-dtor -Wno-deprecated -Wno-format -Wno-dynamic-class-memaccess + WARNINGS_ARE_ERRORS += -Wno-return-type -Wno-empty-body +endif + WARNING_FLAGS = -Wpointer-arith -Wsign-compare -Wundef -Wunused-function -# Since GCC 4.3, -Wconversion has changed its meanings to warn these implicit -# conversions which might affect the values. Only enable it in earlier versions. -ifeq "$(shell expr \( $(CC_VER_MAJOR) \> 4 \) \| \( \( $(CC_VER_MAJOR) = 4 \) \& \( $(CC_VER_MINOR) \>= 3 \) \))" "0" -WARNING_FLAGS += -Wconversion +ifeq ($(USE_CLANG),) + # Since GCC 4.3, -Wconversion has changed its meanings to warn these implicit + # conversions which might affect the values. Only enable it in earlier versions. + ifeq "$(shell expr \( $(CC_VER_MAJOR) \> 4 \) \| \( \( $(CC_VER_MAJOR) = 4 \) \& \( $(CC_VER_MINOR) \>= 3 \) \))" "0" + WARNING_FLAGS += -Wconversion + endif endif CFLAGS_WARN/DEFAULT = $(WARNINGS_ARE_ERRORS) $(WARNING_FLAGS) @@ -165,19 +255,24 @@ OPT_CFLAGS/NOOPT=-O0 -# 6835796. Problem in GCC 4.3.0 with mulnode.o optimized compilation. -ifneq "$(shell expr \( \( $(CC_VER_MAJOR) = 4 \) \& \( $(CC_VER_MINOR) = 3 \) \))" "0" -OPT_CFLAGS/mulnode.o += -O0 +# Work around some compiler bugs. +ifeq ($(USE_CLANG), true) + ifeq ($(shell expr $(CC_VER_MAJOR) = 4 \& $(CC_VER_MINOR) = 2), 1) + OPT_CFLAGS/loopTransform.o += $(OPT_CFLAGS/NOOPT) + endif +else + # 6835796. Problem in GCC 4.3.0 with mulnode.o optimized compilation. + ifeq ($(shell expr $(CC_VER_MAJOR) = 4 \& $(CC_VER_MINOR) = 3), 1) + OPT_CFLAGS/mulnode.o += $(OPT_CFLAGS/NOOPT) + endif endif # Flags for generating make dependency flags. -ifneq ("${CC_VER_MAJOR}", "2") -DEPFLAGS = -fpch-deps -MMD -MP -MF $(DEP_DIR)/$(@:%=%.d) -endif - -# -DDONT_USE_PRECOMPILED_HEADER will exclude all includes in precompiled.hpp. -ifeq ($(USE_PRECOMPILED_HEADER),0) -CFLAGS += -DDONT_USE_PRECOMPILED_HEADER +DEPFLAGS = -MMD -MP -MF $(DEP_DIR)/$(@:%=%.d) +ifeq ($(USE_CLANG),) + ifneq ("${CC_VER_MAJOR}", "2") + DEPFLAGS += -fpch-deps + endif endif #------------------------------------------------------------------------ @@ -186,24 +281,33 @@ # statically link libstdc++.so, work with gcc but ignored by g++ STATIC_STDCXX = -Wl,-Bstatic -lstdc++ -Wl,-Bdynamic -# statically link libgcc and/or libgcc_s, libgcc does not exist before gcc-3.x. -ifneq ("${CC_VER_MAJOR}", "2") -STATIC_LIBGCC += -static-libgcc -endif +ifeq ($(USE_CLANG),) + # statically link libgcc and/or libgcc_s, libgcc does not exist before gcc-3.x. + ifneq ("${CC_VER_MAJOR}", "2") + STATIC_LIBGCC += -static-libgcc + endif -ifeq ($(BUILDARCH), ia64) -LFLAGS += -Wl,-relax + ifeq ($(BUILDARCH), ia64) + LFLAGS += -Wl,-relax + endif endif # Enable linker optimization LFLAGS += -Xlinker -O1 -# If this is a --hash-style=gnu system, use --hash-style=both -# The gnu .hash section won't work on some Linux systems like SuSE 10. -_HAS_HASH_STYLE_GNU:=$(shell $(CC) -dumpspecs | grep -- '--hash-style=gnu') -ifneq ($(_HAS_HASH_STYLE_GNU),) +ifeq ($(USE_CLANG),) + # If this is a --hash-style=gnu system, use --hash-style=both + # The gnu .hash section won't work on some Linux systems like SuSE 10. + _HAS_HASH_STYLE_GNU:=$(shell $(CC) -dumpspecs | grep -- '--hash-style=gnu') + ifneq ($(_HAS_HASH_STYLE_GNU),) + LDFLAGS_HASH_STYLE = -Wl,--hash-style=both + endif +else + # Don't know how to find out the 'hash style' of a system as '-dumpspecs' + # doesn't work for Clang. So for now we'll alwys use --hash-style=both LDFLAGS_HASH_STYLE = -Wl,--hash-style=both endif + LFLAGS += $(LDFLAGS_HASH_STYLE) # Use $(MAPFLAG:FILENAME=real_file_name) to specify a map file. @@ -221,6 +325,13 @@ #------------------------------------------------------------------------ # Debug flags +ifeq ($(USE_CLANG), true) + # Restrict the debug information created by Clang to avoid + # too big object files and speed the build up a little bit + # (see http://llvm.org/bugs/show_bug.cgi?id=7554) + CFLAGS += -flimit-debug-info +endif + # DEBUG_BINARIES uses full -g debug information for all configs ifeq ($(DEBUG_BINARIES), true) CFLAGS += -g @@ -237,7 +348,12 @@ DEBUG_CFLAGS/ppc = -g DEBUG_CFLAGS += $(DEBUG_CFLAGS/$(BUILDARCH)) ifeq ($(DEBUG_CFLAGS/$(BUILDARCH)),) - DEBUG_CFLAGS += -gstabs + ifeq ($(USE_CLANG), true) + # Clang doesn't understand -gstabs + OPT_CFLAGS += -g + else + OPT_CFLAGS += -gstabs + endif endif ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1) @@ -247,7 +363,12 @@ FASTDEBUG_CFLAGS/ppc = -g FASTDEBUG_CFLAGS += $(DEBUG_CFLAGS/$(BUILDARCH)) ifeq ($(FASTDEBUG_CFLAGS/$(BUILDARCH)),) - FASTDEBUG_CFLAGS += -gstabs + ifeq ($(USE_CLANG), true) + # Clang doesn't understand -gstabs + OPT_CFLAGS += -g + else + OPT_CFLAGS += -gstabs + endif endif OPT_CFLAGS/ia64 = -g @@ -256,7 +377,12 @@ OPT_CFLAGS/ppc = -g OPT_CFLAGS += $(OPT_CFLAGS/$(BUILDARCH)) ifeq ($(OPT_CFLAGS/$(BUILDARCH)),) - OPT_CFLAGS += -gstabs + ifeq ($(USE_CLANG), true) + # Clang doesn't understand -gstabs + OPT_CFLAGS += -g + else + OPT_CFLAGS += -gstabs + endif endif endif endif
--- a/make/linux/makefiles/minimal1.make Thu Jun 20 16:30:44 2013 -0700 +++ b/make/linux/makefiles/minimal1.make Fri Jun 21 15:56:24 2013 -0700 @@ -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. -# +# # TYPE=MINIMAL1 @@ -32,6 +32,7 @@ INCLUDE_MANAGEMENT ?= false INCLUDE_ALL_GCS ?= false INCLUDE_NMT ?= false +INCLUDE_TRACE ?= false INCLUDE_CDS ?= false CXXFLAGS += -DMINIMAL_JVM -DCOMPILER1 -DVMTYPE=\"Minimal\"
--- a/make/linux/makefiles/top.make Thu Jun 20 16:30:44 2013 -0700 +++ b/make/linux/makefiles/top.make Fri Jun 21 15:56:24 2013 -0700 @@ -1,5 +1,5 @@ # -# Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -80,7 +80,7 @@ @echo All done. # This is an explicit dependency for the sake of parallel makes. -vm_build_preliminaries: checks $(Cached_plat) $(AD_Files_If_Required) jvmti_stuff sa_stuff +vm_build_preliminaries: checks $(Cached_plat) $(AD_Files_If_Required) trace_stuff jvmti_stuff sa_stuff @# We need a null action here, so implicit rules don't get consulted. $(Cached_plat): $(Plat_File) @@ -94,6 +94,10 @@ jvmti_stuff: $(Cached_plat) $(adjust-mflags) @$(MAKE) -f jvmti.make $(MFLAGS-adjusted) +# generate trace files +trace_stuff: jvmti_stuff $(Cached_plat) $(adjust-mflags) + @$(MAKE) -f trace.make $(MFLAGS-adjusted) + # generate SA jar files and native header sa_stuff: @$(MAKE) -f sa.make $(MFLAGS-adjusted)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/make/linux/makefiles/trace.make Fri Jun 21 15:56:24 2013 -0700 @@ -0,0 +1,120 @@ +# +# Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# 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. +# +# + +# This makefile (trace.make) is included from the trace.make in the +# build directories. +# +# It knows how to build and run the tools to generate trace files. + +include $(GAMMADIR)/make/linux/makefiles/rules.make +include $(GAMMADIR)/make/altsrc.make + +# ######################################################################### + +HAS_ALT_SRC:=$(shell if [ -d $(HS_ALT_SRC)/share/vm/trace ]; then \ + echo "true"; else echo "false";\ + fi) + +TOPDIR = $(shell echo `pwd`) +GENERATED = $(TOPDIR)/../generated +JvmtiOutDir = $(GENERATED)/jvmtifiles +TraceOutDir = $(GENERATED)/tracefiles + +TraceAltSrcDir = $(HS_ALT_SRC)/share/vm/trace +TraceSrcDir = $(HS_COMMON_SRC)/share/vm/trace + +# set VPATH so make knows where to look for source files +Src_Dirs_V += $(TraceSrcDir) $(TraceAltSrcDir) +VPATH += $(Src_Dirs_V:%=%:) + +TraceGeneratedNames = \ + traceEventClasses.hpp \ + traceEventIds.hpp \ + traceTypes.hpp + +ifeq ($(HAS_ALT_SRC), true) +TraceGeneratedNames += \ + traceRequestables.hpp \ + traceEventControl.hpp + +ifneq ($(INCLUDE_TRACE), false) +TraceGeneratedNames += traceProducer.cpp +endif + +endif + +TraceGeneratedFiles = $(TraceGeneratedNames:%=$(TraceOutDir)/%) + +XSLT = $(REMOTE) $(RUN.JAVA) -classpath $(JvmtiOutDir) jvmtiGen + +XML_DEPS = $(TraceSrcDir)/trace.xml $(TraceSrcDir)/tracetypes.xml \ + $(TraceSrcDir)/trace.dtd $(TraceSrcDir)/xinclude.mod +ifeq ($(HAS_ALT_SRC), true) + XML_DEPS += $(TraceAltSrcDir)/traceevents.xml +endif + +.PHONY: all clean cleanall + +# ######################################################################### + +all: $(TraceGeneratedFiles) + +GENERATE_CODE= \ + $(QUIETLY) echo Generating $@; \ + $(XSLT) -IN $(word 1,$^) -XSL $(word 2,$^) -OUT $@; \ + test -f $@ + +$(TraceOutDir)/traceEventIds.hpp: $(TraceSrcDir)/trace.xml $(TraceSrcDir)/traceEventIds.xsl $(XML_DEPS) + $(GENERATE_CODE) + +$(TraceOutDir)/traceTypes.hpp: $(TraceSrcDir)/trace.xml $(TraceSrcDir)/traceTypes.xsl $(XML_DEPS) + $(GENERATE_CODE) + +ifeq ($(HAS_ALT_SRC), false) + +$(TraceOutDir)/traceEventClasses.hpp: $(TraceSrcDir)/trace.xml $(TraceSrcDir)/traceEventClasses.xsl $(XML_DEPS) + $(GENERATE_CODE) + +else + +$(TraceOutDir)/traceEventClasses.hpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir)/traceEventClasses.xsl $(XML_DEPS) + $(GENERATE_CODE) + +$(TraceOutDir)/traceProducer.cpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir)/traceProducer.xsl $(XML_DEPS) + $(GENERATE_CODE) + +$(TraceOutDir)/traceRequestables.hpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir)/traceRequestables.xsl $(XML_DEPS) + $(GENERATE_CODE) + +$(TraceOutDir)/traceEventControl.hpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir)/traceEventControl.xsl $(XML_DEPS) + $(GENERATE_CODE) + +endif + +# ######################################################################### + +clean cleanall: + rm $(TraceGeneratedFiles) + +
--- a/make/linux/makefiles/vm.make Thu Jun 20 16:30:44 2013 -0700 +++ b/make/linux/makefiles/vm.make Fri Jun 21 15:56:24 2013 -0700 @@ -1,5 +1,5 @@ # -# Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -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. -# +# # # Rules to build JVM and related libraries, included from vm.make in the build @@ -52,7 +52,7 @@ # Src_Dirs_V is everything in src/share/vm/*, plus the right os/*/vm and cpu/*/vm # The adfiles directory contains ad_<arch>.[ch]pp. # The jvmtifiles directory contains jvmti*.[ch]pp -Src_Dirs_V += $(GENERATED)/adfiles $(GENERATED)/jvmtifiles +Src_Dirs_V += $(GENERATED)/adfiles $(GENERATED)/jvmtifiles $(GENERATED)/tracefiles VPATH += $(Src_Dirs_V:%=%:) # set INCLUDES for C preprocessor. @@ -72,7 +72,7 @@ endif endif -# HOTSPOT_RELEASE_VERSION and HOTSPOT_BUILD_VERSION are defined +# HOTSPOT_RELEASE_VERSION and HOTSPOT_BUILD_VERSION are defined # in $(GAMMADIR)/make/defs.make ifeq ($(HOTSPOT_BUILD_VERSION),) BUILD_VERSION = -DHOTSPOT_RELEASE_VERSION="\"$(HOTSPOT_RELEASE_VERSION)\"" @@ -99,7 +99,7 @@ # This is VERY important! The version define must only be supplied to vm_version.o # If not, ccache will not re-use the cache at all, since the version string might contain -# a time and date. +# a time and date. CXXFLAGS/vm_version.o += ${JRE_VERSION} CXXFLAGS/BYFILE = $(CXXFLAGS/$@) @@ -108,12 +108,6 @@ CXXFLAGS += $(CXXFLAGS/BYFILE) -ifndef JAVASE_EMBEDDED -ifneq (${ARCH},arm) -CFLAGS += -DINCLUDE_TRACE -endif -endif - # CFLAGS_WARN holds compiler options to suppress/enable warnings. CFLAGS += $(CFLAGS_WARN/BYFILE) @@ -158,16 +152,14 @@ SOURCE_PATHS+=$(HS_COMMON_SRC)/cpu/$(Platform_arch)/vm SOURCE_PATHS+=$(HS_COMMON_SRC)/os_cpu/$(Platform_os_arch)/vm -ifndef JAVASE_EMBEDDED -ifneq (${ARCH},arm) -SOURCE_PATHS+=$(shell if [ -d $(HS_ALT_SRC)/share/vm/jfr ]; then \ +CORE_PATHS=$(foreach path,$(SOURCE_PATHS),$(call altsrc,$(path)) $(path)) +CORE_PATHS+=$(GENERATED)/jvmtifiles $(GENERATED)/tracefiles + +ifneq ($(INCLUDE_TRACE), false) +CORE_PATHS+=$(shell if [ -d $(HS_ALT_SRC)/share/vm/jfr ]; then \ find $(HS_ALT_SRC)/share/vm/jfr -type d; \ fi) endif -endif - -CORE_PATHS=$(foreach path,$(SOURCE_PATHS),$(call altsrc,$(path)) $(path)) -CORE_PATHS+=$(GENERATED)/jvmtifiles COMPILER1_PATHS := $(call altsrc,$(HS_COMMON_SRC)/share/vm/c1) COMPILER1_PATHS += $(HS_COMMON_SRC)/share/vm/c1 @@ -316,7 +308,7 @@ # With more recent Redhat releases (or the cutting edge version Fedora), if # SELinux is configured to be enabled, the runtime linker will fail to apply # the text relocation to libjvm.so considering that it is built as a non-PIC -# DSO. To workaround that, we run chcon to libjvm.so after it is built. See +# DSO. To workaround that, we run chcon to libjvm.so after it is built. See # details in bug 6538311. $(LIBJVM): $(LIBJVM.o) $(LIBJVM_MAPFILE) $(LD_SCRIPT) $(QUIETLY) { \
--- a/make/solaris/makefiles/buildtree.make Thu Jun 20 16:30:44 2013 -0700 +++ b/make/solaris/makefiles/buildtree.make Fri Jun 21 15:56:24 2013 -0700 @@ -47,6 +47,7 @@ # flags.make - with macro settings # vm.make - to support making "$(MAKE) -v vm.make" in makefiles # adlc.make - +# trace.make - generate tracing event and type definitions # jvmti.make - generate JVMTI bindings from the spec (JSR-163) # sa.make - generate SA jar file and natives # @@ -107,7 +108,8 @@ SIMPLE_DIRS = \ $(PLATFORM_DIR)/generated/dependencies \ $(PLATFORM_DIR)/generated/adfiles \ - $(PLATFORM_DIR)/generated/jvmtifiles + $(PLATFORM_DIR)/generated/jvmtifiles \ + $(PLATFORM_DIR)/generated/tracefiles TARGETS = debug fastdebug optimized product SUBMAKE_DIRS = $(addprefix $(PLATFORM_DIR)/,$(TARGETS)) @@ -115,7 +117,7 @@ # For dependencies and recursive makes. BUILDTREE_MAKE = $(GAMMADIR)/make/$(OS_FAMILY)/makefiles/buildtree.make -BUILDTREE_TARGETS = Makefile flags.make flags_vm.make vm.make adlc.make jvmti.make sa.make +BUILDTREE_TARGETS = Makefile flags.make flags_vm.make vm.make adlc.make jvmti.make trace.make sa.make BUILDTREE_VARS = GAMMADIR=$(GAMMADIR) OS_FAMILY=$(OS_FAMILY) \ ARCH=$(ARCH) BUILDARCH=$(BUILDARCH) LIBARCH=$(LIBARCH) VARIANT=$(VARIANT) @@ -327,6 +329,16 @@ echo "include \$$(GAMMADIR)/make/$(OS_FAMILY)/makefiles/$(@F)"; \ ) > $@ +trace.make: $(BUILDTREE_MAKE) + @echo Creating $@ ... + $(QUIETLY) ( \ + $(BUILDTREE_COMMENT); \ + echo; \ + echo include flags.make; \ + echo; \ + echo "include \$$(GAMMADIR)/make/$(OS_FAMILY)/makefiles/$(@F)"; \ + ) > $@ + sa.make: $(BUILDTREE_MAKE) @echo Creating $@ ... $(QUIETLY) ( \
--- a/make/solaris/makefiles/top.make Thu Jun 20 16:30:44 2013 -0700 +++ b/make/solaris/makefiles/top.make Fri Jun 21 15:56:24 2013 -0700 @@ -1,5 +1,5 @@ # -# Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -73,7 +73,7 @@ @echo All done. # This is an explicit dependency for the sake of parallel makes. -vm_build_preliminaries: checks $(Cached_plat) $(AD_Files_If_Required) jvmti_stuff sa_stuff +vm_build_preliminaries: checks $(Cached_plat) $(AD_Files_If_Required) jvmti_stuff trace_stuff sa_stuff @# We need a null action here, so implicit rules don't get consulted. $(Cached_plat): $(Plat_File) @@ -87,6 +87,10 @@ jvmti_stuff: $(Cached_plat) $(adjust-mflags) @$(MAKE) -f jvmti.make $(MFLAGS-adjusted) +# generate trace files +trace_stuff: jvmti_stuff $(Cached_plat) $(adjust-mflags) + @$(MAKE) -f trace.make $(MFLAGS-adjusted) + # generate SA jar files and native header sa_stuff: @$(MAKE) -f sa.make $(MFLAGS-adjusted) @@ -127,5 +131,5 @@ rm -fr $(GENERATED) .PHONY: default vm_build_preliminaries -.PHONY: lists ad_stuff jvmti_stuff sa_stuff the_vm clean realclean +.PHONY: lists ad_stuff jvmti_stuff trace_stuff sa_stuff the_vm clean realclean .PHONY: checks check_os_version install
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/make/solaris/makefiles/trace.make Fri Jun 21 15:56:24 2013 -0700 @@ -0,0 +1,116 @@ +# +# Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# 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. +# +# + +# This makefile (trace.make) is included from the trace.make in the +# build directories. +# +# It knows how to build and run the tools to generate trace files. + +include $(GAMMADIR)/make/solaris/makefiles/rules.make +include $(GAMMADIR)/make/altsrc.make + +# ######################################################################### + +HAS_ALT_SRC:=$(shell if [ -d $(HS_ALT_SRC)/share/vm/trace ]; then \ + echo "true"; else echo "false";\ + fi) + +TOPDIR = $(shell echo `pwd`) +GENERATED = $(TOPDIR)/../generated +JvmtiOutDir = $(GENERATED)/jvmtifiles +TraceOutDir = $(GENERATED)/tracefiles + +TraceAltSrcDir = $(HS_ALT_SRC)/share/vm/trace +TraceSrcDir = $(HS_COMMON_SRC)/share/vm/trace + +# set VPATH so make knows where to look for source files +Src_Dirs_V += $(TraceSrcDir) $(TraceAltSrcDir) +VPATH += $(Src_Dirs_V:%=%:) + +TraceGeneratedNames = \ + traceEventClasses.hpp \ + traceEventIds.hpp \ + traceTypes.hpp + +ifeq ($(HAS_ALT_SRC), true) +TraceGeneratedNames += \ + traceRequestables.hpp \ + traceEventControl.hpp \ + traceProducer.cpp +endif + +TraceGeneratedFiles = $(TraceGeneratedNames:%=$(TraceOutDir)/%) + +XSLT = $(REMOTE) $(RUN.JAVA) -classpath $(JvmtiOutDir) jvmtiGen + +XML_DEPS = $(TraceSrcDir)/trace.xml $(TraceSrcDir)/tracetypes.xml \ + $(TraceSrcDir)/trace.dtd $(TraceSrcDir)/xinclude.mod +ifeq ($(HAS_ALT_SRC), true) + XML_DEPS += $(TraceAltSrcDir)/traceevents.xml +endif + +.PHONY: all clean cleanall + +# ######################################################################### + +all: $(TraceGeneratedFiles) + +GENERATE_CODE= \ + $(QUIETLY) echo Generating $@; \ + $(XSLT) -IN $(word 1,$^) -XSL $(word 2,$^) -OUT $@; \ + test -f $@ + +$(TraceOutDir)/traceEventIds.hpp: $(TraceSrcDir)/trace.xml $(TraceSrcDir)/traceEventIds.xsl $(XML_DEPS) + $(GENERATE_CODE) + +$(TraceOutDir)/traceTypes.hpp: $(TraceSrcDir)/trace.xml $(TraceSrcDir)/traceTypes.xsl $(XML_DEPS) + $(GENERATE_CODE) + +ifeq ($(HAS_ALT_SRC), false) + +$(TraceOutDir)/traceEventClasses.hpp: $(TraceSrcDir)/trace.xml $(TraceSrcDir)/traceEventClasses.xsl $(XML_DEPS) + $(GENERATE_CODE) + +else + +$(TraceOutDir)/traceEventClasses.hpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir)/traceEventClasses.xsl $(XML_DEPS) + $(GENERATE_CODE) + +$(TraceOutDir)/traceProducer.cpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir)/traceProducer.xsl $(XML_DEPS) + $(GENERATE_CODE) + +$(TraceOutDir)/traceRequestables.hpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir)/traceRequestables.xsl $(XML_DEPS) + $(GENERATE_CODE) + +$(TraceOutDir)/traceEventControl.hpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir)/traceEventControl.xsl $(XML_DEPS) + $(GENERATE_CODE) + +endif + +# ######################################################################### + +clean cleanall: + rm $(TraceGeneratedFiles) + +
--- a/make/solaris/makefiles/vm.make Thu Jun 20 16:30:44 2013 -0700 +++ b/make/solaris/makefiles/vm.make Fri Jun 21 15:56:24 2013 -0700 @@ -1,5 +1,5 @@ # -# Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -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. -# +# # # Rules to build JVM and related libraries, included from vm.make in the build @@ -48,7 +48,7 @@ # Src_Dirs_V is everything in src/share/vm/*, plus the right os/*/vm and cpu/*/vm # The adfiles directory contains ad_<arch>.[ch]pp. # The jvmtifiles directory contains jvmti*.[ch]pp -Src_Dirs_V += $(GENERATED)/adfiles $(GENERATED)/jvmtifiles +Src_Dirs_V += $(GENERATED)/adfiles $(GENERATED)/jvmtifiles $(GENERATED)/tracefiles VPATH += $(Src_Dirs_V:%=%:) # set INCLUDES for C preprocessor @@ -87,7 +87,7 @@ # This is VERY important! The version define must only be supplied to vm_version.o # If not, ccache will not re-use the cache at all, since the version string might contain -# a time and date. +# a time and date. CXXFLAGS/vm_version.o += ${JRE_VERSION} CXXFLAGS/BYFILE = $(CXXFLAGS/$@) @@ -103,7 +103,7 @@ CFLAGS += $(CFLAGS/NOEX) # Extra flags from gnumake's invocation or environment -CFLAGS += $(EXTRA_CFLAGS) -DINCLUDE_TRACE +CFLAGS += $(EXTRA_CFLAGS) # Math Library (libm.so), do not use -lm. # There might be two versions of libm.so on the build system: @@ -137,9 +137,7 @@ LIBS += -lsocket -lsched -ldl $(LIBM) -lthread -lc -ldemangle endif # sparcWorks -ifeq ("${Platform_arch}", "sparc") LIBS += -lkstat -endif # By default, link the *.o into the library, not the executable. LINK_INTO$(LINK_INTO) = LIBJVM @@ -177,12 +175,14 @@ 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 \ +CORE_PATHS=$(foreach path,$(SOURCE_PATHS),$(call altsrc,$(path)) $(path)) +CORE_PATHS+=$(GENERATED)/jvmtifiles $(GENERATED)/tracefiles + +ifneq ($(INCLUDE_TRACE), false) +CORE_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 +endif COMPILER1_PATHS := $(call altsrc,$(HS_COMMON_SRC)/share/vm/c1) COMPILER1_PATHS += $(HS_COMMON_SRC)/share/vm/c1 @@ -287,7 +287,7 @@ LINK_VM = $(LINK_LIB.CXX) endif # making the library: -$(LIBJVM): $(ADD_GNU_DEBUGLINK) $(FIX_EMPTY_SEC_HDR_FLAGS) $(LIBJVM.o) $(LIBJVM_MAPFILE) +$(LIBJVM): $(ADD_GNU_DEBUGLINK) $(FIX_EMPTY_SEC_HDR_FLAGS) $(LIBJVM.o) $(LIBJVM_MAPFILE) ifeq ($(filter -sbfast -xsbfast, $(CFLAGS_BROWSE)),) @echo Linking vm... $(QUIETLY) $(LINK_LIB.CXX/PRE_HOOK)
--- a/make/windows/build.make Thu Jun 20 16:30:44 2013 -0700 +++ b/make/windows/build.make Fri Jun 21 15:56:24 2013 -0700 @@ -196,6 +196,12 @@ # End VERSIONINFO parameters +# if hotspot-only build and/or OPENJDK isn't passed down, need to set OPENJDK +!ifndef OPENJDK +!if !exists($(WorkSpace)\src\closed) +OPENJDK=true +!endif +!endif # We don't support SA on ia64, and we can't # build it if we are using a version of Vis Studio @@ -273,6 +279,7 @@ @ echo HS_COMPANY=$(COMPANY_NAME) >> $@ @ echo HS_FILEDESC=$(HS_FILEDESC) >> $@ @ echo HOTSPOT_VM_DISTRO=$(HOTSPOT_VM_DISTRO) >> $@ + @ if "$(OPENJDK)" NEQ "" echo OPENJDK=$(OPENJDK) >> $@ @ echo HS_COPYRIGHT=$(HOTSPOT_VM_COPYRIGHT) >> $@ @ echo HS_NAME=$(PRODUCT_NAME) $(JDK_MKTG_VERSION) >> $@ @ echo HS_BUILD_VER=$(HS_BUILD_VER) >> $@
--- a/make/windows/create_obj_files.sh Thu Jun 20 16:30:44 2013 -0700 +++ b/make/windows/create_obj_files.sh Fri Jun 21 15:56:24 2013 -0700 @@ -71,13 +71,11 @@ BASE_PATHS="${BASE_PATHS} ${COMMONSRC}/${sd}" done -BASE_PATHS="${BASE_PATHS} ${GENERATED}/jvmtifiles" +BASE_PATHS="${BASE_PATHS} ${GENERATED}/jvmtifiles ${GENERATED}/tracefiles" 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" + BASE_PATHS="${BASE_PATHS} ${ALTSRC}/share/vm/jfr" + BASE_PATHS="${BASE_PATHS} ${ALTSRC}/share/vm/jfr/buffers" fi BASE_PATHS="${BASE_PATHS} ${COMMONSRC}/share/vm/prims/wbtestmethods"
--- a/make/windows/makefiles/generated.make Thu Jun 20 16:30:44 2013 -0700 +++ b/make/windows/makefiles/generated.make Fri Jun 21 15:56:24 2013 -0700 @@ -1,5 +1,5 @@ # -# Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -30,15 +30,19 @@ JvmtiOutDir=jvmtifiles !include $(WorkSpace)/make/windows/makefiles/jvmti.make +# Pick up rules for building trace +TraceOutDir=tracefiles +!include $(WorkSpace)/make/windows/makefiles/trace.make + # Pick up rules for building SA !include $(WorkSpace)/make/windows/makefiles/sa.make AdlcOutDir=adfiles !if ("$(Variant)" == "compiler2") || ("$(Variant)" == "tiered") -default:: $(AdlcOutDir)/ad_$(Platform_arch_model).cpp $(AdlcOutDir)/dfa_$(Platform_arch_model).cpp $(JvmtiGeneratedFiles) buildobjfiles +default:: $(AdlcOutDir)/ad_$(Platform_arch_model).cpp $(AdlcOutDir)/dfa_$(Platform_arch_model).cpp $(JvmtiGeneratedFiles) $(TraceGeneratedFiles) buildobjfiles !else -default:: $(JvmtiGeneratedFiles) buildobjfiles +default:: $(JvmtiGeneratedFiles) $(TraceGeneratedFiles) buildobjfiles !endif buildobjfiles:
--- a/make/windows/makefiles/projectcreator.make Thu Jun 20 16:30:44 2013 -0700 +++ b/make/windows/makefiles/projectcreator.make Fri Jun 21 15:56:24 2013 -0700 @@ -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. -# +# # !include $(WorkSpace)/make/windows/makefiles/rules.make @@ -72,7 +72,7 @@ -ignorePath ppc \ -ignorePath zero \ -hidePath .hg - + # This is referenced externally by both the IDE and batch builds ProjectCreatorOptions= @@ -89,7 +89,7 @@ -disablePch bytecodeInterpreter.cpp \ -disablePch bytecodeInterpreterWithChecks.cpp \ -disablePch getThread_windows_$(Platform_arch).cpp \ - -disablePch_compiler2 opcodes.cpp + -disablePch_compiler2 opcodes.cpp # Common options for the IDE builds for core, c1, and c2 ProjectCreatorIDEOptions=\ @@ -115,7 +115,7 @@ -define TARGET_OS_ARCH_windows_x86 \ -define TARGET_OS_FAMILY_windows \ -define TARGET_COMPILER_visCPP \ - -define INCLUDE_TRACE \ + -define INCLUDE_TRACE=1 \ $(ProjectCreatorIncludesPRIVATE) # Add in build-specific options @@ -203,4 +203,12 @@ -additionalFile jvmtiEnter.cpp \ -additionalFile jvmtiEnterTrace.cpp \ -additionalFile jvmti.h \ - -additionalFile bytecodeInterpreterWithChecks.cpp + -additionalFile bytecodeInterpreterWithChecks.cpp \ + -additionalFile traceEventClasses.hpp \ + -additionalFile traceEventIds.hpp \ +!if "$(OPENJDK)" != "true" + -additionalFile traceRequestables.hpp \ + -additionalFile traceEventControl.hpp \ + -additionalFile traceProducer.cpp \ +!endif + -additionalFile traceTypes.hpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/make/windows/makefiles/trace.make Fri Jun 21 15:56:24 2013 -0700 @@ -0,0 +1,121 @@ +# +# Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# 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. +# +# + +# This makefile (trace.make) is included from the trace.make in the +# build directories. +# +# It knows how to build and run the tools to generate trace files. + +!include $(WorkSpace)/make/windows/makefiles/rules.make + +# ######################################################################### + + +TraceAltSrcDir = $(WorkSpace)/src/closed/share/vm/trace +TraceSrcDir = $(WorkSpace)/src/share/vm/trace + +TraceGeneratedNames = \ + traceEventClasses.hpp \ + traceEventIds.hpp \ + traceTypes.hpp + + +!if "$(OPENJDK)" != "true" +TraceGeneratedNames = $(TraceGeneratedNames) \ + traceRequestables.hpp \ + traceEventControl.hpp \ + traceProducer.cpp +!endif + + +#Note: TraceGeneratedFiles must be kept in sync with TraceGeneratedNames by hand. +#Should be equivalent to "TraceGeneratedFiles = $(TraceGeneratedNames:%=$(TraceOutDir)/%)" +TraceGeneratedFiles = \ + $(TraceOutDir)/traceEventClasses.hpp \ + $(TraceOutDir)/traceEventIds.hpp \ + $(TraceOutDir)/traceTypes.hpp + +!if "$(OPENJDK)" != "true" +TraceGeneratedFiles = $(TraceGeneratedFiles) \ + $(TraceOutDir)/traceRequestables.hpp \ + $(TraceOutDir)/traceEventControl.hpp \ + $(TraceOutDir)/traceProducer.cpp +!endif + +XSLT = $(QUIETLY) $(REMOTE) $(RUN_JAVA) -classpath $(JvmtiOutDir) jvmtiGen + +XML_DEPS = $(TraceSrcDir)/trace.xml $(TraceSrcDir)/tracetypes.xml \ + $(TraceSrcDir)/trace.dtd $(TraceSrcDir)/xinclude.mod + +!if "$(OPENJDK)" != "true" +XML_DEPS = $(XML_DEPS) $(TraceAltSrcDir)/traceevents.xml +!endif + +.PHONY: all clean cleanall + +# ######################################################################### + +default:: + @if not exist $(TraceOutDir) mkdir $(TraceOutDir) + +$(TraceOutDir)/traceEventIds.hpp: $(TraceSrcDir)/trace.xml $(TraceSrcDir)/traceEventIds.xsl $(XML_DEPS) + @echo Generating $@ + @$(XSLT) -IN $(TraceSrcDir)/trace.xml -XSL $(TraceSrcDir)/traceEventIds.xsl -OUT $(TraceOutDir)/traceEventIds.hpp + +$(TraceOutDir)/traceTypes.hpp: $(TraceSrcDir)/trace.xml $(TraceSrcDir)/traceTypes.xsl $(XML_DEPS) + @echo Generating $@ + @$(XSLT) -IN $(TraceSrcDir)/trace.xml -XSL $(TraceSrcDir)/traceTypes.xsl -OUT $(TraceOutDir)/traceTypes.hpp + +!if "$(OPENJDK)" == "true" + +$(TraceOutDir)/traceEventClasses.hpp: $(TraceSrcDir)/trace.xml $(TraceSrcDir)/traceEventClasses.xsl $(XML_DEPS) + @echo Generating $@ + @$(XSLT) -IN $(TraceSrcDir)/trace.xml -XSL $(TraceSrcDir)/traceEventClasses.xsl -OUT $(TraceOutDir)/traceEventClasses.hpp + +!else + +$(TraceOutDir)/traceEventClasses.hpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir)/traceEventClasses.xsl $(XML_DEPS) + @echo Generating $@ + @$(XSLT) -IN $(TraceSrcDir)/trace.xml -XSL $(TraceAltSrcDir)/traceEventClasses.xsl -OUT $(TraceOutDir)/traceEventClasses.hpp + +$(TraceOutDir)/traceProducer.cpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir)/traceProducer.xsl $(XML_DEPS) + @echo Generating $@ + @$(XSLT) -IN $(TraceSrcDir)/trace.xml -XSL $(TraceAltSrcDir)/traceProducer.xsl -OUT $(TraceOutDir)/traceProducer.cpp + +$(TraceOutDir)/traceRequestables.hpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir)/traceRequestables.xsl $(XML_DEPS) + @echo Generating $@ + @$(XSLT) -IN $(TraceSrcDir)/trace.xml -XSL $(TraceAltSrcDir)/traceRequestables.xsl -OUT $(TraceOutDir)/traceRequestables.hpp + +$(TraceOutDir)/traceEventControl.hpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir)/traceEventControl.xsl $(XML_DEPS) + @echo Generating $@ + @$(XSLT) -IN $(TraceSrcDir)/trace.xml -XSL $(TraceAltSrcDir)/traceEventControl.xsl -OUT $(TraceOutDir)/traceEventControl.hpp + +!endif + +# ######################################################################### + +cleanall : + rm $(TraceGeneratedFiles) + +
--- a/make/windows/makefiles/vm.make Thu Jun 20 16:30:44 2013 -0700 +++ b/make/windows/makefiles/vm.make Fri Jun 21 15:56:24 2013 -0700 @@ -66,10 +66,6 @@ CXX_FLAGS=$(CXX_FLAGS) /D "HOTSPOT_BUILD_USER=\"$(BuildUser)\"" CXX_FLAGS=$(CXX_FLAGS) /D "HOTSPOT_VM_DISTRO=\"$(HOTSPOT_VM_DISTRO)\"" -!ifndef JAVASE_EMBEDDED -CXX_FLAGS=$(CXX_FLAGS) /D "INCLUDE_TRACE" -!endif - CXX_FLAGS=$(CXX_FLAGS) $(CXX_INCLUDE_DIRS) # Define that so jni.h is on correct side @@ -144,6 +140,7 @@ VM_PATH=../generated VM_PATH=$(VM_PATH);../generated/adfiles VM_PATH=$(VM_PATH);../generated/jvmtifiles +VM_PATH=$(VM_PATH);../generated/tracefiles VM_PATH=$(VM_PATH);$(WorkSpace)/src/share/vm/c1 VM_PATH=$(VM_PATH);$(WorkSpace)/src/share/vm/compiler VM_PATH=$(VM_PATH);$(WorkSpace)/src/share/vm/code @@ -172,10 +169,8 @@ 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 +VM_PATH=$(VM_PATH);$(ALTSRC)/share/vm/jfr/buffers !endif VM_PATH={$(VM_PATH)} @@ -384,16 +379,13 @@ {..\generated\jvmtifiles}.cpp.obj:: $(CXX) $(CXX_FLAGS) $(CXX_USE_PCH) /c $< +{..\generated\tracefiles}.cpp.obj:: + $(CXX) $(CXX_FLAGS) $(CXX_USE_PCH) /c $< + {$(ALTSRC)\share\vm\jfr}.cpp.obj:: $(CXX) $(CXX_FLAGS) $(CXX_USE_PCH) /c $< -{$(ALTSRC)\share\vm\jfr\agent}.cpp.obj:: - $(CXX) $(CXX_FLAGS) $(CXX_USE_PCH) /c $< - -{$(ALTSRC)\share\vm\jfr\agent\isolated_deps\util}.cpp.obj:: - $(CXX) $(CXX_FLAGS) $(CXX_USE_PCH) /c $< - -{$(ALTSRC)\share\vm\jfr\jvm}.cpp.obj:: +{$(ALTSRC)\share\vm\jfr\buffers}.cpp.obj:: $(CXX) $(CXX_FLAGS) $(CXX_USE_PCH) /c $< default::
--- a/make/windows/projectfiles/common/Makefile Thu Jun 20 16:30:44 2013 -0700 +++ b/make/windows/projectfiles/common/Makefile Fri Jun 21 15:56:24 2013 -0700 @@ -1,5 +1,5 @@ # -# Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -45,6 +45,12 @@ !endif !endif +# if hotspot-only build and/or OPENJDK isn't passed down, need to set OPENJDK +!ifndef OPENJDK +!if !exists($(WorkSpace)\src\closed) +OPENJDK=true +!endif +!endif !include $(HOTSPOTWORKSPACE)/make/windows/makefiles/projectcreator.make @@ -54,6 +60,10 @@ JvmtiOutDir=$(HOTSPOTBUILDSPACE)\$(Variant)\generated\jvmtifiles !include $(HOTSPOTWORKSPACE)/make/windows/makefiles/jvmti.make +# Pick up rules for building trace +TraceOutDir=$(HOTSPOTBUILDSPACE)\$(Variant)\generated\tracefiles +!include $(HOTSPOTWORKSPACE)/make/windows/makefiles/trace.make + !if "$(Variant)" == "compiler2" # Pick up rules for building adlc !include $(HOTSPOTWORKSPACE)/make/windows/makefiles/adlc.make @@ -66,7 +76,7 @@ HS_INTERNAL_NAME=jvm -default:: $(AdditionalTargets) $(JvmtiGeneratedFiles) +default:: $(AdditionalTargets) $(JvmtiGeneratedFiles) $(TraceGeneratedFiles) !include $(HOTSPOTWORKSPACE)/make/hotspot_version
--- a/src/cpu/sparc/vm/cppInterpreter_sparc.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/cpu/sparc/vm/cppInterpreter_sparc.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -1065,7 +1065,7 @@ const int slop_factor = 2*wordSize; const int fixed_size = ((sizeof(BytecodeInterpreter) + slop_factor) >> LogBytesPerWord) + // what is the slop factor? - //6815692//Method::extra_stack_words() + // extra push slots for MH adapters + Method::extra_stack_entries() + // extra stack for jsr 292 frame::memory_parameter_word_sp_offset + // register save area + param window (native ? frame::interpreter_frame_extra_outgoing_argument_words : 0); // JNI, class @@ -1221,9 +1221,7 @@ // Full size expression stack __ ld_ptr(constMethod, O3); __ lduh(O3, in_bytes(ConstMethod::max_stack_offset()), O3); - guarantee(!EnableInvokeDynamic, "no support yet for java.lang.invoke.MethodHandle"); //6815692 - //6815692//if (EnableInvokeDynamic) - //6815692// __ inc(O3, Method::extra_stack_entries()); + __ inc(O3, Method::extra_stack_entries()); __ sll(O3, LogBytesPerWord, O3); __ sub(O2, O3, O3); // __ sub(O3, wordSize, O3); // so prepush doesn't look out of bounds @@ -2084,9 +2082,7 @@ const int fixed_size = sizeof(BytecodeInterpreter)/wordSize + // interpreter state object frame::memory_parameter_word_sp_offset; // register save area + param window - const int extra_stack = 0; //6815692//Method::extra_stack_entries(); return (round_to(max_stack + - extra_stack + slop_factor + fixed_size + monitor_size + @@ -2173,8 +2169,7 @@ // Need +1 here because stack_base points to the word just above the first expr stack entry // and stack_limit is supposed to point to the word just below the last expr stack entry. // See generate_compute_interpreter_state. - int extra_stack = 0; //6815692//Method::extra_stack_entries(); - to_fill->_stack_limit = stack_base - (method->max_stack() + 1 + extra_stack); + to_fill->_stack_limit = stack_base - (method->max_stack() + 1); to_fill->_monitor_base = (BasicObjectLock*) monitor_base; // sparc specific
--- a/src/cpu/sparc/vm/frame_sparc.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/cpu/sparc/vm/frame_sparc.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -252,6 +252,16 @@ return false; } + // Could be a zombie method + if (sender_blob->is_zombie() || sender_blob->is_unloaded()) { + return false; + } + + // Could be a zombie method + if (sender_blob->is_zombie() || sender_blob->is_unloaded()) { + return false; + } + // It should be safe to construct the sender though it might not be valid frame sender(_SENDER_SP, younger_sp, adjusted_stack); @@ -294,10 +304,10 @@ return jcw_safe; } - // If the frame size is 0 something is bad because every nmethod has a non-zero frame size + // If the frame size is 0 something (or less) is bad because every nmethod has a non-zero frame size // because you must allocate window space - if (sender_blob->frame_size() == 0) { + if (sender_blob->frame_size() <= 0) { assert(!sender_blob->is_nmethod(), "should count return address at least"); return false; }
--- a/src/cpu/sparc/vm/interp_masm_sparc.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/cpu/sparc/vm/interp_masm_sparc.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -521,7 +521,7 @@ // Compute max expression stack+register save area ld_ptr(Lmethod, in_bytes(Method::const_offset()), Gframe_size); lduh(Gframe_size, in_bytes(ConstMethod::max_stack_offset()), Gframe_size); // Load max stack. - add( Gframe_size, frame::memory_parameter_word_sp_offset, Gframe_size ); + add(Gframe_size, frame::memory_parameter_word_sp_offset+Method::extra_stack_entries(), Gframe_size ); // // now set up a stack frame with the size computed above
--- a/src/cpu/sparc/vm/templateInterpreter_sparc.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/cpu/sparc/vm/templateInterpreter_sparc.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -507,7 +507,7 @@ const int extra_space = rounded_vm_local_words + // frame local scratch space - //6815692//Method::extra_stack_words() + // extra push slots for MH adapters + Method::extra_stack_entries() + // extra stack for jsr 292 frame::memory_parameter_word_sp_offset + // register save area (native_call ? frame::interpreter_frame_extra_outgoing_argument_words : 0); @@ -1558,7 +1558,6 @@ round_to(callee_extra_locals * Interpreter::stackElementWords, WordsPerLong); const int max_stack_words = max_stack * Interpreter::stackElementWords; return (round_to((max_stack_words - //6815692//+ Method::extra_stack_words() + rounded_vm_local_words + frame::memory_parameter_word_sp_offset), WordsPerLong) // already rounded
--- a/src/cpu/x86/vm/cppInterpreter_x86.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/cpu/x86/vm/cppInterpreter_x86.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -539,12 +539,11 @@ // compute full expression stack limit - const int extra_stack = 0; //6815692//Method::extra_stack_words(); __ movptr(rdx, Address(rbx, Method::const_offset())); __ load_unsigned_short(rdx, Address(rdx, ConstMethod::max_stack_offset())); // get size of expression stack in words __ negptr(rdx); // so we can subtract in next step // Allocate expression stack - __ lea(rsp, Address(rsp, rdx, Address::times_ptr, -extra_stack)); + __ lea(rsp, Address(rsp, rdx, Address::times_ptr, -Method::extra_stack_words())); __ movptr(STATE(_stack_limit), rsp); } @@ -692,10 +691,9 @@ // Always give one monitor to allow us to start interp if sync method. // Any additional monitors need a check when moving the expression stack const int one_monitor = frame::interpreter_frame_monitor_size() * wordSize; - const int extra_stack = 0; //6815692//Method::extra_stack_entries(); __ movptr(rax, Address(rbx, Method::const_offset())); __ load_unsigned_short(rax, Address(rax, ConstMethod::max_stack_offset())); // get size of expression stack in words - __ lea(rax, Address(noreg, rax, Interpreter::stackElementScale(), extra_stack + one_monitor)); + __ lea(rax, Address(noreg, rax, Interpreter::stackElementScale(), one_monitor+Method::extra_stack_words())); __ lea(rax, Address(rax, rdx, Interpreter::stackElementScale(), overhead_size)); #ifdef ASSERT @@ -2265,8 +2263,7 @@ const int overhead_size = sizeof(BytecodeInterpreter)/wordSize + ( frame::sender_sp_offset - frame::link_offset) + 2; - const int extra_stack = 0; //6815692//Method::extra_stack_entries(); - const int method_stack = (method->max_locals() + method->max_stack() + extra_stack) * + const int method_stack = (method->max_locals() + method->max_stack()) * Interpreter::stackElementWords; return overhead_size + method_stack + stub_code; } @@ -2331,8 +2328,7 @@ // Need +1 here because stack_base points to the word just above the first expr stack entry // and stack_limit is supposed to point to the word just below the last expr stack entry. // See generate_compute_interpreter_state. - int extra_stack = 0; //6815692//Method::extra_stack_entries(); - to_fill->_stack_limit = stack_base - (method->max_stack() + extra_stack + 1); + to_fill->_stack_limit = stack_base - (method->max_stack() + 1); to_fill->_monitor_base = (BasicObjectLock*) monitor_base; to_fill->_self_link = to_fill; @@ -2380,8 +2376,7 @@ monitor_size); // Now with full size expression stack - int extra_stack = 0; //6815692//Method::extra_stack_entries(); - int full_frame_size = short_frame_size + (method->max_stack() + extra_stack) * BytesPerWord; + int full_frame_size = short_frame_size + method->max_stack() * BytesPerWord; // and now with only live portion of the expression stack short_frame_size = short_frame_size + tempcount * BytesPerWord;
--- a/src/cpu/x86/vm/frame_x86.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/cpu/x86/vm/frame_x86.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,6 +33,7 @@ #include "runtime/handles.inline.hpp" #include "runtime/javaCalls.hpp" #include "runtime/monitorChunk.hpp" +#include "runtime/os.hpp" #include "runtime/signature.hpp" #include "runtime/stubCodeGenerator.hpp" #include "runtime/stubRoutines.hpp" @@ -54,16 +55,22 @@ address sp = (address)_sp; address fp = (address)_fp; address unextended_sp = (address)_unextended_sp; - // sp must be within the stack - bool sp_safe = (sp <= thread->stack_base()) && - (sp >= thread->stack_base() - thread->stack_size()); + + // consider stack guards when trying to determine "safe" stack pointers + static size_t stack_guard_size = os::uses_stack_guard_pages() ? (StackYellowPages + StackRedPages) * os::vm_page_size() : 0; + size_t usable_stack_size = thread->stack_size() - stack_guard_size; + + // sp must be within the usable part of the stack (not in guards) + bool sp_safe = (sp < thread->stack_base()) && + (sp >= thread->stack_base() - usable_stack_size); + if (!sp_safe) { return false; } // unextended sp must be within the stack and above or equal sp - bool unextended_sp_safe = (unextended_sp <= thread->stack_base()) && + bool unextended_sp_safe = (unextended_sp < thread->stack_base()) && (unextended_sp >= sp); if (!unextended_sp_safe) { @@ -71,7 +78,8 @@ } // an fp must be within the stack and above (but not equal) sp - bool fp_safe = (fp <= thread->stack_base()) && (fp > sp); + // second evaluation on fp+ is added to handle situation where fp is -1 + bool fp_safe = (fp < thread->stack_base() && (fp > sp) && (((fp + (return_addr_offset * sizeof(void*))) < thread->stack_base()))); // We know sp/unextended_sp are safe only fp is questionable here @@ -86,6 +94,13 @@ // other generic buffer blobs are more problematic so we just assume they are // ok. adapter blobs never have a frame complete and are never ok. + // check for a valid frame_size, otherwise we are unlikely to get a valid sender_pc + + if (!Interpreter::contains(_pc) && _cb->frame_size() <= 0) { + //assert(0, "Invalid frame_size"); + return false; + } + if (!_cb->is_frame_complete_at(_pc)) { if (_cb->is_nmethod() || _cb->is_adapter_blob() || _cb->is_runtime_stub()) { return false; @@ -107,7 +122,7 @@ address jcw = (address)entry_frame_call_wrapper(); - bool jcw_safe = (jcw <= thread->stack_base()) && ( jcw > fp); + bool jcw_safe = (jcw < thread->stack_base()) && ( jcw > fp); return jcw_safe; @@ -134,12 +149,6 @@ sender_pc = (address) *(sender_sp-1); } - // We must always be able to find a recognizable pc - CodeBlob* sender_blob = CodeCache::find_blob_unsafe(sender_pc); - if (sender_pc == NULL || sender_blob == NULL) { - return false; - } - // If the potential sender is the interpreter then we can do some more checking if (Interpreter::contains(sender_pc)) { @@ -149,7 +158,7 @@ // is really a frame pointer. intptr_t *saved_fp = (intptr_t*)*(sender_sp - frame::sender_sp_offset); - bool saved_fp_safe = ((address)saved_fp <= thread->stack_base()) && (saved_fp > sender_sp); + bool saved_fp_safe = ((address)saved_fp < thread->stack_base()) && (saved_fp > sender_sp); if (!saved_fp_safe) { return false; @@ -163,6 +172,17 @@ } + // We must always be able to find a recognizable pc + CodeBlob* sender_blob = CodeCache::find_blob_unsafe(sender_pc); + if (sender_pc == NULL || sender_blob == NULL) { + return false; + } + + // Could be a zombie method + if (sender_blob->is_zombie() || sender_blob->is_unloaded()) { + return false; + } + // Could just be some random pointer within the codeBlob if (!sender_blob->code_contains(sender_pc)) { return false; @@ -174,10 +194,9 @@ } // Could be the call_stub - if (StubRoutines::returns_to_call_stub(sender_pc)) { intptr_t *saved_fp = (intptr_t*)*(sender_sp - frame::sender_sp_offset); - bool saved_fp_safe = ((address)saved_fp <= thread->stack_base()) && (saved_fp > sender_sp); + bool saved_fp_safe = ((address)saved_fp < thread->stack_base()) && (saved_fp > sender_sp); if (!saved_fp_safe) { return false; @@ -190,15 +209,24 @@ // Validate the JavaCallWrapper an entry frame must have address jcw = (address)sender.entry_frame_call_wrapper(); - bool jcw_safe = (jcw <= thread->stack_base()) && ( jcw > (address)sender.fp()); + bool jcw_safe = (jcw < thread->stack_base()) && ( jcw > (address)sender.fp()); return jcw_safe; } - // If the frame size is 0 something is bad because every nmethod has a non-zero frame size + if (sender_blob->is_nmethod()) { + nmethod* nm = sender_blob->as_nmethod_or_null(); + if (nm != NULL) { + if (nm->is_deopt_mh_entry(sender_pc) || nm->is_deopt_entry(sender_pc)) { + return false; + } + } + } + + // If the frame size is 0 something (or less) is bad because every nmethod has a non-zero frame size // because the return address counts against the callee's frame. - if (sender_blob->frame_size() == 0) { + if (sender_blob->frame_size() <= 0) { assert(!sender_blob->is_nmethod(), "should count return address at least"); return false; } @@ -208,7 +236,9 @@ // should not be anything but the call stub (already covered), the interpreter (already covered) // or an nmethod. - assert(sender_blob->is_nmethod(), "Impossible call chain"); + if (!sender_blob->is_nmethod()) { + return false; + } // Could put some more validation for the potential non-interpreted sender // frame we'd create by calling sender if I could think of any. Wait for next crash in forte...
--- a/src/cpu/x86/vm/templateInterpreter_x86_32.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/cpu/x86/vm/templateInterpreter_x86_32.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -1565,8 +1565,7 @@ // be sure to change this if you add/subtract anything to/from the overhead area const int overhead_size = -frame::interpreter_frame_initial_sp_offset; - const int extra_stack = Method::extra_stack_entries(); - const int method_stack = (method->max_locals() + method->max_stack() + extra_stack) * + const int method_stack = (method->max_locals() + method->max_stack()) * Interpreter::stackElementWords; return overhead_size + method_stack + stub_code; }
--- a/src/cpu/x86/vm/templateInterpreter_x86_64.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/cpu/x86/vm/templateInterpreter_x86_64.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -1574,8 +1574,7 @@ -(frame::interpreter_frame_initial_sp_offset) + entry_size; const int stub_code = frame::entry_frame_after_call_words; - const int extra_stack = Method::extra_stack_entries(); - const int method_stack = (method->max_locals() + method->max_stack() + extra_stack) * + const int method_stack = (method->max_locals() + method->max_stack()) * Interpreter::stackElementWords; return (overhead_size + method_stack + stub_code); }
--- a/src/os/bsd/vm/osThread_bsd.hpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/os/bsd/vm/osThread_bsd.hpp Fri Jun 21 15:56:24 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -94,7 +94,7 @@ // flags that support signal based suspend/resume on Bsd are in a // separate class to avoid confusion with many flags in OSThread that // are used by VM level suspend/resume. - os::Bsd::SuspendResume sr; + os::SuspendResume sr; // _ucontext and _siginfo are used by SR_handler() to save thread context, // and they will later be used to walk the stack or reposition thread PC.
--- a/src/os/bsd/vm/os_bsd.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/os/bsd/vm/os_bsd.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -626,8 +626,6 @@ ////////////////////////////////////////////////////////////////////////////// // create new thread -static address highest_vm_reserved_address(); - // check if it's safe to start a new thread static bool _thread_safety_check(Thread* thread) { return true; @@ -935,10 +933,10 @@ return (1000 * 1000); } -// XXX: For now, code this as if BSD does not support vtime. -bool os::supports_vtime() { return false; } +bool os::supports_vtime() { return true; } bool os::enable_vtime() { return false; } bool os::vtime_enabled() { return false; } + double os::elapsedVTime() { // better than nothing, but not much return elapsedTime(); @@ -1854,17 +1852,118 @@ // Bsd(POSIX) specific hand shaking semaphore. #ifdef __APPLE__ -static semaphore_t sig_sem; +typedef semaphore_t os_semaphore_t; #define SEM_INIT(sem, value) semaphore_create(mach_task_self(), &sem, SYNC_POLICY_FIFO, value) -#define SEM_WAIT(sem) semaphore_wait(sem); -#define SEM_POST(sem) semaphore_signal(sem); +#define SEM_WAIT(sem) semaphore_wait(sem) +#define SEM_POST(sem) semaphore_signal(sem) +#define SEM_DESTROY(sem) semaphore_destroy(mach_task_self(), sem) #else -static sem_t sig_sem; +typedef sem_t os_semaphore_t; #define SEM_INIT(sem, value) sem_init(&sem, 0, value) -#define SEM_WAIT(sem) sem_wait(&sem); -#define SEM_POST(sem) sem_post(&sem); +#define SEM_WAIT(sem) sem_wait(&sem) +#define SEM_POST(sem) sem_post(&sem) +#define SEM_DESTROY(sem) sem_destroy(&sem) #endif +class Semaphore : public StackObj { + public: + Semaphore(); + ~Semaphore(); + void signal(); + void wait(); + bool trywait(); + bool timedwait(unsigned int sec, int nsec); + private: + jlong currenttime() const; + semaphore_t _semaphore; +}; + +Semaphore::Semaphore() : _semaphore(0) { + SEM_INIT(_semaphore, 0); +} + +Semaphore::~Semaphore() { + SEM_DESTROY(_semaphore); +} + +void Semaphore::signal() { + SEM_POST(_semaphore); +} + +void Semaphore::wait() { + SEM_WAIT(_semaphore); +} + +jlong Semaphore::currenttime() const { + struct timeval tv; + gettimeofday(&tv, NULL); + return (tv.tv_sec * NANOSECS_PER_SEC) + (tv.tv_usec * 1000); +} + +#ifdef __APPLE__ +bool Semaphore::trywait() { + return timedwait(0, 0); +} + +bool Semaphore::timedwait(unsigned int sec, int nsec) { + kern_return_t kr = KERN_ABORTED; + mach_timespec_t waitspec; + waitspec.tv_sec = sec; + waitspec.tv_nsec = nsec; + + jlong starttime = currenttime(); + + kr = semaphore_timedwait(_semaphore, waitspec); + while (kr == KERN_ABORTED) { + jlong totalwait = (sec * NANOSECS_PER_SEC) + nsec; + + jlong current = currenttime(); + jlong passedtime = current - starttime; + + if (passedtime >= totalwait) { + waitspec.tv_sec = 0; + waitspec.tv_nsec = 0; + } else { + jlong waittime = totalwait - (current - starttime); + waitspec.tv_sec = waittime / NANOSECS_PER_SEC; + waitspec.tv_nsec = waittime % NANOSECS_PER_SEC; + } + + kr = semaphore_timedwait(_semaphore, waitspec); + } + + return kr == KERN_SUCCESS; +} + +#else + +bool Semaphore::trywait() { + return sem_trywait(&_semaphore) == 0; +} + +bool Semaphore::timedwait(unsigned int sec, int nsec) { + struct timespec ts; + jlong endtime = unpackTime(&ts, false, (sec * NANOSECS_PER_SEC) + nsec); + + while (1) { + int result = sem_timedwait(&_semaphore, &ts); + if (result == 0) { + return true; + } else if (errno == EINTR) { + continue; + } else if (errno == ETIMEDOUT) { + return false; + } else { + return false; + } + } +} + +#endif // __APPLE__ + +static os_semaphore_t sig_sem; +static Semaphore sr_semaphore; + void os::signal_init_pd() { // Initialize signal structures ::memset((void*)pending_signals, 0, sizeof(pending_signals)); @@ -2112,10 +2211,6 @@ return anon_munmap(addr, size); } -static address highest_vm_reserved_address() { - return _highest_vm_reserved_address; -} - static bool bsd_mprotect(char* addr, size_t size, int prot) { // Bsd wants the mprotect address argument to be page aligned. char* bottom = (char*)align_size_down((intptr_t)addr, os::Bsd::page_size()); @@ -2159,43 +2254,6 @@ return false; } -/* -* Set the coredump_filter bits to include largepages in core dump (bit 6) -* -* From the coredump_filter documentation: -* -* - (bit 0) anonymous private memory -* - (bit 1) anonymous shared memory -* - (bit 2) file-backed private memory -* - (bit 3) file-backed shared memory -* - (bit 4) ELF header pages in file-backed private memory areas (it is -* effective only if the bit 2 is cleared) -* - (bit 5) hugetlb private memory -* - (bit 6) hugetlb shared memory -*/ -static void set_coredump_filter(void) { - FILE *f; - long cdm; - - if ((f = fopen("/proc/self/coredump_filter", "r+")) == NULL) { - return; - } - - if (fscanf(f, "%lx", &cdm) != 1) { - fclose(f); - return; - } - - rewind(f); - - if ((cdm & LARGEPAGES_BIT) == 0) { - cdm |= LARGEPAGES_BIT; - fprintf(f, "%#lx", cdm); - } - - fclose(f); -} - // Large page support static size_t _large_page_size = 0; @@ -2659,9 +2717,6 @@ static void resume_clear_context(OSThread *osthread) { osthread->set_ucontext(NULL); osthread->set_siginfo(NULL); - - // notify the suspend action is completed, we have now resumed - osthread->sr.clear_suspended(); } static void suspend_save_context(OSThread *osthread, siginfo_t* siginfo, ucontext_t* context) { @@ -2681,7 +2736,7 @@ // its signal handlers run and prevents sigwait()'s use with the // mutex granting granting signal. // -// Currently only ever called on the VMThread +// Currently only ever called on the VMThread or JavaThread // static void SR_handler(int sig, siginfo_t* siginfo, ucontext_t* context) { // Save and restore errno to avoid confusing native code with EINTR @@ -2690,38 +2745,48 @@ Thread* thread = Thread::current(); OSThread* osthread = thread->osthread(); - assert(thread->is_VM_thread(), "Must be VMThread"); - // read current suspend action - int action = osthread->sr.suspend_action(); - if (action == os::Bsd::SuspendResume::SR_SUSPEND) { + assert(thread->is_VM_thread() || thread->is_Java_thread(), "Must be VMThread or JavaThread"); + + os::SuspendResume::State current = osthread->sr.state(); + if (current == os::SuspendResume::SR_SUSPEND_REQUEST) { suspend_save_context(osthread, siginfo, context); - // Notify the suspend action is about to be completed. do_suspend() - // waits until SR_SUSPENDED is set and then returns. We will wait - // here for a resume signal and that completes the suspend-other - // action. do_suspend/do_resume is always called as a pair from - // the same thread - so there are no races - - // notify the caller - osthread->sr.set_suspended(); - - sigset_t suspend_set; // signals for sigsuspend() - - // get current set of blocked signals and unblock resume signal - pthread_sigmask(SIG_BLOCK, NULL, &suspend_set); - sigdelset(&suspend_set, SR_signum); - - // wait here until we are resumed - do { - sigsuspend(&suspend_set); - // ignore all returns until we get a resume signal - } while (osthread->sr.suspend_action() != os::Bsd::SuspendResume::SR_CONTINUE); + // attempt to switch the state, we assume we had a SUSPEND_REQUEST + os::SuspendResume::State state = osthread->sr.suspended(); + if (state == os::SuspendResume::SR_SUSPENDED) { + sigset_t suspend_set; // signals for sigsuspend() + + // get current set of blocked signals and unblock resume signal + pthread_sigmask(SIG_BLOCK, NULL, &suspend_set); + sigdelset(&suspend_set, SR_signum); + + sr_semaphore.signal(); + // wait here until we are resumed + while (1) { + sigsuspend(&suspend_set); + + os::SuspendResume::State result = osthread->sr.running(); + if (result == os::SuspendResume::SR_RUNNING) { + sr_semaphore.signal(); + break; + } else if (result != os::SuspendResume::SR_SUSPENDED) { + ShouldNotReachHere(); + } + } + + } else if (state == os::SuspendResume::SR_RUNNING) { + // request was cancelled, continue + } else { + ShouldNotReachHere(); + } resume_clear_context(osthread); - + } else if (current == os::SuspendResume::SR_RUNNING) { + // request was cancelled, continue + } else if (current == os::SuspendResume::SR_WAKEUP_REQUEST) { + // ignore } else { - assert(action == os::Bsd::SuspendResume::SR_CONTINUE, "unexpected sr action"); - // nothing special to do - just leave the handler + // ignore } errno = old_errno; @@ -2765,42 +2830,82 @@ return 0; } +static int sr_notify(OSThread* osthread) { + int status = pthread_kill(osthread->pthread_id(), SR_signum); + assert_status(status == 0, status, "pthread_kill"); + return status; +} + +// "Randomly" selected value for how long we want to spin +// before bailing out on suspending a thread, also how often +// we send a signal to a thread we want to resume +static const int RANDOMLY_LARGE_INTEGER = 1000000; +static const int RANDOMLY_LARGE_INTEGER2 = 100; // returns true on success and false on error - really an error is fatal // but this seems the normal response to library errors static bool do_suspend(OSThread* osthread) { + assert(osthread->sr.is_running(), "thread should be running"); + assert(!sr_semaphore.trywait(), "semaphore has invalid state"); + // mark as suspended and send signal - osthread->sr.set_suspend_action(os::Bsd::SuspendResume::SR_SUSPEND); - int status = pthread_kill(osthread->pthread_id(), SR_signum); - assert_status(status == 0, status, "pthread_kill"); - - // check status and wait until notified of suspension - if (status == 0) { - for (int i = 0; !osthread->sr.is_suspended(); i++) { - os::yield_all(i); - } - osthread->sr.set_suspend_action(os::Bsd::SuspendResume::SR_NONE); - return true; - } - else { - osthread->sr.set_suspend_action(os::Bsd::SuspendResume::SR_NONE); + if (osthread->sr.request_suspend() != os::SuspendResume::SR_SUSPEND_REQUEST) { + // failed to switch, state wasn't running? + ShouldNotReachHere(); return false; } + + if (sr_notify(osthread) != 0) { + ShouldNotReachHere(); + } + + // managed to send the signal and switch to SUSPEND_REQUEST, now wait for SUSPENDED + while (true) { + if (sr_semaphore.timedwait(0, 2 * NANOSECS_PER_MILLISEC)) { + break; + } else { + // timeout + os::SuspendResume::State cancelled = osthread->sr.cancel_suspend(); + if (cancelled == os::SuspendResume::SR_RUNNING) { + return false; + } else if (cancelled == os::SuspendResume::SR_SUSPENDED) { + // make sure that we consume the signal on the semaphore as well + sr_semaphore.wait(); + break; + } else { + ShouldNotReachHere(); + return false; + } + } + } + + guarantee(osthread->sr.is_suspended(), "Must be suspended"); + return true; } static void do_resume(OSThread* osthread) { assert(osthread->sr.is_suspended(), "thread should be suspended"); - osthread->sr.set_suspend_action(os::Bsd::SuspendResume::SR_CONTINUE); - - int status = pthread_kill(osthread->pthread_id(), SR_signum); - assert_status(status == 0, status, "pthread_kill"); - // check status and wait unit notified of resumption - if (status == 0) { - for (int i = 0; osthread->sr.is_suspended(); i++) { - os::yield_all(i); + assert(!sr_semaphore.trywait(), "invalid semaphore state"); + + if (osthread->sr.request_wakeup() != os::SuspendResume::SR_WAKEUP_REQUEST) { + // failed to switch to WAKEUP_REQUEST + ShouldNotReachHere(); + return; + } + + while (true) { + if (sr_notify(osthread) == 0) { + if (sr_semaphore.timedwait(0, 2 * NANOSECS_PER_MILLISEC)) { + if (osthread->sr.is_running()) { + return; + } + } + } else { + ShouldNotReachHere(); } } - osthread->sr.set_suspend_action(os::Bsd::SuspendResume::SR_NONE); + + guarantee(osthread->sr.is_running(), "Must be running!"); } //////////////////////////////////////////////////////////////////////////////// @@ -3030,6 +3135,19 @@ sigAct.sa_sigaction = signalHandler; sigAct.sa_flags = SA_SIGINFO|SA_RESTART; } +#if __APPLE__ + // Needed for main thread as XNU (Mac OS X kernel) will only deliver SIGSEGV + // (which starts as SIGBUS) on main thread with faulting address inside "stack+guard pages" + // if the signal handler declares it will handle it on alternate stack. + // Notice we only declare we will handle it on alt stack, but we are not + // actually going to use real alt stack - this is just a workaround. + // Please see ux_exception.c, method catch_mach_exception_raise for details + // link http://www.opensource.apple.com/source/xnu/xnu-2050.18.24/bsd/uxkern/ux_exception.c + if (sig == SIGSEGV) { + sigAct.sa_flags |= SA_ONSTACK; + } +#endif + // Save flags, which are set by ours assert(sig > 0 && sig < MAXSIGNUM, "vm signal out of expected range"); sigflags[sig] = sigAct.sa_flags; @@ -3538,7 +3656,40 @@ return false; } +void os::SuspendedThreadTask::internal_do_task() { + if (do_suspend(_thread->osthread())) { + SuspendedThreadTaskContext context(_thread, _thread->osthread()->ucontext()); + do_task(context); + do_resume(_thread->osthread()); + } +} + /// +class PcFetcher : public os::SuspendedThreadTask { +public: + PcFetcher(Thread* thread) : os::SuspendedThreadTask(thread) {} + ExtendedPC result(); +protected: + void do_task(const os::SuspendedThreadTaskContext& context); +private: + ExtendedPC _epc; +}; + +ExtendedPC PcFetcher::result() { + guarantee(is_done(), "task is not done yet."); + return _epc; +} + +void PcFetcher::do_task(const os::SuspendedThreadTaskContext& context) { + Thread* thread = context.thread(); + OSThread* osthread = thread->osthread(); + if (osthread->ucontext() != NULL) { + _epc = os::Bsd::ucontext_get_pc((ucontext_t *) context.ucontext()); + } else { + // NULL context is unexpected, double-check this is the VMThread + guarantee(thread->is_VM_thread(), "can only be called for VMThread"); + } +} // Suspends the target using the signal mechanism and then grabs the PC before // resuming the target. Used by the flat-profiler only @@ -3547,22 +3698,9 @@ assert(Thread::current()->is_Watcher_thread(), "Must be watcher"); assert(thread->is_VM_thread(), "Can only be called for VMThread"); - ExtendedPC epc; - - OSThread* osthread = thread->osthread(); - if (do_suspend(osthread)) { - if (osthread->ucontext() != NULL) { - epc = os::Bsd::ucontext_get_pc(osthread->ucontext()); - } else { - // NULL context is unexpected, double-check this is the VMThread - guarantee(thread->is_VM_thread(), "can only be called for VMThread"); - } - do_resume(osthread); - } - // failure means pthread_kill failed for some reason - arguably this is - // a fatal problem, but such problems are ignored elsewhere - - return epc; + PcFetcher fetcher(thread); + fetcher.run(); + return fetcher.result(); } int os::Bsd::safe_cond_timedwait(pthread_cond_t *_cond, pthread_mutex_t *_mutex, const struct timespec *_abstime) @@ -4547,3 +4685,4 @@ return n; } +
--- a/src/os/bsd/vm/os_bsd.hpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/os/bsd/vm/os_bsd.hpp Fri Jun 21 15:56:24 2013 -0700 @@ -145,36 +145,6 @@ // BsdThreads work-around for 6292965 static int safe_cond_timedwait(pthread_cond_t *_cond, pthread_mutex_t *_mutex, const struct timespec *_abstime); - - // Bsd suspend/resume support - this helper is a shadow of its former - // self now that low-level suspension is barely used, and old workarounds - // for BsdThreads are no longer needed. - class SuspendResume { - private: - volatile int _suspend_action; - volatile jint _state; - public: - // values for suspend_action: - enum { - SR_NONE = 0x00, - SR_SUSPEND = 0x01, // suspend request - SR_CONTINUE = 0x02, // resume request - SR_SUSPENDED = 0x20 // values for _state: + SR_NONE - }; - - SuspendResume() { _suspend_action = SR_NONE; _state = SR_NONE; } - - int suspend_action() const { return _suspend_action; } - void set_suspend_action(int x) { _suspend_action = x; } - - // atomic updates for _state - inline void set_suspended(); - inline void clear_suspended(); - bool is_suspended() { return _state & SR_SUSPENDED; } - - #undef SR_SUSPENDED - }; - private: typedef int (*sched_getcpu_func_t)(void); typedef int (*numa_node_to_cpus_func_t)(int node, unsigned long *buffer, int bufferlen); @@ -250,7 +220,7 @@ int TryPark () ; int park (jlong millis) ; void SetAssociation (Thread * a) { _Assoc = a ; } -} ; +}; class PlatformParker : public CHeapObj<mtInternal> { protected: @@ -268,6 +238,6 @@ status = pthread_mutex_init (_mutex, NULL); assert_status(status == 0, status, "mutex_init"); } -} ; +}; #endif // OS_BSD_VM_OS_BSD_HPP
--- a/src/os/bsd/vm/os_bsd.inline.hpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/os/bsd/vm/os_bsd.inline.hpp Fri Jun 21 15:56:24 2013 -0700 @@ -286,20 +286,4 @@ return ::setsockopt(fd, level, optname, optval, optlen); } -inline void os::Bsd::SuspendResume::set_suspended() { - jint temp, temp2; - do { - temp = _state; - temp2 = Atomic::cmpxchg(temp | SR_SUSPENDED, &_state, temp); - } while (temp2 != temp); -} - -inline void os::Bsd::SuspendResume::clear_suspended() { - jint temp, temp2; - do { - temp = _state; - temp2 = Atomic::cmpxchg(temp & ~SR_SUSPENDED, &_state, temp); - } while (temp2 != temp); -} - #endif // OS_BSD_VM_OS_BSD_INLINE_HPP
--- a/src/os/linux/vm/osThread_linux.hpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/os/linux/vm/osThread_linux.hpp Fri Jun 21 15:56:24 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -77,7 +77,7 @@ // flags that support signal based suspend/resume on Linux are in a // separate class to avoid confusion with many flags in OSThread that // are used by VM level suspend/resume. - os::Linux::SuspendResume sr; + os::SuspendResume sr; // _ucontext and _siginfo are used by SR_handler() to save thread context, // and they will later be used to walk the stack or reposition thread PC.
--- a/src/os/linux/vm/os_linux.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/os/linux/vm/os_linux.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -101,6 +101,12 @@ # include <inttypes.h> # include <sys/ioctl.h> +// if RUSAGE_THREAD for getrusage() has not been defined, do it here. The code calling +// getrusage() is prepared to handle the associated failure. +#ifndef RUSAGE_THREAD +#define RUSAGE_THREAD (1) /* only the calling thread */ +#endif + #define MAX_PATH (2 * K) // for timer info max values which include all bits @@ -145,6 +151,9 @@ /* Used to protect dlsym() calls */ static pthread_mutex_t dl_mutex; +// Declarations +static void unpackTime(timespec* absTime, bool isAbsolute, jlong time); + #ifdef JAVASE_EMBEDDED class MemNotifyThread: public Thread { friend class VMStructs; @@ -1338,15 +1347,19 @@ return (1000 * 1000); } -// For now, we say that linux does not support vtime. I have no idea -// whether it can actually be made to (DLD, 9/13/05). - -bool os::supports_vtime() { return false; } +bool os::supports_vtime() { return true; } bool os::enable_vtime() { return false; } bool os::vtime_enabled() { return false; } + double os::elapsedVTime() { - // better than nothing, but not much - return elapsedTime(); + struct rusage usage; + int retval = getrusage(RUSAGE_THREAD, &usage); + if (retval == 0) { + return (double) (usage.ru_utime.tv_sec + usage.ru_stime.tv_sec) + (double) (usage.ru_utime.tv_usec + usage.ru_stime.tv_usec) / (1000 * 1000); + } else { + // better than nothing, but not much + return elapsedTime(); + } } jlong os::javaTimeMillis() { @@ -2399,6 +2412,57 @@ return CAST_FROM_FN_PTR(void*, UserHandler); } +class Semaphore : public StackObj { + public: + Semaphore(); + ~Semaphore(); + void signal(); + void wait(); + bool trywait(); + bool timedwait(unsigned int sec, int nsec); + private: + sem_t _semaphore; +}; + + +Semaphore::Semaphore() { + sem_init(&_semaphore, 0, 0); +} + +Semaphore::~Semaphore() { + sem_destroy(&_semaphore); +} + +void Semaphore::signal() { + sem_post(&_semaphore); +} + +void Semaphore::wait() { + sem_wait(&_semaphore); +} + +bool Semaphore::trywait() { + return sem_trywait(&_semaphore) == 0; +} + +bool Semaphore::timedwait(unsigned int sec, int nsec) { + struct timespec ts; + unpackTime(&ts, false, (sec * NANOSECS_PER_SEC) + nsec); + + while (1) { + int result = sem_timedwait(&_semaphore, &ts); + if (result == 0) { + return true; + } else if (errno == EINTR) { + continue; + } else if (errno == ETIMEDOUT) { + return false; + } else { + return false; + } + } +} + extern "C" { typedef void (*sa_handler_t)(int); typedef void (*sa_sigaction_t)(int, siginfo_t *, void *); @@ -2438,6 +2502,7 @@ // Linux(POSIX) specific hand shaking semaphore. static sem_t sig_sem; +static Semaphore sr_semaphore; void os::signal_init_pd() { // Initialize signal structures @@ -3551,9 +3616,6 @@ static void resume_clear_context(OSThread *osthread) { osthread->set_ucontext(NULL); osthread->set_siginfo(NULL); - - // notify the suspend action is completed, we have now resumed - osthread->sr.clear_suspended(); } static void suspend_save_context(OSThread *osthread, siginfo_t* siginfo, ucontext_t* context) { @@ -3573,7 +3635,7 @@ // its signal handlers run and prevents sigwait()'s use with the // mutex granting granting signal. // -// Currently only ever called on the VMThread +// Currently only ever called on the VMThread and JavaThreads (PC sampling) // static void SR_handler(int sig, siginfo_t* siginfo, ucontext_t* context) { // Save and restore errno to avoid confusing native code with EINTR @@ -3582,38 +3644,46 @@ Thread* thread = Thread::current(); OSThread* osthread = thread->osthread(); - assert(thread->is_VM_thread(), "Must be VMThread"); - // read current suspend action - int action = osthread->sr.suspend_action(); - if (action == os::Linux::SuspendResume::SR_SUSPEND) { + assert(thread->is_VM_thread() || thread->is_Java_thread(), "Must be VMThread or JavaThread"); + + os::SuspendResume::State current = osthread->sr.state(); + if (current == os::SuspendResume::SR_SUSPEND_REQUEST) { suspend_save_context(osthread, siginfo, context); - // Notify the suspend action is about to be completed. do_suspend() - // waits until SR_SUSPENDED is set and then returns. We will wait - // here for a resume signal and that completes the suspend-other - // action. do_suspend/do_resume is always called as a pair from - // the same thread - so there are no races - - // notify the caller - osthread->sr.set_suspended(); - - sigset_t suspend_set; // signals for sigsuspend() - - // get current set of blocked signals and unblock resume signal - pthread_sigmask(SIG_BLOCK, NULL, &suspend_set); - sigdelset(&suspend_set, SR_signum); - - // wait here until we are resumed - do { - sigsuspend(&suspend_set); - // ignore all returns until we get a resume signal - } while (osthread->sr.suspend_action() != os::Linux::SuspendResume::SR_CONTINUE); + // attempt to switch the state, we assume we had a SUSPEND_REQUEST + os::SuspendResume::State state = osthread->sr.suspended(); + if (state == os::SuspendResume::SR_SUSPENDED) { + sigset_t suspend_set; // signals for sigsuspend() + + // get current set of blocked signals and unblock resume signal + pthread_sigmask(SIG_BLOCK, NULL, &suspend_set); + sigdelset(&suspend_set, SR_signum); + + sr_semaphore.signal(); + // wait here until we are resumed + while (1) { + sigsuspend(&suspend_set); + + os::SuspendResume::State result = osthread->sr.running(); + if (result == os::SuspendResume::SR_RUNNING) { + sr_semaphore.signal(); + break; + } + } + + } else if (state == os::SuspendResume::SR_RUNNING) { + // request was cancelled, continue + } else { + ShouldNotReachHere(); + } resume_clear_context(osthread); - + } else if (current == os::SuspendResume::SR_RUNNING) { + // request was cancelled, continue + } else if (current == os::SuspendResume::SR_WAKEUP_REQUEST) { + // ignore } else { - assert(action == os::Linux::SuspendResume::SR_CONTINUE, "unexpected sr action"); - // nothing special to do - just leave the handler + // ignore } errno = old_errno; @@ -3657,42 +3727,82 @@ return 0; } +static int sr_notify(OSThread* osthread) { + int status = pthread_kill(osthread->pthread_id(), SR_signum); + assert_status(status == 0, status, "pthread_kill"); + return status; +} + +// "Randomly" selected value for how long we want to spin +// before bailing out on suspending a thread, also how often +// we send a signal to a thread we want to resume +static const int RANDOMLY_LARGE_INTEGER = 1000000; +static const int RANDOMLY_LARGE_INTEGER2 = 100; // returns true on success and false on error - really an error is fatal // but this seems the normal response to library errors static bool do_suspend(OSThread* osthread) { + assert(osthread->sr.is_running(), "thread should be running"); + assert(!sr_semaphore.trywait(), "semaphore has invalid state"); + // mark as suspended and send signal - osthread->sr.set_suspend_action(os::Linux::SuspendResume::SR_SUSPEND); - int status = pthread_kill(osthread->pthread_id(), SR_signum); - assert_status(status == 0, status, "pthread_kill"); - - // check status and wait until notified of suspension - if (status == 0) { - for (int i = 0; !osthread->sr.is_suspended(); i++) { - os::yield_all(i); + if (osthread->sr.request_suspend() != os::SuspendResume::SR_SUSPEND_REQUEST) { + // failed to switch, state wasn't running? + ShouldNotReachHere(); + return false; + } + + if (sr_notify(osthread) != 0) { + ShouldNotReachHere(); + } + + // managed to send the signal and switch to SUSPEND_REQUEST, now wait for SUSPENDED + while (true) { + if (sr_semaphore.timedwait(0, 2 * NANOSECS_PER_MILLISEC)) { + break; + } else { + // timeout + os::SuspendResume::State cancelled = osthread->sr.cancel_suspend(); + if (cancelled == os::SuspendResume::SR_RUNNING) { + return false; + } else if (cancelled == os::SuspendResume::SR_SUSPENDED) { + // make sure that we consume the signal on the semaphore as well + sr_semaphore.wait(); + break; + } else { + ShouldNotReachHere(); + return false; + } } - osthread->sr.set_suspend_action(os::Linux::SuspendResume::SR_NONE); - return true; - } - else { - osthread->sr.set_suspend_action(os::Linux::SuspendResume::SR_NONE); - return false; - } + } + + guarantee(osthread->sr.is_suspended(), "Must be suspended"); + return true; } static void do_resume(OSThread* osthread) { assert(osthread->sr.is_suspended(), "thread should be suspended"); - osthread->sr.set_suspend_action(os::Linux::SuspendResume::SR_CONTINUE); - - int status = pthread_kill(osthread->pthread_id(), SR_signum); - assert_status(status == 0, status, "pthread_kill"); - // check status and wait unit notified of resumption - if (status == 0) { - for (int i = 0; osthread->sr.is_suspended(); i++) { - os::yield_all(i); + assert(!sr_semaphore.trywait(), "invalid semaphore state"); + + if (osthread->sr.request_wakeup() != os::SuspendResume::SR_WAKEUP_REQUEST) { + // failed to switch to WAKEUP_REQUEST + ShouldNotReachHere(); + return; + } + + while (true) { + if (sr_notify(osthread) == 0) { + if (sr_semaphore.timedwait(0, 2 * NANOSECS_PER_MILLISEC)) { + if (osthread->sr.is_running()) { + return; + } + } + } else { + ShouldNotReachHere(); } } - osthread->sr.set_suspend_action(os::Linux::SuspendResume::SR_NONE); + + guarantee(osthread->sr.is_running(), "Must be running!"); } //////////////////////////////////////////////////////////////////////////////// @@ -4463,6 +4573,40 @@ /// +void os::SuspendedThreadTask::internal_do_task() { + if (do_suspend(_thread->osthread())) { + SuspendedThreadTaskContext context(_thread, _thread->osthread()->ucontext()); + do_task(context); + do_resume(_thread->osthread()); + } +} + +class PcFetcher : public os::SuspendedThreadTask { +public: + PcFetcher(Thread* thread) : os::SuspendedThreadTask(thread) {} + ExtendedPC result(); +protected: + void do_task(const os::SuspendedThreadTaskContext& context); +private: + ExtendedPC _epc; +}; + +ExtendedPC PcFetcher::result() { + guarantee(is_done(), "task is not done yet."); + return _epc; +} + +void PcFetcher::do_task(const os::SuspendedThreadTaskContext& context) { + Thread* thread = context.thread(); + OSThread* osthread = thread->osthread(); + if (osthread->ucontext() != NULL) { + _epc = os::Linux::ucontext_get_pc((ucontext_t *) context.ucontext()); + } else { + // NULL context is unexpected, double-check this is the VMThread + guarantee(thread->is_VM_thread(), "can only be called for VMThread"); + } +} + // Suspends the target using the signal mechanism and then grabs the PC before // resuming the target. Used by the flat-profiler only ExtendedPC os::get_thread_pc(Thread* thread) { @@ -4470,22 +4614,9 @@ assert(Thread::current()->is_Watcher_thread(), "Must be watcher"); assert(thread->is_VM_thread(), "Can only be called for VMThread"); - ExtendedPC epc; - - OSThread* osthread = thread->osthread(); - if (do_suspend(osthread)) { - if (osthread->ucontext() != NULL) { - epc = os::Linux::ucontext_get_pc(osthread->ucontext()); - } else { - // NULL context is unexpected, double-check this is the VMThread - guarantee(thread->is_VM_thread(), "can only be called for VMThread"); - } - do_resume(osthread); - } - // failure means pthread_kill failed for some reason - arguably this is - // a fatal problem, but such problems are ignored elsewhere - - return epc; + PcFetcher fetcher(thread); + fetcher.run(); + return fetcher.result(); } int os::Linux::safe_cond_timedwait(pthread_cond_t *_cond, pthread_mutex_t *_mutex, const struct timespec *_abstime) @@ -5607,4 +5738,5 @@ new MemNotifyThread(fd); } } + #endif // JAVASE_EMBEDDED
--- a/src/os/linux/vm/os_linux.hpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/os/linux/vm/os_linux.hpp Fri Jun 21 15:56:24 2013 -0700 @@ -210,35 +210,6 @@ // LinuxThreads work-around for 6292965 static int safe_cond_timedwait(pthread_cond_t *_cond, pthread_mutex_t *_mutex, const struct timespec *_abstime); - - // Linux suspend/resume support - this helper is a shadow of its former - // self now that low-level suspension is barely used, and old workarounds - // for LinuxThreads are no longer needed. - class SuspendResume { - private: - volatile int _suspend_action; - volatile jint _state; - public: - // values for suspend_action: - enum { - SR_NONE = 0x00, - SR_SUSPEND = 0x01, // suspend request - SR_CONTINUE = 0x02, // resume request - SR_SUSPENDED = 0x20 // values for _state: + SR_NONE - }; - - SuspendResume() { _suspend_action = SR_NONE; _state = SR_NONE; } - - int suspend_action() const { return _suspend_action; } - void set_suspend_action(int x) { _suspend_action = x; } - - // atomic updates for _state - inline void set_suspended(); - inline void clear_suspended(); - bool is_suspended() { return _state & SR_SUSPENDED; } - - }; - private: typedef int (*sched_getcpu_func_t)(void); typedef int (*numa_node_to_cpus_func_t)(int node, unsigned long *buffer, int bufferlen); @@ -333,6 +304,6 @@ status = pthread_mutex_init (_mutex, NULL); assert_status(status == 0, status, "mutex_init"); } -} ; +}; #endif // OS_LINUX_VM_OS_LINUX_HPP
--- a/src/os/linux/vm/os_linux.inline.hpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/os/linux/vm/os_linux.inline.hpp Fri Jun 21 15:56:24 2013 -0700 @@ -288,20 +288,4 @@ return ::setsockopt(fd, level, optname, optval, optlen); } -inline void os::Linux::SuspendResume::set_suspended() { - jint temp, temp2; - do { - temp = _state; - temp2 = Atomic::cmpxchg(temp | SR_SUSPENDED, &_state, temp); - } while (temp2 != temp); -} - -inline void os::Linux::SuspendResume::clear_suspended() { - jint temp, temp2; - do { - temp = _state; - temp2 = Atomic::cmpxchg(temp & ~SR_SUSPENDED, &_state, temp); - } while (temp2 != temp); -} - #endif // OS_LINUX_VM_OS_LINUX_INLINE_HPP
--- a/src/os/solaris/vm/osThread_solaris.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/os/solaris/vm/osThread_solaris.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,10 +41,6 @@ _thread_id = 0; sigemptyset(&_caller_sigmask); - _current_callback = NULL; - _current_callback_lock = VM_Version::supports_compare_and_exchange() ? NULL - : new Mutex(Mutex::suspend_resume, "Callback_lock", true); - _saved_interrupt_thread_state = _thread_new; _vm_created_thread = false; } @@ -52,172 +48,6 @@ void OSThread::pd_destroy() { } -// Synchronous interrupt support -// -// _current_callback == NULL no pending callback -// == 1 callback_in_progress -// == other value pointer to the pending callback -// - -// CAS on v8 is implemented by using a global atomic_memory_operation_lock, -// which is shared by other atomic functions. It is OK for normal uses, but -// dangerous if used after some thread is suspended or if used in signal -// handlers. Instead here we use a special per-thread lock to synchronize -// updating _current_callback if we are running on v8. Note in general trying -// to grab locks after a thread is suspended is not safe, but it is safe for -// updating _current_callback, because synchronous interrupt callbacks are -// currently only used in: -// 1. GetThreadPC_Callback - used by WatcherThread to profile VM thread -// There is no overlap between the callbacks, which means we won't try to -// grab a thread's sync lock after the thread has been suspended while holding -// the same lock. - -// used after a thread is suspended -static intptr_t compare_and_exchange_current_callback ( - intptr_t callback, intptr_t *addr, intptr_t compare_value, Mutex *sync) { - if (VM_Version::supports_compare_and_exchange()) { - return Atomic::cmpxchg_ptr(callback, addr, compare_value); - } else { - MutexLockerEx ml(sync, Mutex::_no_safepoint_check_flag); - if (*addr == compare_value) { - *addr = callback; - return compare_value; - } else { - return callback; - } - } -} - -// used in signal handler -static intptr_t exchange_current_callback(intptr_t callback, intptr_t *addr, Mutex *sync) { - if (VM_Version::supports_compare_and_exchange()) { - return Atomic::xchg_ptr(callback, addr); - } else { - MutexLockerEx ml(sync, Mutex::_no_safepoint_check_flag); - intptr_t cb = *addr; - *addr = callback; - return cb; - } -} - -// one interrupt at a time. spin if _current_callback != NULL -int OSThread::set_interrupt_callback(Sync_Interrupt_Callback * cb) { - int count = 0; - while (compare_and_exchange_current_callback( - (intptr_t)cb, (intptr_t *)&_current_callback, (intptr_t)NULL, _current_callback_lock) != NULL) { - while (_current_callback != NULL) { - count++; -#ifdef ASSERT - if ((WarnOnStalledSpinLock > 0) && - (count % WarnOnStalledSpinLock == 0)) { - warning("_current_callback seems to be stalled: %p", _current_callback); - } -#endif - os::yield_all(count); - } - } - return 0; -} - -// reset _current_callback, spin if _current_callback is callback_in_progress -void OSThread::remove_interrupt_callback(Sync_Interrupt_Callback * cb) { - int count = 0; - while (compare_and_exchange_current_callback( - (intptr_t)NULL, (intptr_t *)&_current_callback, (intptr_t)cb, _current_callback_lock) != (intptr_t)cb) { -#ifdef ASSERT - intptr_t p = (intptr_t)_current_callback; - assert(p == (intptr_t)callback_in_progress || - p == (intptr_t)cb, "wrong _current_callback value"); -#endif - while (_current_callback != cb) { - count++; -#ifdef ASSERT - if ((WarnOnStalledSpinLock > 0) && - (count % WarnOnStalledSpinLock == 0)) { - warning("_current_callback seems to be stalled: %p", _current_callback); - } -#endif - os::yield_all(count); - } - } -} - -void OSThread::do_interrupt_callbacks_at_interrupt(InterruptArguments *args) { - Sync_Interrupt_Callback * cb; - cb = (Sync_Interrupt_Callback *)exchange_current_callback( - (intptr_t)callback_in_progress, (intptr_t *)&_current_callback, _current_callback_lock); - - if (cb == NULL) { - // signal is delivered too late (thread is masking interrupt signal??). - // there is nothing we need to do because requesting thread has given up. - } else if ((intptr_t)cb == (intptr_t)callback_in_progress) { - fatal("invalid _current_callback state"); - } else { - assert(cb->target()->osthread() == this, "wrong target"); - cb->execute(args); - cb->leave_callback(); // notify the requester - } - - // restore original _current_callback value - intptr_t p; - p = exchange_current_callback((intptr_t)cb, (intptr_t *)&_current_callback, _current_callback_lock); - assert(p == (intptr_t)callback_in_progress, "just checking"); -} - -// Called by the requesting thread to send a signal to target thread and -// execute "this" callback from the signal handler. -int OSThread::Sync_Interrupt_Callback::interrupt(Thread * target, int timeout) { - // Let signals to the vm_thread go even if the Threads_lock is not acquired - assert(Threads_lock->owned_by_self() || (target == VMThread::vm_thread()), - "must have threads lock to call this"); - - OSThread * osthread = target->osthread(); - - // may block if target thread already has a pending callback - osthread->set_interrupt_callback(this); - - _target = target; - - int rslt = thr_kill(osthread->thread_id(), os::Solaris::SIGasync()); - assert(rslt == 0, "thr_kill != 0"); - - bool status = false; - jlong t1 = os::javaTimeMillis(); - { // don't use safepoint check because we might be the watcher thread. - MutexLockerEx ml(_sync, Mutex::_no_safepoint_check_flag); - while (!is_done()) { - status = _sync->wait(Mutex::_no_safepoint_check_flag, timeout); - - // status == true if timed out - if (status) break; - - // update timeout - jlong t2 = os::javaTimeMillis(); - timeout -= t2 - t1; - t1 = t2; - } - } - - // reset current_callback - osthread->remove_interrupt_callback(this); - - return status; -} - -void OSThread::Sync_Interrupt_Callback::leave_callback() { - if (!_sync->owned_by_self()) { - // notify requesting thread - MutexLockerEx ml(_sync, Mutex::_no_safepoint_check_flag); - _is_done = true; - _sync->notify_all(); - } else { - // Current thread is interrupted while it is holding the _sync lock, trying - // to grab it again will deadlock. The requester will timeout anyway, - // so just return. - _is_done = true; - } -} - // copied from synchronizer.cpp void OSThread::handle_spinlock_contention(int tries) { @@ -229,3 +59,7 @@ os::yield(); // Yield to threads of same or higher priority } } + +void OSThread::SR_handler(Thread* thread, ucontext_t* uc) { + os::Solaris::SR_handler(thread, uc); +}
--- a/src/os/solaris/vm/osThread_solaris.hpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/os/solaris/vm/osThread_solaris.hpp Fri Jun 21 15:56:24 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -72,61 +72,15 @@ // *************************************************************** public: - - class InterruptArguments : StackObj { - private: - Thread* _thread; // the thread to signal was dispatched to - ucontext_t* _ucontext; // the machine context at the time of the signal - - public: - InterruptArguments(Thread* thread, ucontext_t* ucontext) { - _thread = thread; - _ucontext = ucontext; - } - - Thread* thread() const { return _thread; } - ucontext_t* ucontext() const { return _ucontext; } - }; - - // There are currently no asynchronous callbacks - and we'd better not - // support them in the future either, as they need to be deallocated from - // the interrupt handler, which is not safe; they also require locks to - // protect the callback queue. - - class Sync_Interrupt_Callback : private StackObj { - protected: - volatile bool _is_done; - Monitor* _sync; - Thread* _target; - public: - Sync_Interrupt_Callback(Monitor * sync) { - _is_done = false; _target = NULL; _sync = sync; - } - - bool is_done() const { return _is_done; } - Thread* target() const { return _target; } - - int interrupt(Thread * target, int timeout); - - // override to implement the callback. - virtual void execute(InterruptArguments *args) = 0; - - void leave_callback(); - }; + os::SuspendResume sr; private: - - Sync_Interrupt_Callback * volatile _current_callback; - enum { - callback_in_progress = 1 - }; - Mutex * _current_callback_lock; // only used on v8 + ucontext_t* _ucontext; public: - - int set_interrupt_callback (Sync_Interrupt_Callback * cb); - void remove_interrupt_callback(Sync_Interrupt_Callback * cb); - void do_interrupt_callbacks_at_interrupt(InterruptArguments *args); + ucontext_t* ucontext() const { return _ucontext; } + void set_ucontext(ucontext_t* ptr) { _ucontext = ptr; } + static void SR_handler(Thread* thread, ucontext_t* uc); // *************************************************************** // java.lang.Thread.interrupt state.
--- a/src/os/solaris/vm/os_share_solaris.hpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/os/solaris/vm/os_share_solaris.hpp Fri Jun 21 15:56:24 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,28 +27,6 @@ // Defines the interfaces to Solaris operating systems that vary across platforms - -// This is a simple callback that just fetches a PC for an interrupted thread. -// The thread need not be suspended and the fetched PC is just a hint. -// Returned PC and nPC are not necessarily consecutive. -// This one is currently used for profiling the VMThread ONLY! - -// Must be synchronous -class GetThreadPC_Callback : public OSThread::Sync_Interrupt_Callback { - private: - ExtendedPC _addr; - - public: - - GetThreadPC_Callback(Monitor *sync) : - OSThread::Sync_Interrupt_Callback(sync) { } - ExtendedPC addr() const { return _addr; } - - void set_addr(ExtendedPC addr) { _addr = addr; } - - void execute(OSThread::InterruptArguments *args); -}; - // misc extern "C" { void signalHandler(int, siginfo_t*, void*);
--- a/src/os/solaris/vm/os_solaris.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/os/solaris/vm/os_solaris.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -240,6 +240,8 @@ static int pthread_cond_default_init(cond_t *cv, int scope, void *arg){ memset(cv, 0, sizeof(cond_t)); return 0; } } +static void unpackTime(timespec* absTime, bool isAbsolute, jlong time); + // Thread Local Storage // This is common to all Solaris platforms so it is defined here, // in this common file. @@ -2580,6 +2582,57 @@ return CAST_FROM_FN_PTR(void*, UserHandler); } +class Semaphore : public StackObj { + public: + Semaphore(); + ~Semaphore(); + void signal(); + void wait(); + bool trywait(); + bool timedwait(unsigned int sec, int nsec); + private: + sema_t _semaphore; +}; + + +Semaphore::Semaphore() { + sema_init(&_semaphore, 0, NULL, NULL); +} + +Semaphore::~Semaphore() { + sema_destroy(&_semaphore); +} + +void Semaphore::signal() { + sema_post(&_semaphore); +} + +void Semaphore::wait() { + sema_wait(&_semaphore); +} + +bool Semaphore::trywait() { + return sema_trywait(&_semaphore) == 0; +} + +bool Semaphore::timedwait(unsigned int sec, int nsec) { + struct timespec ts; + unpackTime(&ts, false, (sec * NANOSECS_PER_SEC) + nsec); + + while (1) { + int result = sema_timedwait(&_semaphore, &ts); + if (result == 0) { + return true; + } else if (errno == EINTR) { + continue; + } else if (errno == ETIME) { + return false; + } else { + return false; + } + } +} + extern "C" { typedef void (*sa_handler_t)(int); typedef void (*sa_sigaction_t)(int, siginfo_t *, void *); @@ -4164,6 +4217,68 @@ schedctl_start(schedctl_init()); } +static void resume_clear_context(OSThread *osthread) { + osthread->set_ucontext(NULL); +} + +static void suspend_save_context(OSThread *osthread, ucontext_t* context) { + osthread->set_ucontext(context); +} + +static Semaphore sr_semaphore; + +void os::Solaris::SR_handler(Thread* thread, ucontext_t* uc) { + // Save and restore errno to avoid confusing native code with EINTR + // after sigsuspend. + int old_errno = errno; + + OSThread* osthread = thread->osthread(); + assert(thread->is_VM_thread() || thread->is_Java_thread(), "Must be VMThread or JavaThread"); + + os::SuspendResume::State current = osthread->sr.state(); + if (current == os::SuspendResume::SR_SUSPEND_REQUEST) { + suspend_save_context(osthread, uc); + + // attempt to switch the state, we assume we had a SUSPEND_REQUEST + os::SuspendResume::State state = osthread->sr.suspended(); + if (state == os::SuspendResume::SR_SUSPENDED) { + sigset_t suspend_set; // signals for sigsuspend() + + // get current set of blocked signals and unblock resume signal + thr_sigsetmask(SIG_BLOCK, NULL, &suspend_set); + sigdelset(&suspend_set, os::Solaris::SIGasync()); + + sr_semaphore.signal(); + // wait here until we are resumed + while (1) { + sigsuspend(&suspend_set); + + os::SuspendResume::State result = osthread->sr.running(); + if (result == os::SuspendResume::SR_RUNNING) { + sr_semaphore.signal(); + break; + } + } + + } else if (state == os::SuspendResume::SR_RUNNING) { + // request was cancelled, continue + } else { + ShouldNotReachHere(); + } + + resume_clear_context(osthread); + } else if (current == os::SuspendResume::SR_RUNNING) { + // request was cancelled, continue + } else if (current == os::SuspendResume::SR_WAKEUP_REQUEST) { + // ignore + } else { + // ignore + } + + errno = old_errno; +} + + void os::interrupt(Thread* thread) { assert(Thread::current() == thread || Threads_lock->owned_by_self(), "possibility of dangling Thread pointer"); @@ -4247,6 +4362,116 @@ return buf[0] == 'y' || buf[0] == 'Y'; } +static int sr_notify(OSThread* osthread) { + int status = thr_kill(osthread->thread_id(), os::Solaris::SIGasync()); + assert_status(status == 0, status, "thr_kill"); + return status; +} + +// "Randomly" selected value for how long we want to spin +// before bailing out on suspending a thread, also how often +// we send a signal to a thread we want to resume +static const int RANDOMLY_LARGE_INTEGER = 1000000; +static const int RANDOMLY_LARGE_INTEGER2 = 100; + +static bool do_suspend(OSThread* osthread) { + assert(osthread->sr.is_running(), "thread should be running"); + assert(!sr_semaphore.trywait(), "semaphore has invalid state"); + + // mark as suspended and send signal + if (osthread->sr.request_suspend() != os::SuspendResume::SR_SUSPEND_REQUEST) { + // failed to switch, state wasn't running? + ShouldNotReachHere(); + return false; + } + + if (sr_notify(osthread) != 0) { + ShouldNotReachHere(); + } + + // managed to send the signal and switch to SUSPEND_REQUEST, now wait for SUSPENDED + while (true) { + if (sr_semaphore.timedwait(0, 2000 * NANOSECS_PER_MILLISEC)) { + break; + } else { + // timeout + os::SuspendResume::State cancelled = osthread->sr.cancel_suspend(); + if (cancelled == os::SuspendResume::SR_RUNNING) { + return false; + } else if (cancelled == os::SuspendResume::SR_SUSPENDED) { + // make sure that we consume the signal on the semaphore as well + sr_semaphore.wait(); + break; + } else { + ShouldNotReachHere(); + return false; + } + } + } + + guarantee(osthread->sr.is_suspended(), "Must be suspended"); + return true; +} + +static void do_resume(OSThread* osthread) { + assert(osthread->sr.is_suspended(), "thread should be suspended"); + assert(!sr_semaphore.trywait(), "invalid semaphore state"); + + if (osthread->sr.request_wakeup() != os::SuspendResume::SR_WAKEUP_REQUEST) { + // failed to switch to WAKEUP_REQUEST + ShouldNotReachHere(); + return; + } + + while (true) { + if (sr_notify(osthread) == 0) { + if (sr_semaphore.timedwait(0, 2 * NANOSECS_PER_MILLISEC)) { + if (osthread->sr.is_running()) { + return; + } + } + } else { + ShouldNotReachHere(); + } + } + + guarantee(osthread->sr.is_running(), "Must be running!"); +} + +void os::SuspendedThreadTask::internal_do_task() { + if (do_suspend(_thread->osthread())) { + SuspendedThreadTaskContext context(_thread, _thread->osthread()->ucontext()); + do_task(context); + do_resume(_thread->osthread()); + } +} + +class PcFetcher : public os::SuspendedThreadTask { +public: + PcFetcher(Thread* thread) : os::SuspendedThreadTask(thread) {} + ExtendedPC result(); +protected: + void do_task(const os::SuspendedThreadTaskContext& context); +private: + ExtendedPC _epc; +}; + +ExtendedPC PcFetcher::result() { + guarantee(is_done(), "task is not done yet."); + return _epc; +} + +void PcFetcher::do_task(const os::SuspendedThreadTaskContext& context) { + Thread* thread = context.thread(); + OSThread* osthread = thread->osthread(); + if (osthread->ucontext() != NULL) { + _epc = os::Solaris::ucontext_get_pc((ucontext_t *) context.ucontext()); + } else { + // NULL context is unexpected, double-check this is the VMThread + guarantee(thread->is_VM_thread(), "can only be called for VMThread"); + } +} + // A lightweight implementation that does not suspend the target thread and // thus returns only a hint. Used for profiling only! ExtendedPC os::get_thread_pc(Thread* thread) { @@ -4254,21 +4479,9 @@ assert(Thread::current()->is_Watcher_thread(), "Must be watcher and own Threads_lock"); // For now, is only used to profile the VM Thread assert(thread->is_VM_thread(), "Can only be called for VMThread"); - ExtendedPC epc; - - GetThreadPC_Callback cb(ProfileVM_lock); - OSThread *osthread = thread->osthread(); - const int time_to_wait = 400; // 400ms wait for initial response - int status = cb.interrupt(thread, time_to_wait); - - if (cb.is_done() ) { - epc = cb.addr(); - } else { - DEBUG_ONLY(tty->print_cr("Failed to get pc for thread: %d got %d status", - osthread->thread_id(), status);); - // epc is already NULL - } - return epc; + PcFetcher fetcher(thread); + fetcher.run(); + return fetcher.result(); }
--- a/src/os/solaris/vm/os_solaris.hpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/os/solaris/vm/os_solaris.hpp Fri Jun 21 15:56:24 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -127,7 +127,6 @@ static void set_SIGinterrupt(int newsig) { _SIGinterrupt = newsig; } static void set_SIGasync(int newsig) { _SIGasync = newsig; } - public: // Large Page Support--ISM. static bool largepage_range(char* addr, size_t size); @@ -145,6 +144,7 @@ static intptr_t* ucontext_get_sp(ucontext_t* uc); // ucontext_get_fp() is only used by Solaris X86 (see note below) static intptr_t* ucontext_get_fp(ucontext_t* uc); + static address ucontext_get_pc(ucontext_t* uc); // For Analyzer Forte AsyncGetCallTrace profiling support: // Parameter ret_fp is only used by Solaris X86. @@ -157,6 +157,8 @@ static void hotspot_sigmask(Thread* thread); + // SR_handler + static void SR_handler(Thread* thread, ucontext_t* uc); protected: // Solaris-specific interface goes here static julong available_memory();
--- a/src/os/windows/vm/os_windows.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/os/windows/vm/os_windows.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -813,15 +813,21 @@ return result; } -// For now, we say that Windows does not support vtime. I have no idea -// whether it can actually be made to (DLD, 9/13/05). - -bool os::supports_vtime() { return false; } +bool os::supports_vtime() { return true; } bool os::enable_vtime() { return false; } bool os::vtime_enabled() { return false; } + double os::elapsedVTime() { - // better than nothing, but not much - return elapsedTime(); + FILETIME created; + FILETIME exited; + FILETIME kernel; + FILETIME user; + if (GetThreadTimes(GetCurrentThread(), &created, &exited, &kernel, &user) != 0) { + // the resolution of windows_to_java_time() should be sufficient (ms) + return (double) (windows_to_java_time(kernel) + windows_to_java_time(user)) / MILLIUNITS; + } else { + return elapsedTime(); + } } jlong os::javaTimeMillis() { @@ -944,6 +950,8 @@ MINIDUMP_TYPE dumpType; static const char* cwd; +// Default is to always create dump for debug builds, on product builds only dump on server versions of Windows. +#ifndef ASSERT // If running on a client version of Windows and user has not explicitly enabled dumping if (!os::win32::is_windows_server() && !CreateMinidumpOnCrash) { VMError::report_coredump_status("Minidumps are not enabled by default on client versions of Windows", false); @@ -953,6 +961,12 @@ VMError::report_coredump_status("Minidump has been disabled from the command line", false); return; } +#else + if (!FLAG_IS_DEFAULT(CreateMinidumpOnCrash) && !CreateMinidumpOnCrash) { + VMError::report_coredump_status("Minidump has been disabled from the command line", false); + return; + } +#endif dbghelp = os::win32::load_Windows_dll("DBGHELP.DLL", NULL, 0); @@ -1004,7 +1018,21 @@ // the dump types we really want. If first call fails, lets fall back to just use MiniDumpWithFullMemory then. if (_MiniDumpWriteDump(hProcess, processId, dumpFile, dumpType, pmei, NULL, NULL) == false && _MiniDumpWriteDump(hProcess, processId, dumpFile, (MINIDUMP_TYPE)MiniDumpWithFullMemory, pmei, NULL, NULL) == false) { - VMError::report_coredump_status("Call to MiniDumpWriteDump() failed", false); + DWORD error = GetLastError(); + LPTSTR msgbuf = NULL; + + if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, error, 0, (LPTSTR)&msgbuf, 0, NULL) != 0) { + + jio_snprintf(buffer, bufferSize, "Call to MiniDumpWriteDump() failed (Error 0x%x: %s)", error, msgbuf); + LocalFree(msgbuf); + } else { + // Call to FormatMessage failed, just include the result from GetLastError + jio_snprintf(buffer, bufferSize, "Call to MiniDumpWriteDump() failed (Error 0x%x)", error); + } + VMError::report_coredump_status(buffer, false); } else { VMError::report_coredump_status(buffer, true); } @@ -5020,6 +5048,71 @@ return ::setsockopt(fd, level, optname, optval, optlen); } +// WINDOWS CONTEXT Flags for THREAD_SAMPLING +#if defined(IA32) +# define sampling_context_flags (CONTEXT_FULL | CONTEXT_FLOATING_POINT | CONTEXT_EXTENDED_REGISTERS) +#elif defined (AMD64) +# define sampling_context_flags (CONTEXT_FULL | CONTEXT_FLOATING_POINT) +#endif + +// returns true if thread could be suspended, +// false otherwise +static bool do_suspend(HANDLE* h) { + if (h != NULL) { + if (SuspendThread(*h) != ~0) { + return true; + } + } + return false; +} + +// resume the thread +// calling resume on an active thread is a no-op +static void do_resume(HANDLE* h) { + if (h != NULL) { + ResumeThread(*h); + } +} + +// retrieve a suspend/resume context capable handle +// from the tid. Caller validates handle return value. +void get_thread_handle_for_extended_context(HANDLE* h, OSThread::thread_id_t tid) { + if (h != NULL) { + *h = OpenThread(THREAD_SUSPEND_RESUME | THREAD_GET_CONTEXT | THREAD_QUERY_INFORMATION, FALSE, tid); + } +} + +// +// Thread sampling implementation +// +void os::SuspendedThreadTask::internal_do_task() { + CONTEXT ctxt; + HANDLE h = NULL; + + // get context capable handle for thread + get_thread_handle_for_extended_context(&h, _thread->osthread()->thread_id()); + + // sanity + if (h == NULL || h == INVALID_HANDLE_VALUE) { + return; + } + + // suspend the thread + if (do_suspend(&h)) { + ctxt.ContextFlags = sampling_context_flags; + // get thread context + GetThreadContext(h, &ctxt); + SuspendedThreadTaskContext context(_thread, &ctxt); + // pass context to Thread Sampling impl + do_task(context); + // resume thread + do_resume(&h); + } + + // close handle + CloseHandle(h); +} + // Kernel32 API typedef SIZE_T (WINAPI* GetLargePageMinimum_Fn)(void);
--- a/src/os_cpu/bsd_x86/vm/thread_bsd_x86.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/os_cpu/bsd_x86/vm/thread_bsd_x86.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,10 +30,16 @@ // currently interrupted by SIGPROF bool JavaThread::pd_get_top_frame_for_signal_handler(frame* fr_addr, void* ucontext, bool isInJava) { + assert(Thread::current() == this, "caller must be current thread"); + return pd_get_top_frame(fr_addr, ucontext, isInJava); +} - assert(Thread::current() == this, "caller must be current thread"); +bool JavaThread::pd_get_top_frame_for_profiling(frame* fr_addr, void* ucontext, bool isInJava) { + return pd_get_top_frame(fr_addr, ucontext, isInJava); +} + +bool JavaThread::pd_get_top_frame(frame* fr_addr, void* ucontext, bool isInJava) { assert(this->is_Java_thread(), "must be JavaThread"); - JavaThread* jt = (JavaThread *)this; // If we have a last_Java_frame, then we should use it even if
--- a/src/os_cpu/bsd_x86/vm/thread_bsd_x86.hpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/os_cpu/bsd_x86/vm/thread_bsd_x86.hpp Fri Jun 21 15:56:24 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -61,6 +61,13 @@ bool pd_get_top_frame_for_signal_handler(frame* fr_addr, void* ucontext, bool isInJava); + bool pd_get_top_frame_for_profiling(frame* fr_addr, void* ucontext, + bool isInJava); + +private: + bool pd_get_top_frame(frame* fr_addr, void* ucontext, bool isInJava); +public: + // These routines are only used on cpu architectures that // have separate register stacks (Itanium). static bool register_stack_overflow() { return false; }
--- a/src/os_cpu/linux_x86/vm/linux_x86_32.s Thu Jun 20 16:30:44 2013 -0700 +++ b/src/os_cpu/linux_x86/vm/linux_x86_32.s Fri Jun 21 15:56:24 2013 -0700 @@ -241,7 +241,7 @@ jbe 2f # <= 32 dwords rep; smovl jmp 4f - .=.+8 + .space 8 2: subl %esi,%edi .p2align 4,,15 3: movl (%esi),%edx @@ -378,7 +378,7 @@ rep; smovl jmp 4f # copy aligned dwords - .=.+5 + .space 5 2: subl %esi,%edi .p2align 4,,15 3: movl (%esi),%edx @@ -454,7 +454,7 @@ popl %edi popl %esi ret - .=.+10 + .space 10 2: subl %esi,%edi jmp 4f .p2align 4,,15
--- a/src/os_cpu/linux_x86/vm/os_linux_x86.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/os_cpu/linux_x86/vm/os_linux_x86.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -93,6 +93,10 @@ register void *esp; __asm__("mov %%"SPELL_REG_SP", %0":"=r"(esp)); return (address) ((char*)esp + sizeof(long)*2); +#elif defined(__clang__) + intptr_t* esp; + __asm__ __volatile__ ("mov %%"SPELL_REG_SP", %0":"=r"(esp):); + return (address) esp; #else register void *esp __asm__ (SPELL_REG_SP); return (address) esp; @@ -175,6 +179,9 @@ #ifdef SPARC_WORKS register intptr_t **ebp; __asm__("mov %%"SPELL_REG_FP", %0":"=r"(ebp)); +#elif defined(__clang__) + intptr_t **ebp; + __asm__ __volatile__ ("mov %%"SPELL_REG_FP", %0":"=r"(ebp):); #else register intptr_t **ebp __asm__ (SPELL_REG_FP); #endif
--- a/src/os_cpu/linux_x86/vm/thread_linux_x86.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/os_cpu/linux_x86/vm/thread_linux_x86.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,8 +32,15 @@ void* ucontext, bool isInJava) { assert(Thread::current() == this, "caller must be current thread"); + return pd_get_top_frame(fr_addr, ucontext, isInJava); +} + +bool JavaThread::pd_get_top_frame_for_profiling(frame* fr_addr, void* ucontext, bool isInJava) { + return pd_get_top_frame(fr_addr, ucontext, isInJava); +} + +bool JavaThread::pd_get_top_frame(frame* fr_addr, void* ucontext, bool isInJava) { assert(this->is_Java_thread(), "must be JavaThread"); - JavaThread* jt = (JavaThread *)this; // If we have a last_Java_frame, then we should use it even if
--- a/src/os_cpu/linux_x86/vm/thread_linux_x86.hpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/os_cpu/linux_x86/vm/thread_linux_x86.hpp Fri Jun 21 15:56:24 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -61,6 +61,11 @@ bool pd_get_top_frame_for_signal_handler(frame* fr_addr, void* ucontext, bool isInJava); + bool pd_get_top_frame_for_profiling(frame* fr_addr, void* ucontext, bool isInJava); +private: + bool pd_get_top_frame(frame* fr_addr, void* ucontext, bool isInJava); +public: + // These routines are only used on cpu architectures that // have separate register stacks (Itanium). static bool register_stack_overflow() { return false; }
--- a/src/os_cpu/solaris_sparc/vm/os_solaris_sparc.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/os_cpu/solaris_sparc/vm/os_solaris_sparc.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -194,6 +194,11 @@ return NULL; } +address os::Solaris::ucontext_get_pc(ucontext_t *uc) { + return (address) uc->uc_mcontext.gregs[REG_PC]; +} + + // For Forte Analyzer AsyncGetCallTrace profiling support - thread // is currently interrupted by SIGPROF. // @@ -265,22 +270,6 @@ } } - -void GetThreadPC_Callback::execute(OSThread::InterruptArguments *args) { - Thread* thread = args->thread(); - ucontext_t* uc = args->ucontext(); - intptr_t* sp; - - assert(ProfileVM && thread->is_VM_thread(), "just checking"); - - // Skip the mcontext corruption verification. If if occasionally - // things get corrupt, it is ok for profiling - we will just get an unresolved - // function name - ExtendedPC new_addr((address)uc->uc_mcontext.gregs[REG_PC]); - _addr = new_addr; -} - - static int threadgetstate(thread_t tid, int *flags, lwpid_t *lwp, stack_t *ss, gregset_t rs, lwpstatus_t *lwpstatus) { char lwpstatusfile[PROCFILE_LENGTH]; int lwpfd, err; @@ -358,13 +347,8 @@ guarantee(sig != os::Solaris::SIGinterrupt(), "Can not chain VM interrupt signal, try -XX:+UseAltSigs"); if (sig == os::Solaris::SIGasync()) { - if (thread) { - OSThread::InterruptArguments args(thread, uc); - thread->osthread()->do_interrupt_callbacks_at_interrupt(&args); - return true; - } else if (vmthread) { - OSThread::InterruptArguments args(vmthread, uc); - vmthread->osthread()->do_interrupt_callbacks_at_interrupt(&args); + if (thread || vmthread) { + OSThread::SR_handler(t, uc); return true; } else if (os::Solaris::chained_handler(sig, info, ucVoid)) { return true;
--- a/src/os_cpu/solaris_sparc/vm/thread_solaris_sparc.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/os_cpu/solaris_sparc/vm/thread_solaris_sparc.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,11 +36,21 @@ void* ucontext, bool isInJava) { assert(Thread::current() == this, "caller must be current thread"); + return pd_get_top_frame(fr_addr, ucontext, isInJava, true); +} + +bool JavaThread::pd_get_top_frame_for_profiling(frame* fr_addr, void* ucontext, bool isInJava) { + // get ucontext somehow + return pd_get_top_frame(fr_addr, ucontext, isInJava, false); +} + +bool JavaThread::pd_get_top_frame(frame* fr_addr, + void* ucontext, bool isInJava, bool makeWalkable) { assert(this->is_Java_thread(), "must be JavaThread"); JavaThread* jt = (JavaThread *)this; - if (!isInJava) { + if (!isInJava && makeWalkable) { // make_walkable flushes register windows and grabs last_Java_pc // which can not be done if the ucontext sp matches last_Java_sp // stack walking utilities assume last_Java_pc set if marked flushed
--- a/src/os_cpu/solaris_sparc/vm/thread_solaris_sparc.hpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/os_cpu/solaris_sparc/vm/thread_solaris_sparc.hpp Fri Jun 21 15:56:24 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -93,6 +93,11 @@ bool pd_get_top_frame_for_signal_handler(frame* fr_addr, void* ucontext, bool isInJava); + bool pd_get_top_frame_for_profiling(frame* fr_addr, void* ucontext, bool isInJava); +private: + bool pd_get_top_frame(frame* fr_addr, void* ucontext, bool isInJava, bool makeWalkable); +public: + // These routines are only used on cpu architectures that // have separate register stacks (Itanium). static bool register_stack_overflow() { return false; }
--- a/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -183,6 +183,10 @@ return (intptr_t*)uc->uc_mcontext.gregs[REG_FP]; } +address os::Solaris::ucontext_get_pc(ucontext_t *uc) { + return (address) uc->uc_mcontext.gregs[REG_PC]; +} + // For Forte Analyzer AsyncGetCallTrace profiling support - thread // is currently interrupted by SIGPROF. // @@ -252,22 +256,6 @@ } } -// This is a simple callback that just fetches a PC for an interrupted thread. -// The thread need not be suspended and the fetched PC is just a hint. -// This one is currently used for profiling the VMThread ONLY! - -// Must be synchronous -void GetThreadPC_Callback::execute(OSThread::InterruptArguments *args) { - Thread* thread = args->thread(); - ucontext_t* uc = args->ucontext(); - intptr_t* sp; - - assert(ProfileVM && thread->is_VM_thread(), "just checking"); - - ExtendedPC new_addr((address)uc->uc_mcontext.gregs[REG_PC]); - _addr = new_addr; -} - static int threadgetstate(thread_t tid, int *flags, lwpid_t *lwp, stack_t *ss, gregset_t rs, lwpstatus_t *lwpstatus) { char lwpstatusfile[PROCFILE_LENGTH]; int lwpfd, err; @@ -419,14 +407,8 @@ guarantee(sig != os::Solaris::SIGinterrupt(), "Can not chain VM interrupt signal, try -XX:+UseAltSigs"); if (sig == os::Solaris::SIGasync()) { - if(thread){ - OSThread::InterruptArguments args(thread, uc); - thread->osthread()->do_interrupt_callbacks_at_interrupt(&args); - return true; - } - else if(vmthread){ - OSThread::InterruptArguments args(vmthread, uc); - vmthread->osthread()->do_interrupt_callbacks_at_interrupt(&args); + if(thread || vmthread){ + OSThread::SR_handler(t, uc); return true; } else if (os::Solaris::chained_handler(sig, info, ucVoid)) { return true;
--- a/src/os_cpu/solaris_x86/vm/thread_solaris_x86.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/os_cpu/solaris_x86/vm/thread_solaris_x86.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,8 +30,17 @@ // currently interrupted by SIGPROF bool JavaThread::pd_get_top_frame_for_signal_handler(frame* fr_addr, void* ucontext, bool isInJava) { + assert(Thread::current() == this, "caller must be current thread"); + return pd_get_top_frame(fr_addr, ucontext, isInJava); +} - assert(Thread::current() == this, "caller must be current thread"); +bool JavaThread::pd_get_top_frame_for_profiling(frame* fr_addr, + void* ucontext, bool isInJava) { + return pd_get_top_frame(fr_addr, ucontext, isInJava); +} + +bool JavaThread::pd_get_top_frame(frame* fr_addr, + void* ucontext, bool isInJava) { assert(this->is_Java_thread(), "must be JavaThread"); JavaThread* jt = (JavaThread *)this;
--- a/src/os_cpu/solaris_x86/vm/thread_solaris_x86.hpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/os_cpu/solaris_x86/vm/thread_solaris_x86.hpp Fri Jun 21 15:56:24 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -54,6 +54,12 @@ bool pd_get_top_frame_for_signal_handler(frame* fr_addr, void* ucontext, bool isInJava); + bool pd_get_top_frame_for_profiling(frame* fr_addr, void* ucontext, + bool isInJava); +private: + bool pd_get_top_frame(frame* fr_addr, void* ucontext, + bool isInJava); +public: // These routines are only used on cpu architectures that // have separate register stacks (Itanium).
--- a/src/os_cpu/windows_x86/vm/thread_windows_x86.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/os_cpu/windows_x86/vm/thread_windows_x86.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,6 +32,15 @@ void* ucontext, bool isInJava) { assert(Thread::current() == this, "caller must be current thread"); + return pd_get_top_frame(fr_addr, ucontext, isInJava); +} + +bool JavaThread::pd_get_top_frame_for_profiling(frame* fr_addr, void* ucontext, bool isInJava) { + return pd_get_top_frame(fr_addr, ucontext, isInJava); +} + +bool JavaThread::pd_get_top_frame(frame* fr_addr, void* ucontext, bool isInJava) { + assert(this->is_Java_thread(), "must be JavaThread"); JavaThread* jt = (JavaThread *)this; @@ -87,4 +96,3 @@ } void JavaThread::cache_global_variables() { } -
--- a/src/os_cpu/windows_x86/vm/thread_windows_x86.hpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/os_cpu/windows_x86/vm/thread_windows_x86.hpp Fri Jun 21 15:56:24 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -58,6 +58,12 @@ bool pd_get_top_frame_for_signal_handler(frame* fr_addr, void* ucontext, bool isInJava); + bool pd_get_top_frame_for_profiling(frame* fr_addr, void* ucontext, bool isInJava); + +private: + bool pd_get_top_frame(frame* fr_addr, void* ucontext, bool isInJava); + + public: // These routines are only used on cpu architectures that // have separate register stacks (Itanium). static bool register_stack_overflow() { return false; }
--- a/src/share/tools/ProjectCreator/BuildConfig.java Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/tools/ProjectCreator/BuildConfig.java Fri Jun 21 15:56:24 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -152,7 +152,7 @@ sysDefines.add("_WINDOWS"); sysDefines.add("HOTSPOT_BUILD_USER=\\\""+System.getProperty("user.name")+"\\\""); sysDefines.add("HOTSPOT_BUILD_TARGET=\\\""+get("Build")+"\\\""); - sysDefines.add("INCLUDE_TRACE"); + sysDefines.add("INCLUDE_TRACE=1"); sysDefines.add("_JNI_IMPLEMENTATION_"); if (vars.get("PlatformName").equals("Win32")) { sysDefines.add("HOTSPOT_LIB_ARCH=\\\"i386\\\"");
--- a/src/share/vm/adlc/archDesc.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/adlc/archDesc.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -29,8 +29,8 @@ static FILE *errfile = stderr; //--------------------------- utility functions ----------------------------- -inline char toUpper(char lower) { - return (('a' <= lower && lower <= 'z') ? (lower + ('A'-'a')) : lower); +inline char toUpper(char lower) { + return (('a' <= lower && lower <= 'z') ? ((char) (lower + ('A'-'a'))) : lower); } char *toUpper(const char *str) { char *upper = new char[strlen(str)+1];
--- a/src/share/vm/adlc/dict2.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/adlc/dict2.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -64,18 +64,18 @@ int i; // Precompute table of null character hashes - if( !initflag ) { // Not initializated yet? - xsum[0] = (1<<shft[0])+1; // Initialize + if (!initflag) { // Not initializated yet? + xsum[0] = (short) ((1 << shft[0]) + 1); // Initialize for( i = 1; i < MAXID; i++) { - xsum[i] = (1<<shft[i])+1+xsum[i-1]; + xsum[i] = (short) ((1 << shft[i]) + 1 + xsum[i-1]); } initflag = 1; // Never again } _size = 16; // Size is a power of 2 _cnt = 0; // Dictionary is empty - _bin = (bucket*)_arena->Amalloc_4(sizeof(bucket)*_size); - memset(_bin,0,sizeof(bucket)*_size); + _bin = (bucket*)_arena->Amalloc_4(sizeof(bucket) * _size); + memset(_bin, 0, sizeof(bucket) * _size); } //------------------------------~Dict------------------------------------------ @@ -287,11 +287,11 @@ register int sum = 0; register const char *s = (const char *)t; - while( ((c = s[k]) != '\0') && (k < MAXID-1) ) { // Get characters till nul - c = (c<<1)+1; // Characters are always odd! - sum += c + (c<<shft[k++]); // Universal hash function + while (((c = s[k]) != '\0') && (k < MAXID-1)) { // Get characters till nul + c = (char) ((c << 1) + 1); // Characters are always odd! + sum += c + (c << shft[k++]); // Universal hash function } - assert( k < (MAXID), "Exceeded maximum name length"); + assert(k < (MAXID), "Exceeded maximum name length"); return (int)((sum+xsum[k]) >> 1); // Hash key, un-modulo'd table size }
--- a/src/share/vm/adlc/formssel.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/adlc/formssel.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -796,11 +796,11 @@ return num_opnds; } -const char *InstructForm::opnd_ident(int idx) { +const char* InstructForm::opnd_ident(int idx) { return _components.at(idx)->_name; } -const char *InstructForm::unique_opnd_ident(int idx) { +const char* InstructForm::unique_opnd_ident(uint idx) { uint i; for (i = 1; i < num_opnds(); ++i) { if (unique_opnds_idx(i) == idx) { @@ -1315,36 +1315,36 @@ // Seach through operands to determine parameters unique positions. void InstructForm::set_unique_opnds() { uint* uniq_idx = NULL; - int nopnds = num_opnds(); + uint nopnds = num_opnds(); uint num_uniq = nopnds; - int i; + uint i; _uniq_idx_length = 0; - if ( nopnds > 0 ) { + if (nopnds > 0) { // Allocate index array. Worst case we're mapping from each // component back to an index and any DEF always goes at 0 so the // length of the array has to be the number of components + 1. _uniq_idx_length = _components.count() + 1; - uniq_idx = (uint*) malloc(sizeof(uint)*(_uniq_idx_length)); - for( i = 0; i < _uniq_idx_length; i++ ) { + uniq_idx = (uint*) malloc(sizeof(uint) * _uniq_idx_length); + for (i = 0; i < _uniq_idx_length; i++) { uniq_idx[i] = i; } } // Do it only if there is a match rule and no expand rule. With an // expand rule it is done by creating new mach node in Expand() // method. - if ( nopnds > 0 && _matrule != NULL && _exprule == NULL ) { + if (nopnds > 0 && _matrule != NULL && _exprule == NULL) { const char *name; uint count; bool has_dupl_use = false; _parameters.reset(); - while( (name = _parameters.iter()) != NULL ) { + while ((name = _parameters.iter()) != NULL) { count = 0; - int position = 0; - int uniq_position = 0; + uint position = 0; + uint uniq_position = 0; _components.reset(); Component *comp = NULL; - if( sets_result() ) { + if (sets_result()) { comp = _components.iter(); position++; } @@ -1352,11 +1352,11 @@ for (; (comp = _components.iter()) != NULL; ++position) { // When the first component is not a DEF, // leave space for the result operand! - if ( position==0 && (! comp->isa(Component::DEF)) ) { + if (position==0 && (!comp->isa(Component::DEF))) { ++position; } - if( strcmp(name, comp->_name)==0 ) { - if( ++count > 1 ) { + if (strcmp(name, comp->_name) == 0) { + if (++count > 1) { assert(position < _uniq_idx_length, "out of bounds"); uniq_idx[position] = uniq_position; has_dupl_use = true; @@ -1364,22 +1364,25 @@ uniq_position = position; } } - if( comp->isa(Component::DEF) - && comp->isa(Component::USE) ) { + if (comp->isa(Component::DEF) && comp->isa(Component::USE)) { ++position; - if( position != 1 ) + if (position != 1) --position; // only use two slots for the 1st USE_DEF } } } - if( has_dupl_use ) { - for( i = 1; i < nopnds; i++ ) - if( i != uniq_idx[i] ) + if (has_dupl_use) { + for (i = 1; i < nopnds; i++) { + if (i != uniq_idx[i]) { break; - int j = i; - for( ; i < nopnds; i++ ) - if( i == uniq_idx[i] ) + } + } + uint j = i; + for (; i < nopnds; i++) { + if (i == uniq_idx[i]) { uniq_idx[i] = j++; + } + } num_uniq = j; } } @@ -2216,21 +2219,27 @@ bool OperandForm::is_bound_register() const { - RegClass *reg_class = get_RegClass(); - if (reg_class == NULL) return false; - - const char * name = ideal_type(globalAD->globalNames()); - if (name == NULL) return false; - - int size = 0; - if (strcmp(name,"RegFlags")==0) size = 1; - if (strcmp(name,"RegI")==0) size = 1; - if (strcmp(name,"RegF")==0) size = 1; - if (strcmp(name,"RegD")==0) size = 2; - if (strcmp(name,"RegL")==0) size = 2; - if (strcmp(name,"RegN")==0) size = 1; - if (strcmp(name,"RegP")==0) size = globalAD->get_preproc_def("_LP64") ? 2 : 1; - if (size == 0) return false; + RegClass* reg_class = get_RegClass(); + if (reg_class == NULL) { + return false; + } + + const char* name = ideal_type(globalAD->globalNames()); + if (name == NULL) { + return false; + } + + uint size = 0; + if (strcmp(name, "RegFlags") == 0) size = 1; + if (strcmp(name, "RegI") == 0) size = 1; + if (strcmp(name, "RegF") == 0) size = 1; + if (strcmp(name, "RegD") == 0) size = 2; + if (strcmp(name, "RegL") == 0) size = 2; + if (strcmp(name, "RegN") == 0) size = 1; + if (strcmp(name, "RegP") == 0) size = globalAD->get_preproc_def("_LP64") ? 2 : 1; + if (size == 0) { + return false; + } return size == reg_class->size(); }
--- a/src/share/vm/adlc/formssel.hpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/adlc/formssel.hpp Fri Jun 21 15:56:24 2013 -0700 @@ -106,7 +106,7 @@ const char *_ins_pipe; // Instruction Scheduling description class uint *_uniq_idx; // Indexes of unique operands - int _uniq_idx_length; // Length of _uniq_idx array + uint _uniq_idx_length; // Length of _uniq_idx array uint _num_uniq; // Number of unique operands ComponentList _components; // List of Components matches MachNode's // operand structure @@ -272,14 +272,14 @@ void set_unique_opnds(); uint num_unique_opnds() { return _num_uniq; } uint unique_opnds_idx(int idx) { - if( _uniq_idx != NULL && idx > 0 ) { - assert(idx < _uniq_idx_length, "out of bounds"); - return _uniq_idx[idx]; - } else { - return idx; - } + if (_uniq_idx != NULL && idx > 0) { + assert((uint)idx < _uniq_idx_length, "out of bounds"); + return _uniq_idx[idx]; + } else { + return idx; + } } - const char *unique_opnd_ident(int idx); // Name of operand at unique idx. + const char *unique_opnd_ident(uint idx); // Name of operand at unique idx. // Operands which are only KILLs aren't part of the input array and // require special handling in some cases. Their position in this
--- a/src/share/vm/adlc/output_c.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/adlc/output_c.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -463,8 +463,9 @@ uint resources_used_exclusively = 0; for (pipeclass->_resUsage.reset(); - (piperesource = (const PipeClassResourceForm *)pipeclass->_resUsage.iter()) != NULL; ) + (piperesource = (const PipeClassResourceForm*)pipeclass->_resUsage.iter()) != NULL; ) { element_count++; + } // Pre-compute the string length int templen; @@ -482,8 +483,8 @@ for (i = rescount; i > 0; i /= 10) maskdigit++; - static const char * pipeline_use_cycle_mask = "Pipeline_Use_Cycle_Mask"; - static const char * pipeline_use_element = "Pipeline_Use_Element"; + static const char* pipeline_use_cycle_mask = "Pipeline_Use_Cycle_Mask"; + static const char* pipeline_use_element = "Pipeline_Use_Element"; templen = 1 + (int)(strlen(pipeline_use_cycle_mask) + (int)strlen(pipeline_use_element) + @@ -496,11 +497,12 @@ templen = 0; for (pipeclass->_resUsage.reset(); - (piperesource = (const PipeClassResourceForm *)pipeclass->_resUsage.iter()) != NULL; ) { + (piperesource = (const PipeClassResourceForm*)pipeclass->_resUsage.iter()) != NULL; ) { int used_mask = pipeline->_resdict[piperesource->_resource]->is_resource()->mask(); - if (!used_mask) + if (!used_mask) { fprintf(stderr, "*** used_mask is 0 ***\n"); + } resources_used |= used_mask; @@ -509,8 +511,9 @@ for (lb = 0; (used_mask & (1 << lb)) == 0; lb++); for (ub = 31; (used_mask & (1 << ub)) == 0; ub--); - if (lb == ub) + if (lb == ub) { resources_used_exclusively |= used_mask; + } int formatlen = sprintf(&resource_mask[templen], " %s(0x%0*x, %*d, %*d, %s %s(", @@ -526,7 +529,7 @@ int cycles = piperesource->_cycles; uint stage = pipeline->_stages.index(piperesource->_stage); - if (NameList::Not_in_list == stage) { + if ((uint)NameList::Not_in_list == stage) { fprintf(stderr, "pipeline_res_mask_initializer: " "semantic error: " @@ -534,8 +537,8 @@ piperesource->_stage); exit(1); } - uint upper_limit = stage+cycles-1; - uint lower_limit = stage-1; + uint upper_limit = stage + cycles - 1; + uint lower_limit = stage - 1; uint upper_idx = upper_limit >> 5; uint lower_idx = lower_limit >> 5; uint upper_position = upper_limit & 0x1f; @@ -543,7 +546,7 @@ uint mask = (((uint)1) << upper_position) - 1; - while ( upper_idx > lower_idx ) { + while (upper_idx > lower_idx) { res_mask[upper_idx--] |= mask; mask = (uint)-1; } @@ -565,8 +568,9 @@ } resource_mask[templen] = 0; - if (last_comma) + if (last_comma) { last_comma[0] = ' '; + } // See if the same string is in the table int ndx = pipeline_res_mask.index(resource_mask); @@ -580,7 +584,7 @@ fprintf(fp_cpp, "static const Pipeline_Use_Element pipeline_res_mask_%03d[%d] = {\n%s};\n\n", ndx+1, element_count, resource_mask); - char * args = new char [9 + 2*masklen + maskdigit]; + char* args = new char [9 + 2*masklen + maskdigit]; sprintf(args, "0x%0*x, 0x%0*x, %*d", masklen, resources_used, @@ -589,8 +593,9 @@ pipeline_res_args.addName(args); } - else + else { delete [] resource_mask; + } delete [] res_mask; //delete [] res_masks; @@ -1787,7 +1792,7 @@ // Skip first unique operands. for( i = 1; i < cur_num_opnds; i++ ) { comp = node->_components.iter(); - if( (int)i != node->unique_opnds_idx(i) ) { + if (i != node->unique_opnds_idx(i)) { break; } new_num_opnds++; @@ -1795,7 +1800,7 @@ // Replace not unique operands with next unique operands. for( ; i < cur_num_opnds; i++ ) { comp = node->_components.iter(); - int j = node->unique_opnds_idx(i); + uint j = node->unique_opnds_idx(i); // unique_opnds_idx(i) is unique if unique_opnds_idx(j) is not unique. if( j != node->unique_opnds_idx(j) ) { fprintf(fp," set_opnd_array(%d, opnd_array(%d)->clone(C)); // %s\n",
--- a/src/share/vm/c1/c1_LIRGenerator.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/c1/c1_LIRGenerator.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -2232,6 +2232,7 @@ // We still need to continue with the checks. if (src.is_constant()) { ciObject* src_con = src.get_jobject_constant(); + guarantee(src_con != NULL, "no source constant"); if (src_con->is_null_object()) { // The constant src object is null - We can skip
--- a/src/share/vm/classfile/classFileParser.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/classfile/classFileParser.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -39,6 +39,7 @@ #include "memory/gcLocker.hpp" #include "memory/metadataFactory.hpp" #include "memory/oopFactory.hpp" +#include "memory/referenceType.hpp" #include "memory/universe.inline.hpp" #include "oops/constantPool.hpp" #include "oops/fieldStreams.hpp" @@ -444,8 +445,8 @@ break; case JVM_REF_invokeStatic: case JVM_REF_invokeSpecial: - check_property( - tag.is_method() || tag.is_interface_method(), + check_property(tag.is_method() || + ((_major_version >= JAVA_8_VERSION) && tag.is_interface_method()), "Invalid constant pool index %u in class file %s (not a method)", ref_index, CHECK_(nullHandle)); break; @@ -3152,7 +3153,6 @@ } } } - int contended_count = nonstatic_contended_count; // Calculate the starting byte offsets @@ -3177,35 +3177,52 @@ next_nonstatic_field_offset = nonstatic_fields_start; + bool is_contended_class = parsed_annotations->is_contended(); + // Class is contended, pad before all the fields - if (parsed_annotations->is_contended()) { + if (is_contended_class) { next_nonstatic_field_offset += ContendedPaddingWidth; } - // Compute the non-contended fields count + // Compute the non-contended fields count. + // The packing code below relies on these counts to determine if some field + // can be squeezed into the alignment gap. Contended fields are obviously + // exempt from that. unsigned int nonstatic_double_count = fac->count[NONSTATIC_DOUBLE] - fac_contended.count[NONSTATIC_DOUBLE]; unsigned int nonstatic_word_count = fac->count[NONSTATIC_WORD] - fac_contended.count[NONSTATIC_WORD]; unsigned int nonstatic_short_count = fac->count[NONSTATIC_SHORT] - fac_contended.count[NONSTATIC_SHORT]; unsigned int nonstatic_byte_count = fac->count[NONSTATIC_BYTE] - fac_contended.count[NONSTATIC_BYTE]; unsigned int nonstatic_oop_count = fac->count[NONSTATIC_OOP] - fac_contended.count[NONSTATIC_OOP]; + // Total non-static fields count, including every contended field + unsigned int nonstatic_fields_count = fac->count[NONSTATIC_DOUBLE] + fac->count[NONSTATIC_WORD] + + fac->count[NONSTATIC_SHORT] + fac->count[NONSTATIC_BYTE] + + fac->count[NONSTATIC_OOP]; + bool super_has_nonstatic_fields = (_super_klass() != NULL && _super_klass->has_nonstatic_fields()); - bool has_nonstatic_fields = super_has_nonstatic_fields || - ((nonstatic_double_count + nonstatic_word_count + - nonstatic_short_count + nonstatic_byte_count + - nonstatic_oop_count) != 0); + bool has_nonstatic_fields = super_has_nonstatic_fields || (nonstatic_fields_count != 0); // Prepare list of oops for oop map generation. + // + // "offset" and "count" lists are describing the set of contiguous oop + // regions. offset[i] is the start of the i-th region, which then has + // count[i] oops following. Before we know how many regions are required, + // we pessimistically allocate the maps to fit all the oops into the + // distinct regions. + // + // TODO: We add +1 to always allocate non-zero resource arrays; we need + // to figure out if we still need to do this. int* nonstatic_oop_offsets; unsigned int* nonstatic_oop_counts; unsigned int nonstatic_oop_map_count = 0; + unsigned int max_nonstatic_oop_maps = fac->count[NONSTATIC_OOP] + 1; nonstatic_oop_offsets = NEW_RESOURCE_ARRAY_IN_THREAD( - THREAD, int, nonstatic_oop_count + 1); + THREAD, int, max_nonstatic_oop_maps); nonstatic_oop_counts = NEW_RESOURCE_ARRAY_IN_THREAD( - THREAD, unsigned int, nonstatic_oop_count + 1); + THREAD, unsigned int, max_nonstatic_oop_maps); first_nonstatic_oop_offset = 0; // will be set for first oop field @@ -3392,9 +3409,11 @@ int(nonstatic_oop_counts[nonstatic_oop_map_count - 1]) * heapOopSize ) { // Extend current oop map + assert(nonstatic_oop_map_count - 1 < max_nonstatic_oop_maps, "range check"); nonstatic_oop_counts[nonstatic_oop_map_count - 1] += 1; } else { // Create new oop map + assert(nonstatic_oop_map_count < max_nonstatic_oop_maps, "range check"); nonstatic_oop_offsets[nonstatic_oop_map_count] = real_offset; nonstatic_oop_counts [nonstatic_oop_map_count] = 1; nonstatic_oop_map_count += 1; @@ -3452,12 +3471,10 @@ // // Additionally, this should not break alignment for the fields, so we round the alignment up // for each field. - if (contended_count > 0) { + if (nonstatic_contended_count > 0) { // if there is at least one contended field, we need to have pre-padding for them - if (nonstatic_contended_count > 0) { - next_nonstatic_padded_offset += ContendedPaddingWidth; - } + next_nonstatic_padded_offset += ContendedPaddingWidth; // collect all contended groups BitMap bm(_cp->size()); @@ -3518,6 +3535,7 @@ next_nonstatic_padded_offset += heapOopSize; // Create new oop map + assert(nonstatic_oop_map_count < max_nonstatic_oop_maps, "range check"); nonstatic_oop_offsets[nonstatic_oop_map_count] = real_offset; nonstatic_oop_counts [nonstatic_oop_map_count] = 1; nonstatic_oop_map_count += 1; @@ -3554,18 +3572,17 @@ // handle static fields } - // Size of instances - int notaligned_offset = next_nonstatic_padded_offset; - // Entire class is contended, pad in the back. // This helps to alleviate memory contention effects for subclass fields // and/or adjacent object. - if (parsed_annotations->is_contended()) { - notaligned_offset += ContendedPaddingWidth; + if (is_contended_class) { + next_nonstatic_padded_offset += ContendedPaddingWidth; } - int nonstatic_fields_end = align_size_up(notaligned_offset, heapOopSize); - int instance_end = align_size_up(notaligned_offset, wordSize); + int notaligned_nonstatic_fields_end = next_nonstatic_padded_offset; + + int nonstatic_fields_end = align_size_up(notaligned_nonstatic_fields_end, heapOopSize); + int instance_end = align_size_up(notaligned_nonstatic_fields_end, wordSize); int static_fields_end = align_size_up(next_static_byte_offset, wordSize); int static_field_size = (static_fields_end - @@ -3579,6 +3596,14 @@ (instanceOopDesc::base_offset_in_bytes() + nonstatic_field_size*heapOopSize), wordSize) / wordSize), "consistent layout helper value"); + // Invariant: nonstatic_field end/start should only change if there are + // nonstatic fields in the class, or if the class is contended. We compare + // against the non-aligned value, so that end alignment will not fail the + // assert without actually having the fields. + assert((notaligned_nonstatic_fields_end == nonstatic_fields_start) || + is_contended_class || + (nonstatic_fields_count > 0), "double-check nonstatic start/end"); + // Number of non-static oop map blocks allocated at end of klass. const unsigned int total_oop_map_count = compute_oop_map_count(_super_klass, nonstatic_oop_map_count, @@ -4040,6 +4065,9 @@ } } + // Allocate mirror and initialize static fields + java_lang_Class::create_mirror(this_klass, protection_domain, CHECK_(nullHandle)); + #ifdef ASSERT if (ParseAllGenericSignatures) { @@ -4055,17 +4083,6 @@ this_klass(), &all_mirandas, CHECK_(nullHandle)); } - // Allocate mirror and initialize static fields - java_lang_Class::create_mirror(this_klass, CHECK_(nullHandle)); - - // Allocate a simple java object for locking during class initialization. - // This needs to be a java object because it can be held across a java call. - typeArrayOop r = oopFactory::new_typeArray(T_INT, 0, CHECK_NULL); - this_klass->set_init_lock(r); - - // TODO: Move these oops to the mirror - this_klass->set_protection_domain(protection_domain()); - // Update the loader_data graph. record_defined_class_dependencies(this_klass, CHECK_NULL);
--- a/src/share/vm/classfile/classLoaderData.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/classfile/classLoaderData.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -64,6 +64,11 @@ #include "utilities/growableArray.hpp" #include "utilities/ostream.hpp" +#if INCLUDE_TRACE + #include "trace/tracing.hpp" +#endif + + ClassLoaderData * ClassLoaderData::_the_null_class_loader_data = NULL; ClassLoaderData::ClassLoaderData(Handle h_class_loader, bool is_anonymous, Dependencies dependencies) : @@ -120,6 +125,12 @@ } } +void ClassLoaderData::classes_do(void f(Klass * const)) { + for (Klass* k = _klasses; k != NULL; k = k->next_link()) { + f(k); + } +} + void ClassLoaderData::classes_do(void f(InstanceKlass*)) { for (Klass* k = _klasses; k != NULL; k = k->next_link()) { if (k->oop_is_instance()) { @@ -583,6 +594,19 @@ } } +void ClassLoaderDataGraph::classes_do(void f(Klass* const)) { + for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) { + cld->classes_do(f); + } +} + +void ClassLoaderDataGraph::classes_unloading_do(void f(Klass* const)) { + assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint!"); + for (ClassLoaderData* cld = _unloading; cld != NULL; cld = cld->next()) { + cld->classes_do(f); + } +} + GrowableArray<ClassLoaderData*>* ClassLoaderDataGraph::new_clds() { assert(_head == NULL || _saved_head != NULL, "remember_new_clds(true) not called?"); @@ -687,6 +711,11 @@ dead->set_next(_unloading); _unloading = dead; } + + if (seen_dead_loader) { + post_class_unload_events(); + } + return seen_dead_loader; } @@ -702,6 +731,20 @@ Metaspace::purge(); } +void ClassLoaderDataGraph::post_class_unload_events(void) { +#if INCLUDE_TRACE + assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint!"); + if (Tracing::enabled()) { + if (Tracing::is_event_enabled(TraceClassUnloadEvent)) { + assert(_unloading != NULL, "need class loader data unload list!"); + _class_unload_time = Tracing::time(); + classes_unloading_do(&class_unload_event); + } + Tracing::on_unloading_classes(); + } +#endif +} + // CDS support // Global metaspaces for writing information to the shared archive. When @@ -769,3 +812,21 @@ class_loader()->print_value_on(out); } } + +#if INCLUDE_TRACE + +TracingTime ClassLoaderDataGraph::_class_unload_time; + +void ClassLoaderDataGraph::class_unload_event(Klass* const k) { + + // post class unload event + EventClassUnload event(UNTIMED); + event.set_endtime(_class_unload_time); + event.set_unloadedClass(k); + oop defining_class_loader = k->class_loader(); + event.set_definingClassLoader(defining_class_loader != NULL ? + defining_class_loader->klass() : (Klass*)NULL); + event.commit(); +} + +#endif /* INCLUDE_TRACE */
--- a/src/share/vm/classfile/classLoaderData.hpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/classfile/classLoaderData.hpp Fri Jun 21 15:56:24 2013 -0700 @@ -32,6 +32,10 @@ #include "runtime/mutex.hpp" #include "utilities/growableArray.hpp" +#if INCLUDE_TRACE +# include "trace/traceTime.hpp" +#endif + // // A class loader represents a linkset. Conceptually, a linkset identifies // the complete transitive closure of resolved links that a dynamic linker can @@ -49,6 +53,7 @@ class JNIMethodBlock; class JNIHandleBlock; class Metadebug; + // GC root for walking class loader data created class ClassLoaderDataGraph : public AllStatic { @@ -63,6 +68,7 @@ static ClassLoaderData* _saved_head; static ClassLoaderData* add(Handle class_loader, bool anonymous, TRAPS); + static void post_class_unload_events(void); public: static ClassLoaderData* find_or_create(Handle class_loader, TRAPS); static void purge(); @@ -71,6 +77,8 @@ static void always_strong_oops_do(OopClosure* blk, KlassClosure* klass_closure, bool must_claim); static void keep_alive_oops_do(OopClosure* blk, KlassClosure* klass_closure, bool must_claim); static void classes_do(KlassClosure* klass_closure); + static void classes_do(void f(Klass* const)); + static void classes_unloading_do(void f(Klass* const)); static bool do_unloading(BoolObjectClosure* is_alive); // CMS support. @@ -86,6 +94,12 @@ static bool contains(address x); static bool contains_loader_data(ClassLoaderData* loader_data); #endif + +#if INCLUDE_TRACE + private: + static TracingTime _class_unload_time; + static void class_unload_event(Klass* const k); +#endif }; // ClassLoaderData class @@ -171,7 +185,7 @@ void unload(); bool keep_alive() const { return _keep_alive; } bool is_alive(BoolObjectClosure* is_alive_closure) const; - + void classes_do(void f(Klass*)); void classes_do(void f(InstanceKlass*)); // Deallocate free list during class unloading.
--- a/src/share/vm/classfile/defaultMethods.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/classfile/defaultMethods.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -1349,6 +1349,7 @@ // Replace klass methods with new merged lists klass->set_methods(merged_methods); + klass->set_initial_method_idnum(new_size); ClassLoaderData* cld = klass->class_loader_data(); MetadataFactory::free_array(cld, original_methods);
--- a/src/share/vm/classfile/javaClasses.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/classfile/javaClasses.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -512,22 +512,22 @@ // If the offset was read from the shared archive, it was fixed up already if (!k->is_shared()) { - if (k->oop_is_instance()) { - // During bootstrap, java.lang.Class wasn't loaded so static field - // offsets were computed without the size added it. Go back and - // update all the static field offsets to included the size. - for (JavaFieldStream fs(InstanceKlass::cast(k())); !fs.done(); fs.next()) { - if (fs.access_flags().is_static()) { - int real_offset = fs.offset() + InstanceMirrorKlass::offset_of_static_fields(); - fs.set_offset(real_offset); + if (k->oop_is_instance()) { + // During bootstrap, java.lang.Class wasn't loaded so static field + // offsets were computed without the size added it. Go back and + // update all the static field offsets to included the size. + for (JavaFieldStream fs(InstanceKlass::cast(k())); !fs.done(); fs.next()) { + if (fs.access_flags().is_static()) { + int real_offset = fs.offset() + InstanceMirrorKlass::offset_of_static_fields(); + fs.set_offset(real_offset); + } } } } - } - create_mirror(k, CHECK); + create_mirror(k, Handle(NULL), CHECK); } -oop java_lang_Class::create_mirror(KlassHandle k, TRAPS) { +oop java_lang_Class::create_mirror(KlassHandle k, Handle protection_domain, TRAPS) { assert(k->java_mirror() == NULL, "should only assign mirror once"); // Use this moment of initialization to cache modifier_flags also, // to support Class.getModifiers(). Instance classes recalculate @@ -563,6 +563,16 @@ set_array_klass(comp_mirror(), k()); } else { assert(k->oop_is_instance(), "Must be"); + + // Allocate a simple java object for a lock. + // This needs to be a java object because during class initialization + // it can be held across a java call. + typeArrayOop r = oopFactory::new_typeArray(T_INT, 0, CHECK_NULL); + set_init_lock(mirror(), r); + + // Set protection domain also + set_protection_domain(mirror(), protection_domain()); + // Initialize static fields InstanceKlass::cast(k())->do_local_static_fields(&initialize_static_field, CHECK_NULL); } @@ -597,6 +607,34 @@ java_class->int_field_put(_static_oop_field_count_offset, size); } +oop java_lang_Class::protection_domain(oop java_class) { + assert(_protection_domain_offset != 0, "must be set"); + return java_class->obj_field(_protection_domain_offset); +} +void java_lang_Class::set_protection_domain(oop java_class, oop pd) { + assert(_protection_domain_offset != 0, "must be set"); + java_class->obj_field_put(_protection_domain_offset, pd); +} + +oop java_lang_Class::init_lock(oop java_class) { + assert(_init_lock_offset != 0, "must be set"); + return java_class->obj_field(_init_lock_offset); +} +void java_lang_Class::set_init_lock(oop java_class, oop init_lock) { + assert(_init_lock_offset != 0, "must be set"); + java_class->obj_field_put(_init_lock_offset, init_lock); +} + +objArrayOop java_lang_Class::signers(oop java_class) { + assert(_signers_offset != 0, "must be set"); + return (objArrayOop)java_class->obj_field(_signers_offset); +} +void java_lang_Class::set_signers(oop java_class, objArrayOop signers) { + assert(_signers_offset != 0, "must be set"); + java_class->obj_field_put(_signers_offset, (oop)signers); +} + + oop java_lang_Class::create_basic_type_mirror(const char* basic_type_name, BasicType type, TRAPS) { // This should be improved by adding a field at the Java level or by // introducing a new VM klass (see comment in ClassFileParser) @@ -923,7 +961,7 @@ // Read thread status value from threadStatus field in java.lang.Thread java class. java_lang_Thread::ThreadStatus java_lang_Thread::get_thread_status(oop java_thread) { - assert(Thread::current()->is_VM_thread() || + assert(Thread::current()->is_Watcher_thread() || Thread::current()->is_VM_thread() || JavaThread::current()->thread_state() == _thread_in_vm, "Java Thread is not running in vm"); // The threadStatus is only present starting in 1.5 @@ -2934,6 +2972,9 @@ int java_lang_Class::_array_klass_offset; int java_lang_Class::_oop_size_offset; int java_lang_Class::_static_oop_field_count_offset; +int java_lang_Class::_protection_domain_offset; +int java_lang_Class::_init_lock_offset; +int java_lang_Class::_signers_offset; GrowableArray<Klass*>* java_lang_Class::_fixup_mirror_list = NULL; int java_lang_Throwable::backtrace_offset; int java_lang_Throwable::detailMessage_offset;
--- a/src/share/vm/classfile/javaClasses.hpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/classfile/javaClasses.hpp Fri Jun 21 15:56:24 2013 -0700 @@ -208,7 +208,10 @@ macro(java_lang_Class, klass, intptr_signature, false) \ macro(java_lang_Class, array_klass, intptr_signature, false) \ macro(java_lang_Class, oop_size, int_signature, false) \ - macro(java_lang_Class, static_oop_field_count, int_signature, false) + macro(java_lang_Class, static_oop_field_count, int_signature, false) \ + macro(java_lang_Class, protection_domain, object_signature, false) \ + macro(java_lang_Class, init_lock, object_signature, false) \ + macro(java_lang_Class, signers, object_signature, false) class java_lang_Class : AllStatic { friend class VMStructs; @@ -222,15 +225,20 @@ static int _oop_size_offset; static int _static_oop_field_count_offset; + static int _protection_domain_offset; + static int _init_lock_offset; + static int _signers_offset; + static bool offsets_computed; static int classRedefinedCount_offset; static GrowableArray<Klass*>* _fixup_mirror_list; + static void set_init_lock(oop java_class, oop init_lock); public: static void compute_offsets(); // Instance creation - static oop create_mirror(KlassHandle k, TRAPS); + static oop create_mirror(KlassHandle k, Handle protection_domain, TRAPS); static void fixup_mirror(KlassHandle k, TRAPS); static oop create_basic_type_mirror(const char* basic_type_name, BasicType type, TRAPS); // Conversion @@ -262,6 +270,13 @@ static int classRedefinedCount(oop the_class_mirror); static void set_classRedefinedCount(oop the_class_mirror, int value); + // Support for embedded per-class oops + static oop protection_domain(oop java_class); + static void set_protection_domain(oop java_class, oop protection_domain); + static oop init_lock(oop java_class); + static objArrayOop signers(oop java_class); + static void set_signers(oop java_class, objArrayOop signers); + static int oop_size(oop java_class); static void set_oop_size(oop java_class, int size); static int static_oop_field_count(oop java_class);
--- a/src/share/vm/classfile/symbolTable.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/classfile/symbolTable.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -737,7 +737,7 @@ return result; } -void StringTable::unlink(BoolObjectClosure* is_alive) { +void StringTable::unlink_or_oops_do(BoolObjectClosure* is_alive, OopClosure* f) { // Readers of the table are unlocked, so we should only be removing // entries at a safepoint. assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint"); @@ -745,41 +745,31 @@ HashtableEntry<oop, mtSymbol>** p = the_table()->bucket_addr(i); HashtableEntry<oop, mtSymbol>* entry = the_table()->bucket(i); while (entry != NULL) { - // Shared entries are normally at the end of the bucket and if we run into - // a shared entry, then there is nothing more to remove. However, if we - // have rehashed the table, then the shared entries are no longer at the - // end of the bucket. - if (entry->is_shared() && !use_alternate_hashcode()) { - break; - } - assert(entry->literal() != NULL, "just checking"); - if (entry->is_shared() || is_alive->do_object_b(entry->literal())) { + assert(!entry->is_shared(), "CDS not used for the StringTable"); + + if (is_alive->do_object_b(entry->literal())) { + if (f != NULL) { + f->do_oop((oop*)entry->literal_addr()); + } p = entry->next_addr(); } else { *p = entry->next(); the_table()->free_entry(entry); } - entry = (HashtableEntry<oop, mtSymbol>*)HashtableEntry<oop, mtSymbol>::make_ptr(*p); + entry = *p; } } } void StringTable::oops_do(OopClosure* f) { for (int i = 0; i < the_table()->table_size(); ++i) { - HashtableEntry<oop, mtSymbol>** p = the_table()->bucket_addr(i); HashtableEntry<oop, mtSymbol>* entry = the_table()->bucket(i); while (entry != NULL) { + assert(!entry->is_shared(), "CDS not used for the StringTable"); + f->do_oop((oop*)entry->literal_addr()); - // Did the closure remove the literal from the table? - if (entry->literal() == NULL) { - assert(!entry->is_shared(), "immutable hashtable entry?"); - *p = entry->next(); - the_table()->free_entry(entry); - } else { - p = entry->next_addr(); - } - entry = (HashtableEntry<oop, mtSymbol>*)HashtableEntry<oop, mtSymbol>::make_ptr(*p); + entry = entry->next(); } } }
--- a/src/share/vm/classfile/symbolTable.hpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/classfile/symbolTable.hpp Fri Jun 21 15:56:24 2013 -0700 @@ -272,7 +272,10 @@ // GC support // Delete pointers to otherwise-unreachable objects. - static void unlink(BoolObjectClosure* cl); + static void unlink_or_oops_do(BoolObjectClosure* cl, OopClosure* f); + static void unlink(BoolObjectClosure* cl) { + unlink_or_oops_do(cl, NULL); + } // Invoke "f->do_oop" on the locations of all oops in the table. static void oops_do(OopClosure* f);
--- a/src/share/vm/classfile/systemDictionary.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/classfile/systemDictionary.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -56,6 +56,11 @@ #include "services/classLoadingService.hpp" #include "services/threadService.hpp" +#if INCLUDE_TRACE + #include "trace/tracing.hpp" + #include "trace/traceMacros.hpp" +#endif + Dictionary* SystemDictionary::_dictionary = NULL; PlaceholderTable* SystemDictionary::_placeholders = NULL; @@ -586,10 +591,15 @@ } -Klass* SystemDictionary::resolve_instance_class_or_null(Symbol* name, Handle class_loader, Handle protection_domain, TRAPS) { +Klass* SystemDictionary::resolve_instance_class_or_null(Symbol* name, + Handle class_loader, + Handle protection_domain, + TRAPS) { assert(name != NULL && !FieldType::is_array(name) && !FieldType::is_obj(name), "invalid class name"); + TracingTime class_load_start_time = Tracing::time(); + // UseNewReflection // Fix for 4474172; see evaluation for more details class_loader = Handle(THREAD, java_lang_ClassLoader::non_reflection_class_loader(class_loader())); @@ -804,8 +814,9 @@ // during compilations. MutexLocker mu(Compile_lock, THREAD); update_dictionary(d_index, d_hash, p_index, p_hash, - k, class_loader, THREAD); + k, class_loader, THREAD); } + if (JvmtiExport::should_post_class_load()) { Thread *thread = THREAD; assert(thread->is_Java_thread(), "thread->is_Java_thread()"); @@ -861,8 +872,8 @@ // This brackets the SystemDictionary updates for both defining // and initiating loaders MutexLocker mu(SystemDictionary_lock, THREAD); - placeholders()->find_and_remove(p_index, p_hash, name, loader_data, PlaceholderTable::LOAD_INSTANCE, THREAD); - SystemDictionary_lock->notify_all(); + placeholders()->find_and_remove(p_index, p_hash, name, loader_data, PlaceholderTable::LOAD_INSTANCE, THREAD); + SystemDictionary_lock->notify_all(); } } @@ -870,6 +881,8 @@ return NULL; } + post_class_load_event(class_load_start_time, k, class_loader); + #ifdef ASSERT { ClassLoaderData* loader_data = k->class_loader_data(); @@ -993,6 +1006,8 @@ TRAPS) { TempNewSymbol parsed_name = NULL; + TracingTime class_load_start_time = Tracing::time(); + ClassLoaderData* loader_data; if (host_klass.not_null()) { // Create a new CLD for anonymous class, that uses the same class loader @@ -1048,6 +1063,8 @@ assert(THREAD->is_Java_thread(), "thread->is_Java_thread()"); JvmtiExport::post_class_load((JavaThread *) THREAD, k()); } + + post_class_load_event(class_load_start_time, k, class_loader); } assert(host_klass.not_null() || cp_patches == NULL, "cp_patches only found with host_klass"); @@ -1435,6 +1452,7 @@ JvmtiExport::post_class_load((JavaThread *) THREAD, k()); } + } // Support parallel classloading @@ -1678,6 +1696,7 @@ } return newsize; } + // Assumes classes in the SystemDictionary are only unloaded at a safepoint // Note: anonymous classes are not in the SD. bool SystemDictionary::do_unloading(BoolObjectClosure* is_alive) { @@ -2024,12 +2043,6 @@ } } - // 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); - // Make a new system dictionary entry. Klass* sd_check = find_class(d_index, d_hash, name, loader_data); if (sd_check == NULL) { @@ -2612,6 +2625,27 @@ "Loaded klasses should be in SystemDictionary"); } +// utility function for class load event +void SystemDictionary::post_class_load_event(TracingTime start_time, + instanceKlassHandle k, + Handle initiating_loader) { +#if INCLUDE_TRACE + EventClassLoad event(UNTIMED); + if (event.should_commit()) { + event.set_endtime(Tracing::time()); + event.set_starttime(start_time); + event.set_loadedClass(k()); + oop defining_class_loader = k->class_loader(); + event.set_definingClassLoader(defining_class_loader != NULL ? + defining_class_loader->klass() : (Klass*)NULL); + oop class_loader = initiating_loader.is_null() ? (oop)NULL : initiating_loader(); + event.set_initiatingClassLoader(class_loader != NULL ? + class_loader->klass() : (Klass*)NULL); + event.commit(); + } +#endif /* INCLUDE_TRACE */ +} + #ifndef PRODUCT // statistics code
--- a/src/share/vm/classfile/systemDictionary.hpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/classfile/systemDictionary.hpp Fri Jun 21 15:56:24 2013 -0700 @@ -31,9 +31,11 @@ #include "oops/symbol.hpp" #include "runtime/java.hpp" #include "runtime/reflectionUtils.hpp" +#include "trace/traceTime.hpp" #include "utilities/hashtable.hpp" #include "utilities/hashtable.inline.hpp" + // The system dictionary stores all loaded classes and maps: // // [class name,class loader] -> class i.e. [Symbol*,oop] -> Klass* @@ -636,6 +638,9 @@ // Setup link to hierarchy static void add_to_hierarchy(instanceKlassHandle k, TRAPS); + // event based tracing + static void post_class_load_event(TracingTime start_time, instanceKlassHandle k, + Handle initiating_loader); // We pass in the hashtable index so we can calculate it outside of // the SystemDictionary_lock.
--- a/src/share/vm/classfile/verifier.hpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/classfile/verifier.hpp Fri Jun 21 15:56:24 2013 -0700 @@ -36,8 +36,10 @@ class Verifier : AllStatic { public: enum { + STRICTER_ACCESS_CTRL_CHECK_VERSION = 49, STACKMAP_ATTRIBUTE_MAJOR_VERSION = 50, - INVOKEDYNAMIC_MAJOR_VERSION = 51 + INVOKEDYNAMIC_MAJOR_VERSION = 51, + NO_RELAX_ACCESS_CTRL_CHECK_VERSION = 52 }; typedef enum { ThrowException, NoException } Mode;
--- a/src/share/vm/classfile/vmSymbols.hpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/classfile/vmSymbols.hpp Fri Jun 21 15:56:24 2013 -0700 @@ -392,6 +392,9 @@ template(array_klass_name, "array_klass") \ template(oop_size_name, "oop_size") \ template(static_oop_field_count_name, "static_oop_field_count") \ + template(protection_domain_name, "protection_domain") \ + template(init_lock_name, "init_lock") \ + template(signers_name, "signers_name") \ template(loader_data_name, "loader_data") \ template(dependencies_name, "dependencies") \ \
--- a/src/share/vm/code/codeCache.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/code/codeCache.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -45,6 +45,7 @@ #include "runtime/java.hpp" #include "runtime/mutexLocker.hpp" #include "services/memoryService.hpp" +#include "trace/tracing.hpp" #include "utilities/xmlstream.hpp" // Helper class for printing in CodeCache @@ -114,7 +115,6 @@ } }; - // CodeCache implementation CodeHeap * CodeCache::_heap = new CodeHeap(); @@ -126,6 +126,7 @@ nmethod* CodeCache::_scavenge_root_nmethods = NULL; nmethod* CodeCache::_saved_nmethods = NULL; +int CodeCache::_codemem_full_count = 0; CodeBlob* CodeCache::first() { assert_locked_or_safepoint(CodeCache_lock); @@ -829,6 +830,22 @@ } } +void CodeCache::report_codemem_full() { + _codemem_full_count++; + EventCodeCacheFull event; + if (event.should_commit()) { + event.set_startAddress((u8)low_bound()); + event.set_commitedTopAddress((u8)high()); + event.set_reservedTopAddress((u8)high_bound()); + event.set_entryCount(nof_blobs()); + event.set_methodCount(nof_nmethods()); + event.set_adaptorCount(nof_adapters()); + event.set_unallocatedCapacity(unallocated_capacity()/K); + event.set_fullCount(_codemem_full_count); + event.commit(); + } +} + //------------------------------------------------------------------------------------------------ // Non-product version
--- a/src/share/vm/code/codeCache.hpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/code/codeCache.hpp Fri Jun 21 15:56:24 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -64,11 +64,15 @@ static void mark_scavenge_root_nmethods() PRODUCT_RETURN; static void verify_perm_nmethods(CodeBlobClosure* f_or_null) PRODUCT_RETURN; + static int _codemem_full_count; + public: // Initialization static void initialize(); + static void report_codemem_full(); + // Allocation/administration static CodeBlob* allocate(int size, bool is_critical = false); // allocates a new CodeBlob static void commit(CodeBlob* cb); // called when the allocated CodeBlob has been filled @@ -155,6 +159,7 @@ // The full limits of the codeCache static address low_bound() { return (address) _heap->low_boundary(); } static address high_bound() { return (address) _heap->high_boundary(); } + static address high() { return (address) _heap->high(); } // Profiling static address first_address(); // first address used for CodeBlobs @@ -186,6 +191,8 @@ // tells how many nmethods have dependencies static int number_of_nmethods_with_dependencies(); + + static int get_codemem_full_count() { return _codemem_full_count; } }; #endif // SHARE_VM_CODE_CODECACHE_HPP
--- a/src/share/vm/code/nmethod.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/code/nmethod.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -1976,11 +1976,10 @@ if (!method()->is_native()) { SimpleScopeDesc ssd(this, fr.pc()); Bytecode_invoke call(ssd.method(), ssd.bci()); - // compiled invokedynamic call sites have an implicit receiver at - // resolution time, so make sure it gets GC'ed. - bool has_receiver = !call.is_invokestatic(); + bool has_receiver = call.has_receiver(); + bool has_appendix = call.has_appendix(); Symbol* signature = call.signature(); - fr.oops_compiled_arguments_do(signature, has_receiver, reg_map, f); + fr.oops_compiled_arguments_do(signature, has_receiver, has_appendix, reg_map, f); } #endif // !SHARK }
--- a/src/share/vm/compiler/compileBroker.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/compiler/compileBroker.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -43,6 +43,7 @@ #include "runtime/os.hpp" #include "runtime/sharedRuntime.hpp" #include "runtime/sweeper.hpp" +#include "trace/tracing.hpp" #include "utilities/dtrace.hpp" #include "utilities/events.hpp" #ifdef COMPILER1 @@ -179,9 +180,11 @@ int CompileBroker::_sum_nmethod_size = 0; int CompileBroker::_sum_nmethod_code_size = 0; -CompileQueue* CompileBroker::_c2_method_queue = NULL; -CompileQueue* CompileBroker::_c1_method_queue = NULL; -CompileTask* CompileBroker::_task_free_list = NULL; +long CompileBroker::_peak_compilation_time = 0; + +CompileQueue* CompileBroker::_c2_method_queue = NULL; +CompileQueue* CompileBroker::_c1_method_queue = NULL; +CompileTask* CompileBroker::_task_free_list = NULL; GrowableArray<CompilerThread*>* CompileBroker::_method_threads = NULL; @@ -1642,42 +1645,37 @@ // Set up state required by +LogCompilation. void CompileBroker::init_compiler_thread_log() { CompilerThread* thread = CompilerThread::current(); - char fileBuf[4*K]; + char file_name[4*K]; FILE* fp = NULL; - char* file = NULL; intx thread_id = os::current_thread_id(); for (int try_temp_dir = 1; try_temp_dir >= 0; try_temp_dir--) { const char* dir = (try_temp_dir ? os::get_temp_directory() : NULL); if (dir == NULL) { - jio_snprintf(fileBuf, sizeof(fileBuf), "hs_c" UINTX_FORMAT "_pid%u.log", + jio_snprintf(file_name, sizeof(file_name), "hs_c" UINTX_FORMAT "_pid%u.log", thread_id, os::current_process_id()); } else { - jio_snprintf(fileBuf, sizeof(fileBuf), + jio_snprintf(file_name, sizeof(file_name), "%s%shs_c" UINTX_FORMAT "_pid%u.log", dir, os::file_separator(), thread_id, os::current_process_id()); } - fp = fopen(fileBuf, "at"); + + fp = fopen(file_name, "at"); if (fp != NULL) { - file = NEW_C_HEAP_ARRAY(char, strlen(fileBuf)+1, mtCompiler); - strcpy(file, fileBuf); - break; + if (LogCompilation && Verbose) { + tty->print_cr("Opening compilation log %s", file_name); + } + CompileLog* log = new(ResourceObj::C_HEAP, mtCompiler) CompileLog(file_name, fp, thread_id); + thread->init_log(log); + + if (xtty != NULL) { + ttyLocker ttyl; + // Record any per thread log files + xtty->elem("thread_logfile thread='%d' filename='%s'", thread_id, file_name); + } + return; } } - if (fp == NULL) { - warning("Cannot open log file: %s", fileBuf); - } else { - if (LogCompilation && Verbose) - tty->print_cr("Opening compilation log %s", file); - CompileLog* log = new(ResourceObj::C_HEAP, mtCompiler) CompileLog(file, fp, thread_id); - thread->init_log(log); - - if (xtty != NULL) { - ttyLocker ttyl; - - // Record any per thread log files - xtty->elem("thread_logfile thread='%d' filename='%s'", thread_id, file); - } - } + warning("Cannot open log file: %s", file_name); } // ------------------------------------------------------------------ @@ -1800,6 +1798,7 @@ ciMethod* target = ci_env.get_method_from_handle(target_handle); TraceTime t1("compilation", &time); + EventCompilation event; AbstractCompiler *comp = compiler(task_level); if (comp == NULL) { @@ -1841,6 +1840,16 @@ } // simulate crash during compilation assert(task->compile_id() != CICrashAt, "just as planned"); + if (event.should_commit()) { + event.set_method(target->get_Method()); + event.set_compileID(compile_id); + event.set_compileLevel(task->comp_level()); + event.set_succeded(task->is_success()); + event.set_isOsr(is_osr); + event.set_codeSize((task->code() == NULL) ? 0 : task->code()->total_size()); + event.set_inlinedBytes(task->num_inlined_bytecodes()); + event.commit(); + } } pop_jni_handle_block(); @@ -1921,6 +1930,10 @@ } warning("CodeCache is full. Compiler has been disabled."); warning("Try increasing the code cache size using -XX:ReservedCodeCacheSize="); + + CodeCache::report_codemem_full(); + + #ifndef PRODUCT if (CompileTheWorld || ExitOnFullCodeCache) { codecache_print(/* detailed= */ true); @@ -2078,8 +2091,10 @@ // java.lang.management.CompilationMBean _perf_total_compilation->inc(time.ticks()); + _t_total_compilation.add(time); + _peak_compilation_time = time.milliseconds() > _peak_compilation_time ? time.milliseconds() : _peak_compilation_time; + if (CITime) { - _t_total_compilation.add(time); if (is_osr) { _t_osr_compilation.add(time); _sum_osr_bytes_compiled += method->code_size() + task->num_inlined_bytecodes(); @@ -2177,7 +2192,6 @@ tty->print_cr(" nmethod total size : %6d bytes", CompileBroker::_sum_nmethod_size); } - // Debugging output for failure void CompileBroker::print_last_compile() { if ( _last_compile_level != CompLevel_none &&
--- a/src/share/vm/compiler/compileBroker.hpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/compiler/compileBroker.hpp Fri Jun 21 15:56:24 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -299,17 +299,17 @@ static elapsedTimer _t_osr_compilation; static elapsedTimer _t_standard_compilation; + static int _total_compile_count; static int _total_bailout_count; static int _total_invalidated_count; - static int _total_compile_count; static int _total_native_compile_count; static int _total_osr_compile_count; static int _total_standard_compile_count; - static int _sum_osr_bytes_compiled; static int _sum_standard_bytes_compiled; static int _sum_nmethod_size; static int _sum_nmethod_code_size; + static long _peak_compilation_time; static CompilerThread* make_compiler_thread(const char* name, CompileQueue* queue, CompilerCounters* counters, TRAPS); static void init_compiler_threads(int c1_compiler_count, int c2_compiler_count); @@ -421,6 +421,19 @@ // compiler name for debugging static const char* compiler_name(int comp_level); + + static int get_total_compile_count() { return _total_compile_count; } + static int get_total_bailout_count() { return _total_bailout_count; } + static int get_total_invalidated_count() { return _total_invalidated_count; } + static int get_total_native_compile_count() { return _total_native_compile_count; } + static int get_total_osr_compile_count() { return _total_osr_compile_count; } + static int get_total_standard_compile_count() { return _total_standard_compile_count; } + static int get_sum_osr_bytes_compiled() { return _sum_osr_bytes_compiled; } + static int get_sum_standard_bytes_compiled() { return _sum_standard_bytes_compiled; } + static int get_sum_nmethod_size() { return _sum_nmethod_size;} + static int get_sum_nmethod_code_size() { return _sum_nmethod_code_size; } + static long get_peak_compilation_time() { return _peak_compilation_time; } + static long get_total_compilation_time() { return _t_total_compilation.milliseconds(); } }; #endif // SHARE_VM_COMPILER_COMPILEBROKER_HPP
--- a/src/share/vm/compiler/compileLog.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/compiler/compileLog.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -34,17 +34,18 @@ // ------------------------------------------------------------------ // CompileLog::CompileLog -CompileLog::CompileLog(const char* file, FILE* fp, intx thread_id) +CompileLog::CompileLog(const char* file_name, FILE* fp, intx thread_id) : _context(_context_buffer, sizeof(_context_buffer)) { - initialize(new(ResourceObj::C_HEAP, mtCompiler) fileStream(fp)); - _file = file; + initialize(new(ResourceObj::C_HEAP, mtCompiler) fileStream(fp, true)); _file_end = 0; _thread_id = thread_id; _identities_limit = 0; _identities_capacity = 400; _identities = NEW_C_HEAP_ARRAY(char, _identities_capacity, mtCompiler); + _file = NEW_C_HEAP_ARRAY(char, strlen(file_name)+1, mtCompiler); + strcpy((char*)_file, file_name); // link into the global list { MutexLocker locker(CompileTaskAlloc_lock); @@ -57,6 +58,7 @@ delete _out; _out = NULL; FREE_C_HEAP_ARRAY(char, _identities, mtCompiler); + FREE_C_HEAP_ARRAY(char, _file, mtCompiler); } @@ -188,7 +190,8 @@ if (called_exit) return; called_exit = true; - for (CompileLog* log = _first; log != NULL; log = log->_next) { + CompileLog* log = _first; + while (log != NULL) { log->flush(); const char* partial_file = log->file(); int partial_fd = open(partial_file, O_RDONLY); @@ -267,7 +270,11 @@ close(partial_fd); unlink(partial_file); } + CompileLog* next_log = log->_next; + delete log; + log = next_log; } + _first = NULL; } // ------------------------------------------------------------------
--- a/src/share/vm/compiler/compileLog.hpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/compiler/compileLog.hpp Fri Jun 21 15:56:24 2013 -0700 @@ -57,7 +57,7 @@ void va_tag(bool push, const char* format, va_list ap); public: - CompileLog(const char* file, FILE* fp, intx thread_id); + CompileLog(const char* file_name, FILE* fp, intx thread_id); ~CompileLog(); intx thread_id() { return _thread_id; }
--- a/src/share/vm/gc_implementation/concurrentMarkSweep/cmsAdaptiveSizePolicy.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/cmsAdaptiveSizePolicy.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -969,8 +969,8 @@ } -void CMSAdaptiveSizePolicy::compute_young_generation_free_space(size_t cur_eden, - size_t max_eden_size) +void CMSAdaptiveSizePolicy::compute_eden_space_size(size_t cur_eden, + size_t max_eden_size) { size_t desired_eden_size = cur_eden; size_t eden_limit = max_eden_size; @@ -978,7 +978,7 @@ // Printout input if (PrintGC && PrintAdaptiveSizePolicy) { gclog_or_tty->print_cr( - "CMSAdaptiveSizePolicy::compute_young_generation_free_space: " + "CMSAdaptiveSizePolicy::compute_eden_space_size: " "cur_eden " SIZE_FORMAT, cur_eden); } @@ -1024,7 +1024,7 @@ if (PrintGC && PrintAdaptiveSizePolicy) { gclog_or_tty->print_cr( - "CMSAdaptiveSizePolicy::compute_young_generation_free_space limits:" + "CMSAdaptiveSizePolicy::compute_eden_space_size limits:" " desired_eden_size: " SIZE_FORMAT " old_eden_size: " SIZE_FORMAT, desired_eden_size, cur_eden);
--- a/src/share/vm/gc_implementation/concurrentMarkSweep/cmsAdaptiveSizePolicy.hpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/cmsAdaptiveSizePolicy.hpp Fri Jun 21 15:56:24 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -436,8 +436,8 @@ size_t generation_alignment() { return _generation_alignment; } - virtual void compute_young_generation_free_space(size_t cur_eden, - size_t max_eden_size); + virtual void compute_eden_space_size(size_t cur_eden, + size_t max_eden_size); // Calculates new survivor space size; returns a new tenuring threshold // value. Stores new survivor size in _survivor_size. virtual uint compute_survivor_space_size_and_threshold(
--- a/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -37,8 +37,12 @@ #include "gc_implementation/concurrentMarkSweep/vmCMSOperations.hpp" #include "gc_implementation/parNew/parNewGeneration.hpp" #include "gc_implementation/shared/collectorCounters.hpp" +#include "gc_implementation/shared/gcTimer.hpp" +#include "gc_implementation/shared/gcTrace.hpp" +#include "gc_implementation/shared/gcTraceTime.hpp" #include "gc_implementation/shared/isGCActiveMark.hpp" #include "gc_interface/collectedHeap.inline.hpp" +#include "memory/allocation.hpp" #include "memory/cardTableRS.hpp" #include "memory/collectorPolicy.hpp" #include "memory/gcLocker.inline.hpp" @@ -60,7 +64,8 @@ // statics CMSCollector* ConcurrentMarkSweepGeneration::_collector = NULL; -bool CMSCollector::_full_gc_requested = false; +bool CMSCollector::_full_gc_requested = false; +GCCause::Cause CMSCollector::_full_gc_cause = GCCause::_no_gc; ////////////////////////////////////////////////////////////////// // In support of CMS/VM thread synchronization @@ -591,7 +596,10 @@ _concurrent_cycles_since_last_unload(0), _roots_scanning_options(0), _inter_sweep_estimate(CMS_SweepWeight, CMS_SweepPadding), - _intra_sweep_estimate(CMS_SweepWeight, CMS_SweepPadding) + _intra_sweep_estimate(CMS_SweepWeight, CMS_SweepPadding), + _gc_tracer_cm(new (ResourceObj::C_HEAP, mtGC) CMSTracer()), + _gc_timer_cm(new (ResourceObj::C_HEAP, mtGC) ConcurrentGCTimer()), + _cms_start_registered(false) { if (ExplicitGCInvokesConcurrentAndUnloadsClasses) { ExplicitGCInvokesConcurrent = true; @@ -1676,18 +1684,38 @@ _full_gcs_since_conc_gc++; } -void CMSCollector::request_full_gc(unsigned int full_gc_count) { +void CMSCollector::request_full_gc(unsigned int full_gc_count, GCCause::Cause cause) { GenCollectedHeap* gch = GenCollectedHeap::heap(); unsigned int gc_count = gch->total_full_collections(); if (gc_count == full_gc_count) { MutexLockerEx y(CGC_lock, Mutex::_no_safepoint_check_flag); _full_gc_requested = true; + _full_gc_cause = cause; CGC_lock->notify(); // nudge CMS thread } else { assert(gc_count > full_gc_count, "Error: causal loop"); } } +bool CMSCollector::is_external_interruption() { + GCCause::Cause cause = GenCollectedHeap::heap()->gc_cause(); + return GCCause::is_user_requested_gc(cause) || + GCCause::is_serviceability_requested_gc(cause); +} + +void CMSCollector::report_concurrent_mode_interruption() { + if (is_external_interruption()) { + if (PrintGCDetails) { + gclog_or_tty->print(" (concurrent mode interrupted)"); + } + } else { + if (PrintGCDetails) { + gclog_or_tty->print(" (concurrent mode failure)"); + } + _gc_tracer_cm->report_concurrent_mode_failure(); + } +} + // The foreground and background collectors need to coordinate in order // to make sure that they do not mutually interfere with CMS collections. @@ -1845,14 +1873,8 @@ } ) - if (PrintGCDetails && first_state > Idling) { - GCCause::Cause cause = GenCollectedHeap::heap()->gc_cause(); - if (GCCause::is_user_requested_gc(cause) || - GCCause::is_serviceability_requested_gc(cause)) { - gclog_or_tty->print(" (concurrent mode interrupted)"); - } else { - gclog_or_tty->print(" (concurrent mode failure)"); - } + if (first_state > Idling) { + report_concurrent_mode_interruption(); } set_did_compact(should_compact); @@ -1868,6 +1890,10 @@ // Reference objects are active. ref_processor()->clean_up_discovered_references(); + if (first_state > Idling) { + save_heap_summary(); + } + do_compaction_work(clear_all_soft_refs); // Has the GC time limit been exceeded? @@ -1971,7 +1997,14 @@ // a mark-sweep-compact. void CMSCollector::do_compaction_work(bool clear_all_soft_refs) { GenCollectedHeap* gch = GenCollectedHeap::heap(); - TraceTime t("CMS:MSC ", PrintGCDetails && Verbose, true, gclog_or_tty); + + STWGCTimer* gc_timer = GenMarkSweep::gc_timer(); + gc_timer->register_gc_start(os::elapsed_counter()); + + SerialOldTracer* gc_tracer = GenMarkSweep::gc_tracer(); + gc_tracer->report_gc_start(gch->gc_cause(), gc_timer->gc_start()); + + GCTraceTime t("CMS:MSC ", PrintGCDetails && Verbose, true, NULL); if (PrintGC && Verbose && !(GCCause::is_user_requested_gc(gch->gc_cause()))) { gclog_or_tty->print_cr("Compact ConcurrentMarkSweepGeneration after %d " "collections passed to foreground collector", _full_gcs_since_conc_gc); @@ -2062,6 +2095,10 @@ size_policy()->msc_collection_end(gch->gc_cause()); } + gc_timer->register_gc_end(os::elapsed_counter()); + + gc_tracer->report_gc_end(gc_timer->gc_end(), gc_timer->time_partitions()); + // For a mark-sweep-compact, compute_new_size() will be called // in the heap's do_collection() method. } @@ -2093,7 +2130,7 @@ // required. _collectorState = FinalMarking; } - collect_in_foreground(clear_all_soft_refs); + collect_in_foreground(clear_all_soft_refs, GenCollectedHeap::heap()->gc_cause()); // For a mark-sweep, compute_new_size() will be called // in the heap's do_collection() method. @@ -2153,7 +2190,7 @@ // one "collect" method between the background collector and the foreground // collector but the if-then-else required made it cleaner to have // separate methods. -void CMSCollector::collect_in_background(bool clear_all_soft_refs) { +void CMSCollector::collect_in_background(bool clear_all_soft_refs, GCCause::Cause cause) { assert(Thread::current()->is_ConcurrentGC_thread(), "A CMS asynchronous collection is only allowed on a CMS thread."); @@ -2172,6 +2209,7 @@ } else { assert(_collectorState == Idling, "Should be idling before start."); _collectorState = InitialMarking; + register_gc_start(cause); // Reset the expansion cause, now that we are about to begin // a new cycle. clear_expansion_cause(); @@ -2184,6 +2222,7 @@ // ensuing concurrent GC cycle. update_should_unload_classes(); _full_gc_requested = false; // acks all outstanding full gc requests + _full_gc_cause = GCCause::_no_gc; // Signal that we are about to start a collection gch->increment_total_full_collections(); // ... starting a collection cycle _collection_count_start = gch->total_full_collections(); @@ -2263,7 +2302,6 @@ { ReleaseForegroundGC x(this); stats().record_cms_begin(); - VM_CMS_Initial_Mark initial_mark_op(this); VMThread::execute(&initial_mark_op); } @@ -2343,6 +2381,7 @@ CMSTokenSync z(true); // not strictly needed. if (_collectorState == Resizing) { compute_new_size(); + save_heap_summary(); _collectorState = Resetting; } else { assert(_collectorState == Idling, "The state should only change" @@ -2401,7 +2440,39 @@ } } -void CMSCollector::collect_in_foreground(bool clear_all_soft_refs) { +void CMSCollector::register_foreground_gc_start(GCCause::Cause cause) { + if (!_cms_start_registered) { + register_gc_start(cause); + } +} + +void CMSCollector::register_gc_start(GCCause::Cause cause) { + _cms_start_registered = true; + _gc_timer_cm->register_gc_start(os::elapsed_counter()); + _gc_tracer_cm->report_gc_start(cause, _gc_timer_cm->gc_start()); +} + +void CMSCollector::register_gc_end() { + if (_cms_start_registered) { + report_heap_summary(GCWhen::AfterGC); + + _gc_timer_cm->register_gc_end(os::elapsed_counter()); + _gc_tracer_cm->report_gc_end(_gc_timer_cm->gc_end(), _gc_timer_cm->time_partitions()); + _cms_start_registered = false; + } +} + +void CMSCollector::save_heap_summary() { + GenCollectedHeap* gch = GenCollectedHeap::heap(); + _last_heap_summary = gch->create_heap_summary(); + _last_metaspace_summary = gch->create_metaspace_summary(); +} + +void CMSCollector::report_heap_summary(GCWhen::Type when) { + _gc_tracer_cm->report_gc_heap_summary(when, _last_heap_summary, _last_metaspace_summary); +} + +void CMSCollector::collect_in_foreground(bool clear_all_soft_refs, GCCause::Cause cause) { assert(_foregroundGCIsActive && !_foregroundGCShouldWait, "Foreground collector should be waiting, not executing"); assert(Thread::current()->is_VM_thread(), "A foreground collection" @@ -2409,8 +2480,8 @@ assert(ConcurrentMarkSweepThread::vm_thread_has_cms_token(), "VM thread should have CMS token"); - NOT_PRODUCT(TraceTime t("CMS:MS (foreground) ", PrintGCDetails && Verbose, - true, gclog_or_tty);) + NOT_PRODUCT(GCTraceTime t("CMS:MS (foreground) ", PrintGCDetails && Verbose, + true, NULL);) if (UseAdaptiveSizePolicy) { size_policy()->ms_collection_begin(); } @@ -2434,6 +2505,7 @@ } switch (_collectorState) { case InitialMarking: + register_foreground_gc_start(cause); init_mark_was_synchronous = true; // fact to be exploited in re-mark checkpointRootsInitial(false); assert(_collectorState == Marking, "Collector state should have changed" @@ -2482,6 +2554,7 @@ GenCollectedHeap::heap()->total_collections() >= VerifyGCStartAt) { Universe::verify("Verify before reset: "); } + save_heap_summary(); reset(false); assert(_collectorState == Idling, "Collector state should " "have changed"); @@ -3504,6 +3577,9 @@ check_correct_thread_executing(); TraceCMSMemoryManagerStats tms(_collectorState,GenCollectedHeap::heap()->gc_cause()); + save_heap_summary(); + report_heap_summary(GCWhen::BeforeGC); + ReferenceProcessor* rp = ref_processor(); SpecializationStats::clear(); assert(_restart_addr == NULL, "Control point invariant"); @@ -3549,8 +3625,8 @@ // CMS collection cycle. setup_cms_unloading_and_verification_state(); - NOT_PRODUCT(TraceTime t("\ncheckpointRootsInitialWork", - PrintGCDetails && Verbose, true, gclog_or_tty);) + NOT_PRODUCT(GCTraceTime t("\ncheckpointRootsInitialWork", + PrintGCDetails && Verbose, true, _gc_timer_cm);) if (UseAdaptiveSizePolicy) { size_policy()->checkpoint_roots_initial_begin(); } @@ -4542,8 +4618,10 @@ // The code in this method may need further // tweaking for better performance and some restructuring // for cleaner interfaces. + GCTimer *gc_timer = NULL; // Currently not tracing concurrent phases rp->preclean_discovered_references( - rp->is_alive_non_header(), &keep_alive, &complete_trace, &yield_cl); + rp->is_alive_non_header(), &keep_alive, &complete_trace, &yield_cl, + gc_timer); } if (clean_survivor) { // preclean the active survivor space(s) @@ -4885,8 +4963,8 @@ // Temporarily set flag to false, GCH->do_collection will // expect it to be false and set to true FlagSetting fl(gch->_is_gc_active, false); - NOT_PRODUCT(TraceTime t("Scavenge-Before-Remark", - PrintGCDetails && Verbose, true, gclog_or_tty);) + NOT_PRODUCT(GCTraceTime t("Scavenge-Before-Remark", + PrintGCDetails && Verbose, true, _gc_timer_cm);) int level = _cmsGen->level() - 1; if (level >= 0) { gch->do_collection(true, // full (i.e. force, see below) @@ -4915,7 +4993,7 @@ void CMSCollector::checkpointRootsFinalWork(bool asynch, bool clear_all_soft_refs, bool init_mark_was_synchronous) { - NOT_PRODUCT(TraceTime tr("checkpointRootsFinalWork", PrintGCDetails, false, gclog_or_tty);) + NOT_PRODUCT(GCTraceTime tr("checkpointRootsFinalWork", PrintGCDetails, false, _gc_timer_cm);) assert(haveFreelistLocks(), "must have free list locks"); assert_lock_strong(bitMapLock()); @@ -4966,11 +5044,11 @@ // the most recent young generation GC, minus those cleaned up by the // concurrent precleaning. if (CMSParallelRemarkEnabled && CollectedHeap::use_parallel_gc_threads()) { - TraceTime t("Rescan (parallel) ", PrintGCDetails, false, gclog_or_tty); + GCTraceTime t("Rescan (parallel) ", PrintGCDetails, false, _gc_timer_cm); do_remark_parallel(); } else { - TraceTime t("Rescan (non-parallel) ", PrintGCDetails, false, - gclog_or_tty); + GCTraceTime t("Rescan (non-parallel) ", PrintGCDetails, false, + _gc_timer_cm); do_remark_non_parallel(); } } @@ -4983,7 +5061,7 @@ verify_overflow_empty(); { - NOT_PRODUCT(TraceTime ts("refProcessingWork", PrintGCDetails, false, gclog_or_tty);) + NOT_PRODUCT(GCTraceTime ts("refProcessingWork", PrintGCDetails, false, _gc_timer_cm);) refProcessingWork(asynch, clear_all_soft_refs); } verify_work_stacks_empty(); @@ -5044,6 +5122,8 @@ verify_after_remark(); } + _gc_tracer_cm->report_object_count_after_gc(&_is_alive_closure); + // Change under the freelistLocks. _collectorState = Sweeping; // Call isAllClear() under bitMapLock @@ -5697,7 +5777,7 @@ NULL, // space is set further below &_markBitMap, &_markStack, &mrias_cl); { - TraceTime t("grey object rescan", PrintGCDetails, false, gclog_or_tty); + GCTraceTime t("grey object rescan", PrintGCDetails, false, _gc_timer_cm); // Iterate over the dirty cards, setting the corresponding bits in the // mod union table. { @@ -5734,7 +5814,7 @@ Universe::verify(); } { - TraceTime t("root rescan", PrintGCDetails, false, gclog_or_tty); + GCTraceTime t("root rescan", PrintGCDetails, false, _gc_timer_cm); verify_work_stacks_empty(); @@ -5756,7 +5836,7 @@ } { - TraceTime t("visit unhandled CLDs", PrintGCDetails, false, gclog_or_tty); + GCTraceTime t("visit unhandled CLDs", PrintGCDetails, false, _gc_timer_cm); verify_work_stacks_empty(); @@ -5775,7 +5855,7 @@ } { - TraceTime t("dirty klass scan", PrintGCDetails, false, gclog_or_tty); + GCTraceTime t("dirty klass scan", PrintGCDetails, false, _gc_timer_cm); verify_work_stacks_empty(); @@ -5977,7 +6057,9 @@ _span, &_markBitMap, &_markStack, &cmsKeepAliveClosure, false /* !preclean */); { - TraceTime t("weak refs processing", PrintGCDetails, false, gclog_or_tty); + GCTraceTime t("weak refs processing", PrintGCDetails, false, _gc_timer_cm); + + ReferenceProcessorStats stats; if (rp->processing_is_mt()) { // Set the degree of MT here. If the discovery is done MT, there // may have been a different number of threads doing the discovery @@ -5996,16 +6078,20 @@ } rp->set_active_mt_degree(active_workers); CMSRefProcTaskExecutor task_executor(*this); - rp->process_discovered_references(&_is_alive_closure, + stats = rp->process_discovered_references(&_is_alive_closure, &cmsKeepAliveClosure, &cmsDrainMarkingStackClosure, - &task_executor); + &task_executor, + _gc_timer_cm); } else { - rp->process_discovered_references(&_is_alive_closure, + stats = rp->process_discovered_references(&_is_alive_closure, &cmsKeepAliveClosure, &cmsDrainMarkingStackClosure, - NULL); - } + NULL, + _gc_timer_cm); + } + _gc_tracer_cm->report_gc_reference_stats(stats); + } // This is the point where the entire marking should have completed. @@ -6013,7 +6099,7 @@ if (should_unload_classes()) { { - TraceTime t("class unloading", PrintGCDetails, false, gclog_or_tty); + GCTraceTime t("class unloading", PrintGCDetails, false, _gc_timer_cm); // Unload classes and purge the SystemDictionary. bool purged_class = SystemDictionary::do_unloading(&_is_alive_closure); @@ -6026,7 +6112,7 @@ } { - TraceTime t("scrub symbol table", PrintGCDetails, false, gclog_or_tty); + GCTraceTime t("scrub symbol table", PrintGCDetails, false, _gc_timer_cm); // Clean up unreferenced symbols in symbol table. SymbolTable::unlink(); } @@ -6035,7 +6121,7 @@ // CMS doesn't use the StringTable as hard roots when class unloading is turned off. // Need to check if we really scanned the StringTable. if ((roots_scanning_options() & SharedHeap::SO_Strings) == 0) { - TraceTime t("scrub string table", PrintGCDetails, false, gclog_or_tty); + GCTraceTime t("scrub string table", PrintGCDetails, false, _gc_timer_cm); // Delete entries for dead interned strings. StringTable::unlink(&_is_alive_closure); } @@ -6380,12 +6466,14 @@ _cmsGen->rotate_debug_collection_type(); } ) + + register_gc_end(); } void CMSCollector::do_CMS_operation(CMS_op_type op, GCCause::Cause gc_cause) { gclog_or_tty->date_stamp(PrintGC && PrintGCDateStamps); TraceCPUTime tcpu(PrintGCDetails, true, gclog_or_tty); - TraceTime t(GCCauseString("GC", gc_cause), PrintGC, !PrintGCDetails, gclog_or_tty); + GCTraceTime t(GCCauseString("GC", gc_cause), PrintGC, !PrintGCDetails, NULL); TraceCollectorStats tcs(counters()); switch (op) {
--- a/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp Fri Jun 21 15:56:24 2013 -0700 @@ -25,8 +25,10 @@ #ifndef SHARE_VM_GC_IMPLEMENTATION_CONCURRENTMARKSWEEP_CONCURRENTMARKSWEEPGENERATION_HPP #define SHARE_VM_GC_IMPLEMENTATION_CONCURRENTMARKSWEEP_CONCURRENTMARKSWEEPGENERATION_HPP +#include "gc_implementation/shared/gcHeapSummary.hpp" #include "gc_implementation/shared/gSpaceCounters.hpp" #include "gc_implementation/shared/gcStats.hpp" +#include "gc_implementation/shared/gcWhen.hpp" #include "gc_implementation/shared/generationCounters.hpp" #include "memory/freeBlockDictionary.hpp" #include "memory/generation.hpp" @@ -53,6 +55,8 @@ class CMSAdaptiveSizePolicy; class CMSConcMarkingTask; class CMSGCAdaptivePolicyCounters; +class CMSTracer; +class ConcurrentGCTimer; class ConcurrentMarkSweepGeneration; class ConcurrentMarkSweepPolicy; class ConcurrentMarkSweepThread; @@ -61,6 +65,7 @@ class PromotionInfo; class ScanMarkedObjectsAgainCarefullyClosure; class TenuredGeneration; +class SerialOldTracer; // A generic CMS bit map. It's the basis for both the CMS marking bit map // as well as for the mod union table (in each case only a subset of the @@ -567,8 +572,9 @@ bool _completed_initialization; // In support of ExplicitGCInvokesConcurrent - static bool _full_gc_requested; - unsigned int _collection_count_start; + static bool _full_gc_requested; + static GCCause::Cause _full_gc_cause; + unsigned int _collection_count_start; // Should we unload classes this concurrent cycle? bool _should_unload_classes; @@ -609,6 +615,20 @@ AdaptivePaddedAverage _inter_sweep_estimate; AdaptivePaddedAverage _intra_sweep_estimate; + CMSTracer* _gc_tracer_cm; + ConcurrentGCTimer* _gc_timer_cm; + + bool _cms_start_registered; + + GCHeapSummary _last_heap_summary; + MetaspaceSummary _last_metaspace_summary; + + void register_foreground_gc_start(GCCause::Cause cause); + void register_gc_start(GCCause::Cause cause); + void register_gc_end(); + void save_heap_summary(); + void report_heap_summary(GCWhen::Type when); + protected: ConcurrentMarkSweepGeneration* _cmsGen; // old gen (CMS) MemRegion _span; // span covering above two @@ -827,6 +847,10 @@ void do_mark_sweep_work(bool clear_all_soft_refs, CollectorState first_state, bool should_start_over); + // Work methods for reporting concurrent mode interruption or failure + bool is_external_interruption(); + void report_concurrent_mode_interruption(); + // If the backgrould GC is active, acquire control from the background // GC and do the collection. void acquire_control_and_collect(bool full, bool clear_all_soft_refs); @@ -876,11 +900,11 @@ bool clear_all_soft_refs, size_t size, bool tlab); - void collect_in_background(bool clear_all_soft_refs); - void collect_in_foreground(bool clear_all_soft_refs); + void collect_in_background(bool clear_all_soft_refs, GCCause::Cause cause); + void collect_in_foreground(bool clear_all_soft_refs, GCCause::Cause cause); // In support of ExplicitGCInvokesConcurrent - static void request_full_gc(unsigned int full_gc_count); + static void request_full_gc(unsigned int full_gc_count, GCCause::Cause cause); // Should we unload classes in a particular concurrent cycle? bool should_unload_classes() const { return _should_unload_classes;
--- a/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepThread.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepThread.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -140,7 +140,9 @@ while (!_should_terminate) { sleepBeforeNextCycle(); if (_should_terminate) break; - _collector->collect_in_background(false); // !clear_all_soft_refs + GCCause::Cause cause = _collector->_full_gc_requested ? + _collector->_full_gc_cause : GCCause::_cms_concurrent_mark; + _collector->collect_in_background(false, cause); } assert(_should_terminate, "just checking"); // Check that the state of any protocol for synchronization
--- a/src/share/vm/gc_implementation/concurrentMarkSweep/vmCMSOperations.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/vmCMSOperations.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,9 +26,12 @@ #include "gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.inline.hpp" #include "gc_implementation/concurrentMarkSweep/concurrentMarkSweepThread.hpp" #include "gc_implementation/concurrentMarkSweep/vmCMSOperations.hpp" +#include "gc_implementation/shared/gcTimer.hpp" +#include "gc_implementation/shared/gcTraceTime.hpp" #include "gc_implementation/shared/isGCActiveMark.hpp" #include "memory/gcLocker.inline.hpp" #include "runtime/interfaceSupport.hpp" +#include "runtime/os.hpp" #include "utilities/dtrace.hpp" @@ -60,6 +63,7 @@ void VM_CMS_Operation::verify_before_gc() { if (VerifyBeforeGC && GenCollectedHeap::heap()->total_collections() >= VerifyGCStartAt) { + GCTraceTime tm("Verify Before", false, false, _collector->_gc_timer_cm); HandleMark hm; FreelistLocker x(_collector); MutexLockerEx y(_collector->bitMapLock(), Mutex::_no_safepoint_check_flag); @@ -71,6 +75,7 @@ void VM_CMS_Operation::verify_after_gc() { if (VerifyAfterGC && GenCollectedHeap::heap()->total_collections() >= VerifyGCStartAt) { + GCTraceTime tm("Verify After", false, false, _collector->_gc_timer_cm); HandleMark hm; FreelistLocker x(_collector); MutexLockerEx y(_collector->bitMapLock(), Mutex::_no_safepoint_check_flag); @@ -140,6 +145,8 @@ ); #endif /* USDT2 */ + _collector->_gc_timer_cm->register_gc_pause_start("Initial Mark", os::elapsed_counter()); + GenCollectedHeap* gch = GenCollectedHeap::heap(); GCCauseSetter gccs(gch, GCCause::_cms_initial_mark); @@ -149,6 +156,9 @@ _collector->do_CMS_operation(CMSCollector::CMS_op_checkpointRootsInitial, gch->gc_cause()); VM_CMS_Operation::verify_after_gc(); + + _collector->_gc_timer_cm->register_gc_pause_end(os::elapsed_counter()); + #ifndef USDT2 HS_DTRACE_PROBE(hs_private, cms__initmark__end); #else /* USDT2 */ @@ -172,6 +182,8 @@ ); #endif /* USDT2 */ + _collector->_gc_timer_cm->register_gc_pause_start("Final Mark", os::elapsed_counter()); + GenCollectedHeap* gch = GenCollectedHeap::heap(); GCCauseSetter gccs(gch, GCCause::_cms_final_remark); @@ -181,6 +193,10 @@ _collector->do_CMS_operation(CMSCollector::CMS_op_checkpointRootsFinal, gch->gc_cause()); VM_CMS_Operation::verify_after_gc(); + + _collector->save_heap_summary(); + _collector->_gc_timer_cm->register_gc_pause_end(os::elapsed_counter()); + #ifndef USDT2 HS_DTRACE_PROBE(hs_private, cms__remark__end); #else /* USDT2 */ @@ -225,7 +241,7 @@ // In case CMS thread was in icms_wait(), wake it up. CMSCollector::start_icms(); // Nudge the CMS thread to start a concurrent collection. - CMSCollector::request_full_gc(_full_gc_count_before); + CMSCollector::request_full_gc(_full_gc_count_before, _gc_cause); } else { assert(_full_gc_count_before < gch->total_full_collections(), "Error"); FullGCCount_lock->notify_all(); // Inform the Java thread its work is done
--- a/src/share/vm/gc_implementation/g1/concurrentG1Refine.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/gc_implementation/g1/concurrentG1Refine.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -114,6 +114,14 @@ } } +void ConcurrentG1Refine::worker_threads_do(ThreadClosure * tc) { + if (_threads != NULL) { + for (int i = 0; i < worker_thread_num(); i++) { + tc->do_thread(_threads[i]); + } + } +} + int ConcurrentG1Refine::thread_num() { int n_threads = (G1ConcRefinementThreads > 0) ? G1ConcRefinementThreads : ParallelGCThreads; @@ -126,3 +134,7 @@ st->cr(); } } + +ConcurrentG1RefineThread * ConcurrentG1Refine::sampling_thread() const { + return _threads[worker_thread_num()]; +}
--- a/src/share/vm/gc_implementation/g1/concurrentG1Refine.hpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/gc_implementation/g1/concurrentG1Refine.hpp Fri Jun 21 15:56:24 2013 -0700 @@ -35,6 +35,7 @@ class G1CollectedHeap; class G1HotCardCache; class G1RemSet; +class DirtyCardQueue; class ConcurrentG1Refine: public CHeapObj<mtGC> { ConcurrentG1RefineThread** _threads; @@ -78,9 +79,15 @@ void reinitialize_threads(); - // Iterate over the conc refine threads + // Iterate over all concurrent refinement threads void threads_do(ThreadClosure *tc); + // Iterate over all worker refinement threads + void worker_threads_do(ThreadClosure * tc); + + // The RS sampling thread + ConcurrentG1RefineThread * sampling_thread() const; + static int thread_num(); void print_worker_threads_on(outputStream* st) const;
--- a/src/share/vm/gc_implementation/g1/concurrentMark.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/gc_implementation/g1/concurrentMark.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -36,6 +36,9 @@ #include "gc_implementation/g1/heapRegionRemSet.hpp" #include "gc_implementation/g1/heapRegionSeq.inline.hpp" #include "gc_implementation/shared/vmGCOperations.hpp" +#include "gc_implementation/shared/gcTimer.hpp" +#include "gc_implementation/shared/gcTrace.hpp" +#include "gc_implementation/shared/gcTraceTime.hpp" #include "memory/genOopClosures.inline.hpp" #include "memory/referencePolicy.hpp" #include "memory/resourceArea.hpp" @@ -1342,6 +1345,9 @@ _remark_times.add((now - start) * 1000.0); g1p->record_concurrent_mark_remark_end(); + + G1CMIsAliveClosure is_alive(g1h); + g1h->gc_tracer_cm()->report_object_count_after_gc(&is_alive); } // Base class of the closures that finalize and verify the @@ -2129,6 +2135,7 @@ } g1h->verify_region_sets_optional(); + g1h->trace_heap_after_concurrent_cycle(); } void ConcurrentMark::completeCleanup() { @@ -2439,7 +2446,7 @@ if (G1Log::finer()) { gclog_or_tty->put(' '); } - TraceTime t("GC ref-proc", G1Log::finer(), false, gclog_or_tty); + GCTraceTime t("GC ref-proc", G1Log::finer(), false, g1h->gc_timer_cm()); ReferenceProcessor* rp = g1h->ref_processor_cm(); @@ -2491,10 +2498,13 @@ rp->set_active_mt_degree(active_workers); // Process the weak references. - rp->process_discovered_references(&g1_is_alive, - &g1_keep_alive, - &g1_drain_mark_stack, - executor); + const ReferenceProcessorStats& stats = + rp->process_discovered_references(&g1_is_alive, + &g1_keep_alive, + &g1_drain_mark_stack, + executor, + g1h->gc_timer_cm()); + g1h->gc_tracer_cm()->report_gc_reference_stats(stats); // The do_oop work routines of the keep_alive and drain_marking_stack // oop closures will set the has_overflown flag if we overflow the @@ -3227,6 +3237,9 @@ satb_mq_set.set_active_all_threads( false, /* new active value */ satb_mq_set.is_active() /* expected_active */); + + _g1h->trace_heap_after_concurrent_cycle(); + _g1h->register_concurrent_cycle_end(); } static void print_ms_time_info(const char* prefix, const char* name,
--- a/src/share/vm/gc_implementation/g1/concurrentMark.hpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/gc_implementation/g1/concurrentMark.hpp Fri Jun 21 15:56:24 2013 -0700 @@ -569,8 +569,6 @@ void clear_has_overflown() { _has_overflown = false; } bool restart_for_overflow() { return _restart_for_overflow; } - bool has_aborted() { return _has_aborted; } - // Methods to enter the two overflow sync barriers void enter_first_sync_barrier(uint worker_id); void enter_second_sync_barrier(uint worker_id); @@ -821,6 +819,8 @@ // Called to abort the marking cycle after a Full GC takes palce. void abort(); + bool has_aborted() { return _has_aborted; } + // This prints the global/local fingers. It is used for debugging. NOT_PRODUCT(void print_finger();)
--- a/src/share/vm/gc_implementation/g1/concurrentMarkThread.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/gc_implementation/g1/concurrentMarkThread.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -93,7 +93,6 @@ ResourceMark rm; HandleMark hm; double cycle_start = os::elapsedVTime(); - char verbose_str[128]; // We have to ensure that we finish scanning the root regions // before the next GC takes place. To ensure this we have to @@ -155,8 +154,7 @@ } CMCheckpointRootsFinalClosure final_cl(_cm); - sprintf(verbose_str, "GC remark"); - VM_CGC_Operation op(&final_cl, verbose_str, true /* needs_pll */); + VM_CGC_Operation op(&final_cl, "GC remark", true /* needs_pll */); VMThread::execute(&op); } if (cm()->restart_for_overflow()) { @@ -187,8 +185,7 @@ } CMCleanUp cl_cl(_cm); - sprintf(verbose_str, "GC cleanup"); - VM_CGC_Operation op(&cl_cl, verbose_str, false /* needs_pll */); + VM_CGC_Operation op(&cl_cl, "GC cleanup", false /* needs_pll */); VMThread::execute(&op); } else { // We don't want to update the marking status if a GC pause @@ -292,6 +289,7 @@ // called System.gc() with +ExplicitGCInvokesConcurrent). _sts.join(); g1h->increment_old_marking_cycles_completed(true /* concurrent */); + g1h->register_concurrent_cycle_end(); _sts.leave(); } assert(_should_terminate, "just checking");
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/gc_implementation/g1/evacuationInfo.hpp Fri Jun 21 15:56:24 2013 -0700 @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_GC_IMPLEMENTATION_SHARED_EVACUATIONINFO_HPP +#define SHARE_VM_GC_IMPLEMENTATION_SHARED_EVACUATIONINFO_HPP + +#include "memory/allocation.hpp" + +class EvacuationInfo : public StackObj { + uint _collectionset_regions; + uint _allocation_regions; + size_t _collectionset_used_before; + size_t _collectionset_used_after; + size_t _alloc_regions_used_before; + size_t _bytes_copied; + uint _regions_freed; + +public: + EvacuationInfo() : _collectionset_regions(0), _allocation_regions(0), _collectionset_used_before(0), + _collectionset_used_after(0), _alloc_regions_used_before(0), + _bytes_copied(0), _regions_freed(0) { } + + void set_collectionset_regions(uint collectionset_regions) { + _collectionset_regions = collectionset_regions; + } + + void set_allocation_regions(uint allocation_regions) { + _allocation_regions = allocation_regions; + } + + void set_collectionset_used_before(size_t used) { + _collectionset_used_before = used; + } + + void increment_collectionset_used_after(size_t used) { + _collectionset_used_after += used; + } + + void set_alloc_regions_used_before(size_t used) { + _alloc_regions_used_before = used; + } + + void set_bytes_copied(size_t copied) { + _bytes_copied = copied; + } + + void set_regions_freed(uint freed) { + _regions_freed += freed; + } + + uint collectionset_regions() { return _collectionset_regions; } + uint allocation_regions() { return _allocation_regions; } + size_t collectionset_used_before() { return _collectionset_used_before; } + size_t collectionset_used_after() { return _collectionset_used_after; } + size_t alloc_regions_used_before() { return _alloc_regions_used_before; } + size_t bytes_copied() { return _bytes_copied; } + uint regions_freed() { return _regions_freed; } +}; + +#endif // SHARE_VM_GC_IMPLEMENTATION_SHARED_EVACUATIONINFO_HPP
--- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -38,10 +38,15 @@ #include "gc_implementation/g1/g1MarkSweep.hpp" #include "gc_implementation/g1/g1OopClosures.inline.hpp" #include "gc_implementation/g1/g1RemSet.inline.hpp" +#include "gc_implementation/g1/g1YCTypes.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" +#include "gc_implementation/shared/gcHeapSummary.hpp" +#include "gc_implementation/shared/gcTimer.hpp" +#include "gc_implementation/shared/gcTrace.hpp" +#include "gc_implementation/shared/gcTraceTime.hpp" #include "gc_implementation/shared/isGCActiveMark.hpp" #include "memory/gcLocker.inline.hpp" #include "memory/genOopClosures.inline.hpp" @@ -76,7 +81,7 @@ // The number of GC workers is passed to heap_region_par_iterate_chunked(). // It does use run_task() which sets _n_workers in the task. // G1ParTask executes g1_process_strong_roots() -> -// SharedHeap::process_strong_roots() which calls eventuall to +// SharedHeap::process_strong_roots() which calls eventually to // CardTableModRefBS::par_non_clean_card_iterate_work() which uses // SequentialSubTasksDone. SharedHeap::process_strong_roots() also // directly uses SubTasksDone (_process_strong_tasks field in SharedHeap). @@ -457,7 +462,7 @@ #endif // Returns true if the reference points to an object that -// can move in an incremental collecction. +// can move in an incremental collection. bool G1CollectedHeap::is_scavengable(const void* p) { G1CollectedHeap* g1h = G1CollectedHeap::heap(); G1CollectorPolicy* g1p = g1h->g1_policy(); @@ -548,7 +553,7 @@ return res; } - // Wait here until we get notifed either when (a) there are no + // Wait here until we get notified either when (a) there are no // more free regions coming or (b) some regions have been moved on // the secondary_free_list. SecondaryFreeList_lock->wait(Mutex::_no_safepoint_check_flag); @@ -623,7 +628,7 @@ uint first = G1_NULL_HRS_INDEX; if (num_regions == 1) { // Only one region to allocate, no need to go through the slower - // path. The caller will attempt the expasion if this fails, so + // path. The caller will attempt the expansion if this fails, so // let's not try to expand here too. HeapRegion* hr = new_region(word_size, false /* do_expand */); if (hr != NULL) { @@ -688,7 +693,7 @@ // the first region. HeapWord* new_obj = first_hr->bottom(); // This will be the new end of the first region in the series that - // should also match the end of the last region in the seriers. + // should also match the end of the last region in the series. HeapWord* new_end = new_obj + word_size_sum; // This will be the new top of the first region that will reflect // this allocation. @@ -863,7 +868,7 @@ bool* gc_overhead_limit_was_exceeded) { assert_heap_not_locked_and_not_at_safepoint(); - // Loop until the allocation is satisified, or unsatisfied after GC. + // Loop until the allocation is satisfied, or unsatisfied after GC. for (int try_count = 1, gclocker_retry_count = 0; /* we'll return */; try_count += 1) { unsigned int gc_count_before; @@ -1003,7 +1008,7 @@ (*gclocker_retry_count_ret) += 1; } - // We can reach here if we were unsuccessul in scheduling a + // We can reach here if we were unsuccessful in scheduling a // collection (because another thread beat us to it) or if we were // stalled due to the GC locker. In either can we should retry the // allocation attempt in case another thread successfully @@ -1128,7 +1133,7 @@ (*gclocker_retry_count_ret) += 1; } - // We can reach here if we were unsuccessul in scheduling a + // We can reach here if we were unsuccessful in scheduling a // collection (because another thread beat us to it) or if we were // stalled due to the GC locker. In either can we should retry the // allocation attempt in case another thread successfully @@ -1298,10 +1303,17 @@ return false; } + STWGCTimer* gc_timer = G1MarkSweep::gc_timer(); + gc_timer->register_gc_start(os::elapsed_counter()); + + SerialOldTracer* gc_tracer = G1MarkSweep::gc_tracer(); + gc_tracer->report_gc_start(gc_cause(), gc_timer->gc_start()); + SvcGCMarker sgcm(SvcGCMarker::FULL); ResourceMark rm; print_heap_before_gc(); + trace_heap_before_gc(gc_tracer); size_t metadata_prev_used = MetaspaceAux::allocated_used_bytes(); @@ -1322,7 +1334,7 @@ TraceCPUTime tcpu(G1Log::finer(), true, gclog_or_tty); { - TraceTime t(GCCauseString("Full GC", gc_cause()), G1Log::fine(), true, gclog_or_tty); + GCTraceTime t(GCCauseString("Full GC", gc_cause()), G1Log::fine(), true, NULL); TraceCollectorStats tcs(g1mm()->full_collection_counters()); TraceMemoryManagerStats tms(true /* fullGC */, gc_cause()); @@ -1351,7 +1363,7 @@ verify_before_gc(); - pre_full_gc_dump(); + pre_full_gc_dump(gc_timer); COMPILER2_PRESENT(DerivedPointerTable::clear()); @@ -1417,8 +1429,6 @@ MemoryService::track_memory_usage(); - verify_after_gc(); - assert(!ref_processor_stw()->discovery_enabled(), "Postcondition"); ref_processor_stw()->verify_no_references_recorded(); @@ -1435,7 +1445,7 @@ reset_gc_time_stamp(); // Since everything potentially moved, we will clear all remembered - // sets, and clear all cards. Later we will rebuild remebered + // sets, and clear all cards. Later we will rebuild remembered // sets. We will also reset the GC time stamps of the regions. clear_rsets_post_compaction(); check_gc_time_stamps(); @@ -1521,6 +1531,8 @@ _hrs.verify_optional(); verify_region_sets_optional(); + verify_after_gc(); + // Start a new incremental collection set for the next pause assert(g1_policy()->collection_set() == NULL, "must be"); g1_policy()->start_incremental_cset_building(); @@ -1553,8 +1565,12 @@ } print_heap_after_gc(); - - post_full_gc_dump(); + trace_heap_after_gc(gc_tracer); + + post_full_gc_dump(gc_timer); + + gc_timer->register_gc_end(os::elapsed_counter()); + gc_tracer->report_gc_end(gc_timer->gc_end(), gc_timer->time_partitions()); } return true; @@ -1919,7 +1935,7 @@ _ref_processor_stw(NULL), _process_strong_tasks(new SubTasksDone(G1H_PS_NumElements)), _bot_shared(NULL), - _evac_failure_scan_stack(NULL) , + _evac_failure_scan_stack(NULL), _mark_in_progress(false), _cg1r(NULL), _summary_bytes_used(0), _g1mm(NULL), @@ -1939,12 +1955,18 @@ _surviving_young_words(NULL), _old_marking_cycles_started(0), _old_marking_cycles_completed(0), + _concurrent_cycle_started(false), _in_cset_fast_test(NULL), _in_cset_fast_test_base(NULL), _dirty_cards_region_list(NULL), _worker_cset_start_region(NULL), - _worker_cset_start_region_time_stamp(NULL) { - _g1h = this; // To catch bugs. + _worker_cset_start_region_time_stamp(NULL), + _gc_timer_stw(new (ResourceObj::C_HEAP, mtGC) STWGCTimer()), + _gc_timer_cm(new (ResourceObj::C_HEAP, mtGC) ConcurrentGCTimer()), + _gc_tracer_stw(new (ResourceObj::C_HEAP, mtGC) G1NewTracer()), + _gc_tracer_cm(new (ResourceObj::C_HEAP, mtGC) G1OldTracer()) { + + _g1h = this; if (_process_strong_tasks == NULL || !_process_strong_tasks->valid()) { vm_exit_during_initialization("Failed necessary allocation."); } @@ -1959,13 +1981,14 @@ _worker_cset_start_region = NEW_C_HEAP_ARRAY(HeapRegion*, n_queues, mtGC); _worker_cset_start_region_time_stamp = NEW_C_HEAP_ARRAY(unsigned int, n_queues, mtGC); + _evacuation_failed_info_array = NEW_C_HEAP_ARRAY(EvacuationFailedInfo, n_queues, mtGC); for (int i = 0; i < n_queues; i++) { RefToScanQueue* q = new RefToScanQueue(); q->initialize(); _task_queues->register_queue(i, q); - } - + ::new (&_evacuation_failed_info_array[i]) EvacuationFailedInfo(); + } clear_cset_start_regions(); // Initialize the G1EvacuationFailureALot counters and flags. @@ -2025,7 +2048,7 @@ HeapRegion::GrainBytes); // It is important to do this in a way such that concurrent readers can't - // temporarily think somethings in the heap. (I've actually seen this + // temporarily think something is in the heap. (I've actually seen this // happen in asserts: DLD.) _reserved.set_word_size(0); _reserved.set_start((HeapWord*)heap_rs.base()); @@ -2462,7 +2485,7 @@ // We need to clear the "in_progress" flag in the CM thread before // we wake up any waiters (especially when ExplicitInvokesConcurrent // is set) so that if a waiter requests another System.gc() it doesn't - // incorrectly see that a marking cyle is still in progress. + // incorrectly see that a marking cycle is still in progress. if (concurrent) { _cmThread->clear_in_progress(); } @@ -2474,6 +2497,49 @@ FullGCCount_lock->notify_all(); } +void G1CollectedHeap::register_concurrent_cycle_start(jlong start_time) { + _concurrent_cycle_started = true; + _gc_timer_cm->register_gc_start(start_time); + + _gc_tracer_cm->report_gc_start(gc_cause(), _gc_timer_cm->gc_start()); + trace_heap_before_gc(_gc_tracer_cm); +} + +void G1CollectedHeap::register_concurrent_cycle_end() { + if (_concurrent_cycle_started) { + _gc_timer_cm->register_gc_end(os::elapsed_counter()); + + if (_cm->has_aborted()) { + _gc_tracer_cm->report_concurrent_mode_failure(); + } + _gc_tracer_cm->report_gc_end(_gc_timer_cm->gc_end(), _gc_timer_cm->time_partitions()); + + _concurrent_cycle_started = false; + } +} + +void G1CollectedHeap::trace_heap_after_concurrent_cycle() { + if (_concurrent_cycle_started) { + trace_heap_after_gc(_gc_tracer_cm); + } +} + +G1YCType G1CollectedHeap::yc_type() { + bool is_young = g1_policy()->gcs_are_young(); + bool is_initial_mark = g1_policy()->during_initial_mark_pause(); + bool is_during_mark = mark_in_progress(); + + if (is_initial_mark) { + return InitialMark; + } else if (is_during_mark) { + return DuringMark; + } else if (is_young) { + return Normal; + } else { + return Mixed; + } +} + void G1CollectedHeap::collect(GCCause::Cause cause) { assert_heap_not_locked(); @@ -2676,13 +2742,13 @@ break; } - // Noone should have claimed it directly. We can given + // No one should have claimed it directly. We can given // that we claimed its "starts humongous" region. assert(chr->claim_value() != claim_value, "sanity"); assert(chr->humongous_start_region() == r, "sanity"); if (chr->claimHeapRegion(claim_value)) { - // we should always be able to claim it; noone else should + // we should always be able to claim it; no one else should // be trying to claim this region bool res2 = cl->doHeapRegion(chr); @@ -2976,7 +3042,7 @@ // the min TLAB size. // Also, this value can be at most the humongous object threshold, - // since we can't allow tlabs to grow big enough to accomodate + // since we can't allow tlabs to grow big enough to accommodate // humongous objects. HeapRegion* hr = _mutator_alloc_region.get(); @@ -3539,6 +3605,14 @@ } void G1CollectedHeap::gc_epilogue(bool full /* Ignored */) { + + if (G1SummarizeRSetStats && + (G1SummarizeRSetStatsPeriod > 0) && + // we are at the end of the GC. Total collections has already been increased. + ((total_collections() - 1) % G1SummarizeRSetStatsPeriod == 0)) { + g1_rem_set()->print_periodic_summary_info(); + } + // FIXME: what is this about? // I'm ignoring the "fill_newgen()" call if "alloc_event_enabled" // is set. @@ -3735,10 +3809,15 @@ return false; } + _gc_timer_stw->register_gc_start(os::elapsed_counter()); + + _gc_tracer_stw->report_gc_start(gc_cause(), _gc_timer_stw->gc_start()); + SvcGCMarker sgcm(SvcGCMarker::MINOR); ResourceMark rm; print_heap_before_gc(); + trace_heap_before_gc(_gc_tracer_stw); HRSPhaseSetter x(HRSPhaseEvacuation); verify_region_sets_optional(); @@ -3763,11 +3842,17 @@ // Inner scope for scope based logging, timers, and stats collection { + EvacuationInfo evacuation_info; + if (g1_policy()->during_initial_mark_pause()) { // We are about to start a marking cycle, so we increment the // full collection counter. increment_old_marking_cycles_started(); + register_concurrent_cycle_start(_gc_timer_stw->gc_start()); } + + _gc_tracer_stw->report_yc_type(yc_type()); + TraceCPUTime tcpu(G1Log::finer(), true, gclog_or_tty); int active_workers = (G1CollectedHeap::use_parallel_gc_threads() ? @@ -3877,7 +3962,7 @@ g1_policy()->print_collection_set(g1_policy()->inc_cset_head(), gclog_or_tty); #endif // YOUNG_LIST_VERBOSE - g1_policy()->finalize_cset(target_pause_time_ms); + g1_policy()->finalize_cset(target_pause_time_ms, evacuation_info); _cm->note_start_of_gc(); // We should not verify the per-thread SATB buffers given that @@ -3913,10 +3998,10 @@ setup_surviving_young_words(); // Initialize the GC alloc regions. - init_gc_alloc_regions(); + init_gc_alloc_regions(evacuation_info); // Actually do the work... - evacuate_collection_set(); + evacuate_collection_set(evacuation_info); // We do this to mainly verify the per-thread SATB buffers // (which have been filtered by now) since we didn't verify @@ -3928,7 +4013,7 @@ true /* verify_thread_buffers */, true /* verify_fingers */); - free_collection_set(g1_policy()->collection_set()); + free_collection_set(g1_policy()->collection_set(), evacuation_info); g1_policy()->clear_collection_set(); cleanup_surviving_young_words(); @@ -3956,13 +4041,19 @@ #endif // YOUNG_LIST_VERBOSE g1_policy()->record_survivor_regions(_young_list->survivor_length(), - _young_list->first_survivor_region(), - _young_list->last_survivor_region()); + _young_list->first_survivor_region(), + _young_list->last_survivor_region()); _young_list->reset_auxilary_lists(); if (evacuation_failed()) { _summary_bytes_used = recalculate_used(); + uint n_queues = MAX2((int)ParallelGCThreads, 1); + for (uint i = 0; i < n_queues; i++) { + if (_evacuation_failed_info_array[i].has_failed()) { + _gc_tracer_stw->report_evacuation_failed(_evacuation_failed_info_array[i]); + } + } } else { // The "used" of the the collection set have already been subtracted // when they were freed. Add in the bytes evacuated. @@ -4005,7 +4096,7 @@ } } - // We redo the verificaiton but now wrt to the new CSet which + // We redo the verification 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 */, @@ -4018,7 +4109,7 @@ // investigate this in CR 7178365. double sample_end_time_sec = os::elapsedTime(); double pause_time_ms = (sample_end_time_sec - sample_start_time_sec) * MILLIUNITS; - g1_policy()->record_collection_pause_end(pause_time_ms); + g1_policy()->record_collection_pause_end(pause_time_ms, evacuation_info); MemoryService::track_memory_usage(); @@ -4085,20 +4176,19 @@ TASKQUEUE_STATS_ONLY(reset_taskqueue_stats()); print_heap_after_gc(); + trace_heap_after_gc(_gc_tracer_stw); // We must call G1MonitoringSupport::update_sizes() in the same scoping level // as an active TraceMemoryManagerStats object (i.e. before the destructor for the // TraceMemoryManagerStats is called) so that the G1 memory pools are updated // before any GC notifications are raised. g1mm()->update_sizes(); - } - - if (G1SummarizeRSetStats && - (G1SummarizeRSetStatsPeriod > 0) && - (total_collections() % G1SummarizeRSetStatsPeriod == 0)) { - g1_rem_set()->print_summary_info(); - } - + + _gc_tracer_stw->report_evacuation_info(&evacuation_info); + _gc_tracer_stw->report_tenuring_threshold(_g1_policy->tenuring_threshold()); + _gc_timer_stw->register_gc_end(os::elapsed_counter()); + _gc_tracer_stw->report_gc_end(_gc_timer_stw->gc_end(), _gc_timer_stw->time_partitions()); + } // It should now be safe to tell the concurrent mark thread to start // without its logging output interfering with the logging output // that came from the pause. @@ -4150,7 +4240,7 @@ assert(_mutator_alloc_region.get() == NULL, "post-condition"); } -void G1CollectedHeap::init_gc_alloc_regions() { +void G1CollectedHeap::init_gc_alloc_regions(EvacuationInfo& evacuation_info) { assert_at_safepoint(true /* should_be_vm_thread */); _survivor_gc_alloc_region.init(); @@ -4165,7 +4255,7 @@ // a cleanup and it should be on the free list now), or // d) it's humongous (this means that it was emptied // during a cleanup and was added to the free list, but - // has been subseqently used to allocate a humongous + // has been subsequently used to allocate a humongous // object that may be less than the region size). if (retained_region != NULL && !retained_region->in_collection_set() && @@ -4182,10 +4272,13 @@ retained_region->note_start_of_copying(during_im); _old_gc_alloc_region.set(retained_region); _hr_printer.reuse(retained_region); - } -} - -void G1CollectedHeap::release_gc_alloc_regions(uint no_of_gc_workers) { + evacuation_info.set_alloc_regions_used_before(retained_region->used()); + } +} + +void G1CollectedHeap::release_gc_alloc_regions(uint no_of_gc_workers, EvacuationInfo& evacuation_info) { + evacuation_info.set_allocation_regions(_survivor_gc_alloc_region.count() + + _old_gc_alloc_region.count()); _survivor_gc_alloc_region.release(); // If we have an old GC alloc region to release, we'll save it in // _retained_old_gc_alloc_region. If we don't @@ -4268,7 +4361,7 @@ } oop -G1CollectedHeap::handle_evacuation_failure_par(OopsInHeapRegionClosure* cl, +G1CollectedHeap::handle_evacuation_failure_par(G1ParScanThreadState* _par_scan_state, oop old) { assert(obj_in_cs(old), err_msg("obj: "PTR_FORMAT" should still be in the CSet", @@ -4277,7 +4370,12 @@ oop forward_ptr = old->forward_to_atomic(old); if (forward_ptr == NULL) { // Forward-to-self succeeded. - + assert(_par_scan_state != NULL, "par scan state"); + OopsInHeapRegionClosure* cl = _par_scan_state->evac_failure_closure(); + uint queue_num = _par_scan_state->queue_num(); + + _evacuation_failed = true; + _evacuation_failed_info_array[queue_num].register_copy_failure(old->size()); if (_evac_failure_closure != cl) { MutexLockerEx x(EvacFailureStack_lock, Mutex::_no_safepoint_check_flag); assert(!_drain_in_progress, @@ -4308,8 +4406,6 @@ } void G1CollectedHeap::handle_evacuation_failure_common(oop old, markOop m) { - set_evacuation_failed(true); - preserve_mark_if_necessary(old, m); HeapRegion* r = heap_region_containing(old); @@ -4559,8 +4655,7 @@ if (obj_ptr == NULL) { // 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); + return _g1->handle_evacuation_failure_par(_par_scan_state, old); } oop obj = oop(obj_ptr); @@ -5164,7 +5259,7 @@ // will be copied, the reference field set to point to the // new location, and the RSet updated. Otherwise we need to // use the the non-heap or metadata closures directly to copy - // the refernt object and update the pointer, while avoiding + // the referent object and update the pointer, while avoiding // updating the RSet. if (_g1h->is_in_g1_reserved(p)) { @@ -5332,7 +5427,7 @@ } }; -// Driver routine for parallel reference enqueing. +// Driver routine for parallel reference enqueueing. // Creates an instance of the ref enqueueing gang // task and has the worker threads execute it. @@ -5461,7 +5556,7 @@ // processor would have seen that the reference object had already // been 'discovered' and would have skipped discovering the reference, // but would not have treated the reference object as a regular oop. - // As a reult the copy closure would not have been applied to the + // As a result the copy closure would not have been applied to the // referent object. // // We need to explicitly copy these referent objects - the references @@ -5537,21 +5632,28 @@ // Setup the soft refs policy... rp->setup_policy(false); + ReferenceProcessorStats stats; if (!rp->processing_is_mt()) { // Serial reference processing... - rp->process_discovered_references(&is_alive, - &keep_alive, - &drain_queue, - NULL); + stats = rp->process_discovered_references(&is_alive, + &keep_alive, + &drain_queue, + NULL, + _gc_timer_stw); } else { // Parallel reference processing assert(rp->num_q() == no_of_gc_workers, "sanity"); assert(no_of_gc_workers <= rp->max_num_q(), "sanity"); G1STWRefProcTaskExecutor par_task_executor(this, workers(), _task_queues, no_of_gc_workers); - rp->process_discovered_references(&is_alive, &keep_alive, &drain_queue, &par_task_executor); - } - + stats = rp->process_discovered_references(&is_alive, + &keep_alive, + &drain_queue, + &par_task_executor, + _gc_timer_stw); + } + + _gc_tracer_stw->report_gc_reference_stats(stats); // We have completed copying any necessary live referent objects // (that were not copied during the actual pause) so we can // retire any active alloc buffers @@ -5575,7 +5677,7 @@ // Serial reference processing... rp->enqueue_discovered_references(); } else { - // Parallel reference enqueuing + // Parallel reference enqueueing assert(no_of_gc_workers == workers()->active_workers(), "Need to reset active workers"); @@ -5592,15 +5694,15 @@ // FIXME // CM's reference processing also cleans up the string and symbol tables. // Should we do that here also? We could, but it is a serial operation - // and could signicantly increase the pause time. + // and could significantly increase the pause time. double ref_enq_time = os::elapsedTime() - ref_enq_start; g1_policy()->phase_times()->record_ref_enq_time(ref_enq_time * 1000.0); } -void G1CollectedHeap::evacuate_collection_set() { +void G1CollectedHeap::evacuate_collection_set(EvacuationInfo& evacuation_info) { _expand_heap_after_alloc_failure = true; - set_evacuation_failed(false); + _evacuation_failed = false; // Should G1EvacuationFailureALot be in effect for this GC? NOT_PRODUCT(set_evacuation_failure_alot_for_current_gc();) @@ -5689,7 +5791,7 @@ JNIHandles::weak_oops_do(&is_alive, &keep_alive); } - release_gc_alloc_regions(n_workers); + release_gc_alloc_regions(n_workers, evacuation_info); g1_rem_set()->cleanup_after_oops_into_collection_set_do(); // Reset and re-enable the hot card cache. @@ -5712,7 +5814,7 @@ // Enqueue any remaining references remaining on the STW // reference processor's discovered lists. We need to do // this after the card table is cleaned (and verified) as - // the act of enqueuing entries on to the pending list + // the act of enqueueing entries on to the pending list // will log these updates (and dirty their associated // cards). We need these updates logged to update any // RSets. @@ -5940,7 +6042,7 @@ g1_policy()->phase_times()->record_clear_ct_time(elapsed * 1000.0); } -void G1CollectedHeap::free_collection_set(HeapRegion* cs_head) { +void G1CollectedHeap::free_collection_set(HeapRegion* cs_head, EvacuationInfo& evacuation_info) { size_t pre_used = 0; FreeRegionList local_free_list("Local List for CSet Freeing"); @@ -6026,10 +6128,12 @@ cur->set_evacuation_failed(false); // The region is now considered to be old. _old_set.add(cur); + evacuation_info.increment_collectionset_used_after(cur->used()); } cur = next; } + evacuation_info.set_regions_freed(local_free_list.length()); policy->record_max_rs_lengths(rs_lengths); policy->cset_regions_freed();
--- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp Fri Jun 21 15:56:24 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,10 +26,12 @@ #define SHARE_VM_GC_IMPLEMENTATION_G1_G1COLLECTEDHEAP_HPP #include "gc_implementation/g1/concurrentMark.hpp" +#include "gc_implementation/g1/evacuationInfo.hpp" #include "gc_implementation/g1/g1AllocRegion.hpp" #include "gc_implementation/g1/g1HRPrinter.hpp" +#include "gc_implementation/g1/g1MonitoringSupport.hpp" #include "gc_implementation/g1/g1RemSet.hpp" -#include "gc_implementation/g1/g1MonitoringSupport.hpp" +#include "gc_implementation/g1/g1YCTypes.hpp" #include "gc_implementation/g1/heapRegionSeq.hpp" #include "gc_implementation/g1/heapRegionSets.hpp" #include "gc_implementation/shared/hSpaceCounters.hpp" @@ -61,7 +63,12 @@ class ConcurrentMark; class ConcurrentMarkThread; class ConcurrentG1Refine; +class ConcurrentGCTimer; class GenerationCounters; +class STWGCTimer; +class G1NewTracer; +class G1OldTracer; +class EvacuationFailedInfo; typedef OverflowTaskQueue<StarTask, mtGC> RefToScanQueue; typedef GenericTaskQueueSet<RefToScanQueue, mtGC> RefToScanQueueSet; @@ -160,7 +167,7 @@ // An instance is embedded into the G1CH and used as the // (optional) _is_alive_non_header closure in the STW // reference processor. It is also extensively used during -// refence processing during STW evacuation pauses. +// reference processing during STW evacuation pauses. class G1STWIsAliveClosure: public BoolObjectClosure { G1CollectedHeap* _g1; public: @@ -323,10 +330,10 @@ void release_mutator_alloc_region(); // It initializes the GC alloc regions at the start of a GC. - void init_gc_alloc_regions(); + void init_gc_alloc_regions(EvacuationInfo& evacuation_info); // It releases the GC alloc regions at the end of a GC. - void release_gc_alloc_regions(uint no_of_gc_workers); + void release_gc_alloc_regions(uint no_of_gc_workers, EvacuationInfo& evacuation_info); // It does any cleanup that needs to be done on the GC alloc regions // before a Full GC. @@ -389,6 +396,8 @@ // concurrent cycles) we have completed. volatile unsigned int _old_marking_cycles_completed; + bool _concurrent_cycle_started; + // This is a non-product method that is helpful for testing. It is // called at the end of a GC and artificially expands the heap by // allocating a number of dead regions. This way we can induce very @@ -593,11 +602,6 @@ // may not be a humongous - it must fit into a single heap region. HeapWord* par_allocate_during_gc(GCAllocPurpose purpose, size_t word_size); - HeapWord* allocate_during_gc_slow(GCAllocPurpose purpose, - HeapRegion* alloc_region, - bool par, - size_t word_size); - // Ensure that no further allocations can happen in "r", bearing in mind // that parallel threads might be attempting allocations. void par_allocate_remaining_space(HeapRegion* r); @@ -739,6 +743,12 @@ return _old_marking_cycles_completed; } + void register_concurrent_cycle_start(jlong start_time); + void register_concurrent_cycle_end(); + void trace_heap_after_concurrent_cycle(); + + G1YCType yc_type(); + G1HRPrinter* hr_printer() { return &_hr_printer; } protected: @@ -774,7 +784,7 @@ bool do_collection_pause_at_safepoint(double target_pause_time_ms); // Actually do the work of evacuating the collection set. - void evacuate_collection_set(); + void evacuate_collection_set(EvacuationInfo& evacuation_info); // The g1 remembered set of the heap. G1RemSet* _g1_rem_set; @@ -799,7 +809,7 @@ // After a collection pause, make the regions in the CS into free // regions. - void free_collection_set(HeapRegion* cs_head); + void free_collection_set(HeapRegion* cs_head, EvacuationInfo& evacuation_info); // Abandon the current collection set without recording policy // statistics or updating free lists. @@ -868,9 +878,7 @@ // True iff a evacuation has failed in the current collection. bool _evacuation_failed; - // Set the attribute indicating whether evacuation has failed in the - // current collection. - void set_evacuation_failed(bool b) { _evacuation_failed = b; } + EvacuationFailedInfo* _evacuation_failed_info_array; // Failed evacuations cause some logical from-space objects to have // forwarding pointers to themselves. Reset them. @@ -912,7 +920,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); + oop handle_evacuation_failure_par(G1ParScanThreadState* _par_scan_state, oop obj); void handle_evacuation_failure_common(oop obj, markOop m); #ifndef PRODUCT @@ -944,13 +952,13 @@ inline bool evacuation_should_fail(); // Reset the G1EvacuationFailureALot counters. Should be called at - // the end of an evacuation pause in which an evacuation failure ocurred. + // the end of an evacuation pause in which an evacuation failure occurred. inline void reset_evacuation_should_fail(); #endif // !PRODUCT // ("Weak") Reference processing support. // - // G1 has 2 instances of the referece processor class. One + // G1 has 2 instances of the reference processor class. One // (_ref_processor_cm) handles reference object discovery // and subsequent processing during concurrent marking cycles. // @@ -1000,6 +1008,12 @@ // The (stw) reference processor... ReferenceProcessor* _ref_processor_stw; + STWGCTimer* _gc_timer_stw; + ConcurrentGCTimer* _gc_timer_cm; + + G1OldTracer* _gc_tracer_cm; + G1NewTracer* _gc_tracer_stw; + // During reference object discovery, the _is_alive_non_header // closure (if non-null) is applied to the referent object to // determine whether the referent is live. If so then the @@ -1145,9 +1159,12 @@ // The STW reference processor.... ReferenceProcessor* ref_processor_stw() const { return _ref_processor_stw; } - // The Concurent Marking reference processor... + // The Concurrent Marking reference processor... ReferenceProcessor* ref_processor_cm() const { return _ref_processor_cm; } + ConcurrentGCTimer* gc_timer_cm() const { return _gc_timer_cm; } + G1OldTracer* gc_tracer_cm() const { return _gc_tracer_cm; } + virtual size_t capacity() const; virtual size_t used() const; // This should be called when we're not holding the heap lock. The @@ -1205,7 +1222,7 @@ // verify_region_sets_optional() is planted in the code for // list verification in non-product builds (and it can be enabled in - // product builds by definning HEAP_REGION_SET_FORCE_VERIFY to be 1). + // product builds by defining HEAP_REGION_SET_FORCE_VERIFY to be 1). #if HEAP_REGION_SET_FORCE_VERIFY void verify_region_sets_optional() { verify_region_sets(); @@ -1271,7 +1288,7 @@ // The same as above but assume that the caller holds the Heap_lock. void collect_locked(GCCause::Cause cause); - // True iff a evacuation has failed in the most-recent collection. + // True iff an evacuation has failed in the most-recent collection. bool evacuation_failed() { return _evacuation_failed; } // It will free a region if it has allocated objects in it that are @@ -1559,6 +1576,7 @@ // Override; it uses the "prev" marking information virtual void verify(bool silent); + virtual void print_on(outputStream* st) const; virtual void print_extended_on(outputStream* st) const; virtual void print_on_error(outputStream* st) const; @@ -1733,6 +1751,95 @@ ParGCAllocBuffer::retire(end_of_gc, retain); _retired = true; } + + bool is_retired() { + return _retired; + } +}; + +class G1ParGCAllocBufferContainer { +protected: + static int const _priority_max = 2; + G1ParGCAllocBuffer* _priority_buffer[_priority_max]; + +public: + G1ParGCAllocBufferContainer(size_t gclab_word_size) { + for (int pr = 0; pr < _priority_max; ++pr) { + _priority_buffer[pr] = new G1ParGCAllocBuffer(gclab_word_size); + } + } + + ~G1ParGCAllocBufferContainer() { + for (int pr = 0; pr < _priority_max; ++pr) { + assert(_priority_buffer[pr]->is_retired(), "alloc buffers should all retire at this point."); + delete _priority_buffer[pr]; + } + } + + HeapWord* allocate(size_t word_sz) { + HeapWord* obj; + for (int pr = 0; pr < _priority_max; ++pr) { + obj = _priority_buffer[pr]->allocate(word_sz); + if (obj != NULL) return obj; + } + return obj; + } + + bool contains(void* addr) { + for (int pr = 0; pr < _priority_max; ++pr) { + if (_priority_buffer[pr]->contains(addr)) return true; + } + return false; + } + + void undo_allocation(HeapWord* obj, size_t word_sz) { + bool finish_undo; + for (int pr = 0; pr < _priority_max; ++pr) { + if (_priority_buffer[pr]->contains(obj)) { + _priority_buffer[pr]->undo_allocation(obj, word_sz); + finish_undo = true; + } + } + if (!finish_undo) ShouldNotReachHere(); + } + + size_t words_remaining() { + size_t result = 0; + for (int pr = 0; pr < _priority_max; ++pr) { + result += _priority_buffer[pr]->words_remaining(); + } + return result; + } + + size_t words_remaining_in_retired_buffer() { + G1ParGCAllocBuffer* retired = _priority_buffer[0]; + return retired->words_remaining(); + } + + void flush_stats_and_retire(PLABStats* stats, bool end_of_gc, bool retain) { + for (int pr = 0; pr < _priority_max; ++pr) { + _priority_buffer[pr]->flush_stats_and_retire(stats, end_of_gc, retain); + } + } + + void update(bool end_of_gc, bool retain, HeapWord* buf, size_t word_sz) { + G1ParGCAllocBuffer* retired_and_set = _priority_buffer[0]; + retired_and_set->retire(end_of_gc, retain); + retired_and_set->set_buf(buf); + retired_and_set->set_word_size(word_sz); + adjust_priority_order(); + } + +private: + void adjust_priority_order() { + G1ParGCAllocBuffer* retired_and_set = _priority_buffer[0]; + + int last = _priority_max - 1; + for (int pr = 0; pr < last; ++pr) { + _priority_buffer[pr] = _priority_buffer[pr + 1]; + } + _priority_buffer[last] = retired_and_set; + } }; class G1ParScanThreadState : public StackObj { @@ -1743,9 +1850,9 @@ CardTableModRefBS* _ct_bs; G1RemSet* _g1_rem; - G1ParGCAllocBuffer _surviving_alloc_buffer; - G1ParGCAllocBuffer _tenured_alloc_buffer; - G1ParGCAllocBuffer* _alloc_buffers[GCAllocPurposeCount]; + G1ParGCAllocBufferContainer _surviving_alloc_buffer; + G1ParGCAllocBufferContainer _tenured_alloc_buffer; + G1ParGCAllocBufferContainer* _alloc_buffers[GCAllocPurposeCount]; ageTable _age_table; size_t _alloc_buffer_waste; @@ -1755,7 +1862,7 @@ G1ParScanHeapEvacClosure* _evac_cl; G1ParScanPartialArrayClosure* _partial_scan_cl; - int _hash_seed; + int _hash_seed; uint _queue_num; size_t _term_attempts; @@ -1809,7 +1916,7 @@ RefToScanQueue* refs() { return _refs; } ageTable* age_table() { return &_age_table; } - G1ParGCAllocBuffer* alloc_buffer(GCAllocPurpose purpose) { + G1ParGCAllocBufferContainer* alloc_buffer(GCAllocPurpose purpose) { return _alloc_buffers[purpose]; } @@ -1839,15 +1946,13 @@ HeapWord* obj = NULL; size_t gclab_word_size = _g1h->desired_plab_sz(purpose); if (word_sz * 100 < gclab_word_size * ParallelGCBufferWastePct) { - G1ParGCAllocBuffer* alloc_buf = alloc_buffer(purpose); - add_to_alloc_buffer_waste(alloc_buf->words_remaining()); - alloc_buf->retire(false /* end_of_gc */, false /* retain */); + G1ParGCAllocBufferContainer* alloc_buf = alloc_buffer(purpose); HeapWord* buf = _g1h->par_allocate_during_gc(purpose, gclab_word_size); if (buf == NULL) return NULL; // Let caller handle allocation failure. - // Otherwise. - alloc_buf->set_word_size(gclab_word_size); - alloc_buf->set_buf(buf); + + add_to_alloc_buffer_waste(alloc_buf->words_remaining_in_retired_buffer()); + alloc_buf->update(false /* end_of_gc */, false /* retain */, buf, gclab_word_size); obj = alloc_buf->allocate(word_sz); assert(obj != NULL, "buffer was definitely big enough..."); @@ -1959,7 +2064,6 @@ } } -public: void trim_queue(); };
--- a/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -909,7 +909,7 @@ // Anything below that is considered to be zero #define MIN_TIMER_GRANULARITY 0.0000001 -void G1CollectorPolicy::record_collection_pause_end(double pause_time_ms) { +void G1CollectorPolicy::record_collection_pause_end(double pause_time_ms, EvacuationInfo& evacuation_info) { double end_time_sec = os::elapsedTime(); assert(_cur_collection_pause_used_regions_at_start >= cset_region_length(), "otherwise, the subtraction below does not make sense"); @@ -941,6 +941,9 @@ _mmu_tracker->add_pause(end_time_sec - pause_time_ms/1000.0, end_time_sec, false); + evacuation_info.set_collectionset_used_before(_collection_set_bytes_used_before); + evacuation_info.set_bytes_copied(_bytes_copied_during_gc); + if (update_stats) { _trace_gen0_time_data.record_end_collection(pause_time_ms, phase_times()); // this is where we update the allocation rate of the application @@ -1896,7 +1899,7 @@ } -void G1CollectorPolicy::finalize_cset(double target_pause_time_ms) { +void G1CollectorPolicy::finalize_cset(double target_pause_time_ms, EvacuationInfo& evacuation_info) { double young_start_time_sec = os::elapsedTime(); YoungList* young_list = _g1->young_list(); @@ -2102,6 +2105,7 @@ double non_young_end_time_sec = os::elapsedTime(); phase_times()->record_non_young_cset_choice_time_ms((non_young_end_time_sec - non_young_start_time_sec) * 1000.0); + evacuation_info.set_collectionset_regions(cset_region_length()); } void TraceGen0TimeData::record_start_collection(double time_to_stop_the_world_ms) {
--- a/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp Fri Jun 21 15:56:24 2013 -0700 @@ -671,7 +671,7 @@ // Record the start and end of an evacuation pause. void record_collection_pause_start(double start_time_sec); - void record_collection_pause_end(double pause_time_ms); + void record_collection_pause_end(double pause_time_ms, EvacuationInfo& evacuation_info); // Record the start and end of a full collection. void record_full_collection_start(); @@ -720,7 +720,7 @@ // Choose a new collection set. Marks the chosen regions as being // "in_collection_set", and links them together. The head and number of // the collection set are available via access methods. - void finalize_cset(double target_pause_time_ms); + void finalize_cset(double target_pause_time_ms, EvacuationInfo& evacuation_info); // The head of the list (via "next_in_collection_set()") representing the // current collection set. @@ -879,6 +879,7 @@ ageTable _survivors_age_table; public: + uint tenuring_threshold() const { return _tenuring_threshold; } inline GCAllocPurpose evacuation_destination(HeapRegion* src_region, uint age, size_t word_sz) {
--- a/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.hpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.hpp Fri Jun 21 15:56:24 2013 -0700 @@ -38,7 +38,7 @@ NOT_PRODUCT(static const T _uninitialized;) // We are caching the sum and average to only have to calculate them once. - // This is not done in an MT-safe way. It is intetened to allow single + // This is not done in an MT-safe way. It is intended to allow single // threaded code to call sum() and average() multiple times in any order // without having to worry about the cost. bool _has_new_data;
--- a/src/share/vm/gc_implementation/g1/g1MarkSweep.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/gc_implementation/g1/g1MarkSweep.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,6 +31,10 @@ #include "code/icBuffer.hpp" #include "gc_implementation/g1/g1Log.hpp" #include "gc_implementation/g1/g1MarkSweep.hpp" +#include "gc_implementation/shared/gcHeapSummary.hpp" +#include "gc_implementation/shared/gcTimer.hpp" +#include "gc_implementation/shared/gcTrace.hpp" +#include "gc_implementation/shared/gcTraceTime.hpp" #include "memory/gcLocker.hpp" #include "memory/genCollectedHeap.hpp" #include "memory/modRefBarrierSet.hpp" @@ -119,7 +123,7 @@ void G1MarkSweep::mark_sweep_phase1(bool& marked_for_unloading, bool clear_all_softrefs) { // Recursively traverse all live objects and mark them - TraceTime tm("phase 1", G1Log::fine() && Verbose, true, gclog_or_tty); + GCTraceTime tm("phase 1", G1Log::fine() && Verbose, true, gc_timer()); GenMarkSweep::trace(" 1"); SharedHeap* sh = SharedHeap::heap(); @@ -139,10 +143,13 @@ assert(rp == G1CollectedHeap::heap()->ref_processor_stw(), "Sanity"); rp->setup_policy(clear_all_softrefs); - rp->process_discovered_references(&GenMarkSweep::is_alive, - &GenMarkSweep::keep_alive, - &GenMarkSweep::follow_stack_closure, - NULL); + const ReferenceProcessorStats& stats = + rp->process_discovered_references(&GenMarkSweep::is_alive, + &GenMarkSweep::keep_alive, + &GenMarkSweep::follow_stack_closure, + NULL, + gc_timer()); + gc_tracer()->report_gc_reference_stats(stats); // This is the point where the entire marking should have completed. @@ -185,6 +192,8 @@ gclog_or_tty->print_cr("]"); } } + + gc_tracer()->report_object_count_after_gc(&GenMarkSweep::is_alive); } class G1PrepareCompactClosure: public HeapRegionClosure { @@ -257,7 +266,7 @@ G1CollectedHeap* g1h = G1CollectedHeap::heap(); - TraceTime tm("phase 2", G1Log::fine() && Verbose, true, gclog_or_tty); + GCTraceTime tm("phase 2", G1Log::fine() && Verbose, true, gc_timer()); GenMarkSweep::trace("2"); // find the first region @@ -294,7 +303,7 @@ G1CollectedHeap* g1h = G1CollectedHeap::heap(); // Adjust the pointers to reflect the new locations - TraceTime tm("phase 3", G1Log::fine() && Verbose, true, gclog_or_tty); + GCTraceTime tm("phase 3", G1Log::fine() && Verbose, true, gc_timer()); GenMarkSweep::trace("3"); SharedHeap* sh = SharedHeap::heap(); @@ -353,7 +362,7 @@ // to use a higher index (saved from phase2) when verifying perm_gen. G1CollectedHeap* g1h = G1CollectedHeap::heap(); - TraceTime tm("phase 4", G1Log::fine() && Verbose, true, gclog_or_tty); + GCTraceTime tm("phase 4", G1Log::fine() && Verbose, true, gc_timer()); GenMarkSweep::trace("4"); G1SpaceCompactClosure blk;
--- a/src/share/vm/gc_implementation/g1/g1MarkSweep.hpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/gc_implementation/g1/g1MarkSweep.hpp Fri Jun 21 15:56:24 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -54,6 +54,9 @@ static void invoke_at_safepoint(ReferenceProcessor* rp, bool clear_all_softrefs); + static STWGCTimer* gc_timer() { return GenMarkSweep::_gc_timer; } + static SerialOldTracer* gc_tracer() { return GenMarkSweep::_gc_tracer; } + private: // Mark live objects
--- a/src/share/vm/gc_implementation/g1/g1MonitoringSupport.hpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/gc_implementation/g1/g1MonitoringSupport.hpp Fri Jun 21 15:56:24 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -224,6 +224,7 @@ // Monitoring support used by // MemoryService // jstat counters + // Tracing size_t overall_reserved() { return _overall_reserved; } size_t overall_committed() { return _overall_committed; }
--- a/src/share/vm/gc_implementation/g1/g1RemSet.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/gc_implementation/g1/g1RemSet.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -34,6 +34,7 @@ #include "gc_implementation/g1/g1OopClosures.inline.hpp" #include "gc_implementation/g1/g1RemSet.inline.hpp" #include "gc_implementation/g1/heapRegionSeq.inline.hpp" +#include "gc_implementation/g1/heapRegionRemSet.hpp" #include "memory/iterator.hpp" #include "oops/oop.inline.hpp" #include "utilities/intHisto.hpp" @@ -73,7 +74,8 @@ _ct_bs(ct_bs), _g1p(_g1->g1_policy()), _cg1r(g1->concurrent_g1_refine()), _cset_rs_update_cl(NULL), - _cards_scanned(NULL), _total_cards_scanned(0) + _cards_scanned(NULL), _total_cards_scanned(0), + _prev_period_summary() { _seq_task = new SubTasksDone(NumSeqTasks); guarantee(n_workers() > 0, "There should be some workers"); @@ -81,6 +83,7 @@ for (uint i = 0; i < n_workers(); i++) { _cset_rs_update_cl[i] = NULL; } + _prev_period_summary.initialize(this, n_workers()); } G1RemSet::~G1RemSet() { @@ -697,47 +700,29 @@ return has_refs_into_cset; } -class HRRSStatsIter: public HeapRegionClosure { - size_t _occupied; - size_t _total_mem_sz; - size_t _max_mem_sz; - HeapRegion* _max_mem_sz_region; -public: - HRRSStatsIter() : - _occupied(0), - _total_mem_sz(0), - _max_mem_sz(0), - _max_mem_sz_region(NULL) - {} +void G1RemSet::print_periodic_summary_info() { + G1RemSetSummary current; + current.initialize(this, n_workers()); - bool doHeapRegion(HeapRegion* r) { - if (r->continuesHumongous()) return false; - size_t mem_sz = r->rem_set()->mem_size(); - if (mem_sz > _max_mem_sz) { - _max_mem_sz = mem_sz; - _max_mem_sz_region = r; - } - _total_mem_sz += mem_sz; - size_t occ = r->rem_set()->occupied(); - _occupied += occ; - return false; - } - size_t total_mem_sz() { return _total_mem_sz; } - size_t max_mem_sz() { return _max_mem_sz; } - size_t occupied() { return _occupied; } - HeapRegion* max_mem_sz_region() { return _max_mem_sz_region; } -}; + _prev_period_summary.subtract_from(¤t); + print_summary_info(&_prev_period_summary); -class PrintRSThreadVTimeClosure : public ThreadClosure { -public: - virtual void do_thread(Thread *t) { - ConcurrentG1RefineThread* crt = (ConcurrentG1RefineThread*) t; - gclog_or_tty->print(" %5.2f", crt->vtime_accum()); - } -}; + _prev_period_summary.set(¤t); +} void G1RemSet::print_summary_info() { - G1CollectedHeap* g1 = G1CollectedHeap::heap(); + G1RemSetSummary current; + current.initialize(this, n_workers()); + + print_summary_info(¤t, " Cumulative RS summary"); +} + +void G1RemSet::print_summary_info(G1RemSetSummary * summary, const char * header) { + assert(summary != NULL, "just checking"); + + if (header != NULL) { + gclog_or_tty->print_cr("%s", header); + } #if CARD_REPEAT_HISTO gclog_or_tty->print_cr("\nG1 card_repeat count histogram: "); @@ -745,52 +730,13 @@ card_repeat_count.print_on(gclog_or_tty); #endif - gclog_or_tty->print_cr("\n Concurrent RS processed %d cards", - _conc_refine_cards); - DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set(); - jint tot_processed_buffers = - dcqs.processed_buffers_mut() + dcqs.processed_buffers_rs_thread(); - gclog_or_tty->print_cr(" Of %d completed buffers:", tot_processed_buffers); - gclog_or_tty->print_cr(" %8d (%5.1f%%) by conc RS threads.", - dcqs.processed_buffers_rs_thread(), - 100.0*(float)dcqs.processed_buffers_rs_thread()/ - (float)tot_processed_buffers); - gclog_or_tty->print_cr(" %8d (%5.1f%%) by mutator threads.", - dcqs.processed_buffers_mut(), - 100.0*(float)dcqs.processed_buffers_mut()/ - (float)tot_processed_buffers); - gclog_or_tty->print_cr(" Conc RS threads times(s)"); - PrintRSThreadVTimeClosure p; - gclog_or_tty->print(" "); - g1->concurrent_g1_refine()->threads_do(&p); - gclog_or_tty->print_cr(""); - - HRRSStatsIter blk; - g1->heap_region_iterate(&blk); - gclog_or_tty->print_cr(" Total heap region rem set sizes = "SIZE_FORMAT"K." - " Max = "SIZE_FORMAT"K.", - blk.total_mem_sz()/K, blk.max_mem_sz()/K); - gclog_or_tty->print_cr(" Static structures = "SIZE_FORMAT"K," - " free_lists = "SIZE_FORMAT"K.", - HeapRegionRemSet::static_mem_size() / K, - HeapRegionRemSet::fl_mem_size() / K); - gclog_or_tty->print_cr(" "SIZE_FORMAT" occupied cards represented.", - blk.occupied()); - HeapRegion* max_mem_sz_region = blk.max_mem_sz_region(); - HeapRegionRemSet* rem_set = max_mem_sz_region->rem_set(); - gclog_or_tty->print_cr(" Max size region = "HR_FORMAT", " - "size = "SIZE_FORMAT "K, occupied = "SIZE_FORMAT"K.", - HR_FORMAT_PARAMS(max_mem_sz_region), - (rem_set->mem_size() + K - 1)/K, - (rem_set->occupied() + K - 1)/K); - gclog_or_tty->print_cr(" Did %d coarsenings.", - HeapRegionRemSet::n_coarsenings()); + summary->print_on(gclog_or_tty); } void G1RemSet::prepare_for_verify() { if (G1HRRSFlushLogBuffersOnVerify && (VerifyBeforeGC || VerifyAfterGC) - && !_g1->full_collection()) { + && (!_g1->full_collection() || G1VerifyRSetsDuringFullGC)) { cleanupHRRS(); _g1->set_refine_cte_cl_concurrency(false); if (SafepointSynchronize::is_at_safepoint()) {
--- a/src/share/vm/gc_implementation/g1/g1RemSet.hpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/gc_implementation/g1/g1RemSet.hpp Fri Jun 21 15:56:24 2013 -0700 @@ -25,6 +25,8 @@ #ifndef SHARE_VM_GC_IMPLEMENTATION_G1_G1REMSET_HPP #define SHARE_VM_GC_IMPLEMENTATION_G1_G1REMSET_HPP +#include "gc_implementation/g1/g1RemSetSummary.hpp" + // A G1RemSet provides ways of iterating over pointers into a selected // collection set. @@ -37,9 +39,11 @@ // so that they can be used to update the individual region remsets. class G1RemSet: public CHeapObj<mtGC> { +private: + G1RemSetSummary _prev_period_summary; protected: G1CollectedHeap* _g1; - unsigned _conc_refine_cards; + size_t _conc_refine_cards; uint n_workers(); protected: @@ -66,6 +70,8 @@ // references into the collection set. OopsInHeapRegionClosure** _cset_rs_update_cl; + // Print the given summary info + virtual void print_summary_info(G1RemSetSummary * summary, const char * header = NULL); public: // This is called to reset dual hash tables after the gc pause // is finished and the initial hash table is no longer being @@ -123,11 +129,18 @@ int worker_i, bool check_for_refs_into_cset); - // Print any relevant summary info. + // Print accumulated summary info from the start of the VM. virtual void print_summary_info(); + // Print accumulated summary info from the last time called. + virtual void print_periodic_summary_info(); + // Prepare remembered set for verification. virtual void prepare_for_verify(); + + size_t conc_refine_cards() const { + return _conc_refine_cards; + } }; class CountNonCleanMemRegionClosure: public MemRegionClosure {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/gc_implementation/g1/g1RemSetSummary.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -0,0 +1,205 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "gc_implementation/g1/concurrentG1Refine.hpp" +#include "gc_implementation/g1/concurrentG1RefineThread.hpp" +#include "gc_implementation/g1/heapRegion.hpp" +#include "gc_implementation/g1/g1CollectedHeap.inline.hpp" +#include "gc_implementation/g1/g1RemSet.inline.hpp" +#include "gc_implementation/g1/g1RemSetSummary.hpp" +#include "gc_implementation/g1/heapRegionRemSet.hpp" +#include "runtime/thread.inline.hpp" + +class GetRSThreadVTimeClosure : public ThreadClosure { +private: + G1RemSetSummary* _summary; + uint _counter; + +public: + GetRSThreadVTimeClosure(G1RemSetSummary * summary) : ThreadClosure(), _summary(summary), _counter(0) { + assert(_summary != NULL, "just checking"); + } + + virtual void do_thread(Thread* t) { + ConcurrentG1RefineThread* crt = (ConcurrentG1RefineThread*) t; + _summary->set_rs_thread_vtime(_counter, crt->vtime_accum()); + _counter++; + } +}; + +void G1RemSetSummary::update() { + _num_refined_cards = remset()->conc_refine_cards(); + DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set(); + _num_processed_buf_mutator = dcqs.processed_buffers_mut(); + _num_processed_buf_rs_threads = dcqs.processed_buffers_rs_thread(); + + _num_coarsenings = HeapRegionRemSet::n_coarsenings(); + + ConcurrentG1Refine * cg1r = G1CollectedHeap::heap()->concurrent_g1_refine(); + if (_rs_threads_vtimes != NULL) { + GetRSThreadVTimeClosure p(this); + cg1r->worker_threads_do(&p); + } + set_sampling_thread_vtime(cg1r->sampling_thread()->vtime_accum()); +} + +void G1RemSetSummary::set_rs_thread_vtime(uint thread, double value) { + assert(_rs_threads_vtimes != NULL, "just checking"); + assert(thread < _num_vtimes, "just checking"); + _rs_threads_vtimes[thread] = value; +} + +double G1RemSetSummary::rs_thread_vtime(uint thread) const { + assert(_rs_threads_vtimes != NULL, "just checking"); + assert(thread < _num_vtimes, "just checking"); + return _rs_threads_vtimes[thread]; +} + +void G1RemSetSummary::initialize(G1RemSet* remset, uint num_workers) { + assert(_rs_threads_vtimes == NULL, "just checking"); + assert(remset != NULL, "just checking"); + + _remset = remset; + _num_vtimes = num_workers; + _rs_threads_vtimes = NEW_C_HEAP_ARRAY(double, _num_vtimes, mtGC); + memset(_rs_threads_vtimes, 0, sizeof(double) * _num_vtimes); + + update(); +} + +void G1RemSetSummary::set(G1RemSetSummary* other) { + assert(other != NULL, "just checking"); + assert(remset() == other->remset(), "just checking"); + assert(_num_vtimes == other->_num_vtimes, "just checking"); + + _num_refined_cards = other->num_concurrent_refined_cards(); + + _num_processed_buf_mutator = other->num_processed_buf_mutator(); + _num_processed_buf_rs_threads = other->num_processed_buf_rs_threads(); + + _num_coarsenings = other->_num_coarsenings; + + memcpy(_rs_threads_vtimes, other->_rs_threads_vtimes, sizeof(double) * _num_vtimes); + + set_sampling_thread_vtime(other->sampling_thread_vtime()); +} + +void G1RemSetSummary::subtract_from(G1RemSetSummary* other) { + assert(other != NULL, "just checking"); + assert(remset() == other->remset(), "just checking"); + assert(_num_vtimes == other->_num_vtimes, "just checking"); + + _num_refined_cards = other->num_concurrent_refined_cards() - _num_refined_cards; + + _num_processed_buf_mutator = other->num_processed_buf_mutator() - _num_processed_buf_mutator; + _num_processed_buf_rs_threads = other->num_processed_buf_rs_threads() - _num_processed_buf_rs_threads; + + _num_coarsenings = other->num_coarsenings() - _num_coarsenings; + + for (uint i = 0; i < _num_vtimes; i++) { + set_rs_thread_vtime(i, other->rs_thread_vtime(i) - rs_thread_vtime(i)); + } + + _sampling_thread_vtime = other->sampling_thread_vtime() - _sampling_thread_vtime; +} + +class HRRSStatsIter: public HeapRegionClosure { + size_t _occupied; + size_t _total_mem_sz; + size_t _max_mem_sz; + HeapRegion* _max_mem_sz_region; +public: + HRRSStatsIter() : + _occupied(0), + _total_mem_sz(0), + _max_mem_sz(0), + _max_mem_sz_region(NULL) + {} + + bool doHeapRegion(HeapRegion* r) { + size_t mem_sz = r->rem_set()->mem_size(); + if (mem_sz > _max_mem_sz) { + _max_mem_sz = mem_sz; + _max_mem_sz_region = r; + } + _total_mem_sz += mem_sz; + size_t occ = r->rem_set()->occupied(); + _occupied += occ; + return false; + } + size_t total_mem_sz() { return _total_mem_sz; } + size_t max_mem_sz() { return _max_mem_sz; } + size_t occupied() { return _occupied; } + HeapRegion* max_mem_sz_region() { return _max_mem_sz_region; } +}; + +double calc_percentage(size_t numerator, size_t denominator) { + if (denominator != 0) { + return (double)numerator / denominator * 100.0; + } else { + return 0.0f; + } +} + +void G1RemSetSummary::print_on(outputStream* out) { + out->print_cr("\n Concurrent RS processed "SIZE_FORMAT" cards", + num_concurrent_refined_cards()); + out->print_cr(" Of %d completed buffers:", num_processed_buf_total()); + out->print_cr(" %8d (%5.1f%%) by concurrent RS threads.", + num_processed_buf_total(), + calc_percentage(num_processed_buf_rs_threads(), num_processed_buf_total())); + out->print_cr(" %8d (%5.1f%%) by mutator threads.", + num_processed_buf_mutator(), + calc_percentage(num_processed_buf_mutator(), num_processed_buf_total())); + out->print_cr(" Concurrent RS threads times (s)"); + out->print(" "); + for (uint i = 0; i < _num_vtimes; i++) { + out->print(" %5.2f", rs_thread_vtime(i)); + } + out->cr(); + out->print_cr(" Concurrent sampling threads times (s)"); + out->print_cr(" %5.2f", sampling_thread_vtime()); + + HRRSStatsIter blk; + G1CollectedHeap::heap()->heap_region_iterate(&blk); + out->print_cr(" Total heap region rem set sizes = "SIZE_FORMAT"K." + " Max = "SIZE_FORMAT"K.", + blk.total_mem_sz()/K, blk.max_mem_sz()/K); + out->print_cr(" Static structures = "SIZE_FORMAT"K," + " free_lists = "SIZE_FORMAT"K.", + HeapRegionRemSet::static_mem_size() / K, + HeapRegionRemSet::fl_mem_size() / K); + out->print_cr(" "SIZE_FORMAT" occupied cards represented.", + blk.occupied()); + HeapRegion* max_mem_sz_region = blk.max_mem_sz_region(); + HeapRegionRemSet* rem_set = max_mem_sz_region->rem_set(); + out->print_cr(" Max size region = "HR_FORMAT", " + "size = "SIZE_FORMAT "K, occupied = "SIZE_FORMAT"K.", + HR_FORMAT_PARAMS(max_mem_sz_region), + (rem_set->mem_size() + K - 1)/K, + (rem_set->occupied() + K - 1)/K); + + out->print_cr(" Did %d coarsenings.", num_coarsenings()); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/gc_implementation/g1/g1RemSetSummary.hpp Fri Jun 21 15:56:24 2013 -0700 @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_GC_IMPLEMENTATION_G1_G1REMSETSUMMARY_HPP +#define SHARE_VM_GC_IMPLEMENTATION_G1_G1REMSETSUMMARY_HPP + +#include "utilities/ostream.hpp" + +class G1RemSet; + +// A G1RemSetSummary manages statistical information about the G1RemSet + +class G1RemSetSummary VALUE_OBJ_CLASS_SPEC { +private: + friend class GetRSThreadVTimeClosure; + + G1RemSet* _remset; + + G1RemSet* remset() const { + return _remset; + } + + size_t _num_refined_cards; + size_t _num_processed_buf_mutator; + size_t _num_processed_buf_rs_threads; + + size_t _num_coarsenings; + + double* _rs_threads_vtimes; + size_t _num_vtimes; + + double _sampling_thread_vtime; + + void set_rs_thread_vtime(uint thread, double value); + void set_sampling_thread_vtime(double value) { + _sampling_thread_vtime = value; + } + + void free_and_null() { + if (_rs_threads_vtimes) { + FREE_C_HEAP_ARRAY(double, _rs_threads_vtimes, mtGC); + _rs_threads_vtimes = NULL; + _num_vtimes = 0; + } + } + + // update this summary with current data from various places + void update(); + +public: + G1RemSetSummary() : _remset(NULL), _num_refined_cards(0), + _num_processed_buf_mutator(0), _num_processed_buf_rs_threads(0), _num_coarsenings(0), + _rs_threads_vtimes(NULL), _num_vtimes(0), _sampling_thread_vtime(0.0f) { + } + + ~G1RemSetSummary() { + free_and_null(); + } + + // set the counters in this summary to the values of the others + void set(G1RemSetSummary* other); + // subtract all counters from the other summary, and set them in the current + void subtract_from(G1RemSetSummary* other); + + // initialize and get the first sampling + void initialize(G1RemSet* remset, uint num_workers); + + void print_on(outputStream* out); + + double rs_thread_vtime(uint thread) const; + + double sampling_thread_vtime() const { + return _sampling_thread_vtime; + } + + size_t num_concurrent_refined_cards() const { + return _num_refined_cards; + } + + size_t num_processed_buf_mutator() const { + return _num_processed_buf_mutator; + } + + size_t num_processed_buf_rs_threads() const { + return _num_processed_buf_rs_threads; + } + + size_t num_processed_buf_total() const { + return num_processed_buf_mutator() + num_processed_buf_rs_threads(); + } + + size_t num_coarsenings() const { + return _num_coarsenings; + } +}; + +#endif // SHARE_VM_GC_IMPLEMENTATION_G1_G1REMSETSUMMARY_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/gc_implementation/g1/g1YCTypes.hpp Fri Jun 21 15:56:24 2013 -0700 @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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_G1YCTYPES_HPP +#define SHARE_VM_GC_IMPLEMENTATION_G1_G1YCTYPES_HPP + +#include "utilities/debug.hpp" + +enum G1YCType { + Normal, + InitialMark, + DuringMark, + Mixed, + G1YCTypeEndSentinel +}; + +class G1YCTypeHelper { + public: + static const char* to_string(G1YCType type) { + switch(type) { + case Normal: return "Normal"; + case InitialMark: return "Initial Mark"; + case DuringMark: return "During Mark"; + case Mixed: return "Mixed"; + default: ShouldNotReachHere(); return NULL; + } + } +}; + +#endif // SHARE_VM_GC_IMPLEMENTATION_G1_G1YCTYPES_HPP
--- a/src/share/vm/gc_implementation/g1/g1_globals.hpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/gc_implementation/g1/g1_globals.hpp Fri Jun 21 15:56:24 2013 -0700 @@ -329,7 +329,11 @@ \ develop(bool, G1EvacuationFailureALotDuringMixedGC, true, \ "Force use of evacuation failure handling during mixed " \ - "evacuation pauses") + "evacuation pauses") \ + \ + diagnostic(bool, G1VerifyRSetsDuringFullGC, false, \ + "If true, perform verification of each heap region's " \ + "remembered set when verifying the heap during a full GC.") G1_FLAGS(DECLARE_DEVELOPER_FLAG, DECLARE_PD_DEVELOPER_FLAG, DECLARE_PRODUCT_FLAG, DECLARE_PD_PRODUCT_FLAG, DECLARE_DIAGNOSTIC_FLAG, DECLARE_EXPERIMENTAL_FLAG, DECLARE_NOTPRODUCT_FLAG, DECLARE_MANAGEABLE_FLAG, DECLARE_PRODUCT_RW_FLAG)
--- a/src/share/vm/gc_implementation/g1/heapRegion.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/gc_implementation/g1/heapRegion.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -139,7 +139,7 @@ _n_failures++; } - if (!_g1h->full_collection()) { + if (!_g1h->full_collection() || G1VerifyRSetsDuringFullGC) { HeapRegion* from = _g1h->heap_region_containing((HeapWord*)p); HeapRegion* to = _g1h->heap_region_containing(obj); if (from != NULL && to != NULL &&
--- a/src/share/vm/gc_implementation/g1/vm_operations_g1.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/gc_implementation/g1/vm_operations_g1.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,6 +28,8 @@ #include "gc_implementation/g1/g1CollectorPolicy.hpp" #include "gc_implementation/g1/g1Log.hpp" #include "gc_implementation/g1/vm_operations_g1.hpp" +#include "gc_implementation/shared/gcTimer.hpp" +#include "gc_implementation/shared/gcTraceTime.hpp" #include "gc_implementation/shared/isGCActiveMark.hpp" #include "gc_implementation/g1/vm_operations_g1.hpp" #include "runtime/interfaceSupport.hpp" @@ -227,7 +229,7 @@ void VM_CGC_Operation::doit() { gclog_or_tty->date_stamp(G1Log::fine() && PrintGCDateStamps); TraceCPUTime tcpu(G1Log::finer(), true, gclog_or_tty); - TraceTime t(_printGCMessage, G1Log::fine(), true, gclog_or_tty); + GCTraceTime t(_printGCMessage, G1Log::fine(), true, G1CollectedHeap::heap()->gc_timer_cm()); SharedHeap* sh = SharedHeap::heap(); // This could go away if CollectedHeap gave access to _gc_is_active... if (sh != NULL) {
--- a/src/share/vm/gc_implementation/parNew/asParNewGeneration.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/gc_implementation/parNew/asParNewGeneration.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -585,8 +585,7 @@ size_policy->avg_young_live()->sample(used()); size_policy->avg_eden_live()->sample(eden()->used()); - size_policy->compute_young_generation_free_space(eden()->capacity(), - max_gen_size()); + size_policy->compute_eden_space_size(eden()->capacity(), max_gen_size()); resize(size_policy->calculated_eden_size_in_bytes(), size_policy->calculated_survivor_size_in_bytes());
--- a/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,6 +29,11 @@ #include "gc_implementation/shared/adaptiveSizePolicy.hpp" #include "gc_implementation/shared/ageTable.hpp" #include "gc_implementation/shared/parGCAllocBuffer.hpp" +#include "gc_implementation/shared/gcHeapSummary.hpp" +#include "gc_implementation/shared/gcTimer.hpp" +#include "gc_implementation/shared/gcTrace.hpp" +#include "gc_implementation/shared/gcTraceTime.hpp" +#include "gc_implementation/shared/copyFailedInfo.hpp" #include "gc_implementation/shared/spaceDecorator.hpp" #include "memory/defNewGeneration.inline.hpp" #include "memory/genCollectedHeap.hpp" @@ -75,7 +80,6 @@ work_queue_set_, &term_), _is_alive_closure(gen_), _scan_weak_ref_closure(gen_, this), _keep_alive_closure(&_scan_weak_ref_closure), - _promotion_failure_size(0), _strong_roots_time(0.0), _term_time(0.0) { #if TASKQUEUE_STATS @@ -279,13 +283,10 @@ } } -void ParScanThreadState::print_and_clear_promotion_failure_size() { - if (_promotion_failure_size != 0) { - if (PrintPromotionFailure) { - gclog_or_tty->print(" (%d: promotion failure size = " SIZE_FORMAT ") ", - _thread_num, _promotion_failure_size); - } - _promotion_failure_size = 0; +void ParScanThreadState::print_promotion_failure_size() { + if (_promotion_failed_info.has_failed() && PrintPromotionFailure) { + gclog_or_tty->print(" (%d: promotion failure size = " SIZE_FORMAT ") ", + _thread_num, _promotion_failed_info.first_size()); } } @@ -305,6 +306,7 @@ inline ParScanThreadState& thread_state(int i); + void trace_promotion_failed(YoungGCTracer& gc_tracer); void reset(int active_workers, bool promotion_failed); void flush(); @@ -353,13 +355,21 @@ return ((ParScanThreadState*)_data)[i]; } +void ParScanThreadStateSet::trace_promotion_failed(YoungGCTracer& gc_tracer) { + for (int i = 0; i < length(); ++i) { + if (thread_state(i).promotion_failed()) { + gc_tracer.report_promotion_failed(thread_state(i).promotion_failed_info()); + thread_state(i).promotion_failed_info().reset(); + } + } +} void ParScanThreadStateSet::reset(int active_threads, bool promotion_failed) { _term.reset_for_reuse(active_threads); if (promotion_failed) { for (int i = 0; i < length(); ++i) { - thread_state(i).print_and_clear_promotion_failure_size(); + thread_state(i).print_promotion_failure_size(); } } } @@ -583,14 +593,6 @@ gch->set_n_termination(active_workers); } -// The "i" passed to this method is the part of the work for -// this thread. It is not the worker ID. The "i" is derived -// from _started_workers which is incremented in internal_note_start() -// called in GangWorker loop() and which is called under the -// which is called under the protection of the gang monitor and is -// called after a task is started. So "i" is based on -// first-come-first-served. - void ParNewGenTask::work(uint worker_id) { GenCollectedHeap* gch = GenCollectedHeap::heap(); // Since this is being done in a separate thread, need new resource @@ -876,16 +878,45 @@ } +// A Generation that does parallel young-gen collection. + bool ParNewGeneration::_avoid_promotion_undo = false; -// A Generation that does parallel young-gen collection. +void ParNewGeneration::handle_promotion_failed(GenCollectedHeap* gch, ParScanThreadStateSet& thread_state_set, ParNewTracer& gc_tracer) { + assert(_promo_failure_scan_stack.is_empty(), "post condition"); + _promo_failure_scan_stack.clear(true); // Clear cached segments. + + remove_forwarding_pointers(); + if (PrintGCDetails) { + gclog_or_tty->print(" (promotion failed)"); + } + // All the spaces are in play for mark-sweep. + swap_spaces(); // Make life simpler for CMS || rescan; see 6483690. + from()->set_next_compaction_space(to()); + gch->set_incremental_collection_failed(); + // Inform the next generation that a promotion failure occurred. + _next_gen->promotion_failure_occurred(); + + // Trace promotion failure in the parallel GC threads + thread_state_set.trace_promotion_failed(gc_tracer); + // Single threaded code may have reported promotion failure to the global state + if (_promotion_failed_info.has_failed()) { + gc_tracer.report_promotion_failed(_promotion_failed_info); + } + // Reset the PromotionFailureALot counters. + NOT_PRODUCT(Universe::heap()->reset_promotion_should_fail();) +} void ParNewGeneration::collect(bool full, bool clear_all_soft_refs, size_t size, bool is_tlab) { assert(full || size > 0, "otherwise we don't want to collect"); + GenCollectedHeap* gch = GenCollectedHeap::heap(); + + _gc_timer->register_gc_start(os::elapsed_counter()); + assert(gch->kind() == CollectedHeap::GenCollectedHeap, "not a CMS generational heap"); AdaptiveSizePolicy* size_policy = gch->gen_policy()->size_policy(); @@ -906,7 +937,7 @@ set_avoid_promotion_undo(true); } - // If the next generation is too full to accomodate worst-case promotion + // If the next generation is too full to accommodate worst-case promotion // from this generation, pass on collection; let the next generation // do it. if (!collection_attempt_is_safe()) { @@ -915,6 +946,10 @@ } assert(to()->is_empty(), "Else not collection_attempt_is_safe"); + ParNewTracer gc_tracer; + gc_tracer.report_gc_start(gch->gc_cause(), _gc_timer->gc_start()); + gch->trace_heap_before_gc(&gc_tracer); + init_assuming_no_promotion_failure(); if (UseAdaptiveSizePolicy) { @@ -922,7 +957,7 @@ size_policy->minor_collection_begin(); } - TraceTime t1(GCCauseString("GC", gch->gc_cause()), PrintGC && !PrintGCDetails, true, gclog_or_tty); + GCTraceTime t1(GCCauseString("GC", gch->gc_cause()), PrintGC && !PrintGCDetails, true, NULL); // Capture heap used before collection (for printing). size_t gch_prev_used = gch->used(); @@ -975,17 +1010,21 @@ rp->setup_policy(clear_all_soft_refs); // Can the mt_degree be set later (at run_task() time would be best)? rp->set_active_mt_degree(active_workers); + ReferenceProcessorStats stats; if (rp->processing_is_mt()) { ParNewRefProcTaskExecutor task_executor(*this, thread_state_set); - rp->process_discovered_references(&is_alive, &keep_alive, - &evacuate_followers, &task_executor); + stats = rp->process_discovered_references(&is_alive, &keep_alive, + &evacuate_followers, &task_executor, + _gc_timer); } else { thread_state_set.flush(); gch->set_par_threads(0); // 0 ==> non-parallel. gch->save_marks(); - rp->process_discovered_references(&is_alive, &keep_alive, - &evacuate_followers, NULL); + stats = rp->process_discovered_references(&is_alive, &keep_alive, + &evacuate_followers, NULL, + _gc_timer); } + gc_tracer.report_gc_reference_stats(stats); if (!promotion_failed()) { // Swap the survivor spaces. eden()->clear(SpaceDecorator::Mangle); @@ -1010,22 +1049,7 @@ adjust_desired_tenuring_threshold(); } else { - assert(_promo_failure_scan_stack.is_empty(), "post condition"); - _promo_failure_scan_stack.clear(true); // Clear cached segments. - - remove_forwarding_pointers(); - if (PrintGCDetails) { - gclog_or_tty->print(" (promotion failed)"); - } - // All the spaces are in play for mark-sweep. - swap_spaces(); // Make life simpler for CMS || rescan; see 6483690. - from()->set_next_compaction_space(to()); - gch->set_incremental_collection_failed(); - // Inform the next generation that a promotion failure occurred. - _next_gen->promotion_failure_occurred(); - - // Reset the PromotionFailureALot counters. - NOT_PRODUCT(Universe::heap()->reset_promotion_should_fail();) + handle_promotion_failed(gch, thread_state_set, gc_tracer); } // set new iteration safe limit for the survivor spaces from()->set_concurrent_iteration_safe_limit(from()->top()); @@ -1065,6 +1089,13 @@ rp->enqueue_discovered_references(NULL); } rp->verify_no_references_recorded(); + + gch->trace_heap_after_gc(&gc_tracer); + gc_tracer.report_tenuring_threshold(tenuring_threshold()); + + _gc_timer->register_gc_end(os::elapsed_counter()); + + gc_tracer.report_gc_end(_gc_timer->gc_end(), _gc_timer->time_partitions()); } static int sum; @@ -1174,8 +1205,7 @@ new_obj = old; preserve_mark_if_necessary(old, m); - // Log the size of the maiden promotion failure - par_scan_state->log_promotion_failure(sz); + par_scan_state->register_promotion_failure(sz); } old->forward_to(new_obj); @@ -1300,8 +1330,7 @@ failed_to_promote = true; preserve_mark_if_necessary(old, m); - // Log the size of the maiden promotion failure - par_scan_state->log_promotion_failure(sz); + par_scan_state->register_promotion_failure(sz); } } else { // Is in to-space; do copying ourselves. @@ -1599,8 +1628,7 @@ } #undef BUSY -void ParNewGeneration::ref_processor_init() -{ +void ParNewGeneration::ref_processor_init() { if (_ref_processor == NULL) { // Allocate and initialize a reference processor _ref_processor =
--- a/src/share/vm/gc_implementation/parNew/parNewGeneration.hpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/gc_implementation/parNew/parNewGeneration.hpp Fri Jun 21 15:56:24 2013 -0700 @@ -25,7 +25,9 @@ #ifndef SHARE_VM_GC_IMPLEMENTATION_PARNEW_PARNEWGENERATION_HPP #define SHARE_VM_GC_IMPLEMENTATION_PARNEW_PARNEWGENERATION_HPP +#include "gc_implementation/shared/gcTrace.hpp" #include "gc_implementation/shared/parGCAllocBuffer.hpp" +#include "gc_implementation/shared/copyFailedInfo.hpp" #include "memory/defNewGeneration.hpp" #include "utilities/taskqueue.hpp" @@ -105,7 +107,7 @@ #endif // TASKQUEUE_STATS // Stats for promotion failure - size_t _promotion_failure_size; + PromotionFailedInfo _promotion_failed_info; // Timing numbers. double _start; @@ -180,13 +182,16 @@ void undo_alloc_in_to_space(HeapWord* obj, size_t word_sz); // Promotion failure stats - size_t promotion_failure_size() { return promotion_failure_size(); } - void log_promotion_failure(size_t sz) { - if (_promotion_failure_size == 0) { - _promotion_failure_size = sz; - } + void register_promotion_failure(size_t sz) { + _promotion_failed_info.register_copy_failure(sz); } - void print_and_clear_promotion_failure_size(); + PromotionFailedInfo& promotion_failed_info() { + return _promotion_failed_info; + } + bool promotion_failed() { + return _promotion_failed_info.has_failed(); + } + void print_promotion_failure_size(); #if TASKQUEUE_STATS TaskQueueStats & taskqueue_stats() const { return _work_queue->stats; } @@ -337,6 +342,8 @@ // word being overwritten with a self-forwarding-pointer. void preserve_mark_if_necessary(oop obj, markOop m); + void handle_promotion_failed(GenCollectedHeap* gch, ParScanThreadStateSet& thread_state_set, ParNewTracer& gc_tracer); + protected: bool _survivor_overflow;
--- a/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code