# HG changeset patch # User kvn # Date 1371855384 25200 # Node ID b5c8a61d7fa041757e85f7d45005544784e6bfda # Parent d2907f74462eb9ec6d13b5075429f3e76e77396f# Parent aaa45012be984b7d153d398495a03302c695e05d Merge diff -r d2907f74462e -r b5c8a61d7fa0 .hgtags --- 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 diff -r d2907f74462e -r b5c8a61d7fa0 agent/src/share/classes/sun/jvm/hotspot/memory/DictionaryEntry.java --- 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())) { diff -r d2907f74462e -r b5c8a61d7fa0 agent/src/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java --- 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); diff -r d2907f74462e -r b5c8a61d7fa0 agent/src/share/classes/sun/jvm/hotspot/utilities/HeapGXLWriter.java --- 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();) { diff -r d2907f74462e -r b5c8a61d7fa0 agent/src/share/classes/sun/jvm/hotspot/utilities/HeapHprofBinWriter.java --- 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); diff -r d2907f74462e -r b5c8a61d7fa0 agent/src/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaInstanceKlass.java --- 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); } diff -r d2907f74462e -r b5c8a61d7fa0 make/Makefile --- 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: diff -r d2907f74462e -r b5c8a61d7fa0 make/bsd/makefiles/adlc.make --- 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) diff -r d2907f74462e -r b5c8a61d7fa0 make/bsd/makefiles/buildtree.make --- 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) ( \ diff -r d2907f74462e -r b5c8a61d7fa0 make/bsd/makefiles/gcc.make --- 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 diff -r d2907f74462e -r b5c8a61d7fa0 make/bsd/makefiles/minimal1.make --- 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\" diff -r d2907f74462e -r b5c8a61d7fa0 make/bsd/makefiles/top.make --- 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) diff -r d2907f74462e -r b5c8a61d7fa0 make/bsd/makefiles/trace.make --- /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) + diff -r d2907f74462e -r b5c8a61d7fa0 make/bsd/makefiles/vm.make --- 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_.[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 diff -r d2907f74462e -r b5c8a61d7fa0 make/defs.make --- 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 diff -r d2907f74462e -r b5c8a61d7fa0 make/excludeSrc.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 diff -r d2907f74462e -r b5c8a61d7fa0 make/hotspot_version --- 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 diff -r d2907f74462e -r b5c8a61d7fa0 make/linux/makefiles/adlc.make --- 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 = \ diff -r d2907f74462e -r b5c8a61d7fa0 make/linux/makefiles/buildtree.make --- 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) ( \ diff -r d2907f74462e -r b5c8a61d7fa0 make/linux/makefiles/gcc.make --- 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 + + +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 -# 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 + 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 diff -r d2907f74462e -r b5c8a61d7fa0 make/linux/makefiles/minimal1.make --- 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\" diff -r d2907f74462e -r b5c8a61d7fa0 make/linux/makefiles/top.make --- 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) diff -r d2907f74462e -r b5c8a61d7fa0 make/linux/makefiles/trace.make --- /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) + + diff -r d2907f74462e -r b5c8a61d7fa0 make/linux/makefiles/vm.make --- 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_.[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) { \ diff -r d2907f74462e -r b5c8a61d7fa0 make/solaris/makefiles/buildtree.make --- 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) ( \ diff -r d2907f74462e -r b5c8a61d7fa0 make/solaris/makefiles/top.make --- 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 diff -r d2907f74462e -r b5c8a61d7fa0 make/solaris/makefiles/trace.make --- /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) + + diff -r d2907f74462e -r b5c8a61d7fa0 make/solaris/makefiles/vm.make --- 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_.[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) diff -r d2907f74462e -r b5c8a61d7fa0 make/windows/build.make --- 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) >> $@ diff -r d2907f74462e -r b5c8a61d7fa0 make/windows/create_obj_files.sh --- 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" diff -r d2907f74462e -r b5c8a61d7fa0 make/windows/makefiles/generated.make --- 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: diff -r d2907f74462e -r b5c8a61d7fa0 make/windows/makefiles/projectcreator.make --- 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 diff -r d2907f74462e -r b5c8a61d7fa0 make/windows/makefiles/trace.make --- /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) + + diff -r d2907f74462e -r b5c8a61d7fa0 make/windows/makefiles/vm.make --- 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:: diff -r d2907f74462e -r b5c8a61d7fa0 make/windows/projectfiles/common/Makefile --- 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 diff -r d2907f74462e -r b5c8a61d7fa0 src/cpu/sparc/vm/cppInterpreter_sparc.cpp --- 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 diff -r d2907f74462e -r b5c8a61d7fa0 src/cpu/sparc/vm/frame_sparc.cpp --- 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; } diff -r d2907f74462e -r b5c8a61d7fa0 src/cpu/sparc/vm/interp_masm_sparc.cpp --- 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 diff -r d2907f74462e -r b5c8a61d7fa0 src/cpu/sparc/vm/templateInterpreter_sparc.cpp --- 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 diff -r d2907f74462e -r b5c8a61d7fa0 src/cpu/x86/vm/cppInterpreter_x86.cpp --- 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; diff -r d2907f74462e -r b5c8a61d7fa0 src/cpu/x86/vm/frame_x86.cpp --- 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... diff -r d2907f74462e -r b5c8a61d7fa0 src/cpu/x86/vm/templateInterpreter_x86_32.cpp --- 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; } diff -r d2907f74462e -r b5c8a61d7fa0 src/cpu/x86/vm/templateInterpreter_x86_64.cpp --- 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); } diff -r d2907f74462e -r b5c8a61d7fa0 src/os/bsd/vm/osThread_bsd.hpp --- 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. diff -r d2907f74462e -r b5c8a61d7fa0 src/os/bsd/vm/os_bsd.cpp --- 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; } + diff -r d2907f74462e -r b5c8a61d7fa0 src/os/bsd/vm/os_bsd.hpp --- 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 { 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 diff -r d2907f74462e -r b5c8a61d7fa0 src/os/bsd/vm/os_bsd.inline.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 diff -r d2907f74462e -r b5c8a61d7fa0 src/os/linux/vm/osThread_linux.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. diff -r d2907f74462e -r b5c8a61d7fa0 src/os/linux/vm/os_linux.cpp --- 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 # include +// 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 diff -r d2907f74462e -r b5c8a61d7fa0 src/os/linux/vm/os_linux.hpp --- 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 diff -r d2907f74462e -r b5c8a61d7fa0 src/os/linux/vm/os_linux.inline.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 diff -r d2907f74462e -r b5c8a61d7fa0 src/os/solaris/vm/osThread_solaris.cpp --- 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); +} diff -r d2907f74462e -r b5c8a61d7fa0 src/os/solaris/vm/osThread_solaris.hpp --- 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. diff -r d2907f74462e -r b5c8a61d7fa0 src/os/solaris/vm/os_share_solaris.hpp --- 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*); diff -r d2907f74462e -r b5c8a61d7fa0 src/os/solaris/vm/os_solaris.cpp --- 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(); } diff -r d2907f74462e -r b5c8a61d7fa0 src/os/solaris/vm/os_solaris.hpp --- 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(); diff -r d2907f74462e -r b5c8a61d7fa0 src/os/windows/vm/os_windows.cpp --- 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); diff -r d2907f74462e -r b5c8a61d7fa0 src/os_cpu/bsd_x86/vm/thread_bsd_x86.cpp --- 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 diff -r d2907f74462e -r b5c8a61d7fa0 src/os_cpu/bsd_x86/vm/thread_bsd_x86.hpp --- 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; } diff -r d2907f74462e -r b5c8a61d7fa0 src/os_cpu/linux_x86/vm/linux_x86_32.s --- 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 diff -r d2907f74462e -r b5c8a61d7fa0 src/os_cpu/linux_x86/vm/os_linux_x86.cpp --- 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 diff -r d2907f74462e -r b5c8a61d7fa0 src/os_cpu/linux_x86/vm/thread_linux_x86.cpp --- 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 diff -r d2907f74462e -r b5c8a61d7fa0 src/os_cpu/linux_x86/vm/thread_linux_x86.hpp --- 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; } diff -r d2907f74462e -r b5c8a61d7fa0 src/os_cpu/solaris_sparc/vm/os_solaris_sparc.cpp --- 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; diff -r d2907f74462e -r b5c8a61d7fa0 src/os_cpu/solaris_sparc/vm/thread_solaris_sparc.cpp --- 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 diff -r d2907f74462e -r b5c8a61d7fa0 src/os_cpu/solaris_sparc/vm/thread_solaris_sparc.hpp --- 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; } diff -r d2907f74462e -r b5c8a61d7fa0 src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp --- 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; diff -r d2907f74462e -r b5c8a61d7fa0 src/os_cpu/solaris_x86/vm/thread_solaris_x86.cpp --- 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; diff -r d2907f74462e -r b5c8a61d7fa0 src/os_cpu/solaris_x86/vm/thread_solaris_x86.hpp --- 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). diff -r d2907f74462e -r b5c8a61d7fa0 src/os_cpu/windows_x86/vm/thread_windows_x86.cpp --- 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() { } - diff -r d2907f74462e -r b5c8a61d7fa0 src/os_cpu/windows_x86/vm/thread_windows_x86.hpp --- 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; } diff -r d2907f74462e -r b5c8a61d7fa0 src/share/tools/ProjectCreator/BuildConfig.java --- 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\\\""); diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/adlc/archDesc.cpp --- 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]; diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/adlc/dict2.cpp --- 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<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<> 1); // Hash key, un-modulo'd table size } diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/adlc/formssel.cpp --- 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(); } diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/adlc/formssel.hpp --- 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 diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/adlc/output_c.cpp --- 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", diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/c1/c1_LIRGenerator.cpp --- 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 diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/classfile/classFileParser.cpp --- 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); diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/classfile/classLoaderData.cpp --- 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* 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 */ diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/classfile/classLoaderData.hpp --- 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. diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/classfile/defaultMethods.cpp --- 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); diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/classfile/javaClasses.cpp --- 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* java_lang_Class::_fixup_mirror_list = NULL; int java_lang_Throwable::backtrace_offset; int java_lang_Throwable::detailMessage_offset; diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/classfile/javaClasses.hpp --- 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* _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); diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/classfile/symbolTable.cpp --- 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** p = the_table()->bucket_addr(i); HashtableEntry* 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*)HashtableEntry::make_ptr(*p); + entry = *p; } } } void StringTable::oops_do(OopClosure* f) { for (int i = 0; i < the_table()->table_size(); ++i) { - HashtableEntry** p = the_table()->bucket_addr(i); HashtableEntry* 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*)HashtableEntry::make_ptr(*p); + entry = entry->next(); } } } diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/classfile/symbolTable.hpp --- 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); diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/classfile/systemDictionary.cpp --- 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 diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/classfile/systemDictionary.hpp --- 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. diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/classfile/verifier.hpp --- 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; diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/classfile/vmSymbols.hpp --- 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") \ \ diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/code/codeCache.cpp --- 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 diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/code/codeCache.hpp --- 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 diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/code/nmethod.cpp --- 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 } diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/compiler/compileBroker.cpp --- 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* 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 && diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/compiler/compileBroker.hpp --- 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 diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/compiler/compileLog.cpp --- 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; } // ------------------------------------------------------------------ diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/compiler/compileLog.hpp --- 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; } diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/gc_implementation/concurrentMarkSweep/cmsAdaptiveSizePolicy.cpp --- 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); diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/gc_implementation/concurrentMarkSweep/cmsAdaptiveSizePolicy.hpp --- 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( diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp --- 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) { diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp --- 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; diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepThread.cpp --- 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 diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/gc_implementation/concurrentMarkSweep/vmCMSOperations.cpp --- 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 diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/gc_implementation/g1/concurrentG1Refine.cpp --- 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()]; +} diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/gc_implementation/g1/concurrentG1Refine.hpp --- 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 { 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; diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/gc_implementation/g1/concurrentMark.cpp --- 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, diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/gc_implementation/g1/concurrentMark.hpp --- 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();) diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/gc_implementation/g1/concurrentMarkThread.cpp --- 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"); diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/gc_implementation/g1/evacuationInfo.hpp --- /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 diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp --- 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(); diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp --- 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 RefToScanQueue; typedef GenericTaskQueueSet 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(); }; diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp --- 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) { diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp --- 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) { diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/gc_implementation/g1/g1GCPhaseTimes.hpp --- 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; diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/gc_implementation/g1/g1MarkSweep.cpp --- 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; diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/gc_implementation/g1/g1MarkSweep.hpp --- 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 diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/gc_implementation/g1/g1MonitoringSupport.hpp --- 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; } diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/gc_implementation/g1/g1RemSet.cpp --- 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()) { diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/gc_implementation/g1/g1RemSet.hpp --- 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 { +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 { diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/gc_implementation/g1/g1RemSetSummary.cpp --- /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()); +} diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/gc_implementation/g1/g1RemSetSummary.hpp --- /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 diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/gc_implementation/g1/g1YCTypes.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 diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/gc_implementation/g1/g1_globals.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) diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/gc_implementation/g1/heapRegion.cpp --- 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 && diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/gc_implementation/g1/vm_operations_g1.cpp --- 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) { diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/gc_implementation/parNew/asParNewGeneration.cpp --- 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()); diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/gc_implementation/parNew/parNewGeneration.cpp --- 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 = diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/gc_implementation/parNew/parNewGeneration.hpp --- 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; diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp --- 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 is free software; you can redistribute it and/or modify it @@ -35,6 +35,8 @@ #include "gc_implementation/parallelScavenge/psPromotionManager.hpp" #include "gc_implementation/parallelScavenge/psScavenge.hpp" #include "gc_implementation/parallelScavenge/vmPSOperations.hpp" +#include "gc_implementation/shared/gcHeapSummary.hpp" +#include "gc_implementation/shared/gcWhen.hpp" #include "memory/gcLocker.inline.hpp" #include "oops/oop.inline.hpp" #include "runtime/handles.inline.hpp" @@ -642,6 +644,29 @@ ensure_parsability(false); // no need to retire TLABs for verification } +PSHeapSummary ParallelScavengeHeap::create_ps_heap_summary() { + PSOldGen* old = old_gen(); + HeapWord* old_committed_end = (HeapWord*)old->virtual_space()->committed_high_addr(); + VirtualSpaceSummary old_summary(old->reserved().start(), old_committed_end, old->reserved().end()); + SpaceSummary old_space(old->reserved().start(), old_committed_end, old->used_in_bytes()); + + PSYoungGen* young = young_gen(); + VirtualSpaceSummary young_summary(young->reserved().start(), + (HeapWord*)young->virtual_space()->committed_high_addr(), young->reserved().end()); + + MutableSpace* eden = young_gen()->eden_space(); + SpaceSummary eden_space(eden->bottom(), eden->end(), eden->used_in_bytes()); + + MutableSpace* from = young_gen()->from_space(); + SpaceSummary from_space(from->bottom(), from->end(), from->used_in_bytes()); + + MutableSpace* to = young_gen()->to_space(); + SpaceSummary to_space(to->bottom(), to->end(), to->used_in_bytes()); + + VirtualSpaceSummary heap_summary = create_heap_space_summary(); + return PSHeapSummary(heap_summary, used(), old_summary, old_space, young_summary, eden_space, from_space, to_space); +} + void ParallelScavengeHeap::print_on(outputStream* st) const { young_gen()->print_on(st); old_gen()->print_on(st); @@ -706,6 +731,12 @@ } } +void ParallelScavengeHeap::trace_heap(GCWhen::Type when, GCTracer* gc_tracer) { + const PSHeapSummary& heap_summary = create_ps_heap_summary(); + const MetaspaceSummary& metaspace_summary = create_metaspace_summary(); + gc_tracer->report_gc_heap_summary(when, heap_summary, metaspace_summary); +} + ParallelScavengeHeap* ParallelScavengeHeap::heap() { assert(_psh != NULL, "Uninitialized access to ParallelScavengeHeap::heap()"); assert(_psh->kind() == CollectedHeap::ParallelScavengeHeap, "not a parallel scavenge heap"); diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.hpp --- a/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.hpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.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 @@ -30,14 +30,18 @@ #include "gc_implementation/parallelScavenge/psOldGen.hpp" #include "gc_implementation/parallelScavenge/psYoungGen.hpp" #include "gc_implementation/shared/gcPolicyCounters.hpp" +#include "gc_implementation/shared/gcWhen.hpp" #include "gc_interface/collectedHeap.inline.hpp" #include "utilities/ostream.hpp" class AdjoiningGenerations; +class CollectorPolicy; +class GCHeapSummary; class GCTaskManager; -class PSAdaptiveSizePolicy; class GenerationSizer; class CollectorPolicy; +class PSAdaptiveSizePolicy; +class PSHeapSummary; class ParallelScavengeHeap : public CollectedHeap { friend class VMStructs; @@ -65,6 +69,8 @@ static GCTaskManager* _gc_task_manager; // The task manager. + void trace_heap(GCWhen::Type when, GCTracer* tracer); + protected: static inline size_t total_invocations(); HeapWord* allocate_new_tlab(size_t size); @@ -116,7 +122,7 @@ // The alignment used for eden and survivors within the young gen // and for boundary between young gen and old gen. - size_t intra_heap_alignment() const { return 64 * K; } + size_t intra_heap_alignment() const { return 64 * K * HeapWordSize; } size_t capacity() const; size_t used() const; @@ -219,6 +225,7 @@ jlong millis_since_last_gc(); void prepare_for_verify(); + PSHeapSummary create_ps_heap_summary(); virtual void print_on(outputStream* st) const; virtual void print_on_error(outputStream* st) const; virtual void print_gc_threads_on(outputStream* st) const; diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/gc_implementation/parallelScavenge/pcTasks.cpp --- a/src/share/vm/gc_implementation/parallelScavenge/pcTasks.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/gc_implementation/parallelScavenge/pcTasks.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -27,6 +27,8 @@ #include "code/codeCache.hpp" #include "gc_implementation/parallelScavenge/pcTasks.hpp" #include "gc_implementation/parallelScavenge/psParallelCompact.hpp" +#include "gc_implementation/shared/gcTimer.hpp" +#include "gc_implementation/shared/gcTraceTime.hpp" #include "gc_interface/collectedHeap.hpp" #include "memory/universe.hpp" #include "oops/objArrayKlass.inline.hpp" @@ -48,8 +50,8 @@ ResourceMark rm; - NOT_PRODUCT(TraceTime tm("ThreadRootsMarkingTask", - PrintGCDetails && TraceParallelOldGCTasks, true, gclog_or_tty)); + NOT_PRODUCT(GCTraceTime tm("ThreadRootsMarkingTask", + PrintGCDetails && TraceParallelOldGCTasks, true, NULL)); ParCompactionManager* cm = ParCompactionManager::gc_thread_compaction_manager(which); @@ -77,8 +79,8 @@ void MarkFromRootsTask::do_it(GCTaskManager* manager, uint which) { assert(Universe::heap()->is_gc_active(), "called outside gc"); - NOT_PRODUCT(TraceTime tm("MarkFromRootsTask", - PrintGCDetails && TraceParallelOldGCTasks, true, gclog_or_tty)); + NOT_PRODUCT(GCTraceTime tm("MarkFromRootsTask", + PrintGCDetails && TraceParallelOldGCTasks, true, NULL)); ParCompactionManager* cm = ParCompactionManager::gc_thread_compaction_manager(which); PSParallelCompact::MarkAndPushClosure mark_and_push_closure(cm); @@ -120,6 +122,9 @@ case system_dictionary: SystemDictionary::always_strong_oops_do(&mark_and_push_closure); + break; + + case class_loader_data: ClassLoaderDataGraph::always_strong_oops_do(&mark_and_push_closure, &follow_klass_closure, true); break; @@ -145,8 +150,8 @@ { assert(Universe::heap()->is_gc_active(), "called outside gc"); - NOT_PRODUCT(TraceTime tm("RefProcTask", - PrintGCDetails && TraceParallelOldGCTasks, true, gclog_or_tty)); + NOT_PRODUCT(GCTraceTime tm("RefProcTask", + PrintGCDetails && TraceParallelOldGCTasks, true, NULL)); ParCompactionManager* cm = ParCompactionManager::gc_thread_compaction_manager(which); PSParallelCompact::MarkAndPushClosure mark_and_push_closure(cm); @@ -201,8 +206,8 @@ void StealMarkingTask::do_it(GCTaskManager* manager, uint which) { assert(Universe::heap()->is_gc_active(), "called outside gc"); - NOT_PRODUCT(TraceTime tm("StealMarkingTask", - PrintGCDetails && TraceParallelOldGCTasks, true, gclog_or_tty)); + NOT_PRODUCT(GCTraceTime tm("StealMarkingTask", + PrintGCDetails && TraceParallelOldGCTasks, true, NULL)); ParCompactionManager* cm = ParCompactionManager::gc_thread_compaction_manager(which); @@ -234,8 +239,8 @@ void StealRegionCompactionTask::do_it(GCTaskManager* manager, uint which) { assert(Universe::heap()->is_gc_active(), "called outside gc"); - NOT_PRODUCT(TraceTime tm("StealRegionCompactionTask", - PrintGCDetails && TraceParallelOldGCTasks, true, gclog_or_tty)); + NOT_PRODUCT(GCTraceTime tm("StealRegionCompactionTask", + PrintGCDetails && TraceParallelOldGCTasks, true, NULL)); ParCompactionManager* cm = ParCompactionManager::gc_thread_compaction_manager(which); @@ -301,8 +306,8 @@ void UpdateDensePrefixTask::do_it(GCTaskManager* manager, uint which) { - NOT_PRODUCT(TraceTime tm("UpdateDensePrefixTask", - PrintGCDetails && TraceParallelOldGCTasks, true, gclog_or_tty)); + NOT_PRODUCT(GCTraceTime tm("UpdateDensePrefixTask", + PrintGCDetails && TraceParallelOldGCTasks, true, NULL)); ParCompactionManager* cm = ParCompactionManager::gc_thread_compaction_manager(which); @@ -316,8 +321,8 @@ void DrainStacksCompactionTask::do_it(GCTaskManager* manager, uint which) { assert(Universe::heap()->is_gc_active(), "called outside gc"); - NOT_PRODUCT(TraceTime tm("DrainStacksCompactionTask", - PrintGCDetails && TraceParallelOldGCTasks, true, gclog_or_tty)); + NOT_PRODUCT(GCTraceTime tm("DrainStacksCompactionTask", + PrintGCDetails && TraceParallelOldGCTasks, true, NULL)); ParCompactionManager* cm = ParCompactionManager::gc_thread_compaction_manager(which); diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/gc_implementation/parallelScavenge/pcTasks.hpp --- a/src/share/vm/gc_implementation/parallelScavenge/pcTasks.hpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/gc_implementation/parallelScavenge/pcTasks.hpp Fri Jun 21 15:56:24 2013 -0700 @@ -98,7 +98,8 @@ management = 6, jvmti = 7, system_dictionary = 8, - code_cache = 9 + class_loader_data = 9, + code_cache = 10 }; private: RootType _root_type; diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/gc_implementation/parallelScavenge/psAdaptiveSizePolicy.cpp --- a/src/share/vm/gc_implementation/parallelScavenge/psAdaptiveSizePolicy.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/gc_implementation/parallelScavenge/psAdaptiveSizePolicy.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -194,7 +194,7 @@ // If this is not a full GC, only test and modify the young generation. -void PSAdaptiveSizePolicy::compute_generation_free_space( +void PSAdaptiveSizePolicy::compute_generations_free_space( size_t young_live, size_t eden_live, size_t old_live, @@ -729,7 +729,7 @@ if (PrintAdaptiveSizePolicy && Verbose) { gclog_or_tty->print_cr( - "PSAdaptiveSizePolicy::compute_old_gen_free_space " + "PSAdaptiveSizePolicy::adjust_promo_for_pause_time " "adjusting gen sizes for major pause (avg %f goal %f). " "desired_promo_size " SIZE_FORMAT " promo delta " SIZE_FORMAT, _avg_major_pause->average(), gc_pause_goal_sec(), @@ -786,7 +786,7 @@ if (PrintAdaptiveSizePolicy && Verbose) { gclog_or_tty->print_cr( - "PSAdaptiveSizePolicy::compute_eden_space_size " + "PSAdaptiveSizePolicy::adjust_eden_for_pause_time " "adjusting gen sizes for major pause (avg %f goal %f). " "desired_eden_size " SIZE_FORMAT " eden delta " SIZE_FORMAT, _avg_major_pause->average(), gc_pause_goal_sec(), @@ -1001,7 +1001,7 @@ if (PrintAdaptiveSizePolicy && Verbose) { gclog_or_tty->print_cr( - "AdaptiveSizePolicy::compute_generation_free_space " + "AdaptiveSizePolicy::adjust_promo_for_footprint " "adjusting tenured gen for footprint. " "starting promo size " SIZE_FORMAT " reduced promo size " SIZE_FORMAT, @@ -1025,7 +1025,7 @@ if (PrintAdaptiveSizePolicy && Verbose) { gclog_or_tty->print_cr( - "AdaptiveSizePolicy::compute_generation_free_space " + "AdaptiveSizePolicy::adjust_eden_for_footprint " "adjusting eden for footprint. " " starting eden size " SIZE_FORMAT " reduced eden size " SIZE_FORMAT @@ -1280,7 +1280,7 @@ if (PrintAdaptiveSizePolicy) { gclog_or_tty->print( - "AdaptiveSizePolicy::compute_survivor_space_size_and_thresh:" + "AdaptiveSizePolicy::update_averages:" " survived: " SIZE_FORMAT " promoted: " SIZE_FORMAT " overflow: %s", diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/gc_implementation/parallelScavenge/psAdaptiveSizePolicy.hpp --- a/src/share/vm/gc_implementation/parallelScavenge/psAdaptiveSizePolicy.hpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/gc_implementation/parallelScavenge/psAdaptiveSizePolicy.hpp Fri Jun 21 15:56:24 2013 -0700 @@ -344,13 +344,13 @@ // Takes current used space in all generations as input, as well // as an indication if a full gc has just been performed, for use // in deciding if an OOM error should be thrown. - void compute_generation_free_space(size_t young_live, - size_t eden_live, - size_t old_live, - size_t cur_eden, // current eden in bytes - size_t max_old_gen_size, - size_t max_eden_size, - bool is_full_gc); + void compute_generations_free_space(size_t young_live, + size_t eden_live, + size_t old_live, + size_t cur_eden, // current eden in bytes + size_t max_old_gen_size, + size_t max_eden_size, + bool is_full_gc); void compute_eden_space_size(size_t young_live, size_t eden_live, diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/gc_implementation/parallelScavenge/psGCAdaptivePolicyCounters.hpp --- a/src/share/vm/gc_implementation/parallelScavenge/psGCAdaptivePolicyCounters.hpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/gc_implementation/parallelScavenge/psGCAdaptivePolicyCounters.hpp 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 @@ -119,7 +119,7 @@ ps_size_policy()->change_old_gen_for_min_pauses()); } - // compute_generation_free_space() statistics + // compute_generations_free_space() statistics inline void update_avg_major_pause() { _avg_major_pause->set_value( diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp --- a/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -34,6 +34,10 @@ #include "gc_implementation/parallelScavenge/psOldGen.hpp" #include "gc_implementation/parallelScavenge/psScavenge.hpp" #include "gc_implementation/parallelScavenge/psYoungGen.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 "gc_implementation/shared/markSweep.hpp" #include "gc_implementation/shared/spaceDecorator.hpp" @@ -108,8 +112,12 @@ } ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); + assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); GCCause::Cause gc_cause = heap->gc_cause(); - assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); + + _gc_timer->register_gc_start(os::elapsed_counter()); + _gc_tracer->report_gc_start(gc_cause, _gc_timer->gc_start()); + PSAdaptiveSizePolicy* size_policy = heap->size_policy(); // The scope of casr should end after code that can change @@ -131,6 +139,7 @@ AdaptiveSizePolicyOutput(size_policy, heap->total_collections()); heap->print_heap_before_gc(); + heap->trace_heap_before_gc(_gc_tracer); // Fill in TLABs heap->accumulate_statistics_all_tlabs(); @@ -147,7 +156,7 @@ old_gen->verify_object_start_array(); } - heap->pre_full_gc_dump(); + heap->pre_full_gc_dump(_gc_timer); // Filled in below to track the state of the young gen after the collection. bool eden_empty; @@ -159,7 +168,7 @@ gclog_or_tty->date_stamp(PrintGC && PrintGCDateStamps); TraceCPUTime tcpu(PrintGCDetails, true, gclog_or_tty); - TraceTime t1(GCCauseString("Full GC", gc_cause), PrintGC, !PrintGCDetails, gclog_or_tty); + GCTraceTime t1(GCCauseString("Full GC", gc_cause), PrintGC, !PrintGCDetails, NULL); TraceCollectorStats tcs(counters()); TraceMemoryManagerStats tms(true /* Full GC */,gc_cause); @@ -290,13 +299,13 @@ // Used for diagnostics size_policy->clear_generation_free_space_flags(); - size_policy->compute_generation_free_space(young_live, - eden_live, - old_live, - cur_eden, - max_old_gen_size, - max_eden_size, - true /* full gc*/); + size_policy->compute_generations_free_space(young_live, + eden_live, + old_live, + cur_eden, + max_old_gen_size, + max_eden_size, + true /* full gc*/); size_policy->check_gc_overhead_limit(young_live, eden_live, @@ -374,13 +383,18 @@ NOT_PRODUCT(ref_processor()->verify_no_references_recorded()); heap->print_heap_after_gc(); + heap->trace_heap_after_gc(_gc_tracer); - heap->post_full_gc_dump(); + heap->post_full_gc_dump(_gc_timer); #ifdef TRACESPINNING ParallelTaskTerminator::print_termination_counts(); #endif + _gc_timer->register_gc_end(os::elapsed_counter()); + + _gc_tracer->report_gc_end(_gc_timer->gc_end(), _gc_timer->time_partitions()); + return true; } @@ -498,7 +512,7 @@ void PSMarkSweep::mark_sweep_phase1(bool clear_all_softrefs) { // Recursively traverse all live objects and mark them - TraceTime tm("phase 1", PrintGCDetails && Verbose, true, gclog_or_tty); + GCTraceTime tm("phase 1", PrintGCDetails && Verbose, true, _gc_timer); trace(" 1"); ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); @@ -531,8 +545,10 @@ // Process reference objects found during marking { ref_processor()->setup_policy(clear_all_softrefs); - ref_processor()->process_discovered_references( - is_alive_closure(), mark_and_push_closure(), follow_stack_closure(), NULL); + const ReferenceProcessorStats& stats = + ref_processor()->process_discovered_references( + is_alive_closure(), mark_and_push_closure(), follow_stack_closure(), NULL, _gc_timer); + gc_tracer()->report_gc_reference_stats(stats); } // This is the point where the entire marking should have completed. @@ -552,11 +568,12 @@ // Clean up unreferenced symbols in symbol table. SymbolTable::unlink(); + _gc_tracer->report_object_count_after_gc(is_alive_closure()); } void PSMarkSweep::mark_sweep_phase2() { - TraceTime tm("phase 2", PrintGCDetails && Verbose, true, gclog_or_tty); + GCTraceTime tm("phase 2", PrintGCDetails && Verbose, true, _gc_timer); trace("2"); // Now all live objects are marked, compute the new object addresses. @@ -586,7 +603,7 @@ void PSMarkSweep::mark_sweep_phase3() { // Adjust the pointers to reflect the new locations - TraceTime tm("phase 3", PrintGCDetails && Verbose, true, gclog_or_tty); + GCTraceTime tm("phase 3", PrintGCDetails && Verbose, true, _gc_timer); trace("3"); ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); @@ -629,7 +646,7 @@ void PSMarkSweep::mark_sweep_phase4() { EventMark m("4 compact heap"); - TraceTime tm("phase 4", PrintGCDetails && Verbose, true, gclog_or_tty); + GCTraceTime tm("phase 4", PrintGCDetails && Verbose, true, _gc_timer); trace("4"); // All pointers are now adjusted, move objects accordingly diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp --- a/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -39,6 +39,10 @@ #include "gc_implementation/parallelScavenge/psPromotionManager.inline.hpp" #include "gc_implementation/parallelScavenge/psScavenge.hpp" #include "gc_implementation/parallelScavenge/psYoungGen.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 "gc_interface/gcCause.hpp" #include "memory/gcLocker.inline.hpp" @@ -59,13 +63,25 @@ #include // All sizes are in HeapWords. -const size_t ParallelCompactData::Log2RegionSize = 9; // 512 words +const size_t ParallelCompactData::Log2RegionSize = 16; // 64K words const size_t ParallelCompactData::RegionSize = (size_t)1 << Log2RegionSize; const size_t ParallelCompactData::RegionSizeBytes = RegionSize << LogHeapWordSize; const size_t ParallelCompactData::RegionSizeOffsetMask = RegionSize - 1; const size_t ParallelCompactData::RegionAddrOffsetMask = RegionSizeBytes - 1; -const size_t ParallelCompactData::RegionAddrMask = ~RegionAddrOffsetMask; +const size_t ParallelCompactData::RegionAddrMask = ~RegionAddrOffsetMask; + +const size_t ParallelCompactData::Log2BlockSize = 7; // 128 words +const size_t ParallelCompactData::BlockSize = (size_t)1 << Log2BlockSize; +const size_t ParallelCompactData::BlockSizeBytes = + BlockSize << LogHeapWordSize; +const size_t ParallelCompactData::BlockSizeOffsetMask = BlockSize - 1; +const size_t ParallelCompactData::BlockAddrOffsetMask = BlockSizeBytes - 1; +const size_t ParallelCompactData::BlockAddrMask = ~BlockAddrOffsetMask; + +const size_t ParallelCompactData::BlocksPerRegion = RegionSize / BlockSize; +const size_t ParallelCompactData::Log2BlocksPerRegion = + Log2RegionSize - Log2BlockSize; const ParallelCompactData::RegionData::region_sz_t ParallelCompactData::RegionData::dc_shift = 27; @@ -359,6 +375,10 @@ _reserved_byte_size = 0; _region_data = 0; _region_count = 0; + + _block_vspace = 0; + _block_data = 0; + _block_count = 0; } bool ParallelCompactData::initialize(MemRegion covered_region) @@ -372,8 +392,7 @@ assert((region_size & RegionSizeOffsetMask) == 0, "region size not a multiple of RegionSize"); - bool result = initialize_region_data(region_size); - + bool result = initialize_region_data(region_size) && initialize_block_data(); return result; } @@ -418,17 +437,36 @@ return false; } +bool ParallelCompactData::initialize_block_data() +{ + assert(_region_count != 0, "region data must be initialized first"); + const size_t count = _region_count << Log2BlocksPerRegion; + _block_vspace = create_vspace(count, sizeof(BlockData)); + if (_block_vspace != 0) { + _block_data = (BlockData*)_block_vspace->reserved_low_addr(); + _block_count = count; + return true; + } + return false; +} + void ParallelCompactData::clear() { memset(_region_data, 0, _region_vspace->committed_size()); + memset(_block_data, 0, _block_vspace->committed_size()); } void ParallelCompactData::clear_range(size_t beg_region, size_t end_region) { assert(beg_region <= _region_count, "beg_region out of range"); assert(end_region <= _region_count, "end_region out of range"); + assert(RegionSize % BlockSize == 0, "RegionSize not a multiple of BlockSize"); const size_t region_cnt = end_region - beg_region; memset(_region_data + beg_region, 0, region_cnt * sizeof(RegionData)); + + const size_t beg_block = beg_region * BlocksPerRegion; + const size_t block_cnt = region_cnt * BlocksPerRegion; + memset(_block_data + beg_block, 0, block_cnt * sizeof(BlockData)); } HeapWord* ParallelCompactData::partial_obj_end(size_t region_idx) const @@ -707,49 +745,48 @@ HeapWord* ParallelCompactData::calc_new_pointer(HeapWord* addr) { assert(addr != NULL, "Should detect NULL oop earlier"); - assert(PSParallelCompact::gc_heap()->is_in(addr), "addr not in heap"); -#ifdef ASSERT - if (PSParallelCompact::mark_bitmap()->is_unmarked(addr)) { - gclog_or_tty->print_cr("calc_new_pointer:: addr " PTR_FORMAT, addr); - } -#endif - assert(PSParallelCompact::mark_bitmap()->is_marked(addr), "obj not marked"); + assert(PSParallelCompact::gc_heap()->is_in(addr), "not in heap"); + assert(PSParallelCompact::mark_bitmap()->is_marked(addr), "not marked"); // Region covering the object. - size_t region_index = addr_to_region_idx(addr); - const RegionData* const region_ptr = region(region_index); - HeapWord* const region_addr = region_align_down(addr); - - assert(addr < region_addr + RegionSize, "Region does not cover object"); - assert(addr_to_region_ptr(region_addr) == region_ptr, "sanity check"); - + RegionData* const region_ptr = addr_to_region_ptr(addr); HeapWord* result = region_ptr->destination(); - // If all the data in the region is live, then the new location of the object - // can be calculated from the destination of the region plus the offset of the - // object in the region. + // If the entire Region is live, the new location is region->destination + the + // offset of the object within in the Region. + + // Run some performance tests to determine if this special case pays off. It + // is worth it for pointers into the dense prefix. If the optimization to + // avoid pointer updates in regions that only point to the dense prefix is + // ever implemented, this should be revisited. if (region_ptr->data_size() == RegionSize) { - result += pointer_delta(addr, region_addr); - DEBUG_ONLY(PSParallelCompact::check_new_location(addr, result);) + result += region_offset(addr); return result; } - // The new location of the object is - // region destination + - // size of the partial object extending onto the region + - // sizes of the live objects in the Region that are to the left of addr - const size_t partial_obj_size = region_ptr->partial_obj_size(); - HeapWord* const search_start = region_addr + partial_obj_size; + // Otherwise, the new location is region->destination + block offset + the + // number of live words in the Block that are (a) to the left of addr and (b) + // due to objects that start in the Block. + + // Fill in the block table if necessary. This is unsynchronized, so multiple + // threads may fill the block table for a region (harmless, since it is + // idempotent). + if (!region_ptr->blocks_filled()) { + PSParallelCompact::fill_blocks(addr_to_region_idx(addr)); + region_ptr->set_blocks_filled(); + } + + HeapWord* const search_start = block_align_down(addr); + const size_t block_offset = addr_to_block_ptr(addr)->offset(); const ParMarkBitMap* bitmap = PSParallelCompact::mark_bitmap(); - size_t live_to_left = bitmap->live_words_in_range(search_start, oop(addr)); - - result += partial_obj_size + live_to_left; - DEBUG_ONLY(PSParallelCompact::check_new_location(addr, result);) + const size_t live = bitmap->live_words_in_range(search_start, oop(addr)); + result += block_offset + live; + DEBUG_ONLY(PSParallelCompact::check_new_location(addr, result)); return result; } -#ifdef ASSERT +#ifdef ASSERT void ParallelCompactData::verify_clear(const PSVirtualSpace* vspace) { const size_t* const beg = (const size_t*)vspace->committed_low_addr(); @@ -762,16 +799,12 @@ void ParallelCompactData::verify_clear() { verify_clear(_region_vspace); + verify_clear(_block_vspace); } #endif // #ifdef ASSERT -#ifdef NOT_PRODUCT -ParallelCompactData::RegionData* debug_region(size_t region_index) { - ParallelCompactData& sd = PSParallelCompact::summary_data(); - return sd.region(region_index); -} -#endif - +STWGCTimer PSParallelCompact::_gc_timer; +ParallelOldTracer PSParallelCompact::_gc_tracer; elapsedTimer PSParallelCompact::_accumulated_time; unsigned int PSParallelCompact::_total_invocations = 0; unsigned int PSParallelCompact::_maximum_compaction_gc_num = 0; @@ -945,7 +978,7 @@ // at each young gen gc. Do the update unconditionally (even though a // promotion failure does not swap spaces) because an unknown number of minor // collections will have swapped the spaces an unknown number of times. - TraceTime tm("pre compact", print_phases(), true, gclog_or_tty); + GCTraceTime tm("pre compact", print_phases(), true, &_gc_timer); ParallelScavengeHeap* heap = gc_heap(); _space_info[from_space_id].set_space(heap->young_gen()->from_space()); _space_info[to_space_id].set_space(heap->young_gen()->to_space()); @@ -962,6 +995,7 @@ _total_invocations++; heap->print_heap_before_gc(); + heap->trace_heap_before_gc(&_gc_tracer); // Fill in TLABs heap->accumulate_statistics_all_tlabs(); @@ -987,7 +1021,7 @@ void PSParallelCompact::post_compact() { - TraceTime tm("post compact", print_phases(), true, gclog_or_tty); + GCTraceTime tm("post compact", print_phases(), true, &_gc_timer); for (unsigned int id = old_space_id; id < last_space_id; ++id) { // Clear the marking bitmap, summary data and split info. @@ -1813,7 +1847,7 @@ void PSParallelCompact::summary_phase(ParCompactionManager* cm, bool maximum_compaction) { - TraceTime tm("summary phase", print_phases(), true, gclog_or_tty); + GCTraceTime tm("summary phase", print_phases(), true, &_gc_timer); // trace("2"); #ifdef ASSERT @@ -1961,11 +1995,6 @@ maximum_heap_compaction); } -bool ParallelCompactData::region_contains(size_t region_index, HeapWord* addr) { - size_t addr_region_index = addr_to_region_idx(addr); - return region_index == addr_region_index; -} - // This method contains no policy. You should probably // be calling invoke() instead. bool PSParallelCompact::invoke_no_policy(bool maximum_heap_compaction) { @@ -1976,11 +2005,15 @@ return false; } + ParallelScavengeHeap* heap = gc_heap(); + + _gc_timer.register_gc_start(os::elapsed_counter()); + _gc_tracer.report_gc_start(heap->gc_cause(), _gc_timer.gc_start()); + TimeStamp marking_start; TimeStamp compaction_start; TimeStamp collection_exit; - ParallelScavengeHeap* heap = gc_heap(); GCCause::Cause gc_cause = heap->gc_cause(); PSYoungGen* young_gen = heap->young_gen(); PSOldGen* old_gen = heap->old_gen(); @@ -1996,7 +2029,7 @@ heap->record_gen_tops_before_GC(); } - heap->pre_full_gc_dump(); + heap->pre_full_gc_dump(&_gc_timer); _print_phases = PrintGCDetails && PrintParallelOldGCPhaseTimes; @@ -2023,7 +2056,7 @@ gclog_or_tty->date_stamp(PrintGC && PrintGCDateStamps); TraceCPUTime tcpu(PrintGCDetails, true, gclog_or_tty); - TraceTime t1(GCCauseString("Full GC", gc_cause), PrintGC, !PrintGCDetails, gclog_or_tty); + GCTraceTime t1(GCCauseString("Full GC", gc_cause), PrintGC, !PrintGCDetails, NULL); TraceCollectorStats tcs(counters()); TraceMemoryManagerStats tms(true /* Full GC */,gc_cause); @@ -2043,7 +2076,7 @@ bool marked_for_unloading = false; marking_start.update(); - marking_phase(vmthread_cm, maximum_heap_compaction); + marking_phase(vmthread_cm, maximum_heap_compaction, &_gc_tracer); bool max_on_system_gc = UseMaximumCompactionOnSystemGC && gc_cause == GCCause::_java_lang_system_gc; @@ -2101,13 +2134,13 @@ // Used for diagnostics size_policy->clear_generation_free_space_flags(); - size_policy->compute_generation_free_space(young_live, - eden_live, - old_live, - cur_eden, - max_old_gen_size, - max_eden_size, - true /* full gc*/); + size_policy->compute_generations_free_space(young_live, + eden_live, + old_live, + cur_eden, + max_old_gen_size, + max_eden_size, + true /* full gc*/); size_policy->check_gc_overhead_limit(young_live, eden_live, @@ -2196,6 +2229,8 @@ collection_exit.update(); heap->print_heap_after_gc(); + heap->trace_heap_after_gc(&_gc_tracer); + if (PrintGCTaskTimeStamps) { gclog_or_tty->print_cr("VM-Thread " INT64_FORMAT " " INT64_FORMAT " " INT64_FORMAT, @@ -2204,12 +2239,17 @@ gc_task_manager()->print_task_time_stamps(); } - heap->post_full_gc_dump(); + heap->post_full_gc_dump(&_gc_timer); #ifdef TRACESPINNING ParallelTaskTerminator::print_termination_counts(); #endif + _gc_timer.register_gc_end(os::elapsed_counter()); + + _gc_tracer.report_dense_prefix(dense_prefix(old_space_id)); + _gc_tracer.report_gc_end(_gc_timer.gc_end(), _gc_timer.time_partitions()); + return true; } @@ -2308,9 +2348,10 @@ } void PSParallelCompact::marking_phase(ParCompactionManager* cm, - bool maximum_heap_compaction) { + bool maximum_heap_compaction, + ParallelOldTracer *gc_tracer) { // Recursively traverse all live objects and mark them - TraceTime tm("marking phase", print_phases(), true, gclog_or_tty); + GCTraceTime tm("marking phase", print_phases(), true, &_gc_timer); ParallelScavengeHeap* heap = gc_heap(); uint parallel_gc_threads = heap->gc_task_manager()->workers(); @@ -2325,7 +2366,8 @@ ClassLoaderDataGraph::clear_claimed_marks(); { - TraceTime tm_m("par mark", print_phases(), true, gclog_or_tty); + GCTraceTime tm_m("par mark", print_phases(), true, &_gc_timer); + ParallelScavengeHeap::ParStrongRootsScope psrs; GCTaskQueue* q = GCTaskQueue::create(); @@ -2338,6 +2380,7 @@ q->enqueue(new MarkFromRootsTask(MarkFromRootsTask::flat_profiler)); q->enqueue(new MarkFromRootsTask(MarkFromRootsTask::management)); q->enqueue(new MarkFromRootsTask(MarkFromRootsTask::system_dictionary)); + q->enqueue(new MarkFromRootsTask(MarkFromRootsTask::class_loader_data)); q->enqueue(new MarkFromRootsTask(MarkFromRootsTask::jvmti)); q->enqueue(new MarkFromRootsTask(MarkFromRootsTask::code_cache)); @@ -2352,19 +2395,24 @@ // Process reference objects found during marking { - TraceTime tm_r("reference processing", print_phases(), true, gclog_or_tty); + GCTraceTime tm_r("reference processing", print_phases(), true, &_gc_timer); + + ReferenceProcessorStats stats; if (ref_processor()->processing_is_mt()) { RefProcTaskExecutor task_executor; - ref_processor()->process_discovered_references( + stats = ref_processor()->process_discovered_references( is_alive_closure(), &mark_and_push_closure, &follow_stack_closure, - &task_executor); + &task_executor, &_gc_timer); } else { - ref_processor()->process_discovered_references( - is_alive_closure(), &mark_and_push_closure, &follow_stack_closure, NULL); + stats = ref_processor()->process_discovered_references( + is_alive_closure(), &mark_and_push_closure, &follow_stack_closure, NULL, + &_gc_timer); } + + gc_tracer->report_gc_reference_stats(stats); } - TraceTime tm_c("class unloading", print_phases(), true, gclog_or_tty); + GCTraceTime tm_c("class unloading", print_phases(), true, &_gc_timer); // This is the point where the entire marking should have completed. assert(cm->marking_stacks_empty(), "Marking should have completed"); @@ -2383,6 +2431,7 @@ // Clean up unreferenced symbols in symbol table. SymbolTable::unlink(); + _gc_tracer.report_object_count_after_gc(is_alive_closure()); } void PSParallelCompact::follow_klass(ParCompactionManager* cm, Klass* klass) { @@ -2423,7 +2472,7 @@ void PSParallelCompact::adjust_roots() { // Adjust the pointers to reflect the new locations - TraceTime tm("adjust roots", print_phases(), true, gclog_or_tty); + GCTraceTime tm("adjust roots", print_phases(), true, &_gc_timer); // Need new claim bits when tracing through and adjusting pointers. ClassLoaderDataGraph::clear_claimed_marks(); @@ -2459,7 +2508,7 @@ void PSParallelCompact::enqueue_region_draining_tasks(GCTaskQueue* q, uint parallel_gc_threads) { - TraceTime tm("drain task setup", print_phases(), true, gclog_or_tty); + GCTraceTime tm("drain task setup", print_phases(), true, &_gc_timer); // Find the threads that are active unsigned int which = 0; @@ -2533,7 +2582,7 @@ void PSParallelCompact::enqueue_dense_prefix_tasks(GCTaskQueue* q, uint parallel_gc_threads) { - TraceTime tm("dense prefix task setup", print_phases(), true, gclog_or_tty); + GCTraceTime tm("dense prefix task setup", print_phases(), true, &_gc_timer); ParallelCompactData& sd = PSParallelCompact::summary_data(); @@ -2615,7 +2664,7 @@ GCTaskQueue* q, ParallelTaskTerminator* terminator_ptr, uint parallel_gc_threads) { - TraceTime tm("steal task setup", print_phases(), true, gclog_or_tty); + GCTraceTime tm("steal task setup", print_phases(), true, &_gc_timer); // Once a thread has drained it's stack, it should try to steal regions from // other threads. @@ -2626,9 +2675,44 @@ } } +#ifdef ASSERT +// Write a histogram of the number of times the block table was filled for a +// region. +void PSParallelCompact::write_block_fill_histogram(outputStream* const out) +{ + if (!TraceParallelOldGCCompactionPhase) return; + + typedef ParallelCompactData::RegionData rd_t; + ParallelCompactData& sd = summary_data(); + + for (unsigned int id = old_space_id; id < last_space_id; ++id) { + MutableSpace* const spc = _space_info[id].space(); + if (spc->bottom() != spc->top()) { + const rd_t* const beg = sd.addr_to_region_ptr(spc->bottom()); + HeapWord* const top_aligned_up = sd.region_align_up(spc->top()); + const rd_t* const end = sd.addr_to_region_ptr(top_aligned_up); + + size_t histo[5] = { 0, 0, 0, 0, 0 }; + const size_t histo_len = sizeof(histo) / sizeof(size_t); + const size_t region_cnt = pointer_delta(end, beg, sizeof(rd_t)); + + for (const rd_t* cur = beg; cur < end; ++cur) { + ++histo[MIN2(cur->blocks_filled_count(), histo_len - 1)]; + } + out->print("%u %-4s" SIZE_FORMAT_W(5), id, space_names[id], region_cnt); + for (size_t i = 0; i < histo_len; ++i) { + out->print(" " SIZE_FORMAT_W(5) " %5.1f%%", + histo[i], 100.0 * histo[i] / region_cnt); + } + out->cr(); + } + } +} +#endif // #ifdef ASSERT + void PSParallelCompact::compact() { // trace("5"); - TraceTime tm("compaction phase", print_phases(), true, gclog_or_tty); + GCTraceTime tm("compaction phase", print_phases(), true, &_gc_timer); ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); @@ -2645,7 +2729,7 @@ enqueue_region_stealing_tasks(q, &terminator, active_gc_threads); { - TraceTime tm_pc("par compact", print_phases(), true, gclog_or_tty); + GCTraceTime tm_pc("par compact", print_phases(), true, &_gc_timer); gc_task_manager()->execute_and_wait(q); @@ -2659,12 +2743,14 @@ { // Update the deferred objects, if any. Any compaction manager can be used. - TraceTime tm_du("deferred updates", print_phases(), true, gclog_or_tty); + GCTraceTime tm_du("deferred updates", print_phases(), true, &_gc_timer); ParCompactionManager* cm = ParCompactionManager::manager_array(0); for (unsigned int id = old_space_id; id < last_space_id; ++id) { update_deferred_objects(cm, SpaceId(id)); } } + + DEBUG_ONLY(write_block_fill_histogram(gclog_or_tty)); } #ifdef ASSERT @@ -3129,6 +3215,57 @@ } while (true); } +void PSParallelCompact::fill_blocks(size_t region_idx) +{ + // Fill in the block table elements for the specified region. Each block + // table element holds the number of live words in the region that are to the + // left of the first object that starts in the block. Thus only blocks in + // which an object starts need to be filled. + // + // The algorithm scans the section of the bitmap that corresponds to the + // region, keeping a running total of the live words. When an object start is + // found, if it's the first to start in the block that contains it, the + // current total is written to the block table element. + const size_t Log2BlockSize = ParallelCompactData::Log2BlockSize; + const size_t Log2RegionSize = ParallelCompactData::Log2RegionSize; + const size_t RegionSize = ParallelCompactData::RegionSize; + + ParallelCompactData& sd = summary_data(); + const size_t partial_obj_size = sd.region(region_idx)->partial_obj_size(); + if (partial_obj_size >= RegionSize) { + return; // No objects start in this region. + } + + // Ensure the first loop iteration decides that the block has changed. + size_t cur_block = sd.block_count(); + + const ParMarkBitMap* const bitmap = mark_bitmap(); + + const size_t Log2BitsPerBlock = Log2BlockSize - LogMinObjAlignment; + assert((size_t)1 << Log2BitsPerBlock == + bitmap->words_to_bits(ParallelCompactData::BlockSize), "sanity"); + + size_t beg_bit = bitmap->words_to_bits(region_idx << Log2RegionSize); + const size_t range_end = beg_bit + bitmap->words_to_bits(RegionSize); + size_t live_bits = bitmap->words_to_bits(partial_obj_size); + beg_bit = bitmap->find_obj_beg(beg_bit + live_bits, range_end); + while (beg_bit < range_end) { + const size_t new_block = beg_bit >> Log2BitsPerBlock; + if (new_block != cur_block) { + cur_block = new_block; + sd.block(cur_block)->set_offset(bitmap->bits_to_words(live_bits)); + } + + const size_t end_bit = bitmap->find_obj_end(beg_bit, range_end); + if (end_bit < range_end - 1) { + live_bits += end_bit - beg_bit + 1; + beg_bit = bitmap->find_obj_beg(end_bit + 1, range_end); + } else { + return; + } + } +} + void PSParallelCompact::move_and_update(ParCompactionManager* cm, SpaceId space_id) { const MutableSpace* sp = space(space_id); diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.hpp --- a/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.hpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.hpp Fri Jun 21 15:56:24 2013 -0700 @@ -46,6 +46,8 @@ class PreGCValues; class MoveAndUpdateClosure; class RefProcTaskExecutor; +class ParallelOldTracer; +class STWGCTimer; // The SplitInfo class holds the information needed to 'split' a source region // so that the live data can be copied to two destination *spaces*. Normally, @@ -220,6 +222,17 @@ // Mask for the bits in a pointer to get the address of the start of a region. static const size_t RegionAddrMask; + static const size_t Log2BlockSize; + static const size_t BlockSize; + static const size_t BlockSizeBytes; + + static const size_t BlockSizeOffsetMask; + static const size_t BlockAddrOffsetMask; + static const size_t BlockAddrMask; + + static const size_t BlocksPerRegion; + static const size_t Log2BlocksPerRegion; + class RegionData { public: @@ -272,6 +285,12 @@ inline uint destination_count() const; inline uint destination_count_raw() const; + // Whether the block table for this region has been filled. + inline bool blocks_filled() const; + + // Number of times the block table was filled. + DEBUG_ONLY(inline size_t blocks_filled_count() const;) + // The location of the java heap data that corresponds to this region. inline HeapWord* data_location() const; @@ -296,6 +315,7 @@ void set_partial_obj_size(size_t words) { _partial_obj_size = (region_sz_t) words; } + inline void set_blocks_filled(); inline void set_destination_count(uint count); inline void set_live_obj_size(size_t words); @@ -328,7 +348,11 @@ HeapWord* _partial_obj_addr; region_sz_t _partial_obj_size; region_sz_t volatile _dc_and_los; + bool _blocks_filled; + #ifdef ASSERT + size_t _blocks_filled_count; // Number of block table fills. + // These enable optimizations that are only partially implemented. Use // debug builds to prevent the code fragments from breaking. HeapWord* _data_location; @@ -337,11 +361,26 @@ #ifdef ASSERT public: - uint _pushed; // 0 until region is pushed onto a worker's stack + uint _pushed; // 0 until region is pushed onto a stack private: #endif }; + // "Blocks" allow shorter sections of the bitmap to be searched. Each Block + // holds an offset, which is the amount of live data in the Region to the left + // of the first live object that starts in the Block. + class BlockData + { + public: + typedef unsigned short int blk_ofs_t; + + blk_ofs_t offset() const { return _offset; } + void set_offset(size_t val) { _offset = (blk_ofs_t)val; } + + private: + blk_ofs_t _offset; + }; + public: ParallelCompactData(); bool initialize(MemRegion covered_region); @@ -353,8 +392,9 @@ inline RegionData* region(size_t region_idx) const; inline size_t region(const RegionData* const region_ptr) const; - // Returns true if the given address is contained within the region - bool region_contains(size_t region_index, HeapWord* addr); + size_t block_count() const { return _block_count; } + inline BlockData* block(size_t block_idx) const; + inline size_t block(const BlockData* block_ptr) const; void add_obj(HeapWord* addr, size_t len); void add_obj(oop p, size_t len) { add_obj((HeapWord*)p, len); } @@ -394,11 +434,24 @@ inline HeapWord* region_align_up(HeapWord* addr) const; inline bool is_region_aligned(HeapWord* addr) const; + // Analogous to region_offset() for blocks. + size_t block_offset(const HeapWord* addr) const; + size_t addr_to_block_idx(const HeapWord* addr) const; + size_t addr_to_block_idx(const oop obj) const { + return addr_to_block_idx((HeapWord*) obj); + } + inline BlockData* addr_to_block_ptr(const HeapWord* addr) const; + inline HeapWord* block_to_addr(size_t block) const; + inline size_t region_to_block_idx(size_t region) const; + + inline HeapWord* block_align_down(HeapWord* addr) const; + inline HeapWord* block_align_up(HeapWord* addr) const; + inline bool is_block_aligned(HeapWord* addr) const; + // Return the address one past the end of the partial object. HeapWord* partial_obj_end(size_t region_idx) const; - // Return the new location of the object p after the - // the compaction. + // Return the location of the object after compaction. HeapWord* calc_new_pointer(HeapWord* addr); HeapWord* calc_new_pointer(oop p) { @@ -411,6 +464,7 @@ #endif // #ifdef ASSERT private: + bool initialize_block_data(); bool initialize_region_data(size_t region_size); PSVirtualSpace* create_vspace(size_t count, size_t element_size); @@ -424,6 +478,10 @@ size_t _reserved_byte_size; RegionData* _region_data; size_t _region_count; + + PSVirtualSpace* _block_vspace; + BlockData* _block_data; + size_t _block_count; }; inline uint @@ -438,6 +496,28 @@ return destination_count_raw() >> dc_shift; } +inline bool +ParallelCompactData::RegionData::blocks_filled() const +{ + return _blocks_filled; +} + +#ifdef ASSERT +inline size_t +ParallelCompactData::RegionData::blocks_filled_count() const +{ + return _blocks_filled_count; +} +#endif // #ifdef ASSERT + +inline void +ParallelCompactData::RegionData::set_blocks_filled() +{ + _blocks_filled = true; + // Debug builds count the number of times the table was filled. + DEBUG_ONLY(Atomic::inc_ptr(&_blocks_filled_count)); +} + inline void ParallelCompactData::RegionData::set_destination_count(uint count) { @@ -532,6 +612,12 @@ return pointer_delta(region_ptr, _region_data, sizeof(RegionData)); } +inline ParallelCompactData::BlockData* +ParallelCompactData::block(size_t n) const { + assert(n < block_count(), "bad arg"); + return _block_data + n; +} + inline size_t ParallelCompactData::region_offset(const HeapWord* addr) const { @@ -598,6 +684,63 @@ return region_offset(addr) == 0; } +inline size_t +ParallelCompactData::block_offset(const HeapWord* addr) const +{ + assert(addr >= _region_start, "bad addr"); + assert(addr <= _region_end, "bad addr"); + return (size_t(addr) & BlockAddrOffsetMask) >> LogHeapWordSize; +} + +inline size_t +ParallelCompactData::addr_to_block_idx(const HeapWord* addr) const +{ + assert(addr >= _region_start, "bad addr"); + assert(addr <= _region_end, "bad addr"); + return pointer_delta(addr, _region_start) >> Log2BlockSize; +} + +inline ParallelCompactData::BlockData* +ParallelCompactData::addr_to_block_ptr(const HeapWord* addr) const +{ + return block(addr_to_block_idx(addr)); +} + +inline HeapWord* +ParallelCompactData::block_to_addr(size_t block) const +{ + assert(block < _block_count, "block out of range"); + return _region_start + (block << Log2BlockSize); +} + +inline size_t +ParallelCompactData::region_to_block_idx(size_t region) const +{ + return region << Log2BlocksPerRegion; +} + +inline HeapWord* +ParallelCompactData::block_align_down(HeapWord* addr) const +{ + assert(addr >= _region_start, "bad addr"); + assert(addr < _region_end + RegionSize, "bad addr"); + return (HeapWord*)(size_t(addr) & BlockAddrMask); +} + +inline HeapWord* +ParallelCompactData::block_align_up(HeapWord* addr) const +{ + assert(addr >= _region_start, "bad addr"); + assert(addr <= _region_end, "bad addr"); + return block_align_down(addr + BlockSizeOffsetMask); +} + +inline bool +ParallelCompactData::is_block_aligned(HeapWord* addr) const +{ + return block_offset(addr) == 0; +} + // Abstract closure for use with ParMarkBitMap::iterate(), which will invoke the // do_addr() method. // @@ -775,6 +918,7 @@ // Convenient access to type names. typedef ParMarkBitMap::idx_t idx_t; typedef ParallelCompactData::RegionData RegionData; + typedef ParallelCompactData::BlockData BlockData; typedef enum { old_space_id, eden_space_id, @@ -830,6 +974,8 @@ friend class RefProcTaskProxy; private: + static STWGCTimer _gc_timer; + static ParallelOldTracer _gc_tracer; static elapsedTimer _accumulated_time; static unsigned int _total_invocations; static unsigned int _maximum_compaction_gc_num; @@ -873,7 +1019,8 @@ // Mark live objects static void marking_phase(ParCompactionManager* cm, - bool maximum_heap_compaction); + bool maximum_heap_compaction, + ParallelOldTracer *gc_tracer); template static inline void follow_root(ParCompactionManager* cm, T* p); @@ -962,6 +1109,8 @@ // Adjust addresses in roots. Does not adjust addresses in heap. static void adjust_roots(); + DEBUG_ONLY(static void write_block_fill_histogram(outputStream* const out);) + // Move objects to new locations. static void compact_perm(ParCompactionManager* cm); static void compact(); @@ -1128,6 +1277,9 @@ fill_region(cm, region); } + // Fill in the block table for the specified region. + static void fill_blocks(size_t region_idx); + // Update the deferred objects in the space. static void update_deferred_objects(ParCompactionManager* cm, SpaceId id); @@ -1137,6 +1289,8 @@ // Reference Processing static ReferenceProcessor* const ref_processor() { return _ref_processor; } + static STWGCTimer* gc_timer() { return &_gc_timer; } + // Return the SpaceId for the given address. static SpaceId space_id(HeapWord* addr); diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.cpp --- a/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 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,6 +27,7 @@ #include "gc_implementation/parallelScavenge/psOldGen.hpp" #include "gc_implementation/parallelScavenge/psPromotionManager.inline.hpp" #include "gc_implementation/parallelScavenge/psScavenge.inline.hpp" +#include "gc_implementation/shared/gcTrace.hpp" #include "gc_implementation/shared/mutableSpace.hpp" #include "memory/memRegion.hpp" #include "oops/oop.inline.hpp" @@ -49,7 +50,7 @@ guarantee(_manager_array != NULL, "Could not initialize promotion manager"); _stack_array_depth = new OopStarTaskQueueSet(ParallelGCThreads); - guarantee(_stack_array_depth != NULL, "Cound not initialize promotion manager"); + guarantee(_stack_array_depth != NULL, "Could not initialize promotion manager"); // Create and register the PSPromotionManager(s) for the worker threads. for(uint i=0; iclaimed_stack_depth()->is_empty(), "should be empty"); + if (manager->_promotion_failed_info.has_failed()) { + gc_tracer.report_promotion_failed(manager->_promotion_failed_info); + promotion_failure_occurred = true; + } manager->flush_labs(); } + return promotion_failure_occurred; } #if TASKQUEUE_STATS @@ -187,6 +195,8 @@ _old_lab.initialize(MemRegion(lab_base, (size_t)0)); _old_gen_is_full = false; + _promotion_failed_info.reset(); + TASKQUEUE_STATS_ONLY(reset_stats()); } @@ -305,6 +315,8 @@ // We won any races, we "own" this object. assert(obj == obj->forwardee(), "Sanity"); + _promotion_failed_info.register_copy_failure(obj->size()); + obj->push_contents(this); // Save the mark if needed diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.hpp --- a/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.hpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.hpp Fri Jun 21 15:56:24 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 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,6 +26,8 @@ #define SHARE_VM_GC_IMPLEMENTATION_PARALLELSCAVENGE_PSPROMOTIONMANAGER_HPP #include "gc_implementation/parallelScavenge/psPromotionLAB.hpp" +#include "gc_implementation/shared/gcTrace.hpp" +#include "gc_implementation/shared/copyFailedInfo.hpp" #include "memory/allocation.hpp" #include "utilities/taskqueue.hpp" @@ -33,7 +35,7 @@ // psPromotionManager is used by a single thread to manage object survival // during a scavenge. The promotion manager contains thread local data only. // -// NOTE! Be carefull when allocating the stacks on cheap. If you are going +// NOTE! Be careful when allocating the stacks on cheap. If you are going // to use a promotion manager in more than one thread, the stacks MUST be // on cheap. This can lead to memory leaks, though, as they are not auto // deallocated. @@ -85,6 +87,8 @@ uint _array_chunk_size; uint _min_array_size_for_chunking; + PromotionFailedInfo _promotion_failed_info; + // Accessors static PSOldGen* old_gen() { return _old_gen; } static MutableSpace* young_space() { return _young_space; } @@ -149,7 +153,7 @@ static void initialize(); static void pre_scavenge(); - static void post_scavenge(); + static bool post_scavenge(YoungGCTracer& gc_tracer); static PSPromotionManager* gc_thread_promotion_manager(int index); static PSPromotionManager* vm_thread_promotion_manager(); diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.inline.hpp --- a/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.inline.hpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.inline.hpp Fri Jun 21 15:56:24 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 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,7 +43,7 @@ if (o->is_forwarded()) { o = o->forwardee(); // Card mark - if (PSScavenge::is_obj_in_young((HeapWord*) o)) { + if (PSScavenge::is_obj_in_young(o)) { PSScavenge::card_table()->inline_write_ref_field_gc(p, o); } oopDesc::encode_store_heap_oop_not_null(p, o); @@ -153,7 +153,7 @@ // This is the promotion failed test, and code handling. // The code belongs here for two reasons. It is slightly - // different thatn the code below, and cannot share the + // different than the code below, and cannot share the // CAS testing code. Keeping the code here also minimizes // the impact on the common case fast path code. diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp --- a/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -34,6 +34,10 @@ #include "gc_implementation/parallelScavenge/psParallelCompact.hpp" #include "gc_implementation/parallelScavenge/psScavenge.inline.hpp" #include "gc_implementation/parallelScavenge/psTasks.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 "gc_implementation/shared/spaceDecorator.hpp" #include "gc_interface/gcCause.hpp" @@ -61,17 +65,19 @@ bool PSScavenge::_survivor_overflow = false; uint PSScavenge::_tenuring_threshold = 0; HeapWord* PSScavenge::_young_generation_boundary = NULL; +uintptr_t PSScavenge::_young_generation_boundary_compressed = 0; elapsedTimer PSScavenge::_accumulated_time; +STWGCTimer PSScavenge::_gc_timer; +ParallelScavengeTracer PSScavenge::_gc_tracer; Stack PSScavenge::_preserved_mark_stack; Stack PSScavenge::_preserved_oop_stack; CollectorCounters* PSScavenge::_counters = NULL; -bool PSScavenge::_promotion_failed = false; // Define before use class PSIsAliveClosure: public BoolObjectClosure { public: bool do_object_b(oop p) { - return (!PSScavenge::is_obj_in_young((HeapWord*) p)) || p->is_forwarded(); + return (!PSScavenge::is_obj_in_young(p)) || p->is_forwarded(); } }; @@ -258,6 +264,8 @@ assert(_preserved_mark_stack.is_empty(), "should be empty"); assert(_preserved_oop_stack.is_empty(), "should be empty"); + _gc_timer.register_gc_start(os::elapsed_counter()); + TimeStamp scavenge_entry; TimeStamp scavenge_midpoint; TimeStamp scavenge_exit; @@ -277,11 +285,14 @@ return false; } + _gc_tracer.report_gc_start(heap->gc_cause(), _gc_timer.gc_start()); + bool promotion_failure_occurred = false; PSYoungGen* young_gen = heap->young_gen(); PSOldGen* old_gen = heap->old_gen(); PSAdaptiveSizePolicy* size_policy = heap->size_policy(); + heap->increment_total_collections(); AdaptiveSizePolicyOutput(size_policy, heap->total_collections()); @@ -298,12 +309,12 @@ } heap->print_heap_before_gc(); + heap->trace_heap_before_gc(&_gc_tracer); assert(!NeverTenure || _tenuring_threshold == markOopDesc::max_age + 1, "Sanity"); assert(!AlwaysTenure || _tenuring_threshold == 0, "Sanity"); size_t prev_used = heap->used(); - assert(promotion_failed() == false, "Sanity"); // Fill in TLABs heap->accumulate_statistics_all_tlabs(); @@ -320,7 +331,7 @@ gclog_or_tty->date_stamp(PrintGC && PrintGCDateStamps); TraceCPUTime tcpu(PrintGCDetails, true, gclog_or_tty); - TraceTime t1(GCCauseString("GC", gc_cause), PrintGC, !PrintGCDetails, gclog_or_tty); + GCTraceTime t1(GCCauseString("GC", gc_cause), PrintGC, !PrintGCDetails, NULL); TraceCollectorStats tcs(counters()); TraceMemoryManagerStats tms(false /* not full GC */,gc_cause); @@ -386,7 +397,7 @@ // We'll use the promotion manager again later. PSPromotionManager* promotion_manager = PSPromotionManager::vm_thread_promotion_manager(); { - // TraceTime("Roots"); + GCTraceTime tm("Scavenge", false, false, &_gc_timer); ParallelScavengeHeap::ParStrongRootsScope psrs; GCTaskQueue* q = GCTaskQueue::create(); @@ -408,6 +419,7 @@ q->enqueue(new ScavengeRootsTask(ScavengeRootsTask::flat_profiler)); q->enqueue(new ScavengeRootsTask(ScavengeRootsTask::management)); q->enqueue(new ScavengeRootsTask(ScavengeRootsTask::system_dictionary)); + q->enqueue(new ScavengeRootsTask(ScavengeRootsTask::class_loader_data)); q->enqueue(new ScavengeRootsTask(ScavengeRootsTask::jvmti)); q->enqueue(new ScavengeRootsTask(ScavengeRootsTask::code_cache)); @@ -427,38 +439,41 @@ // Process reference objects discovered during scavenge { + GCTraceTime tm("References", false, false, &_gc_timer); + reference_processor()->setup_policy(false); // not always_clear reference_processor()->set_active_mt_degree(active_workers); PSKeepAliveClosure keep_alive(promotion_manager); PSEvacuateFollowersClosure evac_followers(promotion_manager); + ReferenceProcessorStats stats; if (reference_processor()->processing_is_mt()) { PSRefProcTaskExecutor task_executor; - reference_processor()->process_discovered_references( - &_is_alive_closure, &keep_alive, &evac_followers, &task_executor); + stats = reference_processor()->process_discovered_references( + &_is_alive_closure, &keep_alive, &evac_followers, &task_executor, + &_gc_timer); } else { - reference_processor()->process_discovered_references( - &_is_alive_closure, &keep_alive, &evac_followers, NULL); + stats = reference_processor()->process_discovered_references( + &_is_alive_closure, &keep_alive, &evac_followers, NULL, &_gc_timer); + } + + _gc_tracer.report_gc_reference_stats(stats); + + // Enqueue reference objects discovered during scavenge. + if (reference_processor()->processing_is_mt()) { + PSRefProcTaskExecutor task_executor; + reference_processor()->enqueue_discovered_references(&task_executor); + } else { + reference_processor()->enqueue_discovered_references(NULL); } } - // Enqueue reference objects discovered during scavenge. - if (reference_processor()->processing_is_mt()) { - PSRefProcTaskExecutor task_executor; - reference_processor()->enqueue_discovered_references(&task_executor); - } else { - reference_processor()->enqueue_discovered_references(NULL); - } - - // Unlink any dead interned Strings - StringTable::unlink(&_is_alive_closure); - // Process the remaining live ones - PSScavengeRootsClosure root_closure(promotion_manager); - StringTable::oops_do(&root_closure); + GCTraceTime tm("StringTable", false, false, &_gc_timer); + // Unlink any dead interned Strings and process the remaining live ones. + PSScavengeRootsClosure root_closure(promotion_manager); + StringTable::unlink_or_oops_do(&_is_alive_closure, &root_closure); // Finally, flush the promotion_manager's labs, and deallocate its stacks. - PSPromotionManager::post_scavenge(); - - promotion_failure_occurred = promotion_failed(); + promotion_failure_occurred = PSPromotionManager::post_scavenge(_gc_tracer); if (promotion_failure_occurred) { clean_up_failed_promotion(); if (PrintGC) { @@ -473,8 +488,6 @@ if (!promotion_failure_occurred) { // Swap the survivor spaces. - - young_gen->eden_space()->clear(SpaceDecorator::Mangle); young_gen->from_space()->clear(SpaceDecorator::Mangle); young_gen->swap_spaces(); @@ -612,7 +625,11 @@ NOT_PRODUCT(reference_processor()->verify_no_references_recorded()); - CodeCache::prune_scavenge_root_nmethods(); + { + GCTraceTime tm("Prune Scavenge Root Methods", false, false, &_gc_timer); + + CodeCache::prune_scavenge_root_nmethods(); + } // Re-verify object start arrays if (VerifyObjectStartArray && @@ -652,6 +669,8 @@ } heap->print_heap_after_gc(); + heap->trace_heap_after_gc(&_gc_tracer); + _gc_tracer.report_tenuring_threshold(tenuring_threshold()); if (ZapUnusedHeapArea) { young_gen->eden_space()->check_mangled_unused_area_complete(); @@ -672,6 +691,11 @@ ParallelTaskTerminator::print_termination_counts(); #endif + + _gc_timer.register_gc_end(os::elapsed_counter()); + + _gc_tracer.report_gc_end(_gc_timer.gc_end(), _gc_timer.time_partitions()); + return !promotion_failure_occurred; } @@ -681,7 +705,6 @@ void PSScavenge::clean_up_failed_promotion() { ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); - assert(promotion_failed(), "Sanity"); PSYoungGen* young_gen = heap->young_gen(); @@ -706,7 +729,6 @@ // Clear the preserved mark and oop stack caches. _preserved_mark_stack.clear(true); _preserved_oop_stack.clear(true); - _promotion_failed = false; } // Reset the PromotionFailureALot counters. @@ -717,11 +739,10 @@ // fails. Some markOops will need preservation, some will not. Note // that the entire eden is traversed after a failed promotion, with // all forwarded headers replaced by the default markOop. This means -// it is not neccessary to preserve most markOops. +// it is not necessary to preserve most markOops. void PSScavenge::oop_promotion_failed(oop obj, markOop obj_mark) { - _promotion_failed = true; if (obj_mark->must_be_preserved_for_promotion_failure(obj)) { - // Should use per-worker private stakcs hetre rather than + // Should use per-worker private stacks here rather than // locking a common pair of stacks. ThreadCritical tc; _preserved_oop_stack.push(obj); @@ -816,7 +837,7 @@ // Set boundary between young_gen and old_gen assert(old_gen->reserved().end() <= young_gen->eden_space()->bottom(), "old above young"); - _young_generation_boundary = young_gen->eden_space()->bottom(); + set_young_generation_boundary(young_gen->eden_space()->bottom()); // Initialize ref handling object for scavenging. MemRegion mr = young_gen->reserved(); diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/gc_implementation/parallelScavenge/psScavenge.hpp --- a/src/share/vm/gc_implementation/parallelScavenge/psScavenge.hpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/gc_implementation/parallelScavenge/psScavenge.hpp Fri Jun 21 15:56:24 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 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,7 @@ #include "gc_implementation/parallelScavenge/cardTableExtension.hpp" #include "gc_implementation/parallelScavenge/psVirtualspace.hpp" #include "gc_implementation/shared/collectorCounters.hpp" +#include "gc_implementation/shared/gcTrace.hpp" #include "memory/allocation.hpp" #include "oops/oop.hpp" #include "utilities/stack.hpp" @@ -37,8 +38,10 @@ class OopStack; class ReferenceProcessor; class ParallelScavengeHeap; +class ParallelScavengeTracer; class PSIsAliveClosure; class PSRefProcTaskExecutor; +class STWGCTimer; class PSScavenge: AllStatic { friend class PSIsAliveClosure; @@ -62,19 +65,23 @@ protected: // Flags/counters - static ReferenceProcessor* _ref_processor; // Reference processor for scavenging. - static PSIsAliveClosure _is_alive_closure; // Closure used for reference processing - static CardTableExtension* _card_table; // We cache the card table for fast access. - static bool _survivor_overflow; // Overflow this collection - static uint _tenuring_threshold; // tenuring threshold for next scavenge - static elapsedTimer _accumulated_time; // total time spent on scavenge - static HeapWord* _young_generation_boundary; // The lowest address possible for the young_gen. - // This is used to decide if an oop should be scavenged, - // cards should be marked, etc. + static ReferenceProcessor* _ref_processor; // Reference processor for scavenging. + static PSIsAliveClosure _is_alive_closure; // Closure used for reference processing + static CardTableExtension* _card_table; // We cache the card table for fast access. + static bool _survivor_overflow; // Overflow this collection + static uint _tenuring_threshold; // tenuring threshold for next scavenge + static elapsedTimer _accumulated_time; // total time spent on scavenge + static STWGCTimer _gc_timer; // GC time book keeper + static ParallelScavengeTracer _gc_tracer; // GC tracing + // The lowest address possible for the young_gen. + // This is used to decide if an oop should be scavenged, + // cards should be marked, etc. + static HeapWord* _young_generation_boundary; + // Used to optimize compressed oops young gen boundary checking. + static uintptr_t _young_generation_boundary_compressed; static Stack _preserved_mark_stack; // List of marks to be restored after failed promotion static Stack _preserved_oop_stack; // List of oops that need their mark restored. - static CollectorCounters* _counters; // collector performance counters - static bool _promotion_failed; + static CollectorCounters* _counters; // collector performance counters static void clean_up_failed_promotion(); @@ -90,7 +97,6 @@ // Accessors static uint tenuring_threshold() { return _tenuring_threshold; } static elapsedTimer* accumulated_time() { return &_accumulated_time; } - static bool promotion_failed() { return _promotion_failed; } static int consecutive_skipped_scavenges() { return _consecutive_skipped_scavenges; } @@ -112,6 +118,9 @@ // boundary moves, _young_generation_boundary must be reset static void set_young_generation_boundary(HeapWord* v) { _young_generation_boundary = v; + if (UseCompressedOops) { + _young_generation_boundary_compressed = (uintptr_t)oopDesc::encode_heap_oop((oop)v); + } } // Called by parallelScavengeHeap to init the tenuring threshold @@ -140,11 +149,19 @@ static void copy_and_push_safe_barrier_from_klass(PSPromotionManager* pm, oop* p); // Is an object in the young generation - // This assumes that the HeapWord argument is in the heap, + // This assumes that the 'o' is in the heap, // so it only checks one side of the complete predicate. + + inline static bool is_obj_in_young(oop o) { + return (HeapWord*)o >= _young_generation_boundary; + } + + inline static bool is_obj_in_young(narrowOop o) { + return (uintptr_t)o >= _young_generation_boundary_compressed; + } + inline static bool is_obj_in_young(HeapWord* o) { - const bool result = (o >= _young_generation_boundary); - return result; + return o >= _young_generation_boundary; } }; diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/gc_implementation/parallelScavenge/psScavenge.inline.hpp --- a/src/share/vm/gc_implementation/parallelScavenge/psScavenge.inline.hpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/gc_implementation/parallelScavenge/psScavenge.inline.hpp Fri Jun 21 15:56:24 2013 -0700 @@ -39,9 +39,7 @@ template inline bool PSScavenge::should_scavenge(T* p) { T heap_oop = oopDesc::load_heap_oop(p); - if (oopDesc::is_null(heap_oop)) return false; - oop obj = oopDesc::decode_heap_oop_not_null(heap_oop); - return PSScavenge::is_obj_in_young((HeapWord*)obj); + return PSScavenge::is_obj_in_young(heap_oop); } template @@ -94,7 +92,7 @@ // or from metadata. if ((!PSScavenge::is_obj_in_young((HeapWord*)p)) && Universe::heap()->is_in_reserved(p)) { - if (PSScavenge::is_obj_in_young((HeapWord*)new_obj)) { + if (PSScavenge::is_obj_in_young(new_obj)) { card_table()->inline_write_ref_field_gc(p, new_obj); } } @@ -147,7 +145,7 @@ } oopDesc::encode_store_heap_oop_not_null(p, new_obj); - if (PSScavenge::is_obj_in_young((HeapWord*)new_obj)) { + if (PSScavenge::is_obj_in_young(new_obj)) { do_klass_barrier(); } } diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/gc_implementation/parallelScavenge/psTasks.cpp --- a/src/share/vm/gc_implementation/parallelScavenge/psTasks.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/gc_implementation/parallelScavenge/psTasks.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -79,14 +79,15 @@ break; case system_dictionary: - { SystemDictionary::oops_do(&roots_closure); + break; - // Move this to another root_type? - PSScavengeKlassClosure klass_closure(pm); - ClassLoaderDataGraph::oops_do(&roots_closure, &klass_closure, false); - } - break; + case class_loader_data: + { + PSScavengeKlassClosure klass_closure(pm); + ClassLoaderDataGraph::oops_do(&roots_closure, &klass_closure, false); + } + break; case management: Management::oops_do(&roots_closure); diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/gc_implementation/parallelScavenge/psTasks.hpp --- a/src/share/vm/gc_implementation/parallelScavenge/psTasks.hpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/gc_implementation/parallelScavenge/psTasks.hpp Fri Jun 21 15:56:24 2013 -0700 @@ -59,9 +59,10 @@ object_synchronizer = 4, flat_profiler = 5, system_dictionary = 6, - management = 7, - jvmti = 8, - code_cache = 9 + class_loader_data = 7, + management = 8, + jvmti = 9, + code_cache = 10 }; private: RootType _root_type; diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/gc_implementation/shared/adaptiveSizePolicy.cpp --- a/src/share/vm/gc_implementation/shared/adaptiveSizePolicy.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/gc_implementation/shared/adaptiveSizePolicy.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 @@ -467,7 +467,7 @@ (free_in_old_gen < (size_t) mem_free_old_limit && free_in_eden < (size_t) mem_free_eden_limit))) { gclog_or_tty->print_cr( - "PSAdaptiveSizePolicy::compute_generation_free_space limits:" + "PSAdaptiveSizePolicy::check_gc_overhead_limit:" " promo_limit: " SIZE_FORMAT " max_eden_size: " SIZE_FORMAT " total_free_limit: " SIZE_FORMAT diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/gc_implementation/shared/copyFailedInfo.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/gc_implementation/shared/copyFailedInfo.hpp Fri Jun 21 15:56:24 2013 -0700 @@ -0,0 +1,90 @@ +/* + * 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_SHARED_COPYFAILEDINFO_HPP +#define SHARE_VM_GC_IMPLEMENTATION_SHARED_COPYFAILEDINFO_HPP + +#include "runtime/thread.hpp" +#include "utilities/globalDefinitions.hpp" + +class CopyFailedInfo : public CHeapObj { + size_t _first_size; + size_t _smallest_size; + size_t _total_size; + uint _count; + + public: + CopyFailedInfo() : _first_size(0), _smallest_size(0), _total_size(0), _count(0) {} + + virtual void register_copy_failure(size_t size) { + if (_first_size == 0) { + _first_size = size; + _smallest_size = size; + } else if (size < _smallest_size) { + _smallest_size = size; + } + _total_size += size; + _count++; + } + + virtual void reset() { + _first_size = 0; + _smallest_size = 0; + _total_size = 0; + _count = 0; + } + + bool has_failed() const { return _count != 0; } + size_t first_size() const { return _first_size; } + size_t smallest_size() const { return _smallest_size; } + size_t total_size() const { return _total_size; } + uint failed_count() const { return _count; } +}; + +class PromotionFailedInfo : public CopyFailedInfo { + OSThread* _thread; + + public: + PromotionFailedInfo() : CopyFailedInfo(), _thread(NULL) {} + + void register_copy_failure(size_t size) { + CopyFailedInfo::register_copy_failure(size); + if (_thread == NULL) { + _thread = Thread::current()->osthread(); + } else { + assert(_thread == Thread::current()->osthread(), "The PromotionFailedInfo should be thread local."); + } + } + + void reset() { + CopyFailedInfo::reset(); + _thread = NULL; + } + + OSThread* thread() const { return _thread; } +}; + +class EvacuationFailedInfo : public CopyFailedInfo {}; + +#endif /* SHARE_VM_GC_IMPLEMENTATION_SHARED_COPYFAILEDINFO_HPP */ diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/gc_implementation/shared/gcHeapSummary.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/gc_implementation/shared/gcHeapSummary.hpp Fri Jun 21 15:56:24 2013 -0700 @@ -0,0 +1,142 @@ +/* + * 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_SHARED_GCHEAPSUMMARY_HPP +#define SHARE_VM_GC_IMPLEMENTATION_SHARED_GCHEAPSUMMARY_HPP + +#include "memory/allocation.hpp" + +class VirtualSpaceSummary : public StackObj { + HeapWord* _start; + HeapWord* _committed_end; + HeapWord* _reserved_end; +public: + VirtualSpaceSummary() : + _start(NULL), _committed_end(NULL), _reserved_end(NULL) { } + VirtualSpaceSummary(HeapWord* start, HeapWord* committed_end, HeapWord* reserved_end) : + _start(start), _committed_end(committed_end), _reserved_end(reserved_end) { } + + HeapWord* start() const { return _start; } + HeapWord* committed_end() const { return _committed_end; } + HeapWord* reserved_end() const { return _reserved_end; } + size_t committed_size() const { return (uintptr_t)_committed_end - (uintptr_t)_start; } + size_t reserved_size() const { return (uintptr_t)_reserved_end - (uintptr_t)_start; } +}; + +class SpaceSummary : public StackObj { + HeapWord* _start; + HeapWord* _end; + size_t _used; +public: + SpaceSummary() : + _start(NULL), _end(NULL), _used(0) { } + SpaceSummary(HeapWord* start, HeapWord* end, size_t used) : + _start(start), _end(end), _used(used) { } + + HeapWord* start() const { return _start; } + HeapWord* end() const { return _end; } + size_t used() const { return _used; } + size_t size() const { return (uintptr_t)_end - (uintptr_t)_start; } +}; + +class MetaspaceSizes : public StackObj { + size_t _capacity; + size_t _used; + size_t _reserved; + + public: + MetaspaceSizes() : _capacity(0), _used(0), _reserved(0) {} + MetaspaceSizes(size_t capacity, size_t used, size_t reserved) : + _capacity(capacity), _used(used), _reserved(reserved) {} + + size_t capacity() const { return _capacity; } + size_t used() const { return _used; } + size_t reserved() const { return _reserved; } +}; + +class GCHeapSummary; +class PSHeapSummary; + +class GCHeapSummaryVisitor { + public: + virtual void visit(const GCHeapSummary* heap_summary) const = 0; + virtual void visit(const PSHeapSummary* heap_summary) const {} +}; + +class GCHeapSummary : public StackObj { + VirtualSpaceSummary _heap; + size_t _used; + + public: + GCHeapSummary() : + _heap(), _used(0) { } + GCHeapSummary(VirtualSpaceSummary& heap_space, size_t used) : + _heap(heap_space), _used(used) { } + + const VirtualSpaceSummary& heap() const { return _heap; } + size_t used() const { return _used; } + + virtual void accept(GCHeapSummaryVisitor* visitor) const { + visitor->visit(this); + } +}; + +class PSHeapSummary : public GCHeapSummary { + VirtualSpaceSummary _old; + SpaceSummary _old_space; + VirtualSpaceSummary _young; + SpaceSummary _eden; + SpaceSummary _from; + SpaceSummary _to; + public: + PSHeapSummary(VirtualSpaceSummary& heap_space, size_t heap_used, VirtualSpaceSummary old, SpaceSummary old_space, VirtualSpaceSummary young, SpaceSummary eden, SpaceSummary from, SpaceSummary to) : + GCHeapSummary(heap_space, heap_used), _old(old), _old_space(old_space), _young(young), _eden(eden), _from(from), _to(to) { } + const VirtualSpaceSummary& old() const { return _old; } + const SpaceSummary& old_space() const { return _old_space; } + const VirtualSpaceSummary& young() const { return _young; } + const SpaceSummary& eden() const { return _eden; } + const SpaceSummary& from() const { return _from; } + const SpaceSummary& to() const { return _to; } + + virtual void accept(GCHeapSummaryVisitor* visitor) const { + visitor->visit(this); + } +}; + +class MetaspaceSummary : public StackObj { + MetaspaceSizes _meta_space; + MetaspaceSizes _data_space; + MetaspaceSizes _class_space; + + public: + MetaspaceSummary() : _meta_space(), _data_space(), _class_space() {} + MetaspaceSummary(const MetaspaceSizes& meta_space, const MetaspaceSizes& data_space, const MetaspaceSizes& class_space) : + _meta_space(meta_space), _data_space(data_space), _class_space(class_space) { } + + const MetaspaceSizes& meta_space() const { return _meta_space; } + const MetaspaceSizes& data_space() const { return _data_space; } + const MetaspaceSizes& class_space() const { return _class_space; } +}; + +#endif // SHARE_VM_GC_IMPLEMENTATION_SHARED_GCHEAPSUMMARY_HPP diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/gc_implementation/shared/gcTimer.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/gc_implementation/shared/gcTimer.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -0,0 +1,374 @@ +/* + * 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. + * + */ + +#include "precompiled.hpp" +#include "gc_implementation/shared/gcTimer.hpp" +#include "utilities/growableArray.hpp" + +void GCTimer::register_gc_start(jlong time) { + _time_partitions.clear(); + _gc_start = time; +} + +void GCTimer::register_gc_end(jlong time) { + assert(!_time_partitions.has_active_phases(), + "We should have ended all started phases, before ending the GC"); + + _gc_end = time; +} + +void GCTimer::register_gc_pause_start(const char* name, jlong time) { + _time_partitions.report_gc_phase_start(name, time); +} + +void GCTimer::register_gc_pause_end(jlong time) { + _time_partitions.report_gc_phase_end(time); +} + +void GCTimer::register_gc_phase_start(const char* name, jlong time) { + _time_partitions.report_gc_phase_start(name, time); +} + +void GCTimer::register_gc_phase_end(jlong time) { + _time_partitions.report_gc_phase_end(time); +} + + +void STWGCTimer::register_gc_start(jlong time) { + GCTimer::register_gc_start(time); + register_gc_pause_start("GC Pause", time); +} + +void STWGCTimer::register_gc_end(jlong time) { + register_gc_pause_end(time); + GCTimer::register_gc_end(time); +} + +void ConcurrentGCTimer::register_gc_pause_start(const char* name, jlong time) { + GCTimer::register_gc_pause_start(name, time); +} + +void ConcurrentGCTimer::register_gc_pause_end(jlong time) { + GCTimer::register_gc_pause_end(time); +} + +void PhasesStack::clear() { + _next_phase_level = 0; +} + +void PhasesStack::push(int phase_index) { + assert(_next_phase_level < PHASE_LEVELS, "Overflow"); + + _phase_indices[_next_phase_level] = phase_index; + + _next_phase_level++; +} + +int PhasesStack::pop() { + assert(_next_phase_level > 0, "Underflow"); + + _next_phase_level--; + + return _phase_indices[_next_phase_level]; +} + +int PhasesStack::count() const { + return _next_phase_level; +} + + +TimePartitions::TimePartitions() { + _phases = new (ResourceObj::C_HEAP, mtGC) GrowableArray(INITIAL_CAPACITY, true, mtGC); + clear(); +} + +TimePartitions::~TimePartitions() { + delete _phases; + _phases = NULL; +} + +void TimePartitions::clear() { + _phases->clear(); + _active_phases.clear(); + _sum_of_pauses = 0; + _longest_pause = 0; +} + +void TimePartitions::report_gc_phase_start(const char* name, jlong time) { + assert(_phases->length() <= 1000, "Too many recored phases?"); + + int level = _active_phases.count(); + + PausePhase phase; + phase.set_level(level); + phase.set_name(name); + phase.set_start(time); + + int index = _phases->append(phase); + + _active_phases.push(index); +} + +void TimePartitions::update_statistics(GCPhase* phase) { + // FIXME: This should only be done for pause phases + if (phase->level() == 0) { + jlong pause = phase->end() - phase->start(); + _sum_of_pauses += pause; + _longest_pause = MAX2(pause, _longest_pause); + } +} + +void TimePartitions::report_gc_phase_end(jlong time) { + int phase_index = _active_phases.pop(); + GCPhase* phase = _phases->adr_at(phase_index); + phase->set_end(time); + update_statistics(phase); +} + +int TimePartitions::num_phases() const { + return _phases->length(); +} + +GCPhase* TimePartitions::phase_at(int index) const { + assert(index >= 0, "Out of bounds"); + assert(index < _phases->length(), "Out of bounds"); + + return _phases->adr_at(index); +} + +jlong TimePartitions::sum_of_pauses() { + return _sum_of_pauses; +} + +jlong TimePartitions::longest_pause() { + return _longest_pause; +} + +bool TimePartitions::has_active_phases() { + return _active_phases.count() > 0; +} + +bool TimePartitionPhasesIterator::has_next() { + return _next < _time_partitions->num_phases(); +} + +GCPhase* TimePartitionPhasesIterator::next() { + assert(has_next(), "Must have phases left"); + return _time_partitions->phase_at(_next++); +} + + +/////////////// Unit tests /////////////// + +#ifndef PRODUCT + +class TimePartitionPhasesIteratorTest { + public: + static void all() { + one_pause(); + two_pauses(); + one_sub_pause_phase(); + many_sub_pause_phases(); + many_sub_pause_phases2(); + max_nested_pause_phases(); + } + + static void validate_pause_phase(GCPhase* phase, int level, const char* name, jlong start, jlong end) { + assert(phase->level() == level, "Incorrect level"); + assert(strcmp(phase->name(), name) == 0, "Incorrect name"); + assert(phase->start() == start, "Incorrect start"); + assert(phase->end() == end, "Incorrect end"); + } + + static void one_pause() { + TimePartitions time_partitions; + time_partitions.report_gc_phase_start("PausePhase", 2); + time_partitions.report_gc_phase_end(8); + + TimePartitionPhasesIterator iter(&time_partitions); + + validate_pause_phase(iter.next(), 0, "PausePhase", 2, 8); + assert(time_partitions.sum_of_pauses() == 8-2, "Incorrect"); + assert(time_partitions.longest_pause() == 8-2, "Incorrect"); + + assert(!iter.has_next(), "Too many elements"); + } + + static void two_pauses() { + TimePartitions time_partitions; + time_partitions.report_gc_phase_start("PausePhase1", 2); + time_partitions.report_gc_phase_end(3); + time_partitions.report_gc_phase_start("PausePhase2", 4); + time_partitions.report_gc_phase_end(6); + + TimePartitionPhasesIterator iter(&time_partitions); + + validate_pause_phase(iter.next(), 0, "PausePhase1", 2, 3); + validate_pause_phase(iter.next(), 0, "PausePhase2", 4, 6); + + assert(time_partitions.sum_of_pauses() == 3, "Incorrect"); + assert(time_partitions.longest_pause() == 2, "Incorrect"); + + assert(!iter.has_next(), "Too many elements"); + } + + static void one_sub_pause_phase() { + TimePartitions time_partitions; + time_partitions.report_gc_phase_start("PausePhase", 2); + time_partitions.report_gc_phase_start("SubPhase", 3); + time_partitions.report_gc_phase_end(4); + time_partitions.report_gc_phase_end(5); + + TimePartitionPhasesIterator iter(&time_partitions); + + validate_pause_phase(iter.next(), 0, "PausePhase", 2, 5); + validate_pause_phase(iter.next(), 1, "SubPhase", 3, 4); + + assert(time_partitions.sum_of_pauses() == 3, "Incorrect"); + assert(time_partitions.longest_pause() == 3, "Incorrect"); + + assert(!iter.has_next(), "Too many elements"); + } + + static void max_nested_pause_phases() { + TimePartitions time_partitions; + time_partitions.report_gc_phase_start("PausePhase", 2); + time_partitions.report_gc_phase_start("SubPhase1", 3); + time_partitions.report_gc_phase_start("SubPhase2", 4); + time_partitions.report_gc_phase_start("SubPhase3", 5); + time_partitions.report_gc_phase_end(6); + time_partitions.report_gc_phase_end(7); + time_partitions.report_gc_phase_end(8); + time_partitions.report_gc_phase_end(9); + + TimePartitionPhasesIterator iter(&time_partitions); + + validate_pause_phase(iter.next(), 0, "PausePhase", 2, 9); + validate_pause_phase(iter.next(), 1, "SubPhase1", 3, 8); + validate_pause_phase(iter.next(), 2, "SubPhase2", 4, 7); + validate_pause_phase(iter.next(), 3, "SubPhase3", 5, 6); + + assert(time_partitions.sum_of_pauses() == 7, "Incorrect"); + assert(time_partitions.longest_pause() == 7, "Incorrect"); + + assert(!iter.has_next(), "Too many elements"); + } + + static void many_sub_pause_phases() { + TimePartitions time_partitions; + time_partitions.report_gc_phase_start("PausePhase", 2); + + time_partitions.report_gc_phase_start("SubPhase1", 3); + time_partitions.report_gc_phase_end(4); + time_partitions.report_gc_phase_start("SubPhase2", 5); + time_partitions.report_gc_phase_end(6); + time_partitions.report_gc_phase_start("SubPhase3", 7); + time_partitions.report_gc_phase_end(8); + time_partitions.report_gc_phase_start("SubPhase4", 9); + time_partitions.report_gc_phase_end(10); + + time_partitions.report_gc_phase_end(11); + + TimePartitionPhasesIterator iter(&time_partitions); + + validate_pause_phase(iter.next(), 0, "PausePhase", 2, 11); + validate_pause_phase(iter.next(), 1, "SubPhase1", 3, 4); + validate_pause_phase(iter.next(), 1, "SubPhase2", 5, 6); + validate_pause_phase(iter.next(), 1, "SubPhase3", 7, 8); + validate_pause_phase(iter.next(), 1, "SubPhase4", 9, 10); + + assert(time_partitions.sum_of_pauses() == 9, "Incorrect"); + assert(time_partitions.longest_pause() == 9, "Incorrect"); + + assert(!iter.has_next(), "Too many elements"); + } + + static void many_sub_pause_phases2() { + TimePartitions time_partitions; + time_partitions.report_gc_phase_start("PausePhase", 2); + + time_partitions.report_gc_phase_start("SubPhase1", 3); + time_partitions.report_gc_phase_start("SubPhase11", 4); + time_partitions.report_gc_phase_end(5); + time_partitions.report_gc_phase_start("SubPhase12", 6); + time_partitions.report_gc_phase_end(7); + time_partitions.report_gc_phase_end(8); + time_partitions.report_gc_phase_start("SubPhase2", 9); + time_partitions.report_gc_phase_start("SubPhase21", 10); + time_partitions.report_gc_phase_end(11); + time_partitions.report_gc_phase_start("SubPhase22", 12); + time_partitions.report_gc_phase_end(13); + time_partitions.report_gc_phase_end(14); + time_partitions.report_gc_phase_start("SubPhase3", 15); + time_partitions.report_gc_phase_end(16); + + time_partitions.report_gc_phase_end(17); + + TimePartitionPhasesIterator iter(&time_partitions); + + validate_pause_phase(iter.next(), 0, "PausePhase", 2, 17); + validate_pause_phase(iter.next(), 1, "SubPhase1", 3, 8); + validate_pause_phase(iter.next(), 2, "SubPhase11", 4, 5); + validate_pause_phase(iter.next(), 2, "SubPhase12", 6, 7); + validate_pause_phase(iter.next(), 1, "SubPhase2", 9, 14); + validate_pause_phase(iter.next(), 2, "SubPhase21", 10, 11); + validate_pause_phase(iter.next(), 2, "SubPhase22", 12, 13); + validate_pause_phase(iter.next(), 1, "SubPhase3", 15, 16); + + assert(time_partitions.sum_of_pauses() == 15, "Incorrect"); + assert(time_partitions.longest_pause() == 15, "Incorrect"); + + assert(!iter.has_next(), "Too many elements"); + } +}; + +class GCTimerTest { +public: + static void all() { + gc_start(); + gc_end(); + } + + static void gc_start() { + GCTimer gc_timer; + gc_timer.register_gc_start(1); + + assert(gc_timer.gc_start() == 1, "Incorrect"); + } + + static void gc_end() { + GCTimer gc_timer; + gc_timer.register_gc_start(1); + gc_timer.register_gc_end(2); + + assert(gc_timer.gc_end() == 2, "Incorrect"); + } +}; + +void GCTimerAllTest::all() { + GCTimerTest::all(); + TimePartitionPhasesIteratorTest::all(); +} + +#endif diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/gc_implementation/shared/gcTimer.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/gc_implementation/shared/gcTimer.hpp Fri Jun 21 15:56:24 2013 -0700 @@ -0,0 +1,195 @@ +/* + * 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_SHARED_GCTIMER_HPP +#define SHARE_VM_GC_IMPLEMENTATION_SHARED_GCTIMER_HPP + +#include "memory/allocation.hpp" +#include "prims/jni_md.h" +#include "utilities/macros.hpp" + +class ConcurrentPhase; +class GCPhase; +class PausePhase; + +template class GrowableArray; + +class PhaseVisitor { + public: + virtual void visit(GCPhase* phase) = 0; + virtual void visit(PausePhase* phase) { visit((GCPhase*)phase); } + virtual void visit(ConcurrentPhase* phase) { visit((GCPhase*)phase); } +}; + +class GCPhase { + const char* _name; + int _level; + jlong _start; + jlong _end; + + public: + void set_name(const char* name) { _name = name; } + const char* name() { return _name; } + + int level() { return _level; } + void set_level(int level) { _level = level; } + + jlong start() { return _start; } + void set_start(jlong time) { _start = time; } + + jlong end() { return _end; } + void set_end(jlong time) { _end = time; } + + virtual void accept(PhaseVisitor* visitor) = 0; +}; + +class PausePhase : public GCPhase { + public: + void accept(PhaseVisitor* visitor) { + visitor->visit(this); + } +}; + +class ConcurrentPhase : public GCPhase { + void accept(PhaseVisitor* visitor) { + visitor->visit(this); + } +}; + +class PhasesStack { + public: + // FIXME: Temporary set to 5 (used to be 4), since Reference processing needs it. + static const int PHASE_LEVELS = 5; + + private: + int _phase_indices[PHASE_LEVELS]; + int _next_phase_level; + + public: + PhasesStack() { clear(); } + void clear(); + + void push(int phase_index); + int pop(); + int count() const; +}; + +class TimePartitions { + static const int INITIAL_CAPACITY = 10; + + // Currently we only support pause phases. + GrowableArray* _phases; + PhasesStack _active_phases; + + jlong _sum_of_pauses; + jlong _longest_pause; + + public: + TimePartitions(); + ~TimePartitions(); + void clear(); + + void report_gc_phase_start(const char* name, jlong time); + void report_gc_phase_end(jlong time); + + int num_phases() const; + GCPhase* phase_at(int index) const; + + jlong sum_of_pauses(); + jlong longest_pause(); + + bool has_active_phases(); + private: + void update_statistics(GCPhase* phase); +}; + +class PhasesIterator { + public: + virtual bool has_next() = 0; + virtual GCPhase* next() = 0; +}; + +class GCTimer : public ResourceObj { + NOT_PRODUCT(friend class GCTimerTest;) + protected: + jlong _gc_start; + jlong _gc_end; + TimePartitions _time_partitions; + + public: + virtual void register_gc_start(jlong time); + virtual void register_gc_end(jlong time); + + void register_gc_phase_start(const char* name, jlong time); + void register_gc_phase_end(jlong time); + + jlong gc_start() { return _gc_start; } + jlong gc_end() { return _gc_end; } + + TimePartitions* time_partitions() { return &_time_partitions; } + + long longest_pause(); + long sum_of_pauses(); + + protected: + void register_gc_pause_start(const char* name, jlong time); + void register_gc_pause_end(jlong time); +}; + +class STWGCTimer : public GCTimer { + public: + virtual void register_gc_start(jlong time); + virtual void register_gc_end(jlong time); +}; + +class ConcurrentGCTimer : public GCTimer { + public: + void register_gc_pause_start(const char* name, jlong time); + void register_gc_pause_end(jlong time); +}; + +class TimePartitionPhasesIterator { + TimePartitions* _time_partitions; + int _next; + + public: + TimePartitionPhasesIterator(TimePartitions* time_partitions) : _time_partitions(time_partitions), _next(0) { } + + virtual bool has_next(); + virtual GCPhase* next(); +}; + + +/////////////// Unit tests /////////////// + +#ifndef PRODUCT + +class GCTimerAllTest { + public: + static void all(); +}; + +#endif + +#endif // SHARE_VM_GC_IMPLEMENTATION_SHARED_GCTIMER_HPP diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/gc_implementation/shared/gcTrace.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/gc_implementation/shared/gcTrace.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -0,0 +1,207 @@ +/* + * 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. + * + */ + +#include "precompiled.hpp" +#include "gc_implementation/shared/gcHeapSummary.hpp" +#include "gc_implementation/shared/gcTimer.hpp" +#include "gc_implementation/shared/gcTrace.hpp" +#include "gc_implementation/shared/copyFailedInfo.hpp" +#include "memory/heapInspection.hpp" +#include "memory/referenceProcessorStats.hpp" +#include "utilities/globalDefinitions.hpp" + +#if INCLUDE_ALL_GCS +#include "gc_implementation/g1/evacuationInfo.hpp" +#endif + +#define assert_unset_gc_id() assert(_shared_gc_info.id() == SharedGCInfo::UNSET_GCID, "GC already started?") +#define assert_set_gc_id() assert(_shared_gc_info.id() != SharedGCInfo::UNSET_GCID, "GC not started?") + +static jlong GCTracer_next_gc_id = 0; +static GCId create_new_gc_id() { + return GCTracer_next_gc_id++; +} + +void GCTracer::report_gc_start_impl(GCCause::Cause cause, jlong timestamp) { + assert_unset_gc_id(); + + GCId gc_id = create_new_gc_id(); + _shared_gc_info.set_id(gc_id); + _shared_gc_info.set_cause(cause); + _shared_gc_info.set_start_timestamp(timestamp); +} + +void GCTracer::report_gc_start(GCCause::Cause cause, jlong timestamp) { + assert_unset_gc_id(); + + report_gc_start_impl(cause, timestamp); +} + +bool GCTracer::has_reported_gc_start() const { + return _shared_gc_info.id() != SharedGCInfo::UNSET_GCID; +} + +void GCTracer::report_gc_end_impl(jlong timestamp, TimePartitions* time_partitions) { + assert_set_gc_id(); + + _shared_gc_info.set_sum_of_pauses(time_partitions->sum_of_pauses()); + _shared_gc_info.set_longest_pause(time_partitions->longest_pause()); + _shared_gc_info.set_end_timestamp(timestamp); + + send_phase_events(time_partitions); + send_garbage_collection_event(); +} + +void GCTracer::report_gc_end(jlong timestamp, TimePartitions* time_partitions) { + assert_set_gc_id(); + + report_gc_end_impl(timestamp, time_partitions); + + _shared_gc_info.set_id(SharedGCInfo::UNSET_GCID); +} + +void GCTracer::report_gc_reference_stats(const ReferenceProcessorStats& rps) const { + assert_set_gc_id(); + + send_reference_stats_event(REF_SOFT, rps.soft_count()); + send_reference_stats_event(REF_WEAK, rps.weak_count()); + send_reference_stats_event(REF_FINAL, rps.final_count()); + send_reference_stats_event(REF_PHANTOM, rps.phantom_count()); +} + +#if INCLUDE_SERVICES +void ObjectCountEventSenderClosure::do_cinfo(KlassInfoEntry* entry) { + if (should_send_event(entry)) { + send_event(entry); + } +} + +void ObjectCountEventSenderClosure::send_event(KlassInfoEntry* entry) { + _gc_tracer->send_object_count_after_gc_event(entry->klass(), entry->count(), + entry->words() * BytesPerWord); +} + +bool ObjectCountEventSenderClosure::should_send_event(KlassInfoEntry* entry) const { + double percentage_of_heap = ((double) entry->words()) / _total_size_in_words; + return percentage_of_heap > _size_threshold_percentage; +} + +void GCTracer::report_object_count_after_gc(BoolObjectClosure* is_alive_cl) { + assert_set_gc_id(); + + if (should_send_object_count_after_gc_event()) { + ResourceMark rm; + + KlassInfoTable cit(false); + if (!cit.allocation_failed()) { + HeapInspection hi(false, false, false, NULL); + hi.populate_table(&cit, is_alive_cl); + + ObjectCountEventSenderClosure event_sender(this, cit.size_of_instances_in_words()); + cit.iterate(&event_sender); + } + } +} +#endif + +void GCTracer::report_gc_heap_summary(GCWhen::Type when, const GCHeapSummary& heap_summary, const MetaspaceSummary& meta_space_summary) const { + assert_set_gc_id(); + + send_gc_heap_summary_event(when, heap_summary); + send_meta_space_summary_event(when, meta_space_summary); +} + +void YoungGCTracer::report_gc_end_impl(jlong timestamp, TimePartitions* time_partitions) { + assert_set_gc_id(); + assert(_tenuring_threshold != UNSET_TENURING_THRESHOLD, "Tenuring threshold has not been reported"); + + GCTracer::report_gc_end_impl(timestamp, time_partitions); + send_young_gc_event(); + + _tenuring_threshold = UNSET_TENURING_THRESHOLD; +} + +void YoungGCTracer::report_promotion_failed(const PromotionFailedInfo& pf_info) { + assert_set_gc_id(); + + send_promotion_failed_event(pf_info); +} + +void YoungGCTracer::report_tenuring_threshold(const uint tenuring_threshold) { + _tenuring_threshold = tenuring_threshold; +} + +void OldGCTracer::report_gc_end_impl(jlong timestamp, TimePartitions* time_partitions) { + assert_set_gc_id(); + + GCTracer::report_gc_end_impl(timestamp, time_partitions); + send_old_gc_event(); +} + +void ParallelOldTracer::report_gc_end_impl(jlong timestamp, TimePartitions* time_partitions) { + assert_set_gc_id(); + + OldGCTracer::report_gc_end_impl(timestamp, time_partitions); + send_parallel_old_event(); +} + +void ParallelOldTracer::report_dense_prefix(void* dense_prefix) { + assert_set_gc_id(); + + _parallel_old_gc_info.report_dense_prefix(dense_prefix); +} + +void OldGCTracer::report_concurrent_mode_failure() { + assert_set_gc_id(); + + send_concurrent_mode_failure_event(); +} + +#if INCLUDE_ALL_GCS +void G1NewTracer::report_yc_type(G1YCType type) { + assert_set_gc_id(); + + _g1_young_gc_info.set_type(type); +} + +void G1NewTracer::report_gc_end_impl(jlong timestamp, TimePartitions* time_partitions) { + assert_set_gc_id(); + + YoungGCTracer::report_gc_end_impl(timestamp, time_partitions); + send_g1_young_gc_event(); +} + +void G1NewTracer::report_evacuation_info(EvacuationInfo* info) { + assert_set_gc_id(); + + send_evacuation_info_event(info); +} + +void G1NewTracer::report_evacuation_failed(EvacuationFailedInfo& ef_info) { + assert_set_gc_id(); + + send_evacuation_failed_event(ef_info); + ef_info.reset(); +} +#endif diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/gc_implementation/shared/gcTrace.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/gc_implementation/shared/gcTrace.hpp Fri Jun 21 15:56:24 2013 -0700 @@ -0,0 +1,255 @@ +/* + * 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_SHARED_GCTRACE_HPP +#define SHARE_VM_GC_IMPLEMENTATION_SHARED_GCTRACE_HPP + +#include "gc_interface/gcCause.hpp" +#include "gc_interface/gcName.hpp" +#include "gc_implementation/shared/gcWhen.hpp" +#include "gc_implementation/shared/copyFailedInfo.hpp" +#include "memory/allocation.hpp" +#include "memory/klassInfoClosure.hpp" +#include "memory/referenceType.hpp" +#if INCLUDE_ALL_GCS +#include "gc_implementation/g1/g1YCTypes.hpp" +#endif +#include "utilities/macros.hpp" + +typedef uint GCId; + +class EvacuationInfo; +class GCHeapSummary; +class MetaspaceSummary; +class PSHeapSummary; +class ReferenceProcessorStats; +class TimePartitions; +class BoolObjectClosure; + +class SharedGCInfo VALUE_OBJ_CLASS_SPEC { + static const jlong UNSET_TIMESTAMP = -1; + + public: + static const GCId UNSET_GCID = (GCId)-1; + + private: + GCId _id; + GCName _name; + GCCause::Cause _cause; + jlong _start_timestamp; + jlong _end_timestamp; + jlong _sum_of_pauses; + jlong _longest_pause; + + public: + SharedGCInfo(GCName name) : _id(UNSET_GCID), _name(name), _cause(GCCause::_last_gc_cause), + _start_timestamp(UNSET_TIMESTAMP), _end_timestamp(UNSET_TIMESTAMP), _sum_of_pauses(0), _longest_pause(0) {} + + void set_id(GCId id) { _id = id; } + GCId id() const { return _id; } + + void set_start_timestamp(jlong timestamp) { _start_timestamp = timestamp; } + jlong start_timestamp() const { return _start_timestamp; } + + void set_end_timestamp(jlong timestamp) { _end_timestamp = timestamp; } + jlong end_timestamp() const { return _end_timestamp; } + + void set_name(GCName name) { _name = name; } + GCName name() const { return _name; } + + void set_cause(GCCause::Cause cause) { _cause = cause; } + GCCause::Cause cause() const { return _cause; } + + void set_sum_of_pauses(jlong duration) { _sum_of_pauses = duration; } + jlong sum_of_pauses() const { return _sum_of_pauses; } + + void set_longest_pause(jlong duration) { _longest_pause = duration; } + jlong longest_pause() const { return _longest_pause; } +}; + +class ParallelOldGCInfo VALUE_OBJ_CLASS_SPEC { + void* _dense_prefix; + public: + ParallelOldGCInfo() : _dense_prefix(NULL) {} + void report_dense_prefix(void* addr) { + _dense_prefix = addr; + } + void* dense_prefix() const { return _dense_prefix; } +}; + +#if INCLUDE_ALL_GCS + +class G1YoungGCInfo VALUE_OBJ_CLASS_SPEC { + G1YCType _type; + public: + G1YoungGCInfo() : _type(G1YCTypeEndSentinel) {} + void set_type(G1YCType type) { + _type = type; + } + G1YCType type() const { return _type; } +}; + +#endif // INCLUDE_ALL_GCS + +class GCTracer : public ResourceObj { + friend class ObjectCountEventSenderClosure; + protected: + SharedGCInfo _shared_gc_info; + + public: + void report_gc_start(GCCause::Cause cause, jlong timestamp); + void report_gc_end(jlong timestamp, TimePartitions* time_partitions); + void report_gc_heap_summary(GCWhen::Type when, const GCHeapSummary& heap_summary, const MetaspaceSummary& meta_space_summary) const; + void report_gc_reference_stats(const ReferenceProcessorStats& rp) const; + void report_object_count_after_gc(BoolObjectClosure* object_filter) NOT_SERVICES_RETURN; + + bool has_reported_gc_start() const; + + protected: + GCTracer(GCName name) : _shared_gc_info(name) {} + virtual void report_gc_start_impl(GCCause::Cause cause, jlong timestamp); + virtual void report_gc_end_impl(jlong timestamp, TimePartitions* time_partitions); + + private: + void send_garbage_collection_event() const; + void send_gc_heap_summary_event(GCWhen::Type when, const GCHeapSummary& heap_summary) const; + void send_meta_space_summary_event(GCWhen::Type when, const MetaspaceSummary& meta_space_summary) const; + void send_reference_stats_event(ReferenceType type, size_t count) const; + void send_phase_events(TimePartitions* time_partitions) const; + void send_object_count_after_gc_event(Klass* klass, jlong count, julong total_size) const NOT_SERVICES_RETURN; + bool should_send_object_count_after_gc_event() const; +}; + +class ObjectCountEventSenderClosure : public KlassInfoClosure { + GCTracer* _gc_tracer; + const double _size_threshold_percentage; + const size_t _total_size_in_words; + public: + ObjectCountEventSenderClosure(GCTracer* gc_tracer, size_t total_size_in_words) : + _gc_tracer(gc_tracer), + _size_threshold_percentage(ObjectCountCutOffPercent / 100), + _total_size_in_words(total_size_in_words) + {} + virtual void do_cinfo(KlassInfoEntry* entry); + protected: + virtual void send_event(KlassInfoEntry* entry); + private: + bool should_send_event(KlassInfoEntry* entry) const; +}; + +class YoungGCTracer : public GCTracer { + static const uint UNSET_TENURING_THRESHOLD = (uint) -1; + + uint _tenuring_threshold; + + protected: + YoungGCTracer(GCName name) : GCTracer(name), _tenuring_threshold(UNSET_TENURING_THRESHOLD) {} + virtual void report_gc_end_impl(jlong timestamp, TimePartitions* time_partitions); + + public: + void report_promotion_failed(const PromotionFailedInfo& pf_info); + void report_tenuring_threshold(const uint tenuring_threshold); + + private: + void send_young_gc_event() const; + void send_promotion_failed_event(const PromotionFailedInfo& pf_info) const; +}; + +class OldGCTracer : public GCTracer { + protected: + OldGCTracer(GCName name) : GCTracer(name) {} + virtual void report_gc_end_impl(jlong timestamp, TimePartitions* time_partitions); + + public: + void report_concurrent_mode_failure(); + + private: + void send_old_gc_event() const; + void send_concurrent_mode_failure_event(); +}; + +class ParallelOldTracer : public OldGCTracer { + ParallelOldGCInfo _parallel_old_gc_info; + + public: + ParallelOldTracer() : OldGCTracer(ParallelOld) {} + void report_dense_prefix(void* dense_prefix); + + protected: + void report_gc_end_impl(jlong timestamp, TimePartitions* time_partitions); + + private: + void send_parallel_old_event() const; +}; + +class SerialOldTracer : public OldGCTracer { + public: + SerialOldTracer() : OldGCTracer(SerialOld) {} +}; + +class ParallelScavengeTracer : public YoungGCTracer { + public: + ParallelScavengeTracer() : YoungGCTracer(ParallelScavenge) {} +}; + +class DefNewTracer : public YoungGCTracer { + public: + DefNewTracer() : YoungGCTracer(DefNew) {} +}; + +class ParNewTracer : public YoungGCTracer { + public: + ParNewTracer() : YoungGCTracer(ParNew) {} +}; + +#if INCLUDE_ALL_GCS +class G1NewTracer : public YoungGCTracer { + G1YoungGCInfo _g1_young_gc_info; + + public: + G1NewTracer() : YoungGCTracer(G1New) {} + + void report_yc_type(G1YCType type); + void report_gc_end_impl(jlong timestamp, TimePartitions* time_partitions); + void report_evacuation_info(EvacuationInfo* info); + void report_evacuation_failed(EvacuationFailedInfo& ef_info); + + private: + void send_g1_young_gc_event(); + void send_evacuation_info_event(EvacuationInfo* info); + void send_evacuation_failed_event(const EvacuationFailedInfo& ef_info) const; +}; +#endif + +class CMSTracer : public OldGCTracer { + public: + CMSTracer() : OldGCTracer(ConcurrentMarkSweep) {} +}; + +class G1OldTracer : public OldGCTracer { + public: + G1OldTracer() : OldGCTracer(G1Old) {} +}; + +#endif // SHARE_VM_GC_IMPLEMENTATION_SHARED_GCTRACE_HPP diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/gc_implementation/shared/gcTraceSend.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/gc_implementation/shared/gcTraceSend.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -0,0 +1,318 @@ +/* + * 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. + * + */ + +#include "precompiled.hpp" +#include "gc_implementation/shared/gcHeapSummary.hpp" +#include "gc_implementation/shared/gcTimer.hpp" +#include "gc_implementation/shared/gcTrace.hpp" +#include "gc_implementation/shared/gcWhen.hpp" +#include "gc_implementation/shared/copyFailedInfo.hpp" +#include "trace/tracing.hpp" +#include "trace/traceBackend.hpp" +#if INCLUDE_ALL_GCS +#include "gc_implementation/g1/evacuationInfo.hpp" +#include "gc_implementation/g1/g1YCTypes.hpp" +#endif + +// All GC dependencies against the trace framework is contained within this file. + +typedef uintptr_t TraceAddress; + +void GCTracer::send_garbage_collection_event() const { + EventGCGarbageCollection event(UNTIMED); + if (event.should_commit()) { + event.set_gcId(_shared_gc_info.id()); + event.set_name(_shared_gc_info.name()); + event.set_cause((u2) _shared_gc_info.cause()); + event.set_sumOfPauses(_shared_gc_info.sum_of_pauses()); + event.set_longestPause(_shared_gc_info.longest_pause()); + event.set_starttime(_shared_gc_info.start_timestamp()); + event.set_endtime(_shared_gc_info.end_timestamp()); + event.commit(); + } +} + +void GCTracer::send_reference_stats_event(ReferenceType type, size_t count) const { + EventGCReferenceStatistics e; + if (e.should_commit()) { + e.set_gcId(_shared_gc_info.id()); + e.set_type((u1)type); + e.set_count(count); + e.commit(); + } +} + +void ParallelOldTracer::send_parallel_old_event() const { + EventGCParallelOld e(UNTIMED); + if (e.should_commit()) { + e.set_gcId(_shared_gc_info.id()); + e.set_densePrefix((TraceAddress)_parallel_old_gc_info.dense_prefix()); + e.set_starttime(_shared_gc_info.start_timestamp()); + e.set_endtime(_shared_gc_info.end_timestamp()); + e.commit(); + } +} + +void YoungGCTracer::send_young_gc_event() const { + EventGCYoungGarbageCollection e(UNTIMED); + if (e.should_commit()) { + e.set_gcId(_shared_gc_info.id()); + e.set_tenuringThreshold(_tenuring_threshold); + e.set_starttime(_shared_gc_info.start_timestamp()); + e.set_endtime(_shared_gc_info.end_timestamp()); + e.commit(); + } +} + +void OldGCTracer::send_old_gc_event() const { + EventGCOldGarbageCollection e(UNTIMED); + if (e.should_commit()) { + e.set_gcId(_shared_gc_info.id()); + e.set_starttime(_shared_gc_info.start_timestamp()); + e.set_endtime(_shared_gc_info.end_timestamp()); + e.commit(); + } +} + +static TraceStructCopyFailed to_trace_struct(const CopyFailedInfo& cf_info) { + TraceStructCopyFailed failed_info; + failed_info.set_objectCount(cf_info.failed_count()); + failed_info.set_firstSize(cf_info.first_size()); + failed_info.set_smallestSize(cf_info.smallest_size()); + failed_info.set_totalSize(cf_info.total_size()); + return failed_info; +} + +void YoungGCTracer::send_promotion_failed_event(const PromotionFailedInfo& pf_info) const { + EventPromotionFailed e; + if (e.should_commit()) { + e.set_gcId(_shared_gc_info.id()); + e.set_data(to_trace_struct(pf_info)); + e.set_thread(pf_info.thread()->thread_id()); + e.commit(); + } +} + +// Common to CMS and G1 +void OldGCTracer::send_concurrent_mode_failure_event() { + EventConcurrentModeFailure e; + if (e.should_commit()) { + e.set_gcId(_shared_gc_info.id()); + e.commit(); + } +} + +#if INCLUDE_SERVICES +void GCTracer::send_object_count_after_gc_event(Klass* klass, jlong count, julong total_size) const { + EventObjectCountAfterGC e; + if (e.should_commit()) { + e.set_gcId(_shared_gc_info.id()); + e.set_class(klass); + e.set_count(count); + e.set_totalSize(total_size); + e.commit(); + } +} +#endif + +bool GCTracer::should_send_object_count_after_gc_event() const { +#if INCLUDE_TRACE + return Tracing::is_event_enabled(EventObjectCountAfterGC::eventId); +#else + return false; +#endif +} + +#if INCLUDE_ALL_GCS +void G1NewTracer::send_g1_young_gc_event() { + EventGCG1GarbageCollection e(UNTIMED); + if (e.should_commit()) { + e.set_gcId(_shared_gc_info.id()); + e.set_type(_g1_young_gc_info.type()); + e.set_starttime(_shared_gc_info.start_timestamp()); + e.set_endtime(_shared_gc_info.end_timestamp()); + e.commit(); + } +} + +void G1NewTracer::send_evacuation_info_event(EvacuationInfo* info) { + EventEvacuationInfo e; + if (e.should_commit()) { + e.set_gcId(_shared_gc_info.id()); + e.set_cSetRegions(info->collectionset_regions()); + e.set_cSetUsedBefore(info->collectionset_used_before()); + e.set_cSetUsedAfter(info->collectionset_used_after()); + e.set_allocationRegions(info->allocation_regions()); + e.set_allocRegionsUsedBefore(info->alloc_regions_used_before()); + e.set_allocRegionsUsedAfter(info->alloc_regions_used_before() + info->bytes_copied()); + e.set_bytesCopied(info->bytes_copied()); + e.set_regionsFreed(info->regions_freed()); + e.commit(); + } +} + +void G1NewTracer::send_evacuation_failed_event(const EvacuationFailedInfo& ef_info) const { + EventEvacuationFailed e; + if (e.should_commit()) { + e.set_gcId(_shared_gc_info.id()); + e.set_data(to_trace_struct(ef_info)); + e.commit(); + } +} +#endif + +static TraceStructVirtualSpace to_trace_struct(const VirtualSpaceSummary& summary) { + TraceStructVirtualSpace space; + space.set_start((TraceAddress)summary.start()); + space.set_committedEnd((TraceAddress)summary.committed_end()); + space.set_committedSize(summary.committed_size()); + space.set_reservedEnd((TraceAddress)summary.reserved_end()); + space.set_reservedSize(summary.reserved_size()); + return space; +} + +static TraceStructObjectSpace to_trace_struct(const SpaceSummary& summary) { + TraceStructObjectSpace space; + space.set_start((TraceAddress)summary.start()); + space.set_end((TraceAddress)summary.end()); + space.set_used(summary.used()); + space.set_size(summary.size()); + return space; +} + +class GCHeapSummaryEventSender : public GCHeapSummaryVisitor { + GCId _id; + GCWhen::Type _when; + public: + GCHeapSummaryEventSender(GCId id, GCWhen::Type when) : _id(id), _when(when) {} + + void visit(const GCHeapSummary* heap_summary) const { + const VirtualSpaceSummary& heap_space = heap_summary->heap(); + + EventGCHeapSummary e; + if (e.should_commit()) { + e.set_gcId(_id); + e.set_when((u1)_when); + e.set_heapSpace(to_trace_struct(heap_space)); + e.set_heapUsed(heap_summary->used()); + e.commit(); + } + } + + void visit(const PSHeapSummary* ps_heap_summary) const { + visit((GCHeapSummary*)ps_heap_summary); + + const VirtualSpaceSummary& old_summary = ps_heap_summary->old(); + const SpaceSummary& old_space = ps_heap_summary->old_space(); + const VirtualSpaceSummary& young_summary = ps_heap_summary->young(); + const SpaceSummary& eden_space = ps_heap_summary->eden(); + const SpaceSummary& from_space = ps_heap_summary->from(); + const SpaceSummary& to_space = ps_heap_summary->to(); + + EventPSHeapSummary e; + if (e.should_commit()) { + e.set_gcId(_id); + e.set_when((u1)_when); + + e.set_oldSpace(to_trace_struct(ps_heap_summary->old())); + e.set_oldObjectSpace(to_trace_struct(ps_heap_summary->old_space())); + e.set_youngSpace(to_trace_struct(ps_heap_summary->young())); + e.set_edenSpace(to_trace_struct(ps_heap_summary->eden())); + e.set_fromSpace(to_trace_struct(ps_heap_summary->from())); + e.set_toSpace(to_trace_struct(ps_heap_summary->to())); + e.commit(); + } + } +}; + +void GCTracer::send_gc_heap_summary_event(GCWhen::Type when, const GCHeapSummary& heap_summary) const { + GCHeapSummaryEventSender visitor(_shared_gc_info.id(), when); + heap_summary.accept(&visitor); +} + +static TraceStructMetaspaceSizes to_trace_struct(const MetaspaceSizes& sizes) { + TraceStructMetaspaceSizes meta_sizes; + + meta_sizes.set_capacity(sizes.capacity()); + meta_sizes.set_used(sizes.used()); + meta_sizes.set_reserved(sizes.reserved()); + + return meta_sizes; +} + +void GCTracer::send_meta_space_summary_event(GCWhen::Type when, const MetaspaceSummary& meta_space_summary) const { + EventMetaspaceSummary e; + if (e.should_commit()) { + e.set_gcId(_shared_gc_info.id()); + e.set_when((u1) when); + e.set_metaspace(to_trace_struct(meta_space_summary.meta_space())); + e.set_dataSpace(to_trace_struct(meta_space_summary.data_space())); + e.set_classSpace(to_trace_struct(meta_space_summary.class_space())); + e.commit(); + } +} + +class PhaseSender : public PhaseVisitor { + GCId _gc_id; + public: + PhaseSender(GCId gc_id) : _gc_id(gc_id) {} + + template + void send_phase(PausePhase* pause) { + T event(UNTIMED); + if (event.should_commit()) { + event.set_gcId(_gc_id); + event.set_name(pause->name()); + event.set_starttime(pause->start()); + event.set_endtime(pause->end()); + event.commit(); + } + } + + void visit(GCPhase* pause) { ShouldNotReachHere(); } + void visit(ConcurrentPhase* pause) { Unimplemented(); } + void visit(PausePhase* pause) { + assert(PhasesStack::PHASE_LEVELS == 5, "Need more event types"); + + switch (pause->level()) { + case 0: send_phase(pause); break; + case 1: send_phase(pause); break; + case 2: send_phase(pause); break; + case 3: send_phase(pause); break; + default: /* Ignore sending this phase */ break; + } + } + +#undef send_phase +}; + +void GCTracer::send_phase_events(TimePartitions* time_partitions) const { + PhaseSender phase_reporter(_shared_gc_info.id()); + + TimePartitionPhasesIterator iter(time_partitions); + while (iter.has_next()) { + GCPhase* phase = iter.next(); + phase->accept(&phase_reporter); + } +} diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/gc_implementation/shared/gcTraceTime.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/gc_implementation/shared/gcTraceTime.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -0,0 +1,79 @@ +/* + * 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. + * + */ + +#include "precompiled.hpp" +#include "gc_implementation/shared/gcTimer.hpp" +#include "gc_implementation/shared/gcTraceTime.hpp" +#include "runtime/globals.hpp" +#include "runtime/os.hpp" +#include "runtime/safepoint.hpp" +#include "runtime/thread.inline.hpp" +#include "runtime/timer.hpp" +#include "utilities/ostream.hpp" + + +GCTraceTime::GCTraceTime(const char* title, bool doit, bool print_cr, GCTimer* timer) : + _title(title), _doit(doit), _print_cr(print_cr), _timer(timer) { + if (_doit || _timer != NULL) { + _start_counter = os::elapsed_counter(); + } + + if (_timer != NULL) { + assert(SafepointSynchronize::is_at_safepoint(), "Tracing currently only supported at safepoints"); + assert(Thread::current()->is_VM_thread(), "Tracing currently only supported from the VM thread"); + + _timer->register_gc_phase_start(title, _start_counter); + } + + if (_doit) { + if (PrintGCTimeStamps) { + gclog_or_tty->stamp(); + gclog_or_tty->print(": "); + } + gclog_or_tty->print("[%s", title); + gclog_or_tty->flush(); + } +} + +GCTraceTime::~GCTraceTime() { + jlong stop_counter = 0; + + if (_doit || _timer != NULL) { + stop_counter = os::elapsed_counter(); + } + + if (_timer != NULL) { + _timer->register_gc_phase_end(stop_counter); + } + + if (_doit) { + double seconds = TimeHelper::counter_to_seconds(stop_counter - _start_counter); + if (_print_cr) { + gclog_or_tty->print_cr(", %3.7f secs]", seconds); + } else { + gclog_or_tty->print(", %3.7f secs]", seconds); + } + gclog_or_tty->flush(); + } +} diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/gc_implementation/shared/gcTraceTime.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/gc_implementation/shared/gcTraceTime.hpp Fri Jun 21 15:56:24 2013 -0700 @@ -0,0 +1,44 @@ +/* + * 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_SHARED_GCTRACETIME_HPP +#define SHARE_VM_GC_IMPLEMENTATION_SHARED_GCTRACETIME_HPP + +#include "prims/jni_md.h" + +class GCTimer; + +class GCTraceTime { + const char* _title; + bool _doit; + bool _print_cr; + GCTimer* _timer; + jlong _start_counter; + + public: + GCTraceTime(const char* title, bool doit, bool print_cr, GCTimer* timer); + ~GCTraceTime(); +}; + +#endif // SHARE_VM_GC_IMPLEMENTATION_SHARED_GCTRACETIME_HPP diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/gc_implementation/shared/gcWhen.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/gc_implementation/shared/gcWhen.hpp Fri Jun 21 15:56:24 2013 -0700 @@ -0,0 +1,48 @@ +/* + * 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_SHARED_GCWHEN_HPP +#define SHARE_VM_GC_IMPLEMENTATION_SHARED_GCWHEN_HPP + +#include "memory/allocation.hpp" +#include "utilities/debug.hpp" + +class GCWhen : AllStatic { + public: + enum Type { + BeforeGC, + AfterGC, + GCWhenEndSentinel + }; + + static const char* to_string(GCWhen::Type when) { + switch (when) { + case BeforeGC: return "Before GC"; + case AfterGC: return "After GC"; + default: ShouldNotReachHere(); return NULL; + } + } +}; + +#endif // SHARE_VM_GC_IMPLEMENTATION_SHARED_GCWHEN_HPP diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/gc_implementation/shared/markSweep.cpp --- a/src/share/vm/gc_implementation/shared/markSweep.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/gc_implementation/shared/markSweep.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -24,6 +24,8 @@ #include "precompiled.hpp" #include "compiler/compileBroker.hpp" +#include "gc_implementation/shared/gcTimer.hpp" +#include "gc_implementation/shared/gcTrace.hpp" #include "gc_implementation/shared/markSweep.inline.hpp" #include "gc_interface/collectedHeap.inline.hpp" #include "oops/methodData.hpp" @@ -41,6 +43,8 @@ size_t MarkSweep::_preserved_count_max = 0; PreservedMark* MarkSweep::_preserved_marks = NULL; ReferenceProcessor* MarkSweep::_ref_processor = NULL; +STWGCTimer* MarkSweep::_gc_timer = NULL; +SerialOldTracer* MarkSweep::_gc_tracer = NULL; MarkSweep::FollowRootClosure MarkSweep::follow_root_closure; CodeBlobToOopClosure MarkSweep::follow_code_root_closure(&MarkSweep::follow_root_closure, /*do_marking=*/ true); @@ -173,7 +177,10 @@ void MarkSweep::KeepAliveClosure::do_oop(oop* p) { MarkSweep::KeepAliveClosure::do_oop_work(p); } void MarkSweep::KeepAliveClosure::do_oop(narrowOop* p) { MarkSweep::KeepAliveClosure::do_oop_work(p); } -void marksweep_init() { /* empty */ } +void marksweep_init() { + MarkSweep::_gc_timer = new (ResourceObj::C_HEAP, mtGC) STWGCTimer(); + MarkSweep::_gc_tracer = new (ResourceObj::C_HEAP, mtGC) SerialOldTracer(); +} #ifndef PRODUCT diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/gc_implementation/shared/markSweep.hpp --- a/src/share/vm/gc_implementation/shared/markSweep.hpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/gc_implementation/shared/markSweep.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 @@ -36,6 +36,8 @@ class ReferenceProcessor; class DataLayout; +class SerialOldTracer; +class STWGCTimer; // MarkSweep takes care of global mark-compact garbage collection for a // GenCollectedHeap using a four-phase pointer forwarding algorithm. All @@ -128,6 +130,9 @@ // Reference processing (used in ...follow_contents) static ReferenceProcessor* _ref_processor; + static STWGCTimer* _gc_timer; + static SerialOldTracer* _gc_tracer; + // Non public closures static KeepAliveClosure keep_alive; @@ -151,6 +156,9 @@ // Reference Processing static ReferenceProcessor* const ref_processor() { return _ref_processor; } + static STWGCTimer* gc_timer() { return _gc_timer; } + static SerialOldTracer* gc_tracer() { return _gc_tracer; } + // Call backs for marking static void mark_object(oop obj); // Mark pointer and follow contents. Empty marking stack afterwards. diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/gc_implementation/shared/parGCAllocBuffer.hpp --- a/src/share/vm/gc_implementation/shared/parGCAllocBuffer.hpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/gc_implementation/shared/parGCAllocBuffer.hpp Fri Jun 21 15:56:24 2013 -0700 @@ -158,7 +158,7 @@ // Fills in the unallocated portion of the buffer with a garbage object. // If "end_of_gc" is TRUE, is after the last use in the GC. IF "retain" // is true, attempt to re-use the unused portion in the next GC. - void retire(bool end_of_gc, bool retain); + virtual void retire(bool end_of_gc, bool retain); void print() PRODUCT_RETURN; }; diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/gc_implementation/shared/vmGCOperations.cpp --- a/src/share/vm/gc_implementation/shared/vmGCOperations.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/gc_implementation/shared/vmGCOperations.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -145,32 +145,37 @@ return false; } +bool VM_GC_HeapInspection::collect() { + if (GC_locker::is_active()) { + return false; + } + Universe::heap()->collect_as_vm_thread(GCCause::_heap_inspection); + return true; +} + void VM_GC_HeapInspection::doit() { HandleMark hm; - CollectedHeap* ch = Universe::heap(); - ch->ensure_parsability(false); // must happen, even if collection does - // not happen (e.g. due to GC_locker) + Universe::heap()->ensure_parsability(false); // must happen, even if collection does + // not happen (e.g. due to GC_locker) + // or _full_gc being false if (_full_gc) { - // The collection attempt below would be skipped anyway if - // the gc locker is held. The following dump may then be a tad - // misleading to someone expecting only live objects to show - // up in the dump (see CR 6944195). Just issue a suitable warning - // in that case and do not attempt to do a collection. - // The latter is a subtle point, because even a failed attempt - // to GC will, in fact, induce one in the future, which we - // probably want to avoid in this case because the GC that we may - // be about to attempt holds value for us only - // if it happens now and not if it happens in the eventual - // future. - if (GC_locker::is_active()) { + if (!collect()) { + // The collection attempt was skipped because the gc locker is held. + // The following dump may then be a tad misleading to someone expecting + // only live objects to show up in the dump (see CR 6944195). Just issue + // a suitable warning in that case and do not attempt to do a collection. + // The latter is a subtle point, because even a failed attempt + // to GC will, in fact, induce one in the future, which we + // probably want to avoid in this case because the GC that we may + // be about to attempt holds value for us only + // if it happens now and not if it happens in the eventual + // future. warning("GC locker is held; pre-dump GC was skipped"); - } else { - ch->collect_as_vm_thread(GCCause::_heap_inspection); } } HeapInspection inspect(_csv_format, _print_help, _print_class_stats, _columns); - inspect.heap_inspection(_out, _need_prologue /* need_prologue */); + inspect.heap_inspection(_out); } diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/gc_implementation/shared/vmGCOperations.hpp --- a/src/share/vm/gc_implementation/shared/vmGCOperations.hpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/gc_implementation/shared/vmGCOperations.hpp Fri Jun 21 15:56:24 2013 -0700 @@ -129,21 +129,18 @@ private: outputStream* _out; bool _full_gc; - bool _need_prologue; bool _csv_format; // "comma separated values" format for spreadsheet. bool _print_help; bool _print_class_stats; const char* _columns; public: - VM_GC_HeapInspection(outputStream* out, bool request_full_gc, - bool need_prologue) : + VM_GC_HeapInspection(outputStream* out, bool request_full_gc) : VM_GC_Operation(0 /* total collections, dummy, ignored */, GCCause::_heap_inspection /* GC Cause */, 0 /* total full collections, dummy, ignored */, request_full_gc) { _out = out; _full_gc = request_full_gc; - _need_prologue = need_prologue; _csv_format = false; _print_help = false; _print_class_stats = false; @@ -159,6 +156,8 @@ void set_print_help(bool value) {_print_help = value;} void set_print_class_stats(bool value) {_print_class_stats = value;} void set_columns(const char* value) {_columns = value;} + protected: + bool collect(); }; diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/gc_interface/allocTracer.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/gc_interface/allocTracer.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -0,0 +1,48 @@ +/* + * 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_interface/allocTracer.hpp" +#include "trace/tracing.hpp" +#include "runtime/handles.hpp" +#include "utilities/globalDefinitions.hpp" + +void AllocTracer::send_allocation_outside_tlab_event(KlassHandle klass, size_t alloc_size) { + EventAllocObjectOutsideTLAB event; + if (event.should_commit()) { + event.set_class(klass()); + event.set_allocationSize(alloc_size); + event.commit(); + } +} + +void AllocTracer::send_allocation_in_new_tlab_event(KlassHandle klass, size_t tlab_size, size_t alloc_size) { + EventAllocObjectInNewTLAB event; + if (event.should_commit()) { + event.set_class(klass()); + event.set_allocationSize(alloc_size); + event.set_tlabSize(tlab_size); + event.commit(); + } +} diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/gc_interface/allocTracer.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/gc_interface/allocTracer.hpp Fri Jun 21 15:56:24 2013 -0700 @@ -0,0 +1,37 @@ +/* + * 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_INTERFACE_ALLOCTRACER_HPP +#define SHARE_VM_GC_INTERFACE_ALLOCTRACER_HPP + +#include "memory/allocation.hpp" +#include "runtime/handles.hpp" + +class AllocTracer : AllStatic { + public: + static void send_allocation_outside_tlab_event(KlassHandle klass, size_t alloc_size); + static void send_allocation_in_new_tlab_event(KlassHandle klass, size_t tlab_size, size_t alloc_size); +}; + +#endif /* SHARE_VM_GC_INTERFACE_ALLOCTRACER_HPP */ diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/gc_interface/collectedHeap.cpp --- a/src/share/vm/gc_interface/collectedHeap.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/gc_interface/collectedHeap.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 @@ -24,9 +24,15 @@ #include "precompiled.hpp" #include "classfile/systemDictionary.hpp" +#include "gc_implementation/shared/gcHeapSummary.hpp" +#include "gc_implementation/shared/gcTrace.hpp" +#include "gc_implementation/shared/gcTraceTime.hpp" +#include "gc_implementation/shared/gcWhen.hpp" #include "gc_implementation/shared/vmGCOperations.hpp" +#include "gc_interface/allocTracer.hpp" #include "gc_interface/collectedHeap.hpp" #include "gc_interface/collectedHeap.inline.hpp" +#include "memory/metaspace.hpp" #include "oops/oop.inline.hpp" #include "oops/instanceMirrorKlass.hpp" #include "runtime/init.hpp" @@ -65,11 +71,71 @@ } } +VirtualSpaceSummary CollectedHeap::create_heap_space_summary() { + size_t capacity_in_words = capacity() / HeapWordSize; + + return VirtualSpaceSummary( + reserved_region().start(), reserved_region().start() + capacity_in_words, reserved_region().end()); +} + +GCHeapSummary CollectedHeap::create_heap_summary() { + VirtualSpaceSummary heap_space = create_heap_space_summary(); + return GCHeapSummary(heap_space, used()); +} + +MetaspaceSummary CollectedHeap::create_metaspace_summary() { + const MetaspaceSizes meta_space( + 0, /*MetaspaceAux::capacity_in_bytes(),*/ + 0, /*MetaspaceAux::used_in_bytes(),*/ + MetaspaceAux::reserved_in_bytes()); + const MetaspaceSizes data_space( + 0, /*MetaspaceAux::capacity_in_bytes(Metaspace::NonClassType),*/ + 0, /*MetaspaceAux::used_in_bytes(Metaspace::NonClassType),*/ + MetaspaceAux::reserved_in_bytes(Metaspace::NonClassType)); + const MetaspaceSizes class_space( + 0, /*MetaspaceAux::capacity_in_bytes(Metaspace::ClassType),*/ + 0, /*MetaspaceAux::used_in_bytes(Metaspace::ClassType),*/ + MetaspaceAux::reserved_in_bytes(Metaspace::ClassType)); + + return MetaspaceSummary(meta_space, data_space, class_space); +} + +void CollectedHeap::print_heap_before_gc() { + if (PrintHeapAtGC) { + Universe::print_heap_before_gc(); + } + if (_gc_heap_log != NULL) { + _gc_heap_log->log_heap_before(); + } +} + +void CollectedHeap::print_heap_after_gc() { + if (PrintHeapAtGC) { + Universe::print_heap_after_gc(); + } + if (_gc_heap_log != NULL) { + _gc_heap_log->log_heap_after(); + } +} + +void CollectedHeap::trace_heap(GCWhen::Type when, GCTracer* gc_tracer) { + const GCHeapSummary& heap_summary = create_heap_summary(); + const MetaspaceSummary& metaspace_summary = create_metaspace_summary(); + gc_tracer->report_gc_heap_summary(when, heap_summary, metaspace_summary); +} + +void CollectedHeap::trace_heap_before_gc(GCTracer* gc_tracer) { + trace_heap(GCWhen::BeforeGC, gc_tracer); +} + +void CollectedHeap::trace_heap_after_gc(GCTracer* gc_tracer) { + trace_heap(GCWhen::AfterGC, gc_tracer); +} + // Memory state functions. CollectedHeap::CollectedHeap() : _n_par_threads(0) - { const size_t max_len = size_t(arrayOopDesc::max_array_length(T_INT)); const size_t elements_per_word = HeapWordSize / sizeof(jint); @@ -185,7 +251,7 @@ } #endif -HeapWord* CollectedHeap::allocate_from_tlab_slow(Thread* thread, size_t size) { +HeapWord* CollectedHeap::allocate_from_tlab_slow(KlassHandle klass, Thread* thread, size_t size) { // Retain tlab and allocate object in shared space if // the amount free in the tlab is too large to discard. @@ -209,6 +275,9 @@ if (obj == NULL) { return NULL; } + + AllocTracer::send_allocation_in_new_tlab_event(klass, new_tlab_size * HeapWordSize, size * HeapWordSize); + if (ZeroTLAB) { // ..and clear it. Copy::zero_to_words(obj, new_tlab_size); @@ -458,28 +527,28 @@ } } -void CollectedHeap::pre_full_gc_dump() { +void CollectedHeap::pre_full_gc_dump(GCTimer* timer) { if (HeapDumpBeforeFullGC) { - TraceTime tt("Heap Dump (before full gc): ", PrintGCDetails, false, gclog_or_tty); + GCTraceTime tt("Heap Dump (before full gc): ", PrintGCDetails, false, timer); // We are doing a "major" collection and a heap dump before // major collection has been requested. HeapDumper::dump_heap(); } if (PrintClassHistogramBeforeFullGC) { - TraceTime tt("Class Histogram (before full gc): ", PrintGCDetails, true, gclog_or_tty); - VM_GC_HeapInspection inspector(gclog_or_tty, false /* ! full gc */, false /* ! prologue */); + GCTraceTime tt("Class Histogram (before full gc): ", PrintGCDetails, true, timer); + VM_GC_HeapInspection inspector(gclog_or_tty, false /* ! full gc */); inspector.doit(); } } -void CollectedHeap::post_full_gc_dump() { +void CollectedHeap::post_full_gc_dump(GCTimer* timer) { if (HeapDumpAfterFullGC) { - TraceTime tt("Heap Dump (after full gc): ", PrintGCDetails, false, gclog_or_tty); + GCTraceTime tt("Heap Dump (after full gc): ", PrintGCDetails, false, timer); HeapDumper::dump_heap(); } if (PrintClassHistogramAfterFullGC) { - TraceTime tt("Class Histogram (after full gc): ", PrintGCDetails, true, gclog_or_tty); - VM_GC_HeapInspection inspector(gclog_or_tty, false /* ! full gc */, false /* ! prologue */); + GCTraceTime tt("Class Histogram (after full gc): ", PrintGCDetails, true, timer); + VM_GC_HeapInspection inspector(gclog_or_tty, false /* ! full gc */); inspector.doit(); } } @@ -490,7 +559,7 @@ assert(size >= 0, "int won't convert to size_t"); HeapWord* obj; assert(ScavengeRootsInCode > 0, "must be"); - obj = common_mem_allocate_init(size, CHECK_NULL); + obj = common_mem_allocate_init(real_klass, size, CHECK_NULL); post_allocation_setup_common(klass, obj); assert(Universe::is_bootstrapping() || !((oop)obj)->is_array(), "must not be an array"); diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/gc_interface/collectedHeap.hpp --- a/src/share/vm/gc_interface/collectedHeap.hpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/gc_interface/collectedHeap.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,6 +26,7 @@ #define SHARE_VM_GC_INTERFACE_COLLECTEDHEAP_HPP #include "gc_interface/gcCause.hpp" +#include "gc_implementation/shared/gcWhen.hpp" #include "memory/allocation.hpp" #include "memory/barrierSet.hpp" #include "runtime/handles.hpp" @@ -38,11 +39,16 @@ // class defines the functions that a heap must implement, and contains // infrastructure common to all heaps. +class AdaptiveSizePolicy; class BarrierSet; +class CollectorPolicy; +class GCHeapSummary; +class GCTimer; +class GCTracer; +class MetaspaceSummary; +class Thread; class ThreadClosure; -class AdaptiveSizePolicy; -class Thread; -class CollectorPolicy; +class VirtualSpaceSummary; class GCMessage : public FormatBuffer<1024> { public: @@ -128,16 +134,16 @@ virtual void resize_all_tlabs(); // Allocate from the current thread's TLAB, with broken-out slow path. - inline static HeapWord* allocate_from_tlab(Thread* thread, size_t size); - static HeapWord* allocate_from_tlab_slow(Thread* thread, size_t size); + inline static HeapWord* allocate_from_tlab(KlassHandle klass, Thread* thread, size_t size); + static HeapWord* allocate_from_tlab_slow(KlassHandle klass, Thread* thread, size_t size); // Allocate an uninitialized block of the given size, or returns NULL if // this is impossible. - inline static HeapWord* common_mem_allocate_noinit(size_t size, TRAPS); + inline static HeapWord* common_mem_allocate_noinit(KlassHandle klass, size_t size, TRAPS); // Like allocate_init, but the block returned by a successful allocation // is guaranteed initialized to zeros. - inline static HeapWord* common_mem_allocate_init(size_t size, TRAPS); + inline static HeapWord* common_mem_allocate_init(KlassHandle klass, size_t size, TRAPS); // Helper functions for (VM) allocation. inline static void post_allocation_setup_common(KlassHandle klass, HeapWord* obj); @@ -166,6 +172,8 @@ // Fill with a single object (either an int array or a java.lang.Object). static inline void fill_with_object_impl(HeapWord* start, size_t words, bool zap = true); + virtual void trace_heap(GCWhen::Type when, GCTracer* tracer); + // Verification functions virtual void check_for_bad_heap_word_value(HeapWord* addr, size_t size) PRODUCT_RETURN; @@ -202,8 +210,6 @@ MemRegion reserved_region() const { return _reserved; } address base() const { return (address)reserved_region().start(); } - // Future cleanup here. The following functions should specify bytes or - // heapwords as part of their signature. virtual size_t capacity() const = 0; virtual size_t used() const = 0; @@ -550,8 +556,13 @@ virtual void prepare_for_verify() = 0; // Generate any dumps preceding or following a full gc - void pre_full_gc_dump(); - void post_full_gc_dump(); + void pre_full_gc_dump(GCTimer* timer); + void post_full_gc_dump(GCTimer* timer); + + VirtualSpaceSummary create_heap_space_summary(); + GCHeapSummary create_heap_summary(); + + MetaspaceSummary create_metaspace_summary(); // Print heap information on the given outputStream. virtual void print_on(outputStream* st) const = 0; @@ -560,7 +571,7 @@ print_on(tty); } // Print more detailed heap information on the given - // outputStream. The default behaviour is to call print_on(). It is + // outputStream. The default behavior is to call print_on(). It is // up to each subclass to override it and add any additional output // it needs. virtual void print_extended_on(outputStream* st) const { @@ -589,23 +600,11 @@ // Default implementation does nothing. virtual void print_tracing_info() const = 0; - // If PrintHeapAtGC is set call the appropriate routi - void print_heap_before_gc() { - if (PrintHeapAtGC) { - Universe::print_heap_before_gc(); - } - if (_gc_heap_log != NULL) { - _gc_heap_log->log_heap_before(); - } - } - void print_heap_after_gc() { - if (PrintHeapAtGC) { - Universe::print_heap_after_gc(); - } - if (_gc_heap_log != NULL) { - _gc_heap_log->log_heap_after(); - } - } + void print_heap_before_gc(); + void print_heap_after_gc(); + + void trace_heap_before_gc(GCTracer* gc_tracer); + void trace_heap_after_gc(GCTracer* gc_tracer); // Heap verification virtual void verify(bool silent, VerifyOption option) = 0; @@ -619,7 +618,7 @@ inline bool promotion_should_fail(); // Reset the PromotionFailureALot counters. Should be called at the end of a - // GC in which promotion failure ocurred. + // GC in which promotion failure occurred. inline void reset_promotion_should_fail(volatile size_t* count); inline void reset_promotion_should_fail(); #endif // #ifndef PRODUCT diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/gc_interface/collectedHeap.inline.hpp --- a/src/share/vm/gc_interface/collectedHeap.inline.hpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/gc_interface/collectedHeap.inline.hpp Fri Jun 21 15:56:24 2013 -0700 @@ -25,6 +25,7 @@ #ifndef SHARE_VM_GC_INTERFACE_COLLECTEDHEAP_INLINE_HPP #define SHARE_VM_GC_INTERFACE_COLLECTEDHEAP_INLINE_HPP +#include "gc_interface/allocTracer.hpp" #include "gc_interface/collectedHeap.hpp" #include "memory/threadLocalAllocBuffer.inline.hpp" #include "memory/universe.hpp" @@ -107,7 +108,7 @@ post_allocation_notify(klass, (oop)obj); } -HeapWord* CollectedHeap::common_mem_allocate_noinit(size_t size, TRAPS) { +HeapWord* CollectedHeap::common_mem_allocate_noinit(KlassHandle klass, size_t size, TRAPS) { // Clear unhandled oops for memory allocation. Memory allocation might // not take out a lock if from tlab, so clear here. @@ -120,7 +121,7 @@ HeapWord* result = NULL; if (UseTLAB) { - result = CollectedHeap::allocate_from_tlab(THREAD, size); + result = allocate_from_tlab(klass, THREAD, size); if (result != NULL) { assert(!HAS_PENDING_EXCEPTION, "Unexpected exception, will result in uninitialized storage"); @@ -136,6 +137,9 @@ assert(!HAS_PENDING_EXCEPTION, "Unexpected exception, will result in uninitialized storage"); THREAD->incr_allocated_bytes(size * HeapWordSize); + + AllocTracer::send_allocation_outside_tlab_event(klass, size * HeapWordSize); + return result; } @@ -165,13 +169,13 @@ } } -HeapWord* CollectedHeap::common_mem_allocate_init(size_t size, TRAPS) { - HeapWord* obj = common_mem_allocate_noinit(size, CHECK_NULL); +HeapWord* CollectedHeap::common_mem_allocate_init(KlassHandle klass, size_t size, TRAPS) { + HeapWord* obj = common_mem_allocate_noinit(klass, size, CHECK_NULL); init_obj(obj, size); return obj; } -HeapWord* CollectedHeap::allocate_from_tlab(Thread* thread, size_t size) { +HeapWord* CollectedHeap::allocate_from_tlab(KlassHandle klass, Thread* thread, size_t size) { assert(UseTLAB, "should use UseTLAB"); HeapWord* obj = thread->tlab().allocate(size); @@ -179,7 +183,7 @@ return obj; } // Otherwise... - return allocate_from_tlab_slow(thread, size); + return allocate_from_tlab_slow(klass, thread, size); } void CollectedHeap::init_obj(HeapWord* obj, size_t size) { @@ -194,7 +198,7 @@ debug_only(check_for_valid_allocation_state()); assert(!Universe::heap()->is_gc_active(), "Allocation during gc not allowed"); assert(size >= 0, "int won't convert to size_t"); - HeapWord* obj = common_mem_allocate_init(size, CHECK_NULL); + HeapWord* obj = common_mem_allocate_init(klass, size, CHECK_NULL); post_allocation_setup_obj(klass, obj); NOT_PRODUCT(Universe::heap()->check_for_bad_heap_word_value(obj, size)); return (oop)obj; @@ -207,7 +211,7 @@ debug_only(check_for_valid_allocation_state()); assert(!Universe::heap()->is_gc_active(), "Allocation during gc not allowed"); assert(size >= 0, "int won't convert to size_t"); - HeapWord* obj = common_mem_allocate_init(size, CHECK_NULL); + HeapWord* obj = common_mem_allocate_init(klass, size, CHECK_NULL); post_allocation_setup_array(klass, obj, length); NOT_PRODUCT(Universe::heap()->check_for_bad_heap_word_value(obj, size)); return (oop)obj; @@ -220,7 +224,7 @@ debug_only(check_for_valid_allocation_state()); assert(!Universe::heap()->is_gc_active(), "Allocation during gc not allowed"); assert(size >= 0, "int won't convert to size_t"); - HeapWord* obj = common_mem_allocate_noinit(size, CHECK_NULL); + HeapWord* obj = common_mem_allocate_noinit(klass, size, CHECK_NULL); ((oop)obj)->set_klass_gap(0); post_allocation_setup_array(klass, obj, length); #ifndef PRODUCT diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/gc_interface/gcCause.cpp --- a/src/share/vm/gc_interface/gcCause.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/gc_interface/gcCause.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -72,6 +72,9 @@ case _cms_final_remark: return "CMS Final Remark"; + case _cms_concurrent_mark: + return "CMS Concurrent Mark"; + case _old_generation_expanded_on_last_scavenge: return "Old Generation Expanded On Last Scavenge"; diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/gc_interface/gcCause.hpp --- a/src/share/vm/gc_interface/gcCause.hpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/gc_interface/gcCause.hpp Fri Jun 21 15:56:24 2013 -0700 @@ -60,6 +60,7 @@ _cms_generation_full, _cms_initial_mark, _cms_final_remark, + _cms_concurrent_mark, _old_generation_expanded_on_last_scavenge, _old_generation_too_full_to_scavenge, diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/gc_interface/gcName.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/gc_interface/gcName.hpp Fri Jun 21 15:56:24 2013 -0700 @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2002, 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_INTERFACE_GCNAME_HPP +#define SHARE_VM_GC_INTERFACE_GCNAME_HPP + +#include "utilities/debug.hpp" + +enum GCName { + ParallelOld, + SerialOld, + PSMarkSweep, + ParallelScavenge, + DefNew, + ParNew, + G1New, + ConcurrentMarkSweep, + G1Old, + GCNameEndSentinel +}; + +class GCNameHelper { + public: + static const char* to_string(GCName name) { + switch(name) { + case ParallelOld: return "ParallelOld"; + case SerialOld: return "SerialOld"; + case PSMarkSweep: return "PSMarkSweep"; + case ParallelScavenge: return "ParallelScavenge"; + case DefNew: return "DefNew"; + case ParNew: return "ParNew"; + case G1New: return "G1New"; + case ConcurrentMarkSweep: return "ConcurrentMarkSweep"; + case G1Old: return "G1Old"; + default: ShouldNotReachHere(); return NULL; + } + } +}; + +#endif // SHARE_VM_GC_INTERFACE_GCNAME_HPP diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/interpreter/bytecodeInterpreter.cpp --- a/src/share/vm/interpreter/bytecodeInterpreter.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/interpreter/bytecodeInterpreter.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -468,7 +468,25 @@ #ifdef ASSERT if (istate->_msg != initialize) { - assert(abs(istate->_stack_base - istate->_stack_limit) == (istate->_method->max_stack() + 1), "bad stack limit"); + // We have a problem here if we are running with a pre-hsx24 JDK (for example during bootstrap) + // because in that case, EnableInvokeDynamic is true by default but will be later switched off + // if java_lang_invoke_MethodHandle::compute_offsets() detects that the JDK only has the classes + // for the old JSR292 implementation. + // This leads to a situation where 'istate->_stack_limit' always accounts for + // methodOopDesc::extra_stack_entries() because it is computed in + // CppInterpreterGenerator::generate_compute_interpreter_state() which was generated while + // EnableInvokeDynamic was still true. On the other hand, istate->_method->max_stack() doesn't + // account for extra_stack_entries() anymore because at the time when it is called + // EnableInvokeDynamic was already set to false. + // So we have a second version of the assertion which handles the case where EnableInvokeDynamic was + // switched off because of the wrong classes. + if (EnableInvokeDynamic || FLAG_IS_CMDLINE(EnableInvokeDynamic)) { + assert(abs(istate->_stack_base - istate->_stack_limit) == (istate->_method->max_stack() + 1), "bad stack limit"); + } else { + const int extra_stack_entries = Method::extra_stack_entries_for_indy; + assert(labs(istate->_stack_base - istate->_stack_limit) == (istate->_method->max_stack() + extra_stack_entries + + 1), "bad stack limit"); + } #ifndef SHARK IA32_ONLY(assert(istate->_stack_limit == istate->_thread->last_Java_sp() + 1, "wrong")); #endif // !SHARK diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/memory/allocation.cpp --- a/src/share/vm/memory/allocation.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/memory/allocation.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -60,10 +60,11 @@ void _ValueObj::operator delete [](void* p) { ShouldNotCallThis(); } void* MetaspaceObj::operator new(size_t size, ClassLoaderData* loader_data, - size_t word_size, bool read_only, TRAPS) { + size_t word_size, bool read_only, + MetaspaceObj::Type type, TRAPS) { // Klass has it's own operator new return Metaspace::allocate(loader_data, word_size, read_only, - Metaspace::NonClassType, CHECK_NULL); + type, CHECK_NULL); } bool MetaspaceObj::is_shared() const { diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/memory/allocation.hpp --- a/src/share/vm/memory/allocation.hpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/memory/allocation.hpp Fri Jun 21 15:56:24 2013 -0700 @@ -157,7 +157,8 @@ mtJavaHeap = 0x0C00, // Java heap mtClassShared = 0x0D00, // class data sharing mtTest = 0x0E00, // Test type for verifying NMT - mt_number_of_types = 0x000E, // number of memory types (mtDontTrack + mtTracing = 0x0F00, // memory used for Tracing + mt_number_of_types = 0x000F, // number of memory types (mtDontTrack // is not included as validate type) mtDontTrack = 0x0F00, // memory we do not or cannot track mt_masks = 0x7F00, @@ -268,8 +269,55 @@ bool is_shared() const; void print_address_on(outputStream* st) const; // nonvirtual address printing +#define METASPACE_OBJ_TYPES_DO(f) \ + f(Unknown) \ + f(Class) \ + f(Symbol) \ + f(TypeArrayU1) \ + f(TypeArrayU2) \ + f(TypeArrayU4) \ + f(TypeArrayU8) \ + f(TypeArrayOther) \ + f(Method) \ + f(ConstMethod) \ + f(MethodData) \ + f(ConstantPool) \ + f(ConstantPoolCache) \ + f(Annotation) \ + f(MethodCounters) + +#define METASPACE_OBJ_TYPE_DECLARE(name) name ## Type, +#define METASPACE_OBJ_TYPE_NAME_CASE(name) case name ## Type: return #name; + + enum Type { + // Types are MetaspaceObj::ClassType, MetaspaceObj::SymbolType, etc + METASPACE_OBJ_TYPES_DO(METASPACE_OBJ_TYPE_DECLARE) + _number_of_types + }; + + static const char * type_name(Type type) { + switch(type) { + METASPACE_OBJ_TYPES_DO(METASPACE_OBJ_TYPE_NAME_CASE) + default: + ShouldNotReachHere(); + return NULL; + } + } + + static MetaspaceObj::Type array_type(size_t elem_size) { + switch (elem_size) { + case 1: return TypeArrayU1Type; + case 2: return TypeArrayU2Type; + case 4: return TypeArrayU4Type; + case 8: return TypeArrayU8Type; + default: + return TypeArrayOtherType; + } + } + void* operator new(size_t size, ClassLoaderData* loader_data, - size_t word_size, bool read_only, Thread* thread); + size_t word_size, bool read_only, + Type type, Thread* thread); // can't use TRAPS from this header file. void operator delete(void* p) { ShouldNotCallThis(); } }; diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/memory/defNewGeneration.cpp --- a/src/share/vm/memory/defNewGeneration.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/memory/defNewGeneration.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 @@ -25,6 +25,10 @@ #include "precompiled.hpp" #include "gc_implementation/shared/collectorCounters.hpp" #include "gc_implementation/shared/gcPolicyCounters.hpp" +#include "gc_implementation/shared/gcHeapSummary.hpp" +#include "gc_implementation/shared/gcTimer.hpp" +#include "gc_implementation/shared/gcTraceTime.hpp" +#include "gc_implementation/shared/gcTrace.hpp" #include "gc_implementation/shared/spaceDecorator.hpp" #include "memory/defNewGeneration.inline.hpp" #include "memory/gcLocker.inline.hpp" @@ -223,6 +227,8 @@ _next_gen = NULL; _tenuring_threshold = MaxTenuringThreshold; _pretenure_size_threshold_words = PretenureSizeThreshold >> LogHeapWordSize; + + _gc_timer = new (ResourceObj::C_HEAP, mtGC) STWGCTimer(); } void DefNewGeneration::compute_space_boundaries(uintx minimum_eden_size, @@ -558,12 +564,18 @@ 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()); + DefNewTracer gc_tracer; + gc_tracer.report_gc_start(gch->gc_cause(), _gc_timer->gc_start()); + _next_gen = gch->next_gen(this); assert(_next_gen != NULL, "This must be the youngest gen, and not the only gen"); - // If the next generation is too full to accomodate promotion + // If the next generation is too full to accommodate promotion // from this generation, pass on collection; let the next generation // do it. if (!collection_attempt_is_safe()) { @@ -577,10 +589,12 @@ init_assuming_no_promotion_failure(); - 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(); + gch->trace_heap_before_gc(&gc_tracer); + SpecializationStats::clear(); // These can be shared for all code paths @@ -631,9 +645,12 @@ FastKeepAliveClosure keep_alive(this, &scan_weak_ref); ReferenceProcessor* rp = ref_processor(); rp->setup_policy(clear_all_soft_refs); + const ReferenceProcessorStats& stats = rp->process_discovered_references(&is_alive, &keep_alive, &evacuate_followers, - NULL); - if (!promotion_failed()) { + NULL, _gc_timer); + gc_tracer.report_gc_reference_stats(stats); + + if (!_promotion_failed) { // Swap the survivor spaces. eden()->clear(SpaceDecorator::Mangle); from()->clear(SpaceDecorator::Mangle); @@ -680,6 +697,7 @@ // Inform the next generation that a promotion failure occurred. _next_gen->promotion_failure_occurred(); + gc_tracer.report_promotion_failed(_promotion_failed_info); // Reset the PromotionFailureALot counters. NOT_PRODUCT(Universe::heap()->reset_promotion_should_fail();) @@ -689,11 +707,18 @@ to()->set_concurrent_iteration_safe_limit(to()->top()); SpecializationStats::print(); - // We need to use a monotonically non-deccreasing time in ms + // We need to use a monotonically non-decreasing time in ms // or we will see time-warp warnings and os::javaTimeMillis() // does not guarantee monotonicity. jlong now = os::javaTimeNanos() / NANOSECS_PER_MILLISEC; update_time_of_last_gc(now); + + 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()); } class RemoveForwardPointerClosure: public ObjectClosure { @@ -705,6 +730,7 @@ void DefNewGeneration::init_assuming_no_promotion_failure() { _promotion_failed = false; + _promotion_failed_info.reset(); from()->set_next_compaction_space(NULL); } @@ -726,7 +752,7 @@ } void DefNewGeneration::preserve_mark(oop obj, markOop m) { - assert(promotion_failed() && m->must_be_preserved_for_promotion_failure(obj), + assert(_promotion_failed && m->must_be_preserved_for_promotion_failure(obj), "Oversaving!"); _objs_with_preserved_marks.push(obj); _preserved_marks_of_objs.push(m); @@ -744,6 +770,7 @@ old->size()); } _promotion_failed = true; + _promotion_failed_info.register_copy_failure(old->size()); preserve_mark_if_necessary(old, old->mark()); // forward to self old->forward_to(old); @@ -962,6 +989,10 @@ from()->set_top_for_allocations(); } +void DefNewGeneration::ref_processor_init() { + Generation::ref_processor_init(); +} + void DefNewGeneration::update_counters() { if (UsePerfData) { diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/memory/defNewGeneration.hpp --- a/src/share/vm/memory/defNewGeneration.hpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/memory/defNewGeneration.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 @@ -28,12 +28,14 @@ #include "gc_implementation/shared/ageTable.hpp" #include "gc_implementation/shared/cSpaceCounters.hpp" #include "gc_implementation/shared/generationCounters.hpp" +#include "gc_implementation/shared/copyFailedInfo.hpp" #include "memory/generation.inline.hpp" #include "utilities/stack.hpp" class EdenSpace; class ContiguousSpace; class ScanClosure; +class STWGCTimer; // DefNewGeneration is a young generation containing eden, from- and // to-space. @@ -46,15 +48,17 @@ uint _tenuring_threshold; // Tenuring threshold for next collection. ageTable _age_table; // Size of object to pretenure in words; command line provides bytes - size_t _pretenure_size_threshold_words; + size_t _pretenure_size_threshold_words; ageTable* age_table() { return &_age_table; } + // Initialize state to optimistically assume no promotion failure will // happen. void init_assuming_no_promotion_failure(); // True iff a promotion has failed in the current collection. bool _promotion_failed; bool promotion_failed() { return _promotion_failed; } + PromotionFailedInfo _promotion_failed_info; // Handling promotion failure. A young generation collection // can fail if a live object cannot be copied out of its @@ -132,6 +136,8 @@ ContiguousSpace* _from_space; ContiguousSpace* _to_space; + STWGCTimer* _gc_timer; + enum SomeProtectedConstants { // Generations are GenGrain-aligned and have size that are multiples of // GenGrain. @@ -203,6 +209,8 @@ DefNewGeneration(ReservedSpace rs, size_t initial_byte_size, int level, const char* policy="Copy"); + virtual void ref_processor_init(); + virtual Generation::Name kind() { return Generation::DefNew; } // Accessing spaces diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/memory/genCollectedHeap.cpp --- a/src/share/vm/memory/genCollectedHeap.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/memory/genCollectedHeap.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,6 +28,7 @@ #include "classfile/vmSymbols.hpp" #include "code/icBuffer.hpp" #include "gc_implementation/shared/collectorCounters.hpp" +#include "gc_implementation/shared/gcTraceTime.hpp" #include "gc_implementation/shared/vmGCOperations.hpp" #include "gc_interface/collectedHeap.inline.hpp" #include "memory/filemap.hpp" @@ -388,7 +389,7 @@ const char* gc_cause_prefix = complete ? "Full GC" : "GC"; gclog_or_tty->date_stamp(PrintGC && PrintGCDateStamps); TraceCPUTime tcpu(PrintGCDetails, true, gclog_or_tty); - TraceTime t(GCCauseString(gc_cause_prefix, gc_cause()), PrintGCDetails, false, gclog_or_tty); + GCTraceTime t(GCCauseString(gc_cause_prefix, gc_cause()), PrintGCDetails, false, NULL); gc_prologue(complete); increment_total_collections(complete); @@ -417,10 +418,11 @@ // The full_collections increment was missed above. increment_total_full_collections(); } - pre_full_gc_dump(); // do any pre full gc dumps + pre_full_gc_dump(NULL); // do any pre full gc dumps } // Timer for individual generations. Last argument is false: no CR - TraceTime t1(_gens[i]->short_name(), PrintGCDetails, false, gclog_or_tty); + // FIXME: We should try to start the timing earlier to cover more of the GC pause + GCTraceTime t1(_gens[i]->short_name(), PrintGCDetails, false, NULL); TraceCollectorStats tcs(_gens[i]->counters()); TraceMemoryManagerStats tmms(_gens[i]->kind(),gc_cause()); @@ -534,7 +536,8 @@ complete = complete || (max_level_collected == n_gens() - 1); if (complete) { // We did a "major" collection - post_full_gc_dump(); // do any post full gc dumps + // FIXME: See comment at pre_full_gc_dump call + post_full_gc_dump(NULL); // do any post full gc dumps } if (PrintGCDetails) { diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/memory/genMarkSweep.cpp --- a/src/share/vm/memory/genMarkSweep.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/memory/genMarkSweep.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,10 @@ #include "classfile/vmSymbols.hpp" #include "code/codeCache.hpp" #include "code/icBuffer.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_interface/collectedHeap.inline.hpp" #include "memory/genCollectedHeap.hpp" #include "memory/genMarkSweep.hpp" @@ -65,7 +69,9 @@ _ref_processor = rp; rp->setup_policy(clear_all_softrefs); - TraceTime t1(GCCauseString("Full GC", gch->gc_cause()), PrintGC && !PrintGCDetails, true, gclog_or_tty); + GCTraceTime t1(GCCauseString("Full GC", gch->gc_cause()), PrintGC && !PrintGCDetails, true, NULL); + + gch->trace_heap_before_gc(_gc_tracer); // When collecting the permanent generation Method*s may be moving, // so we either have to flush all bcp data or convert it into bci. @@ -155,6 +161,8 @@ // does not guarantee monotonicity. jlong now = os::javaTimeNanos() / NANOSECS_PER_MILLISEC; gch->update_time_of_last_gc(now); + + gch->trace_heap_after_gc(_gc_tracer); } void GenMarkSweep::allocate_stacks() { @@ -192,7 +200,7 @@ void GenMarkSweep::mark_sweep_phase1(int level, bool clear_all_softrefs) { // Recursively traverse all live objects and mark them - TraceTime tm("phase 1", PrintGC && Verbose, true, gclog_or_tty); + GCTraceTime tm("phase 1", PrintGC && Verbose, true, _gc_timer); trace(" 1"); GenCollectedHeap* gch = GenCollectedHeap::heap(); @@ -219,8 +227,10 @@ // Process reference objects found during marking { ref_processor()->setup_policy(clear_all_softrefs); - ref_processor()->process_discovered_references( - &is_alive, &keep_alive, &follow_stack_closure, NULL); + const ReferenceProcessorStats& stats = + ref_processor()->process_discovered_references( + &is_alive, &keep_alive, &follow_stack_closure, NULL, _gc_timer); + gc_tracer()->report_gc_reference_stats(stats); } // This is the point where the entire marking should have completed. @@ -240,6 +250,8 @@ // Clean up unreferenced symbols in symbol table. SymbolTable::unlink(); + + gc_tracer()->report_object_count_after_gc(&is_alive); } @@ -259,7 +271,7 @@ GenCollectedHeap* gch = GenCollectedHeap::heap(); - TraceTime tm("phase 2", PrintGC && Verbose, true, gclog_or_tty); + GCTraceTime tm("phase 2", PrintGC && Verbose, true, _gc_timer); trace("2"); gch->prepare_for_compaction(); @@ -276,7 +288,7 @@ GenCollectedHeap* gch = GenCollectedHeap::heap(); // Adjust the pointers to reflect the new locations - TraceTime tm("phase 3", PrintGC && Verbose, true, gclog_or_tty); + GCTraceTime tm("phase 3", PrintGC && Verbose, true, _gc_timer); trace("3"); // Need new claim bits for the pointer adjustment tracing. @@ -331,7 +343,7 @@ // to use a higher index (saved from phase2) when verifying perm_gen. GenCollectedHeap* gch = GenCollectedHeap::heap(); - TraceTime tm("phase 4", PrintGC && Verbose, true, gclog_or_tty); + GCTraceTime tm("phase 4", PrintGC && Verbose, true, _gc_timer); trace("4"); GenCompactClosure blk; diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/memory/generation.cpp --- a/src/share/vm/memory/generation.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/memory/generation.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 @@ -23,6 +23,8 @@ */ #include "precompiled.hpp" +#include "gc_implementation/shared/gcTimer.hpp" +#include "gc_implementation/shared/gcTrace.hpp" #include "gc_implementation/shared/spaceDecorator.hpp" #include "gc_interface/collectedHeap.inline.hpp" #include "memory/allocation.inline.hpp" @@ -624,12 +626,26 @@ bool clear_all_soft_refs, size_t size, bool is_tlab) { + GenCollectedHeap* gch = GenCollectedHeap::heap(); + SpecializationStats::clear(); // Temporarily expand the span of our ref processor, so // refs discovery is over the entire heap, not just this generation ReferenceProcessorSpanMutator - x(ref_processor(), GenCollectedHeap::heap()->reserved_region()); + x(ref_processor(), gch->reserved_region()); + + 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()); + GenMarkSweep::invoke_at_safepoint(_level, ref_processor(), clear_all_soft_refs); + + gc_timer->register_gc_end(os::elapsed_counter()); + + gc_tracer->report_gc_end(os::elapsed_counter(), gc_timer->time_partitions()); + SpecializationStats::print(); } diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/memory/heapInspection.cpp --- a/src/share/vm/memory/heapInspection.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/memory/heapInspection.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -95,7 +95,7 @@ } elt = elt->next(); } - elt = new KlassInfoEntry(k, list()); + elt = new (std::nothrow) KlassInfoEntry(k, list()); // We may be out of space to allocate the new entry. if (elt != NULL) { set_list(elt); @@ -127,13 +127,15 @@ _table->lookup(k); } -KlassInfoTable::KlassInfoTable(int size, HeapWord* ref, - bool need_class_stats) { +KlassInfoTable::KlassInfoTable(bool need_class_stats) { + _size_of_instances_in_words = 0; _size = 0; - _ref = ref; - _buckets = NEW_C_HEAP_ARRAY(KlassInfoBucket, size, mtInternal); + _ref = (HeapWord*) Universe::boolArrayKlassObj(); + _buckets = + (KlassInfoBucket*) AllocateHeap(sizeof(KlassInfoBucket) * _num_buckets, + mtInternal, 0, AllocFailStrategy::RETURN_NULL); if (_buckets != NULL) { - _size = size; + _size = _num_buckets; for (int index = 0; index < _size; index++) { _buckets[index].initialize(); } @@ -179,6 +181,7 @@ if (elt != NULL) { elt->set_count(elt->count() + 1); elt->set_words(elt->words() + obj->size()); + _size_of_instances_in_words += obj->size(); return true; } else { return false; @@ -192,14 +195,18 @@ } } +size_t KlassInfoTable::size_of_instances_in_words() const { + return _size_of_instances_in_words; +} + int KlassInfoHisto::sort_helper(KlassInfoEntry** e1, KlassInfoEntry** e2) { return (*e1)->compare(*e1,*e2); } -KlassInfoHisto::KlassInfoHisto(KlassInfoTable* cit, const char* title, int estimatedCount) : +KlassInfoHisto::KlassInfoHisto(KlassInfoTable* cit, const char* title) : _cit(cit), _title(title) { - _elements = new (ResourceObj::C_HEAP, mtInternal) GrowableArray(estimatedCount,true); + _elements = new (ResourceObj::C_HEAP, mtInternal) GrowableArray(_histo_initial_size, true); } KlassInfoHisto::~KlassInfoHisto() { @@ -444,25 +451,37 @@ private: KlassInfoTable* _cit; size_t _missed_count; + BoolObjectClosure* _filter; public: - RecordInstanceClosure(KlassInfoTable* cit) : - _cit(cit), _missed_count(0) {} + RecordInstanceClosure(KlassInfoTable* cit, BoolObjectClosure* filter) : + _cit(cit), _missed_count(0), _filter(filter) {} void do_object(oop obj) { - if (!_cit->record_instance(obj)) { - _missed_count++; + if (should_visit(obj)) { + if (!_cit->record_instance(obj)) { + _missed_count++; + } } } size_t missed_count() { return _missed_count; } + + private: + bool should_visit(oop obj) { + return _filter == NULL || _filter->do_object_b(obj); + } }; -void HeapInspection::heap_inspection(outputStream* st, bool need_prologue) { +size_t HeapInspection::populate_table(KlassInfoTable* cit, BoolObjectClosure *filter) { ResourceMark rm; - // Get some random number for ref (the hash key) - HeapWord* ref = (HeapWord*) Universe::boolArrayKlassObj(); - CollectedHeap* heap = Universe::heap(); - bool is_shared_heap = false; + + RecordInstanceClosure ric(cit, filter); + Universe::heap()->object_iterate(&ric); + return ric.missed_count(); +} + +void HeapInspection::heap_inspection(outputStream* st) { + ResourceMark rm; if (_print_help) { for (int c=0; cobject_iterate(&ric); - - // Report if certain classes are not counted because of - // running out of C-heap for the histogram. - size_t missed_count = ric.missed_count(); + size_t missed_count = populate_table(&cit); if (missed_count != 0) { st->print_cr("WARNING: Ran out of C-heap; undercounted " SIZE_FORMAT " total instances in data below", missed_count); } + // Sort and print klass instance info const char *title = "\n" " num #instances #bytes class name\n" "----------------------------------------------"; - KlassInfoHisto histo(&cit, title, KlassInfoHisto::histo_initial_size); + KlassInfoHisto histo(&cit, title); HistoClosure hc(&histo); + cit.iterate(&hc); + histo.sort(); histo.print_histo_on(st, _print_class_stats, _csv_format, _columns); } else { st->print_cr("WARNING: Ran out of C-heap; histogram not generated"); } st->flush(); - - if (need_prologue && is_shared_heap) { - SharedHeap* sh = (SharedHeap*)heap; - sh->gc_epilogue(false /* !full */); // release all acquired locks, etc. - } } class FindInstanceClosure : public ObjectClosure { diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/memory/heapInspection.hpp --- a/src/share/vm/memory/heapInspection.hpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/memory/heapInspection.hpp Fri Jun 21 15:56:24 2013 -0700 @@ -26,6 +26,7 @@ #define SHARE_VM_MEMORY_HEAPINSPECTION_HPP #include "memory/allocation.inline.hpp" +#include "memory/klassInfoClosure.hpp" #include "oops/oop.inline.hpp" #include "oops/annotations.hpp" #include "utilities/macros.hpp" @@ -203,12 +204,6 @@ const char* name() const; }; -class KlassInfoClosure: public StackObj { - public: - // Called for each KlassInfoEntry. - virtual void do_cinfo(KlassInfoEntry* cie) = 0; -}; - class KlassInfoBucket: public CHeapObj { private: KlassInfoEntry* _list; @@ -224,6 +219,8 @@ class KlassInfoTable: public StackObj { private: int _size; + static const int _num_buckets = 20011; + size_t _size_of_instances_in_words; // An aligned reference address (typically the least // address in the perm gen) used for hashing klass @@ -242,21 +239,19 @@ }; public: - // Table size - enum { - cit_size = 20011 - }; - KlassInfoTable(int size, HeapWord* ref, bool need_class_stats); + KlassInfoTable(bool need_class_stats); ~KlassInfoTable(); bool record_instance(const oop obj); void iterate(KlassInfoClosure* cic); bool allocation_failed() { return _buckets == NULL; } + size_t size_of_instances_in_words() const; friend class KlassInfoHisto; }; class KlassInfoHisto : public StackObj { private: + static const int _histo_initial_size = 1000; KlassInfoTable *_cit; GrowableArray* _elements; GrowableArray* elements() const { return _elements; } @@ -334,11 +329,7 @@ } public: - enum { - histo_initial_size = 1000 - }; - KlassInfoHisto(KlassInfoTable* cit, const char* title, - int estimatedCount); + KlassInfoHisto(KlassInfoTable* cit, const char* title); ~KlassInfoHisto(); void add(KlassInfoEntry* cie); void print_histo_on(outputStream* st, bool print_class_stats, bool csv_format, const char *columns); @@ -347,6 +338,11 @@ #endif // INCLUDE_SERVICES +// These declarations are needed since teh declaration of KlassInfoTable and +// KlassInfoClosure are guarded by #if INLCUDE_SERVICES +class KlassInfoTable; +class KlassInfoClosure; + class HeapInspection : public StackObj { bool _csv_format; // "comma separated values" format for spreadsheet. bool _print_help; @@ -357,8 +353,11 @@ bool print_class_stats, const char *columns) : _csv_format(csv_format), _print_help(print_help), _print_class_stats(print_class_stats), _columns(columns) {} - void heap_inspection(outputStream* st, bool need_prologue) NOT_SERVICES_RETURN; + void heap_inspection(outputStream* st) NOT_SERVICES_RETURN; + size_t populate_table(KlassInfoTable* cit, BoolObjectClosure* filter = NULL) NOT_SERVICES_RETURN; static void find_instances_at_safepoint(Klass* k, GrowableArray* result) NOT_SERVICES_RETURN; + private: + void iterate_over_heap(KlassInfoTable* cit, BoolObjectClosure* filter = NULL); }; #endif // SHARE_VM_MEMORY_HEAPINSPECTION_HPP diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/memory/klassInfoClosure.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/memory/klassInfoClosure.hpp Fri Jun 21 15:56:24 2013 -0700 @@ -0,0 +1,36 @@ +/* + * 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_MEMORY_KLASSINFOCLOSURE_HPP +#define SHARE_VM_MEMORY_KLASSINFOCLOSURE_HPP + +class KlassInfoEntry; + +class KlassInfoClosure : public StackObj { + public: + // Called for each KlassInfoEntry. + virtual void do_cinfo(KlassInfoEntry* cie) = 0; +}; + +#endif // SHARE_VM_MEMORY_KLASSINFOCLOSURE_HPP diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/memory/metaspace.cpp --- a/src/share/vm/memory/metaspace.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/memory/metaspace.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -713,6 +713,23 @@ #ifdef ASSERT void verify_allocated_blocks_words(); #endif + + size_t get_raw_word_size(size_t word_size) { + // If only the dictionary is going to be used (i.e., no + // indexed free list), then there is a minimum size requirement. + // MinChunkSize is a placeholder for the real minimum size JJJ + size_t byte_size = word_size * BytesPerWord; + + size_t byte_size_with_overhead = byte_size + Metablock::overhead(); + + size_t raw_bytes_size = MAX2(byte_size_with_overhead, + Metablock::min_block_byte_size()); + raw_bytes_size = ARENA_ALIGN(raw_bytes_size); + size_t raw_word_size = raw_bytes_size / BytesPerWord; + assert(raw_word_size * BytesPerWord == raw_bytes_size, "Size problem"); + + return raw_word_size; + } }; uint const SpaceManager::_small_chunk_limit = 4; @@ -2320,19 +2337,7 @@ MetaWord* SpaceManager::allocate(size_t word_size) { MutexLockerEx cl(lock(), Mutex::_no_safepoint_check_flag); - // If only the dictionary is going to be used (i.e., no - // indexed free list), then there is a minimum size requirement. - // MinChunkSize is a placeholder for the real minimum size JJJ - size_t byte_size = word_size * BytesPerWord; - - size_t byte_size_with_overhead = byte_size + Metablock::overhead(); - - size_t raw_bytes_size = MAX2(byte_size_with_overhead, - Metablock::min_block_byte_size()); - raw_bytes_size = ARENA_ALIGN(raw_bytes_size); - size_t raw_word_size = raw_bytes_size / BytesPerWord; - assert(raw_word_size * BytesPerWord == raw_bytes_size, "Size problem"); - + size_t raw_word_size = get_raw_word_size(word_size); BlockFreelist* fl = block_freelists(); MetaWord* p = NULL; // Allocation from the dictionary is expensive in the sense that @@ -2896,6 +2901,9 @@ if (class_chunk != NULL) { class_vsm()->add_chunk(class_chunk, true); } + + _alloc_record_head = NULL; + _alloc_record_tail = NULL; } size_t Metaspace::align_word_size_up(size_t word_size) { @@ -3000,12 +3008,14 @@ } Metablock* Metaspace::allocate(ClassLoaderData* loader_data, size_t word_size, - bool read_only, MetadataType mdtype, TRAPS) { + bool read_only, MetaspaceObj::Type type, TRAPS) { if (HAS_PENDING_EXCEPTION) { assert(false, "Should not allocate with exception pending"); return NULL; // caller does a CHECK_NULL too } + MetadataType mdtype = (type == MetaspaceObj::ClassType) ? ClassType : NonClassType; + // SSS: Should we align the allocations and make sure the sizes are aligned. MetaWord* result = NULL; @@ -3015,13 +3025,13 @@ // with the SymbolTable_lock. Dumping is single threaded for now. We'll have // to revisit this for application class data sharing. if (DumpSharedSpaces) { - if (read_only) { - result = loader_data->ro_metaspace()->allocate(word_size, NonClassType); - } else { - result = loader_data->rw_metaspace()->allocate(word_size, NonClassType); - } + assert(type > MetaspaceObj::UnknownType && type < MetaspaceObj::_number_of_types, "sanity"); + Metaspace* space = read_only ? loader_data->ro_metaspace() : loader_data->rw_metaspace(); + result = space->allocate(word_size, NonClassType); if (result == NULL) { report_out_of_shared_space(read_only ? SharedReadOnly : SharedReadWrite); + } else { + space->record_allocation(result, type, space->vsm()->get_raw_word_size(word_size)); } return Metablock::initialize(result, word_size); } @@ -3056,6 +3066,38 @@ return Metablock::initialize(result, word_size); } +void Metaspace::record_allocation(void* ptr, MetaspaceObj::Type type, size_t word_size) { + assert(DumpSharedSpaces, "sanity"); + + AllocRecord *rec = new AllocRecord((address)ptr, type, (int)word_size * HeapWordSize); + if (_alloc_record_head == NULL) { + _alloc_record_head = _alloc_record_tail = rec; + } else { + _alloc_record_tail->_next = rec; + _alloc_record_tail = rec; + } +} + +void Metaspace::iterate(Metaspace::AllocRecordClosure *closure) { + assert(DumpSharedSpaces, "unimplemented for !DumpSharedSpaces"); + + address last_addr = (address)bottom(); + + for (AllocRecord *rec = _alloc_record_head; rec; rec = rec->_next) { + address ptr = rec->_ptr; + if (last_addr < ptr) { + closure->doit(last_addr, MetaspaceObj::UnknownType, ptr - last_addr); + } + closure->doit(ptr, rec->_type, rec->_byte_size); + last_addr = ptr + rec->_byte_size; + } + + address top = ((address)bottom()) + used_bytes_slow(Metaspace::NonClassType); + if (last_addr < top) { + closure->doit(last_addr, MetaspaceObj::UnknownType, top - last_addr); + } +} + void Metaspace::purge() { MutexLockerEx cl(SpaceManager::expand_lock(), Mutex::_no_safepoint_check_flag); diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/memory/metaspace.hpp --- a/src/share/vm/memory/metaspace.hpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/memory/metaspace.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 @@ -127,6 +127,23 @@ static VirtualSpaceList* space_list() { return _space_list; } static VirtualSpaceList* class_space_list() { return _class_space_list; } + // This is used by DumpSharedSpaces only, where only _vsm is used. So we will + // maintain a single list for now. + void record_allocation(void* ptr, MetaspaceObj::Type type, size_t word_size); + + class AllocRecord : public CHeapObj { + public: + AllocRecord(address ptr, MetaspaceObj::Type type, int byte_size) + : _next(NULL), _ptr(ptr), _type(type), _byte_size(byte_size) {} + AllocRecord *_next; + address _ptr; + MetaspaceObj::Type _type; + int _byte_size; + }; + + AllocRecord * _alloc_record_head; + AllocRecord * _alloc_record_tail; + public: Metaspace(Mutex* lock, MetaspaceType type); @@ -148,8 +165,8 @@ size_t used_bytes_slow(MetadataType mdtype) const; size_t capacity_bytes_slow(MetadataType mdtype) const; - static Metablock* allocate(ClassLoaderData* loader_data, size_t size, - bool read_only, MetadataType mdtype, TRAPS); + static Metablock* allocate(ClassLoaderData* loader_data, size_t word_size, + bool read_only, MetaspaceObj::Type type, TRAPS); void deallocate(MetaWord* ptr, size_t byte_size, bool is_class); MetaWord* expand_and_allocate(size_t size, @@ -166,10 +183,20 @@ void print_on(outputStream* st) const; // Debugging support void verify(); + + class AllocRecordClosure : public StackObj { + public: + virtual void doit(address ptr, MetaspaceObj::Type type, int byte_size) = 0; + }; + + void iterate(AllocRecordClosure *closure); }; class MetaspaceAux : AllStatic { + static size_t free_chunks_total(Metaspace::MetadataType mdtype); + static size_t free_chunks_total_in_bytes(Metaspace::MetadataType mdtype); + public: // Statistics for class space and data space in metaspace. // These methods iterate over the classloader data graph @@ -181,10 +208,6 @@ // Iterates over the virtual space list. static size_t reserved_in_bytes(Metaspace::MetadataType mdtype); - static size_t free_chunks_total(Metaspace::MetadataType mdtype); - static size_t free_chunks_total_in_bytes(Metaspace::MetadataType mdtype); - - public: // Running sum of space in all Metachunks that has been // allocated to a Metaspace. This is used instead of // iterating over all the classloaders. One for each diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/memory/metaspaceShared.cpp --- a/src/share/vm/memory/metaspaceShared.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/memory/metaspaceShared.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -243,6 +243,147 @@ bool reading() const { return false; } }; +// This is for dumping detailed statistics for the allocations +// in the shared spaces. +class DumpAllocClosure : public Metaspace::AllocRecordClosure { +public: + + // Here's poor man's enum inheritance +#define SHAREDSPACE_OBJ_TYPES_DO(f) \ + METASPACE_OBJ_TYPES_DO(f) \ + f(SymbolHashentry) \ + f(SymbolBuckets) \ + f(Other) + +#define SHAREDSPACE_OBJ_TYPE_DECLARE(name) name ## Type, +#define SHAREDSPACE_OBJ_TYPE_NAME_CASE(name) case name ## Type: return #name; + + enum Type { + // Types are MetaspaceObj::ClassType, MetaspaceObj::SymbolType, etc + SHAREDSPACE_OBJ_TYPES_DO(SHAREDSPACE_OBJ_TYPE_DECLARE) + _number_of_types + }; + + static const char * type_name(Type type) { + switch(type) { + SHAREDSPACE_OBJ_TYPES_DO(SHAREDSPACE_OBJ_TYPE_NAME_CASE) + default: + ShouldNotReachHere(); + return NULL; + } + } + +public: + enum { + RO = 0, + RW = 1 + }; + + int _counts[2][_number_of_types]; + int _bytes [2][_number_of_types]; + int _which; + + DumpAllocClosure() { + memset(_counts, 0, sizeof(_counts)); + memset(_bytes, 0, sizeof(_bytes)); + }; + + void iterate_metaspace(Metaspace* space, int which) { + assert(which == RO || which == RW, "sanity"); + _which = which; + space->iterate(this); + } + + virtual void doit(address ptr, MetaspaceObj::Type type, int byte_size) { + assert(int(type) >= 0 && type < MetaspaceObj::_number_of_types, "sanity"); + _counts[_which][type] ++; + _bytes [_which][type] += byte_size; + } + + void dump_stats(int ro_all, int rw_all, int md_all, int mc_all); +}; + +void DumpAllocClosure::dump_stats(int ro_all, int rw_all, int md_all, int mc_all) { + rw_all += (md_all + mc_all); // md and mc are all mapped Read/Write + int other_bytes = md_all + mc_all; + + // Calculate size of data that was not allocated by Metaspace::allocate() + int symbol_count = _counts[RO][MetaspaceObj::SymbolType]; + int symhash_bytes = symbol_count * sizeof (HashtableEntry); + int symbuck_count = SymbolTable::the_table()->table_size(); + int symbuck_bytes = symbuck_count * sizeof(HashtableBucket); + + _counts[RW][SymbolHashentryType] = symbol_count; + _bytes [RW][SymbolHashentryType] = symhash_bytes; + other_bytes -= symhash_bytes; + + _counts[RW][SymbolBucketsType] = symbuck_count; + _bytes [RW][SymbolBucketsType] = symbuck_bytes; + other_bytes -= symbuck_bytes; + + // TODO: count things like dictionary, vtable, etc + _bytes[RW][OtherType] = other_bytes; + + // prevent divide-by-zero + if (ro_all < 1) { + ro_all = 1; + } + if (rw_all < 1) { + rw_all = 1; + } + + int all_ro_count = 0; + int all_ro_bytes = 0; + int all_rw_count = 0; + int all_rw_bytes = 0; + + const char *fmt = "%-20s: %8d %10d %5.1f | %8d %10d %5.1f | %8d %10d %5.1f"; + const char *sep = "--------------------+---------------------------+---------------------------+--------------------------"; + const char *hdr = " ro_cnt ro_bytes % | rw_cnt rw_bytes % | all_cnt all_bytes %"; + + tty->print_cr("Detailed metadata info (rw includes md and mc):"); + tty->print_cr(hdr); + tty->print_cr(sep); + for (int type = 0; type < int(_number_of_types); type ++) { + const char *name = type_name((Type)type); + int ro_count = _counts[RO][type]; + int ro_bytes = _bytes [RO][type]; + int rw_count = _counts[RW][type]; + int rw_bytes = _bytes [RW][type]; + int count = ro_count + rw_count; + int bytes = ro_bytes + rw_bytes; + + double ro_perc = 100.0 * double(ro_bytes) / double(ro_all); + double rw_perc = 100.0 * double(rw_bytes) / double(rw_all); + double perc = 100.0 * double(bytes) / double(ro_all + rw_all); + + tty->print_cr(fmt, name, + ro_count, ro_bytes, ro_perc, + rw_count, rw_bytes, rw_perc, + count, bytes, perc); + + all_ro_count += ro_count; + all_ro_bytes += ro_bytes; + all_rw_count += rw_count; + all_rw_bytes += rw_bytes; + } + + int all_count = all_ro_count + all_rw_count; + int all_bytes = all_ro_bytes + all_rw_bytes; + + double all_ro_perc = 100.0 * double(all_ro_bytes) / double(ro_all); + double all_rw_perc = 100.0 * double(all_rw_bytes) / double(rw_all); + double all_perc = 100.0 * double(all_bytes) / double(ro_all + rw_all); + + tty->print_cr(sep); + tty->print_cr(fmt, "Total", + all_ro_count, all_ro_bytes, all_ro_perc, + all_rw_count, all_rw_bytes, all_rw_perc, + all_count, all_bytes, all_perc); + + assert(all_ro_bytes == ro_all, "everything should have been counted"); + assert(all_rw_bytes == rw_all, "everything should have been counted"); +} // Populate the shared space. @@ -454,6 +595,14 @@ mapinfo->close(); memmove(vtbl_list, saved_vtbl, vtbl_list_size * sizeof(void*)); + + if (PrintSharedSpaces) { + DumpAllocClosure dac; + dac.iterate_metaspace(_loader_data->ro_metaspace(), DumpAllocClosure::RO); + dac.iterate_metaspace(_loader_data->rw_metaspace(), DumpAllocClosure::RW); + + dac.dump_stats(int(ro_bytes), int(rw_bytes), int(md_bytes), int(mc_bytes)); + } } static void link_shared_classes(Klass* obj, TRAPS) { diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/memory/oopFactory.hpp --- a/src/share/vm/memory/oopFactory.hpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/memory/oopFactory.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 @@ -27,6 +27,7 @@ #include "classfile/symbolTable.hpp" #include "classfile/systemDictionary.hpp" +#include "memory/referenceType.hpp" #include "memory/universe.hpp" #include "oops/objArrayKlass.hpp" #include "oops/oop.hpp" diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/memory/referenceProcessor.cpp --- a/src/share/vm/memory/referenceProcessor.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/memory/referenceProcessor.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 @@ -25,6 +25,8 @@ #include "precompiled.hpp" #include "classfile/javaClasses.hpp" #include "classfile/systemDictionary.hpp" +#include "gc_implementation/shared/gcTimer.hpp" +#include "gc_implementation/shared/gcTraceTime.hpp" #include "gc_interface/collectedHeap.hpp" #include "gc_interface/collectedHeap.inline.hpp" #include "memory/referencePolicy.hpp" @@ -180,11 +182,20 @@ // past clock value. } -void ReferenceProcessor::process_discovered_references( +size_t ReferenceProcessor::total_count(DiscoveredList lists[]) { + size_t total = 0; + for (uint i = 0; i < _max_num_q; ++i) { + total += lists[i].length(); + } + return total; +} + +ReferenceProcessorStats ReferenceProcessor::process_discovered_references( BoolObjectClosure* is_alive, OopClosure* keep_alive, VoidClosure* complete_gc, - AbstractRefProcTaskExecutor* task_executor) { + AbstractRefProcTaskExecutor* task_executor, + GCTimer* gc_timer) { NOT_PRODUCT(verify_ok_to_handle_reflists()); assert(!enqueuing_is_done(), "If here enqueuing should not be complete"); @@ -202,34 +213,43 @@ _soft_ref_timestamp_clock = java_lang_ref_SoftReference::clock(); bool trace_time = PrintGCDetails && PrintReferenceGC; + // Soft references + size_t soft_count = 0; { - TraceTime tt("SoftReference", trace_time, false, gclog_or_tty); - process_discovered_reflist(_discoveredSoftRefs, _current_soft_ref_policy, true, - is_alive, keep_alive, complete_gc, task_executor); + GCTraceTime tt("SoftReference", trace_time, false, gc_timer); + soft_count = + process_discovered_reflist(_discoveredSoftRefs, _current_soft_ref_policy, true, + is_alive, keep_alive, complete_gc, task_executor); } update_soft_ref_master_clock(); // Weak references + size_t weak_count = 0; { - TraceTime tt("WeakReference", trace_time, false, gclog_or_tty); - process_discovered_reflist(_discoveredWeakRefs, NULL, true, - is_alive, keep_alive, complete_gc, task_executor); + GCTraceTime tt("WeakReference", trace_time, false, gc_timer); + weak_count = + process_discovered_reflist(_discoveredWeakRefs, NULL, true, + is_alive, keep_alive, complete_gc, task_executor); } // Final references + size_t final_count = 0; { - TraceTime tt("FinalReference", trace_time, false, gclog_or_tty); - process_discovered_reflist(_discoveredFinalRefs, NULL, false, - is_alive, keep_alive, complete_gc, task_executor); + GCTraceTime tt("FinalReference", trace_time, false, gc_timer); + final_count = + process_discovered_reflist(_discoveredFinalRefs, NULL, false, + is_alive, keep_alive, complete_gc, task_executor); } // Phantom references + size_t phantom_count = 0; { - TraceTime tt("PhantomReference", trace_time, false, gclog_or_tty); - process_discovered_reflist(_discoveredPhantomRefs, NULL, false, - is_alive, keep_alive, complete_gc, task_executor); + GCTraceTime tt("PhantomReference", trace_time, false, gc_timer); + phantom_count = + process_discovered_reflist(_discoveredPhantomRefs, NULL, false, + is_alive, keep_alive, complete_gc, task_executor); } // Weak global JNI references. It would make more sense (semantically) to @@ -238,12 +258,14 @@ // thus use JNI weak references to circumvent the phantom references and // resurrect a "post-mortem" object. { - TraceTime tt("JNI Weak Reference", trace_time, false, gclog_or_tty); + GCTraceTime tt("JNI Weak Reference", trace_time, false, gc_timer); if (task_executor != NULL) { task_executor->set_single_threaded_mode(); } process_phaseJNI(is_alive, keep_alive, complete_gc); } + + return ReferenceProcessorStats(soft_count, weak_count, final_count, phantom_count); } #ifndef PRODUCT @@ -878,7 +900,7 @@ balance_queues(_discoveredPhantomRefs); } -void +size_t ReferenceProcessor::process_discovered_reflist( DiscoveredList refs_lists[], ReferencePolicy* policy, @@ -901,12 +923,11 @@ must_balance) { balance_queues(refs_lists); } + + size_t total_list_count = total_count(refs_lists); + if (PrintReferenceGC && PrintGCDetails) { - size_t total = 0; - for (uint i = 0; i < _max_num_q; ++i) { - total += refs_lists[i].length(); - } - gclog_or_tty->print(", %u refs", total); + gclog_or_tty->print(", %u refs", total_list_count); } // Phase 1 (soft refs only): @@ -951,6 +972,8 @@ is_alive, keep_alive, complete_gc); } } + + return total_list_count; } void ReferenceProcessor::clean_up_discovered_references() { @@ -1266,14 +1289,15 @@ BoolObjectClosure* is_alive, OopClosure* keep_alive, VoidClosure* complete_gc, - YieldClosure* yield) { + YieldClosure* yield, + GCTimer* gc_timer) { NOT_PRODUCT(verify_ok_to_handle_reflists()); // Soft references { - TraceTime tt("Preclean SoftReferences", PrintGCDetails && PrintReferenceGC, - false, gclog_or_tty); + GCTraceTime tt("Preclean SoftReferences", PrintGCDetails && PrintReferenceGC, + false, gc_timer); for (uint i = 0; i < _max_num_q; i++) { if (yield->should_return()) { return; @@ -1285,8 +1309,8 @@ // Weak references { - TraceTime tt("Preclean WeakReferences", PrintGCDetails && PrintReferenceGC, - false, gclog_or_tty); + GCTraceTime tt("Preclean WeakReferences", PrintGCDetails && PrintReferenceGC, + false, gc_timer); for (uint i = 0; i < _max_num_q; i++) { if (yield->should_return()) { return; @@ -1298,8 +1322,8 @@ // Final references { - TraceTime tt("Preclean FinalReferences", PrintGCDetails && PrintReferenceGC, - false, gclog_or_tty); + GCTraceTime tt("Preclean FinalReferences", PrintGCDetails && PrintReferenceGC, + false, gc_timer); for (uint i = 0; i < _max_num_q; i++) { if (yield->should_return()) { return; @@ -1311,8 +1335,8 @@ // Phantom references { - TraceTime tt("Preclean PhantomReferences", PrintGCDetails && PrintReferenceGC, - false, gclog_or_tty); + GCTraceTime tt("Preclean PhantomReferences", PrintGCDetails && PrintReferenceGC, + false, gc_timer); for (uint i = 0; i < _max_num_q; i++) { if (yield->should_return()) { return; diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/memory/referenceProcessor.hpp --- a/src/share/vm/memory/referenceProcessor.hpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/memory/referenceProcessor.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,8 +26,12 @@ #define SHARE_VM_MEMORY_REFERENCEPROCESSOR_HPP #include "memory/referencePolicy.hpp" +#include "memory/referenceProcessorStats.hpp" +#include "memory/referenceType.hpp" #include "oops/instanceRefKlass.hpp" +class GCTimer; + // ReferenceProcessor class encapsulates the per-"collector" processing // of java.lang.Reference objects for GC. The interface is useful for supporting // a generational abstraction, in particular when there are multiple @@ -204,6 +208,10 @@ }; class ReferenceProcessor : public CHeapObj { + + private: + size_t total_count(DiscoveredList lists[]); + protected: // Compatibility with pre-4965777 JDK's static bool _pending_list_uses_discovered_field; @@ -282,13 +290,13 @@ } // Process references with a certain reachability level. - void process_discovered_reflist(DiscoveredList refs_lists[], - ReferencePolicy* policy, - bool clear_referent, - BoolObjectClosure* is_alive, - OopClosure* keep_alive, - VoidClosure* complete_gc, - AbstractRefProcTaskExecutor* task_executor); + size_t process_discovered_reflist(DiscoveredList refs_lists[], + ReferencePolicy* policy, + bool clear_referent, + BoolObjectClosure* is_alive, + OopClosure* keep_alive, + VoidClosure* complete_gc, + AbstractRefProcTaskExecutor* task_executor); void process_phaseJNI(BoolObjectClosure* is_alive, OopClosure* keep_alive, @@ -349,7 +357,8 @@ void preclean_discovered_references(BoolObjectClosure* is_alive, OopClosure* keep_alive, VoidClosure* complete_gc, - YieldClosure* yield); + YieldClosure* yield, + GCTimer* gc_timer); // Delete entries in the discovered lists that have // either a null referent or are not active. Such @@ -500,12 +509,13 @@ bool discover_reference(oop obj, ReferenceType rt); // Process references found during GC (called by the garbage collector) - void process_discovered_references(BoolObjectClosure* is_alive, - OopClosure* keep_alive, - VoidClosure* complete_gc, - AbstractRefProcTaskExecutor* task_executor); + ReferenceProcessorStats + process_discovered_references(BoolObjectClosure* is_alive, + OopClosure* keep_alive, + VoidClosure* complete_gc, + AbstractRefProcTaskExecutor* task_executor, + GCTimer *gc_timer); - public: // Enqueue references at end of GC (called by the garbage collector) bool enqueue_discovered_references(AbstractRefProcTaskExecutor* task_executor = NULL); diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/memory/referenceProcessorStats.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/memory/referenceProcessorStats.hpp Fri Jun 21 15:56:24 2013 -0700 @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2012 Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_MEMORY_REFERENCEPROCESSORSTATS_HPP +#define SHARE_VM_MEMORY_REFERENCEPROCESSORSTATS_HPP + +#include "utilities/globalDefinitions.hpp" + +class ReferenceProcessor; + +// ReferenceProcessorStats contains statistics about how many references that +// have been traversed when processing references during garbage collection. +class ReferenceProcessorStats { + size_t _soft_count; + size_t _weak_count; + size_t _final_count; + size_t _phantom_count; + + public: + ReferenceProcessorStats() : + _soft_count(0), + _weak_count(0), + _final_count(0), + _phantom_count(0) {} + + ReferenceProcessorStats(size_t soft_count, + size_t weak_count, + size_t final_count, + size_t phantom_count) : + _soft_count(soft_count), + _weak_count(weak_count), + _final_count(final_count), + _phantom_count(phantom_count) + {} + + size_t soft_count() const { + return _soft_count; + } + + size_t weak_count() const { + return _weak_count; + } + + size_t final_count() const { + return _final_count; + } + + size_t phantom_count() const { + return _phantom_count; + } +}; +#endif diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/memory/referenceType.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/memory/referenceType.hpp Fri Jun 21 15:56:24 2013 -0700 @@ -0,0 +1,41 @@ +/* + * 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_MEMORY_REFRERENCETYPE_HPP +#define SHARE_VM_MEMORY_REFRERENCETYPE_HPP + +#include "utilities/debug.hpp" + +// ReferenceType is used to distinguish between java/lang/ref/Reference subclasses + +enum ReferenceType { + REF_NONE, // Regular class + REF_OTHER, // Subclass of java/lang/ref/Reference, but not subclass of one of the classes below + REF_SOFT, // Subclass of java/lang/ref/SoftReference + REF_WEAK, // Subclass of java/lang/ref/WeakReference + REF_FINAL, // Subclass of java/lang/ref/FinalReference + REF_PHANTOM // Subclass of java/lang/ref/PhantomReference +}; + +#endif // SHARE_VM_MEMORY_REFRERENCETYPE_HPP diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/memory/sharedHeap.cpp --- a/src/share/vm/memory/sharedHeap.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/memory/sharedHeap.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -45,6 +45,7 @@ SH_PS_FlatProfiler_oops_do, SH_PS_Management_oops_do, SH_PS_SystemDictionary_oops_do, + SH_PS_ClassLoaderDataGraph_oops_do, SH_PS_jvmti_oops_do, SH_PS_StringTable_oops_do, SH_PS_CodeCache_oops_do, @@ -173,15 +174,21 @@ if (!_process_strong_tasks->is_task_claimed(SH_PS_SystemDictionary_oops_do)) { if (so & SO_AllClasses) { SystemDictionary::oops_do(roots); - ClassLoaderDataGraph::oops_do(roots, klass_closure, !is_scavenging); } else if (so & SO_SystemClasses) { SystemDictionary::always_strong_oops_do(roots); - ClassLoaderDataGraph::always_strong_oops_do(roots, klass_closure, !is_scavenging); } else { fatal("We should always have selected either SO_AllClasses or SO_SystemClasses"); } } + if (!_process_strong_tasks->is_task_claimed(SH_PS_ClassLoaderDataGraph_oops_do)) { + if (so & SO_AllClasses) { + ClassLoaderDataGraph::oops_do(roots, klass_closure, !is_scavenging); + } else if (so & SO_SystemClasses) { + ClassLoaderDataGraph::always_strong_oops_do(roots, klass_closure, !is_scavenging); + } + } + if (!_process_strong_tasks->is_task_claimed(SH_PS_StringTable_oops_do)) { if (so & SO_Strings) { StringTable::oops_do(roots); diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/memory/universe.cpp --- a/src/share/vm/memory/universe.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/memory/universe.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -228,11 +228,8 @@ void Universe::check_alignment(uintx size, uintx alignment, const char* name) { if (size < alignment || size % alignment != 0) { - ResourceMark rm; - stringStream st; - st.print("Size of %s (" UINTX_FORMAT " bytes) must be aligned to " UINTX_FORMAT " bytes", name, size, alignment); - char* error = st.as_string(); - vm_exit_during_initialization(error); + vm_exit_during_initialization( + err_msg("Size of %s (" UINTX_FORMAT " bytes) must be aligned to " UINTX_FORMAT " bytes", name, size, alignment)); } } @@ -822,12 +819,14 @@ // keep the Universe::narrow_oop_base() set in Universe::reserve_heap() Universe::set_narrow_oop_shift(LogMinObjAlignmentInBytes); if (verbose) { - tty->print(", Compressed Oops with base: "PTR_FORMAT, Universe::narrow_oop_base()); + tty->print(", %s: "PTR_FORMAT, + narrow_oop_mode_to_string(HeapBasedNarrowOop), + Universe::narrow_oop_base()); } } else { Universe::set_narrow_oop_base(0); if (verbose) { - tty->print(", zero based Compressed Oops"); + tty->print(", %s", narrow_oop_mode_to_string(ZeroBasedNarrowOop)); } #ifdef _WIN64 if (!Universe::narrow_oop_use_implicit_null_checks()) { @@ -842,7 +841,7 @@ } else { Universe::set_narrow_oop_shift(0); if (verbose) { - tty->print(", 32-bits Oops"); + tty->print(", %s", narrow_oop_mode_to_string(UnscaledNarrowOop)); } } } @@ -916,7 +915,7 @@ } if (!total_rs.is_reserved()) { - vm_exit_during_initialization(err_msg("Could not reserve enough space for object heap %d bytes", total_reserved)); + vm_exit_during_initialization(err_msg("Could not reserve enough space for " SIZE_FORMAT "KB object heap", total_reserved/K)); return total_rs; } @@ -949,6 +948,33 @@ } +const char* Universe::narrow_oop_mode_to_string(Universe::NARROW_OOP_MODE mode) { + switch (mode) { + case UnscaledNarrowOop: + return "32-bits Oops"; + case ZeroBasedNarrowOop: + return "zero based Compressed Oops"; + case HeapBasedNarrowOop: + return "Compressed Oops with base"; + } + + ShouldNotReachHere(); + return ""; +} + + +Universe::NARROW_OOP_MODE Universe::narrow_oop_mode() { + if (narrow_oop_base() != 0) { + return HeapBasedNarrowOop; + } + + if (narrow_oop_shift() != 0) { + return ZeroBasedNarrowOop; + } + + return UnscaledNarrowOop; +} + void universe2_init() { EXCEPTION_MARK; diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/memory/universe.hpp --- a/src/share/vm/memory/universe.hpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/memory/universe.hpp Fri Jun 21 15:56:24 2013 -0700 @@ -253,19 +253,6 @@ return m; } - // Narrow Oop encoding mode: - // 0 - Use 32-bits oops without encoding when - // NarrowOopHeapBaseMin + heap_size < 4Gb - // 1 - Use zero based compressed oops with encoding when - // NarrowOopHeapBaseMin + heap_size < 32Gb - // 2 - Use compressed oops with heap base + encoding. - enum NARROW_OOP_MODE { - UnscaledNarrowOop = 0, - ZeroBasedNarrowOop = 1, - HeapBasedNarrowOop = 2 - }; - static char* preferred_heap_base(size_t heap_size, NARROW_OOP_MODE mode); - static char* preferred_metaspace_base(size_t heap_size, NARROW_OOP_MODE mode); static void set_narrow_oop_base(address base) { assert(UseCompressedOops, "no compressed oops?"); _narrow_oop._base = base; @@ -380,6 +367,21 @@ static CollectedHeap* heap() { return _collectedHeap; } // For UseCompressedOops + // Narrow Oop encoding mode: + // 0 - Use 32-bits oops without encoding when + // NarrowOopHeapBaseMin + heap_size < 4Gb + // 1 - Use zero based compressed oops with encoding when + // NarrowOopHeapBaseMin + heap_size < 32Gb + // 2 - Use compressed oops with heap base + encoding. + enum NARROW_OOP_MODE { + UnscaledNarrowOop = 0, + ZeroBasedNarrowOop = 1, + HeapBasedNarrowOop = 2 + }; + static NARROW_OOP_MODE narrow_oop_mode(); + static const char* narrow_oop_mode_to_string(NARROW_OOP_MODE mode); + static char* preferred_heap_base(size_t heap_size, NARROW_OOP_MODE mode); + static char* preferred_metaspace_base(size_t heap_size, NARROW_OOP_MODE mode); static address narrow_oop_base() { return _narrow_oop._base; } static bool is_narrow_oop_base(void* addr) { return (narrow_oop_base() == (address)addr); } static int narrow_oop_shift() { return _narrow_oop._shift; } diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/oops/annotations.cpp --- a/src/share/vm/oops/annotations.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/oops/annotations.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -33,7 +33,7 @@ // Allocate annotations in metadata area Annotations* Annotations::allocate(ClassLoaderData* loader_data, TRAPS) { - return new (loader_data, size(), true, THREAD) Annotations(); + return new (loader_data, size(), true, MetaspaceObj::AnnotationType, THREAD) Annotations(); } // helper diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/oops/arrayKlass.cpp --- a/src/share/vm/oops/arrayKlass.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/oops/arrayKlass.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -94,7 +94,7 @@ ResourceMark rm(THREAD); k->initialize_supers(super_klass(), CHECK); k->vtable()->initialize_vtable(false, CHECK); - java_lang_Class::create_mirror(k, CHECK); + java_lang_Class::create_mirror(k, Handle(NULL), CHECK); } GrowableArray* ArrayKlass::compute_secondary_supers(int num_extra_slots) { diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/oops/constMethod.cpp --- a/src/share/vm/oops/constMethod.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/oops/constMethod.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -40,7 +40,7 @@ MethodType method_type, TRAPS) { int size = ConstMethod::size(byte_code_size, sizes); - return new (loader_data, size, true, THREAD) ConstMethod( + return new (loader_data, size, true, MetaspaceObj::ConstMethodType, THREAD) ConstMethod( byte_code_size, sizes, method_type, size); } diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/oops/constantPool.cpp --- a/src/share/vm/oops/constantPool.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/oops/constantPool.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -55,7 +55,7 @@ // the resolved_references array, which is recreated at startup time. // But that could be moved to InstanceKlass (although a pain to access from // assembly code). Maybe it could be moved to the cpCache which is RW. - return new (loader_data, size, false, THREAD) ConstantPool(tags); + return new (loader_data, size, false, MetaspaceObj::ConstantPoolType, THREAD) ConstantPool(tags); } ConstantPool::ConstantPool(Array* tags) { @@ -1063,9 +1063,10 @@ int k2 = cp2->invoke_dynamic_name_and_type_ref_index_at(index2); int i1 = invoke_dynamic_bootstrap_specifier_index(index1); int i2 = cp2->invoke_dynamic_bootstrap_specifier_index(index2); - bool match = compare_entry_to(k1, cp2, k2, CHECK_false) && - compare_operand_to(i1, cp2, i2, CHECK_false); - return match; + // separate statements and variables because CHECK_false is used + bool match_entry = compare_entry_to(k1, cp2, k2, CHECK_false); + bool match_operand = compare_operand_to(i1, cp2, i2, CHECK_false); + return (match_entry && match_operand); } break; case JVM_CONSTANT_String: diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/oops/cpCache.cpp --- a/src/share/vm/oops/cpCache.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/oops/cpCache.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -542,7 +542,8 @@ const intStack& invokedynamic_map, TRAPS) { int size = ConstantPoolCache::size(length); - return new (loader_data, size, false, THREAD) ConstantPoolCache(length, index_map, invokedynamic_map); + return new (loader_data, size, false, MetaspaceObj::ConstantPoolCacheType, THREAD) + ConstantPoolCache(length, index_map, invokedynamic_map); } void ConstantPoolCache::initialize(const intArray& inverse_index_map, diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/oops/instanceKlass.cpp --- a/src/share/vm/oops/instanceKlass.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/oops/instanceKlass.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -268,8 +268,6 @@ set_fields(NULL, 0); set_constants(NULL); set_class_loader_data(NULL); - set_protection_domain(NULL); - set_signers(NULL); set_source_file_name(NULL); set_source_debug_extension(NULL, 0); set_array_name(NULL); @@ -279,7 +277,6 @@ set_is_marked_dependent(false); set_init_state(InstanceKlass::allocated); set_init_thread(NULL); - set_init_lock(NULL); set_reference_type(rt); set_oop_map_cache(NULL); set_jni_ids(NULL); @@ -408,12 +405,6 @@ } set_inner_classes(NULL); - // Null out Java heap objects, although these won't be walked to keep - // alive once this InstanceKlass is deallocated. - set_protection_domain(NULL); - set_signers(NULL); - set_init_lock(NULL); - // We should deallocate the Annotations instance MetadataFactory::free_metadata(loader_data, annotations()); set_annotations(NULL); @@ -451,6 +442,24 @@ } } +// JVMTI spec thinks there are signers and protection domain in the +// instanceKlass. These accessors pretend these fields are there. +// The hprof specification also thinks these fields are in InstanceKlass. +oop InstanceKlass::protection_domain() const { + // return the protection_domain from the mirror + return java_lang_Class::protection_domain(java_mirror()); +} + +// To remove these from requires an incompatible change and CCC request. +objArrayOop InstanceKlass::signers() const { + // return the signers from the mirror + return java_lang_Class::signers(java_mirror()); +} + +volatile oop InstanceKlass::init_lock() const { + // return the init lock from the mirror + return java_lang_Class::init_lock(java_mirror()); +} void InstanceKlass::eager_initialize_impl(instanceKlassHandle this_oop) { EXCEPTION_MARK; @@ -1883,16 +1892,6 @@ // Garbage collection -void InstanceKlass::oops_do(OopClosure* cl) { - Klass::oops_do(cl); - - cl->do_oop(adr_protection_domain()); - cl->do_oop(adr_signers()); - cl->do_oop(adr_init_lock()); - - // Don't walk the arrays since they are walked from the ClassLoaderData objects. -} - #ifdef ASSERT template void assert_is_in(T *p) { T heap_oop = oopDesc::load_heap_oop(p); @@ -2241,9 +2240,6 @@ m->remove_unshareable_info(); } - // Need to reinstate when reading back the class. - set_init_lock(NULL); - // do array classes also. array_klasses_do(remove_unshareable_in_class); } @@ -2275,13 +2271,6 @@ ik->itable()->initialize_itable(false, CHECK); } - // 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); - Handle h(THREAD, (oop)r); - ik->set_init_lock(h()); - // restore constant pool resolved references ik->constants()->restore_unshareable_info(CHECK); @@ -2331,10 +2320,15 @@ FreeHeap(jmeths); } - MemberNameTable* mnt = member_names(); - if (mnt != NULL) { - delete mnt; - set_member_names(NULL); + // Deallocate MemberNameTable + { + Mutex* lock_or_null = SafepointSynchronize::is_at_safepoint() ? NULL : MemberNameTable_lock; + MutexLockerEx ml(lock_or_null, Mutex::_no_safepoint_check_flag); + MemberNameTable* mnt = member_names(); + if (mnt != NULL) { + delete mnt; + set_member_names(NULL); + } } int* indices = methods_cached_itable_indices_acquire(); @@ -2765,15 +2759,28 @@ return NULL; } -void InstanceKlass::add_member_name(Handle mem_name) { +void InstanceKlass::add_member_name(int index, Handle mem_name) { jweak mem_name_wref = JNIHandles::make_weak_global(mem_name); MutexLocker ml(MemberNameTable_lock); + assert(0 <= index && index < idnum_allocated_count(), "index is out of bounds"); DEBUG_ONLY(No_Safepoint_Verifier nsv); if (_member_names == NULL) { - _member_names = new (ResourceObj::C_HEAP, mtClass) MemberNameTable(); + _member_names = new (ResourceObj::C_HEAP, mtClass) MemberNameTable(idnum_allocated_count()); } - _member_names->add_member_name(mem_name_wref); + _member_names->add_member_name(index, mem_name_wref); +} + +oop InstanceKlass::get_member_name(int index) { + MutexLocker ml(MemberNameTable_lock); + assert(0 <= index && index < idnum_allocated_count(), "index is out of bounds"); + DEBUG_ONLY(No_Safepoint_Verifier nsv); + + if (_member_names == NULL) { + return NULL; + } + oop mem_name =_member_names->get_member_name(index); + return mem_name; } // ----------------------------------------------------------------------------------------------------- @@ -2836,10 +2843,7 @@ class_loader_data()->print_value_on(st); st->cr(); } - st->print(BULLET"protection domain: "); ((InstanceKlass*)this)->protection_domain()->print_value_on(st); st->cr(); st->print(BULLET"host class: "); host_klass()->print_value_on_maybe_null(st); st->cr(); - st->print(BULLET"signers: "); signers()->print_value_on(st); st->cr(); - st->print(BULLET"init_lock: "); ((oop)_init_lock)->print_value_on(st); st->cr(); if (source_file_name() != NULL) { st->print(BULLET"source file: "); source_file_name()->print_value_on(st); @@ -3040,7 +3044,6 @@ n += (sz->_method_ordering_bytes = sz->count_array(method_ordering())); n += (sz->_local_interfaces_bytes = sz->count_array(local_interfaces())); n += (sz->_transitive_interfaces_bytes = sz->count_array(transitive_interfaces())); - n += (sz->_signers_bytes = sz->count_array(signers())); n += (sz->_fields_bytes = sz->count_array(fields())); n += (sz->_inner_classes_bytes = sz->count_array(inner_classes())); sz->_ro_bytes += n; @@ -3206,17 +3209,11 @@ guarantee(constants()->is_metadata(), "should be in metaspace"); guarantee(constants()->is_constantPool(), "should be constant pool"); } - if (protection_domain() != NULL) { - guarantee(protection_domain()->is_oop(), "should be oop"); - } const Klass* host = host_klass(); if (host != NULL) { guarantee(host->is_metadata(), "should be in metaspace"); guarantee(host->is_klass(), "should be klass"); } - if (signers() != NULL) { - guarantee(signers()->is_objArray(), "should be obj array"); - } } void InstanceKlass::oop_verify_on(oop obj, outputStream* st) { diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/oops/instanceKlass.hpp --- a/src/share/vm/oops/instanceKlass.hpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/oops/instanceKlass.hpp Fri Jun 21 15:56:24 2013 -0700 @@ -26,6 +26,7 @@ #define SHARE_VM_OOPS_INSTANCEKLASS_HPP #include "classfile/classLoaderData.hpp" +#include "memory/referenceType.hpp" #include "oops/annotations.hpp" #include "oops/constMethod.hpp" #include "oops/fieldInfo.hpp" @@ -37,6 +38,7 @@ #include "utilities/accessFlags.hpp" #include "utilities/bitMap.inline.hpp" #include "utilities/macros.hpp" +#include "trace/traceMacros.hpp" // An InstanceKlass is the VM level representation of a Java class. // It contains all information needed for at class at execution runtime. @@ -58,8 +60,6 @@ // [fields ] // [constants ] // [class loader ] -// [protection domain ] -// [signers ] // [source file name ] // [inner classes ] // [static field size ] @@ -180,16 +180,6 @@ static volatile int _total_instanceKlass_count; protected: - // Protection domain. - oop _protection_domain; - // Class signers. - objArrayOop _signers; - // Lock for (1) initialization; (2) access to the ConstantPool of this class. - // Must be one per class and it has to be a VM internal object so java code - // cannot lock it (like the mirror). - // It has to be an object not a Mutex because it's held through java calls. - volatile oop _init_lock; - // Annotations for this class Annotations* _annotations; // Array classes holding elements of this class. @@ -527,8 +517,10 @@ void set_constants(ConstantPool* c) { _constants = c; } // protection domain - oop protection_domain() { return _protection_domain; } - void set_protection_domain(oop pd) { klass_oop_store(&_protection_domain, pd); } + oop protection_domain() const; + + // signers + objArrayOop signers() const; // host class Klass* host_klass() const { @@ -575,10 +567,6 @@ } } - // signers - objArrayOop signers() const { return _signers; } - void set_signers(objArrayOop s) { klass_oop_store((oop*)&_signers, s); } - // source file name Symbol* source_file_name() const { return _source_file_name; } void set_source_file_name(Symbol* n); @@ -912,8 +900,6 @@ Method* method_at_itable(Klass* holder, int index, TRAPS); // Garbage collection - virtual void oops_do(OopClosure* cl); - void oop_follow_contents(oop obj); int oop_adjust_pointers(oop obj); @@ -999,14 +985,12 @@ // Lock during initialization public: - volatile oop init_lock() const {return _init_lock; } + // Lock for (1) initialization; (2) access to the ConstantPool of this class. + // Must be one per class and it has to be a VM internal object so java code + // cannot lock it (like the mirror). + // It has to be an object not a Mutex because it's held through java calls. + volatile oop init_lock() const; private: - void set_init_lock(oop value) { klass_oop_store(&_init_lock, value); } - - // Offsets for memory management - oop* adr_protection_domain() const { return (oop*)&this->_protection_domain;} - oop* adr_signers() const { return (oop*)&this->_signers;} - oop* adr_init_lock() const { return (oop*)&this->_init_lock;} // Static methods that are used to implement member methods where an exposed this pointer // is needed due to possible GCs @@ -1040,7 +1024,8 @@ // JSR-292 support MemberNameTable* member_names() { return _member_names; } void set_member_names(MemberNameTable* member_names) { _member_names = member_names; } - void add_member_name(Handle member_name); + void add_member_name(int index, Handle member_name); + oop get_member_name(int index); public: // JVMTI support diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/oops/klass.cpp --- a/src/share/vm/oops/klass.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/oops/klass.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -37,6 +37,7 @@ #include "oops/klass.inline.hpp" #include "oops/oop.inline2.hpp" #include "runtime/atomic.hpp" +#include "trace/traceMacros.hpp" #include "utilities/stack.hpp" #include "utilities/macros.hpp" #if INCLUDE_ALL_GCS @@ -140,7 +141,7 @@ void* Klass::operator new(size_t size, ClassLoaderData* loader_data, size_t word_size, TRAPS) { return Metaspace::allocate(loader_data, word_size, /*read_only*/false, - Metaspace::ClassType, CHECK_NULL); + MetaspaceObj::ClassType, CHECK_NULL); } Klass::Klass() { @@ -168,7 +169,7 @@ set_next_sibling(NULL); set_next_link(NULL); set_alloc_count(0); - TRACE_SET_KLASS_TRACE_ID(this, 0); + TRACE_INIT_ID(this); set_prototype_header(markOopDesc::prototype()); set_biased_lock_revocation_count(0); @@ -511,8 +512,9 @@ // (same order as class file parsing) loader_data->add_class(this); - // Recreate the class mirror - java_lang_Class::create_mirror(this, CHECK); + // Recreate the class mirror. The protection_domain is always null for + // boot loader, for now. + java_lang_Class::create_mirror(this, Handle(NULL), CHECK); } Klass* Klass::array_klass_or_null(int rank) { diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/oops/klass.hpp --- a/src/share/vm/oops/klass.hpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/oops/klass.hpp Fri Jun 21 15:56:24 2013 -0700 @@ -445,7 +445,7 @@ Klass* array_klass_or_null(int rank); Klass* array_klass_or_null(); - virtual oop protection_domain() { return NULL; } + virtual oop protection_domain() const = 0; oop class_loader() const; diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/oops/method.cpp --- a/src/share/vm/oops/method.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/oops/method.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -74,7 +74,7 @@ int size = Method::size(access_flags.is_native()); - return new (loader_data, size, false, THREAD) Method(cm, access_flags, size); + return new (loader_data, size, false, MetaspaceObj::MethodType, THREAD) Method(cm, access_flags, size); } Method::Method(ConstMethod* xconst, AccessFlags access_flags, int size) { diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/oops/method.hpp --- a/src/share/vm/oops/method.hpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/oops/method.hpp Fri Jun 21 15:56:24 2013 -0700 @@ -671,13 +671,15 @@ Symbol* signature, //anything at all TRAPS); static Klass* check_non_bcp_klass(Klass* klass); - // these operate only on invoke methods: + + // How many extra stack entries for invokedynamic when it's enabled + static const int extra_stack_entries_for_jsr292 = 1; + + // this operates only on invoke methods: // presize interpreter frames for extra interpreter stack entries, if needed - // method handles want to be able to push a few extra values (e.g., a bound receiver), and - // invokedynamic sometimes needs to push a bootstrap method, call site, and arglist, - // all without checking for a stack overflow - static int extra_stack_entries() { return EnableInvokeDynamic ? 2 : 0; } - static int extra_stack_words(); // = extra_stack_entries() * Interpreter::stackElementSize() + // Account for the extra appendix argument for invokehandle/invokedynamic + static int extra_stack_entries() { return EnableInvokeDynamic ? extra_stack_entries_for_jsr292 : 0; } + static int extra_stack_words(); // = extra_stack_entries() * Interpreter::stackElementSize // RedefineClasses() support: bool is_old() const { return access_flags().is_old(); } diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/oops/methodCounters.cpp --- a/src/share/vm/oops/methodCounters.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/oops/methodCounters.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -26,7 +26,7 @@ #include "runtime/thread.inline.hpp" MethodCounters* MethodCounters::allocate(ClassLoaderData* loader_data, TRAPS) { - return new(loader_data, size(), false, THREAD) MethodCounters(); + return new(loader_data, size(), false, MetaspaceObj::MethodCountersType, THREAD) MethodCounters(); } void MethodCounters::clear_counters() { diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/oops/methodData.cpp --- a/src/share/vm/oops/methodData.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/oops/methodData.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -388,7 +388,8 @@ MethodData* MethodData::allocate(ClassLoaderData* loader_data, methodHandle method, TRAPS) { int size = MethodData::compute_allocation_size_in_words(method); - return new (loader_data, size, false, THREAD) MethodData(method(), size, CHECK_NULL); + return new (loader_data, size, false, MetaspaceObj::MethodDataType, THREAD) + MethodData(method(), size, CHECK_NULL); } int MethodData::bytecode_cell_count(Bytecodes::Code code) { diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/oops/objArrayKlass.hpp --- a/src/share/vm/oops/objArrayKlass.hpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/oops/objArrayKlass.hpp Fri Jun 21 15:56:24 2013 -0700 @@ -75,7 +75,7 @@ void copy_array(arrayOop s, int src_pos, arrayOop d, int dst_pos, int length, TRAPS); // Compute protection domain - oop protection_domain() { return bottom_klass()->protection_domain(); } + oop protection_domain() const { return bottom_klass()->protection_domain(); } private: // Either oop or narrowOop depending on UseCompressedOops. diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/oops/symbol.cpp --- a/src/share/vm/oops/symbol.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/oops/symbol.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -55,7 +55,7 @@ address res; int alloc_size = size(len)*HeapWordSize; res = (address) Metaspace::allocate(loader_data, size(len), true, - Metaspace::NonClassType, CHECK_NULL); + MetaspaceObj::SymbolType, CHECK_NULL); return res; } diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/oops/typeArrayKlass.hpp --- a/src/share/vm/oops/typeArrayKlass.hpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/oops/typeArrayKlass.hpp Fri Jun 21 15:56:24 2013 -0700 @@ -67,6 +67,8 @@ typeArrayOop allocate(int length, TRAPS) { return allocate_common(length, true, THREAD); } oop multi_allocate(int rank, jint* sizes, TRAPS); + oop protection_domain() const { return NULL; } + // Copying void copy_array(arrayOop s, int src_pos, arrayOop d, int dst_pos, int length, TRAPS); diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/opto/compile.cpp --- a/src/share/vm/opto/compile.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/opto/compile.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 @@ -63,6 +63,7 @@ #include "runtime/signature.hpp" #include "runtime/stubRoutines.hpp" #include "runtime/timer.hpp" +#include "trace/tracing.hpp" #include "utilities/copy.hpp" #ifdef TARGET_ARCH_MODEL_x86_32 # include "adfiles/ad_x86_32.hpp" @@ -789,7 +790,7 @@ if (failing()) return; - print_method("Before RemoveUseless", 3); + print_method(PHASE_BEFORE_REMOVEUSELESS, 3); // Remove clutter produced by parsing. if (!failing()) { @@ -1804,9 +1805,9 @@ { ResourceMark rm; - print_method("Before StringOpts", 3); + print_method(PHASE_BEFORE_STRINGOPTS, 3); PhaseStringOpts pso(initial_gvn(), for_igvn()); - print_method("After StringOpts", 3); + print_method(PHASE_AFTER_STRINGOPTS, 3); } // now inline anything that we skipped the first time around @@ -1961,7 +1962,7 @@ NOT_PRODUCT( verify_graph_edges(); ) - print_method("After Parsing"); + print_method(PHASE_AFTER_PARSING); { // Iterative Global Value Numbering, including ideal transforms @@ -1972,7 +1973,7 @@ igvn.optimize(); } - print_method("Iter GVN 1", 2); + print_method(PHASE_ITER_GVN1, 2); if (failing()) return; @@ -1981,7 +1982,7 @@ inline_incrementally(igvn); } - print_method("Incremental Inline", 2); + print_method(PHASE_INCREMENTAL_INLINE, 2); if (failing()) return; @@ -1990,7 +1991,7 @@ // Inline valueOf() methods now. inline_boxing_calls(igvn); - print_method("Incremental Boxing Inline", 2); + print_method(PHASE_INCREMENTAL_BOXING_INLINE, 2); if (failing()) return; } @@ -2005,7 +2006,7 @@ // Cleanup graph (remove dead nodes). TracePhase t2("idealLoop", &_t_idealLoop, true); PhaseIdealLoop ideal_loop( igvn, false, true ); - if (major_progress()) print_method("PhaseIdealLoop before EA", 2); + if (major_progress()) print_method(PHASE_PHASEIDEAL_BEFORE_EA, 2); if (failing()) return; } ConnectionGraph::do_analysis(this, &igvn); @@ -2014,7 +2015,7 @@ // Optimize out fields loads from scalar replaceable allocations. igvn.optimize(); - print_method("Iter GVN after EA", 2); + print_method(PHASE_ITER_GVN_AFTER_EA, 2); if (failing()) return; @@ -2025,7 +2026,7 @@ igvn.set_delay_transform(false); igvn.optimize(); - print_method("Iter GVN after eliminating allocations and locks", 2); + print_method(PHASE_ITER_GVN_AFTER_ELIMINATION, 2); if (failing()) return; } @@ -2041,7 +2042,7 @@ TracePhase t2("idealLoop", &_t_idealLoop, true); PhaseIdealLoop ideal_loop( igvn, true ); loop_opts_cnt--; - if (major_progress()) print_method("PhaseIdealLoop 1", 2); + if (major_progress()) print_method(PHASE_PHASEIDEALLOOP1, 2); if (failing()) return; } // Loop opts pass if partial peeling occurred in previous pass @@ -2049,7 +2050,7 @@ TracePhase t3("idealLoop", &_t_idealLoop, true); PhaseIdealLoop ideal_loop( igvn, false ); loop_opts_cnt--; - if (major_progress()) print_method("PhaseIdealLoop 2", 2); + if (major_progress()) print_method(PHASE_PHASEIDEALLOOP2, 2); if (failing()) return; } // Loop opts pass for loop-unrolling before CCP @@ -2057,7 +2058,7 @@ TracePhase t4("idealLoop", &_t_idealLoop, true); PhaseIdealLoop ideal_loop( igvn, false ); loop_opts_cnt--; - if (major_progress()) print_method("PhaseIdealLoop 3", 2); + if (major_progress()) print_method(PHASE_PHASEIDEALLOOP3, 2); } if (!failing()) { // Verify that last round of loop opts produced a valid graph @@ -2074,7 +2075,7 @@ TracePhase t2("ccp", &_t_ccp, true); ccp.do_transform(); } - print_method("PhaseCPP 1", 2); + print_method(PHASE_CPP1, 2); assert( true, "Break here to ccp.dump_old2new_map()"); @@ -2085,7 +2086,7 @@ igvn.optimize(); } - print_method("Iter GVN 2", 2); + print_method(PHASE_ITER_GVN2, 2); if (failing()) return; @@ -2098,7 +2099,7 @@ assert( cnt++ < 40, "infinite cycle in loop optimization" ); PhaseIdealLoop ideal_loop( igvn, true); loop_opts_cnt--; - if (major_progress()) print_method("PhaseIdealLoop iterations", 2); + if (major_progress()) print_method(PHASE_PHASEIDEALLOOP_ITERATIONS, 2); if (failing()) return; } } @@ -2131,7 +2132,7 @@ } } - print_method("Optimize finished", 2); + print_method(PHASE_OPTIMIZE_FINISHED, 2); } @@ -2179,7 +2180,7 @@ cfg.GlobalCodeMotion(m,unique(),proj_list); if (failing()) return; - print_method("Global code motion", 2); + print_method(PHASE_GLOBAL_CODE_MOTION, 2); NOT_PRODUCT( verify_graph_edges(); ) @@ -2232,7 +2233,7 @@ Output(); } - print_method("Final Code"); + print_method(PHASE_FINAL_CODE); // He's dead, Jim. _cfg = (PhaseCFG*)0xdeadbeef; @@ -3319,8 +3320,16 @@ // Record the first failure reason. _failure_reason = reason; } + + EventCompilerFailure event; + if (event.should_commit()) { + event.set_compileID(Compile::compile_id()); + event.set_failure(reason); + event.commit(); + } + if (!C->failure_reason_is(C2Compiler::retry_no_subsuming_loads())) { - C->print_method(_failure_reason); + C->print_method(PHASE_FAILURE); } _root = NULL; // flush the graph, too } diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/opto/compile.hpp --- a/src/share/vm/opto/compile.hpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/opto/compile.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 @@ -36,10 +36,12 @@ #include "libadt/vectset.hpp" #include "memory/resourceArea.hpp" #include "opto/idealGraphPrinter.hpp" +#include "opto/phasetype.hpp" #include "opto/phase.hpp" #include "opto/regmask.hpp" #include "runtime/deoptimization.hpp" #include "runtime/vmThread.hpp" +#include "trace/tracing.hpp" class Block; class Bundle; @@ -322,6 +324,7 @@ IdealGraphPrinter* _printer; #endif + // Node management uint _unique; // Counter for unique Node indices VectorSet _dead_node_list; // Set of dead nodes @@ -573,17 +576,43 @@ bool has_method_handle_invokes() const { return _has_method_handle_invokes; } void set_has_method_handle_invokes(bool z) { _has_method_handle_invokes = z; } + jlong _latest_stage_start_counter; + void begin_method() { #ifndef PRODUCT if (_printer) _printer->begin_method(this); #endif + C->_latest_stage_start_counter = os::elapsed_counter(); } - void print_method(const char * name, int level = 1) { + + void print_method(CompilerPhaseType cpt, int level = 1) { + EventCompilerPhase event(UNTIMED); + if (event.should_commit()) { + event.set_starttime(C->_latest_stage_start_counter); + event.set_endtime(os::elapsed_counter()); + event.set_phase((u1) cpt); + event.set_compileID(C->_compile_id); + event.set_phaseLevel(level); + event.commit(); + } + + #ifndef PRODUCT - if (_printer) _printer->print_method(this, name, level); + if (_printer) _printer->print_method(this, CompilerPhaseTypeHelper::to_string(cpt), level); #endif + C->_latest_stage_start_counter = os::elapsed_counter(); } - void end_method() { + + void end_method(int level = 1) { + EventCompilerPhase event(UNTIMED); + if (event.should_commit()) { + event.set_starttime(C->_latest_stage_start_counter); + event.set_endtime(os::elapsed_counter()); + event.set_phase((u1) PHASE_END); + event.set_compileID(C->_compile_id); + event.set_phaseLevel(level); + event.commit(); + } #ifndef PRODUCT if (_printer) _printer->end_method(); #endif diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/opto/escape.cpp --- a/src/share/vm/opto/escape.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/opto/escape.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 @@ -277,7 +277,7 @@ // scalar replaceable objects. split_unique_types(alloc_worklist); if (C->failing()) return false; - C->print_method("After Escape Analysis", 2); + C->print_method(PHASE_AFTER_EA, 2); #ifdef ASSERT } else if (Verbose && (PrintEscapeAnalysis || PrintEliminateAllocations)) { @@ -2202,7 +2202,7 @@ int opcode = uncast_base->Opcode(); assert(opcode == Op_ConP || opcode == Op_ThreadLocal || opcode == Op_CastX2P || uncast_base->is_DecodeNarrowPtr() || - (uncast_base->is_Mem() && uncast_base->bottom_type() == TypeRawPtr::NOTNULL) || + (uncast_base->is_Mem() && (uncast_base->bottom_type()->isa_rawptr() != NULL)) || (uncast_base->is_Proj() && uncast_base->in(0)->is_Allocate()), "sanity"); } return base; diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/opto/library_call.cpp --- a/src/share/vm/opto/library_call.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/opto/library_call.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 @@ -38,6 +38,7 @@ #include "opto/subnode.hpp" #include "prims/nativeLookup.hpp" #include "runtime/sharedRuntime.hpp" +#include "trace/traceMacros.hpp" class LibraryIntrinsic : public InlineCallGenerator { // Extend the set of intrinsics known to the runtime: diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/opto/loopnode.cpp --- a/src/share/vm/opto/loopnode.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/opto/loopnode.cpp 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 @@ -440,7 +440,7 @@ // ---- SUCCESS! Found A Trip-Counted Loop! ----- // assert(x->Opcode() == Op_Loop, "regular loops only"); - C->print_method("Before CountedLoop", 3); + C->print_method(PHASE_BEFORE_CLOOPS, 3); Node *hook = new (C) Node(6); @@ -791,7 +791,7 @@ } #endif - C->print_method("After CountedLoop", 3); + C->print_method(PHASE_AFTER_CLOOPS, 3); return true; } @@ -2164,7 +2164,7 @@ // Split shared headers and insert loop landing pads. // Do not bother doing this on the Root loop of course. if( !_verify_me && !_verify_only && _ltree_root->_child ) { - C->print_method("Before beautify loops", 3); + C->print_method(PHASE_BEFORE_BEAUTIFY_LOOPS, 3); if( _ltree_root->_child->beautify_loops( this ) ) { // Re-build loop tree! _ltree_root->_child = NULL; @@ -2178,7 +2178,7 @@ // Reset loop nesting depth _ltree_root->set_nest( 0 ); - C->print_method("After beautify loops", 3); + C->print_method(PHASE_AFTER_BEAUTIFY_LOOPS, 3); } } diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/opto/matcher.cpp --- a/src/share/vm/opto/matcher.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/opto/matcher.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 @@ -320,7 +320,7 @@ find_shared( C->root() ); find_shared( C->top() ); - C->print_method("Before Matching"); + C->print_method(PHASE_BEFORE_MATCHING); // Create new ideal node ConP #NULL even if it does exist in old space // to avoid false sharing if the corresponding mach node is not used. @@ -1285,16 +1285,6 @@ mcall->_argsize = out_arg_limit_per_call - begin_out_arg_area; } - if (is_method_handle_invoke) { - // Kill some extra stack space in case method handles want to do - // a little in-place argument insertion. - // FIXME: Is this still necessary? - int regs_per_word = NOT_LP64(1) LP64_ONLY(2); // %%% make a global const! - out_arg_limit_per_call += Method::extra_stack_entries() * regs_per_word; - // Do not update mcall->_argsize because (a) the extra space is not - // pushed as arguments and (b) _argsize is dead (not used anywhere). - } - // Compute the max stack slot killed by any call. These will not be // available for debug info, and will be used to adjust FIRST_STACK_mask // after all call sites have been visited. @@ -1861,7 +1851,7 @@ for( uint i=0; kid != NULL && i<2; kid = s->_kids[1], i++ ) { // binary tree int newrule; - if( i == 0 ) + if( i == 0) newrule = kid->_rule[_leftOp[rule]]; else newrule = kid->_rule[_rightOp[rule]]; diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/opto/phasetype.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/opto/phasetype.hpp Fri Jun 21 15:56:24 2013 -0700 @@ -0,0 +1,98 @@ +/* + * 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_OPTO_PHASETYPE_HPP +#define SHARE_VM_OPTO_PHASETYPE_HPP + +enum CompilerPhaseType { + PHASE_BEFORE_STRINGOPTS, + PHASE_AFTER_STRINGOPTS, + PHASE_BEFORE_REMOVEUSELESS, + PHASE_AFTER_PARSING, + PHASE_ITER_GVN1, + PHASE_PHASEIDEAL_BEFORE_EA, + PHASE_ITER_GVN_AFTER_EA, + PHASE_ITER_GVN_AFTER_ELIMINATION, + PHASE_PHASEIDEALLOOP1, + PHASE_PHASEIDEALLOOP2, + PHASE_PHASEIDEALLOOP3, + PHASE_CPP1, + PHASE_ITER_GVN2, + PHASE_PHASEIDEALLOOP_ITERATIONS, + PHASE_OPTIMIZE_FINISHED, + PHASE_GLOBAL_CODE_MOTION, + PHASE_FINAL_CODE, + PHASE_AFTER_EA, + PHASE_BEFORE_CLOOPS, + PHASE_AFTER_CLOOPS, + PHASE_BEFORE_BEAUTIFY_LOOPS, + PHASE_AFTER_BEAUTIFY_LOOPS, + PHASE_BEFORE_MATCHING, + PHASE_INCREMENTAL_INLINE, + PHASE_INCREMENTAL_BOXING_INLINE, + PHASE_END, + PHASE_FAILURE, + + PHASE_NUM_TYPES +}; + +class CompilerPhaseTypeHelper { + public: + static const char* to_string(CompilerPhaseType cpt) { + switch (cpt) { + case PHASE_BEFORE_STRINGOPTS: return "Before StringOpts"; + case PHASE_AFTER_STRINGOPTS: return "After StringOpts"; + case PHASE_BEFORE_REMOVEUSELESS: return "Before RemoveUseless"; + case PHASE_AFTER_PARSING: return "After Parsing"; + case PHASE_ITER_GVN1: return "Iter GVN 1"; + case PHASE_PHASEIDEAL_BEFORE_EA: return "PhaseIdealLoop before EA"; + case PHASE_ITER_GVN_AFTER_EA: return "Iter GVN after EA"; + case PHASE_ITER_GVN_AFTER_ELIMINATION: return "Iter GVN after eliminating allocations and locks"; + case PHASE_PHASEIDEALLOOP1: return "PhaseIdealLoop 1"; + case PHASE_PHASEIDEALLOOP2: return "PhaseIdealLoop 2"; + case PHASE_PHASEIDEALLOOP3: return "PhaseIdealLoop 3"; + case PHASE_CPP1: return "PhaseCPP 1"; + case PHASE_ITER_GVN2: return "Iter GVN 2"; + case PHASE_PHASEIDEALLOOP_ITERATIONS: return "PhaseIdealLoop iterations"; + case PHASE_OPTIMIZE_FINISHED: return "Optimize finished"; + case PHASE_GLOBAL_CODE_MOTION: return "Global code motion"; + case PHASE_FINAL_CODE: return "Final Code"; + case PHASE_AFTER_EA: return "After Escape Analysis"; + case PHASE_BEFORE_CLOOPS: return "Before CountedLoop"; + case PHASE_AFTER_CLOOPS: return "After CountedLoop"; + case PHASE_BEFORE_BEAUTIFY_LOOPS: return "Before beautify loops"; + case PHASE_AFTER_BEAUTIFY_LOOPS: return "After beautify loops"; + case PHASE_BEFORE_MATCHING: return "Before Matching"; + case PHASE_INCREMENTAL_INLINE: return "Incremental Inline"; + case PHASE_INCREMENTAL_BOXING_INLINE: return "Incremental Boxing Inline"; + case PHASE_END: return "End"; + case PHASE_FAILURE: return "Failure"; + default: + ShouldNotReachHere(); + return NULL; + } + } +}; + +#endif //SHARE_VM_OPTO_PHASETYPE_HPP diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/opto/reg_split.cpp --- a/src/share/vm/opto/reg_split.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/opto/reg_split.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -51,6 +51,15 @@ static const char out_of_nodes[] = "out of nodes during split"; +static bool contains_no_live_range_input(const Node* def) { + for (uint i = 1; i < def->req(); ++i) { + if (def->in(i) != NULL && def->in_RegMask(i).is_NotEmpty()) { + return false; + } + } + return true; +} + //------------------------------get_spillcopy_wide----------------------------- // Get a SpillCopy node with wide-enough masks. Use the 'wide-mask', the // wide ideal-register spill-mask if possible. If the 'wide-mask' does @@ -1312,7 +1321,7 @@ Node *def = Reaches[pidx][slidx]; assert( def, "must have reaching def" ); // If input up/down sense and reg-pressure DISagree - if( def->rematerialize() ) { + if (def->rematerialize() && contains_no_live_range_input(def)) { // Place the rematerialized node above any MSCs created during // phi node splitting. end_idx points at the insertion point // so look at the node before it. diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/precompiled/precompiled.hpp --- a/src/share/vm/precompiled/precompiled.hpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/precompiled/precompiled.hpp Fri Jun 21 15:56:24 2013 -0700 @@ -26,7 +26,6 @@ // or if the user passes USE_PRECOMPILED_HEADER=0 to the makefiles. #ifndef DONT_USE_PRECOMPILED_HEADER - # include "asm/assembler.hpp" # include "asm/assembler.inline.hpp" # include "asm/codeBuffer.hpp" diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/prims/forte.cpp --- a/src/share/vm/prims/forte.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/prims/forte.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -35,6 +35,19 @@ #include "runtime/vframe.hpp" #include "runtime/vframeArray.hpp" +// call frame copied from old .h file and renamed +typedef struct { + jint lineno; // line number in the source file + jmethodID method_id; // method executed in this frame +} ASGCT_CallFrame; + +// call trace copied from old .h file and renamed +typedef struct { + JNIEnv *env_id; // Env where trace was recorded + jint num_frames; // number of frames in this trace + ASGCT_CallFrame *frames; // frames +} ASGCT_CallTrace; + // These name match the names reported by the forte quality kit enum { ticks_no_Java_frame = 0, @@ -50,6 +63,8 @@ ticks_safepoint = -10 }; +#if INCLUDE_JVMTI + //------------------------------------------------------- // Native interfaces for use by Forte tools. @@ -360,20 +375,6 @@ } - -// call frame copied from old .h file and renamed -typedef struct { - jint lineno; // line number in the source file - jmethodID method_id; // method executed in this frame -} ASGCT_CallFrame; - -// call trace copied from old .h file and renamed -typedef struct { - JNIEnv *env_id; // Env where trace was recorded - jint num_frames; // number of frames in this trace - ASGCT_CallFrame *frames; // frames -} ASGCT_CallTrace; - static void forte_fill_call_trace_given_top(JavaThread* thd, ASGCT_CallTrace* trace, int depth, @@ -634,3 +635,12 @@ pointer_delta(end, start, sizeof(jbyte)), 0, NULL); #endif // !_WINDOWS && !IA64 } + +#else // INCLUDE_JVMTI +extern "C" { + JNIEXPORT + void AsyncGetCallTrace(ASGCT_CallTrace *trace, jint depth, void* ucontext) { + trace->num_frames = ticks_no_class_load; // -1 + } +} +#endif // INCLUDE_JVMTI diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/prims/jni.cpp --- a/src/share/vm/prims/jni.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/prims/jni.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -74,7 +74,6 @@ #include "runtime/vm_operations.hpp" #include "services/runtimeService.hpp" #include "trace/tracing.hpp" -#include "trace/traceEventTypes.hpp" #include "utilities/defaultStream.hpp" #include "utilities/dtrace.hpp" #include "utilities/events.hpp" @@ -5014,6 +5013,7 @@ #ifndef PRODUCT +#include "gc_implementation/shared/gcTimer.hpp" #include "gc_interface/collectedHeap.hpp" #if INCLUDE_ALL_GCS #include "gc_implementation/g1/heapRegionRemSet.hpp" @@ -5031,6 +5031,7 @@ if (ExecuteInternalVMTests) { tty->print_cr("Running internal VM tests"); run_unit_test(GlobalDefinitions::test_globals()); + run_unit_test(GCTimerAllTest::all()); run_unit_test(arrayOopDesc::test_max_array_length()); run_unit_test(CollectedHeap::test_is_in()); run_unit_test(QuickSort::test_quick_sort()); @@ -5131,9 +5132,11 @@ JvmtiExport::post_thread_start(thread); } - EVENT_BEGIN(TraceEventThreadStart, event); - EVENT_COMMIT(event, - EVENT_SET(event, javalangthread, java_lang_Thread::thread_id(thread->threadObj()))); + EventThreadStart event; + if (event.should_commit()) { + event.set_javalangthread(java_lang_Thread::thread_id(thread->threadObj())); + event.commit(); + } // Check if we should compile all classes on bootclasspath NOT_PRODUCT(if (CompileTheWorld) ClassLoader::compile_the_world();) @@ -5334,9 +5337,11 @@ JvmtiExport::post_thread_start(thread); } - EVENT_BEGIN(TraceEventThreadStart, event); - EVENT_COMMIT(event, - EVENT_SET(event, javalangthread, java_lang_Thread::thread_id(thread->threadObj()))); + EventThreadStart event; + if (event.should_commit()) { + event.set_javalangthread(java_lang_Thread::thread_id(thread->threadObj())); + event.commit(); + } *(JNIEnv**)penv = thread->jni_environment(); diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/prims/jvm.cpp --- a/src/share/vm/prims/jvm.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/prims/jvm.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -59,6 +59,7 @@ #include "services/attachListener.hpp" #include "services/management.hpp" #include "services/threadService.hpp" +#include "trace/tracing.hpp" #include "utilities/copy.hpp" #include "utilities/defaultStream.hpp" #include "utilities/dtrace.hpp" @@ -1072,11 +1073,7 @@ return NULL; } - Klass* k = java_lang_Class::as_Klass(JNIHandles::resolve_non_null(cls)); - objArrayOop signers = NULL; - if (k->oop_is_instance()) { - signers = InstanceKlass::cast(k)->signers(); - } + objArrayOop signers = java_lang_Class::signers(JNIHandles::resolve_non_null(cls)); // If there are no signers set in the class, or if the class // is an array, return NULL. @@ -1102,7 +1099,7 @@ // be called with an array. Only the bootstrap loader creates arrays. Klass* k = java_lang_Class::as_Klass(JNIHandles::resolve_non_null(cls)); if (k->oop_is_instance()) { - InstanceKlass::cast(k)->set_signers(objArrayOop(JNIHandles::resolve(signers))); + java_lang_Class::set_signers(k->java_mirror(), objArrayOop(JNIHandles::resolve(signers))); } } JVM_END @@ -1119,8 +1116,8 @@ return NULL; } - Klass* k = java_lang_Class::as_Klass(JNIHandles::resolve(cls)); - return (jobject) JNIHandles::make_local(env, k->protection_domain()); + oop pd = java_lang_Class::protection_domain(JNIHandles::resolve(cls)); + return (jobject) JNIHandles::make_local(env, pd); JVM_END @@ -1139,7 +1136,7 @@ if (k->oop_is_instance()) { oop pd = JNIHandles::resolve(protection_domain); assert(pd == NULL || pd->is_oop(), "just checking"); - InstanceKlass::cast(k)->set_protection_domain(pd); + java_lang_Class::set_protection_domain(k->java_mirror(), pd); } } JVM_END @@ -3003,6 +3000,8 @@ millis); #endif /* USDT2 */ + EventThreadSleep event; + if (millis == 0) { // When ConvertSleepToYield is on, this matches the classic VM implementation of // JVM_Sleep. Critical for similar threading behaviour (Win32) @@ -3023,6 +3022,10 @@ // An asynchronous exception (e.g., ThreadDeathException) could have been thrown on // us while we were sleeping. We do not overwrite those. if (!HAS_PENDING_EXCEPTION) { + if (event.should_commit()) { + event.set_time(millis); + event.commit(); + } #ifndef USDT2 HS_DTRACE_PROBE1(hotspot, thread__sleep__end,1); #else /* USDT2 */ @@ -3036,6 +3039,10 @@ } thread->osthread()->set_state(old_state); } + if (event.should_commit()) { + event.set_time(millis); + event.commit(); + } #ifndef USDT2 HS_DTRACE_PROBE1(hotspot, thread__sleep__end,0); #else /* USDT2 */ diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/prims/jvmtiGen.java --- a/src/share/vm/prims/jvmtiGen.java Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/prims/jvmtiGen.java Fri Jun 21 15:56:24 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2005, 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 @@ -31,7 +31,6 @@ import org.xml.sax.SAXParseException; import org.w3c.dom.Document; import org.w3c.dom.DOMException; - // For write operation import javax.xml.transform.Transformer; import javax.xml.transform.TransformerException; @@ -129,6 +128,7 @@ factory.setNamespaceAware(true); factory.setValidating(true); + factory.setXIncludeAware(true); try { File datafile = new File(inFileName); diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/prims/jvmtiImpl.cpp --- a/src/share/vm/prims/jvmtiImpl.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/prims/jvmtiImpl.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -360,19 +360,14 @@ case CLEAR_BREAKPOINT: _breakpoints->clear_at_safepoint(*_bp); break; - case CLEAR_ALL_BREAKPOINT: - _breakpoints->clearall_at_safepoint(); - break; default: assert(false, "Unknown operation"); } } void VM_ChangeBreakpoints::oops_do(OopClosure* f) { - // This operation keeps breakpoints alive - if (_breakpoints != NULL) { - _breakpoints->oops_do(f); - } + // The JvmtiBreakpoints in _breakpoints will be visited via + // JvmtiExport::oops_do. if (_bp != NULL) { _bp->oops_do(f); } @@ -433,23 +428,13 @@ } } -void JvmtiBreakpoints::clearall_at_safepoint() { - assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint"); - - int len = _bps.length(); - for (int i=0; imethod_holder()->add_member_name(mname); + m->method_holder()->add_member_name(m->method_idnum(), mname); + return mname(); } @@ -301,7 +302,6 @@ // Although the fieldDescriptor::_index would also identify the field, // we do not use it, because it is harder to decode. // TO DO: maybe intern mname_oop - InstanceKlass::cast(field_holder())->add_member_name(mname); return mname(); } @@ -943,7 +943,8 @@ // MemberNameTable // -MemberNameTable::MemberNameTable() : GrowableArray(10, true) { +MemberNameTable::MemberNameTable(int methods_cnt) + : GrowableArray(methods_cnt, true) { assert_locked_or_safepoint(MemberNameTable_lock); } @@ -957,29 +958,18 @@ } } -// Return entry index if found, return -1 otherwise. -int MemberNameTable::find_member_name(oop mem_name) { +void MemberNameTable::add_member_name(int index, jweak mem_name_wref) { assert_locked_or_safepoint(MemberNameTable_lock); - int len = this->length(); - - for (int idx = 0; idx < len; idx++) { - jweak ref = this->at(idx); - oop entry = JNIHandles::resolve(ref); - if (entry == mem_name) { - return idx; - } - } - return -1; + this->at_put_grow(index, mem_name_wref); } -void MemberNameTable::add_member_name(jweak mem_name_wref) { +// Return a member name oop or NULL. +oop MemberNameTable::get_member_name(int index) { assert_locked_or_safepoint(MemberNameTable_lock); - oop mem_name = JNIHandles::resolve(mem_name_wref); - // Each member name may appear just once: add only if not found - if (find_member_name(mem_name) == -1) { - this->append(mem_name_wref); - } + jweak ref = this->at(index); + oop mem_name = JNIHandles::resolve(ref); + return mem_name; } #if INCLUDE_JVMTI diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/prims/methodHandles.hpp --- a/src/share/vm/prims/methodHandles.hpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/prims/methodHandles.hpp Fri Jun 21 15:56:24 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 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 @@ -219,7 +219,6 @@ } }; - //------------------------------------------------------------------------------ // MethodHandlesAdapterGenerator // @@ -233,13 +232,13 @@ //------------------------------------------------------------------------------ // MemberNameTable // + class MemberNameTable : public GrowableArray { public: - MemberNameTable(); + MemberNameTable(int methods_cnt); ~MemberNameTable(); - void add_member_name(jweak mem_name_ref); - private: - int find_member_name(oop mem_name); + void add_member_name(int index, jweak mem_name_ref); + oop get_member_name(int index); #if INCLUDE_JVMTI public: diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/prims/unsafe.cpp --- a/src/share/vm/prims/unsafe.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/prims/unsafe.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,6 +36,7 @@ #include "runtime/reflection.hpp" #include "runtime/synchronizer.hpp" #include "services/threadService.hpp" +#include "trace/tracing.hpp" #include "utilities/copy.hpp" #include "utilities/dtrace.hpp" @@ -115,8 +116,6 @@ inline void* index_oop_from_field_offset_long(oop p, jlong field_offset) { jlong byte_offset = field_offset_to_byte_offset(field_offset); - // Don't allow unsafe to be used to read or write the header word of oops - assert(p == NULL || field_offset >= oopDesc::header_size(), "offset must be outside of header"); #ifdef ASSERT if (p != NULL) { assert(byte_offset >= 0 && byte_offset <= (jlong)MAX_OBJECT_SIZE, "sane offset"); @@ -1206,6 +1205,7 @@ UNSAFE_ENTRY(void, Unsafe_Park(JNIEnv *env, jobject unsafe, jboolean isAbsolute, jlong time)) UnsafeWrapper("Unsafe_Park"); + EventThreadPark event; #ifndef USDT2 HS_DTRACE_PROBE3(hotspot, thread__park__begin, thread->parker(), (int) isAbsolute, time); #else /* USDT2 */ @@ -1220,6 +1220,13 @@ HOTSPOT_THREAD_PARK_END( (uintptr_t) thread->parker()); #endif /* USDT2 */ + if (event.should_commit()) { + oop obj = thread->current_park_blocker(); + event.set_klass(obj ? obj->klass() : NULL); + event.set_timeout(time); + event.set_address(obj ? (TYPE_ADDRESS) (uintptr_t) obj : 0); + event.commit(); + } UNSAFE_END UNSAFE_ENTRY(void, Unsafe_Unpark(JNIEnv *env, jobject unsafe, jobject jthread)) diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/prims/whitebox.cpp --- a/src/share/vm/prims/whitebox.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/prims/whitebox.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -37,6 +37,7 @@ #include "runtime/os.hpp" #include "utilities/debug.hpp" #include "utilities/macros.hpp" +#include "utilities/exceptions.hpp" #if INCLUDE_ALL_GCS #include "gc_implementation/g1/concurrentMark.hpp" @@ -330,8 +331,18 @@ WB_END -WB_ENTRY(jlong, WB_ReserveMemory(JNIEnv* env, jobject o, jlong size)) - return (jlong)os::reserve_memory(size, NULL, 0); +WB_ENTRY(void, WB_ReadReservedMemory(JNIEnv* env, jobject o)) + // static+volatile in order to force the read to happen + // (not be eliminated by the compiler) + static char c; + static volatile char* p; + + p = os::reserve_memory(os::vm_allocation_granularity(), NULL, 0); + if (p == NULL) { + THROW_MSG(vmSymbols::java_lang_OutOfMemoryError(), "Failed to reserve memory"); + } + + c = *p; WB_END //Some convenience methods to deal with objects from java @@ -437,7 +448,7 @@ {CC"isInStringTable", CC"(Ljava/lang/String;)Z", (void*)&WB_IsInStringTable }, {CC"fullGC", CC"()V", (void*)&WB_FullGC }, - {CC"reserveMemory", CC"(J)J", (void*)&WB_ReserveMemory }, + {CC"readReservedMemory", CC"()V", (void*)&WB_ReadReservedMemory }, }; #undef CC diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/runtime/arguments.cpp --- a/src/share/vm/runtime/arguments.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/runtime/arguments.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -2217,6 +2217,13 @@ status = false; } + if (ReservedCodeCacheSize < InitialCodeCacheSize) { + jio_fprintf(defaultStream::error_stream(), + "Invalid ReservedCodeCacheSize: %dK. Should be greater than InitialCodeCacheSize=%dK\n", + ReservedCodeCacheSize/K, InitialCodeCacheSize/K); + status = false; + } + return status; } @@ -2619,13 +2626,10 @@ } else if (match_option(option, "-Xmaxjitcodesize", &tail) || match_option(option, "-XX:ReservedCodeCacheSize=", &tail)) { julong long_ReservedCodeCacheSize = 0; - ArgsRange errcode = parse_memory_size(tail, &long_ReservedCodeCacheSize, - (size_t)InitialCodeCacheSize); + ArgsRange errcode = parse_memory_size(tail, &long_ReservedCodeCacheSize, 1); if (errcode != arg_in_range) { jio_fprintf(defaultStream::error_stream(), - "Invalid maximum code cache size: %s. Should be greater than InitialCodeCacheSize=%dK\n", - option->optionString, InitialCodeCacheSize/K); - describe_range_error(errcode); + "Invalid maximum code cache size: %s.\n", option->optionString); return JNI_EINVAL; } FLAG_SET_CMDLINE(uintx, ReservedCodeCacheSize, (uintx)long_ReservedCodeCacheSize); diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/runtime/deoptimization.cpp --- a/src/share/vm/runtime/deoptimization.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/runtime/deoptimization.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -638,18 +638,22 @@ // at an uncommon trap for an invoke (where the compiler // generates debug info before the invoke has executed) Bytecodes::Code cur_code = str.next(); - if (cur_code == Bytecodes::_invokevirtual || - cur_code == Bytecodes::_invokespecial || - cur_code == Bytecodes::_invokestatic || - cur_code == Bytecodes::_invokeinterface) { + if (cur_code == Bytecodes::_invokevirtual || + cur_code == Bytecodes::_invokespecial || + cur_code == Bytecodes::_invokestatic || + cur_code == Bytecodes::_invokeinterface || + cur_code == Bytecodes::_invokedynamic) { Bytecode_invoke invoke(mh, iframe->interpreter_frame_bci()); Symbol* signature = invoke.signature(); ArgumentSizeComputer asc(signature); cur_invoke_parameter_size = asc.size(); - if (cur_code != Bytecodes::_invokestatic) { + if (invoke.has_receiver()) { // Add in receiver ++cur_invoke_parameter_size; } + if (i != 0 && !invoke.is_invokedynamic() && MethodHandles::has_member_arg(invoke.klass(), invoke.name())) { + callee_size_of_parameters++; + } } if (str.bci() < max_bci) { Bytecodes::Code bc = str.next(); @@ -664,6 +668,7 @@ case Bytecodes::_invokespecial: case Bytecodes::_invokestatic: case Bytecodes::_invokeinterface: + case Bytecodes::_invokedynamic: case Bytecodes::_athrow: break; default: { diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/runtime/frame.cpp --- a/src/share/vm/runtime/frame.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/runtime/frame.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -1008,6 +1008,7 @@ OopClosure* _f; int _offset; // the current offset, incremented with each argument bool _has_receiver; // true if the callee has a receiver + bool _has_appendix; // true if the call has an appendix frame _fr; RegisterMap* _reg_map; int _arg_size; @@ -1027,19 +1028,20 @@ } public: - CompiledArgumentOopFinder(Symbol* signature, bool has_receiver, OopClosure* f, frame fr, const RegisterMap* reg_map) + CompiledArgumentOopFinder(Symbol* signature, bool has_receiver, bool has_appendix, OopClosure* f, frame fr, const RegisterMap* reg_map) : SignatureInfo(signature) { // initialize CompiledArgumentOopFinder _f = f; _offset = 0; _has_receiver = has_receiver; + _has_appendix = has_appendix; _fr = fr; _reg_map = (RegisterMap*)reg_map; - _arg_size = ArgumentSizeComputer(signature).size() + (has_receiver ? 1 : 0); + _arg_size = ArgumentSizeComputer(signature).size() + (has_receiver ? 1 : 0) + (has_appendix ? 1 : 0); int arg_size; - _regs = SharedRuntime::find_callee_arguments(signature, has_receiver, &arg_size); + _regs = SharedRuntime::find_callee_arguments(signature, has_receiver, has_appendix, &arg_size); assert(arg_size == _arg_size, "wrong arg size"); } @@ -1049,12 +1051,16 @@ _offset++; } iterate_parameters(); + if (_has_appendix) { + handle_oop_offset(); + _offset++; + } } }; -void frame::oops_compiled_arguments_do(Symbol* signature, bool has_receiver, const RegisterMap* reg_map, OopClosure* f) { +void frame::oops_compiled_arguments_do(Symbol* signature, bool has_receiver, bool has_appendix, const RegisterMap* reg_map, OopClosure* f) { ResourceMark rm; - CompiledArgumentOopFinder finder(signature, has_receiver, f, *this, reg_map); + CompiledArgumentOopFinder finder(signature, has_receiver, has_appendix, f, *this, reg_map); finder.oops_do(); } diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/runtime/frame.hpp --- a/src/share/vm/runtime/frame.hpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/runtime/frame.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 @@ -137,6 +137,7 @@ bool is_interpreted_frame() const; bool is_java_frame() const; bool is_entry_frame() const; // Java frame called from C? + bool is_stub_frame() const; bool is_ignored_frame() const; bool is_native_frame() const; bool is_runtime_frame() const; @@ -414,7 +415,7 @@ oop* oopmapreg_to_location(VMReg reg, const RegisterMap* regmap) const; // Oops-do's - void oops_compiled_arguments_do(Symbol* signature, bool has_receiver, const RegisterMap* reg_map, OopClosure* f); + void oops_compiled_arguments_do(Symbol* signature, bool has_receiver, bool has_appendix, const RegisterMap* reg_map, OopClosure* f); void oops_interpreted_do(OopClosure* f, CLDToOopClosure* cld_f, const RegisterMap* map, bool query_oop_map_cache = true); private: diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/runtime/frame.inline.hpp --- a/src/share/vm/runtime/frame.inline.hpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/runtime/frame.inline.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 @@ -79,6 +79,10 @@ return StubRoutines::returns_to_call_stub(pc()); } +inline bool frame::is_stub_frame() const { + return StubRoutines::is_stub_code(pc()) || (_cb != NULL && _cb->is_adapter_blob()); +} + inline bool frame::is_first_frame() const { return is_entry_frame() && entry_frame_is_first(); } diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/runtime/globals.hpp --- a/src/share/vm/runtime/globals.hpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/runtime/globals.hpp Fri Jun 21 15:56:24 2013 -0700 @@ -2310,6 +2310,10 @@ "Print diagnostic message when GC is stalled" \ "by JNI critical section") \ \ + experimental(double, ObjectCountCutOffPercent, 0.5, \ + "The percentage of the used heap that the instances of a class " \ + "must occupy for the class to generate a trace event.") \ + \ /* GC log rotation setting */ \ \ product(bool, UseGCLogFileRotation, false, \ @@ -3688,7 +3692,13 @@ experimental(uintx, ArrayAllocatorMallocLimit, \ SOLARIS_ONLY(64*K) NOT_SOLARIS(max_uintx), \ "Allocation less than this value will be allocated " \ - "using malloc. Larger allocations will use mmap.") + "using malloc. Larger allocations will use mmap.") \ + \ + product(bool, EnableTracing, false, \ + "Enable event-based tracing") \ + product(bool, UseLockedTracing, false, \ + "Use locked-tracing when doing event-based tracing") + /* * Macros for factoring of globals diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/runtime/java.cpp --- a/src/share/vm/runtime/java.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/runtime/java.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 @@ -60,7 +60,6 @@ #include "services/memReporter.hpp" #include "services/memTracker.hpp" #include "trace/tracing.hpp" -#include "trace/traceEventTypes.hpp" #include "utilities/dtrace.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/histogram.hpp" @@ -528,9 +527,12 @@ JvmtiExport::post_thread_end(thread); } - EVENT_BEGIN(TraceEventThreadEnd, event); - EVENT_COMMIT(event, - EVENT_SET(event, javalangthread, java_lang_Thread::thread_id(thread->threadObj()))); + + EventThreadEnd event; + if (event.should_commit()) { + event.set_javalangthread(java_lang_Thread::thread_id(thread->threadObj())); + event.commit(); + } // Always call even when there are not JVMTI environments yet, since environments // may be attached late and JVMTI must track phases of VM execution diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/runtime/mutexLocker.cpp --- a/src/share/vm/runtime/mutexLocker.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/runtime/mutexLocker.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 @@ -270,13 +270,12 @@ def(MethodCompileQueue_lock , Monitor, nonleaf+4, true ); def(Debug2_lock , Mutex , nonleaf+4, true ); def(Debug3_lock , Mutex , nonleaf+4, true ); - def(ProfileVM_lock , Monitor, nonleaf+4, false); // used for profiling of the VMThread + def(ProfileVM_lock , Monitor, special, false); // used for profiling of the VMThread def(CompileThread_lock , Monitor, nonleaf+5, false ); - def(JfrQuery_lock , Monitor, nonleaf, true); // JFR locks, keep these in consecutive order - def(JfrMsg_lock , Monitor, nonleaf+2, true); - def(JfrBuffer_lock , Mutex, nonleaf+3, true); - def(JfrStream_lock , Mutex, nonleaf+4, true); + def(JfrMsg_lock , Monitor, leaf, true); + def(JfrBuffer_lock , Mutex, nonleaf+1, true); + def(JfrStream_lock , Mutex, nonleaf+2, true); def(PeriodicTask_lock , Monitor, nonleaf+5, true); } diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/runtime/objectMonitor.cpp --- a/src/share/vm/runtime/objectMonitor.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/runtime/objectMonitor.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -36,7 +36,10 @@ #include "runtime/stubRoutines.hpp" #include "runtime/thread.inline.hpp" #include "services/threadService.hpp" +#include "trace/tracing.hpp" +#include "trace/traceMacros.hpp" #include "utilities/dtrace.hpp" +#include "utilities/macros.hpp" #include "utilities/preserveException.hpp" #ifdef TARGET_OS_FAMILY_linux # include "os_linux.inline.hpp" @@ -371,6 +374,8 @@ // Ensure the object-monitor relationship remains stable while there's contention. Atomic::inc_ptr(&_count); + EventJavaMonitorEnter event; + { // Change java thread status to indicate blocked on monitor enter. JavaThreadBlockedOnMonitorEnterState jtbmes(jt, this); @@ -402,7 +407,7 @@ // _recursions = 0 ; _succ = NULL ; - exit (Self) ; + exit (false, Self) ; jt->java_suspend_self(); } @@ -435,6 +440,14 @@ if (JvmtiExport::should_post_monitor_contended_entered()) { JvmtiExport::post_monitor_contended_entered(jt, this); } + + if (event.should_commit()) { + event.set_klass(((oop)this->object())->klass()); + event.set_previousOwner((TYPE_JAVALANGTHREAD)_previous_owner_tid); + event.set_address((TYPE_ADDRESS)(uintptr_t)(this->object_addr())); + event.commit(); + } + if (ObjectMonitor::_sync_ContendedLockAttempts != NULL) { ObjectMonitor::_sync_ContendedLockAttempts->inc() ; } @@ -917,7 +930,7 @@ // Both impinge on OS scalability. Given that, at most one thread parked on // a monitor will use a timer. -void ATTR ObjectMonitor::exit(TRAPS) { +void ATTR ObjectMonitor::exit(bool not_suspended, TRAPS) { Thread * Self = THREAD ; if (THREAD != _owner) { if (THREAD->is_lock_owned((address) _owner)) { @@ -954,6 +967,14 @@ _Responsible = NULL ; } +#if INCLUDE_TRACE + // get the owner's thread id for the MonitorEnter event + // if it is enabled and the thread isn't suspended + if (not_suspended && Tracing::is_event_enabled(TraceJavaMonitorEnterEvent)) { + _previous_owner_tid = SharedRuntime::get_java_tid(Self); + } +#endif + for (;;) { assert (THREAD == _owner, "invariant") ; @@ -1343,7 +1364,7 @@ guarantee(Self == _owner, "complete_exit not owner"); intptr_t save = _recursions; // record the old recursion count _recursions = 0; // set the recursion level to be 0 - exit (Self) ; // exit the monitor + exit (true, Self) ; // exit the monitor guarantee (_owner != Self, "invariant"); return save; } @@ -1397,6 +1418,20 @@ for (v = *adr ; Atomic::cmpxchg (v + dx, adr, v) != v; v = *adr) ; return v ; } + +// helper method for posting a monitor wait event +void ObjectMonitor::post_monitor_wait_event(EventJavaMonitorWait* event, + jlong notifier_tid, + jlong timeout, + bool timedout) { + event->set_klass(((oop)this->object())->klass()); + event->set_timeout((TYPE_ULONG)timeout); + event->set_address((TYPE_ADDRESS)(uintptr_t)(this->object_addr())); + event->set_notifier((TYPE_OSTHREAD)notifier_tid); + event->set_timedOut((TYPE_BOOLEAN)timedout); + event->commit(); +} + // ----------------------------------------------------------------------------- // Wait/Notify/NotifyAll // @@ -1412,6 +1447,8 @@ // Throw IMSX or IEX. CHECK_OWNER(); + EventJavaMonitorWait event; + // check for a pending interrupt if (interruptible && Thread::is_interrupted(Self, true) && !HAS_PENDING_EXCEPTION) { // post monitor waited event. Note that this is past-tense, we are done waiting. @@ -1420,10 +1457,14 @@ // wait was not timed out due to thread interrupt. JvmtiExport::post_monitor_waited(jt, this, false); } + if (event.should_commit()) { + post_monitor_wait_event(&event, 0, millis, false); + } TEVENT (Wait - Throw IEX) ; THROW(vmSymbols::java_lang_InterruptedException()); return ; } + TEVENT (Wait) ; assert (Self->_Stalled == 0, "invariant") ; @@ -1455,7 +1496,7 @@ intptr_t save = _recursions; // record the old recursion count _waiters++; // increment the number of waiters _recursions = 0; // set the recursion level to be 1 - exit (Self) ; // exit the monitor + exit (true, Self) ; // exit the monitor guarantee (_owner != Self, "invariant") ; // As soon as the ObjectMonitor's ownership is dropped in the exit() @@ -1555,6 +1596,11 @@ if (JvmtiExport::should_post_monitor_waited()) { JvmtiExport::post_monitor_waited(jt, this, ret == OS_TIMEOUT); } + + if (event.should_commit()) { + post_monitor_wait_event(&event, node._notifier_tid, millis, ret == OS_TIMEOUT); + } + OrderAccess::fence() ; assert (Self->_Stalled != 0, "invariant") ; @@ -1634,6 +1680,8 @@ iterator->TState = ObjectWaiter::TS_ENTER ; } iterator->_notified = 1 ; + Thread * Self = THREAD; + iterator->_notifier_tid = Self->osthread()->thread_id(); ObjectWaiter * List = _EntryList ; if (List != NULL) { @@ -1758,6 +1806,8 @@ guarantee (iterator->TState == ObjectWaiter::TS_WAIT, "invariant") ; guarantee (iterator->_notified == 0, "invariant") ; iterator->_notified = 1 ; + Thread * Self = THREAD; + iterator->_notifier_tid = Self->osthread()->thread_id(); if (Policy != 4) { iterator->TState = ObjectWaiter::TS_ENTER ; } diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/runtime/objectMonitor.hpp --- a/src/share/vm/runtime/objectMonitor.hpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/runtime/objectMonitor.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 @@ -29,7 +29,6 @@ #include "runtime/park.hpp" #include "runtime/perfData.hpp" - // ObjectWaiter serves as a "proxy" or surrogate thread. // TODO-FIXME: Eliminate ObjectWaiter and use the thread-specific // ParkEvent instead. Beware, however, that the JVMTI code @@ -43,6 +42,7 @@ ObjectWaiter * volatile _next; ObjectWaiter * volatile _prev; Thread* _thread; + jlong _notifier_tid; ParkEvent * _event; volatile int _notified ; volatile TStates TState ; @@ -55,6 +55,9 @@ void wait_reenter_end(ObjectMonitor *mon); }; +// forward declaration to avoid include tracing.hpp +class EventJavaMonitorWait; + // WARNING: // This is a very sensitive and fragile class. DO NOT make any // change unless you are fully aware of the underlying semantics. @@ -151,6 +154,7 @@ _SpinFreq = 0 ; _SpinClock = 0 ; OwnerIsThread = 0 ; + _previous_owner_tid = 0; } ~ObjectMonitor() { @@ -192,7 +196,7 @@ bool try_enter (TRAPS) ; void enter(TRAPS); - void exit(TRAPS); + void exit(bool not_suspended, TRAPS); void wait(jlong millis, bool interruptable, TRAPS); void notify(TRAPS); void notifyAll(TRAPS); @@ -218,6 +222,10 @@ void ctAsserts () ; void ExitEpilog (Thread * Self, ObjectWaiter * Wakee) ; bool ExitSuspendEquivalent (JavaThread * Self) ; + void post_monitor_wait_event(EventJavaMonitorWait * event, + jlong notifier_tid, + jlong timeout, + bool timedout); private: friend class ObjectSynchronizer; @@ -240,6 +248,7 @@ protected: // protected for jvmtiRawMonitor void * volatile _owner; // pointer to owning thread OR BasicLock + volatile jlong _previous_owner_tid; // thread id of the previous owner of the monitor volatile intptr_t _recursions; // recursion count, 0 for first entry private: int OwnerIsThread ; // _owner is (Thread *) vs SP/BasicLock diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/runtime/os.cpp --- a/src/share/vm/runtime/os.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/runtime/os.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -265,8 +265,7 @@ VMThread::execute(&op1); Universe::print_heap_at_SIGBREAK(); if (PrintClassHistogram) { - VM_GC_HeapInspection op1(gclog_or_tty, true /* force full GC before heap inspection */, - true /* need_prologue */); + VM_GC_HeapInspection op1(gclog_or_tty, true /* force full GC before heap inspection */); VMThread::execute(&op1); } if (JvmtiExport::should_post_data_dump()) { @@ -1444,11 +1443,16 @@ return (int) i; } +void os::SuspendedThreadTask::run() { + assert(Threads_lock->owned_by_self() || (_thread == VMThread::vm_thread()), "must have threads lock to call this"); + internal_do_task(); + _done = true; +} + bool os::create_stack_guard_pages(char* addr, size_t bytes) { return os::pd_create_stack_guard_pages(addr, bytes); } - char* os::reserve_memory(size_t bytes, char* addr, size_t alignment_hint) { char* result = pd_reserve_memory(bytes, addr, alignment_hint); if (result != NULL) { @@ -1551,3 +1555,19 @@ pd_realign_memory(addr, bytes, alignment_hint); } +#ifndef TARGET_OS_FAMILY_windows +/* try to switch state from state "from" to state "to" + * returns the state set after the method is complete + */ +os::SuspendResume::State os::SuspendResume::switch_state(os::SuspendResume::State from, + os::SuspendResume::State to) +{ + os::SuspendResume::State result = + (os::SuspendResume::State) Atomic::cmpxchg((jint) to, (jint *) &_state, (jint) from); + if (result == from) { + // success + return to; + } + return result; +} +#endif diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/runtime/os.hpp --- a/src/share/vm/runtime/os.hpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/runtime/os.hpp Fri Jun 21 15:56:24 2013 -0700 @@ -781,6 +781,104 @@ // ResumeThread call) static void pause(); + class SuspendedThreadTaskContext { + public: + SuspendedThreadTaskContext(Thread* thread, void *ucontext) : _thread(thread), _ucontext(ucontext) {} + Thread* thread() const { return _thread; } + void* ucontext() const { return _ucontext; } + private: + Thread* _thread; + void* _ucontext; + }; + + class SuspendedThreadTask { + public: + SuspendedThreadTask(Thread* thread) : _thread(thread), _done(false) {} + virtual ~SuspendedThreadTask() {} + void run(); + bool is_done() { return _done; } + virtual void do_task(const SuspendedThreadTaskContext& context) = 0; + protected: + private: + void internal_do_task(); + Thread* _thread; + bool _done; + }; + +#ifndef TARGET_OS_FAMILY_windows + // Suspend/resume support + // Protocol: + // + // a thread starts in SR_RUNNING + // + // SR_RUNNING can go to + // * SR_SUSPEND_REQUEST when the WatcherThread wants to suspend it + // SR_SUSPEND_REQUEST can go to + // * SR_RUNNING if WatcherThread decides it waited for SR_SUSPENDED too long (timeout) + // * SR_SUSPENDED if the stopped thread receives the signal and switches state + // SR_SUSPENDED can go to + // * SR_WAKEUP_REQUEST when the WatcherThread has done the work and wants to resume + // SR_WAKEUP_REQUEST can go to + // * SR_RUNNING when the stopped thread receives the signal + // * SR_WAKEUP_REQUEST on timeout (resend the signal and try again) + class SuspendResume { + public: + enum State { + SR_RUNNING, + SR_SUSPEND_REQUEST, + SR_SUSPENDED, + SR_WAKEUP_REQUEST + }; + + private: + volatile State _state; + + private: + /* try to switch state from state "from" to state "to" + * returns the state set after the method is complete + */ + State switch_state(State from, State to); + + public: + SuspendResume() : _state(SR_RUNNING) { } + + State state() const { return _state; } + + State request_suspend() { + return switch_state(SR_RUNNING, SR_SUSPEND_REQUEST); + } + + State cancel_suspend() { + return switch_state(SR_SUSPEND_REQUEST, SR_RUNNING); + } + + State suspended() { + return switch_state(SR_SUSPEND_REQUEST, SR_SUSPENDED); + } + + State request_wakeup() { + return switch_state(SR_SUSPENDED, SR_WAKEUP_REQUEST); + } + + State running() { + return switch_state(SR_WAKEUP_REQUEST, SR_RUNNING); + } + + bool is_running() const { + return _state == SR_RUNNING; + } + + bool is_suspend_request() const { + return _state == SR_SUSPEND_REQUEST; + } + + bool is_suspended() const { + return _state == SR_SUSPENDED; + } + }; +#endif + + protected: static long _rand_seed; // seed for random number generator static int _processor_count; // number of processors diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/runtime/perfData.cpp --- a/src/share/vm/runtime/perfData.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/runtime/perfData.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -323,6 +323,10 @@ } } +PerfData* PerfDataManager::find_by_name(const char* name) { + return _all->find_by_name(name); +} + PerfDataList* PerfDataManager::all() { MutexLocker ml(PerfDataManager_lock); diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/runtime/perfData.hpp --- a/src/share/vm/runtime/perfData.hpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/runtime/perfData.hpp Fri Jun 21 15:56:24 2013 -0700 @@ -693,6 +693,9 @@ // the given name. static bool exists(const char* name) { return _all->contains(name); } + // method to search for a instrumentation object by name + static PerfData* find_by_name(const char* name); + // method to map a CounterNS enumeration to a namespace string static const char* ns_to_string(CounterNS ns) { return _name_spaces[ns]; diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/runtime/reflection.cpp --- a/src/share/vm/runtime/reflection.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/runtime/reflection.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 @@ -44,8 +44,6 @@ #include "runtime/signature.hpp" #include "runtime/vframe.hpp" -#define JAVA_1_5_VERSION 49 - static void trace_class_resolution(Klass* to_class) { ResourceMark rm; int line_number = -1; @@ -375,7 +373,7 @@ } } klass = klass->array_klass(dim, CHECK_NULL); - oop obj = ArrayKlass::cast(klass)->multi_allocate(len, dimensions, THREAD); + oop obj = ArrayKlass::cast(klass)->multi_allocate(len, dimensions, CHECK_NULL); assert(obj->is_array(), "just checking"); return arrayOop(obj); } @@ -507,9 +505,11 @@ under_host_klass(accessee_ik, accessor)) return true; - if (RelaxAccessControlCheck || - (accessor_ik->major_version() < JAVA_1_5_VERSION && - accessee_ik->major_version() < JAVA_1_5_VERSION)) { + if ((RelaxAccessControlCheck && + accessor_ik->major_version() < Verifier::NO_RELAX_ACCESS_CTRL_CHECK_VERSION && + accessee_ik->major_version() < Verifier::NO_RELAX_ACCESS_CTRL_CHECK_VERSION) || + (accessor_ik->major_version() < Verifier::STRICTER_ACCESS_CTRL_CHECK_VERSION && + accessee_ik->major_version() < Verifier::STRICTER_ACCESS_CTRL_CHECK_VERSION)) { return classloader_only && Verifier::relax_verify_for(accessor_ik->class_loader()) && accessor_ik->protection_domain() == accessee_ik->protection_domain() && @@ -817,6 +817,10 @@ typeArrayOop an_oop = Annotations::make_java_array(method->parameter_annotations(), CHECK_NULL); java_lang_reflect_Constructor::set_parameter_annotations(ch(), an_oop); } + if (java_lang_reflect_Constructor::has_type_annotations_field()) { + typeArrayOop an_oop = Annotations::make_java_array(method->type_annotations(), CHECK_NULL); + java_lang_reflect_Constructor::set_type_annotations(ch(), an_oop); + } return ch(); } diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/runtime/sharedRuntime.cpp --- a/src/share/vm/runtime/sharedRuntime.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/runtime/sharedRuntime.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -2726,7 +2726,7 @@ return regs.first(); } -VMRegPair *SharedRuntime::find_callee_arguments(Symbol* sig, bool has_receiver, int* arg_size) { +VMRegPair *SharedRuntime::find_callee_arguments(Symbol* sig, bool has_receiver, bool has_appendix, int* arg_size) { // This method is returning a data structure allocating as a // ResourceObject, so do not put any ResourceMarks in here. char *s = sig->as_C_string(); @@ -2770,6 +2770,11 @@ default : ShouldNotReachHere(); } } + + if (has_appendix) { + sig_bt[cnt++] = T_OBJECT; + } + assert( cnt < 256, "grow table size" ); int comp_args_on_stack; diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/runtime/sharedRuntime.hpp --- a/src/share/vm/runtime/sharedRuntime.hpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/runtime/sharedRuntime.hpp Fri Jun 21 15:56:24 2013 -0700 @@ -410,7 +410,7 @@ // Convert a sig into a calling convention register layout // and find interesting things about it. - static VMRegPair* find_callee_arguments(Symbol* sig, bool has_receiver, int *arg_size); + static VMRegPair* find_callee_arguments(Symbol* sig, bool has_receiver, bool has_appendix, int *arg_size); static VMReg name_for_receiver(); // "Top of Stack" slots that may be unused by the calling convention but must diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/runtime/stubRoutines.hpp --- a/src/share/vm/runtime/stubRoutines.hpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/runtime/stubRoutines.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 @@ -226,6 +226,8 @@ static void initialize1(); // must happen before universe::genesis static void initialize2(); // must happen after universe::genesis + static bool is_stub_code(address addr) { return contains(addr); } + static bool contains(address addr) { return (_code1 != NULL && _code1->blob_contains(addr)) || diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/runtime/sweeper.cpp --- a/src/share/vm/runtime/sweeper.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/runtime/sweeper.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 @@ -36,6 +36,7 @@ #include "runtime/os.hpp" #include "runtime/sweeper.hpp" #include "runtime/vm_operations.hpp" +#include "trace/tracing.hpp" #include "utilities/events.hpp" #include "utilities/xmlstream.hpp" @@ -130,6 +131,9 @@ long NMethodSweeper::_traversals = 0; // No. of stack traversals performed nmethod* NMethodSweeper::_current = NULL; // Current nmethod int NMethodSweeper::_seen = 0 ; // No. of nmethods we have currently processed in current pass of CodeCache +int NMethodSweeper::_flushed_count = 0; // Nof. nmethods flushed in current sweep +int NMethodSweeper::_zombified_count = 0; // Nof. nmethods made zombie in current sweep +int NMethodSweeper::_marked_count = 0; // Nof. nmethods marked for reclaim in current sweep volatile int NMethodSweeper::_invocations = 0; // No. of invocations left until we are completed with this pass volatile int NMethodSweeper::_sweep_started = 0; // Whether a sweep is in progress. @@ -143,6 +147,15 @@ int NMethodSweeper::_dead_compile_ids = 0; long NMethodSweeper::_last_flush_traversal_id = 0; +int NMethodSweeper::_number_of_flushes = 0; // Total of full traversals caused by full cache +int NMethodSweeper::_total_nof_methods_reclaimed = 0; +jlong NMethodSweeper::_total_time_sweeping = 0; +jlong NMethodSweeper::_total_time_this_sweep = 0; +jlong NMethodSweeper::_peak_sweep_time = 0; +jlong NMethodSweeper::_peak_sweep_fraction_time = 0; +jlong NMethodSweeper::_total_disconnect_time = 0; +jlong NMethodSweeper::_peak_disconnect_time = 0; + class MarkActivationClosure: public CodeBlobClosure { public: virtual void do_code_blob(CodeBlob* cb) { @@ -176,6 +189,8 @@ _invocations = NmethodSweepFraction; _current = CodeCache::first_nmethod(); _traversals += 1; + _total_time_this_sweep = 0; + if (PrintMethodFlushing) { tty->print_cr("### Sweep: stack traversal %d", _traversals); } @@ -229,12 +244,13 @@ } void NMethodSweeper::sweep_code_cache() { -#ifdef ASSERT - jlong sweep_start; - if (PrintMethodFlushing) { - sweep_start = os::javaTimeMillis(); - } -#endif + + jlong sweep_start_counter = os::elapsed_counter(); + + _flushed_count = 0; + _zombified_count = 0; + _marked_count = 0; + if (PrintMethodFlushing && Verbose) { tty->print_cr("### Sweep at %d out of %d. Invocations left: %d", _seen, CodeCache::nof_nmethods(), _invocations); } @@ -302,14 +318,34 @@ } } + jlong sweep_end_counter = os::elapsed_counter(); + jlong sweep_time = sweep_end_counter - sweep_start_counter; + _total_time_sweeping += sweep_time; + _total_time_this_sweep += sweep_time; + _peak_sweep_fraction_time = MAX2(sweep_time, _peak_sweep_fraction_time); + _total_nof_methods_reclaimed += _flushed_count; + + EventSweepCodeCache event(UNTIMED); + if (event.should_commit()) { + event.set_starttime(sweep_start_counter); + event.set_endtime(sweep_end_counter); + event.set_sweepIndex(_traversals); + event.set_sweepFractionIndex(NmethodSweepFraction - _invocations + 1); + event.set_sweptCount(todo); + event.set_flushedCount(_flushed_count); + event.set_markedCount(_marked_count); + event.set_zombifiedCount(_zombified_count); + event.commit(); + } + #ifdef ASSERT if(PrintMethodFlushing) { - jlong sweep_end = os::javaTimeMillis(); - tty->print_cr("### sweeper: sweep time(%d): " INT64_FORMAT, _invocations, sweep_end - sweep_start); + tty->print_cr("### sweeper: sweep time(%d): " INT64_FORMAT, _invocations, (jlong)sweep_time); } #endif if (_invocations == 1) { + _peak_sweep_time = MAX2(_peak_sweep_time, _total_time_this_sweep); log_sweep("finished"); } @@ -388,12 +424,14 @@ tty->print_cr("### Nmethod %3d/" PTR_FORMAT " (marked for reclamation) being flushed", nm->compile_id(), nm); } release_nmethod(nm); + _flushed_count++; } else { if (PrintMethodFlushing && Verbose) { tty->print_cr("### Nmethod %3d/" PTR_FORMAT " (zombie) being marked for reclamation", nm->compile_id(), nm); } nm->mark_for_reclamation(); _resweep = true; + _marked_count++; SWEEP(nm); } } else if (nm->is_not_entrant()) { @@ -405,6 +443,7 @@ } nm->make_zombie(); _resweep = true; + _zombified_count++; SWEEP(nm); } else { // Still alive, clean up its inline caches @@ -420,13 +459,16 @@ // Unloaded code, just make it a zombie if (PrintMethodFlushing && Verbose) tty->print_cr("### Nmethod %3d/" PTR_FORMAT " (unloaded) being made zombie", nm->compile_id(), nm); + if (nm->is_osr_method()) { SWEEP(nm); // No inline caches will ever point to osr methods, so we can just remove it release_nmethod(nm); + _flushed_count++; } else { nm->make_zombie(); _resweep = true; + _zombified_count++; SWEEP(nm); } } else { @@ -484,7 +526,7 @@ // If there was a race in detecting full code cache, only run // one vm op for it or keep the compiler shut off - debug_only(jlong start = os::javaTimeMillis();) + jlong disconnect_start_counter = os::elapsed_counter(); // Traverse the code cache trying to dump the oldest nmethods int curr_max_comp_id = CompileBroker::get_compilation_id(); @@ -541,13 +583,28 @@ _last_full_flush_time = os::javaTimeMillis(); } + jlong disconnect_end_counter = os::elapsed_counter(); + jlong disconnect_time = disconnect_end_counter - disconnect_start_counter; + _total_disconnect_time += disconnect_time; + _peak_disconnect_time = MAX2(disconnect_time, _peak_disconnect_time); + + EventCleanCodeCache event(UNTIMED); + if (event.should_commit()) { + event.set_starttime(disconnect_start_counter); + event.set_endtime(disconnect_end_counter); + event.set_disconnectedCount(disconnected); + event.set_madeNonEntrantCount(made_not_entrant); + event.commit(); + } + _number_of_flushes++; + // After two more traversals the sweeper will get rid of unrestored nmethods _last_flush_traversal_id = _traversals; _resweep = true; #ifdef ASSERT - jlong end = os::javaTimeMillis(); + if(PrintMethodFlushing && Verbose) { - tty->print_cr("### sweeper: unload time: " INT64_FORMAT, end-start); + tty->print_cr("### sweeper: unload time: " INT64_FORMAT, (jlong)disconnect_time); } #endif } diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/runtime/sweeper.hpp --- a/src/share/vm/runtime/sweeper.hpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/runtime/sweeper.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 @@ -31,9 +31,12 @@ // class NMethodSweeper : public AllStatic { - static long _traversals; // Stack traversal count - static nmethod* _current; // Current nmethod - static int _seen; // Nof. nmethod we have currently processed in current pass of CodeCache + static long _traversals; // Stack scan count, also sweep ID. + static nmethod* _current; // Current nmethod + static int _seen; // Nof. nmethod we have currently processed in current pass of CodeCache + static int _flushed_count; // Nof. nmethods flushed in current sweep + static int _zombified_count; // Nof. nmethods made zombie in current sweep + static int _marked_count; // Nof. nmethods marked for reclaim in current sweep static volatile int _invocations; // No. of invocations left until we are completed with this pass static volatile int _sweep_started; // Flag to control conc sweeper @@ -53,6 +56,16 @@ static int _highest_marked; // highest compile id dumped at last emergency unloading static int _dead_compile_ids; // number of compile ids that where not in the cache last flush + // Stat counters + static int _number_of_flushes; // Total of full traversals caused by full cache + static int _total_nof_methods_reclaimed; // Accumulated nof methods flushed + static jlong _total_time_sweeping; // Accumulated time sweeping + static jlong _total_time_this_sweep; // Total time this sweep + static jlong _peak_sweep_time; // Peak time for a full sweep + static jlong _peak_sweep_fraction_time; // Peak time sweeping one fraction + static jlong _total_disconnect_time; // Total time cleaning code mem + static jlong _peak_disconnect_time; // Peak time cleaning code mem + static void process_nmethod(nmethod *nm); static void release_nmethod(nmethod* nm); @@ -60,7 +73,14 @@ static bool sweep_in_progress(); public: - static long traversal_count() { return _traversals; } + static long traversal_count() { return _traversals; } + static int number_of_flushes() { return _number_of_flushes; } + static int total_nof_methods_reclaimed() { return _total_nof_methods_reclaimed; } + static jlong total_time_sweeping() { return _total_time_sweeping; } + static jlong peak_sweep_time() { return _peak_sweep_time; } + static jlong peak_sweep_fraction_time() { return _peak_sweep_fraction_time; } + static jlong total_disconnect_time() { return _total_disconnect_time; } + static jlong peak_disconnect_time() { return _peak_disconnect_time; } #ifdef ASSERT // Keep track of sweeper activity in the ring buffer diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/runtime/synchronizer.cpp --- a/src/share/vm/runtime/synchronizer.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/runtime/synchronizer.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -213,7 +213,7 @@ } } - ObjectSynchronizer::inflate(THREAD, object)->exit (THREAD) ; + ObjectSynchronizer::inflate(THREAD, object)->exit (true, THREAD) ; } // ----------------------------------------------------------------------------- @@ -343,7 +343,7 @@ // If this thread has locked the object, exit the monitor. Note: can't use // monitor->check(CHECK); must exit even if an exception is pending. if (monitor->check(THREAD)) { - monitor->exit(THREAD); + monitor->exit(true, THREAD); } } diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/runtime/task.cpp --- a/src/share/vm/runtime/task.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/runtime/task.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -114,9 +114,11 @@ disenroll(); } +/* enroll could be called from a JavaThread, so we have to check for + * safepoint when taking the lock to avoid deadlocking */ void PeriodicTask::enroll() { MutexLockerEx ml(PeriodicTask_lock->owned_by_self() ? - NULL : PeriodicTask_lock, Mutex::_no_safepoint_check_flag); + NULL : PeriodicTask_lock); if (_num_tasks == PeriodicTask::max_tasks) { fatal("Overflow in PeriodicTask table"); @@ -131,9 +133,11 @@ } } +/* disenroll could be called from a JavaThread, so we have to check for + * safepoint when taking the lock to avoid deadlocking */ void PeriodicTask::disenroll() { MutexLockerEx ml(PeriodicTask_lock->owned_by_self() ? - NULL : PeriodicTask_lock, Mutex::_no_safepoint_check_flag); + NULL : PeriodicTask_lock); int index; for(index = 0; index < _num_tasks && _tasks[index] != this; index++) diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/runtime/thread.cpp --- a/src/share/vm/runtime/thread.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/runtime/thread.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -77,7 +77,8 @@ #include "services/management.hpp" #include "services/memTracker.hpp" #include "services/threadService.hpp" -#include "trace/traceEventTypes.hpp" +#include "trace/tracing.hpp" +#include "trace/traceMacros.hpp" #include "utilities/defaultStream.hpp" #include "utilities/dtrace.hpp" #include "utilities/events.hpp" @@ -238,7 +239,6 @@ CHECK_UNHANDLED_OOPS_ONLY(_gc_locked_out_count = 0;) _jvmti_env_iteration_count = 0; set_allocated_bytes(0); - set_trace_buffer(NULL); _vm_operation_started_count = 0; _vm_operation_completed_count = 0; _current_pending_monitor = NULL; @@ -1659,9 +1659,11 @@ JvmtiExport::post_thread_start(this); } - EVENT_BEGIN(TraceEventThreadStart, event); - EVENT_COMMIT(event, - EVENT_SET(event, javalangthread, java_lang_Thread::thread_id(this->threadObj()))); + EventThreadStart event; + if (event.should_commit()) { + event.set_javalangthread(java_lang_Thread::thread_id(this->threadObj())); + event.commit(); + } // We call another function to do the rest so we are sure that the stack addresses used // from there will be lower than the stack base just computed @@ -1791,9 +1793,11 @@ // Called before the java thread exit since we want to read info // from java_lang_Thread object - EVENT_BEGIN(TraceEventThreadEnd, event); - EVENT_COMMIT(event, - EVENT_SET(event, javalangthread, java_lang_Thread::thread_id(this->threadObj()))); + EventThreadEnd event; + if (event.should_commit()) { + event.set_javalangthread(java_lang_Thread::thread_id(this->threadObj())); + event.commit(); + } // Call after last event on thread EVENT_THREAD_EXIT(this); @@ -3648,8 +3652,8 @@ // Notify JVMTI agents that VM initialization is complete - nop if no agents. JvmtiExport::post_vm_initialized(); - if (!TRACE_START()) { - vm_exit_during_initialization(Handle(THREAD, PENDING_EXCEPTION)); + if (TRACE_START() != JNI_OK) { + vm_exit_during_initialization("Failed to start tracing backend."); } if (CleanChunkPoolAsync) { diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/runtime/thread.hpp --- a/src/share/vm/runtime/thread.hpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/runtime/thread.hpp Fri Jun 21 15:56:24 2013 -0700 @@ -47,7 +47,8 @@ #include "services/memRecorder.hpp" #endif // INCLUDE_NMT -#include "trace/tracing.hpp" +#include "trace/traceBackend.hpp" +#include "trace/traceMacros.hpp" #include "utilities/exceptions.hpp" #include "utilities/top.hpp" #if INCLUDE_ALL_GCS @@ -258,7 +259,7 @@ jlong _allocated_bytes; // Cumulative number of bytes allocated on // the Java heap - TRACE_BUFFER _trace_buffer; // Thread-local buffer for tracing + TRACE_DATA _trace_data; // Thread-local data for tracing int _vm_operation_started_count; // VM_Operation support int _vm_operation_completed_count; // VM_Operation support @@ -449,8 +450,7 @@ return allocated_bytes; } - TRACE_BUFFER trace_buffer() { return _trace_buffer; } - void set_trace_buffer(TRACE_BUFFER buf) { _trace_buffer = buf; } + TRACE_DATA* trace_data() { return &_trace_data; } // VM operation support int vm_operation_ticket() { return ++_vm_operation_started_count; } @@ -638,9 +638,6 @@ jint _hashStateZ ; void * _schedctl ; - intptr_t _ScratchA, _ScratchB ; // Scratch locations for fast-path sync code - static ByteSize ScratchA_offset() { return byte_offset_of(Thread, _ScratchA ); } - static ByteSize ScratchB_offset() { return byte_offset_of(Thread, _ScratchB ); } volatile jint rng [4] ; // RNG for spin loop diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/runtime/timer.cpp --- a/src/share/vm/runtime/timer.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/runtime/timer.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 @@ -39,6 +39,11 @@ # include "os_bsd.inline.hpp" #endif +double TimeHelper::counter_to_seconds(jlong counter) { + double count = (double) counter; + double freq = (double) os::elapsed_frequency(); + return counter/freq; +} void elapsedTimer::add(elapsedTimer t) { _counter += t._counter; @@ -59,9 +64,7 @@ } double elapsedTimer::seconds() const { - double count = (double) _counter; - double freq = (double) os::elapsed_frequency(); - return count/freq; + return TimeHelper::counter_to_seconds(_counter); } jlong elapsedTimer::milliseconds() const { @@ -90,9 +93,7 @@ double TimeStamp::seconds() const { assert(is_updated(), "must not be clear"); jlong new_count = os::elapsed_counter(); - double count = (double) new_count - _counter; - double freq = (double) os::elapsed_frequency(); - return count/freq; + return TimeHelper::counter_to_seconds(new_count - _counter); } jlong TimeStamp::milliseconds() const { @@ -110,19 +111,15 @@ } TraceTime::TraceTime(const char* title, - bool doit, - bool print_cr, - outputStream* logfile) { + bool doit) { _active = doit; _verbose = true; - _print_cr = print_cr; - _logfile = (logfile != NULL) ? logfile : tty; if (_active) { _accum = NULL; - _logfile->stamp(PrintGCTimeStamps); - _logfile->print("[%s", title); - _logfile->flush(); + tty->stamp(PrintGCTimeStamps); + tty->print("[%s", title); + tty->flush(); _t.start(); } } @@ -130,17 +127,14 @@ TraceTime::TraceTime(const char* title, elapsedTimer* accumulator, bool doit, - bool verbose, - outputStream* logfile) { + bool verbose) { _active = doit; _verbose = verbose; - _print_cr = true; - _logfile = (logfile != NULL) ? logfile : tty; if (_active) { if (_verbose) { - _logfile->stamp(PrintGCTimeStamps); - _logfile->print("[%s", title); - _logfile->flush(); + tty->stamp(PrintGCTimeStamps); + tty->print("[%s", title); + tty->flush(); } _accum = accumulator; _t.start(); @@ -152,12 +146,8 @@ _t.stop(); if (_accum!=NULL) _accum->add(_t); if (_verbose) { - if (_print_cr) { - _logfile->print_cr(", %3.7f secs]", _t.seconds()); - } else { - _logfile->print(", %3.7f secs]", _t.seconds()); - } - _logfile->flush(); + tty->print_cr(", %3.7f secs]", _t.seconds()); + tty->flush(); } } } diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/runtime/timer.hpp --- a/src/share/vm/runtime/timer.hpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/runtime/timer.hpp Fri Jun 21 15:56:24 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -82,21 +82,16 @@ private: bool _active; // do timing bool _verbose; // report every timing - bool _print_cr; // add a CR to the end of the timer report elapsedTimer _t; // timer elapsedTimer* _accum; // accumulator - outputStream* _logfile; // output log file public: - // Constuctors + // Constructors TraceTime(const char* title, - bool doit = true, - bool print_cr = true, - outputStream *logfile = NULL); + bool doit = true); TraceTime(const char* title, elapsedTimer* accumulator, bool doit = true, - bool verbose = false, - outputStream *logfile = NULL ); + bool verbose = false); ~TraceTime(); // Accessors @@ -125,4 +120,9 @@ ~TraceCPUTime(); }; +class TimeHelper { + public: + static double counter_to_seconds(jlong counter); +}; + #endif // SHARE_VM_RUNTIME_TIMER_HPP diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/runtime/vmStructs.cpp --- a/src/share/vm/runtime/vmStructs.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/runtime/vmStructs.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -60,6 +60,7 @@ #include "memory/generationSpec.hpp" #include "memory/heap.hpp" #include "memory/metablock.hpp" +#include "memory/referenceType.hpp" #include "memory/space.hpp" #include "memory/tenuredGeneration.hpp" #include "memory/universe.hpp" @@ -295,10 +296,8 @@ nonstatic_field(InstanceKlass, _transitive_interfaces, Array*) \ nonstatic_field(InstanceKlass, _fields, Array*) \ nonstatic_field(InstanceKlass, _java_fields_count, u2) \ - nonstatic_field(InstanceKlass, _constants, ConstantPool*) \ + nonstatic_field(InstanceKlass, _constants, ConstantPool*) \ nonstatic_field(InstanceKlass, _class_loader_data, ClassLoaderData*) \ - nonstatic_field(InstanceKlass, _protection_domain, oop) \ - nonstatic_field(InstanceKlass, _signers, objArrayOop) \ nonstatic_field(InstanceKlass, _source_file_name, Symbol*) \ nonstatic_field(InstanceKlass, _source_debug_extension, char*) \ nonstatic_field(InstanceKlass, _inner_classes, Array*) \ diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/runtime/vmThread.cpp --- a/src/share/vm/runtime/vmThread.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/runtime/vmThread.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -35,6 +35,7 @@ #include "runtime/vmThread.hpp" #include "runtime/vm_operations.hpp" #include "services/runtimeService.hpp" +#include "trace/tracing.hpp" #include "utilities/dtrace.hpp" #include "utilities/events.hpp" #include "utilities/xmlstream.hpp" @@ -365,7 +366,23 @@ (char *) op->name(), strlen(op->name()), op->evaluation_mode()); #endif /* USDT2 */ + + EventExecuteVMOperation event; + op->evaluate(); + + if (event.should_commit()) { + bool is_concurrent = op->evaluate_concurrently(); + event.set_operation(op->type()); + event.set_safepoint(op->evaluate_at_safepoint()); + event.set_blocking(!is_concurrent); + // Only write caller thread information for non-concurrent vm operations. + // For concurrent vm operations, the thread id is set to 0 indicating thread is unknown. + // This is because the caller thread could have exited already. + event.set_caller(is_concurrent ? 0 : op->calling_thread()->osthread()->thread_id()); + event.commit(); + } + #ifndef USDT2 HS_DTRACE_PROBE3(hotspot, vmops__end, op->name(), strlen(op->name()), op->evaluation_mode()); @@ -601,7 +618,7 @@ { VMOperationQueue_lock->lock_without_safepoint_check(); bool ok = _vm_queue->add(op); - op->set_timestamp(os::javaTimeMillis()); + op->set_timestamp(os::javaTimeMillis()); VMOperationQueue_lock->notify(); VMOperationQueue_lock->unlock(); // VM_Operation got skipped diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/runtime/vm_operations.cpp --- a/src/share/vm/runtime/vm_operations.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/runtime/vm_operations.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,6 +37,7 @@ #include "runtime/thread.inline.hpp" #include "runtime/vm_operations.hpp" #include "services/threadService.hpp" +#include "trace/tracing.hpp" #define VM_OP_NAME_INITIALIZE(name) #name, @@ -62,19 +63,21 @@ } } +const char* VM_Operation::mode_to_string(Mode mode) { + switch(mode) { + case _safepoint : return "safepoint"; + case _no_safepoint : return "no safepoint"; + case _concurrent : return "concurrent"; + case _async_safepoint: return "async safepoint"; + default : return "unknown"; + } +} // Called by fatal error handler. void VM_Operation::print_on_error(outputStream* st) const { st->print("VM_Operation (" PTR_FORMAT "): ", this); st->print("%s", name()); - const char* mode; - switch(evaluation_mode()) { - case _safepoint : mode = "safepoint"; break; - case _no_safepoint : mode = "no safepoint"; break; - case _concurrent : mode = "concurrent"; break; - case _async_safepoint: mode = "async safepoint"; break; - default : mode = "unknown"; break; - } + const char* mode = mode_to_string(evaluation_mode()); st->print(", mode: %s", mode); if (calling_thread()) { diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/runtime/vm_operations.hpp --- a/src/share/vm/runtime/vm_operations.hpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/runtime/vm_operations.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 @@ -178,6 +178,8 @@ evaluation_mode() == _async_safepoint; } + static const char* mode_to_string(Mode mode); + // Debugging void print_on_error(outputStream* st) const; const char* name() const { return _names[type()]; } diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/services/attachListener.cpp --- a/src/share/vm/services/attachListener.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/services/attachListener.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -227,7 +227,7 @@ } live_objects_only = strcmp(arg0, "-live") == 0; } - VM_GC_HeapInspection heapop(out, live_objects_only /* request full gc */, true /* need_prologue */); + VM_GC_HeapInspection heapop(out, live_objects_only /* request full gc */); VMThread::execute(&heapop); return JNI_OK; } diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/services/diagnosticArgument.cpp --- a/src/share/vm/services/diagnosticArgument.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/services/diagnosticArgument.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "memory/allocation.inline.hpp" +#include "memory/resourceArea.hpp" #include "runtime/thread.hpp" #include "services/diagnosticArgument.hpp" @@ -86,9 +87,18 @@ template <> void DCmdArgument::parse_value(const char* str, size_t len, TRAPS) { - if (str == NULL || sscanf(str, JLONG_FORMAT, &_value) != 1) { - THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), - "Integer parsing error in diagnostic command arguments\n"); + int scanned = -1; + if (str == NULL + || sscanf(str, JLONG_FORMAT"%n", &_value, &scanned) != 1 + || (size_t)scanned != len) + { + ResourceMark rm; + + char* buf = NEW_RESOURCE_ARRAY(char, len + 1); + strncpy(buf, str, len); + buf[len] = '\0'; + Exceptions::fthrow(THREAD_AND_LOCATION, vmSymbols::java_lang_IllegalArgumentException(), + "Integer parsing error in command argument '%s'. Could not parse: %s.", _name, buf); } } @@ -96,7 +106,7 @@ if (has_default()) { this->parse_value(_default_string, strlen(_default_string), THREAD); if (HAS_PENDING_EXCEPTION) { - fatal("Default string must be parsable"); + fatal("Default string must be parseable"); } } else { set_value(0); @@ -116,8 +126,13 @@ } else if (len == strlen("false") && strncasecmp(str, "false", len) == 0) { set_value(false); } else { - THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), - "Boolean parsing error in diagnostic command arguments"); + ResourceMark rm; + + char* buf = NEW_RESOURCE_ARRAY(char, len + 1); + strncpy(buf, str, len); + buf[len] = '\0'; + Exceptions::fthrow(THREAD_AND_LOCATION, vmSymbols::java_lang_IllegalArgumentException(), + "Boolean parsing error in command argument '%s'. Could not parse: %s.", _name, buf); } } } @@ -168,7 +183,7 @@ size_t len, TRAPS) { if (str == NULL) { THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), - "Integer parsing error nanotime value: syntax error"); + "Integer parsing error nanotime value: syntax error, value is null"); } int argc = sscanf(str, JLONG_FORMAT, &_value._time); diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/services/diagnosticCommand.cpp --- a/src/share/vm/services/diagnosticCommand.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/services/diagnosticCommand.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -320,8 +320,7 @@ void ClassHistogramDCmd::execute(DCmdSource source, TRAPS) { VM_GC_HeapInspection heapop(output(), - !_all.value() /* request full gc if false */, - true /* need_prologue */); + !_all.value() /* request full gc if false */); VMThread::execute(&heapop); } @@ -361,8 +360,7 @@ } VM_GC_HeapInspection heapop(output(), - true, /* request_full_gc */ - true /* need_prologue */); + true /* request_full_gc */); heapop.set_csv_format(_csv.value()); heapop.set_print_help(_help.value()); heapop.set_print_class_stats(true); diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/services/memBaseline.cpp --- a/src/share/vm/services/memBaseline.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/services/memBaseline.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -41,6 +41,7 @@ {mtOther, "Other"}, {mtSymbol, "Symbol"}, {mtNMT, "Memory Tracking"}, + {mtTracing, "Tracing"}, {mtChunk, "Pooled Free Chunks"}, {mtClassShared,"Shared spaces for classes"}, {mtTest, "Test"}, diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/services/memTracker.cpp --- a/src/share/vm/services/memTracker.cpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/services/memTracker.cpp Fri Jun 21 15:56:24 2013 -0700 @@ -34,6 +34,7 @@ #include "services/memReporter.hpp" #include "services/memTracker.hpp" #include "utilities/decoder.hpp" +#include "utilities/defaultStream.hpp" #include "utilities/globalDefinitions.hpp" bool NMT_track_callsite = false; @@ -77,7 +78,15 @@ if (strcmp(option_line, "=summary") == 0) { _tracking_level = NMT_summary; } else if (strcmp(option_line, "=detail") == 0) { - _tracking_level = NMT_detail; + // detail relies on a stack-walking ability that may not + // be available depending on platform and/or compiler flags + if (PLATFORM_NMT_DETAIL_SUPPORTED) { + _tracking_level = NMT_detail; + } else { + jio_fprintf(defaultStream::error_stream(), + "NMT detail is not supported on this platform. Using NMT summary instead."); + _tracking_level = NMT_summary; + } } else if (strcmp(option_line, "=off") != 0) { vm_exit_during_initialization("Syntax error, expecting -XX:NativeMemoryTracking=[off|summary|detail]", NULL); } diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/trace/noTraceBackend.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/trace/noTraceBackend.hpp Fri Jun 21 15:56:24 2013 -0700 @@ -0,0 +1,48 @@ +/* + * 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_TRACE_NOTRACEBACKEND_HPP +#define SHARE_VM_TRACE_NOTRACEBACKEND_HPP + +#include "prims/jni.h" + +typedef jlong TracingTime; +typedef jlong RelativeTracingTime; + +class NoTraceBackend { +public: + static TracingTime time() { + return 0; + } +}; + +class TraceThreadData { +public: + TraceThreadData() {} +}; + +typedef NoTraceBackend Tracing; + +#endif + + diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/trace/trace.dtd --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/trace/trace.dtd Fri Jun 21 15:56:24 2013 -0700 @@ -0,0 +1,86 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/trace/trace.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/trace/trace.xml Fri Jun 21 15:56:24 2013 -0700 @@ -0,0 +1,367 @@ + + + + + +%xinclude; +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/trace/traceBackend.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/trace/traceBackend.hpp Fri Jun 21 15:56:24 2013 -0700 @@ -0,0 +1,70 @@ +/* + * 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_TRACE_TRACEBACKEND_HPP +#define SHARE_VM_TRACE_TRACEBACKEND_HPP + +#include "utilities/macros.hpp" + +#if INCLUDE_TRACE + +#include "runtime/globals.hpp" +#include "runtime/os.hpp" +#include "trace/traceTime.hpp" +#include "tracefiles/traceEventIds.hpp" + +class TraceBackend { +public: + static bool enabled(void) { + return EnableTracing; + } + + static bool is_event_enabled(TraceEventId id) { + return enabled(); + } + + static TracingTime time() { + return os::elapsed_counter(); + } + + static TracingTime time_adjustment(jlong time) { + return time; + } + + static void on_unloading_classes(void) { + } +}; + +class TraceThreadData { +public: + TraceThreadData() {} +}; + +typedef TraceBackend Tracing; + +#else /* INCLUDE_TRACE */ + +#include "trace/noTraceBackend.hpp" + +#endif /* INCLUDE_TRACE */ +#endif /* SHARE_VM_TRACE_TRACEBACKEND_HPP */ diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/trace/traceDataTypes.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/trace/traceDataTypes.hpp Fri Jun 21 15:56:24 2013 -0700 @@ -0,0 +1,67 @@ +/* + * 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_TRACE_TRACEDATATYPES_HPP +#define SHARE_VM_TRACE_TRACEDATATYPES_HPP + +#include + +#include "utilities/globalDefinitions.hpp" + +enum { + CONTENT_TYPE_NONE = 0, + CONTENT_TYPE_BYTES = 1, + CONTENT_TYPE_EPOCHMILLIS = 2, + CONTENT_TYPE_MILLIS = 3, + CONTENT_TYPE_NANOS = 4, + CONTENT_TYPE_TICKS = 5, + CONTENT_TYPE_ADDRESS = 6, + + CONTENT_TYPE_OSTHREAD, + CONTENT_TYPE_JAVALANGTHREAD, + CONTENT_TYPE_STACKTRACE, + CONTENT_TYPE_CLASS, + CONTENT_TYPE_PERCENTAGE, + + JVM_CONTENT_TYPES_START = 30, + JVM_CONTENT_TYPES_END = 100 +}; + +enum ReservedEvent { + EVENT_PRODUCERS, + EVENT_CHECKPOINT, + EVENT_BUFFERLOST, + + NUM_RESERVED_EVENTS +}; + +typedef enum ReservedEvent ReservedEvent; + +typedef u8 classid; +typedef u8 stacktraceid; +typedef u8 methodid; +typedef u8 fieldid; + +#endif // SHARE_VM_TRACE_TRACEDATATYPES_HPP + diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/trace/traceEvent.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/trace/traceEvent.hpp Fri Jun 21 15:56:24 2013 -0700 @@ -0,0 +1,150 @@ +/* + * 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_TRACE_TRACEEVENT_HPP +#define SHARE_VM_TRACE_TRACEEVENT_HPP + +enum EventStartTime { + UNTIMED, + TIMED +}; + +#include "utilities/macros.hpp" + +#if INCLUDE_TRACE + +#include "trace/traceBackend.hpp" +#include "trace/tracing.hpp" +#include "tracefiles/traceEventIds.hpp" +#include "tracefiles/traceTypes.hpp" + +template +class TraceEvent : public StackObj { + protected: + jlong _startTime; + jlong _endTime; + + private: + bool _started; +#ifdef ASSERT + bool _committed; + bool _cancelled; + protected: + bool _ignore_check; +#endif + + public: + TraceEvent(EventStartTime timing=TIMED) : + _startTime(0), + _endTime(0), + _started(false) +#ifdef ASSERT + , + _committed(false), + _cancelled(false), + _ignore_check(false) +#endif + { + if (T::is_enabled()) { + _started = true; + if (timing == TIMED && !T::isInstant) { + static_cast(this)->set_starttime(Tracing::time()); + } + } + } + + static bool is_enabled() { + return Tracing::is_event_enabled(T::eventId); + } + + bool should_commit() { + return _started; + } + + void ignoreCheck() { + DEBUG_ONLY(_ignore_check = true); + } + + void commit() { + if (!should_commit()) { + cancel(); + return; + } + if (_endTime == 0) { + static_cast(this)->set_endtime(Tracing::time()); + } + if (static_cast(this)->should_write()) { + static_cast(this)->writeEvent(); + } + set_commited(); + } + + void set_starttime(jlong time) { + _startTime = time; + } + + void set_endtime(jlong time) { + _endTime = time; + } + + TraceEventId id() const { + return T::eventId; + } + + bool is_instant() const { + return T::isInstant; + } + + bool is_requestable() const { + return T::isRequestable; + } + + bool has_thread() const { + return T::hasThread; + } + + bool has_stacktrace() const { + return T::hasStackTrace; + } + + void cancel() { + assert(!_committed && !_cancelled, "event was already committed/cancelled"); + DEBUG_ONLY(_cancelled = true); + } + + void set_commited() { + assert(!_committed, "event has already been committed"); + DEBUG_ONLY(_committed = true); + } + + ~TraceEvent() { + if (_started) { + assert(_ignore_check || _committed || _cancelled, "event was not committed/cancelled"); + } + } +}; + +#endif /* INCLUDE_TRACE */ + +#endif /* SHARE_VM_TRACE_TRACEEVENT_HPP */ diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/trace/traceEventClasses.xsl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/trace/traceEventClasses.xsl Fri Jun 21 15:56:24 2013 -0700 @@ -0,0 +1,246 @@ + + + + + + + + + + +#ifndef TRACEFILES_TRACEEVENTCLASSES_HPP +#define TRACEFILES_TRACEEVENTCLASSES_HPP + +// On purpose outside the INCLUDE_TRACE +// Some parts of traceEvent.hpp are used outside of +// INCLUDE_TRACE + +#include "memory/resourceArea.hpp" +#include "tracefiles/traceTypes.hpp" +#include "trace/traceEvent.hpp" +#include "utilities/macros.hpp" + +#if INCLUDE_TRACE + + +#include "trace/traceStream.hpp" +#include "utilities/ostream.hpp" + + + + +#else + +class TraceEvent { +public: + TraceEvent() {} + void set_starttime(jlong time) const {} + void set_endtime(jlong time) const {} + bool should_commit() const { return false; } + void commit() const {} +}; + + + + +#endif + +#endif + + + +struct TraceStruct +{ +private: + +public: + + + void writeStruct(TraceStream& ts) { + + } +}; + + + + +struct TraceStruct +{ +public: + +}; + + + + + +{ + public: + + + + + +}; + + + + + + +{ + public: + static const bool hasThread = ; + static const bool hasStackTrace = ; + static const bool isInstant = ; + static const bool isRequestable = ; + static const TraceEventId eventId = ; + + private: + + + void writeEventContent(void) { + TraceStream ts(*tty); + ts.print(": ["); + + ts.print("]\n"); + } + + public: + + + bool should_write(void) { + return true; + } + + + + + void writeEvent(void) { + ResourceMark rm; + if (UseLockedTracing) { + ttyLocker lock; + writeEventContent(); + } else { + writeEventContent(); + } + } +}; + + + + + + + + + + + + + + + + + + + + + + + + + +#if INCLUDE_TRACE + +#else + +#endif + + + +#if INCLUDE_TRACE + +#else + +#endif + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ts.print(", "); + + + + + + + + + ts.print(", "); + + + + + diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/trace/traceEventIds.xsl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/trace/traceEventIds.xsl Fri Jun 21 15:56:24 2013 -0700 @@ -0,0 +1,74 @@ + + + + + + + + + + +#ifndef TRACEFILES_JFREVENTIDS_HPP +#define TRACEFILES_JFREVENTIDS_HPP + +#include "utilities/macros.hpp" + +#if INCLUDE_TRACE + +#include "trace/traceDataTypes.hpp" + +/** + * Enum of the event types in the JVM + */ +enum TraceEventId { + _traceeventbase = (NUM_RESERVED_EVENTS-1), // Make sure we start at right index. + + // Events -> enum entry + + + + MaxTraceEventId +}; + +/** + * Struct types in the JVM + */ +enum TraceStructId { + + + + + + + MaxTraceStructId +}; + +typedef enum TraceEventId TraceEventId; +typedef enum TraceStructId TraceStructId; + +#endif +#endif + + + diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/trace/traceEventTypes.hpp --- a/src/share/vm/trace/traceEventTypes.hpp Thu Jun 20 16:30:44 2013 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,30 +0,0 @@ -/* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#ifndef SHARE_VM_TRACE_TRACE_EVENT_TYPES_HPP -#define SHARE_VM_TRACE_TRACE_EVENT_TYPES_HPP - -/* Empty, just a placeholder for tracing events */ - -#endif diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/trace/traceMacros.hpp --- a/src/share/vm/trace/traceMacros.hpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/trace/traceMacros.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) 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 @@ -25,22 +25,14 @@ #ifndef SHARE_VM_TRACE_TRACE_MACRO_HPP #define SHARE_VM_TRACE_TRACE_MACRO_HPP -#define EVENT_BEGIN(type, name) -#define EVENT_SET(name, field, value) -#define EVENT_COMMIT(name, ...) -#define EVENT_STARTED(name, time) -#define EVENT_ENDED(name, time) #define EVENT_THREAD_EXIT(thread) -#define TRACE_ENABLED 0 - #define TRACE_INIT_ID(k) -#define TRACE_BUFFER void* +#define TRACE_DATA TraceThreadData -#define TRACE_START() true -#define TRACE_INITIALIZE() 0 +#define TRACE_START() JNI_OK +#define TRACE_INITIALIZE() JNI_OK -#define TRACE_SET_KLASS_TRACE_ID(x1, x2) do { } while (0) #define TRACE_DEFINE_KLASS_METHODS typedef int ___IGNORED_hs_trace_type1 #define TRACE_DEFINE_KLASS_TRACE_ID typedef int ___IGNORED_hs_trace_type2 #define TRACE_DEFINE_OFFSET typedef int ___IGNORED_hs_trace_type3 diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/trace/traceStream.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/trace/traceStream.hpp Fri Jun 21 15:56:24 2013 -0700 @@ -0,0 +1,121 @@ +/* + * 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_TRACE_TRACESTREAM_HPP +#define SHARE_VM_TRACE_TRACESTREAM_HPP + +#include "utilities/macros.hpp" + +#if INCLUDE_TRACE + +#include "oops/klass.hpp" +#include "oops/method.hpp" +#include "oops/symbol.hpp" +#include "utilities/ostream.hpp" + +class TraceStream : public StackObj { + private: + outputStream& _st; + + public: + TraceStream(outputStream& stream): _st(stream) {} + + void print_val(const char* label, u1 val) { + _st.print("%s = "UINT32_FORMAT, label, val); + } + + void print_val(const char* label, u2 val) { + _st.print("%s = "UINT32_FORMAT, label, val); + } + + void print_val(const char* label, s2 val) { + _st.print("%s = "INT32_FORMAT, label, val); + } + + void print_val(const char* label, u4 val) { + _st.print("%s = "UINT32_FORMAT, label, val); + } + + void print_val(const char* label, s4 val) { + _st.print("%s = "INT32_FORMAT, label, val); + } + + void print_val(const char* label, u8 val) { + _st.print("%s = "UINT64_FORMAT, label, val); + } + + void print_val(const char* label, s8 val) { + _st.print("%s = "INT64_FORMAT, label, val); + } + + void print_val(const char* label, bool val) { + _st.print("%s = %s", label, val ? "true" : "false"); + } + + void print_val(const char* label, float val) { + _st.print("%s = %f", label, val); + } + + void print_val(const char* label, double val) { + _st.print("%s = %f", label, val); + } + + // Caller is machine generated code located in traceEventClasses.hpp + // Event::writeEvent() (pseudocode) contains the + // necessary ResourceMark for the resource allocations below. + // See traceEventClasses.xsl for details. + void print_val(const char* label, const Klass* const val) { + const char* description = "NULL"; + if (val != NULL) { + Symbol* name = val->name(); + if (name != NULL) { + description = name->as_C_string(); + } + } + _st.print("%s = %s", label, description); + } + + // Caller is machine generated code located in traceEventClasses.hpp + // Event::writeEvent() (pseudocode) contains the + // necessary ResourceMark for the resource allocations below. + // See traceEventClasses.xsl for details. + void print_val(const char* label, const Method* const val) { + const char* description = "NULL"; + if (val != NULL) { + description = val->name_and_sig_as_C_string(); + } + _st.print("%s = %s", label, description); + } + + void print_val(const char* label, const char* val) { + _st.print("%s = '%s'", label, val); + } + + void print(const char* val) { + _st.print(val); + } +}; + +#endif /* INCLUDE_TRACE */ +#endif /* SHARE_VM_TRACE_TRACESTREAM_HPP */ diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/trace/traceTime.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/trace/traceTime.hpp Fri Jun 21 15:56:24 2013 -0700 @@ -0,0 +1,33 @@ +/* + * 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_TRACE_TRACETIME_HPP +#define SHARE_VM_TRACE_TRACETIME_HPP + +#include "prims/jni.h" + +typedef jlong TracingTime; +typedef jlong RelativeTracingTime; + +#endif diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/trace/traceTypes.xsl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/trace/traceTypes.xsl Fri Jun 21 15:56:24 2013 -0700 @@ -0,0 +1,72 @@ + + + + + + + + + + +#ifndef TRACEFILES_JFRTYPES_HPP +#define TRACEFILES_JFRTYPES_HPP + +#include "trace/traceDataTypes.hpp" +#include "utilities/globalDefinitions.hpp" +#include "oops/symbol.hpp" + +enum JVMContentType { + _not_a_content_type = (JVM_CONTENT_TYPES_START - 1), + + + + + NUM_JVM_CONTENT_TYPES +}; + + +enum JVMEventRelations { + JVM_REL_NOT_AVAILABLE = 0, + + + + + NUM_EVENT_RELATIONS +}; + +/** + * Create typedefs for the JRA types: + * typedef s8 TYPE_LONG; + * typedef s4 TYPE_INTEGER; + * typedef const char * TYPE_STRING; + * ... + */ + +typedef TYPE_; + + +#endif // JFRFILES_JFRTYPES_HPP + + + diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/trace/tracetypes.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/trace/tracetypes.xml Fri Jun 21 15:56:24 2013 -0700 @@ -0,0 +1,368 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/trace/tracing.hpp --- a/src/share/vm/trace/tracing.hpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/trace/tracing.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) 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 @@ -25,6 +25,7 @@ #ifndef SHARE_VM_TRACE_TRACING_HPP #define SHARE_VM_TRACE_TRACING_HPP -#include "trace/traceMacros.hpp" +#include "tracefiles/traceEventClasses.hpp" +#include "tracefiles/traceEventIds.hpp" #endif diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/trace/xinclude.mod --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/trace/xinclude.mod Fri Jun 21 15:56:24 2013 -0700 @@ -0,0 +1,61 @@ + + + + + + + + + diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/trace/xsl_util.xsl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/trace/xsl_util.xsl Fri Jun 21 15:56:24 2013 -0700 @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + " + + + + /* AUTOMATICALLY GENERATED FILE - DO NOT EDIT */ + + + + + + + + + + + + + + + + + + + + + + + + diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/utilities/array.hpp --- a/src/share/vm/utilities/array.hpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/utilities/array.hpp Fri Jun 21 15:56:24 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -320,7 +320,7 @@ void* operator new(size_t size, ClassLoaderData* loader_data, int length, bool read_only, TRAPS) { size_t word_size = Array::size(length); return (void*) Metaspace::allocate(loader_data, word_size, read_only, - Metaspace::NonClassType, CHECK_NULL); + MetaspaceObj::array_type(sizeof(T)), CHECK_NULL); } static size_t byte_sizeof(int length) { return sizeof(Array) + MAX2(length - 1, 0) * sizeof(T); } diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/utilities/globalDefinitions.hpp --- a/src/share/vm/utilities/globalDefinitions.hpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/utilities/globalDefinitions.hpp Fri Jun 21 15:56:24 2013 -0700 @@ -380,6 +380,14 @@ # include "globalDefinitions_ppc.hpp" #endif +/* + * If a platform does not support NMT_detail + * the platform specific globalDefinitions (above) + * can set PLATFORM_NMT_DETAIL_SUPPORTED to false + */ +#ifndef PLATFORM_NMT_DETAIL_SUPPORTED +#define PLATFORM_NMT_DETAIL_SUPPORTED true +#endif // The byte alignment to be used by Arena::Amalloc. See bugid 4169348. // Note: this value must be a power of 2 @@ -755,18 +763,6 @@ TosState as_TosState(BasicType type); -// ReferenceType is used to distinguish between java/lang/ref/Reference subclasses - -enum ReferenceType { - REF_NONE, // Regular class - REF_OTHER, // Subclass of java/lang/ref/Reference, but not subclass of one of the classes below - REF_SOFT, // Subclass of java/lang/ref/SoftReference - REF_WEAK, // Subclass of java/lang/ref/WeakReference - REF_FINAL, // Subclass of java/lang/ref/FinalReference - REF_PHANTOM // Subclass of java/lang/ref/PhantomReference -}; - - // JavaThreadState keeps track of which part of the code a thread is executing in. This // information is needed by the safepoint code. // diff -r d2907f74462e -r b5c8a61d7fa0 src/share/vm/utilities/macros.hpp --- a/src/share/vm/utilities/macros.hpp Thu Jun 20 16:30:44 2013 -0700 +++ b/src/share/vm/utilities/macros.hpp Fri Jun 21 15:56:24 2013 -0700 @@ -160,6 +160,10 @@ #define NOT_NMT_RETURN_(code) { return code; } #endif // INCLUDE_NMT +#ifndef INCLUDE_TRACE +#define INCLUDE_TRACE 1 +#endif // INCLUDE_TRACE + // COMPILER1 variant #ifdef COMPILER1 #ifdef COMPILER2 diff -r d2907f74462e -r b5c8a61d7fa0 test/compiler/8011771/Test8011771.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/8011771/Test8011771.java Fri Jun 21 15:56:24 2013 -0700 @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8011771 + * @summary Array bound check elimination's in block motion doesn't always reset its data structures from one step to the other. + * @run main/othervm -XX:-BackgroundCompilation Test8011771 + * + */ + +public class Test8011771 { + + static void m(int[] a, int[] b, int j) { + // Array bound check elimination inserts a predicate before + // the loop. We'll have the predicate fail, so the method is + // recompiled without optimistic optimizations + for (int i = 0; i < 10; i++) { + a[i] = i; + } + + // The test itself + a[j] = 0; + a[j+5] = 0; + b[j+4] = 0; // this range check shouldn't be eliminated + } + + static public void main(String[] args) { + int[] arr1 = new int[10], arr2 = new int[10]; + // force compilation: + for (int i = 0; i < 5000; i++) { + m(arr1, arr2, 0); + } + + try { + m(new int[1], null, 0); // force predicate failure + } catch(ArrayIndexOutOfBoundsException e) {} + + // force compilation again (no optimistic opts): + for (int i = 0; i < 5000; i++) { + m(arr1, arr2, 0); + } + + // Check that the range check on the second array wasn't optimized out + boolean success = false; + try { + m(arr1, new int[1], 0); + } catch(ArrayIndexOutOfBoundsException e) { + success = true; + } + if (success) { + System.out.println("TEST PASSED"); + } else { + throw new RuntimeException("TEST FAILED: erroneous bound check elimination"); + } + } +} diff -r d2907f74462e -r b5c8a61d7fa0 test/compiler/8013496/Test8013496.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/8013496/Test8013496.sh Fri Jun 21 15:56:24 2013 -0700 @@ -0,0 +1,55 @@ +#!/bin/sh +# +# Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# +# +# @test +# @bug 8013496 +# @summary Test checks that the order in which ReversedCodeCacheSize and +# InitialCodeCacheSize are passed to the VM is irrelevant. +# @run shell Test8013496.sh +# +# +## some tests require path to find test source dir +if [ "${TESTSRC}" = "" ] +then + TESTSRC=${PWD} + echo "TESTSRC not set. Using "${TESTSRC}" as default" +fi +echo "TESTSRC=${TESTSRC}" +## Adding common setup Variables for running shell tests. +. ${TESTSRC}/../../test_env.sh +set -x + +${TESTJAVA}/bin/java ${TESTVMOPTS} -XX:ReservedCodeCacheSize=2m -XX:InitialCodeCacheSize=500K -version > 1.out 2>&1 +${TESTJAVA}/bin/java ${TESTVMOPTS} -XX:InitialCodeCacheSize=500K -XX:ReservedCodeCacheSize=2m -version > 2.out 2>&1 + +diff 1.out 2.out + +result=$? +if [ $result -eq 0 ] ; then + echo "Test Passed" + exit 0 +else + echo "Test Failed" + exit 1 +fi diff -r d2907f74462e -r b5c8a61d7fa0 test/compiler/8015436/Test8015436.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/8015436/Test8015436.java Fri Jun 21 15:56:24 2013 -0700 @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8015436 + * @summary the IK _initial_method_idnum value must be adjusted if overpass methods are added + * @run main Test8015436 + * + */ + +/* + * The test checks that a MemberName for the defaultMethod() is cached in + * the class MemberNameTable without a crash in the VM fastdebug mode. + * The original issue was that the InstanceKlass _initial_method_idnum was + * not adjusted properly when the overpass methods are added to the class. + * The expected/correct behavior: The test does not crash nor throw any exceptions. + * All the invocations of the defaultMethod() must be completed successfully. + */ + +import java.lang.invoke.*; + +interface InterfaceWithDefaultMethod { + public void someMethod(); + + default public void defaultMethod(String str){ + System.out.println("defaultMethod() " + str); + } +} + +public class Test8015436 implements InterfaceWithDefaultMethod { + @Override + public void someMethod() { + System.out.println("someMethod() invoked"); + } + + public static void main(String[] args) throws Throwable { + Test8015436 testObj = new Test8015436(); + testObj.someMethod(); + testObj.defaultMethod("invoked directly"); + + MethodHandles.Lookup lookup = MethodHandles.lookup(); + MethodType mt = MethodType.methodType(void.class, String.class); + MethodHandle mh = lookup.findVirtual(Test8015436.class, "defaultMethod", mt); + mh.invokeExact(testObj, "invoked via a MethodHandle"); + } +} + +/* + * A successful execution gives the output: + * someMethod() invoked + * defaultMethod() invoked directly + * defaultMethod() invoked via a MethodHandle + */ diff -r d2907f74462e -r b5c8a61d7fa0 test/gc/g1/TestSummarizeRSetStats.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/gc/g1/TestSummarizeRSetStats.java Fri Jun 21 15:56:24 2013 -0700 @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test TestSummarizeRSetStats.java + * @bug 8013895 + * @library /testlibrary + * @build TestSummarizeRSetStats + * @summary Verify output of -XX:+G1SummarizeRSetStats + * @run main TestSummarizeRSetStats + * + * Test the output of G1SummarizeRSetStats in conjunction with G1SummarizeRSetStatsPeriod. + */ + +import com.oracle.java.testlibrary.*; +import java.lang.Thread; +import java.util.ArrayList; +import java.util.Arrays; + +class RunSystemGCs { + // 4M size, both are directly allocated into the old gen + static Object[] largeObject1 = new Object[1024 * 1024]; + static Object[] largeObject2 = new Object[1024 * 1024]; + + static int[] temp; + + public static void main(String[] args) { + // create some cross-references between these objects + for (int i = 0; i < largeObject1.length; i++) { + largeObject1[i] = largeObject2; + } + + for (int i = 0; i < largeObject2.length; i++) { + largeObject2[i] = largeObject1; + } + + int numGCs = Integer.parseInt(args[0]); + + if (numGCs > 0) { + // try to force a minor collection: the young gen is 4M, the + // amount of data allocated below is roughly that (4*1024*1024 + + // some header data) + for (int i = 0; i < 1024 ; i++) { + temp = new int[1024]; + } + } + + for (int i = 0; i < numGCs - 1; i++) { + System.gc(); + } + } +} + +public class TestSummarizeRSetStats { + + public static String runTest(String[] additionalArgs, int numGCs) throws Exception { + ArrayList finalargs = new ArrayList(); + String[] defaultArgs = new String[] { + "-XX:+UseG1GC", + "-Xmn4m", + "-Xmx20m", + "-XX:InitiatingHeapOccupancyPercent=100", // we don't want the additional GCs due to initial marking + "-XX:+PrintGC", + "-XX:+UnlockDiagnosticVMOptions", + "-XX:G1HeapRegionSize=1M", + }; + + finalargs.addAll(Arrays.asList(defaultArgs)); + + if (additionalArgs != null) { + finalargs.addAll(Arrays.asList(additionalArgs)); + } + + finalargs.add(RunSystemGCs.class.getName()); + finalargs.add(String.valueOf(numGCs)); + + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + finalargs.toArray(new String[0])); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + + output.shouldHaveExitValue(0); + + String result = output.getStdout(); + return result; + } + + private static void expectStatistics(String result, int expectedCumulative, int expectedPeriodic) throws Exception { + int actualTotal = result.split("Concurrent RS processed").length - 1; + int actualCumulative = result.split("Cumulative RS summary").length - 1; + + if (expectedCumulative != actualCumulative) { + throw new Exception("Incorrect amount of RSet summaries at the end. Expected " + expectedCumulative + ", got " + actualCumulative); + } + + if (expectedPeriodic != (actualTotal - actualCumulative)) { + throw new Exception("Incorrect amount of per-period RSet summaries at the end. Expected " + expectedPeriodic + ", got " + (actualTotal - actualCumulative)); + } + } + + public static void main(String[] args) throws Exception { + String result; + + // no RSet statistics output + result = runTest(null, 0); + expectStatistics(result, 0, 0); + + // no RSet statistics output + result = runTest(null, 2); + expectStatistics(result, 0, 0); + + // no RSet statistics output + result = runTest(new String[] { "-XX:G1SummarizeRSetStatsPeriod=1" }, 3); + expectStatistics(result, 0, 0); + + // single RSet statistics output at the end + result = runTest(new String[] { "-XX:+G1SummarizeRSetStats" }, 0); + expectStatistics(result, 1, 0); + + // single RSet statistics output at the end + result = runTest(new String[] { "-XX:+G1SummarizeRSetStats" }, 2); + expectStatistics(result, 1, 0); + + // single RSet statistics output + result = runTest(new String[] { "-XX:+G1SummarizeRSetStats", "-XX:G1SummarizeRSetStatsPeriod=1" }, 0); + expectStatistics(result, 1, 0); + + // two times RSet statistics output + result = runTest(new String[] { "-XX:+G1SummarizeRSetStats", "-XX:G1SummarizeRSetStatsPeriod=1" }, 1); + expectStatistics(result, 1, 1); + + // four times RSet statistics output + result = runTest(new String[] { "-XX:+G1SummarizeRSetStats", "-XX:G1SummarizeRSetStatsPeriod=1" }, 3); + expectStatistics(result, 1, 3); + + // three times RSet statistics output + result = runTest(new String[] { "-XX:+G1SummarizeRSetStats", "-XX:G1SummarizeRSetStatsPeriod=2" }, 3); + expectStatistics(result, 1, 2); + + // single RSet statistics output + result = runTest(new String[] { "-XX:+G1SummarizeRSetStats", "-XX:G1SummarizeRSetStatsPeriod=100" }, 3); + expectStatistics(result, 1, 1); + } +} + diff -r d2907f74462e -r b5c8a61d7fa0 test/runtime/8007320/ConstMethodTest.java --- a/test/runtime/8007320/ConstMethodTest.java Thu Jun 20 16:30:44 2013 -0700 +++ b/test/runtime/8007320/ConstMethodTest.java Fri Jun 21 15:56:24 2013 -0700 @@ -23,7 +23,7 @@ /* * @test - * @bug 8007320 + * @bug 8007320 8014709 * @summary Test all optional fields in ConstMethod * @compile -g -parameters ConstMethodTest.java * @run main ConstMethodTest @@ -74,6 +74,11 @@ @MyAnnotation(name="someName", value = "Hello World") public class ConstMethodTest { + public @TypeAnno("constructor") ConstMethodTest() { } + + public ConstMethodTest(int i) { + // needs a second unannotated constructor + } private static void check(boolean b) { if (!b) @@ -139,10 +144,26 @@ } } + private static void testConstructor() throws Exception { + for (Constructor c : ConstMethodTest.class.getDeclaredConstructors()) { + Annotation[] aa = c.getAnnotatedReturnType().getAnnotations(); + if (c.getParameterTypes().length == 1) { // should be un-annotated + check(aa.length == 0); + } else if (c.getParameterTypes().length == 0) { //should be annotated + check(aa.length == 1); + check(((TypeAnno)aa[0]).value().equals("constructor")); + } else { + //should not happen + check(false); + } + } + } + public static void main(java.lang.String[] unused) throws Throwable { // pass 5 so kitchenSinkFunc is instantiated with an int kitchenSinkFunc("parameter", "param2", 5); test1(); + testConstructor(); } }; diff -r d2907f74462e -r b5c8a61d7fa0 test/runtime/Metaspace/FragmentMetaspace.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/Metaspace/FragmentMetaspace.java Fri Jun 21 15:56:24 2013 -0700 @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @library /runtime/testlibrary + * @build GeneratedClassLoader + * @run main/othervm/timeout=200 FragmentMetaspace + */ + +import java.io.IOException; + +/** + * Test that tries to fragment the native memory used by class loaders. + * This test creates class loaders that load classes of increasing size for every + * iteration. By increasing the size of the class meta data needed for every iteration + * we stress the subsystem for allocating native memory for meta data. + */ +public class FragmentMetaspace { + + public static void main(String... args) { + runGrowing(Long.valueOf(System.getProperty("time", "80000"))); + // try to clean up and unload classes to decrease + // class verification time in debug vm + System.gc(); + } + + private static void runGrowing(long time) { + long startTime = System.currentTimeMillis(); + for (int i = 0; System.currentTimeMillis() < startTime + time; ++i) { + try { + GeneratedClassLoader gcl = new GeneratedClassLoader(); + + Class c = gcl.getGeneratedClasses(i, 100)[0]; + c.newInstance(); + c = null; + + gcl = null; + } catch (IOException|InstantiationException|IllegalAccessException ex) { + throw new RuntimeException(ex); + } + } + } +} diff -r d2907f74462e -r b5c8a61d7fa0 test/runtime/Metaspace/FragmentMetaspaceSimple.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/Metaspace/FragmentMetaspaceSimple.java Fri Jun 21 15:56:24 2013 -0700 @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @library /runtime/testlibrary + * @library classes + * @build test.Empty ClassUnloadCommon + * @run main/othervm/timeout=200 FragmentMetaspaceSimple + */ + +import java.util.ArrayList; + +/** + * Test that tries to fragment the native memory used by class loaders. + * Keeps every other class loader alive in order to fragment the memory space + * used to store classes and meta data. Since the memory is probably allocated in + * chunks per class loader this will cause a lot of fragmentation if not handled + * properly since every other chunk will be unused. + */ +public class FragmentMetaspaceSimple { + public static void main(String... args) { + runSimple(Long.valueOf(System.getProperty("time", "80000"))); + System.gc(); + } + + private static void runSimple(long time) { + long startTime = System.currentTimeMillis(); + ArrayList cls = new ArrayList<>(); + for (int i = 0; System.currentTimeMillis() < startTime + time; ++i) { + ClassLoader ldr = ClassUnloadCommon.newClassLoader(); + if (i % 1000 == 0) { + cls.clear(); + } + // only keep every other class loader alive + if (i % 2 == 1) { + cls.add(ldr); + } + Class c = null; + try { + c = ldr.loadClass("test.Empty"); + } catch (ClassNotFoundException ex) { + throw new RuntimeException(ex); + } + c = null; + } + cls = null; + } +} diff -r d2907f74462e -r b5c8a61d7fa0 test/runtime/Metaspace/classes/test/Empty.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/Metaspace/classes/test/Empty.java Fri Jun 21 15:56:24 2013 -0700 @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package test; + +public class Empty { +public String toString() { return "nothing"; } +} diff -r d2907f74462e -r b5c8a61d7fa0 test/runtime/contended/HasNonStatic.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/contended/HasNonStatic.java Fri Jun 21 15:56:24 2013 -0700 @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.lang.Class; +import java.lang.String; +import java.lang.System; +import java.lang.management.ManagementFactory; +import java.lang.management.RuntimeMXBean; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CyclicBarrier; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import sun.misc.Unsafe; +import sun.misc.Contended; + +/* + * @test + * @bug 8015270 + * @summary \@Contended: fix multiple issues in the layout code + * + * @run main/othervm -XX:-RestrictContended HasNonStatic + */ +public class HasNonStatic { + + public static void main(String[] args) throws Exception { + R1 r1 = new R1(); + R2 r2 = new R2(); + R3 r3 = new R3(); + R4 r4 = new R4(); + } + + public static class R1 { + @Contended + Object o; + } + + @Contended + public static class R2 { + Object o; + } + + @Contended + public static class R3 { + } + + public static class R4 extends R3 { + } + +} + diff -r d2907f74462e -r b5c8a61d7fa0 test/runtime/contended/OopMaps.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/contended/OopMaps.java Fri Jun 21 15:56:24 2013 -0700 @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.lang.Class; +import java.lang.String; +import java.lang.System; +import java.lang.management.ManagementFactory; +import java.lang.management.RuntimeMXBean; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CyclicBarrier; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import sun.misc.Unsafe; +import sun.misc.Contended; + +/* + * @test + * @bug 8015270 + * @bug 8015493 + * @summary \@Contended: fix multiple issues in the layout code + * + * @run main/othervm -XX:-RestrictContended -XX:ContendedPaddingWidth=128 -Xmx128m OopMaps + */ +public class OopMaps { + + public static final int COUNT = 10000; + + public static void main(String[] args) throws Exception { + Object o01 = new Object(); + Object o02 = new Object(); + Object o03 = new Object(); + Object o04 = new Object(); + Object o05 = new Object(); + Object o06 = new Object(); + Object o07 = new Object(); + Object o08 = new Object(); + Object o09 = new Object(); + Object o10 = new Object(); + Object o11 = new Object(); + Object o12 = new Object(); + Object o13 = new Object(); + Object o14 = new Object(); + + R1[] rs = new R1[COUNT]; + + for (int i = 0; i < COUNT; i++) { + R1 r1 = new R1(); + r1.o01 = o01; + r1.o02 = o02; + r1.o03 = o03; + r1.o04 = o04; + r1.o05 = o05; + r1.o06 = o06; + r1.o07 = o07; + r1.o08 = o08; + r1.o09 = o09; + r1.o10 = o10; + r1.o11 = o11; + r1.o12 = o12; + r1.o13 = o13; + r1.o14 = o14; + r1.i1 = 1; + r1.i2 = 2; + r1.i3 = 3; + r1.i4 = 4; + rs[i] = r1; + } + + System.gc(); + + for (int i = 0; i < COUNT; i++) { + R1 r1 = rs[i]; + if (r1.o01 != o01) throw new Error("Test Error: o01"); + if (r1.o02 != o02) throw new Error("Test Error: o02"); + if (r1.o03 != o03) throw new Error("Test Error: o03"); + if (r1.o04 != o04) throw new Error("Test Error: o04"); + if (r1.o05 != o05) throw new Error("Test Error: o05"); + if (r1.o06 != o06) throw new Error("Test Error: o06"); + if (r1.o07 != o07) throw new Error("Test Error: o07"); + if (r1.o08 != o08) throw new Error("Test Error: o08"); + if (r1.o09 != o09) throw new Error("Test Error: o09"); + if (r1.o10 != o10) throw new Error("Test Error: o10"); + if (r1.o11 != o11) throw new Error("Test Error: o11"); + if (r1.o12 != o12) throw new Error("Test Error: o12"); + if (r1.o13 != o13) throw new Error("Test Error: o13"); + if (r1.o14 != o14) throw new Error("Test Error: o14"); + if (r1.i1 != 1) throw new Error("Test Error: i1"); + if (r1.i2 != 2) throw new Error("Test Error: i2"); + if (r1.i3 != 3) throw new Error("Test Error: i3"); + if (r1.i4 != 4) throw new Error("Test Error: i4"); + } + } + + public static class R0 { + int i1; + int i2; + + Object o01; + Object o02; + + @Contended + Object o03; + + @Contended + Object o04; + + @Contended + Object o05; + + @Contended + Object o06; + + @Contended + Object o07; + } + + public static class R1 extends R0 { + int i3; + int i4; + + Object o08; + Object o09; + + @Contended + Object o10; + + @Contended + Object o11; + + @Contended + Object o12; + + @Contended + Object o13; + + @Contended + Object o14; + } + +} + diff -r d2907f74462e -r b5c8a61d7fa0 test/runtime/memory/MultiAllocateNullCheck.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/memory/MultiAllocateNullCheck.java Fri Jun 21 15:56:24 2013 -0700 @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test MultiAllocateNullCheck + * @bug 6726963 + * @summary multi_allocate() call does not CHECK_NULL and causes crash in fastdebug bits + * @run main/othervm -Xmx32m MultiAllocateNullCheck + */ + +import java.lang.reflect.Array; + +public class MultiAllocateNullCheck { + public static void main(String[] args) throws Exception { + Object x = null; + try + { + x = Array.newInstance(String.class, new int[] + {Integer.MAX_VALUE, Integer.MAX_VALUE}); + System.out.println("Array was created"); + } catch (OutOfMemoryError e) { + System.out.println("Out of memory occured, which is OK in this case"); + } + } +} diff -r d2907f74462e -r b5c8a61d7fa0 test/runtime/memory/ReserveMemory.java --- a/test/runtime/memory/ReserveMemory.java Thu Jun 20 16:30:44 2013 -0700 +++ b/test/runtime/memory/ReserveMemory.java Fri Jun 21 15:56:24 2013 -0700 @@ -34,29 +34,20 @@ import com.oracle.java.testlibrary.*; -import java.lang.reflect.Field; import sun.hotspot.WhiteBox; -import sun.misc.Unsafe; public class ReserveMemory { - private static Unsafe getUnsafe() throws Exception { - Field f = Unsafe.class.getDeclaredField("theUnsafe"); - f.setAccessible(true); - return (Unsafe)f.get(null); - } - private static boolean isWindows() { return System.getProperty("os.name").toLowerCase().startsWith("win"); } + private static boolean isOsx() { + return System.getProperty("os.name").toLowerCase().startsWith("mac"); + } + public static void main(String args[]) throws Exception { if (args.length > 0) { - long address = WhiteBox.getWhiteBox().reserveMemory(4096); - - System.out.println("Reserved memory at address: 0x" + Long.toHexString(address)); - System.out.println("Will now read from the address, expecting a crash!"); - - int x = getUnsafe().getInt(address); + WhiteBox.getWhiteBox().readReservedMemory(); throw new Exception("Read of reserved/uncommitted memory unexpectedly succeeded, expected crash!"); } @@ -71,6 +62,8 @@ OutputAnalyzer output = new OutputAnalyzer(pb.start()); if (isWindows()) { output.shouldContain("EXCEPTION_ACCESS_VIOLATION"); + } else if (isOsx()) { + output.shouldContain("SIGBUS"); } else { output.shouldContain("SIGSEGV"); } diff -r d2907f74462e -r b5c8a61d7fa0 test/runtime/testlibrary/GeneratedClassLoader.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/testlibrary/GeneratedClassLoader.java Fri Jun 21 15:56:24 2013 -0700 @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.DataInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import javax.tools.JavaCompiler; +import javax.tools.ToolProvider; + +/** + * A class loader that generates new classes. + * The generated classes are made by first emitting java sources with nested + * static classes, these are then compiled and the class files are read back. + * Some efforts are made to make the class instances unique and of not insignificant + * size. + */ +public class GeneratedClassLoader extends ClassLoader { + /** + * Holds a pair of class bytecodes and class name (for use with defineClass). + */ + private static class GeneratedClass { + public byte[] bytes; + public String name; + public GeneratedClass(byte[] bytes, String name) { + this.bytes = bytes; this.name = name; + } + } + + /** + * Used to uniquely name every class generated. + */ + private static int count = 0; + /** + * Used to enable/disable keeping the class files and java sources for + * the generated classes. + */ + private static boolean deleteFiles = Boolean.parseBoolean( + System.getProperty("GeneratedClassLoader.deleteFiles", "true")); + + private static String bigstr = + "Lorem ipsum dolor sit amet, consectetur adipiscing elit. " + + "In facilisis scelerisque vehicula. Donec congue nisi a " + + "leo posuere placerat lobortis felis ultrices. Pellentesque " + + "habitant morbi tristique senectus et netus et malesuada " + + "fames ac turpis egestas. Nam tristique velit at felis " + + "iaculis at tempor sem vestibulum. Sed adipiscing lectus " + + "non mi molestie sagittis. Morbi eu purus urna. Nam tempor " + + "tristique massa eget semper. Mauris cursus, nulla et ornare " + + "vehicula, leo dolor scelerisque metus, sit amet rutrum erat " + + "sapien quis dui. Nullam eleifend risus et velit accumsan sed " + + "suscipit felis pulvinar. Nullam faucibus suscipit gravida. " + + "Pellentesque habitant morbi tristique senectus et netus et " + + "malesuada fames ac turpis egestas. Nullam ut massa augue, " + + "nec viverra mauris."; + + private static int getNextCount() { + return count++; + } + + ////// end statics + + private JavaCompiler javac; + private String nameBase; + + public GeneratedClassLoader() { + javac = ToolProvider.getSystemJavaCompiler(); + nameBase = "TestSimpleClass"; + } + + private long getBigValue(int which) { + // > 65536 is too large to encode in the bytecode + // so this will force us to emit a constant pool entry for this int + return (long)which + 65537; + } + + private String getBigString(int which) { + return bigstr + which; + } + + private String getClassName(int count) { + return nameBase + count; + } + + private String generateSource(int count, int sizeFactor, int numClasses) { + StringBuilder sb = new StringBuilder(); + sb.append("public class ").append(getClassName(count)).append("{\n"); + for (int j = 0; j < numClasses; ++j) { + sb.append("public static class ") + .append("Class") + .append(j) + .append("{\n"); + for (int i = 0; i < sizeFactor; ++i) { + int value = i; + sb.append("private long field") + .append(i).append(" = ") + .append(getBigValue(value++)) + .append(";\n"); + sb.append("public long method") + .append(i) + .append("() {\n"); + sb.append("return ") + .append(getBigValue(value++)) + .append(";"); + sb.append("}\n"); + sb.append("private String str").append(i) + .append(" = \"") + .append(getBigString(i)) + .append("\";"); + } + sb.append("\n}"); + } + sb.append("\n}"); + return sb.toString(); + } + + private GeneratedClass[] getGeneratedClass(int sizeFactor, int numClasses) throws IOException { + int uniqueCount = getNextCount(); + String src = generateSource(uniqueCount, sizeFactor, numClasses); + String className = getClassName(uniqueCount); + File file = new File(className + ".java"); + try (PrintWriter pw = new PrintWriter(new FileWriter(file))) { + pw.append(src); + pw.flush(); + } + int exitcode = javac.run(null, null, null, file.getCanonicalPath()); + if (exitcode != 0) { + throw new RuntimeException("javac failure when compiling: " + + file.getCanonicalPath()); + } else { + if (deleteFiles) { + file.delete(); + } + } + GeneratedClass[] gc = new GeneratedClass[numClasses]; + for (int i = 0; i < numClasses; ++i) { + String name = className + "$" + "Class" + i; + File classFile = new File(name + ".class"); + byte[] bytes; + try (DataInputStream dis = new DataInputStream(new FileInputStream(classFile))) { + bytes = new byte[dis.available()]; + dis.readFully(bytes); + } + if (deleteFiles) { + classFile.delete(); + } + gc[i] = new GeneratedClass(bytes, name); + } + if (deleteFiles) { + new File(className + ".class").delete(); + } + return gc; + } + + /** + * Generate a single class, compile it and load it. + * @param sizeFactor Fuzzy measure of how large the class should be. + * @return the Class instance. + * @throws IOException + */ + public Class generateClass(int sizeFactor) throws IOException { + return getGeneratedClasses(sizeFactor, 1)[0]; + } + + /** + * Generate several classes, compile and load them. + * @param sizeFactor Fuzzy measure of how large each class should be. + * @param numClasses The number of classes to create + * @return an array of the Class instances. + * @throws IOException + */ + public Class[] getGeneratedClasses(int sizeFactor, int numClasses) throws IOException { + GeneratedClass[] gc = getGeneratedClass(sizeFactor, numClasses); + Class[] classes = new Class[numClasses]; + for (int i = 0; i < numClasses; ++i) { + classes[i] = defineClass(gc[i].name, gc[i].bytes, 0 , gc[i].bytes.length); + } + return classes; + } +} diff -r d2907f74462e -r b5c8a61d7fa0 test/testlibrary/whitebox/sun/hotspot/WhiteBox.java --- a/test/testlibrary/whitebox/sun/hotspot/WhiteBox.java Thu Jun 20 16:30:44 2013 -0700 +++ b/test/testlibrary/whitebox/sun/hotspot/WhiteBox.java Fri Jun 21 15:56:24 2013 -0700 @@ -115,7 +115,7 @@ public native boolean isInStringTable(String str); // Memory - public native long reserveMemory(long size); + public native void readReservedMemory(); // force Full GC public native void fullGC();