OpenJDK / bsd-port / bsd-port / hotspot
changeset 510:2551e5deace8
. Merge from the main OpenJDK repository.
author | glewis@misty.eyesbeyond.com |
---|---|
date | Sun, 28 Dec 2008 11:28:04 -0800 |
parents | de4c58dbee8f fc6a5ae3fef5 |
children | 897a4fb539b6 |
files | src/share/vm/includeDB_core src/share/vm/runtime/globals.hpp src/share/vm/runtime/os.cpp src/share/vm/utilities/macros.hpp src/share/vm/utilities/vmError.cpp |
diffstat | 164 files changed, 2416 insertions(+), 1051 deletions(-) [+] |
line wrap: on
line diff
--- a/.hgtags Wed Nov 26 05:05:13 2008 -0800 +++ b/.hgtags Sun Dec 28 11:28:04 2008 -0800 @@ -15,3 +15,5 @@ d9bc824aa078573829bb66572af847e26e1bd12e jdk7-b38 49ca90d77f34571b0757ebfcb8a7848ef2696b88 jdk7-b39 81a0cbe3b28460ce836109934ece03db7afaf9cc jdk7-b40 +f9d938ede1960d18cb7cf23c645b026519c1a678 jdk7-b41 +ad8c8ca4ab0f4c86e74c061958f44a8f4a930f2c jdk7-b42
--- a/make/hotspot_version Wed Nov 26 05:05:13 2008 -0800 +++ b/make/hotspot_version Sun Dec 28 11:28:04 2008 -0800 @@ -35,7 +35,7 @@ HS_MAJOR_VER=14 HS_MINOR_VER=0 -HS_BUILD_NUMBER=08 +HS_BUILD_NUMBER=10 JDK_MAJOR_VER=1 JDK_MINOR_VER=7
--- a/make/linux/adlc_updater Wed Nov 26 05:05:13 2008 -0800 +++ b/make/linux/adlc_updater Sun Dec 28 11:28:04 2008 -0800 @@ -7,5 +7,13 @@ # # adlc-updater <file> <source-dir> <target-dir> # -[ -f $3/$1 ] && cmp -s $2/$1 $3/$1 || \ -( [ -f $3/$1 ]; echo Updating $3/$1 ; touch $2/made-change ; mv $2/$1 $3/$1 ) +fix_lines() { + # repair bare #line directives in $1 to refer to $2 + awk < $1 > $1+ ' + /^#line 999999$/ {print "#line " (NR+1) " \"" F2 "\""; next} + {print} + ' F2=$2 + mv $1+ $1 +} +[ -f $3/$1 ] && (fix_lines $2/$1 $3/$1; cmp -s $2/$1 $3/$1) || \ +( [ -f $3/$1 ] && echo Updating $3/$1 ; touch $2/made-change ; mv $2/$1 $3/$1 )
--- a/make/linux/makefiles/adlc.make Wed Nov 26 05:05:13 2008 -0800 +++ b/make/linux/makefiles/adlc.make Sun Dec 28 11:28:04 2008 -0800 @@ -54,9 +54,11 @@ Src_Dirs_I = ${Src_Dirs} $(GENERATED) INCLUDES += $(Src_Dirs_I:%=-I%) +# set flags for adlc compilation +CPPFLAGS = $(SYSDEFS) $(INCLUDES) + # Force assertions on. -SYSDEFS += -DASSERT -CPPFLAGS = $(SYSDEFS) $(INCLUDES) +CPPFLAGS += -DASSERT # CFLAGS_WARN holds compiler options to suppress/enable warnings. # Suppress warnings (for now) @@ -125,7 +127,15 @@ # Note that product files are updated via "mv", which is atomic. TEMPDIR := $(OUTDIR)/mktmp$(shell echo $$$$) -ADLCFLAGS = -q -T +# Pass -D flags into ADLC. +ADLCFLAGS += $(SYSDEFS) + +# Note "+="; it is a hook so flags.make can add more flags, like -g or -DFOO. +ADLCFLAGS += -q -T + +# Normally, debugging is done directly on the ad_<arch>*.cpp files. +# But -g will put #line directives in those files pointing back to <arch>.ad. +#ADLCFLAGS += -g ifdef LP64 ADLCFLAGS += -D_LP64 @@ -140,6 +150,8 @@ # ADLC_UPDATER_DIRECTORY = $(GAMMADIR)/make/$(OS) ADLC_UPDATER = adlc_updater +$(ADLC_UPDATER): $(ADLC_UPDATER_DIRECTORY)/$(ADLC_UPDATER) + $(QUIETLY) cp $< $@; chmod +x $@ # This action refreshes all generated adlc files simultaneously. # The way it works is this: @@ -149,9 +161,8 @@ # 4) call $(ADLC_UPDATER) on each generated adlc file. It will selectively update changed or missing files. # 5) If we actually updated any files, echo a notice. # -refresh_adfiles: $(EXEC) $(SOURCE.AD) +refresh_adfiles: $(EXEC) $(SOURCE.AD) $(ADLC_UPDATER) @rm -rf $(TEMPDIR); mkdir $(TEMPDIR) - $(QUIETLY) [ -f $(ADLC_UPDATER) ] || ( cp $(ADLC_UPDATER_DIRECTORY)/$(ADLC_UPDATER) . ; chmod +x $(ADLC_UPDATER) ) $(QUIETLY) $(EXEC) $(ADLCFLAGS) $(SOURCE.AD) \ -c$(TEMPDIR)/ad_$(Platform_arch_model).cpp -h$(TEMPDIR)/ad_$(Platform_arch_model).hpp -a$(TEMPDIR)/dfa_$(Platform_arch_model).cpp -v$(TEMPDIR)/adGlobals_$(Platform_arch_model).hpp \ || { rm -rf $(TEMPDIR); exit 1; } @@ -174,7 +185,15 @@ # ######################################################################### $(SOURCE.AD): $(SOURCES.AD) - $(QUIETLY) cat $(SOURCES.AD) > $(SOURCE.AD) + $(QUIETLY) $(PROCESS_AD_FILES) $(SOURCES.AD) > $(SOURCE.AD) + +#PROCESS_AD_FILES = cat +# Pass through #line directives, in case user enables -g option above: +PROCESS_AD_FILES = awk '{ \ + if (CUR_FN != FILENAME) { CUR_FN=FILENAME; NR_BASE=NR-1; need_lineno=1 } \ + if (need_lineno && $$0 !~ /\/\//) \ + { print "\n\n\#line " (NR-NR_BASE) " \"" FILENAME "\""; need_lineno=0 }; \ + print }' $(OUTDIR)/%.o: %.cpp @echo Compiling $<
--- a/make/solaris/adlc_updater Wed Nov 26 05:05:13 2008 -0800 +++ b/make/solaris/adlc_updater Sun Dec 28 11:28:04 2008 -0800 @@ -7,5 +7,13 @@ # # adlc-updater <file> <source-dir> <target-dir> # -[ -f $3/$1 ] && cmp -s $2/$1 $3/$1 || \ -( [ -f $3/$1 ]; echo Updating $3/$1 ; touch $2/made-change ; mv $2/$1 $3/$1 ) +fix_lines() { + # repair bare #line directives in $1 to refer to $2 + awk < $1 > $1+ ' + /^#line 999999$/ {print "#line " (NR+1) " \"" F2 "\""; next} + {print} + ' F2=$2 + mv $1+ $1 +} +[ -f $3/$1 ] && (fix_lines $2/$1 $3/$1; cmp -s $2/$1 $3/$1) || \ +( [ -f $3/$1 ] && echo Updating $3/$1 ; touch $2/made-change ; mv $2/$1 $3/$1 )
--- a/make/solaris/makefiles/adlc.make Wed Nov 26 05:05:13 2008 -0800 +++ b/make/solaris/makefiles/adlc.make Sun Dec 28 11:28:04 2008 -0800 @@ -54,9 +54,11 @@ Src_Dirs_I = ${Src_Dirs} $(GENERATED) INCLUDES += $(Src_Dirs_I:%=-I%) +# set flags for adlc compilation +CPPFLAGS = $(SYSDEFS) $(INCLUDES) + # Force assertions on. -SYSDEFS += -DASSERT -CPPFLAGS = $(SYSDEFS) $(INCLUDES) +CPPFLAGS += -DASSERT ifndef USE_GCC # We need libCstd.so for adlc @@ -141,7 +143,15 @@ # Note that product files are updated via "mv", which is atomic. TEMPDIR := $(OUTDIR)/mktmp$(shell echo $$$$) -ADLCFLAGS = -q -T +# Pass -D flags into ADLC. +ADLCFLAGS += $(SYSDEFS) + +# Note "+="; it is a hook so flags.make can add more flags, like -g or -DFOO. +ADLCFLAGS += -q -T + +# Normally, debugging is done directly on the ad_<arch>*.cpp files. +# But -g will put #line directives in those files pointing back to <arch>.ad. +#ADLCFLAGS += -g ifdef LP64 ADLCFLAGS += -D_LP64 @@ -156,6 +166,8 @@ # ADLC_UPDATER_DIRECTORY = $(GAMMADIR)/make/$(OS) ADLC_UPDATER = adlc_updater +$(ADLC_UPDATER): $(ADLC_UPDATER_DIRECTORY)/$(ADLC_UPDATER) + $(QUIETLY) cp $< $@; chmod +x $@ # This action refreshes all generated adlc files simultaneously. # The way it works is this: @@ -165,9 +177,8 @@ # 4) call $(ADLC_UPDATER) on each generated adlc file. It will selectively update changed or missing files. # 5) If we actually updated any files, echo a notice. # -refresh_adfiles: $(EXEC) $(SOURCE.AD) +refresh_adfiles: $(EXEC) $(SOURCE.AD) $(ADLC_UPDATER) @rm -rf $(TEMPDIR); mkdir $(TEMPDIR) - $(QUIETLY) [ -f $(ADLC_UPDATER) ] || ( cp $(ADLC_UPDATER_DIRECTORY)/$(ADLC_UPDATER) . ; chmod +x $(ADLC_UPDATER) ) $(QUIETLY) $(EXEC) $(ADLCFLAGS) $(SOURCE.AD) \ -c$(TEMPDIR)/ad_$(Platform_arch_model).cpp -h$(TEMPDIR)/ad_$(Platform_arch_model).hpp -a$(TEMPDIR)/dfa_$(Platform_arch_model).cpp -v$(TEMPDIR)/adGlobals_$(Platform_arch_model).hpp \ || { rm -rf $(TEMPDIR); exit 1; } @@ -190,7 +201,15 @@ # ######################################################################### $(SOURCE.AD): $(SOURCES.AD) - $(QUIETLY) cat $(SOURCES.AD) > $(SOURCE.AD) + $(QUIETLY) $(PROCESS_AD_FILES) $(SOURCES.AD) > $(SOURCE.AD) + +#PROCESS_AD_FILES = cat +# Pass through #line directives, in case user enables -g option above: +PROCESS_AD_FILES = awk '{ \ + if (CUR_FN != FILENAME) { CUR_FN=FILENAME; NR_BASE=NR-1; need_lineno=1 } \ + if (need_lineno && $$0 !~ /\/\//) \ + { print "\n\n\#line " (NR-NR_BASE) " \"" FILENAME "\""; need_lineno=0 }; \ + print }' $(OUTDIR)/%.o: %.cpp @echo Compiling $<
--- a/make/windows/build.make Wed Nov 26 05:05:13 2008 -0800 +++ b/make/windows/build.make Sun Dec 28 11:28:04 2008 -0800 @@ -200,29 +200,6 @@ checkSA:: @echo Not building SA: ARCH = ia64 -!elseif exist("$(MSVCDIR)\PlatformSDK\Include\dbgeng.h") -# These don't have to be set because the default -# setting of INCLUDE and LIB already contain the needed dirs. -SA_INCLUDE = -SA_LIB = - -!elseif exist("$(SYSTEMROOT)\..\Program Files\Microsoft SDK\include\dbgeng.h") -# These don't have to be set because the default -# setting of INCLUDE and LIB already contain the needed dirs. -SA_INCLUDE = -SA_LIB = - -!else -checkSA:: - @echo . - @echo ERROR: Can't build SA because dbgeng.h does not exist here: - @echo $(MSVCDIR)\PlatformSDK\Include\dbgeng.h - @echo nor here: - @echo $(SYSTEMROOT)\..\Program Files\Microsoft SDK\include\dbgeng.h - @echo You must use Vis. Studio .Net 2003 on Win 32, and you must - @echo have the Microsoft SDK installed on Win amd64. - @echo You can disable building of SA by specifying BUILD_WIN_SA = 0 - @echo . && false !endif # ! "$(BUILD_WIN_SA)" != "1" #########################################################################
--- a/make/windows/makefiles/defs.make Wed Nov 26 05:05:13 2008 -0800 +++ b/make/windows/makefiles/defs.make Sun Dec 28 11:28:04 2008 -0800 @@ -119,7 +119,7 @@ # we want to release it. If we build it here, # the SDK makefiles will copy it over and put it into # the created image. -BUILD_WIN_SA = 0 +BUILD_WIN_SA = 1 ifneq ($(ALT_BUILD_WIN_SA),) BUILD_WIN_SA = $(ALT_BUILD_WIN_SA) endif
--- a/make/windows/makefiles/sa.make Wed Nov 26 05:05:13 2008 -0800 +++ b/make/windows/makefiles/sa.make Sun Dec 28 11:28:04 2008 -0800 @@ -49,6 +49,9 @@ default:: $(GENERATED)\sa-jdi.jar +# Remove the space between $(SA_BUILD_VERSION_PROP) and > below as it adds a white space +# at the end of SA version string and causes a version mismatch with the target VM version. + $(GENERATED)\sa-jdi.jar: $(AGENT_FILES1:/=\) $(AGENT_FILES2:/=\) @if not exist $(SA_CLASSDIR) mkdir $(SA_CLASSDIR) @echo ...Building sa-jdi.jar @@ -56,15 +59,15 @@ @$(COMPILE_JAVAC) -source 1.4 -classpath $(SA_CLASSPATH) -sourcepath $(AGENT_SRC_DIR) -g -d $(SA_CLASSDIR) $(AGENT_FILES1:/=\) @$(COMPILE_JAVAC) -source 1.4 -classpath $(SA_CLASSPATH) -sourcepath $(AGENT_SRC_DIR) -g -d $(SA_CLASSDIR) $(AGENT_FILES2:/=\) $(COMPILE_RMIC) -classpath $(SA_CLASSDIR) -d $(SA_CLASSDIR) sun.jvm.hotspot.debugger.remote.RemoteDebuggerServer - $(QUIETLY) echo $(SA_BUILD_VERSION_PROP) > $(SA_PROPERTIES) - $(RUN_JAR) cf $@ -C saclasses . - $(RUN_JAR) uf $@ -C $(AGENT_SRC_DIR:/=\) META-INF\services\com.sun.jdi.connect.Connector + $(QUIETLY) echo $(SA_BUILD_VERSION_PROP)> $(SA_PROPERTIES) $(QUIETLY) rm -f $(SA_CLASSDIR)/sun/jvm/hotspot/utilities/soql/sa.js $(QUIETLY) cp $(AGENT_SRC_DIR)/sun/jvm/hotspot/utilities/soql/sa.js $(SA_CLASSDIR)/sun/jvm/hotspot/utilities/soql - $(QUIETLY) mkdir -p $(SA_CLASSDIR)/sun/jvm/hotspot/ui/resources - $(QUIETLY) rm -f $(SA_CLASSDIR)/sun/jvm/hotspot/ui/resources/* - $(QUIETLY) cp $(AGENT_SRC_DIR)/sun/jvm/hotspot/ui/resources/*.png $(SA_CLASSDIR)/sun/jvm/hotspot/ui/resources/ - $(QUIETLY) cp -r $(AGENT_SRC_DIR)/images/* $(SA_CLASSDIR)/ + $(QUIETLY) rm -rf $(SA_CLASSDIR)/sun/jvm/hotspot/ui/resources + $(QUIETLY) mkdir $(SA_CLASSDIR)\sun\jvm\hotspot\ui\resources + $(QUIETLY) cp $(AGENT_SRC_DIR)/sun/jvm/hotspot/ui/resources/*.png $(SA_CLASSDIR)/sun/jvm/hotspot/ui/resources + $(QUIETLY) cp -r $(AGENT_SRC_DIR)/images/* $(SA_CLASSDIR) + $(RUN_JAR) cf $@ -C saclasses . + $(RUN_JAR) uf $@ -C $(AGENT_SRC_DIR:/=\) META-INF\services\com.sun.jdi.connect.Connector $(RUN_JAVAH) -classpath $(SA_CLASSDIR) -jni sun.jvm.hotspot.debugger.windbg.WindbgDebuggerLocal $(RUN_JAVAH) -classpath $(SA_CLASSDIR) -jni sun.jvm.hotspot.debugger.x86.X86ThreadContext $(RUN_JAVAH) -classpath $(SA_CLASSDIR) -jni sun.jvm.hotspot.debugger.ia64.IA64ThreadContext @@ -93,7 +96,7 @@ SA_CFLAGS = /nologo $(MS_RUNTIME_OPTION) /W3 /Gm $(GX_OPTION) /ZI /Od /D "WIN32" /D "_WINDOWS" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c !endif !if "$(MT)" != "" - SA_LINK_FLAGS = /manifest $(SA_LINK_FLAGS) +SA_LINK_FLAGS = /manifest $(SA_LINK_FLAGS) !endif SASRCFILE = $(AGENT_DIR)/src/os/win32/windbg/sawindbg.cpp SA_LFLAGS = $(SA_LINK_FLAGS) /nologo /subsystem:console /map /debug /machine:$(MACHINE)
--- a/src/cpu/sparc/vm/templateTable_sparc.cpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/cpu/sparc/vm/templateTable_sparc.cpp Sun Dec 28 11:28:04 2008 -0800 @@ -2085,7 +2085,7 @@ } else { if (has_tos) { // save object pointer before call_VM() clobbers it - __ mov(Otos_i, Lscratch); + __ push_ptr(Otos_i); // put object on tos where GC wants it. } else { // Load top of stack (do not pop the value off the stack); __ ld_ptr(Lesp, Interpreter::expr_offset_in_bytes(0), Otos_i); @@ -2097,7 +2097,7 @@ __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::post_field_access), Otos_i, Rcache); if (!is_static && has_tos) { - __ mov(Lscratch, Otos_i); // restore object pointer + __ pop_ptr(Otos_i); // restore object pointer __ verify_oop(Otos_i); } __ get_cache_and_index_at_bcp(Rcache, index, 1);
--- a/src/cpu/x86/vm/vm_version_x86_32.hpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/cpu/x86/vm/vm_version_x86_32.hpp Sun Dec 28 11:28:04 2008 -0800 @@ -1,5 +1,5 @@ /* - * Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2008 Sun Microsystems, Inc. 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
--- a/src/cpu/x86/vm/vm_version_x86_64.hpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/cpu/x86/vm/vm_version_x86_64.hpp Sun Dec 28 11:28:04 2008 -0800 @@ -1,5 +1,5 @@ /* - * Copyright 2003-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2008 Sun Microsystems, Inc. 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
--- a/src/os/linux/launcher/java.c Wed Nov 26 05:05:13 2008 -0800 +++ b/src/os/linux/launcher/java.c Sun Dec 28 11:28:04 2008 -0800 @@ -1,5 +1,5 @@ /* - * Copyright 1999-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1999-2008 Sun Microsystems, Inc. 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
--- a/src/os/linux/launcher/java.h Wed Nov 26 05:05:13 2008 -0800 +++ b/src/os/linux/launcher/java.h Sun Dec 28 11:28:04 2008 -0800 @@ -1,5 +1,5 @@ /* - * Copyright 1999-2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1999-2008 Sun Microsystems, Inc. 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
--- a/src/os/linux/launcher/java_md.c Wed Nov 26 05:05:13 2008 -0800 +++ b/src/os/linux/launcher/java_md.c Sun Dec 28 11:28:04 2008 -0800 @@ -1,5 +1,5 @@ /* - * Copyright 1999-2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1999-2008 Sun Microsystems, Inc. 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
--- a/src/os/linux/vm/globals_linux.hpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/os/linux/vm/globals_linux.hpp Sun Dec 28 11:28:04 2008 -0800 @@ -1,5 +1,5 @@ /* - * Copyright 2005-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2005-2008 Sun Microsystems, Inc. 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
--- a/src/os/linux/vm/os_linux.cpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/os/linux/vm/os_linux.cpp Sun Dec 28 11:28:04 2008 -0800 @@ -2272,7 +2272,9 @@ uncommit_memory(addr, bytes); } -void os::numa_make_global(char *addr, size_t bytes) { } +void os::numa_make_global(char *addr, size_t bytes) { + Linux::numa_interleave_memory(addr, bytes); +} void os::numa_make_local(char *addr, size_t bytes, int lgrp_hint) { Linux::numa_tonode_memory(addr, bytes, lgrp_hint); @@ -2314,7 +2316,7 @@ extern "C" void numa_warn(int number, char *where, ...) { } extern "C" void numa_error(char *where) { } -void os::Linux::libnuma_init() { +bool os::Linux::libnuma_init() { // sched_getcpu() should be in libc. set_sched_getcpu(CAST_TO_FN_PTR(sched_getcpu_func_t, dlsym(RTLD_DEFAULT, "sched_getcpu"))); @@ -2330,31 +2332,51 @@ dlsym(handle, "numa_available"))); set_numa_tonode_memory(CAST_TO_FN_PTR(numa_tonode_memory_func_t, dlsym(handle, "numa_tonode_memory"))); + set_numa_interleave_memory(CAST_TO_FN_PTR(numa_interleave_memory_func_t, + dlsym(handle, "numa_interleave_memory"))); + + if (numa_available() != -1) { + set_numa_all_nodes((unsigned long*)dlsym(handle, "numa_all_nodes")); // Create a cpu -> node mapping _cpu_to_node = new (ResourceObj::C_HEAP) GrowableArray<int>(0, true); rebuild_cpu_to_node_map(); + return true; } } } + return false; } // rebuild_cpu_to_node_map() constructs a table mapping cpud id to node id. // The table is later used in get_node_by_cpu(). void os::Linux::rebuild_cpu_to_node_map() { - int cpu_num = os::active_processor_count(); + const size_t NCPUS = 32768; // Since the buffer size computation is very obscure + // in libnuma (possible values are starting from 16, + // and continuing up with every other power of 2, but less + // than the maximum number of CPUs supported by kernel), and + // is a subject to change (in libnuma version 2 the requirements + // are more reasonable) we'll just hardcode the number they use + // in the library. + const size_t BitsPerCLong = sizeof(long) * CHAR_BIT; + + size_t cpu_num = os::active_processor_count(); + size_t cpu_map_size = NCPUS / BitsPerCLong; + size_t cpu_map_valid_size = + MIN2((cpu_num + BitsPerCLong - 1) / BitsPerCLong, cpu_map_size); + cpu_to_node()->clear(); cpu_to_node()->at_grow(cpu_num - 1); - int node_num = numa_get_groups_num(); - int cpu_map_size = (cpu_num + BitsPerLong - 1) / BitsPerLong; + size_t node_num = numa_get_groups_num(); + unsigned long *cpu_map = NEW_C_HEAP_ARRAY(unsigned long, cpu_map_size); - for (int i = 0; i < node_num; i++) { + for (size_t i = 0; i < node_num; i++) { if (numa_node_to_cpus(i, cpu_map, cpu_map_size * sizeof(unsigned long)) != -1) { - for (int j = 0; j < cpu_map_size; j++) { + for (size_t j = 0; j < cpu_map_valid_size; j++) { if (cpu_map[j] != 0) { - for (int k = 0; k < BitsPerLong; k++) { + for (size_t k = 0; k < BitsPerCLong; k++) { if (cpu_map[j] & (1UL << k)) { - cpu_to_node()->at_put(j * BitsPerLong + k, i); + cpu_to_node()->at_put(j * BitsPerCLong + k, i); } } } @@ -2377,7 +2399,8 @@ os::Linux::numa_max_node_func_t os::Linux::_numa_max_node; os::Linux::numa_available_func_t os::Linux::_numa_available; os::Linux::numa_tonode_memory_func_t os::Linux::_numa_tonode_memory; - +os::Linux::numa_interleave_memory_func_t os::Linux::_numa_interleave_memory; +unsigned long* os::Linux::_numa_all_nodes; bool os::uncommit_memory(char* addr, size_t size) { return ::mmap(addr, size, @@ -2477,7 +2500,7 @@ } bool os::unguard_memory(char* addr, size_t size) { - return linux_mprotect(addr, size, PROT_READ|PROT_WRITE|PROT_EXEC); + return linux_mprotect(addr, size, PROT_READ|PROT_WRITE); } // Large page support @@ -3695,7 +3718,17 @@ } if (UseNUMA) { - Linux::libnuma_init(); + if (!Linux::libnuma_init()) { + UseNUMA = false; + } else { + if ((Linux::numa_max_node() < 1)) { + // There's only one node(they start from 0), disable NUMA. + UseNUMA = false; + } + } + if (!UseNUMA && ForceNUMA) { + UseNUMA = true; + } } if (MaxFDLimit) {
--- a/src/os/linux/vm/os_linux.hpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/os/linux/vm/os_linux.hpp Sun Dec 28 11:28:04 2008 -0800 @@ -146,7 +146,7 @@ static bool is_floating_stack() { return _is_floating_stack; } static void libpthread_init(); - static void libnuma_init(); + static bool libnuma_init(); // Minimum stack size a thread can be created with (allowing // the VM to completely create the thread and enter user code) @@ -240,20 +240,23 @@ typedef int (*numa_max_node_func_t)(void); typedef int (*numa_available_func_t)(void); typedef int (*numa_tonode_memory_func_t)(void *start, size_t size, int node); - + typedef void (*numa_interleave_memory_func_t)(void *start, size_t size, unsigned long *nodemask); static sched_getcpu_func_t _sched_getcpu; static numa_node_to_cpus_func_t _numa_node_to_cpus; static numa_max_node_func_t _numa_max_node; static numa_available_func_t _numa_available; static numa_tonode_memory_func_t _numa_tonode_memory; + static numa_interleave_memory_func_t _numa_interleave_memory; + static unsigned long* _numa_all_nodes; static void set_sched_getcpu(sched_getcpu_func_t func) { _sched_getcpu = func; } static void set_numa_node_to_cpus(numa_node_to_cpus_func_t func) { _numa_node_to_cpus = func; } static void set_numa_max_node(numa_max_node_func_t func) { _numa_max_node = func; } static void set_numa_available(numa_available_func_t func) { _numa_available = func; } static void set_numa_tonode_memory(numa_tonode_memory_func_t func) { _numa_tonode_memory = func; } - + static void set_numa_interleave_memory(numa_interleave_memory_func_t func) { _numa_interleave_memory = func; } + static void set_numa_all_nodes(unsigned long* ptr) { _numa_all_nodes = ptr; } public: static int sched_getcpu() { return _sched_getcpu != NULL ? _sched_getcpu() : -1; } static int numa_node_to_cpus(int node, unsigned long *buffer, int bufferlen) { @@ -264,6 +267,11 @@ static int numa_tonode_memory(void *start, size_t size, int node) { return _numa_tonode_memory != NULL ? _numa_tonode_memory(start, size, node) : -1; } + static void numa_interleave_memory(void *start, size_t size) { + if (_numa_interleave_memory != NULL && _numa_all_nodes != NULL) { + _numa_interleave_memory(start, size, _numa_all_nodes); + } + } static int get_node_by_cpu(int cpu_id); };
--- a/src/os/solaris/launcher/java.c Wed Nov 26 05:05:13 2008 -0800 +++ b/src/os/solaris/launcher/java.c Sun Dec 28 11:28:04 2008 -0800 @@ -1,5 +1,5 @@ /* - * Copyright 1998-2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1998-2008 Sun Microsystems, Inc. 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
--- a/src/os/solaris/launcher/java.h Wed Nov 26 05:05:13 2008 -0800 +++ b/src/os/solaris/launcher/java.h Sun Dec 28 11:28:04 2008 -0800 @@ -1,5 +1,5 @@ /* - * Copyright 1998-2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1998-2008 Sun Microsystems, Inc. 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
--- a/src/os/solaris/launcher/java_md.c Wed Nov 26 05:05:13 2008 -0800 +++ b/src/os/solaris/launcher/java_md.c Sun Dec 28 11:28:04 2008 -0800 @@ -1,5 +1,5 @@ /* - * Copyright 1998-2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1998-2008 Sun Microsystems, Inc. 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
--- a/src/os/solaris/vm/globals_solaris.hpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/os/solaris/vm/globals_solaris.hpp Sun Dec 28 11:28:04 2008 -0800 @@ -1,5 +1,5 @@ /* - * Copyright 2005-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2005-2008 Sun Microsystems, Inc. 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
--- a/src/os/solaris/vm/os_solaris.cpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/os/solaris/vm/os_solaris.cpp Sun Dec 28 11:28:04 2008 -0800 @@ -1638,16 +1638,24 @@ // getTimeNanos is guaranteed to not move backward on Solaris inline hrtime_t getTimeNanos() { if (VM_Version::supports_cx8()) { - bool retry = false; - hrtime_t newtime = gethrtime(); - hrtime_t oldmaxtime = max_hrtime; - hrtime_t retmaxtime = oldmaxtime; - while ((newtime > retmaxtime) && (retry == false || retmaxtime != oldmaxtime)) { - oldmaxtime = retmaxtime; - retmaxtime = Atomic::cmpxchg(newtime, (volatile jlong *)&max_hrtime, oldmaxtime); - retry = true; - } - return (newtime > retmaxtime) ? newtime : retmaxtime; + const hrtime_t now = gethrtime(); + const hrtime_t prev = max_hrtime; + if (now <= prev) return prev; // same or retrograde time; + const hrtime_t obsv = Atomic::cmpxchg(now, (volatile jlong*)&max_hrtime, prev); + assert(obsv >= prev, "invariant"); // Monotonicity + // If the CAS succeeded then we're done and return "now". + // If the CAS failed and the observed value "obs" is >= now then + // we should return "obs". If the CAS failed and now > obs > prv then + // some other thread raced this thread and installed a new value, in which case + // we could either (a) retry the entire operation, (b) retry trying to install now + // or (c) just return obs. We use (c). No loop is required although in some cases + // we might discard a higher "now" value in deference to a slightly lower but freshly + // installed obs value. That's entirely benign -- it admits no new orderings compared + // to (a) or (b) -- and greatly reduces coherence traffic. + // We might also condition (c) on the magnitude of the delta between obs and now. + // Avoiding excessive CAS operations to hot RW locations is critical. + // See http://blogs.sun.com/dave/entry/cas_and_cache_trivia_invalidate + return (prev == obsv) ? now : obsv ; } else { return oldgetTimeNanos(); } @@ -3026,6 +3034,8 @@ // Protect memory (Used to pass readonly pages through // JNI GetArray<type>Elements with empty arrays.) +// Also, used for serialization page and for compressed oops null pointer +// checking. bool os::protect_memory(char* addr, size_t bytes, ProtType prot, bool is_committed) { unsigned int p = 0; @@ -3049,7 +3059,7 @@ } bool os::unguard_memory(char* addr, size_t bytes) { - return solaris_mprotect(addr, bytes, PROT_READ|PROT_WRITE|PROT_EXEC); + return solaris_mprotect(addr, bytes, PROT_READ|PROT_WRITE); } // Large page support @@ -4638,7 +4648,7 @@ } } -void os::Solaris::liblgrp_init() { +bool os::Solaris::liblgrp_init() { void *handle = dlopen("liblgrp.so.1", RTLD_LAZY); if (handle != NULL) { os::Solaris::set_lgrp_home(CAST_TO_FN_PTR(lgrp_home_func_t, dlsym(handle, "lgrp_home"))); @@ -4653,9 +4663,9 @@ lgrp_cookie_t c = lgrp_init(LGRP_VIEW_CALLER); set_lgrp_cookie(c); - } else { - warning("your OS does not support NUMA"); - } + return true; + } + return false; } void os::Solaris::misc_sym_init() { @@ -4824,9 +4834,25 @@ vm_page_size())); Solaris::libthread_init(); + if (UseNUMA) { - Solaris::liblgrp_init(); - } + if (!Solaris::liblgrp_init()) { + UseNUMA = false; + } else { + size_t lgrp_limit = os::numa_get_groups_num(); + int *lgrp_ids = NEW_C_HEAP_ARRAY(int, lgrp_limit); + size_t lgrp_num = os::numa_get_leaf_groups(lgrp_ids, lgrp_limit); + FREE_C_HEAP_ARRAY(int, lgrp_ids); + if (lgrp_num < 2) { + // There's only one locality group, disable NUMA. + UseNUMA = false; + } + } + if (!UseNUMA && ForceNUMA) { + UseNUMA = true; + } + } + Solaris::misc_sym_init(); Solaris::signal_sets_init(); Solaris::init_signal_mem();
--- a/src/os/solaris/vm/os_solaris.hpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/os/solaris/vm/os_solaris.hpp Sun Dec 28 11:28:04 2008 -0800 @@ -176,7 +176,7 @@ public: static void libthread_init(); static void synchronization_init(); - static void liblgrp_init(); + static bool liblgrp_init(); // Load miscellaneous symbols. static void misc_sym_init(); // This boolean allows users to forward their own non-matching signals
--- a/src/os/windows/vm/globals_windows.hpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/os/windows/vm/globals_windows.hpp Sun Dec 28 11:28:04 2008 -0800 @@ -1,5 +1,5 @@ /* - * Copyright 2005-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2005-2008 Sun Microsystems, Inc. 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
--- a/src/os/windows/vm/os_windows.cpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/os/windows/vm/os_windows.cpp Sun Dec 28 11:28:04 2008 -0800 @@ -2020,10 +2020,11 @@ if (UnguardOnExecutionViolation > 0 && addr != last_addr && (UnguardOnExecutionViolation > 1 || os::address_is_in_vm(addr))) { - // Unguard and retry + // Set memory to RWX and retry address page_start = (address) align_size_down((intptr_t) addr, (intptr_t) page_size); - bool res = os::unguard_memory((char*) page_start, page_size); + bool res = os::protect_memory((char*) page_start, page_size, + os::MEM_PROT_RWX); if (PrintMiscellaneous && Verbose) { char buf[256]; @@ -2217,15 +2218,10 @@ // We only expect null pointers in the stubs (vtable) // the rest are checked explicitly now. // - CodeBlob* cb = CodeCache::find_blob(pc); - if (cb != NULL) { - if (VtableStubs::stub_containing(pc) != NULL) { - if (((uintptr_t)addr) < os::vm_page_size() ) { - // an access to the first page of VM--assume it is a null pointer - return Handle_Exception(exceptionInfo, - SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::IMPLICIT_NULL)); - } - } + if (((uintptr_t)addr) < os::vm_page_size() ) { + // an access to the first page of VM--assume it is a null pointer + address stub = SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::IMPLICIT_NULL); + if (stub != NULL) return Handle_Exception(exceptionInfo, stub); } } } // in_java @@ -2241,9 +2237,8 @@ // Windows 98 reports faulting addresses incorrectly if (!MacroAssembler::needs_explicit_null_check((intptr_t)addr) || !os::win32::is_nt()) { - - return Handle_Exception(exceptionInfo, - SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::IMPLICIT_NULL)); + address stub = SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::IMPLICIT_NULL); + if (stub != NULL) return Handle_Exception(exceptionInfo, stub); } report_error(t, exception_code, pc, exceptionInfo->ExceptionRecord, exceptionInfo->ContextRecord); @@ -2761,12 +2756,12 @@ bool os::guard_memory(char* addr, size_t bytes) { DWORD old_status; - return VirtualProtect(addr, bytes, PAGE_EXECUTE_READWRITE | PAGE_GUARD, &old_status) != 0; + return VirtualProtect(addr, bytes, PAGE_READWRITE | PAGE_GUARD, &old_status) != 0; } bool os::unguard_memory(char* addr, size_t bytes) { DWORD old_status; - return VirtualProtect(addr, bytes, PAGE_EXECUTE_READWRITE, &old_status) != 0; + return VirtualProtect(addr, bytes, PAGE_READWRITE, &old_status) != 0; } void os::realign_memory(char *addr, size_t bytes, size_t alignment_hint) { } @@ -3353,6 +3348,10 @@ // initialize thread priority policy prio_init(); + if (UseNUMA && !ForceNUMA) { + UseNUMA = false; // Currently unsupported. + } + return JNI_OK; }
--- a/src/os/windows/vm/os_windows.hpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/os/windows/vm/os_windows.hpp Sun Dec 28 11:28:04 2008 -0800 @@ -1,5 +1,5 @@ /* - * Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2008 Sun Microsystems, Inc. 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
--- a/src/os_cpu/linux_x86/vm/linux_x86_32.ad Wed Nov 26 05:05:13 2008 -0800 +++ b/src/os_cpu/linux_x86/vm/linux_x86_32.ad Sun Dec 28 11:28:04 2008 -0800 @@ -1,5 +1,5 @@ // -// Copyright 1999-2006 Sun Microsystems, Inc. All Rights Reserved. +// Copyright 1999-2008 Sun Microsystems, Inc. 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
--- a/src/os_cpu/linux_x86/vm/os_linux_x86.cpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/os_cpu/linux_x86/vm/os_linux_x86.cpp Sun Dec 28 11:28:04 2008 -0800 @@ -422,10 +422,11 @@ if (addr != last_addr && (UnguardOnExecutionViolation > 1 || os::address_is_in_vm(addr))) { - // Unguard and retry + // Set memory to RWX and retry address page_start = (address) align_size_down((intptr_t) addr, (intptr_t) page_size); - bool res = os::unguard_memory((char*) page_start, page_size); + bool res = os::protect_memory((char*) page_start, page_size, + os::MEM_PROT_RWX); if (PrintMiscellaneous && Verbose) { char buf[256];
--- a/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp Sun Dec 28 11:28:04 2008 -0800 @@ -203,10 +203,10 @@ return frame(fr->sender_sp(), fr->link(), fr->sender_pc()); } -extern "C" intptr_t *_get_previous_fp(); // in .il file. +extern "C" intptr_t *_get_current_fp(); // in .il file frame os::current_frame() { - intptr_t* fp = _get_previous_fp(); + intptr_t* fp = _get_current_fp(); // it's inlined so want current fp frame myframe((intptr_t*)os::current_stack_pointer(), (intptr_t*)fp, CAST_FROM_FN_PTR(address, os::current_frame)); @@ -576,10 +576,11 @@ if (addr != last_addr && (UnguardOnExecutionViolation > 1 || os::address_is_in_vm(addr))) { - // Unguard and retry + // Make memory rwx and retry address page_start = (address) align_size_down((intptr_t) addr, (intptr_t) page_size); - bool res = os::unguard_memory((char*) page_start, page_size); + bool res = os::protect_memory((char*) page_start, page_size, + os::MEM_PROT_RWX); if (PrintMiscellaneous && Verbose) { char buf[256];
--- a/src/os_cpu/solaris_x86/vm/solaris_x86_32.il Wed Nov 26 05:05:13 2008 -0800 +++ b/src/os_cpu/solaris_x86/vm/solaris_x86_32.il Sun Dec 28 11:28:04 2008 -0800 @@ -37,10 +37,10 @@ movl %gs:0, %eax .end - // Get callers fp - .inline _get_previous_fp,0 + // Get current fp + .inline _get_current_fp,0 + .volatile movl %ebp, %eax - movl %eax, %eax .end // Support for jint Atomic::add(jint inc, volatile jint* dest)
--- a/src/os_cpu/solaris_x86/vm/solaris_x86_64.il Wed Nov 26 05:05:13 2008 -0800 +++ b/src/os_cpu/solaris_x86/vm/solaris_x86_64.il Sun Dec 28 11:28:04 2008 -0800 @@ -30,10 +30,10 @@ movq %fs:0, %rax .end - // Get the frame pointer from previous frame. - .inline _get_previous_fp,0 + // Get the frame pointer from current frame. + .inline _get_current_fp,0 + .volatile movq %rbp, %rax - movq %rax, %rax .end // Support for jint Atomic::add(jint add_value, volatile jint* dest)
--- a/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/XMLWriter.java Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/XMLWriter.java Sun Dec 28 11:28:04 2008 -0800 @@ -1,5 +1,5 @@ /* - * Copyright 1998-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1998-2008 Sun Microsystems, Inc. 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
--- a/src/share/tools/IdealGraphVisualizer/Difference/src/com/sun/hotspot/igv/difference/Difference.java Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/tools/IdealGraphVisualizer/Difference/src/com/sun/hotspot/igv/difference/Difference.java Sun Dec 28 11:28:04 2008 -0800 @@ -1,5 +1,5 @@ /* - * Copyright 1998-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1998-2008 Sun Microsystems, Inc. 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
--- a/src/share/tools/IdealGraphVisualizer/Filter/src/com/sun/hotspot/igv/filter/CustomFilter.java Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/tools/IdealGraphVisualizer/Filter/src/com/sun/hotspot/igv/filter/CustomFilter.java Sun Dec 28 11:28:04 2008 -0800 @@ -1,5 +1,5 @@ /* - * Copyright 1998-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1998-2008 Sun Microsystems, Inc. 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
--- a/src/share/tools/IdealGraphVisualizer/Util/src/com/sun/hotspot/igv/util/PropertiesSheet.java Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/tools/IdealGraphVisualizer/Util/src/com/sun/hotspot/igv/util/PropertiesSheet.java Sun Dec 28 11:28:04 2008 -0800 @@ -1,5 +1,5 @@ /* - * Copyright 1998-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1998-2008 Sun Microsystems, Inc. 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
--- a/src/share/tools/IdealGraphVisualizer/Util/src/com/sun/hotspot/igv/util/RangeSliderModel.java Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/tools/IdealGraphVisualizer/Util/src/com/sun/hotspot/igv/util/RangeSliderModel.java Sun Dec 28 11:28:04 2008 -0800 @@ -1,5 +1,5 @@ /* - * Copyright 1998-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1998-2008 Sun Microsystems, Inc. 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
--- a/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/DiagramViewModel.java Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/DiagramViewModel.java Sun Dec 28 11:28:04 2008 -0800 @@ -1,5 +1,5 @@ /* - * Copyright 1998-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1998-2008 Sun Microsystems, Inc. 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
--- a/src/share/vm/adlc/adlparse.cpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/adlc/adlparse.cpp Sun Dec 28 11:28:04 2008 -0800 @@ -1,5 +1,5 @@ /* - * Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2008 Sun Microsystems, Inc. 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 @@ -108,6 +108,7 @@ else if (!strcmp(ident, "pipeline")) pipe_parse(); else if (!strcmp(ident, "definitions")) definitions_parse(); else if (!strcmp(ident, "peephole")) peep_parse(); + else if (!strcmp(ident, "#line")) preproc_line(); else if (!strcmp(ident, "#define")) preproc_define(); else if (!strcmp(ident, "#undef")) preproc_undef(); else { @@ -786,9 +787,11 @@ parse_err(SYNERR, "missing identifier inside register block.\n"); return; } - if (strcmp(token,"reg_def")==0) { reg_def_parse(); } - if (strcmp(token,"reg_class")==0) { reg_class_parse(); } - if (strcmp(token,"alloc_class")==0) { alloc_class_parse(); } + if (strcmp(token,"reg_def")==0) { reg_def_parse(); } + else if (strcmp(token,"reg_class")==0) { reg_class_parse(); } + else if (strcmp(token,"alloc_class")==0) { alloc_class_parse(); } + else if (strcmp(token,"#define")==0) { preproc_define(); } + else { parse_err(SYNERR, "bad token %s inside register block.\n", token); break; } skipws(); } } @@ -903,11 +906,7 @@ skipws_no_preproc(); // Skip leading whitespace // Prepend location descriptor, for debugging; cf. ADLParser::find_cpp_block if (_AD._adlocation_debug) { - const char* file = _AD._ADL_file._name; - int line = linenum(); - char* location = (char *)malloc(strlen(file) + 100); - sprintf(location, "#line %d \"%s\"\n", line, file); - encoding->add_code(location); + encoding->add_code(get_line_string()); } // Collect the parts of the encode description @@ -948,6 +947,10 @@ skipws(); + if (_AD._adlocation_debug) { + encoding->add_code(end_line_marker()); + } + // Debug Stuff if (_AD._adl_debug > 1) fprintf(stderr,"EncodingClass Form: %s\n", ec_name); } @@ -2349,7 +2352,11 @@ return; } RegDef *regDef = _AD._register->getRegDef(rname); - reg_class->addReg(regDef); // add regDef to regClass + if (!regDef) { + parse_err(SEMERR, "unknown identifier %s inside reg_class list.\n", rname); + } else { + reg_class->addReg(regDef); // add regDef to regClass + } // Check for ',' and position to next token. skipws(); @@ -2746,7 +2753,8 @@ char *rule = NULL; // String representation of predicate skipws(); // Skip leading whitespace - if ( (rule = get_paren_expr("pred expression")) == NULL ) { + int line = linenum(); + if ( (rule = get_paren_expr("pred expression", true)) == NULL ) { parse_err(SYNERR, "incorrect or missing expression for 'predicate'\n"); return NULL; } @@ -3407,7 +3415,12 @@ // Check if there is a string to pass through to output char *start = _ptr; // Record start of the next string while ((_curchar != '$') && (_curchar != '"') && (_curchar != '%') && (_curchar != '\n')) { - if (_curchar == '\\') next_char(); // superquote + if (_curchar == '\\') { + next_char(); // superquote + if ((_curchar == '$') || (_curchar == '%')) + // hack to avoid % escapes and warnings about undefined \ escapes + *(_ptr-1) = _curchar; + } if (_curchar == '\n') parse_err(SYNERR, "newline in string"); // unimplemented! next_char(); } @@ -3942,8 +3955,7 @@ next_char(); // Skip block delimiter skipws_no_preproc(); // Skip leading whitespace cppBlock = _ptr; // Point to start of expression - const char* file = _AD._ADL_file._name; - int line = linenum(); + int line = linenum(); next = _ptr + 1; while(((_curchar != '%') || (*next != '}')) && (_curchar != '\0')) { next_char_or_line(); @@ -3958,15 +3970,16 @@ _curchar = *_ptr; // Maintain invariant // Prepend location descriptor, for debugging. - char* location = (char *)malloc(strlen(file) + 100); - *location = '\0'; - if (_AD._adlocation_debug) - sprintf(location, "#line %d \"%s\"\n", line, file); - char* result = (char *)malloc(strlen(location) + strlen(cppBlock) + 1); - strcpy(result, location); - strcat(result, cppBlock); - cppBlock = result; - free(location); + if (_AD._adlocation_debug) { + char* location = get_line_string(line); + char* end_loc = end_line_marker(); + char* result = (char *)malloc(strlen(location) + strlen(cppBlock) + strlen(end_loc) + 1); + strcpy(result, location); + strcat(result, cppBlock); + strcat(result, end_loc); + cppBlock = result; + free(location); + } } return cppBlock; @@ -4036,13 +4049,26 @@ // Helper function around get_expr // Sets _curchar to '(' so that get_paren_expr will search for a matching ')' -char *ADLParser::get_paren_expr(const char *description) { +char *ADLParser::get_paren_expr(const char *description, bool include_location) { + int line = linenum(); if (_curchar != '(') // Escape if not valid starting position return NULL; next_char(); // Skip the required initial paren. char *token2 = get_expr(description, ")"); if (_curchar == ')') next_char(); // Skip required final paren. + int junk = 0; + if (include_location && _AD._adlocation_debug && !is_int_token(token2, junk)) { + // Prepend location descriptor, for debugging. + char* location = get_line_string(line); + char* end_loc = end_line_marker(); + char* result = (char *)malloc(strlen(location) + strlen(token2) + strlen(end_loc) + 1); + strcpy(result, location); + strcat(result, token2); + strcat(result, end_loc); + token2 = result; + free(location); + } return token2; } @@ -4082,10 +4108,16 @@ if (do_preproc && start != NULL) { const char* def = _AD.get_preproc_def(start); if (def != NULL && strcmp(def, start)) { - const char* def2 = _AD.get_preproc_def(def); - if (def2 != NULL && strcmp(def2, def)) { - parse_err(SYNERR, "unimplemented: using %s defined as %s => %s", - start, def, def2); + const char* def1 = def; + const char* def2 = _AD.get_preproc_def(def1); + // implement up to 2 levels of #define + if (def2 != NULL && strcmp(def2, def1)) { + def = def2; + const char* def3 = _AD.get_preproc_def(def2); + if (def3 != NULL && strcmp(def3, def2) && strcmp(def3, def1)) { + parse_err(SYNERR, "unimplemented: using %s defined as %s => %s => %s", + start, def1, def2, def3); + } } start = strdup(def); } @@ -4431,6 +4463,35 @@ } +//-------------------------------preproc_line---------------------------------- +// A "#line" keyword has been seen, so parse the rest of the line. +void ADLParser::preproc_line(void) { + int line = get_int(); + skipws_no_preproc(); + const char* file = NULL; + if (_curchar == '"') { + next_char(); // Move past the initial '"' + file = _ptr; + while (true) { + if (_curchar == '\n') { + parse_err(SYNERR, "missing '\"' at end of #line directive"); + return; + } + if (_curchar == '"') { + *_ptr = '\0'; // Terminate the string + next_char(); + skipws_no_preproc(); + break; + } + next_char(); + } + } + ensure_end_of_line(); + if (file != NULL) + _AD._ADL_file._name = file; + _buf.set_linenum(line); +} + //------------------------------preproc_define--------------------------------- // A "#define" keyword has been seen, so parse the rest of the line. void ADLParser::preproc_define(void) { @@ -4494,6 +4555,7 @@ // A preprocessor directive has been encountered. Be sure it has fallen at // the begining of a line, or else report an error. void ADLParser::ensure_start_of_line(void) { + if (_curchar == '\n') { next_line(); return; } assert( _ptr >= _curline && _ptr < _curline+strlen(_curline), "Must be able to find which line we are in" ); @@ -4662,6 +4724,7 @@ //---------------------------next_char----------------------------------------- void ADLParser::next_char() { + if (_curchar == '\n') parse_err(WARN, "must call next_line!"); _curchar = *++_ptr; // if ( _curchar == '\n' ) { // next_line(); @@ -4682,6 +4745,18 @@ //---------------------------next_line----------------------------------------- void ADLParser::next_line() { _curline = _buf.get_line(); + _curchar = ' '; +} + +//------------------------get_line_string-------------------------------------- +// Prepended location descriptor, for debugging. +// Must return a malloced string (that can be freed if desired). +char* ADLParser::get_line_string(int linenum) { + const char* file = _AD._ADL_file._name; + int line = linenum ? linenum : this->linenum(); + char* location = (char *)malloc(strlen(file) + 100); + sprintf(location, "\n#line %d \"%s\"\n", line, file); + return location; } //-------------------------is_literal_constant--------------------------------- @@ -4722,6 +4797,66 @@ return true; } +static const char* skip_expr_ws(const char* str) { + const char * cp = str; + while (cp[0]) { + if (cp[0] <= ' ') { + ++cp; + } else if (cp[0] == '#') { + ++cp; + while (cp[0] == ' ') ++cp; + assert(0 == strncmp(cp, "line", 4), "must be a #line directive"); + const char* eol = strchr(cp, '\n'); + assert(eol != NULL, "must find end of line"); + if (eol == NULL) eol = cp + strlen(cp); + cp = eol; + } else { + break; + } + } + return cp; +} + +//-----------------------equivalent_expressions-------------------------------- +bool ADLParser::equivalent_expressions(const char* str1, const char* str2) { + if (str1 == str2) + return true; + else if (str1 == NULL || str2 == NULL) + return false; + const char* cp1 = str1; + const char* cp2 = str2; + char in_quote = '\0'; + while (cp1[0] && cp2[0]) { + if (!in_quote) { + // skip spaces and/or cpp directives + const char* cp1a = skip_expr_ws(cp1); + const char* cp2a = skip_expr_ws(cp2); + if (cp1a > cp1 && cp2a > cp2) { + cp1 = cp1a; cp2 = cp2a; + continue; + } + if (cp1a > cp1 || cp2a > cp2) break; // fail + } + // match one non-space char + if (cp1[0] != cp2[0]) break; // fail + char ch = cp1[0]; + cp1++; cp2++; + // watch for quotes + if (in_quote && ch == '\\') { + if (cp1[0] != cp2[0]) break; // fail + if (!cp1[0]) break; + cp1++; cp2++; + } + if (in_quote && ch == in_quote) { + in_quote = '\0'; + } else if (!in_quote && (ch == '"' || ch == '\'')) { + in_quote = ch; + } + } + return (!cp1[0] && !cp2[0]); +} + + //-------------------------------trim------------------------------------------ void ADLParser::trim(char* &token) { while (*token <= ' ') token++;
--- a/src/share/vm/adlc/adlparse.hpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/adlc/adlparse.hpp Sun Dec 28 11:28:04 2008 -0800 @@ -1,5 +1,5 @@ /* - * Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2008 Sun Microsystems, Inc. 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,7 @@ void pipe_parse(void); // Parse pipeline section void definitions_parse(void); // Parse definitions section void peep_parse(void); // Parse peephole rule definitions + void preproc_line(void); // Parse a #line statement void preproc_define(void); // Parse a #define statement void preproc_undef(void); // Parse an #undef statement @@ -226,7 +227,7 @@ void get_effectlist(FormDict &effects, FormDict &operands); // Parse effect-operand pairs // Return the contents of a parenthesized expression. // Requires initial '(' and consumes final ')', which is replaced by '\0'. - char *get_paren_expr(const char *description); + char *get_paren_expr(const char *description, bool include_location = false); // Return expression up to next stop-char, which terminator replaces. // Does not require initial '('. Does not consume final stop-char. // Final stop-char is left in _curchar, but is also is replaced by '\0'. @@ -234,6 +235,11 @@ char *find_cpp_block(const char *description); // Parse a C++ code block // Issue parser error message & go to EOL void parse_err(int flag, const char *fmt, ...); + // Create a location marker for this file and line. + char *get_line_string(int linenum = 0); + // Return a location marker which tells the C preprocessor to + // forget the previous location marker. (Requires awk postprocessing.) + char *end_line_marker() { return (char*)"\n#line 999999\n"; } // Return pointer to current character inline char cur_char(void); @@ -268,5 +274,6 @@ static bool is_literal_constant(const char *hex_string); static bool is_hex_digit(char digit); static bool is_int_token(const char* token, int& intval); + static bool equivalent_expressions(const char* str1, const char* str2); static void trim(char* &token); // trim leading & trailing spaces };
--- a/src/share/vm/adlc/archDesc.cpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/adlc/archDesc.cpp Sun Dec 28 11:28:04 2008 -0800 @@ -140,7 +140,7 @@ if ((rch == _rchild) || (rch && _rchild && !strcmp(rch, _rchild))) { char * predStr = get_pred(); char * prStr = pr?pr->_pred:NULL; - if ((prStr == predStr) || (prStr && predStr && !strcmp(prStr, predStr))) { + if (ADLParser::equivalent_expressions(prStr, predStr)) { return true; } }
--- a/src/share/vm/adlc/dfa.cpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/adlc/dfa.cpp Sun Dec 28 11:28:04 2008 -0800 @@ -458,7 +458,7 @@ class dfa_shared_preds { - enum { count = 2 }; + enum { count = 4 }; static bool _found[count]; static const char* _type [count]; @@ -479,12 +479,15 @@ char c = *prev; switch( c ) { case ' ': + case '\n': return dfa_shared_preds::valid_loc(pred, prev); case '!': case '(': case '<': case '=': return true; + case '"': // such as: #line 10 "myfile.ad"\n mypredicate + return true; case '|': if( prev != pred && *(prev-1) == '|' ) return true; case '&': @@ -564,10 +567,14 @@ } }; // shared predicates, _var and _pred entry should be the same length -bool dfa_shared_preds::_found[dfa_shared_preds::count] = { false, false }; -const char* dfa_shared_preds::_type[dfa_shared_preds::count] = { "int", "bool" }; -const char* dfa_shared_preds::_var [dfa_shared_preds::count] = { "_n_get_int__", "Compile__current____select_24_bit_instr__" }; -const char* dfa_shared_preds::_pred[dfa_shared_preds::count] = { "n->get_int()", "Compile::current()->select_24_bit_instr()" }; +bool dfa_shared_preds::_found[dfa_shared_preds::count] + = { false, false, false, false }; +const char* dfa_shared_preds::_type[dfa_shared_preds::count] + = { "int", "jlong", "intptr_t", "bool" }; +const char* dfa_shared_preds::_var [dfa_shared_preds::count] + = { "_n_get_int__", "_n_get_long__", "_n_get_intptr_t__", "Compile__current____select_24_bit_instr__" }; +const char* dfa_shared_preds::_pred[dfa_shared_preds::count] + = { "n->get_int()", "n->get_long()", "n->get_intptr_t()", "Compile::current()->select_24_bit_instr()" }; void ArchDesc::gen_dfa_state_body(FILE* fp, Dict &minimize, ProductionState &status, Dict &operands_chained_from, int i) {
--- a/src/share/vm/adlc/filebuff.cpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/adlc/filebuff.cpp Sun Dec 28 11:28:04 2008 -0800 @@ -1,5 +1,5 @@ /* - * Copyright 1997-2002 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2008 Sun Microsystems, Inc. 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
--- a/src/share/vm/adlc/filebuff.hpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/adlc/filebuff.hpp Sun Dec 28 11:28:04 2008 -0800 @@ -1,5 +1,5 @@ /* - * Copyright 1997-2004 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2008 Sun Microsystems, Inc. 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 @@ -68,6 +68,7 @@ // and increments bufeol and filepos to point at the end of that line. char *get_line(void); int linenum() const { return _linenum; } + void set_linenum(int line) { _linenum = line; } // This converts a pointer into the buffer to a file offset. It only works // when the pointer is valid (i.e. just obtained from getline()).
--- a/src/share/vm/adlc/formssel.cpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/adlc/formssel.cpp Sun Dec 28 11:28:04 2008 -0800 @@ -1102,10 +1102,7 @@ } if( pred1 != NULL && pred2 != NULL ) { // compare the predicates - const char *str1 = pred1->_pred; - const char *str2 = pred2->_pred; - if( (str1 == NULL && str2 == NULL) - || (str1 != NULL && str2 != NULL && strcmp(str1,str2) == 0) ) { + if (ADLParser::equivalent_expressions(pred1->_pred, pred2->_pred)) { return true; } }
--- a/src/share/vm/adlc/formssel.hpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/adlc/formssel.hpp Sun Dec 28 11:28:04 2008 -0800 @@ -1,5 +1,5 @@ /* - * Copyright 1998-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1998-2008 Sun Microsystems, Inc. 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
--- a/src/share/vm/c1/c1_GraphBuilder.cpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/c1/c1_GraphBuilder.cpp Sun Dec 28 11:28:04 2008 -0800 @@ -1,5 +1,5 @@ /* - * Copyright 1999-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1999-2008 Sun Microsystems, Inc. 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 @@ -676,21 +676,6 @@ } -void GraphBuilder::kill_field(ciField* field) { - if (UseLocalValueNumbering) { - vmap()->kill_field(field); - } -} - - -void GraphBuilder::kill_array(Value value) { - if (UseLocalValueNumbering) { - vmap()->kill_array(value->type()); - } - _memory->store_value(value); -} - - void GraphBuilder::kill_all() { if (UseLocalValueNumbering) { vmap()->kill_all(); @@ -987,8 +972,8 @@ length = append(new ArrayLength(array, lock_stack())); } StoreIndexed* result = new StoreIndexed(array, index, length, type, value, lock_stack()); - kill_array(value); // invalidate all CSEs that are memory accesses of the same type append(result); + _memory->store_value(value); } @@ -1478,9 +1463,6 @@ case Bytecodes::_putstatic: { Value val = pop(type); append(new StoreField(append(obj), offset, field, val, true, lock_stack(), state_copy, is_loaded, is_initialized)); - if (UseLocalValueNumbering) { - vmap()->kill_field(field); // invalidate all CSEs that are memory accesses - } } break; case Bytecodes::_getfield : @@ -1503,7 +1485,6 @@ if (is_loaded) store = _memory->store(store); if (store != NULL) { append(store); - kill_field(field); // invalidate all CSEs that are accesses of this field } } break; @@ -1900,6 +1881,8 @@ assert(i2->bci() != -1, "should already be linked"); return i2; } + ValueNumberingEffects vne(vmap()); + i1->visit(&vne); } if (i1->as_Phi() == NULL && i1->as_Local() == NULL) { @@ -1926,14 +1909,8 @@ assert(_last == i1, "adjust code below"); StateSplit* s = i1->as_StateSplit(); if (s != NULL && i1->as_BlockEnd() == NULL) { - // Continue CSE across certain intrinsics - Intrinsic* intrinsic = s->as_Intrinsic(); - if (UseLocalValueNumbering) { - if (intrinsic == NULL || !intrinsic->preserves_state()) { - vmap()->kill_all(); // for now, hopefully we need this only for calls eventually - } - } if (EliminateFieldAccess) { + Intrinsic* intrinsic = s->as_Intrinsic(); if (s->as_Invoke() != NULL || (intrinsic && !intrinsic->preserves_state())) { _memory->kill(); }
--- a/src/share/vm/c1/c1_GraphBuilder.hpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/c1/c1_GraphBuilder.hpp Sun Dec 28 11:28:04 2008 -0800 @@ -1,5 +1,5 @@ /* - * Copyright 1999-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1999-2008 Sun Microsystems, Inc. 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 @@ -283,8 +283,6 @@ Dependencies* dependency_recorder() const; // = compilation()->dependencies() bool direct_compare(ciKlass* k); - void kill_field(ciField* field); - void kill_array(Value value); void kill_all(); ValueStack* lock_stack();
--- a/src/share/vm/c1/c1_IR.cpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/c1/c1_IR.cpp Sun Dec 28 11:28:04 2008 -0800 @@ -1,5 +1,5 @@ /* - * Copyright 1999-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1999-2008 Sun Microsystems, Inc. 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
--- a/src/share/vm/c1/c1_LIRGenerator.cpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/c1/c1_LIRGenerator.cpp Sun Dec 28 11:28:04 2008 -0800 @@ -1210,8 +1210,8 @@ break; case T_LONG: case T_DOUBLE: - if (c->as_jint_hi_bits() != other->as_jint_lo_bits()) continue; - if (c->as_jint_lo_bits() != other->as_jint_hi_bits()) continue; + if (c->as_jint_hi_bits() != other->as_jint_hi_bits()) continue; + if (c->as_jint_lo_bits() != other->as_jint_lo_bits()) continue; break; case T_OBJECT: if (c->as_jobject() != other->as_jobject()) continue;
--- a/src/share/vm/c1/c1_Optimizer.cpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/c1/c1_Optimizer.cpp Sun Dec 28 11:28:04 2008 -0800 @@ -327,8 +327,6 @@ BlockBegin* fsux = if_->fsux(); if (swapped) { cond = Instruction::mirror(cond); - tsux = if_->fsux(); - fsux = if_->tsux(); } BlockBegin* tblock = tval->compare(cond, con, tsux, fsux);
--- a/src/share/vm/c1/c1_Runtime1.cpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/c1/c1_Runtime1.cpp Sun Dec 28 11:28:04 2008 -0800 @@ -842,6 +842,13 @@ if (TracePatching) { tty->print_cr("Deoptimizing for patching volatile field reference"); } + // It's possible the nmethod was invalidated in the last + // safepoint, but if it's still alive then make it not_entrant. + nmethod* nm = CodeCache::find_nmethod(caller_frame.pc()); + if (nm != NULL) { + nm->make_not_entrant(); + } + VM_DeoptimizeFrame deopt(thread, caller_frame.id()); VMThread::execute(&deopt);
--- a/src/share/vm/c1/c1_ValueMap.hpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/c1/c1_ValueMap.hpp Sun Dec 28 11:28:04 2008 -0800 @@ -1,5 +1,5 @@ /* - * Copyright 1999-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1999-2008 Sun Microsystems, Inc. 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 @@ -133,53 +133,77 @@ virtual void kill_array(ValueType* type) = 0; // visitor functions - void do_StoreField (StoreField* x) { kill_field(x->field()); }; - void do_StoreIndexed (StoreIndexed* x) { kill_array(x->type()); }; - void do_MonitorEnter (MonitorEnter* x) { kill_memory(); }; - void do_MonitorExit (MonitorExit* x) { kill_memory(); }; - void do_Invoke (Invoke* x) { kill_memory(); }; - void do_UnsafePutRaw (UnsafePutRaw* x) { kill_memory(); }; - void do_UnsafePutObject(UnsafePutObject* x) { kill_memory(); }; - void do_Intrinsic (Intrinsic* x) { if (!x->preserves_state()) kill_memory(); }; + void do_StoreField (StoreField* x) { + if (!x->is_initialized()) { + kill_memory(); + } else { + kill_field(x->field()); + } + } + void do_StoreIndexed (StoreIndexed* x) { kill_array(x->type()); } + void do_MonitorEnter (MonitorEnter* x) { kill_memory(); } + void do_MonitorExit (MonitorExit* x) { kill_memory(); } + void do_Invoke (Invoke* x) { kill_memory(); } + void do_UnsafePutRaw (UnsafePutRaw* x) { kill_memory(); } + void do_UnsafePutObject(UnsafePutObject* x) { kill_memory(); } + void do_Intrinsic (Intrinsic* x) { if (!x->preserves_state()) kill_memory(); } - void do_Phi (Phi* x) { /* nothing to do */ }; - void do_Local (Local* x) { /* nothing to do */ }; - void do_Constant (Constant* x) { /* nothing to do */ }; - void do_LoadField (LoadField* x) { /* nothing to do */ }; - void do_ArrayLength (ArrayLength* x) { /* nothing to do */ }; - void do_LoadIndexed (LoadIndexed* x) { /* nothing to do */ }; - void do_NegateOp (NegateOp* x) { /* nothing to do */ }; - void do_ArithmeticOp (ArithmeticOp* x) { /* nothing to do */ }; - void do_ShiftOp (ShiftOp* x) { /* nothing to do */ }; - void do_LogicOp (LogicOp* x) { /* nothing to do */ }; - void do_CompareOp (CompareOp* x) { /* nothing to do */ }; - void do_IfOp (IfOp* x) { /* nothing to do */ }; - void do_Convert (Convert* x) { /* nothing to do */ }; - void do_NullCheck (NullCheck* x) { /* nothing to do */ }; - void do_NewInstance (NewInstance* x) { /* nothing to do */ }; - void do_NewTypeArray (NewTypeArray* x) { /* nothing to do */ }; - void do_NewObjectArray (NewObjectArray* x) { /* nothing to do */ }; - void do_NewMultiArray (NewMultiArray* x) { /* nothing to do */ }; - void do_CheckCast (CheckCast* x) { /* nothing to do */ }; - void do_InstanceOf (InstanceOf* x) { /* nothing to do */ }; - void do_BlockBegin (BlockBegin* x) { /* nothing to do */ }; - void do_Goto (Goto* x) { /* nothing to do */ }; - void do_If (If* x) { /* nothing to do */ }; - void do_IfInstanceOf (IfInstanceOf* x) { /* nothing to do */ }; - void do_TableSwitch (TableSwitch* x) { /* nothing to do */ }; - void do_LookupSwitch (LookupSwitch* x) { /* nothing to do */ }; - void do_Return (Return* x) { /* nothing to do */ }; - void do_Throw (Throw* x) { /* nothing to do */ }; - void do_Base (Base* x) { /* nothing to do */ }; - void do_OsrEntry (OsrEntry* x) { /* nothing to do */ }; - void do_ExceptionObject(ExceptionObject* x) { /* nothing to do */ }; - void do_RoundFP (RoundFP* x) { /* nothing to do */ }; - void do_UnsafeGetRaw (UnsafeGetRaw* x) { /* nothing to do */ }; - void do_UnsafeGetObject(UnsafeGetObject* x) { /* nothing to do */ }; - void do_UnsafePrefetchRead (UnsafePrefetchRead* x) { /* nothing to do */ }; - void do_UnsafePrefetchWrite(UnsafePrefetchWrite* x) { /* nothing to do */ }; - void do_ProfileCall (ProfileCall* x) { /* nothing to do */ }; - void do_ProfileCounter (ProfileCounter* x) { /* nothing to do */ }; + void do_Phi (Phi* x) { /* nothing to do */ } + void do_Local (Local* x) { /* nothing to do */ } + void do_Constant (Constant* x) { /* nothing to do */ } + void do_LoadField (LoadField* x) { + if (!x->is_initialized()) { + kill_memory(); + } + } + void do_ArrayLength (ArrayLength* x) { /* nothing to do */ } + void do_LoadIndexed (LoadIndexed* x) { /* nothing to do */ } + void do_NegateOp (NegateOp* x) { /* nothing to do */ } + void do_ArithmeticOp (ArithmeticOp* x) { /* nothing to do */ } + void do_ShiftOp (ShiftOp* x) { /* nothing to do */ } + void do_LogicOp (LogicOp* x) { /* nothing to do */ } + void do_CompareOp (CompareOp* x) { /* nothing to do */ } + void do_IfOp (IfOp* x) { /* nothing to do */ } + void do_Convert (Convert* x) { /* nothing to do */ } + void do_NullCheck (NullCheck* x) { /* nothing to do */ } + void do_NewInstance (NewInstance* x) { /* nothing to do */ } + void do_NewTypeArray (NewTypeArray* x) { /* nothing to do */ } + void do_NewObjectArray (NewObjectArray* x) { /* nothing to do */ } + void do_NewMultiArray (NewMultiArray* x) { /* nothing to do */ } + void do_CheckCast (CheckCast* x) { /* nothing to do */ } + void do_InstanceOf (InstanceOf* x) { /* nothing to do */ } + void do_BlockBegin (BlockBegin* x) { /* nothing to do */ } + void do_Goto (Goto* x) { /* nothing to do */ } + void do_If (If* x) { /* nothing to do */ } + void do_IfInstanceOf (IfInstanceOf* x) { /* nothing to do */ } + void do_TableSwitch (TableSwitch* x) { /* nothing to do */ } + void do_LookupSwitch (LookupSwitch* x) { /* nothing to do */ } + void do_Return (Return* x) { /* nothing to do */ } + void do_Throw (Throw* x) { /* nothing to do */ } + void do_Base (Base* x) { /* nothing to do */ } + void do_OsrEntry (OsrEntry* x) { /* nothing to do */ } + void do_ExceptionObject(ExceptionObject* x) { /* nothing to do */ } + void do_RoundFP (RoundFP* x) { /* nothing to do */ } + void do_UnsafeGetRaw (UnsafeGetRaw* x) { /* nothing to do */ } + void do_UnsafeGetObject(UnsafeGetObject* x) { /* nothing to do */ } + void do_UnsafePrefetchRead (UnsafePrefetchRead* x) { /* nothing to do */ } + void do_UnsafePrefetchWrite(UnsafePrefetchWrite* x) { /* nothing to do */ } + void do_ProfileCall (ProfileCall* x) { /* nothing to do */ } + void do_ProfileCounter (ProfileCounter* x) { /* nothing to do */ } +}; + + +class ValueNumberingEffects: public ValueNumberingVisitor { + private: + ValueMap* _map; + + public: + // implementation for abstract methods of ValueNumberingVisitor + void kill_memory() { _map->kill_memory(); } + void kill_field(ciField* field) { _map->kill_field(field); } + void kill_array(ValueType* type) { _map->kill_array(type); } + + ValueNumberingEffects(ValueMap* map): _map(map) {} };
--- a/src/share/vm/ci/ciEnv.cpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/ci/ciEnv.cpp Sun Dec 28 11:28:04 2008 -0800 @@ -1,5 +1,5 @@ /* - * Copyright 1999-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1999-2008 Sun Microsystems, Inc. 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
--- a/src/share/vm/ci/ciTypeFlow.cpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/ci/ciTypeFlow.cpp Sun Dec 28 11:28:04 2008 -0800 @@ -1,5 +1,5 @@ /* - * Copyright 2000-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2000-2008 Sun Microsystems, Inc. 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
--- a/src/share/vm/classfile/classFileParser.cpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/classfile/classFileParser.cpp Sun Dec 28 11:28:04 2008 -0800 @@ -581,7 +581,8 @@ interf = KlassHandle(THREAD, k); vmtimer->resume(); - cp->klass_at_put(interface_index, interf()); // eagerly resolve + if (LinkWellKnownClasses) // my super type is well known to me + cp->klass_at_put(interface_index, interf()); // eagerly resolve } if (!Klass::cast(interf())->is_interface()) { @@ -2699,7 +2700,8 @@ CHECK_(nullHandle)); KlassHandle kh (THREAD, k); super_klass = instanceKlassHandle(THREAD, kh()); - cp->klass_at_put(super_class_index, super_klass()); // eagerly resolve + if (LinkWellKnownClasses) // my super class is well known to me + cp->klass_at_put(super_class_index, super_klass()); // eagerly resolve } if (super_klass.not_null()) { if (super_klass->is_interface()) { @@ -3128,7 +3130,8 @@ this_klass->set_method_ordering(method_ordering()); this_klass->set_initial_method_idnum(methods->length()); this_klass->set_name(cp->klass_name_at(this_class_index)); - cp->klass_at_put(this_class_index, this_klass()); // eagerly resolve + if (LinkWellKnownClasses) // I am well known to myself + cp->klass_at_put(this_class_index, this_klass()); // eagerly resolve this_klass->set_protection_domain(protection_domain()); this_klass->set_fields_annotations(fields_annotations()); this_klass->set_methods_annotations(methods_annotations());
--- a/src/share/vm/classfile/classFileParser.hpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/classfile/classFileParser.hpp Sun Dec 28 11:28:04 2008 -0800 @@ -1,5 +1,5 @@ /* - * Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2008 Sun Microsystems, Inc. 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
--- a/src/share/vm/gc_implementation/concurrentMarkSweep/cmsOopClosures.hpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/cmsOopClosures.hpp Sun Dec 28 11:28:04 2008 -0800 @@ -325,24 +325,30 @@ // For objects in CMS generation, this closure marks // given objects (transitively) as being reachable/live. // This is currently used during the (weak) reference object -// processing phase of the CMS final checkpoint step. +// processing phase of the CMS final checkpoint step, as +// well as during the concurrent precleaning of the discovered +// reference lists. class CMSKeepAliveClosure: public OopClosure { private: CMSCollector* _collector; const MemRegion _span; CMSMarkStack* _mark_stack; CMSBitMap* _bit_map; + bool _concurrent_precleaning; protected: DO_OOP_WORK_DEFN public: CMSKeepAliveClosure(CMSCollector* collector, MemRegion span, - CMSBitMap* bit_map, CMSMarkStack* mark_stack): + CMSBitMap* bit_map, CMSMarkStack* mark_stack, + bool cpc): _collector(collector), _span(span), _bit_map(bit_map), - _mark_stack(mark_stack) { + _mark_stack(mark_stack), + _concurrent_precleaning(cpc) { assert(!_span.is_empty(), "Empty span could spell trouble"); } + bool concurrent_precleaning() const { return _concurrent_precleaning; } virtual void do_oop(oop* p); virtual void do_oop(narrowOop* p); inline void do_oop_nv(oop* p) { CMSKeepAliveClosure::do_oop_work(p); }
--- a/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp Sun Dec 28 11:28:04 2008 -0800 @@ -538,6 +538,7 @@ _survivor_chunk_capacity(0), // -- ditto -- _survivor_chunk_index(0), // -- ditto -- _ser_pmc_preclean_ovflw(0), + _ser_kac_preclean_ovflw(0), _ser_pmc_remark_ovflw(0), _par_pmc_remark_ovflw(0), _ser_kac_ovflw(0), @@ -1960,6 +1961,7 @@ ref_processor()->set_enqueuing_is_done(false); ref_processor()->enable_discovery(); + ref_processor()->setup_policy(clear_all_soft_refs); // If an asynchronous collection finishes, the _modUnionTable is // all clear. If we are assuming the collection from an asynchronous // collection, clear the _modUnionTable. @@ -2383,6 +2385,9 @@ Universe::verify(true); } + // Snapshot the soft reference policy to be used in this collection cycle. + ref_processor()->setup_policy(clear_all_soft_refs); + bool init_mark_was_synchronous = false; // until proven otherwise while (_collectorState != Idling) { if (TraceCMSState) { @@ -4388,10 +4393,10 @@ CMSPrecleanRefsYieldClosure yield_cl(this); assert(rp->span().equals(_span), "Spans should be equal"); CMSKeepAliveClosure keep_alive(this, _span, &_markBitMap, - &_markStack); + &_markStack, true /* preclean */); CMSDrainMarkingStackClosure complete_trace(this, - _span, &_markBitMap, &_markStack, - &keep_alive); + _span, &_markBitMap, &_markStack, + &keep_alive, true /* preclean */); // We don't want this step to interfere with a young // collection because we don't want to take CPU @@ -4590,11 +4595,11 @@ if (!dirtyRegion.is_empty()) { assert(numDirtyCards > 0, "consistency check"); HeapWord* stop_point = NULL; + stopTimer(); + CMSTokenSyncWithLocks ts(true, gen->freelistLock(), + bitMapLock()); + startTimer(); { - stopTimer(); - CMSTokenSyncWithLocks ts(true, gen->freelistLock(), - bitMapLock()); - startTimer(); verify_work_stacks_empty(); verify_overflow_empty(); sample_eden(); @@ -4611,10 +4616,6 @@ assert((CMSPermGenPrecleaningEnabled && (gen == _permGen)) || (_collectorState == AbortablePreclean && should_abort_preclean()), "Unparsable objects should only be in perm gen."); - - stopTimer(); - CMSTokenSyncWithLocks ts(true, bitMapLock()); - startTimer(); _modUnionTable.mark_range(MemRegion(stop_point, dirtyRegion.end())); if (should_abort_preclean()) { break; // out of preclean loop @@ -4852,17 +4853,19 @@ // recurrence of that condition. assert(_markStack.isEmpty(), "No grey objects"); size_t ser_ovflw = _ser_pmc_remark_ovflw + _ser_pmc_preclean_ovflw + - _ser_kac_ovflw; + _ser_kac_ovflw + _ser_kac_preclean_ovflw; if (ser_ovflw > 0) { if (PrintCMSStatistics != 0) { gclog_or_tty->print_cr("Marking stack overflow (benign) " - "(pmc_pc="SIZE_FORMAT", pmc_rm="SIZE_FORMAT", kac="SIZE_FORMAT")", + "(pmc_pc="SIZE_FORMAT", pmc_rm="SIZE_FORMAT", kac="SIZE_FORMAT + ", kac_preclean="SIZE_FORMAT")", _ser_pmc_preclean_ovflw, _ser_pmc_remark_ovflw, - _ser_kac_ovflw); + _ser_kac_ovflw, _ser_kac_preclean_ovflw); } _markStack.expand(); _ser_pmc_remark_ovflw = 0; _ser_pmc_preclean_ovflw = 0; + _ser_kac_preclean_ovflw = 0; _ser_kac_ovflw = 0; } if (_par_pmc_remark_ovflw > 0 || _par_kac_ovflw > 0) { @@ -5675,40 +5678,29 @@ ResourceMark rm; HandleMark hm; - ReferencePolicy* soft_ref_policy; - - assert(!ref_processor()->enqueuing_is_done(), "Enqueuing should not be complete"); - // Process weak references. - if (clear_all_soft_refs) { - soft_ref_policy = new AlwaysClearPolicy(); - } else { -#ifdef COMPILER2 - soft_ref_policy = new LRUMaxHeapPolicy(); -#else - soft_ref_policy = new LRUCurrentHeapPolicy(); -#endif // COMPILER2 - } - verify_work_stacks_empty(); ReferenceProcessor* rp = ref_processor(); assert(rp->span().equals(_span), "Spans should be equal"); + assert(!rp->enqueuing_is_done(), "Enqueuing should not be complete"); + // Process weak references. + rp->setup_policy(clear_all_soft_refs); + verify_work_stacks_empty(); + CMSKeepAliveClosure cmsKeepAliveClosure(this, _span, &_markBitMap, - &_markStack); + &_markStack, false /* !preclean */); CMSDrainMarkingStackClosure cmsDrainMarkingStackClosure(this, _span, &_markBitMap, &_markStack, - &cmsKeepAliveClosure); + &cmsKeepAliveClosure, false /* !preclean */); { TraceTime t("weak refs processing", PrintGCDetails, false, gclog_or_tty); if (rp->processing_is_mt()) { CMSRefProcTaskExecutor task_executor(*this); - rp->process_discovered_references(soft_ref_policy, - &_is_alive_closure, + rp->process_discovered_references(&_is_alive_closure, &cmsKeepAliveClosure, &cmsDrainMarkingStackClosure, &task_executor); } else { - rp->process_discovered_references(soft_ref_policy, - &_is_alive_closure, + rp->process_discovered_references(&_is_alive_closure, &cmsKeepAliveClosure, &cmsDrainMarkingStackClosure, NULL); @@ -6163,8 +6155,8 @@ #endif size_t CMSCollector::block_size_using_printezis_bits(HeapWord* addr) const { - assert(_markBitMap.isMarked(addr) && _markBitMap.isMarked(addr + 1), - "missing Printezis mark?"); + assert(_markBitMap.isMarked(addr) && _markBitMap.isMarked(addr + 1), + "missing Printezis mark?"); HeapWord* nextOneAddr = _markBitMap.getNextMarkedWordAddress(addr + 2); size_t size = pointer_delta(nextOneAddr + 1, addr); assert(size == CompactibleFreeListSpace::adjustObjectSize(size), @@ -8302,8 +8294,29 @@ } ) if (simulate_overflow || !_mark_stack->push(obj)) { - _collector->push_on_overflow_list(obj); - _collector->_ser_kac_ovflw++; + if (_concurrent_precleaning) { + // We dirty the overflown object and let the remark + // phase deal with it. + assert(_collector->overflow_list_is_empty(), "Error"); + // In the case of object arrays, we need to dirty all of + // the cards that the object spans. No locking or atomics + // are needed since no one else can be mutating the mod union + // table. + if (obj->is_objArray()) { + size_t sz = obj->size(); + HeapWord* end_card_addr = + (HeapWord*)round_to((intptr_t)(addr+sz), CardTableModRefBS::card_size); + MemRegion redirty_range = MemRegion(addr, end_card_addr); + assert(!redirty_range.is_empty(), "Arithmetical tautology"); + _collector->_modUnionTable.mark_range(redirty_range); + } else { + _collector->_modUnionTable.mark(addr); + } + _collector->_ser_kac_preclean_ovflw++; + } else { + _collector->push_on_overflow_list(obj); + _collector->_ser_kac_ovflw++; + } } } } @@ -8400,6 +8413,8 @@ void CMSDrainMarkingStackClosure::do_void() { // the max number to take from overflow list at a time const size_t num = _mark_stack->capacity()/4; + assert(!_concurrent_precleaning || _collector->overflow_list_is_empty(), + "Overflow list should be NULL during concurrent phases"); while (!_mark_stack->isEmpty() || // if stack is empty, check the overflow list _collector->take_from_overflow_list(num, _mark_stack)) {
--- a/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp Sun Dec 28 11:28:04 2008 -0800 @@ -592,6 +592,7 @@ size_t _ser_pmc_preclean_ovflw; size_t _ser_pmc_remark_ovflw; size_t _par_pmc_remark_ovflw; + size_t _ser_kac_preclean_ovflw; size_t _ser_kac_ovflw; size_t _par_kac_ovflw; NOT_PRODUCT(size_t _num_par_pushes;) @@ -1749,21 +1750,30 @@ // work-routine/closure used to complete transitive // marking of objects as live after a certain point // in which an initial set has been completely accumulated. +// This closure is currently used both during the final +// remark stop-world phase, as well as during the concurrent +// precleaning of the discovered reference lists. class CMSDrainMarkingStackClosure: public VoidClosure { CMSCollector* _collector; MemRegion _span; CMSMarkStack* _mark_stack; CMSBitMap* _bit_map; CMSKeepAliveClosure* _keep_alive; + bool _concurrent_precleaning; public: CMSDrainMarkingStackClosure(CMSCollector* collector, MemRegion span, CMSBitMap* bit_map, CMSMarkStack* mark_stack, - CMSKeepAliveClosure* keep_alive): + CMSKeepAliveClosure* keep_alive, + bool cpc): _collector(collector), _span(span), _bit_map(bit_map), _mark_stack(mark_stack), - _keep_alive(keep_alive) { } + _keep_alive(keep_alive), + _concurrent_precleaning(cpc) { + assert(_concurrent_precleaning == _keep_alive->concurrent_precleaning(), + "Mismatch"); + } void do_void(); };
--- a/src/share/vm/gc_implementation/g1/concurrentMark.cpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/gc_implementation/g1/concurrentMark.cpp Sun Dec 28 11:28:04 2008 -0800 @@ -1,5 +1,5 @@ /* - * Copyright 2001-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2001-2008 Sun Microsystems, Inc. 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 @@ -811,6 +811,7 @@ ReferenceProcessor* rp = g1h->ref_processor(); rp->verify_no_references_recorded(); rp->enable_discovery(); // enable ("weak") refs discovery + rp->setup_policy(false); // snapshot the soft ref policy to be used in this cycle SATBMarkQueueSet& satb_mq_set = JavaThread::satb_mark_queue_set(); satb_mq_set.set_process_completed_threshold(G1SATBProcessCompletedThreshold); @@ -1829,32 +1830,21 @@ void ConcurrentMark::weakRefsWork(bool clear_all_soft_refs) { ResourceMark rm; HandleMark hm; - ReferencePolicy* soft_ref_policy; + G1CollectedHeap* g1h = G1CollectedHeap::heap(); + ReferenceProcessor* rp = g1h->ref_processor(); // Process weak references. - if (clear_all_soft_refs) { - soft_ref_policy = new AlwaysClearPolicy(); - } else { -#ifdef COMPILER2 - soft_ref_policy = new LRUMaxHeapPolicy(); -#else - soft_ref_policy = new LRUCurrentHeapPolicy(); -#endif - } + rp->setup_policy(clear_all_soft_refs); assert(_markStack.isEmpty(), "mark stack should be empty"); - G1CollectedHeap* g1 = G1CollectedHeap::heap(); - G1CMIsAliveClosure g1IsAliveClosure(g1); - - G1CMKeepAliveClosure g1KeepAliveClosure(g1, this, nextMarkBitMap()); + G1CMIsAliveClosure g1IsAliveClosure (g1h); + G1CMKeepAliveClosure g1KeepAliveClosure(g1h, this, nextMarkBitMap()); G1CMDrainMarkingStackClosure g1DrainMarkingStackClosure(nextMarkBitMap(), &_markStack, &g1KeepAliveClosure); // XXXYYY Also: copy the parallel ref processing code from CMS. - ReferenceProcessor* rp = g1->ref_processor(); - rp->process_discovered_references(soft_ref_policy, - &g1IsAliveClosure, + rp->process_discovered_references(&g1IsAliveClosure, &g1KeepAliveClosure, &g1DrainMarkingStackClosure, NULL);
--- a/src/share/vm/gc_implementation/g1/dirtyCardQueue.cpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/gc_implementation/g1/dirtyCardQueue.cpp Sun Dec 28 11:28:04 2008 -0800 @@ -1,5 +1,5 @@ /* - * Copyright 2001-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2001-2008 Sun Microsystems, Inc. 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
--- a/src/share/vm/gc_implementation/g1/g1BlockOffsetTable.cpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/gc_implementation/g1/g1BlockOffsetTable.cpp Sun Dec 28 11:28:04 2008 -0800 @@ -1,5 +1,5 @@ /* - * Copyright 2001-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2001-2008 Sun Microsystems, Inc. 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
--- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Sun Dec 28 11:28:04 2008 -0800 @@ -1,5 +1,5 @@ /* - * Copyright 2001-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2001-2008 Sun Microsystems, Inc. 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 @@ -891,6 +891,7 @@ ReferenceProcessorIsAliveMutator rp_is_alive_null(ref_processor(), NULL); ref_processor()->enable_discovery(); + ref_processor()->setup_policy(clear_all_soft_refs); // Do collection work { @@ -2463,7 +2464,7 @@ COMPILER2_PRESENT(DerivedPointerTable::clear()); - // We want to turn off ref discovere, if necessary, and turn it back on + // We want to turn off ref discovery, if necessary, and turn it back on // on again later if we do. bool was_enabled = ref_processor()->discovery_enabled(); if (was_enabled) ref_processor()->disable_discovery(); @@ -2953,7 +2954,7 @@ // The object has been either evacuated or is dead. Fill it with a // dummy object. MemRegion mr((HeapWord*)obj, obj->size()); - SharedHeap::fill_region_with_object(mr); + CollectedHeap::fill_with_object(mr); _cm->clearRangeBothMaps(mr); } } @@ -3224,7 +3225,7 @@ // Otherwise, try to claim it. block = r->par_allocate(free_words); } while (block == NULL); - SharedHeap::fill_region_with_object(MemRegion(block, free_words)); + fill_with_object(block, free_words); } #define use_local_bitmaps 1 @@ -3618,9 +3619,8 @@ guarantee(alloc_buffer(purpose)->contains(obj + word_sz - 1), "should contain whole object"); alloc_buffer(purpose)->undo_allocation(obj, word_sz); - } - else { - SharedHeap::fill_region_with_object(MemRegion(obj, word_sz)); + } else { + CollectedHeap::fill_with_object(obj, word_sz); add_to_undo_waste(word_sz); } }
--- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp Sun Dec 28 11:28:04 2008 -0800 @@ -1,5 +1,5 @@ /* - * Copyright 2001-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2001-2008 Sun Microsystems, Inc. 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
--- a/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp Sun Dec 28 11:28:04 2008 -0800 @@ -1,5 +1,5 @@ /* - * Copyright 2001-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2001-2008 Sun Microsystems, Inc. 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
--- a/src/share/vm/gc_implementation/g1/g1MarkSweep.cpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/gc_implementation/g1/g1MarkSweep.cpp Sun Dec 28 11:28:04 2008 -0800 @@ -1,5 +1,5 @@ /* - * Copyright 2001-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2001-2008 Sun Microsystems, Inc. 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,8 +33,9 @@ // hook up weak ref data so it can be used during Mark-Sweep assert(GenMarkSweep::ref_processor() == NULL, "no stomping"); + assert(rp != NULL, "should be non-NULL"); GenMarkSweep::_ref_processor = rp; - assert(rp != NULL, "should be non-NULL"); + rp->setup_policy(clear_all_softrefs); // When collecting the permanent generation methodOops may be moving, // so we either have to flush all bcp data or convert it into bci. @@ -121,23 +122,12 @@ &GenMarkSweep::follow_root_closure); // Process reference objects found during marking - ReferencePolicy *soft_ref_policy; - if (clear_all_softrefs) { - soft_ref_policy = new AlwaysClearPolicy(); - } else { -#ifdef COMPILER2 - soft_ref_policy = new LRUMaxHeapPolicy(); -#else - soft_ref_policy = new LRUCurrentHeapPolicy(); -#endif - } - assert(soft_ref_policy != NULL,"No soft reference policy"); - GenMarkSweep::ref_processor()->process_discovered_references( - soft_ref_policy, - &GenMarkSweep::is_alive, - &GenMarkSweep::keep_alive, - &GenMarkSweep::follow_stack_closure, - NULL); + ReferenceProcessor* rp = GenMarkSweep::ref_processor(); + rp->setup_policy(clear_all_softrefs); + rp->process_discovered_references(&GenMarkSweep::is_alive, + &GenMarkSweep::keep_alive, + &GenMarkSweep::follow_stack_closure, + NULL); // Follow system dictionary roots and unload classes bool purged_class = SystemDictionary::do_unloading(&GenMarkSweep::is_alive);
--- a/src/share/vm/gc_implementation/g1/heapRegion.cpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/gc_implementation/g1/heapRegion.cpp Sun Dec 28 11:28:04 2008 -0800 @@ -1,5 +1,5 @@ /* - * Copyright 2001-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2001-2008 Sun Microsystems, Inc. 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
--- a/src/share/vm/gc_implementation/g1/heapRegion.hpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/gc_implementation/g1/heapRegion.hpp Sun Dec 28 11:28:04 2008 -0800 @@ -1,5 +1,5 @@ /* - * Copyright 2001-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2001-2008 Sun Microsystems, Inc. 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
--- a/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp Sun Dec 28 11:28:04 2008 -0800 @@ -181,7 +181,7 @@ void scrub(CardTableModRefBS* ctbs, BitMap* card_bm) { HeapWord* hr_bot = hr()->bottom(); - int hr_first_card_index = ctbs->index_for(hr_bot); + size_t hr_first_card_index = ctbs->index_for(hr_bot); bm()->set_intersection_at_offset(*card_bm, hr_first_card_index); #if PRT_COUNT_OCCUPIED recount_occupied();
--- a/src/share/vm/gc_implementation/g1/heapRegionSeq.cpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/gc_implementation/g1/heapRegionSeq.cpp Sun Dec 28 11:28:04 2008 -0800 @@ -1,5 +1,5 @@ /* - * Copyright 2001-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2001-2008 Sun Microsystems, Inc. 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 @@ -102,7 +102,7 @@ HeapWord* tmp = hr->allocate(sz); assert(tmp != NULL, "Humongous allocation failure"); MemRegion mr = MemRegion(tmp, sz); - SharedHeap::fill_region_with_object(mr); + CollectedHeap::fill_with_object(mr); hr->declare_filled_region_to_BOT(mr); if (i == first) { first_hr->set_startsHumongous();
--- a/src/share/vm/gc_implementation/g1/heapRegionSeq.hpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/gc_implementation/g1/heapRegionSeq.hpp Sun Dec 28 11:28:04 2008 -0800 @@ -1,5 +1,5 @@ /* - * Copyright 2001-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2001-2008 Sun Microsystems, Inc. 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
--- a/src/share/vm/gc_implementation/g1/ptrQueue.cpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/gc_implementation/g1/ptrQueue.cpp Sun Dec 28 11:28:04 2008 -0800 @@ -1,5 +1,5 @@ /* - * Copyright 2001-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2001-2008 Sun Microsystems, Inc. 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
--- a/src/share/vm/gc_implementation/g1/ptrQueue.hpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/gc_implementation/g1/ptrQueue.hpp Sun Dec 28 11:28:04 2008 -0800 @@ -1,5 +1,5 @@ /* - * Copyright 2001-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2001-2008 Sun Microsystems, Inc. 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
--- a/src/share/vm/gc_implementation/includeDB_gc_g1 Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/gc_implementation/includeDB_gc_g1 Sun Dec 28 11:28:04 2008 -0800 @@ -1,5 +1,5 @@ // -// Copyright 2004-2006 Sun Microsystems, Inc. All Rights Reserved. +// Copyright 2004-2008 Sun Microsystems, Inc. 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
--- a/src/share/vm/gc_implementation/parNew/parGCAllocBuffer.cpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/gc_implementation/parNew/parGCAllocBuffer.cpp Sun Dec 28 11:28:04 2008 -0800 @@ -51,14 +51,14 @@ if (_retained) { // If the buffer had been retained shorten the previous filler object. assert(_retained_filler.end() <= _top, "INVARIANT"); - SharedHeap::fill_region_with_object(_retained_filler); + CollectedHeap::fill_with_object(_retained_filler); // Wasted space book-keeping, otherwise (normally) done in invalidate() _wasted += _retained_filler.word_size(); _retained = false; } assert(!end_of_gc || !_retained, "At this point, end_of_gc ==> !_retained."); if (_top < _hard_end) { - SharedHeap::fill_region_with_object(MemRegion(_top, _hard_end)); + CollectedHeap::fill_with_object(_top, _hard_end); if (!retain) { invalidate(); } else { @@ -155,7 +155,7 @@ // modifying the _next_threshold state in the BOT. void ParGCAllocBufferWithBOT::fill_region_with_block(MemRegion mr, bool contig) { - SharedHeap::fill_region_with_object(mr); + CollectedHeap::fill_with_object(mr); if (contig) { _bt.alloc_block(mr.start(), mr.end()); } else { @@ -171,7 +171,7 @@ "or else _true_end should be equal to _hard_end"); assert(_retained, "or else _true_end should be equal to _hard_end"); assert(_retained_filler.end() <= _top, "INVARIANT"); - SharedHeap::fill_region_with_object(_retained_filler); + CollectedHeap::fill_with_object(_retained_filler); if (_top < _hard_end) { fill_region_with_block(MemRegion(_top, _hard_end), true); } @@ -316,11 +316,9 @@ while (_top <= chunk_boundary) { assert(pointer_delta(_hard_end, chunk_boundary) >= AlignmentReserve, "Consequence of last card handling above."); - MemRegion chunk_portion(chunk_boundary, _hard_end); - _bt.BlockOffsetArray::alloc_block(chunk_portion.start(), - chunk_portion.end()); - SharedHeap::fill_region_with_object(chunk_portion); - _hard_end = chunk_portion.start(); + _bt.BlockOffsetArray::alloc_block(chunk_boundary, _hard_end); + CollectedHeap::fill_with_object(chunk_boundary, _hard_end); + _hard_end = chunk_boundary; chunk_boundary -= ChunkSizeInWords; } _end = _hard_end - AlignmentReserve;
--- a/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp Sun Dec 28 11:28:04 2008 -0800 @@ -201,7 +201,7 @@ "Should contain whole object."); to_space_alloc_buffer()->undo_allocation(obj, word_sz); } else { - SharedHeap::fill_region_with_object(MemRegion(obj, word_sz)); + CollectedHeap::fill_with_object(obj, word_sz); } } @@ -759,17 +759,12 @@ thread_state_set.steals(), thread_state_set.pops()+thread_state_set.steals()); } - assert(thread_state_set.pushes() == thread_state_set.pops() + thread_state_set.steals(), + assert(thread_state_set.pushes() == thread_state_set.pops() + + thread_state_set.steals(), "Or else the queues are leaky."); - // For now, process discovered weak refs sequentially. -#ifdef COMPILER2 - ReferencePolicy *soft_ref_policy = new LRUMaxHeapPolicy(); -#else - ReferencePolicy *soft_ref_policy = new LRUCurrentHeapPolicy(); -#endif // COMPILER2 - // Process (weak) reference objects found during scavenge. + ReferenceProcessor* rp = ref_processor(); IsAliveClosure is_alive(this); ScanWeakRefClosure scan_weak_ref(this); KeepAliveClosure keep_alive(&scan_weak_ref); @@ -778,18 +773,17 @@ set_promo_failure_scan_stack_closure(&scan_without_gc_barrier); EvacuateFollowersClosureGeneral evacuate_followers(gch, _level, &scan_without_gc_barrier, &scan_with_gc_barrier); - if (ref_processor()->processing_is_mt()) { + rp->setup_policy(clear_all_soft_refs); + if (rp->processing_is_mt()) { ParNewRefProcTaskExecutor task_executor(*this, thread_state_set); - ref_processor()->process_discovered_references( - soft_ref_policy, &is_alive, &keep_alive, &evacuate_followers, - &task_executor); + rp->process_discovered_references(&is_alive, &keep_alive, + &evacuate_followers, &task_executor); } else { thread_state_set.flush(); gch->set_par_threads(0); // 0 ==> non-parallel. gch->save_marks(); - ref_processor()->process_discovered_references( - soft_ref_policy, &is_alive, &keep_alive, &evacuate_followers, - NULL); + rp->process_discovered_references(&is_alive, &keep_alive, + &evacuate_followers, NULL); } if (!promotion_failed()) { // Swap the survivor spaces. @@ -851,14 +845,14 @@ SpecializationStats::print(); - ref_processor()->set_enqueuing_is_done(true); - if (ref_processor()->processing_is_mt()) { + rp->set_enqueuing_is_done(true); + if (rp->processing_is_mt()) { ParNewRefProcTaskExecutor task_executor(*this, thread_state_set); - ref_processor()->enqueue_discovered_references(&task_executor); + rp->enqueue_discovered_references(&task_executor); } else { - ref_processor()->enqueue_discovered_references(NULL); + rp->enqueue_discovered_references(NULL); } - ref_processor()->verify_no_references_recorded(); + rp->verify_no_references_recorded(); } static int sum; @@ -1211,7 +1205,7 @@ int n = 0; while (cur != NULL) { oop obj_to_push = cur->forwardee(); - oop next = oop(cur->klass()); + oop next = oop(cur->klass_or_null()); cur->set_klass(obj_to_push->klass()); if (par_scan_state->should_be_partially_scanned(obj_to_push, cur)) { obj_to_push = cur;
--- a/src/share/vm/gc_implementation/parallelScavenge/pcTasks.hpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/gc_implementation/parallelScavenge/pcTasks.hpp Sun Dec 28 11:28:04 2008 -0800 @@ -1,5 +1,5 @@ /* - * Copyright 2005-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2005-2008 Sun Microsystems, Inc. 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
--- a/src/share/vm/gc_implementation/parallelScavenge/psCompactionManager.cpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/gc_implementation/parallelScavenge/psCompactionManager.cpp Sun Dec 28 11:28:04 2008 -0800 @@ -1,5 +1,5 @@ /* - * Copyright 2005-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2005-2008 Sun Microsystems, Inc. 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
--- a/src/share/vm/gc_implementation/parallelScavenge/psCompactionManager.hpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/gc_implementation/parallelScavenge/psCompactionManager.hpp Sun Dec 28 11:28:04 2008 -0800 @@ -1,5 +1,5 @@ /* - * Copyright 2005-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2005-2008 Sun Microsystems, Inc. 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
--- a/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp Sun Dec 28 11:28:04 2008 -0800 @@ -172,6 +172,7 @@ COMPILER2_PRESENT(DerivedPointerTable::clear()); ref_processor()->enable_discovery(); + ref_processor()->setup_policy(clear_all_softrefs); mark_sweep_phase1(clear_all_softrefs); @@ -388,7 +389,7 @@ // full GC. const size_t alignment = old_gen->virtual_space()->alignment(); const size_t eden_used = eden_space->used_in_bytes(); - const size_t promoted = (size_t)(size_policy->avg_promoted()->padded_average()); + const size_t promoted = (size_t)size_policy->avg_promoted()->padded_average(); const size_t absorb_size = align_size_up(eden_used + promoted, alignment); const size_t eden_capacity = eden_space->capacity_in_bytes(); @@ -415,16 +416,14 @@ // Fill the unused part of the old gen. MutableSpace* const old_space = old_gen->object_space(); - MemRegion old_gen_unused(old_space->top(), old_space->end()); + HeapWord* const unused_start = old_space->top(); + size_t const unused_words = pointer_delta(old_space->end(), unused_start); - // If the unused part of the old gen cannot be filled, skip - // absorbing eden. - if (old_gen_unused.word_size() < SharedHeap::min_fill_size()) { - return false; - } - - if (!old_gen_unused.is_empty()) { - SharedHeap::fill_region_with_object(old_gen_unused); + if (unused_words > 0) { + if (unused_words < CollectedHeap::min_fill_size()) { + return false; // If the old gen cannot be filled, must give up. + } + CollectedHeap::fill_with_objects(unused_start, unused_words); } // Take the live data from eden and set both top and end in the old gen to @@ -440,9 +439,8 @@ // Update the object start array for the filler object and the data from eden. ObjectStartArray* const start_array = old_gen->start_array(); - HeapWord* const start = old_gen_unused.start(); - for (HeapWord* addr = start; addr < new_top; addr += oop(addr)->size()) { - start_array->allocate_block(addr); + for (HeapWord* p = unused_start; p < new_top; p += oop(p)->size()) { + start_array->allocate_block(p); } // Could update the promoted average here, but it is not typically updated at @@ -517,20 +515,9 @@ // Process reference objects found during marking { - ReferencePolicy *soft_ref_policy; - if (clear_all_softrefs) { - soft_ref_policy = new AlwaysClearPolicy(); - } else { -#ifdef COMPILER2 - soft_ref_policy = new LRUMaxHeapPolicy(); -#else - soft_ref_policy = new LRUCurrentHeapPolicy(); -#endif // COMPILER2 - } - assert(soft_ref_policy != NULL,"No soft reference policy"); + ref_processor()->setup_policy(clear_all_softrefs); ref_processor()->process_discovered_references( - soft_ref_policy, is_alive_closure(), mark_and_push_closure(), - follow_stack_closure(), NULL); + is_alive_closure(), mark_and_push_closure(), follow_stack_closure(), NULL); } // Follow system dictionary roots and unload classes
--- a/src/share/vm/gc_implementation/parallelScavenge/psMarkSweepDecorator.cpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/gc_implementation/parallelScavenge/psMarkSweepDecorator.cpp Sun Dec 28 11:28:04 2008 -0800 @@ -275,22 +275,9 @@ HeapWord* q, size_t deadlength) { if (allowed_deadspace_words >= deadlength) { allowed_deadspace_words -= deadlength; - oop(q)->set_mark(markOopDesc::prototype()->set_marked()); - const size_t aligned_min_int_array_size = - align_object_size(typeArrayOopDesc::header_size(T_INT)); - if (deadlength >= aligned_min_int_array_size) { - oop(q)->set_klass(Universe::intArrayKlassObj()); - assert(((deadlength - aligned_min_int_array_size) * (HeapWordSize/sizeof(jint))) < (size_t)max_jint, - "deadspace too big for Arrayoop"); - typeArrayOop(q)->set_length((int)((deadlength - aligned_min_int_array_size) - * (HeapWordSize/sizeof(jint)))); - } else { - assert((int) deadlength == instanceOopDesc::header_size(), - "size for smallest fake dead object doesn't match"); - oop(q)->set_klass(SystemDictionary::object_klass()); - } - assert((int) deadlength == oop(q)->size(), - "make sure size for fake dead object match"); + CollectedHeap::fill_with_object(q, deadlength); + oop(q)->set_mark(oop(q)->mark()->set_marked()); + assert((int) deadlength == oop(q)->size(), "bad filler object size"); // Recall that we required "q == compaction_top". return true; } else {
--- a/src/share/vm/gc_implementation/parallelScavenge/psMarkSweepDecorator.hpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/gc_implementation/parallelScavenge/psMarkSweepDecorator.hpp Sun Dec 28 11:28:04 2008 -0800 @@ -1,5 +1,5 @@ /* - * Copyright 2001-2002 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2001-2008 Sun Microsystems, Inc. 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
--- a/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp Sun Dec 28 11:28:04 2008 -0800 @@ -88,6 +88,72 @@ GrowableArray<size_t> * PSParallelCompact::_last_gc_live_oops_size = NULL; #endif +void SplitInfo::record(size_t src_region_idx, size_t partial_obj_size, + HeapWord* destination) +{ + assert(src_region_idx != 0, "invalid src_region_idx"); + assert(partial_obj_size != 0, "invalid partial_obj_size argument"); + assert(destination != NULL, "invalid destination argument"); + + _src_region_idx = src_region_idx; + _partial_obj_size = partial_obj_size; + _destination = destination; + + // These fields may not be updated below, so make sure they're clear. + assert(_dest_region_addr == NULL, "should have been cleared"); + assert(_first_src_addr == NULL, "should have been cleared"); + + // Determine the number of destination regions for the partial object. + HeapWord* const last_word = destination + partial_obj_size - 1; + const ParallelCompactData& sd = PSParallelCompact::summary_data(); + HeapWord* const beg_region_addr = sd.region_align_down(destination); + HeapWord* const end_region_addr = sd.region_align_down(last_word); + + if (beg_region_addr == end_region_addr) { + // One destination region. + _destination_count = 1; + if (end_region_addr == destination) { + // The destination falls on a region boundary, thus the first word of the + // partial object will be the first word copied to the destination region. + _dest_region_addr = end_region_addr; + _first_src_addr = sd.region_to_addr(src_region_idx); + } + } else { + // Two destination regions. When copied, the partial object will cross a + // destination region boundary, so a word somewhere within the partial + // object will be the first word copied to the second destination region. + _destination_count = 2; + _dest_region_addr = end_region_addr; + const size_t ofs = pointer_delta(end_region_addr, destination); + assert(ofs < _partial_obj_size, "sanity"); + _first_src_addr = sd.region_to_addr(src_region_idx) + ofs; + } +} + +void SplitInfo::clear() +{ + _src_region_idx = 0; + _partial_obj_size = 0; + _destination = NULL; + _destination_count = 0; + _dest_region_addr = NULL; + _first_src_addr = NULL; + assert(!is_valid(), "sanity"); +} + +#ifdef ASSERT +void SplitInfo::verify_clear() +{ + assert(_src_region_idx == 0, "not clear"); + assert(_partial_obj_size == 0, "not clear"); + assert(_destination == NULL, "not clear"); + assert(_destination_count == 0, "not clear"); + assert(_dest_region_addr == NULL, "not clear"); + assert(_first_src_addr == NULL, "not clear"); +} +#endif // #ifdef ASSERT + + #ifndef PRODUCT const char* PSParallelCompact::space_names[] = { "perm", "old ", "eden", "from", "to " @@ -416,21 +482,134 @@ } } -bool ParallelCompactData::summarize(HeapWord* target_beg, HeapWord* target_end, +// Find the point at which a space can be split and, if necessary, record the +// split point. +// +// If the current src region (which overflowed the destination space) doesn't +// have a partial object, the split point is at the beginning of the current src +// region (an "easy" split, no extra bookkeeping required). +// +// If the current src region has a partial object, the split point is in the +// region where that partial object starts (call it the split_region). If +// split_region has a partial object, then the split point is just after that +// partial object (a "hard" split where we have to record the split data and +// zero the partial_obj_size field). With a "hard" split, we know that the +// partial_obj ends within split_region because the partial object that caused +// the overflow starts in split_region. If split_region doesn't have a partial +// obj, then the split is at the beginning of split_region (another "easy" +// split). +HeapWord* +ParallelCompactData::summarize_split_space(size_t src_region, + SplitInfo& split_info, + HeapWord* destination, + HeapWord* target_end, + HeapWord** target_next) +{ + assert(destination <= target_end, "sanity"); + assert(destination + _region_data[src_region].data_size() > target_end, + "region should not fit into target space"); + + size_t split_region = src_region; + HeapWord* split_destination = destination; + size_t partial_obj_size = _region_data[src_region].partial_obj_size(); + + if (destination + partial_obj_size > target_end) { + // The split point is just after the partial object (if any) in the + // src_region that contains the start of the object that overflowed the + // destination space. + // + // Find the start of the "overflow" object and set split_region to the + // region containing it. + HeapWord* const overflow_obj = _region_data[src_region].partial_obj_addr(); + split_region = addr_to_region_idx(overflow_obj); + + // Clear the source_region field of all destination regions whose first word + // came from data after the split point (a non-null source_region field + // implies a region must be filled). + // + // An alternative to the simple loop below: clear during post_compact(), + // which uses memcpy instead of individual stores, and is easy to + // parallelize. (The downside is that it clears the entire RegionData + // object as opposed to just one field.) + // + // post_compact() would have to clear the summary data up to the highest + // address that was written during the summary phase, which would be + // + // max(top, max(new_top, clear_top)) + // + // where clear_top is a new field in SpaceInfo. Would have to set clear_top + // to destination + partial_obj_size, where both have the values passed to + // this routine. + const RegionData* const sr = region(split_region); + const size_t beg_idx = + addr_to_region_idx(region_align_up(sr->destination() + + sr->partial_obj_size())); + const size_t end_idx = + addr_to_region_idx(region_align_up(destination + partial_obj_size)); + + if (TraceParallelOldGCSummaryPhase) { + gclog_or_tty->print_cr("split: clearing source_region field in [" + SIZE_FORMAT ", " SIZE_FORMAT ")", + beg_idx, end_idx); + } + for (size_t idx = beg_idx; idx < end_idx; ++idx) { + _region_data[idx].set_source_region(0); + } + + // Set split_destination and partial_obj_size to reflect the split region. + split_destination = sr->destination(); + partial_obj_size = sr->partial_obj_size(); + } + + // The split is recorded only if a partial object extends onto the region. + if (partial_obj_size != 0) { + _region_data[split_region].set_partial_obj_size(0); + split_info.record(split_region, partial_obj_size, split_destination); + } + + // Setup the continuation addresses. + *target_next = split_destination + partial_obj_size; + HeapWord* const source_next = region_to_addr(split_region) + partial_obj_size; + + if (TraceParallelOldGCSummaryPhase) { + const char * split_type = partial_obj_size == 0 ? "easy" : "hard"; + gclog_or_tty->print_cr("%s split: src=" PTR_FORMAT " src_c=" SIZE_FORMAT + " pos=" SIZE_FORMAT, + split_type, source_next, split_region, + partial_obj_size); + gclog_or_tty->print_cr("%s split: dst=" PTR_FORMAT " dst_c=" SIZE_FORMAT + " tn=" PTR_FORMAT, + split_type, split_destination, + addr_to_region_idx(split_destination), + *target_next); + + if (partial_obj_size != 0) { + HeapWord* const po_beg = split_info.destination(); + HeapWord* const po_end = po_beg + split_info.partial_obj_size(); + gclog_or_tty->print_cr("%s split: " + "po_beg=" PTR_FORMAT " " SIZE_FORMAT " " + "po_end=" PTR_FORMAT " " SIZE_FORMAT, + split_type, + po_beg, addr_to_region_idx(po_beg), + po_end, addr_to_region_idx(po_end)); + } + } + + return source_next; +} + +bool ParallelCompactData::summarize(SplitInfo& split_info, HeapWord* source_beg, HeapWord* source_end, - HeapWord** target_next, - HeapWord** source_next) { - // This is too strict. - // assert(region_offset(source_beg) == 0, "not RegionSize aligned"); - + HeapWord** source_next, + HeapWord* target_beg, HeapWord* target_end, + HeapWord** target_next) +{ if (TraceParallelOldGCSummaryPhase) { - tty->print_cr("tb=" PTR_FORMAT " te=" PTR_FORMAT " " - "sb=" PTR_FORMAT " se=" PTR_FORMAT " " - "tn=" PTR_FORMAT " sn=" PTR_FORMAT, - target_beg, target_end, - source_beg, source_end, - target_next != 0 ? *target_next : (HeapWord*) 0, - source_next != 0 ? *source_next : (HeapWord*) 0); + HeapWord* const source_next_val = source_next == NULL ? NULL : *source_next; + tty->print_cr("sb=" PTR_FORMAT " se=" PTR_FORMAT " sn=" PTR_FORMAT + "tb=" PTR_FORMAT " te=" PTR_FORMAT " tn=" PTR_FORMAT, + source_beg, source_end, source_next_val, + target_beg, target_end, *target_next); } size_t cur_region = addr_to_region_idx(source_beg); @@ -438,45 +617,53 @@ HeapWord *dest_addr = target_beg; while (cur_region < end_region) { + // The destination must be set even if the region has no data. + _region_data[cur_region].set_destination(dest_addr); + size_t words = _region_data[cur_region].data_size(); - -#if 1 - assert(pointer_delta(target_end, dest_addr) >= words, - "source region does not fit into target region"); -#else - // XXX - need some work on the corner cases here. If the region does not - // fit, then must either make sure any partial_obj from the region fits, or - // "undo" the initial part of the partial_obj that is in the previous - // region. - if (dest_addr + words >= target_end) { - // Let the caller know where to continue. - *target_next = dest_addr; - *source_next = region_to_addr(cur_region); - return false; - } -#endif // #if 1 - - _region_data[cur_region].set_destination(dest_addr); - - // Set the destination_count for cur_region, and if necessary, update - // source_region for a destination region. The source_region field is - // updated if cur_region is the first (left-most) region to be copied to a - // destination region. - // - // The destination_count calculation is a bit subtle. A region that has - // data that compacts into itself does not count itself as a destination. - // This maintains the invariant that a zero count means the region is - // available and can be claimed and then filled. if (words > 0) { + // If cur_region does not fit entirely into the target space, find a point + // at which the source space can be 'split' so that part is copied to the + // target space and the rest is copied elsewhere. + if (dest_addr + words > target_end) { + assert(source_next != NULL, "source_next is NULL when splitting"); + *source_next = summarize_split_space(cur_region, split_info, dest_addr, + target_end, target_next); + return false; + } + + // Compute the destination_count for cur_region, and if necessary, update + // source_region for a destination region. The source_region field is + // updated if cur_region is the first (left-most) region to be copied to a + // destination region. + // + // The destination_count calculation is a bit subtle. A region that has + // data that compacts into itself does not count itself as a destination. + // This maintains the invariant that a zero count means the region is + // available and can be claimed and then filled. + uint destination_count = 0; + if (split_info.is_split(cur_region)) { + // The current region has been split: the partial object will be copied + // to one destination space and the remaining data will be copied to + // another destination space. Adjust the initial destination_count and, + // if necessary, set the source_region field if the partial object will + // cross a destination region boundary. + destination_count = split_info.destination_count(); + if (destination_count == 2) { + size_t dest_idx = addr_to_region_idx(split_info.dest_region_addr()); + _region_data[dest_idx].set_source_region(cur_region); + } + } + HeapWord* const last_addr = dest_addr + words - 1; const size_t dest_region_1 = addr_to_region_idx(dest_addr); const size_t dest_region_2 = addr_to_region_idx(last_addr); -#if 0 + // Initially assume that the destination regions will be the same and // adjust the value below if necessary. Under this assumption, if // cur_region == dest_region_2, then cur_region will be compacted // completely into itself. - uint destination_count = cur_region == dest_region_2 ? 0 : 1; + destination_count += cur_region == dest_region_2 ? 0 : 1; if (dest_region_1 != dest_region_2) { // Destination regions differ; adjust destination_count. destination_count += 1; @@ -487,25 +674,6 @@ // region. _region_data[dest_region_1].set_source_region(cur_region); } -#else - // Initially assume that the destination regions will be different and - // adjust the value below if necessary. Under this assumption, if - // cur_region == dest_region2, then cur_region will be compacted partially - // into dest_region_1 and partially into itself. - uint destination_count = cur_region == dest_region_2 ? 1 : 2; - if (dest_region_1 != dest_region_2) { - // Data from cur_region will be copied to the start of dest_region_2. - _region_data[dest_region_2].set_source_region(cur_region); - } else { - // Destination regions are the same; adjust destination_count. - destination_count -= 1; - if (region_offset(dest_addr) == 0) { - // Data from cur_region will be copied to the start of the destination - // region. - _region_data[dest_region_1].set_source_region(cur_region); - } - } -#endif // #if 0 _region_data[cur_region].set_destination_count(destination_count); _region_data[cur_region].set_data_location(region_to_addr(cur_region)); @@ -558,7 +726,7 @@ size_t live_to_left = bitmap->live_words_in_range(search_start, oop(addr)); result += partial_obj_size + live_to_left; - assert(result <= addr, "object cannot move to the right"); + DEBUG_ONLY(PSParallelCompact::check_new_location(addr, result);) return result; } @@ -749,6 +917,13 @@ const size_t end_region = _summary_data.addr_to_region_idx(_summary_data.region_align_up(max_top)); _summary_data.clear_range(beg_region, end_region); + + // Clear the data used to 'split' regions. + SplitInfo& split_info = _space_info[id].split_info(); + if (split_info.is_valid()) { + split_info.clear(); + } + DEBUG_ONLY(split_info.verify_clear();) } void PSParallelCompact::pre_compact(PreGCValues* pre_gc_values) @@ -807,10 +982,11 @@ { TraceTime tm("post compact", print_phases(), true, gclog_or_tty); - // Clear the marking bitmap and summary data and update top() in each space. for (unsigned int id = perm_space_id; id < last_space_id; ++id) { + // Clear the marking bitmap, summary data and split info. clear_data_covering_space(SpaceId(id)); - _space_info[id].space()->set_top(_space_info[id].new_top()); + // Update top(). Must be done after clearing the bitmap and summary data. + _space_info[id].publish_new_top(); } MutableSpace* const eden_space = _space_info[eden_space_id].space(); @@ -1151,6 +1327,13 @@ PSParallelCompact::compute_dense_prefix(const SpaceId id, bool maximum_compaction) { + if (ParallelOldGCSplitALot) { + if (_space_info[id].dense_prefix() != _space_info[id].space()->bottom()) { + // The value was chosen to provoke splitting a young gen space; use it. + return _space_info[id].dense_prefix(); + } + } + const size_t region_size = ParallelCompactData::RegionSize; const ParallelCompactData& sd = summary_data(); @@ -1239,16 +1422,221 @@ return sd.region_to_addr(best_cp); } +#ifndef PRODUCT +void +PSParallelCompact::fill_with_live_objects(SpaceId id, HeapWord* const start, + size_t words) +{ + if (TraceParallelOldGCSummaryPhase) { + tty->print_cr("fill_with_live_objects [" PTR_FORMAT " " PTR_FORMAT ") " + SIZE_FORMAT, start, start + words, words); + } + + ObjectStartArray* const start_array = _space_info[id].start_array(); + CollectedHeap::fill_with_objects(start, words); + for (HeapWord* p = start; p < start + words; p += oop(p)->size()) { + _mark_bitmap.mark_obj(p, words); + _summary_data.add_obj(p, words); + start_array->allocate_block(p); + } +} + +void +PSParallelCompact::summarize_new_objects(SpaceId id, HeapWord* start) +{ + ParallelCompactData& sd = summary_data(); + MutableSpace* space = _space_info[id].space(); + + // Find the source and destination start addresses. + HeapWord* const src_addr = sd.region_align_down(start); + HeapWord* dst_addr; + if (src_addr < start) { + dst_addr = sd.addr_to_region_ptr(src_addr)->destination(); + } else if (src_addr > space->bottom()) { + // The start (the original top() value) is aligned to a region boundary so + // the associated region does not have a destination. Compute the + // destination from the previous region. + RegionData* const cp = sd.addr_to_region_ptr(src_addr) - 1; + dst_addr = cp->destination() + cp->data_size(); + } else { + // Filling the entire space. + dst_addr = space->bottom(); + } + assert(dst_addr != NULL, "sanity"); + + // Update the summary data. + bool result = _summary_data.summarize(_space_info[id].split_info(), + src_addr, space->top(), NULL, + dst_addr, space->end(), + _space_info[id].new_top_addr()); + assert(result, "should not fail: bad filler object size"); +} + +void +PSParallelCompact::provoke_split_fill_survivor(SpaceId id) +{ + if (total_invocations() % (ParallelOldGCSplitInterval * 3) != 0) { + return; + } + + MutableSpace* const space = _space_info[id].space(); + if (space->is_empty()) { + HeapWord* b = space->bottom(); + HeapWord* t = b + space->capacity_in_words() / 2; + space->set_top(t); + if (ZapUnusedHeapArea) { + space->set_top_for_allocations(); + } + + size_t obj_len = 8; + while (b + obj_len <= t) { + CollectedHeap::fill_with_object(b, obj_len); + mark_bitmap()->mark_obj(b, obj_len); + summary_data().add_obj(b, obj_len); + b += obj_len; + obj_len = (obj_len & 0x18) + 8; // 8 16 24 32 8 16 24 32 ... + } + if (b < t) { + // The loop didn't completely fill to t (top); adjust top downward. + space->set_top(b); + if (ZapUnusedHeapArea) { + space->set_top_for_allocations(); + } + } + + HeapWord** nta = _space_info[id].new_top_addr(); + bool result = summary_data().summarize(_space_info[id].split_info(), + space->bottom(), space->top(), NULL, + space->bottom(), space->end(), nta); + assert(result, "space must fit into itself"); + } +} + +void +PSParallelCompact::provoke_split(bool & max_compaction) +{ + if (total_invocations() % ParallelOldGCSplitInterval != 0) { + return; + } + + const size_t region_size = ParallelCompactData::RegionSize; + ParallelCompactData& sd = summary_data(); + + MutableSpace* const eden_space = _space_info[eden_space_id].space(); + MutableSpace* const from_space = _space_info[from_space_id].space(); + const size_t eden_live = pointer_delta(eden_space->top(), + _space_info[eden_space_id].new_top()); + const size_t from_live = pointer_delta(from_space->top(), + _space_info[from_space_id].new_top()); + + const size_t min_fill_size = CollectedHeap::min_fill_size(); + const size_t eden_free = pointer_delta(eden_space->end(), eden_space->top()); + const size_t eden_fillable = eden_free >= min_fill_size ? eden_free : 0; + const size_t from_free = pointer_delta(from_space->end(), from_space->top()); + const size_t from_fillable = from_free >= min_fill_size ? from_free : 0; + + // Choose the space to split; need at least 2 regions live (or fillable). + SpaceId id; + MutableSpace* space; + size_t live_words; + size_t fill_words; + if (eden_live + eden_fillable >= region_size * 2) { + id = eden_space_id; + space = eden_space; + live_words = eden_live; + fill_words = eden_fillable; + } else if (from_live + from_fillable >= region_size * 2) { + id = from_space_id; + space = from_space; + live_words = from_live; + fill_words = from_fillable; + } else { + return; // Give up. + } + assert(fill_words == 0 || fill_words >= min_fill_size, "sanity"); + + if (live_words < region_size * 2) { + // Fill from top() to end() w/live objects of mixed sizes. + HeapWord* const fill_start = space->top(); + live_words += fill_words; + + space->set_top(fill_start + fill_words); + if (ZapUnusedHeapArea) { + space->set_top_for_allocations(); + } + + HeapWord* cur_addr = fill_start; + while (fill_words > 0) { + const size_t r = (size_t)os::random() % (region_size / 2) + min_fill_size; + size_t cur_size = MIN2(align_object_size_(r), fill_words); + if (fill_words - cur_size < min_fill_size) { + cur_size = fill_words; // Avoid leaving a fragment too small to fill. + } + + CollectedHeap::fill_with_object(cur_addr, cur_size); + mark_bitmap()->mark_obj(cur_addr, cur_size); + sd.add_obj(cur_addr, cur_size); + + cur_addr += cur_size; + fill_words -= cur_size; + } + + summarize_new_objects(id, fill_start); + } + + max_compaction = false; + + // Manipulate the old gen so that it has room for about half of the live data + // in the target young gen space (live_words / 2). + id = old_space_id; + space = _space_info[id].space(); + const size_t free_at_end = space->free_in_words(); + const size_t free_target = align_object_size(live_words / 2); + const size_t dead = pointer_delta(space->top(), _space_info[id].new_top()); + + if (free_at_end >= free_target + min_fill_size) { + // Fill space above top() and set the dense prefix so everything survives. + HeapWord* const fill_start = space->top(); + const size_t fill_size = free_at_end - free_target; + space->set_top(space->top() + fill_size); + if (ZapUnusedHeapArea) { + space->set_top_for_allocations(); + } + fill_with_live_objects(id, fill_start, fill_size); + summarize_new_objects(id, fill_start); + _space_info[id].set_dense_prefix(sd.region_align_down(space->top())); + } else if (dead + free_at_end > free_target) { + // Find a dense prefix that makes the right amount of space available. + HeapWord* cur = sd.region_align_down(space->top()); + HeapWord* cur_destination = sd.addr_to_region_ptr(cur)->destination(); + size_t dead_to_right = pointer_delta(space->end(), cur_destination); + while (dead_to_right < free_target) { + cur -= region_size; + cur_destination = sd.addr_to_region_ptr(cur)->destination(); + dead_to_right = pointer_delta(space->end(), cur_destination); + } + _space_info[id].set_dense_prefix(cur); + } +} +#endif // #ifndef PRODUCT + void PSParallelCompact::summarize_spaces_quick() { for (unsigned int i = 0; i < last_space_id; ++i) { const MutableSpace* space = _space_info[i].space(); - bool result = _summary_data.summarize(space->bottom(), space->end(), - space->bottom(), space->top(), - _space_info[i].new_top_addr()); - assert(result, "should never fail"); + HeapWord** nta = _space_info[i].new_top_addr(); + bool result = _summary_data.summarize(_space_info[i].split_info(), + space->bottom(), space->top(), NULL, + space->bottom(), space->end(), nta); + assert(result, "space must fit into itself"); _space_info[i].set_dense_prefix(space->bottom()); } + +#ifndef PRODUCT + if (ParallelOldGCSplitALot) { + provoke_split_fill_survivor(to_space_id); + } +#endif // #ifndef PRODUCT } void PSParallelCompact::fill_dense_prefix_end(SpaceId id) @@ -1308,8 +1696,7 @@ } #endif // #ifdef _LP64 - MemRegion region(obj_beg, obj_len); - SharedHeap::fill_region_with_object(region); + CollectedHeap::fill_with_object(obj_beg, obj_len); _mark_bitmap.mark_obj(obj_beg, obj_len); _summary_data.add_obj(obj_beg, obj_len); assert(start_array(id) != NULL, "sanity"); @@ -1318,11 +1705,23 @@ } void +PSParallelCompact::clear_source_region(HeapWord* beg_addr, HeapWord* end_addr) +{ + RegionData* const beg_ptr = _summary_data.addr_to_region_ptr(beg_addr); + HeapWord* const end_aligned_up = _summary_data.region_align_up(end_addr); + RegionData* const end_ptr = _summary_data.addr_to_region_ptr(end_aligned_up); + for (RegionData* cur = beg_ptr; cur < end_ptr; ++cur) { + cur->set_source_region(0); + } +} + +void PSParallelCompact::summarize_space(SpaceId id, bool maximum_compaction) { assert(id < last_space_id, "id out of range"); - assert(_space_info[id].dense_prefix() == _space_info[id].space()->bottom(), - "should have been set in summarize_spaces_quick()"); + assert(_space_info[id].dense_prefix() == _space_info[id].space()->bottom() || + ParallelOldGCSplitALot && id == old_space_id, + "should have been reset in summarize_spaces_quick()"); const MutableSpace* space = _space_info[id].space(); if (_space_info[id].new_top() != space->bottom()) { @@ -1338,20 +1737,24 @@ } #endif // #ifndef PRODUCT - // If dead space crosses the dense prefix boundary, it is (at least - // partially) filled with a dummy object, marked live and added to the - // summary data. This simplifies the copy/update phase and must be done - // before the final locations of objects are determined, to prevent leaving - // a fragment of dead space that is too small to fill with an object. + // Recompute the summary data, taking into account the dense prefix. If + // every last byte will be reclaimed, then the existing summary data which + // compacts everything can be left in place. if (!maximum_compaction && dense_prefix_end != space->bottom()) { + // If dead space crosses the dense prefix boundary, it is (at least + // partially) filled with a dummy object, marked live and added to the + // summary data. This simplifies the copy/update phase and must be done + // before the final locations of objects are determined, to prevent + // leaving a fragment of dead space that is too small to fill. fill_dense_prefix_end(id); + + // Compute the destination of each Region, and thus each object. + _summary_data.summarize_dense_prefix(space->bottom(), dense_prefix_end); + _summary_data.summarize(_space_info[id].split_info(), + dense_prefix_end, space->top(), NULL, + dense_prefix_end, space->end(), + _space_info[id].new_top_addr()); } - - // Compute the destination of each Region, and thus each object. - _summary_data.summarize_dense_prefix(space->bottom(), dense_prefix_end); - _summary_data.summarize(dense_prefix_end, space->end(), - dense_prefix_end, space->top(), - _space_info[id].new_top_addr()); } if (TraceParallelOldGCSummaryPhase) { @@ -1371,6 +1774,30 @@ } } +#ifndef PRODUCT +void PSParallelCompact::summary_phase_msg(SpaceId dst_space_id, + HeapWord* dst_beg, HeapWord* dst_end, + SpaceId src_space_id, + HeapWord* src_beg, HeapWord* src_end) +{ + if (TraceParallelOldGCSummaryPhase) { + tty->print_cr("summarizing %d [%s] into %d [%s]: " + "src=" PTR_FORMAT "-" PTR_FORMAT " " + SIZE_FORMAT "-" SIZE_FORMAT " " + "dst=" PTR_FORMAT "-" PTR_FORMAT " " + SIZE_FORMAT "-" SIZE_FORMAT, + src_space_id, space_names[src_space_id], + dst_space_id, space_names[dst_space_id], + src_beg, src_end, + _summary_data.addr_to_region_idx(src_beg), + _summary_data.addr_to_region_idx(src_end), + dst_beg, dst_end, + _summary_data.addr_to_region_idx(dst_beg), + _summary_data.addr_to_region_idx(dst_end)); + } +} +#endif // #ifndef PRODUCT + void PSParallelCompact::summary_phase(ParCompactionManager* cm, bool maximum_compaction) { @@ -1403,57 +1830,80 @@ // The amount of live data that will end up in old space (assuming it fits). size_t old_space_total_live = 0; - unsigned int id; - for (id = old_space_id; id < last_space_id; ++id) { + assert(perm_space_id < old_space_id, "should not count perm data here"); + for (unsigned int id = old_space_id; id < last_space_id; ++id) { old_space_total_live += pointer_delta(_space_info[id].new_top(), _space_info[id].space()->bottom()); } - const MutableSpace* old_space = _space_info[old_space_id].space(); - if (old_space_total_live > old_space->capacity_in_words()) { + MutableSpace* const old_space = _space_info[old_space_id].space(); + const size_t old_capacity = old_space->capacity_in_words(); + if (old_space_total_live > old_capacity) { // XXX - should also try to expand maximum_compaction = true; - } else if (!UseParallelOldGCDensePrefix) { - maximum_compaction = true; } +#ifndef PRODUCT + if (ParallelOldGCSplitALot && old_space_total_live < old_capacity) { + provoke_split(maximum_compaction); + } +#endif // #ifndef PRODUCT // Permanent and Old generations. summarize_space(perm_space_id, maximum_compaction); summarize_space(old_space_id, maximum_compaction); - // Summarize the remaining spaces (those in the young gen) into old space. If - // the live data from a space doesn't fit, the existing summarization is left - // intact, so the data is compacted down within the space itself. - HeapWord** new_top_addr = _space_info[old_space_id].new_top_addr(); - HeapWord* const target_space_end = old_space->end(); - for (id = eden_space_id; id < last_space_id; ++id) { + // Summarize the remaining spaces in the young gen. The initial target space + // is the old gen. If a space does not fit entirely into the target, then the + // remainder is compacted into the space itself and that space becomes the new + // target. + SpaceId dst_space_id = old_space_id; + HeapWord* dst_space_end = old_space->end(); + HeapWord** new_top_addr = _space_info[dst_space_id].new_top_addr(); + for (unsigned int id = eden_space_id; id < last_space_id; ++id) { const MutableSpace* space = _space_info[id].space(); const size_t live = pointer_delta(_space_info[id].new_top(), space->bottom()); - const size_t available = pointer_delta(target_space_end, *new_top_addr); + const size_t available = pointer_delta(dst_space_end, *new_top_addr); + + NOT_PRODUCT(summary_phase_msg(dst_space_id, *new_top_addr, dst_space_end, + SpaceId(id), space->bottom(), space->top());) if (live > 0 && live <= available) { // All the live data will fit. - if (TraceParallelOldGCSummaryPhase) { - tty->print_cr("summarizing %d into old_space @ " PTR_FORMAT, - id, *new_top_addr); - } - _summary_data.summarize(*new_top_addr, target_space_end, - space->bottom(), space->top(), - new_top_addr); - - // Clear the source_region field for each region in the space. - HeapWord* const new_top = _space_info[id].new_top(); - HeapWord* const clear_end = _summary_data.region_align_up(new_top); - RegionData* beg_region = - _summary_data.addr_to_region_ptr(space->bottom()); - RegionData* end_region = _summary_data.addr_to_region_ptr(clear_end); - while (beg_region < end_region) { - beg_region->set_source_region(0); - ++beg_region; - } + bool done = _summary_data.summarize(_space_info[id].split_info(), + space->bottom(), space->top(), + NULL, + *new_top_addr, dst_space_end, + new_top_addr); + assert(done, "space must fit into old gen"); // Reset the new_top value for the space. _space_info[id].set_new_top(space->bottom()); + } else if (live > 0) { + // Attempt to fit part of the source space into the target space. + HeapWord* next_src_addr = NULL; + bool done = _summary_data.summarize(_space_info[id].split_info(), + space->bottom(), space->top(), + &next_src_addr, + *new_top_addr, dst_space_end, + new_top_addr); + assert(!done, "space should not fit into old gen"); + assert(next_src_addr != NULL, "sanity"); + + // The source space becomes the new target, so the remainder is compacted + // within the space itself. + dst_space_id = SpaceId(id); + dst_space_end = space->end(); + new_top_addr = _space_info[id].new_top_addr(); + NOT_PRODUCT(summary_phase_msg(dst_space_id, + space->bottom(), dst_space_end, + SpaceId(id), next_src_addr, space->top());) + done = _summary_data.summarize(_space_info[id].split_info(), + next_src_addr, space->top(), + NULL, + space->bottom(), dst_space_end, + new_top_addr); + assert(done, "space must fit when compacted into itself"); + assert(*new_top_addr <= space->top(), "usage should not grow"); } } @@ -1578,6 +2028,7 @@ COMPILER2_PRESENT(DerivedPointerTable::clear()); ref_processor()->enable_discovery(); + ref_processor()->setup_policy(maximum_heap_compaction); bool marked_for_unloading = false; @@ -1806,9 +2257,14 @@ // Fill the unused part of the old gen. MutableSpace* const old_space = old_gen->object_space(); - MemRegion old_gen_unused(old_space->top(), old_space->end()); - if (!old_gen_unused.is_empty()) { - SharedHeap::fill_region_with_object(old_gen_unused); + HeapWord* const unused_start = old_space->top(); + size_t const unused_words = pointer_delta(old_space->end(), unused_start); + + if (unused_words > 0) { + if (unused_words < CollectedHeap::min_fill_size()) { + return false; // If the old gen cannot be filled, must give up. + } + CollectedHeap::fill_with_objects(unused_start, unused_words); } // Take the live data from eden and set both top and end in the old gen to @@ -1824,9 +2280,8 @@ // Update the object start array for the filler object and the data from eden. ObjectStartArray* const start_array = old_gen->start_array(); - HeapWord* const start = old_gen_unused.start(); - for (HeapWord* addr = start; addr < new_top; addr += oop(addr)->size()) { - start_array->allocate_block(addr); + for (HeapWord* p = unused_start; p < new_top; p += oop(p)->size()) { + start_array->allocate_block(p); } // Could update the promoted average here, but it is not typically updated at @@ -1894,26 +2349,14 @@ // Process reference objects found during marking { TraceTime tm_r("reference processing", print_phases(), true, gclog_or_tty); - ReferencePolicy *soft_ref_policy; - if (maximum_heap_compaction) { - soft_ref_policy = new AlwaysClearPolicy(); - } else { -#ifdef COMPILER2 - soft_ref_policy = new LRUMaxHeapPolicy(); -#else - soft_ref_policy = new LRUCurrentHeapPolicy(); -#endif // COMPILER2 - } - assert(soft_ref_policy != NULL, "No soft reference policy"); if (ref_processor()->processing_is_mt()) { RefProcTaskExecutor task_executor; ref_processor()->process_discovered_references( - soft_ref_policy, is_alive_closure(), &mark_and_push_closure, - &follow_stack_closure, &task_executor); + is_alive_closure(), &mark_and_push_closure, &follow_stack_closure, + &task_executor); } else { ref_processor()->process_discovered_references( - soft_ref_policy, is_alive_closure(), &mark_and_push_closure, - &follow_stack_closure, NULL); + is_alive_closure(), &mark_and_push_closure, &follow_stack_closure, NULL); } } @@ -2059,14 +2502,13 @@ // regions in the dense prefix. Assume that 1 gc thread // will work on opening the gaps and the remaining gc threads // will work on the dense prefix. - SpaceId space_id = old_space_id; - while (space_id != last_space_id) { + unsigned int space_id; + for (space_id = old_space_id; space_id < last_space_id; ++ space_id) { HeapWord* const dense_prefix_end = _space_info[space_id].dense_prefix(); const MutableSpace* const space = _space_info[space_id].space(); if (dense_prefix_end == space->bottom()) { // There is no dense prefix for this space. - space_id = next_compaction_space_id(space_id); continue; } @@ -2116,23 +2558,20 @@ // region_index_end is not processed size_t region_index_end = MIN2(region_index_start + regions_per_thread, region_index_end_dense_prefix); - q->enqueue(new UpdateDensePrefixTask( - space_id, - region_index_start, - region_index_end)); + q->enqueue(new UpdateDensePrefixTask(SpaceId(space_id), + region_index_start, + region_index_end)); region_index_start = region_index_end; } } // This gets any part of the dense prefix that did not // fit evenly. if (region_index_start < region_index_end_dense_prefix) { - q->enqueue(new UpdateDensePrefixTask( - space_id, - region_index_start, - region_index_end_dense_prefix)); + q->enqueue(new UpdateDensePrefixTask(SpaceId(space_id), + region_index_start, + region_index_end_dense_prefix)); } - space_id = next_compaction_space_id(space_id); - } // End tasks for dense prefix + } } void PSParallelCompact::enqueue_region_stealing_tasks( @@ -2578,16 +3017,24 @@ return m->bit_to_addr(cur_beg); } -HeapWord* -PSParallelCompact::first_src_addr(HeapWord* const dest_addr, - size_t src_region_idx) +HeapWord* PSParallelCompact::first_src_addr(HeapWord* const dest_addr, + SpaceId src_space_id, + size_t src_region_idx) { + assert(summary_data().is_region_aligned(dest_addr), "not aligned"); + + const SplitInfo& split_info = _space_info[src_space_id].split_info(); + if (split_info.dest_region_addr() == dest_addr) { + // The partial object ending at the split point contains the first word to + // be copied to dest_addr. + return split_info.first_src_addr(); + } + + const ParallelCompactData& sd = summary_data(); ParMarkBitMap* const bitmap = mark_bitmap(); - const ParallelCompactData& sd = summary_data(); const size_t RegionSize = ParallelCompactData::RegionSize; assert(sd.is_region_aligned(dest_addr), "not aligned"); - const RegionData* const src_region_ptr = sd.region(src_region_idx); const size_t partial_obj_size = src_region_ptr->partial_obj_size(); HeapWord* const src_region_destination = src_region_ptr->destination(); @@ -2636,19 +3083,34 @@ } void PSParallelCompact::decrement_destination_counts(ParCompactionManager* cm, + SpaceId src_space_id, size_t beg_region, HeapWord* end_addr) { ParallelCompactData& sd = summary_data(); + +#ifdef ASSERT + MutableSpace* const src_space = _space_info[src_space_id].space(); + HeapWord* const beg_addr = sd.region_to_addr(beg_region); + assert(src_space->contains(beg_addr) || beg_addr == src_space->end(), + "src_space_id does not match beg_addr"); + assert(src_space->contains(end_addr) || end_addr == src_space->end(), + "src_space_id does not match end_addr"); +#endif // #ifdef ASSERT + RegionData* const beg = sd.region(beg_region); - HeapWord* const end_addr_aligned_up = sd.region_align_up(end_addr); - RegionData* const end = sd.addr_to_region_ptr(end_addr_aligned_up); - size_t cur_idx = beg_region; - for (RegionData* cur = beg; cur < end; ++cur, ++cur_idx) { + RegionData* const end = sd.addr_to_region_ptr(sd.region_align_up(end_addr)); + + // Regions up to new_top() are enqueued if they become available. + HeapWord* const new_top = _space_info[src_space_id].new_top(); + RegionData* const enqueue_end = + sd.addr_to_region_ptr(sd.region_align_up(new_top)); + + for (RegionData* cur = beg; cur < end; ++cur) { assert(cur->data_size() > 0, "region must have live data"); cur->decrement_destination_count(); - if (cur_idx <= cur->source_region() && cur->available() && cur->claim()) { - cm->save_for_processing(cur_idx); + if (cur < enqueue_end && cur->available() && cur->claim()) { + cm->save_for_processing(sd.region(cur)); } } } @@ -2748,7 +3210,7 @@ HeapWord* src_space_top = _space_info[src_space_id].space()->top(); MoveAndUpdateClosure closure(bitmap, cm, start_array, dest_addr, words); - closure.set_source(first_src_addr(dest_addr, src_region_idx)); + closure.set_source(first_src_addr(dest_addr, src_space_id, src_region_idx)); // Adjust src_region_idx to prepare for decrementing destination counts (the // destination count is not decremented when a region is copied to itself). @@ -2763,7 +3225,8 @@ HeapWord* const old_src_addr = closure.source(); closure.copy_partial_obj(); if (closure.is_full()) { - decrement_destination_counts(cm, src_region_idx, closure.source()); + decrement_destination_counts(cm, src_space_id, src_region_idx, + closure.source()); region_ptr->set_deferred_obj_addr(NULL); region_ptr->set_completed(); return; @@ -2772,7 +3235,7 @@ HeapWord* const end_addr = sd.region_align_down(closure.source()); if (sd.region_align_down(old_src_addr) != end_addr) { // The partial object was copied from more than one source region. - decrement_destination_counts(cm, src_region_idx, end_addr); + decrement_destination_counts(cm, src_space_id, src_region_idx, end_addr); // Move to the next source region, possibly switching spaces as well. All // args except end_addr may be modified. @@ -2812,19 +3275,21 @@ region_ptr->set_deferred_obj_addr(closure.destination()); status = closure.copy_until_full(); // copies from closure.source() - decrement_destination_counts(cm, src_region_idx, closure.source()); + decrement_destination_counts(cm, src_space_id, src_region_idx, + closure.source()); region_ptr->set_completed(); return; } if (status == ParMarkBitMap::full) { - decrement_destination_counts(cm, src_region_idx, closure.source()); + decrement_destination_counts(cm, src_space_id, src_region_idx, + closure.source()); region_ptr->set_deferred_obj_addr(NULL); region_ptr->set_completed(); return; } - decrement_destination_counts(cm, src_region_idx, end_addr); + decrement_destination_counts(cm, src_space_id, src_region_idx, end_addr); // Move to the next source region, possibly switching spaces as well. All // args except end_addr may be modified. @@ -2903,7 +3368,7 @@ ParMarkBitMap::IterationStatus MoveAndUpdateClosure::copy_until_full() { if (source() != destination()) { - assert(source() > destination(), "must copy to the left"); + DEBUG_ONLY(PSParallelCompact::check_new_location(source(), destination());) Copy::aligned_conjoint_words(source(), destination(), words_remaining()); } update_state(words_remaining()); @@ -2924,7 +3389,7 @@ // This test is necessary; if omitted, the pointer updates to a partial object // that crosses the dense prefix boundary could be overwritten. if (source() != destination()) { - assert(source() > destination(), "must copy to the left"); + DEBUG_ONLY(PSParallelCompact::check_new_location(source(), destination());) Copy::aligned_conjoint_words(source(), destination(), words); } update_state(words); @@ -2949,7 +3414,7 @@ } if (destination() != source()) { - assert(destination() < source(), "must copy to the left"); + DEBUG_ONLY(PSParallelCompact::check_new_location(source(), destination());) Copy::aligned_conjoint_words(source(), destination(), words); } @@ -3019,34 +3484,3 @@ summary_data().calc_new_pointer(Universe::intArrayKlassObj()); } -// The initial implementation of this method created a field -// _next_compaction_space_id in SpaceInfo and initialized -// that field in SpaceInfo::initialize_space_info(). That -// required that _next_compaction_space_id be declared a -// SpaceId in SpaceInfo and that would have required that -// either SpaceId be declared in a separate class or that -// it be declared in SpaceInfo. It didn't seem consistent -// to declare it in SpaceInfo (didn't really fit logically). -// Alternatively, defining a separate class to define SpaceId -// seem excessive. This implementation is simple and localizes -// the knowledge. - -PSParallelCompact::SpaceId -PSParallelCompact::next_compaction_space_id(SpaceId id) { - assert(id < last_space_id, "id out of range"); - switch (id) { - case perm_space_id : - return last_space_id; - case old_space_id : - return eden_space_id; - case eden_space_id : - return from_space_id; - case from_space_id : - return to_space_id; - case to_space_id : - return last_space_id; - default: - assert(false, "Bad space id"); - return last_space_id; - } -}
--- a/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.hpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.hpp Sun Dec 28 11:28:04 2008 -0800 @@ -36,6 +36,123 @@ class MoveAndUpdateClosure; class RefProcTaskExecutor; +// 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, +// all the live data in a region is copied to a single destination space (e.g., +// everything live in a region in eden is copied entirely into the old gen). +// However, when the heap is nearly full, all the live data in eden may not fit +// into the old gen. Copying only some of the regions from eden to old gen +// requires finding a region that does not contain a partial object (i.e., no +// live object crosses the region boundary) somewhere near the last object that +// does fit into the old gen. Since it's not always possible to find such a +// region, splitting is necessary for predictable behavior. +// +// A region is always split at the end of the partial object. This avoids +// additional tests when calculating the new location of a pointer, which is a +// very hot code path. The partial object and everything to its left will be +// copied to another space (call it dest_space_1). The live data to the right +// of the partial object will be copied either within the space itself, or to a +// different destination space (distinct from dest_space_1). +// +// Split points are identified during the summary phase, when region +// destinations are computed: data about the split, including the +// partial_object_size, is recorded in a SplitInfo record and the +// partial_object_size field in the summary data is set to zero. The zeroing is +// possible (and necessary) since the partial object will move to a different +// destination space than anything to its right, thus the partial object should +// not affect the locations of any objects to its right. +// +// The recorded data is used during the compaction phase, but only rarely: when +// the partial object on the split region will be copied across a destination +// region boundary. This test is made once each time a region is filled, and is +// a simple address comparison, so the overhead is negligible (see +// PSParallelCompact::first_src_addr()). +// +// Notes: +// +// Only regions with partial objects are split; a region without a partial +// object does not need any extra bookkeeping. +// +// At most one region is split per space, so the amount of data required is +// constant. +// +// A region is split only when the destination space would overflow. Once that +// happens, the destination space is abandoned and no other data (even from +// other source spaces) is targeted to that destination space. Abandoning the +// destination space may leave a somewhat large unused area at the end, if a +// large object caused the overflow. +// +// Future work: +// +// More bookkeeping would be required to continue to use the destination space. +// The most general solution would allow data from regions in two different +// source spaces to be "joined" in a single destination region. At the very +// least, additional code would be required in next_src_region() to detect the +// join and skip to an out-of-order source region. If the join region was also +// the last destination region to which a split region was copied (the most +// likely case), then additional work would be needed to get fill_region() to +// stop iteration and switch to a new source region at the right point. Basic +// idea would be to use a fake value for the top of the source space. It is +// doable, if a bit tricky. +// +// A simpler (but less general) solution would fill the remainder of the +// destination region with a dummy object and continue filling the next +// destination region. + +class SplitInfo +{ +public: + // Return true if this split info is valid (i.e., if a split has been + // recorded). The very first region cannot have a partial object and thus is + // never split, so 0 is the 'invalid' value. + bool is_valid() const { return _src_region_idx > 0; } + + // Return true if this split holds data for the specified source region. + inline bool is_split(size_t source_region) const; + + // The index of the split region, the size of the partial object on that + // region and the destination of the partial object. + size_t src_region_idx() const { return _src_region_idx; } + size_t partial_obj_size() const { return _partial_obj_size; } + HeapWord* destination() const { return _destination; } + + // The destination count of the partial object referenced by this split + // (either 1 or 2). This must be added to the destination count of the + // remainder of the source region. + unsigned int destination_count() const { return _destination_count; } + + // If a word within the partial object will be written to the first word of a + // destination region, this is the address of the destination region; + // otherwise this is NULL. + HeapWord* dest_region_addr() const { return _dest_region_addr; } + + // If a word within the partial object will be written to the first word of a + // destination region, this is the address of that word within the partial + // object; otherwise this is NULL. + HeapWord* first_src_addr() const { return _first_src_addr; } + + // Record the data necessary to split the region src_region_idx. + void record(size_t src_region_idx, size_t partial_obj_size, + HeapWord* destination); + + void clear(); + + DEBUG_ONLY(void verify_clear();) + +private: + size_t _src_region_idx; + size_t _partial_obj_size; + HeapWord* _destination; + unsigned int _destination_count; + HeapWord* _dest_region_addr; + HeapWord* _first_src_addr; +}; + +inline bool SplitInfo::is_split(size_t region_idx) const +{ + return _src_region_idx == region_idx && is_valid(); +} + class SpaceInfo { public: @@ -58,18 +175,23 @@ // is no start array. ObjectStartArray* start_array() const { return _start_array; } + SplitInfo& split_info() { return _split_info; } + void set_space(MutableSpace* s) { _space = s; } void set_new_top(HeapWord* addr) { _new_top = addr; } void set_min_dense_prefix(HeapWord* addr) { _min_dense_prefix = addr; } void set_dense_prefix(HeapWord* addr) { _dense_prefix = addr; } void set_start_array(ObjectStartArray* s) { _start_array = s; } + void publish_new_top() const { _space->set_top(_new_top); } + private: MutableSpace* _space; HeapWord* _new_top; HeapWord* _min_dense_prefix; HeapWord* _dense_prefix; ObjectStartArray* _start_array; + SplitInfo _split_info; }; class ParallelCompactData @@ -230,9 +352,14 @@ // must be region-aligned; end need not be. void summarize_dense_prefix(HeapWord* beg, HeapWord* end); - bool summarize(HeapWord* target_beg, HeapWord* target_end, + HeapWord* summarize_split_space(size_t src_region, SplitInfo& split_info, + HeapWord* destination, HeapWord* target_end, + HeapWord** target_next); + bool summarize(SplitInfo& split_info, HeapWord* source_beg, HeapWord* source_end, - HeapWord** target_next, HeapWord** source_next = 0); + HeapWord** source_next, + HeapWord* target_beg, HeapWord* target_end, + HeapWord** target_next); void clear(); void clear_range(size_t beg_region, size_t end_region); @@ -838,13 +965,31 @@ // non-empty. static void fill_dense_prefix_end(SpaceId id); + // Clear the summary data source_region field for the specified addresses. + static void clear_source_region(HeapWord* beg_addr, HeapWord* end_addr); + +#ifndef PRODUCT + // Routines to provoke splitting a young gen space (ParallelOldGCSplitALot). + + // Fill the region [start, start + words) with live object(s). Only usable + // for the old and permanent generations. + static void fill_with_live_objects(SpaceId id, HeapWord* const start, + size_t words); + // Include the new objects in the summary data. + static void summarize_new_objects(SpaceId id, HeapWord* start); + + // Add live objects to a survivor space since it's rare that both survivors + // are non-empty. + static void provoke_split_fill_survivor(SpaceId id); + + // Add live objects and/or choose the dense prefix to provoke splitting. + static void provoke_split(bool & maximum_compaction); +#endif + static void summarize_spaces_quick(); static void summarize_space(SpaceId id, bool maximum_compaction); static void summary_phase(ParCompactionManager* cm, bool maximum_compaction); - // The space that is compacted after space_id. - static SpaceId next_compaction_space_id(SpaceId space_id); - // Adjust addresses in roots. Does not adjust addresses in heap. static void adjust_roots(); @@ -999,6 +1144,7 @@ // Return the address of the word to be copied to dest_addr, which must be // aligned to a region boundary. static HeapWord* first_src_addr(HeapWord* const dest_addr, + SpaceId src_space_id, size_t src_region_idx); // Determine the next source region, set closure.source() to the start of the @@ -1012,8 +1158,10 @@ HeapWord* end_addr); // Decrement the destination count for each non-empty source region in the - // range [beg_region, region(region_align_up(end_addr))). + // range [beg_region, region(region_align_up(end_addr))). If the destination + // count for a region goes to 0 and it needs to be filled, enqueue it. static void decrement_destination_counts(ParCompactionManager* cm, + SpaceId src_space_id, size_t beg_region, HeapWord* end_addr); @@ -1081,9 +1229,15 @@ const SpaceId id, const bool maximum_compaction, HeapWord* const addr); + static void summary_phase_msg(SpaceId dst_space_id, + HeapWord* dst_beg, HeapWord* dst_end, + SpaceId src_space_id, + HeapWord* src_beg, HeapWord* src_end); #endif // #ifndef PRODUCT #ifdef ASSERT + // Sanity check the new location of a word in the heap. + static inline void check_new_location(HeapWord* old_addr, HeapWord* new_addr); // Verify that all the regions have been emptied. static void verify_complete(SpaceId space_id); #endif // #ifdef ASSERT @@ -1251,6 +1405,15 @@ } } +#ifdef ASSERT +inline void +PSParallelCompact::check_new_location(HeapWord* old_addr, HeapWord* new_addr) +{ + assert(old_addr >= new_addr || space_id(old_addr) != space_id(new_addr), + "must move left or to a different space"); +} +#endif // ASSERT + class MoveAndUpdateClosure: public ParMarkBitMapClosure { public: inline MoveAndUpdateClosure(ParMarkBitMap* bitmap, ParCompactionManager* cm, @@ -1324,31 +1487,28 @@ oop(addr)->update_contents(compaction_manager()); } -class FillClosure: public ParMarkBitMapClosure { - public: +class FillClosure: public ParMarkBitMapClosure +{ +public: FillClosure(ParCompactionManager* cm, PSParallelCompact::SpaceId space_id) : ParMarkBitMapClosure(PSParallelCompact::mark_bitmap(), cm), - _space_id(space_id), - _start_array(PSParallelCompact::start_array(space_id)) { - assert(_space_id == PSParallelCompact::perm_space_id || - _space_id == PSParallelCompact::old_space_id, + _start_array(PSParallelCompact::start_array(space_id)) + { + assert(space_id == PSParallelCompact::perm_space_id || + space_id == PSParallelCompact::old_space_id, "cannot use FillClosure in the young gen"); - assert(bitmap() != NULL, "need a bitmap"); - assert(_start_array != NULL, "need a start array"); - } - - void fill_region(HeapWord* addr, size_t size) { - MemRegion region(addr, size); - SharedHeap::fill_region_with_object(region); - _start_array->allocate_block(addr); } virtual IterationStatus do_addr(HeapWord* addr, size_t size) { - fill_region(addr, size); + CollectedHeap::fill_with_objects(addr, size); + HeapWord* const end = addr + size; + do { + _start_array->allocate_block(addr); + addr += oop(addr)->size(); + } while (addr < end); return ParMarkBitMap::incomplete; } private: - const PSParallelCompact::SpaceId _space_id; - ObjectStartArray* const _start_array; + ObjectStartArray* const _start_array; };
--- a/src/share/vm/gc_implementation/parallelScavenge/psPermGen.cpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/gc_implementation/parallelScavenge/psPermGen.cpp Sun Dec 28 11:28:04 2008 -0800 @@ -1,5 +1,5 @@ /* - * Copyright 2001-2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2001-2008 Sun Microsystems, Inc. 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
--- a/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.cpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.cpp Sun Dec 28 11:28:04 2008 -0800 @@ -499,26 +499,15 @@ // We lost, someone else "owns" this object guarantee(o->is_forwarded(), "Object must be forwarded if the cas failed."); - // Unallocate the space used. NOTE! We may have directly allocated - // the object. If so, we cannot deallocate it, so we have to test! + // Try to deallocate the space. If it was directly allocated we cannot + // deallocate it, so we have to test. If the deallocation fails, + // overwrite with a filler object. if (new_obj_is_tenured) { if (!_old_lab.unallocate_object(new_obj)) { - // The promotion lab failed to unallocate the object. - // We need to overwrite the object with a filler that - // contains no interior pointers. - MemRegion mr((HeapWord*)new_obj, new_obj_size); - // Clean this up and move to oopFactory (see bug 4718422) - SharedHeap::fill_region_with_object(mr); + CollectedHeap::fill_with_object((HeapWord*) new_obj, new_obj_size); } - } else { - if (!_young_lab.unallocate_object(new_obj)) { - // The promotion lab failed to unallocate the object. - // We need to overwrite the object with a filler that - // contains no interior pointers. - MemRegion mr((HeapWord*)new_obj, new_obj_size); - // Clean this up and move to oopFactory (see bug 4718422) - SharedHeap::fill_region_with_object(mr); - } + } else if (!_young_lab.unallocate_object(new_obj)) { + CollectedHeap::fill_with_object((HeapWord*) new_obj, new_obj_size); } // don't update this before the unallocation!
--- a/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp Sun Dec 28 11:28:04 2008 -0800 @@ -330,6 +330,7 @@ COMPILER2_PRESENT(DerivedPointerTable::clear()); reference_processor()->enable_discovery(); + reference_processor()->setup_policy(false); // We track how much was promoted to the next generation for // the AdaptiveSizePolicy. @@ -394,24 +395,16 @@ // Process reference objects discovered during scavenge { -#ifdef COMPILER2 - ReferencePolicy *soft_ref_policy = new LRUMaxHeapPolicy(); -#else - ReferencePolicy *soft_ref_policy = new LRUCurrentHeapPolicy(); -#endif // COMPILER2 - + reference_processor()->setup_policy(false); // not always_clear PSKeepAliveClosure keep_alive(promotion_manager); PSEvacuateFollowersClosure evac_followers(promotion_manager); - assert(soft_ref_policy != NULL,"No soft reference policy"); if (reference_processor()->processing_is_mt()) { PSRefProcTaskExecutor task_executor; reference_processor()->process_discovered_references( - soft_ref_policy, &_is_alive_closure, &keep_alive, &evac_followers, - &task_executor); + &_is_alive_closure, &keep_alive, &evac_followers, &task_executor); } else { reference_processor()->process_discovered_references( - soft_ref_policy, &_is_alive_closure, &keep_alive, &evac_followers, - NULL); + &_is_alive_closure, &keep_alive, &evac_followers, NULL); } }
--- a/src/share/vm/gc_implementation/shared/mutableNUMASpace.cpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/gc_implementation/shared/mutableNUMASpace.cpp Sun Dec 28 11:28:04 2008 -0800 @@ -76,8 +76,8 @@ MutableSpace *s = ls->space(); if (s->top() < top()) { // For all spaces preceeding the one containing top() if (s->free_in_words() > 0) { - SharedHeap::fill_region_with_object(MemRegion(s->top(), s->end())); size_t area_touched_words = pointer_delta(s->end(), s->top()); + CollectedHeap::fill_with_object(s->top(), area_touched_words); #ifndef ASSERT if (!ZapUnusedHeapArea) { area_touched_words = MIN2((size_t)align_object_size(typeArrayOopDesc::header_size(T_INT)), @@ -414,9 +414,20 @@ if (limit > 0) { limit = round_down(limit, page_size()); if (chunk_size > current_chunk_size(i)) { - chunk_size = MIN2((off_t)chunk_size, (off_t)current_chunk_size(i) + (off_t)limit); + size_t upper_bound = pages_available * page_size(); + if (upper_bound > limit && + current_chunk_size(i) < upper_bound - limit) { + // The resulting upper bound should not exceed the available + // amount of memory (pages_available * page_size()). + upper_bound = current_chunk_size(i) + limit; + } + chunk_size = MIN2(chunk_size, upper_bound); } else { - chunk_size = MAX2((off_t)chunk_size, (off_t)current_chunk_size(i) - (off_t)limit); + size_t lower_bound = page_size(); + if (current_chunk_size(i) > limit) { // lower_bound shouldn't underflow. + lower_bound = current_chunk_size(i) - limit; + } + chunk_size = MAX2(chunk_size, lower_bound); } } assert(chunk_size <= pages_available * page_size(), "Chunk size out of range"); @@ -675,11 +686,11 @@ // a minimal object; assuming that's not the last chunk in which case we don't care. if (i < lgrp_spaces()->length() - 1) { size_t remainder = pointer_delta(s->end(), value); - const size_t minimal_object_size = oopDesc::header_size(); - if (remainder < minimal_object_size && remainder > 0) { - // Add a filler object of a minimal size, it will cross the chunk boundary. - SharedHeap::fill_region_with_object(MemRegion(value, minimal_object_size)); - value += minimal_object_size; + const size_t min_fill_size = CollectedHeap::min_fill_size(); + if (remainder < min_fill_size && remainder > 0) { + // Add a minimum size filler object; it will cross the chunk boundary. + CollectedHeap::fill_with_object(value, min_fill_size); + value += min_fill_size; assert(!s->contains(value), "Should be in the next chunk"); // Restart the loop from the same chunk, since the value has moved // to the next one.
--- a/src/share/vm/gc_interface/collectedHeap.cpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/gc_interface/collectedHeap.cpp Sun Dec 28 11:28:04 2008 -0800 @@ -30,12 +30,21 @@ int CollectedHeap::_fire_out_of_memory_count = 0; #endif +size_t CollectedHeap::_filler_array_max_size = 0; + // Memory state functions. -CollectedHeap::CollectedHeap() : - _reserved(), _barrier_set(NULL), _is_gc_active(false), - _total_collections(0), _total_full_collections(0), - _gc_cause(GCCause::_no_gc), _gc_lastcause(GCCause::_no_gc) { +CollectedHeap::CollectedHeap() +{ + const size_t max_len = size_t(arrayOopDesc::max_array_length(T_INT)); + const size_t elements_per_word = HeapWordSize / sizeof(jint); + _filler_array_max_size = align_object_size(filler_array_hdr_size() + + max_len * elements_per_word); + + _barrier_set = NULL; + _is_gc_active = false; + _total_collections = _total_full_collections = 0; + _gc_cause = _gc_lastcause = GCCause::_no_gc; NOT_PRODUCT(_promotion_failure_alot_count = 0;) NOT_PRODUCT(_promotion_failure_alot_gc_number = 0;) @@ -128,6 +137,94 @@ return obj; } +size_t CollectedHeap::filler_array_hdr_size() { + return size_t(arrayOopDesc::header_size(T_INT)); +} + +size_t CollectedHeap::filler_array_min_size() { + return align_object_size(filler_array_hdr_size()); +} + +size_t CollectedHeap::filler_array_max_size() { + return _filler_array_max_size; +} + +#ifdef ASSERT +void CollectedHeap::fill_args_check(HeapWord* start, size_t words) +{ + assert(words >= min_fill_size(), "too small to fill"); + assert(words % MinObjAlignment == 0, "unaligned size"); + assert(Universe::heap()->is_in_reserved(start), "not in heap"); + assert(Universe::heap()->is_in_reserved(start + words - 1), "not in heap"); +} + +void CollectedHeap::zap_filler_array(HeapWord* start, size_t words) +{ + if (ZapFillerObjects) { + Copy::fill_to_words(start + filler_array_hdr_size(), + words - filler_array_hdr_size(), 0XDEAFBABE); + } +} +#endif // ASSERT + +void +CollectedHeap::fill_with_array(HeapWord* start, size_t words) +{ + assert(words >= filler_array_min_size(), "too small for an array"); + assert(words <= filler_array_max_size(), "too big for a single object"); + + const size_t payload_size = words - filler_array_hdr_size(); + const size_t len = payload_size * HeapWordSize / sizeof(jint); + + // Set the length first for concurrent GC. + ((arrayOop)start)->set_length((int)len); + post_allocation_setup_common(Universe::intArrayKlassObj(), start, words); + DEBUG_ONLY(zap_filler_array(start, words);) +} + +void +CollectedHeap::fill_with_object_impl(HeapWord* start, size_t words) +{ + assert(words <= filler_array_max_size(), "too big for a single object"); + + if (words >= filler_array_min_size()) { + fill_with_array(start, words); + } else if (words > 0) { + assert(words == min_fill_size(), "unaligned size"); + post_allocation_setup_common(SystemDictionary::object_klass(), start, + words); + } +} + +void CollectedHeap::fill_with_object(HeapWord* start, size_t words) +{ + DEBUG_ONLY(fill_args_check(start, words);) + HandleMark hm; // Free handles before leaving. + fill_with_object_impl(start, words); +} + +void CollectedHeap::fill_with_objects(HeapWord* start, size_t words) +{ + DEBUG_ONLY(fill_args_check(start, words);) + HandleMark hm; // Free handles before leaving. + +#ifdef LP64 + // A single array can fill ~8G, so multiple objects are needed only in 64-bit. + // First fill with arrays, ensuring that any remaining space is big enough to + // fill. The remainder is filled with a single object. + const size_t min = min_fill_size(); + const size_t max = filler_array_max_size(); + while (words > max) { + const size_t cur = words - max >= min ? max : max - min; + fill_with_array(start, cur); + start += cur; + words -= cur; + } +#endif + + fill_with_object_impl(start, words); +} + oop CollectedHeap::new_store_barrier(oop new_obj) { // %%% This needs refactoring. (It was imported from the server compiler.) guarantee(can_elide_tlab_store_barriers(), "store barrier elision not supported");
--- a/src/share/vm/gc_interface/collectedHeap.hpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/gc_interface/collectedHeap.hpp Sun Dec 28 11:28:04 2008 -0800 @@ -47,6 +47,9 @@ static int _fire_out_of_memory_count; #endif + // Used for filler objects (static, but initialized in ctor). + static size_t _filler_array_max_size; + protected: MemRegion _reserved; BarrierSet* _barrier_set; @@ -119,6 +122,21 @@ // Clears an allocated object. inline static void init_obj(HeapWord* obj, size_t size); + // Filler object utilities. + static inline size_t filler_array_hdr_size(); + static inline size_t filler_array_min_size(); + static inline size_t filler_array_max_size(); + + DEBUG_ONLY(static void fill_args_check(HeapWord* start, size_t words);) + DEBUG_ONLY(static void zap_filler_array(HeapWord* start, size_t words);) + + // Fill with a single array; caller must ensure filler_array_min_size() <= + // words <= filler_array_max_size(). + static inline void fill_with_array(HeapWord* start, size_t words); + + // 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); + // Verification functions virtual void check_for_bad_heap_word_value(HeapWord* addr, size_t size) PRODUCT_RETURN; @@ -294,6 +312,27 @@ // The boundary between a "large" and "small" array of primitives, in words. virtual size_t large_typearray_limit() = 0; + // Utilities for turning raw memory into filler objects. + // + // min_fill_size() is the smallest region that can be filled. + // fill_with_objects() can fill arbitrary-sized regions of the heap using + // multiple objects. fill_with_object() is for regions known to be smaller + // than the largest array of integers; it uses a single object to fill the + // region and has slightly less overhead. + static size_t min_fill_size() { + return size_t(align_object_size(oopDesc::header_size())); + } + + static void fill_with_objects(HeapWord* start, size_t words); + + static void fill_with_object(HeapWord* start, size_t words); + static void fill_with_object(MemRegion region) { + fill_with_object(region.start(), region.word_size()); + } + static void fill_with_object(HeapWord* start, HeapWord* end) { + fill_with_object(start, pointer_delta(end, start)); + } + // Some heaps may offer a contiguous region for shared non-blocking // allocation, via inlined code (by exporting the address of the top and // end fields defining the extent of the contiguous allocation region.)
--- a/src/share/vm/gc_interface/collectedHeap.inline.hpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/gc_interface/collectedHeap.inline.hpp Sun Dec 28 11:28:04 2008 -0800 @@ -34,7 +34,6 @@ void CollectedHeap::post_allocation_setup_no_klass_install(KlassHandle klass, HeapWord* objPtr, size_t size) { - oop obj = (oop)objPtr; assert(obj != NULL, "NULL object pointer"); @@ -44,9 +43,6 @@ // May be bootstrapping obj->set_mark(markOopDesc::prototype()); } - - // support low memory notifications (no-op if not enabled) - LowMemoryDetector::detect_low_memory_for_collected_pools(); } void CollectedHeap::post_allocation_install_obj_klass(KlassHandle klass, @@ -65,6 +61,9 @@ // Support for jvmti and dtrace inline void post_allocation_notify(KlassHandle klass, oop obj) { + // support low memory notifications (no-op if not enabled) + LowMemoryDetector::detect_low_memory_for_collected_pools(); + // support for JVMTI VMObjectAlloc event (no-op if not enabled) JvmtiExport::vm_object_alloc_event_collector(obj);
--- a/src/share/vm/includeDB_core Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/includeDB_core Sun Dec 28 11:28:04 2008 -0800 @@ -2303,6 +2303,7 @@ javaCalls.cpp interfaceSupport.hpp javaCalls.cpp interpreter.hpp javaCalls.cpp javaCalls.hpp +javaCalls.cpp jniCheck.hpp javaCalls.cpp linkResolver.hpp javaCalls.cpp mutexLocker.hpp javaCalls.cpp nmethod.hpp @@ -3435,6 +3436,7 @@ referenceProcessor.cpp systemDictionary.hpp referenceProcessor.hpp instanceRefKlass.hpp +referenceProcessor.hpp referencePolicy.hpp reflection.cpp arguments.hpp reflection.cpp handles.inline.hpp
--- a/src/share/vm/includeDB_features Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/includeDB_features Sun Dec 28 11:28:04 2008 -0800 @@ -115,6 +115,8 @@ heapInspection.cpp os.hpp heapInspection.cpp resourceArea.hpp +javaCalls.cpp jniCheck.hpp + jniCheck.cpp fieldDescriptor.hpp jniCheck.cpp handles.hpp jniCheck.cpp instanceKlass.hpp
--- a/src/share/vm/includeDB_gc Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/includeDB_gc Sun Dec 28 11:28:04 2008 -0800 @@ -28,21 +28,22 @@ collectedHeap.cpp collectedHeap.inline.hpp collectedHeap.cpp init.hpp collectedHeap.cpp oop.inline.hpp +collectedHeap.cpp systemDictionary.hpp collectedHeap.cpp thread_<os_family>.inline.hpp collectedHeap.hpp allocation.hpp collectedHeap.hpp barrierSet.hpp collectedHeap.hpp gcCause.hpp collectedHeap.hpp handles.hpp -collectedHeap.hpp perfData.hpp +collectedHeap.hpp perfData.hpp collectedHeap.hpp safepoint.hpp collectedHeap.inline.hpp arrayOop.hpp collectedHeap.inline.hpp collectedHeap.hpp collectedHeap.inline.hpp copy.hpp collectedHeap.inline.hpp jvmtiExport.hpp -collectedHeap.inline.hpp lowMemoryDetector.hpp -collectedHeap.inline.hpp sharedRuntime.hpp +collectedHeap.inline.hpp lowMemoryDetector.hpp +collectedHeap.inline.hpp sharedRuntime.hpp collectedHeap.inline.hpp thread.hpp collectedHeap.inline.hpp threadLocalAllocBuffer.inline.hpp collectedHeap.inline.hpp universe.hpp
--- a/src/share/vm/interpreter/bytecodeStream.cpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/interpreter/bytecodeStream.cpp Sun Dec 28 11:28:04 2008 -0800 @@ -1,5 +1,5 @@ /* - * Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2008 Sun Microsystems, Inc. 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
--- a/src/share/vm/interpreter/bytecodes.cpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/interpreter/bytecodes.cpp Sun Dec 28 11:28:04 2008 -0800 @@ -1,5 +1,5 @@ /* - * Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2008 Sun Microsystems, Inc. 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
--- a/src/share/vm/interpreter/bytecodes.hpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/interpreter/bytecodes.hpp Sun Dec 28 11:28:04 2008 -0800 @@ -1,5 +1,5 @@ /* - * Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2008 Sun Microsystems, Inc. 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
--- a/src/share/vm/memory/cardTableModRefBS.cpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/memory/cardTableModRefBS.cpp Sun Dec 28 11:28:04 2008 -0800 @@ -283,7 +283,7 @@ } else { entry = byte_after(old_region.last()); } - assert(index_for(new_region.last()) < (int) _guard_index, + assert(index_for(new_region.last()) < _guard_index, "The guard card will be overwritten"); // This line commented out cleans the newly expanded region and // not the aligned up expanded region.
--- a/src/share/vm/memory/cardTableModRefBS.hpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/memory/cardTableModRefBS.hpp Sun Dec 28 11:28:04 2008 -0800 @@ -428,7 +428,7 @@ } // Mapping from address to card marking array index. - int index_for(void* p) { + size_t index_for(void* p) { assert(_whole_heap.contains(p), "out of bounds access to card marking array"); return byte_for(p) - _byte_map;
--- a/src/share/vm/memory/defNewGeneration.cpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/memory/defNewGeneration.cpp Sun Dec 28 11:28:04 2008 -0800 @@ -540,14 +540,6 @@ assert(gch->no_allocs_since_save_marks(0), "save marks have not been newly set."); - // Weak refs. - // FIXME: Are these storage leaks, or are they resource objects? -#ifdef COMPILER2 - ReferencePolicy *soft_ref_policy = new LRUMaxHeapPolicy(); -#else - ReferencePolicy *soft_ref_policy = new LRUCurrentHeapPolicy(); -#endif // COMPILER2 - // Not very pretty. CollectorPolicy* cp = gch->collector_policy(); @@ -574,8 +566,10 @@ evacuate_followers.do_void(); FastKeepAliveClosure keep_alive(this, &scan_weak_ref); - ref_processor()->process_discovered_references( - soft_ref_policy, &is_alive, &keep_alive, &evacuate_followers, NULL); + ReferenceProcessor* rp = ref_processor(); + rp->setup_policy(clear_all_soft_refs); + rp->process_discovered_references(&is_alive, &keep_alive, &evacuate_followers, + NULL); if (!promotion_failed()) { // Swap the survivor spaces. eden()->clear(SpaceDecorator::Mangle);
--- a/src/share/vm/memory/genCollectedHeap.cpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/memory/genCollectedHeap.cpp Sun Dec 28 11:28:04 2008 -0800 @@ -525,8 +525,9 @@ if (rp->discovery_is_atomic()) { rp->verify_no_references_recorded(); rp->enable_discovery(); + rp->setup_policy(clear_all_soft_refs); } else { - // collect() will enable discovery as appropriate + // collect() below will enable discovery as appropriate } _gens[i]->collect(full, clear_all_soft_refs, size, is_tlab); if (!rp->enqueuing_is_done()) {
--- a/src/share/vm/memory/genMarkSweep.cpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/memory/genMarkSweep.cpp Sun Dec 28 11:28:04 2008 -0800 @@ -31,8 +31,9 @@ // hook up weak ref data so it can be used during Mark-Sweep assert(ref_processor() == NULL, "no stomping"); + assert(rp != NULL, "should be non-NULL"); _ref_processor = rp; - assert(rp != NULL, "should be non-NULL"); + rp->setup_policy(clear_all_softrefs); TraceTime t1("Full GC", PrintGC && !PrintGCDetails, true, gclog_or_tty); @@ -245,20 +246,9 @@ // Process reference objects found during marking { - ReferencePolicy *soft_ref_policy; - if (clear_all_softrefs) { - soft_ref_policy = new AlwaysClearPolicy(); - } else { -#ifdef COMPILER2 - soft_ref_policy = new LRUMaxHeapPolicy(); -#else - soft_ref_policy = new LRUCurrentHeapPolicy(); -#endif // COMPILER2 - } - assert(soft_ref_policy != NULL,"No soft reference policy"); + ref_processor()->setup_policy(clear_all_softrefs); ref_processor()->process_discovered_references( - soft_ref_policy, &is_alive, &keep_alive, - &follow_stack_closure, NULL); + &is_alive, &keep_alive, &follow_stack_closure, NULL); } // Follow system dictionary roots and unload classes
--- a/src/share/vm/memory/permGen.cpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/memory/permGen.cpp Sun Dec 28 11:28:04 2008 -0800 @@ -26,20 +26,24 @@ #include "incls/_permGen.cpp.incl" HeapWord* PermGen::mem_allocate_in_gen(size_t size, Generation* gen) { - MutexLocker ml(Heap_lock); GCCause::Cause next_cause = GCCause::_permanent_generation_full; GCCause::Cause prev_cause = GCCause::_no_gc; + unsigned int gc_count_before, full_gc_count_before; + HeapWord* obj; for (;;) { - HeapWord* obj = gen->allocate(size, false); - if (obj != NULL) { - return obj; - } - if (gen->capacity() < _capacity_expansion_limit || - prev_cause != GCCause::_no_gc) { - obj = gen->expand_and_allocate(size, false); - } - if (obj == NULL && prev_cause != GCCause::_last_ditch_collection) { + { + MutexLocker ml(Heap_lock); + if ((obj = gen->allocate(size, false)) != NULL) { + return obj; + } + if (gen->capacity() < _capacity_expansion_limit || + prev_cause != GCCause::_no_gc) { + obj = gen->expand_and_allocate(size, false); + } + if (obj != NULL || prev_cause == GCCause::_last_ditch_collection) { + return obj; + } if (GC_locker::is_active_and_needs_gc()) { // If this thread is not in a jni critical section, we stall // the requestor until the critical section has cleared and @@ -61,31 +65,27 @@ return NULL; } } + // Read the GC count while holding the Heap_lock + gc_count_before = SharedHeap::heap()->total_collections(); + full_gc_count_before = SharedHeap::heap()->total_full_collections(); + } - // Read the GC count while holding the Heap_lock - unsigned int gc_count_before = SharedHeap::heap()->total_collections(); - unsigned int full_gc_count_before = SharedHeap::heap()->total_full_collections(); - { - MutexUnlocker mu(Heap_lock); // give up heap lock, execute gets it back - VM_GenCollectForPermanentAllocation op(size, gc_count_before, full_gc_count_before, - next_cause); - VMThread::execute(&op); - if (!op.prologue_succeeded() || op.gc_locked()) { - assert(op.result() == NULL, "must be NULL if gc_locked() is true"); - continue; // retry and/or stall as necessary - } - obj = op.result(); - assert(obj == NULL || SharedHeap::heap()->is_in_reserved(obj), - "result not in heap"); - if (obj != NULL) { - return obj; - } - } - prev_cause = next_cause; - next_cause = GCCause::_last_ditch_collection; - } else { + // Give up heap lock above, VMThread::execute below gets it back + VM_GenCollectForPermanentAllocation op(size, gc_count_before, full_gc_count_before, + next_cause); + VMThread::execute(&op); + if (!op.prologue_succeeded() || op.gc_locked()) { + assert(op.result() == NULL, "must be NULL if gc_locked() is true"); + continue; // retry and/or stall as necessary + } + obj = op.result(); + assert(obj == NULL || SharedHeap::heap()->is_in_reserved(obj), + "result not in heap"); + if (obj != NULL) { return obj; } + prev_cause = next_cause; + next_cause = GCCause::_last_ditch_collection; } }
--- a/src/share/vm/memory/referencePolicy.cpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/memory/referencePolicy.cpp Sun Dec 28 11:28:04 2008 -0800 @@ -1,5 +1,5 @@ /* - * Copyright 2000-2003 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2000-2008 Sun Microsystems, Inc. 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,11 @@ # include "incls/_referencePolicy.cpp.incl" LRUCurrentHeapPolicy::LRUCurrentHeapPolicy() { + setup(); +} + +// Capture state (of-the-VM) information needed to evaluate the policy +void LRUCurrentHeapPolicy::setup() { _max_interval = (Universe::get_heap_free_at_last_gc() / M) * SoftRefLRUPolicyMSPerMB; assert(_max_interval >= 0,"Sanity check"); } @@ -47,6 +52,11 @@ /////////////////////// MaxHeap ////////////////////// LRUMaxHeapPolicy::LRUMaxHeapPolicy() { + setup(); +} + +// Capture state (of-the-VM) information needed to evaluate the policy +void LRUMaxHeapPolicy::setup() { size_t max_heap = MaxHeapSize; max_heap -= Universe::get_heap_used_at_last_gc(); max_heap /= M;
--- a/src/share/vm/memory/referencePolicy.hpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/memory/referencePolicy.hpp Sun Dec 28 11:28:04 2008 -0800 @@ -1,5 +1,5 @@ /* - * Copyright 2000 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2000-2008 Sun Microsystems, Inc. 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,11 @@ // should be cleared. -class ReferencePolicy : public ResourceObj { +class ReferencePolicy : public CHeapObj { public: virtual bool should_clear_reference(oop p) { ShouldNotReachHere(); return true; } + // Capture state (of-the-VM) information needed to evaluate the policy + virtual void setup() { /* do nothing */ } }; class NeverClearPolicy : public ReferencePolicy { @@ -48,6 +50,8 @@ public: LRUCurrentHeapPolicy(); + // Capture state (of-the-VM) information needed to evaluate the policy + void setup(); bool should_clear_reference(oop p); }; @@ -58,5 +62,7 @@ public: LRUMaxHeapPolicy(); + // Capture state (of-the-VM) information needed to evaluate the policy + void setup(); bool should_clear_reference(oop p); };
--- a/src/share/vm/memory/referenceProcessor.cpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/memory/referenceProcessor.cpp Sun Dec 28 11:28:04 2008 -0800 @@ -25,6 +25,11 @@ # include "incls/_precompiled.incl" # include "incls/_referenceProcessor.cpp.incl" +ReferencePolicy* ReferenceProcessor::_always_clear_soft_ref_policy = NULL; +ReferencePolicy* ReferenceProcessor::_default_soft_ref_policy = NULL; +oop ReferenceProcessor::_sentinelRef = NULL; +const int subclasses_of_ref = REF_PHANTOM - REF_OTHER; + // List of discovered references. class DiscoveredList { public: @@ -47,7 +52,9 @@ } bool empty() const { return head() == ReferenceProcessor::sentinel_ref(); } size_t length() { return _len; } - void set_length(size_t len) { _len = len; } + void set_length(size_t len) { _len = len; } + void inc_length(size_t inc) { _len += inc; assert(_len > 0, "Error"); } + void dec_length(size_t dec) { _len -= dec; } private: // Set value depending on UseCompressedOops. This could be a template class // but then we have to fix all the instantiations and declarations that use this class. @@ -56,10 +63,6 @@ size_t _len; }; -oop ReferenceProcessor::_sentinelRef = NULL; - -const int subclasses_of_ref = REF_PHANTOM - REF_OTHER; - void referenceProcessor_init() { ReferenceProcessor::init_statics(); } @@ -80,6 +83,12 @@ } assert(_sentinelRef != NULL && _sentinelRef->is_oop(), "Just constructed it!"); + _always_clear_soft_ref_policy = new AlwaysClearPolicy(); + _default_soft_ref_policy = new COMPILER2_PRESENT(LRUMaxHeapPolicy()) + NOT_COMPILER2(LRUCurrentHeapPolicy()); + if (_always_clear_soft_ref_policy == NULL || _default_soft_ref_policy == NULL) { + vm_exit_during_initialization("Could not allocate reference policy object"); + } guarantee(RefDiscoveryPolicy == ReferenceBasedDiscovery || RefDiscoveryPolicy == ReferentBasedDiscovery, "Unrecongnized RefDiscoveryPolicy"); @@ -106,6 +115,7 @@ vm_exit_during_initialization("Could not allocate ReferenceProcessor object"); } rp->set_is_alive_non_header(is_alive_non_header); + rp->setup_policy(false /* default soft ref policy */); return rp; } @@ -192,7 +202,6 @@ } void ReferenceProcessor::process_discovered_references( - ReferencePolicy* policy, BoolObjectClosure* is_alive, OopClosure* keep_alive, VoidClosure* complete_gc, @@ -207,7 +216,7 @@ // Soft references { TraceTime tt("SoftReference", trace_time, false, gclog_or_tty); - process_discovered_reflist(_discoveredSoftRefs, policy, true, + process_discovered_reflist(_discoveredSoftRefs, _current_soft_ref_policy, true, is_alive, keep_alive, complete_gc, task_executor); } @@ -436,13 +445,13 @@ // The "allow_null_referent" argument tells us to allow for the possibility // of a NULL referent in the discovered Reference object. This typically // happens in the case of concurrent collectors that may have done the - // discovery concurrently or interleaved with mutator execution. + // discovery concurrently, or interleaved, with mutator execution. inline void load_ptrs(DEBUG_ONLY(bool allow_null_referent)); // Move to the next discovered reference. inline void next(); - // Remove the current reference from the list and move to the next. + // Remove the current reference from the list inline void remove(); // Make the Reference object active again. @@ -476,7 +485,6 @@ inline size_t removed() const { return _removed; } ) -private: inline void move_to_next(); private: @@ -553,7 +561,7 @@ oopDesc::store_heap_oop((oop*)_prev_next, _next); } NOT_PRODUCT(_removed++); - move_to_next(); + _refs_list.dec_length(1); } inline void DiscoveredListIterator::move_to_next() { @@ -591,12 +599,13 @@ gclog_or_tty->print_cr("Dropping reference (" INTPTR_FORMAT ": %s" ") by policy", iter.obj(), iter.obj()->blueprint()->internal_name()); } + // Remove Reference object from list + iter.remove(); // Make the Reference object active again iter.make_active(); // keep the referent around iter.make_referent_alive(); - // Remove Reference object from list - iter.remove(); + iter.move_to_next(); } else { iter.next(); } @@ -629,12 +638,13 @@ iter.obj(), iter.obj()->blueprint()->internal_name()); } // The referent is reachable after all. + // Remove Reference object from list. + iter.remove(); // Update the referent pointer as necessary: Note that this // should not entail any recursive marking because the // referent must already have been traversed. iter.make_referent_alive(); - // Remove Reference object from list - iter.remove(); + iter.move_to_next(); } else { iter.next(); } @@ -670,6 +680,7 @@ } else { keep_alive->do_oop((oop*)next_addr); } + iter.move_to_next(); } else { iter.next(); } @@ -832,9 +843,9 @@ } java_lang_ref_Reference::set_discovered(move_tail, ref_lists[to_idx].head()); ref_lists[to_idx].set_head(move_head); - ref_lists[to_idx].set_length(ref_lists[to_idx].length() + refs_to_move); + ref_lists[to_idx].inc_length(refs_to_move); ref_lists[from_idx].set_head(new_head); - ref_lists[from_idx].set_length(ref_lists[from_idx].length() - refs_to_move); + ref_lists[from_idx].dec_length(refs_to_move); } else { ++to_idx; } @@ -923,7 +934,6 @@ void ReferenceProcessor::clean_up_discovered_reflist(DiscoveredList& refs_list) { assert(!discovery_is_atomic(), "Else why call this method?"); DiscoveredListIterator iter(refs_list, NULL, NULL); - size_t length = refs_list.length(); while (iter.has_next()) { iter.load_ptrs(DEBUG_ONLY(true /* allow_null_referent */)); oop next = java_lang_ref_Reference::next(iter.obj()); @@ -941,12 +951,11 @@ ) // Remove Reference object from list iter.remove(); - --length; + iter.move_to_next(); } else { iter.next(); } } - refs_list.set_length(length); NOT_PRODUCT( if (PrintGCDetails && TraceReferenceGC) { gclog_or_tty->print( @@ -1024,7 +1033,7 @@ // We have separate lists for enqueueing so no synchronization // is necessary. refs_list.set_head(obj); - refs_list.set_length(refs_list.length() + 1); + refs_list.inc_length(1); if (_discovered_list_needs_barrier) { _bs->write_ref_field((void*)discovered_addr, current_head); guarantee(false, "Needs to be fixed: YSR"); } @@ -1090,15 +1099,28 @@ // reachable. if (is_alive_non_header() != NULL) { oop referent = java_lang_ref_Reference::referent(obj); - // We'd like to assert the following: - // assert(referent != NULL, "Refs with null referents already filtered"); - // However, since this code may be executed concurrently with - // mutators, which can clear() the referent, it is not - // guaranteed that the referent is non-NULL. + // In the case of non-concurrent discovery, the last + // disjunct below should hold. It may not hold in the + // case of concurrent discovery because mutators may + // concurrently clear() a Reference. + assert(UseConcMarkSweepGC || UseG1GC || referent != NULL, + "Refs with null referents already filtered"); if (is_alive_non_header()->do_object_b(referent)) { return false; // referent is reachable } } + if (rt == REF_SOFT) { + // For soft refs we can decide now if these are not + // current candidates for clearing, in which case we + // can mark through them now, rather than delaying that + // to the reference-processing phase. Since all current + // time-stamp policies advance the soft-ref clock only + // at a major collection cycle, this is always currently + // accurate. + if (!_current_soft_ref_policy->should_clear_reference(obj)) { + return false; + } + } HeapWord* const discovered_addr = java_lang_ref_Reference::discovered_addr(obj); const oop discovered = java_lang_ref_Reference::discovered(obj); @@ -1168,7 +1190,7 @@ _bs->write_ref_field((oop*)discovered_addr, current_head); } list->set_head(obj); - list->set_length(list->length() + 1); + list->inc_length(1); } // In the MT discovery case, it is currently possible to see @@ -1209,45 +1231,48 @@ TraceTime tt("Preclean SoftReferences", PrintGCDetails && PrintReferenceGC, false, gclog_or_tty); for (int i = 0; i < _num_q; i++) { + if (yield->should_return()) { + return; + } preclean_discovered_reflist(_discoveredSoftRefs[i], is_alive, keep_alive, complete_gc, yield); } } - if (yield->should_return()) { - return; - } // Weak references { TraceTime tt("Preclean WeakReferences", PrintGCDetails && PrintReferenceGC, false, gclog_or_tty); for (int i = 0; i < _num_q; i++) { + if (yield->should_return()) { + return; + } preclean_discovered_reflist(_discoveredWeakRefs[i], is_alive, keep_alive, complete_gc, yield); } } - if (yield->should_return()) { - return; - } // Final references { TraceTime tt("Preclean FinalReferences", PrintGCDetails && PrintReferenceGC, false, gclog_or_tty); for (int i = 0; i < _num_q; i++) { + if (yield->should_return()) { + return; + } preclean_discovered_reflist(_discoveredFinalRefs[i], is_alive, keep_alive, complete_gc, yield); } } - if (yield->should_return()) { - return; - } // Phantom references { TraceTime tt("Preclean PhantomReferences", PrintGCDetails && PrintReferenceGC, false, gclog_or_tty); for (int i = 0; i < _num_q; i++) { + if (yield->should_return()) { + return; + } preclean_discovered_reflist(_discoveredPhantomRefs[i], is_alive, keep_alive, complete_gc, yield); } @@ -1256,9 +1281,12 @@ // Walk the given discovered ref list, and remove all reference objects // whose referents are still alive, whose referents are NULL or which -// are not active (have a non-NULL next field). NOTE: For this to work -// correctly, refs discovery can not be happening concurrently with this -// step. +// are not active (have a non-NULL next field). NOTE: When we are +// thus precleaning the ref lists (which happens single-threaded today), +// we do not disable refs discovery to honour the correct semantics of +// java.lang.Reference. As a result, we need to be careful below +// that ref removal steps interleave safely with ref discovery steps +// (in this thread). void ReferenceProcessor::preclean_discovered_reflist(DiscoveredList& refs_list, BoolObjectClosure* is_alive, @@ -1266,7 +1294,6 @@ VoidClosure* complete_gc, YieldClosure* yield) { DiscoveredListIterator iter(refs_list, keep_alive, is_alive); - size_t length = refs_list.length(); while (iter.has_next()) { iter.load_ptrs(DEBUG_ONLY(true /* allow_null_referent */)); oop obj = iter.obj(); @@ -1281,7 +1308,6 @@ } // Remove Reference object from list iter.remove(); - --length; // Keep alive its cohort. iter.make_referent_alive(); if (UseCompressedOops) { @@ -1291,12 +1317,11 @@ oop* next_addr = (oop*)java_lang_ref_Reference::next_addr(obj); keep_alive->do_oop(next_addr); } + iter.move_to_next(); } else { iter.next(); } } - refs_list.set_length(length); - // Close the reachable set complete_gc->do_void();
--- a/src/share/vm/memory/referenceProcessor.hpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/memory/referenceProcessor.hpp Sun Dec 28 11:28:04 2008 -0800 @@ -23,7 +23,7 @@ */ // ReferenceProcessor class encapsulates the per-"collector" processing -// of "weak" references for GC. The interface is useful for supporting +// of java.lang.Reference objects for GC. The interface is useful for supporting // a generational abstraction, in particular when there are multiple // generations that are being independently collected -- possibly // concurrently and/or incrementally. Note, however, that the @@ -75,6 +75,14 @@ // all collectors but the CMS collector). BoolObjectClosure* _is_alive_non_header; + // Soft ref clearing policies + // . the default policy + static ReferencePolicy* _default_soft_ref_policy; + // . the "clear all" policy + static ReferencePolicy* _always_clear_soft_ref_policy; + // . the current policy below is either one of the above + ReferencePolicy* _current_soft_ref_policy; + // The discovered ref lists themselves // The MT'ness degree of the queues below @@ -90,6 +98,12 @@ DiscoveredList* discovered_soft_refs() { return _discoveredSoftRefs; } static oop sentinel_ref() { return _sentinelRef; } static oop* adr_sentinel_ref() { return &_sentinelRef; } + ReferencePolicy* setup_policy(bool always_clear) { + _current_soft_ref_policy = always_clear ? + _always_clear_soft_ref_policy : _default_soft_ref_policy; + _current_soft_ref_policy->setup(); // snapshot the policy threshold + return _current_soft_ref_policy; + } public: // Process references with a certain reachability level. @@ -297,8 +311,7 @@ bool discover_reference(oop obj, ReferenceType rt); // Process references found during GC (called by the garbage collector) - void process_discovered_references(ReferencePolicy* policy, - BoolObjectClosure* is_alive, + void process_discovered_references(BoolObjectClosure* is_alive, OopClosure* keep_alive, VoidClosure* complete_gc, AbstractRefProcTaskExecutor* task_executor);
--- a/src/share/vm/memory/sharedHeap.cpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/memory/sharedHeap.cpp Sun Dec 28 11:28:04 2008 -0800 @@ -248,46 +248,6 @@ perm_gen()->ref_processor_init(); } -void SharedHeap::fill_region_with_object(MemRegion mr) { - // Disable the posting of JVMTI VMObjectAlloc events as we - // don't want the filling of tlabs with filler arrays to be - // reported to the profiler. - NoJvmtiVMObjectAllocMark njm; - - // Disable low memory detector because there is no real allocation. - LowMemoryDetectorDisabler lmd_dis; - - // It turns out that post_allocation_setup_array takes a handle, so the - // call below contains an implicit conversion. Best to free that handle - // as soon as possible. - HandleMark hm; - - size_t word_size = mr.word_size(); - size_t aligned_array_header_size = - align_object_size(typeArrayOopDesc::header_size(T_INT)); - - if (word_size >= aligned_array_header_size) { - const size_t array_length = - pointer_delta(mr.end(), mr.start()) - - typeArrayOopDesc::header_size(T_INT); - const size_t array_length_words = - array_length * (HeapWordSize/sizeof(jint)); - post_allocation_setup_array(Universe::intArrayKlassObj(), - mr.start(), - mr.word_size(), - (int)array_length_words); -#ifdef ASSERT - HeapWord* elt_words = (mr.start() + typeArrayOopDesc::header_size(T_INT)); - Copy::fill_to_words(elt_words, array_length, 0xDEAFBABE); -#endif - } else { - assert(word_size == (size_t)oopDesc::header_size(), "Unaligned?"); - post_allocation_setup_obj(SystemDictionary::object_klass(), - mr.start(), - mr.word_size()); - } -} - // Some utilities. void SharedHeap::print_size_transition(outputStream* out, size_t bytes_before,
--- a/src/share/vm/memory/sharedHeap.hpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/memory/sharedHeap.hpp Sun Dec 28 11:28:04 2008 -0800 @@ -108,14 +108,6 @@ void set_perm(PermGen* perm_gen) { _perm_gen = perm_gen; } - // A helper function that fills a region of the heap with - // with a single object. - static void fill_region_with_object(MemRegion mr); - - // Minimum garbage fill object size - static size_t min_fill_size() { return (size_t)align_object_size(oopDesc::header_size()); } - static size_t min_fill_size_in_bytes() { return min_fill_size() * HeapWordSize; } - // This function returns the "GenRemSet" object that allows us to scan // generations; at least the perm gen, possibly more in a fully // generational heap.
--- a/src/share/vm/memory/space.cpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/memory/space.cpp Sun Dec 28 11:28:04 2008 -0800 @@ -409,19 +409,9 @@ HeapWord* q, size_t deadlength) { if (allowed_deadspace_words >= deadlength) { allowed_deadspace_words -= deadlength; - oop(q)->set_mark(markOopDesc::prototype()->set_marked()); - const size_t min_int_array_size = typeArrayOopDesc::header_size(T_INT); - if (deadlength >= min_int_array_size) { - oop(q)->set_klass(Universe::intArrayKlassObj()); - typeArrayOop(q)->set_length((int)((deadlength - min_int_array_size) - * (HeapWordSize/sizeof(jint)))); - } else { - assert((int) deadlength == instanceOopDesc::header_size(), - "size for smallest fake dead object doesn't match"); - oop(q)->set_klass(SystemDictionary::object_klass()); - } - assert((int) deadlength == oop(q)->size(), - "make sure size for fake dead object match"); + CollectedHeap::fill_with_object(q, deadlength); + oop(q)->set_mark(oop(q)->mark()->set_marked()); + assert((int) deadlength == oop(q)->size(), "bad filler object size"); // Recall that we required "q == compaction_top". return true; } else {
--- a/src/share/vm/memory/tenuredGeneration.cpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/memory/tenuredGeneration.cpp Sun Dec 28 11:28:04 2008 -0800 @@ -387,7 +387,7 @@ "should contain whole object"); buf->undo_allocation(obj, word_sz); } else { - SharedHeap::fill_region_with_object(MemRegion(obj, word_sz)); + CollectedHeap::fill_with_object(obj, word_sz); } }
--- a/src/share/vm/memory/tenuredGeneration.hpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/memory/tenuredGeneration.hpp Sun Dec 28 11:28:04 2008 -0800 @@ -1,5 +1,5 @@ /* - * Copyright 2001-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2001-2008 Sun Microsystems, Inc. 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
--- a/src/share/vm/memory/threadLocalAllocBuffer.cpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/memory/threadLocalAllocBuffer.cpp Sun Dec 28 11:28:04 2008 -0800 @@ -100,8 +100,7 @@ void ThreadLocalAllocBuffer::make_parsable(bool retire) { if (end() != NULL) { invariants(); - MemRegion mr(top(), hard_end()); - SharedHeap::fill_region_with_object(mr); + CollectedHeap::fill_with_object(top(), hard_end()); if (retire || ZeroTLAB) { // "Reset" the TLAB set_start(NULL);
--- a/src/share/vm/memory/universe.cpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/memory/universe.cpp Sun Dec 28 11:28:04 2008 -0800 @@ -49,16 +49,16 @@ klassOop Universe::_constantPoolCacheKlassObj = NULL; klassOop Universe::_compiledICHolderKlassObj = NULL; klassOop Universe::_systemObjArrayKlassObj = NULL; -oop Universe::_int_mirror = NULL; -oop Universe::_float_mirror = NULL; -oop Universe::_double_mirror = NULL; -oop Universe::_byte_mirror = NULL; -oop Universe::_bool_mirror = NULL; -oop Universe::_char_mirror = NULL; -oop Universe::_long_mirror = NULL; -oop Universe::_short_mirror = NULL; -oop Universe::_void_mirror = NULL; -oop Universe::_mirrors[T_VOID+1] = { NULL /*, NULL...*/ }; +oop Universe::_int_mirror = NULL; +oop Universe::_float_mirror = NULL; +oop Universe::_double_mirror = NULL; +oop Universe::_byte_mirror = NULL; +oop Universe::_bool_mirror = NULL; +oop Universe::_char_mirror = NULL; +oop Universe::_long_mirror = NULL; +oop Universe::_short_mirror = NULL; +oop Universe::_void_mirror = NULL; +oop Universe::_mirrors[T_VOID+1] = { NULL /*, NULL...*/ }; oop Universe::_main_thread_group = NULL; oop Universe::_system_thread_group = NULL; typeArrayOop Universe::_the_empty_byte_array = NULL; @@ -96,7 +96,7 @@ bool Universe::_fully_initialized = false; size_t Universe::_heap_capacity_at_last_gc; -size_t Universe::_heap_used_at_last_gc; +size_t Universe::_heap_used_at_last_gc = 0; CollectedHeap* Universe::_collectedHeap = NULL; address Universe::_heap_base = NULL; @@ -257,16 +257,16 @@ _typeArrayKlassObjs[T_INT] = _intArrayKlassObj; _typeArrayKlassObjs[T_LONG] = _longArrayKlassObj; - _methodKlassObj = methodKlass::create_klass(CHECK); - _constMethodKlassObj = constMethodKlass::create_klass(CHECK); - _methodDataKlassObj = methodDataKlass::create_klass(CHECK); + _methodKlassObj = methodKlass::create_klass(CHECK); + _constMethodKlassObj = constMethodKlass::create_klass(CHECK); + _methodDataKlassObj = methodDataKlass::create_klass(CHECK); _constantPoolKlassObj = constantPoolKlass::create_klass(CHECK); _constantPoolCacheKlassObj = constantPoolCacheKlass::create_klass(CHECK); _compiledICHolderKlassObj = compiledICHolderKlass::create_klass(CHECK); _systemObjArrayKlassObj = objArrayKlassKlass::cast(objArrayKlassKlassObj())->allocate_system_objArray_klass(CHECK); - _the_empty_byte_array = oopFactory::new_permanent_byteArray(0, CHECK); + _the_empty_byte_array = oopFactory::new_permanent_byteArray(0, CHECK); _the_empty_short_array = oopFactory::new_permanent_shortArray(0, CHECK); _the_empty_int_array = oopFactory::new_permanent_intArray(0, CHECK); _the_empty_system_obj_array = oopFactory::new_system_objArray(0, CHECK); @@ -274,7 +274,6 @@ _the_array_interfaces_array = oopFactory::new_system_objArray(2, CHECK); _vm_exception = oopFactory::new_symbol("vm exception holder", CHECK); } else { - FileMapInfo *mapinfo = FileMapInfo::current_info(); char* buffer = mapinfo->region_base(CompactingPermGenGen::md); void** vtbl_list = (void**)buffer;
--- a/src/share/vm/memory/universe.hpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/memory/universe.hpp Sun Dec 28 11:28:04 2008 -0800 @@ -92,6 +92,7 @@ class Universe: AllStatic { + // Ugh. Universe is much too friendly. friend class MarkSweep; friend class oopDesc; friend class ClassLoader;
--- a/src/share/vm/oops/arrayOop.hpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/oops/arrayOop.hpp Sun Dec 28 11:28:04 2008 -0800 @@ -96,19 +96,20 @@ : typesize_in_bytes/HeapWordSize); } - // This method returns the maximum length that can passed into - // typeArrayOop::object_size(scale, length, header_size) without causing an - // overflow. We substract an extra 2*wordSize to guard against double word - // alignments. It gets the scale from the type2aelembytes array. + // Return the maximum length of an array of BasicType. The length can passed + // to typeArrayOop::object_size(scale, length, header_size) without causing an + // overflow. static int32_t max_array_length(BasicType type) { assert(type >= 0 && type < T_CONFLICT, "wrong type"); assert(type2aelembytes(type) != 0, "wrong type"); - // We use max_jint, since object_size is internally represented by an 'int' - // This gives us an upper bound of max_jint words for the size of the oop. - int32_t max_words = (max_jint - header_size(type) - 2); - int elembytes = type2aelembytes(type); - jlong len = ((jlong)max_words * HeapWordSize) / elembytes; - return (len > max_jint) ? max_jint : (int32_t)len; + const int bytes_per_element = type2aelembytes(type); + if (bytes_per_element < HeapWordSize) { + return max_jint; + } + + const int32_t max_words = align_size_down(max_jint, MinObjAlignment); + const int32_t max_element_words = max_words - header_size(type); + const int32_t words_per_element = bytes_per_element >> LogHeapWordSize; + return max_element_words / words_per_element; } - };
--- a/src/share/vm/oops/constantPoolOop.cpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/oops/constantPoolOop.cpp Sun Dec 28 11:28:04 2008 -0800 @@ -1,5 +1,5 @@ /* - * Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2008 Sun Microsystems, Inc. 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
--- a/src/share/vm/oops/oop.inline.hpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/oops/oop.inline.hpp Sun Dec 28 11:28:04 2008 -0800 @@ -92,7 +92,7 @@ // This is only to be used during GC, for from-space objects, so no // barrier is needed. if (UseCompressedOops) { - _metadata._compressed_klass = encode_heap_oop_not_null(k); + _metadata._compressed_klass = encode_heap_oop(k); // may be null (parnew overflow handling) } else { _metadata._klass = (klassOop)k; }
--- a/src/share/vm/oops/typeArrayKlass.cpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/oops/typeArrayKlass.cpp Sun Dec 28 11:28:04 2008 -0800 @@ -36,13 +36,14 @@ return element_type() == tak->element_type(); } -klassOop typeArrayKlass::create_klass(BasicType type, int scale, TRAPS) { +klassOop typeArrayKlass::create_klass(BasicType type, int scale, + const char* name_str, TRAPS) { typeArrayKlass o; symbolHandle sym(symbolOop(NULL)); // bootstrapping: don't create sym if symbolKlass not created yet - if (Universe::symbolKlassObj() != NULL) { - sym = oopFactory::new_symbol_handle(external_name(type), CHECK_NULL); + if (Universe::symbolKlassObj() != NULL && name_str != NULL) { + sym = oopFactory::new_symbol_handle(name_str, CHECK_NULL); } KlassHandle klassklass (THREAD, Universe::typeArrayKlassKlassObj());
--- a/src/share/vm/oops/typeArrayKlass.hpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/oops/typeArrayKlass.hpp Sun Dec 28 11:28:04 2008 -0800 @@ -39,7 +39,11 @@ // klass allocation DEFINE_ALLOCATE_PERMANENT(typeArrayKlass); - static klassOop create_klass(BasicType type, int scale, TRAPS); + static klassOop create_klass(BasicType type, int scale, const char* name_str, + TRAPS); + static inline klassOop create_klass(BasicType type, int scale, TRAPS) { + return create_klass(type, scale, external_name(type), CHECK_NULL); + } int oop_size(oop obj) const; int klass_oop_size() const { return object_size(); }
--- a/src/share/vm/opto/block.hpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/opto/block.hpp Sun Dec 28 11:28:04 2008 -0800 @@ -1,5 +1,5 @@ /* - * Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2008 Sun Microsystems, Inc. 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
--- a/src/share/vm/opto/callnode.cpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/opto/callnode.cpp Sun Dec 28 11:28:04 2008 -0800 @@ -395,7 +395,13 @@ OptoReg::regname(OptoReg::c_frame_pointer), regalloc->reg2offset(box_reg)); } - format_helper( regalloc, st, obj, "MON-OBJ[", i, &scobjs ); + const char* obj_msg = "MON-OBJ["; + if (EliminateLocks) { + while( !box->is_BoxLock() ) box = box->in(1); + if (box->as_BoxLock()->is_eliminated()) + obj_msg = "MON-OBJ(LOCK ELIMINATED)["; + } + format_helper( regalloc, st, obj, obj_msg, i, &scobjs ); } for (i = 0; i < (uint)scobjs.length(); i++) { @@ -908,8 +914,9 @@ add_req(lock->box_node()); add_req(lock->obj_node()); } else { - add_req(NULL); - add_req(NULL); + Node* top = Compile::current()->top(); + add_req(top); + add_req(top); } jvms()->set_scloff(nextmon+MonitorEdges); jvms()->set_endoff(req()); @@ -1382,7 +1389,7 @@ // // If we are locking an unescaped object, the lock/unlock is unnecessary // - ConnectionGraph *cgr = Compile::current()->congraph(); + ConnectionGraph *cgr = phase->C->congraph(); PointsToNode::EscapeState es = PointsToNode::GlobalEscape; if (cgr != NULL) es = cgr->escape_state(obj_node(), phase); @@ -1450,6 +1457,7 @@ // Mark it eliminated to update any counters lock->set_eliminated(); + lock->set_coarsened(); } } else if (result != NULL && ctrl->is_Region() && iter->_worklist.member(ctrl)) { @@ -1484,7 +1492,7 @@ // // If we are unlocking an unescaped object, the lock/unlock is unnecessary. // - ConnectionGraph *cgr = Compile::current()->congraph(); + ConnectionGraph *cgr = phase->C->congraph(); PointsToNode::EscapeState es = PointsToNode::GlobalEscape; if (cgr != NULL) es = cgr->escape_state(obj_node(), phase);
--- a/src/share/vm/opto/callnode.hpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/opto/callnode.hpp Sun Dec 28 11:28:04 2008 -0800 @@ -780,7 +780,8 @@ //------------------------------AbstractLockNode----------------------------------- class AbstractLockNode: public CallNode { private: - bool _eliminate; // indicates this lock can be safely eliminated + bool _eliminate; // indicates this lock can be safely eliminated + bool _coarsened; // indicates this lock was coarsened #ifndef PRODUCT NamedCounter* _counter; #endif @@ -801,6 +802,7 @@ public: AbstractLockNode(const TypeFunc *tf) : CallNode(tf, NULL, TypeRawPtr::BOTTOM), + _coarsened(false), _eliminate(false) { #ifndef PRODUCT @@ -819,6 +821,9 @@ // mark node as eliminated and update the counter if there is one void set_eliminated(); + bool is_coarsened() { return _coarsened; } + void set_coarsened() { _coarsened = true; } + // locking does not modify its arguments virtual bool may_modify(const TypePtr *addr_t, PhaseTransform *phase){ return false;}
--- a/src/share/vm/opto/compile.cpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/opto/compile.cpp Sun Dec 28 11:28:04 2008 -0800 @@ -1532,11 +1532,6 @@ if (failing()) return; - // get rid of the connection graph since it's information is not - // updated by optimizations - _congraph = NULL; - - // Loop transforms on the ideal graph. Range Check Elimination, // peeling, unrolling, etc. @@ -2197,6 +2192,9 @@ case Op_DecodeN: assert(!n->in(1)->is_EncodeP(), "should be optimized out"); + // DecodeN could be pinned on Sparc where it can't be fold into + // an address expression, see the code for Op_CastPP above. + assert(n->in(0) == NULL || !Matcher::clone_shift_expressions, "no control except on sparc"); break; case Op_EncodeP: {
--- a/src/share/vm/opto/escape.cpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/opto/escape.cpp Sun Dec 28 11:28:04 2008 -0800 @@ -199,7 +199,8 @@ es = ptnode_adr(idx)->escape_state(); // if we have already computed a value, return it - if (es != PointsToNode::UnknownEscape) + if (es != PointsToNode::UnknownEscape && + ptnode_adr(idx)->node_type() == PointsToNode::JavaObject) return es; // PointsTo() calls n->uncast() which can return a new ideal node.
--- a/src/share/vm/opto/locknode.cpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/opto/locknode.cpp Sun Dec 28 11:28:04 2008 -0800 @@ -44,10 +44,15 @@ _inmask.Insert(reg); } +//-----------------------------hash-------------------------------------------- +uint BoxLockNode::hash() const { + return Node::hash() + _slot + (_is_eliminated ? Compile::current()->fixed_slots() : 0); +} + //------------------------------cmp-------------------------------------------- uint BoxLockNode::cmp( const Node &n ) const { const BoxLockNode &bn = (const BoxLockNode &)n; - return bn._slot == _slot; + return bn._slot == _slot && bn._is_eliminated == _is_eliminated; } OptoReg::Name BoxLockNode::stack_slot(Node* box_node) {
--- a/src/share/vm/opto/locknode.hpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/opto/locknode.hpp Sun Dec 28 11:28:04 2008 -0800 @@ -36,7 +36,7 @@ virtual const RegMask &in_RegMask(uint) const; virtual const RegMask &out_RegMask() const; virtual uint size_of() const; - virtual uint hash() const { return Node::hash() + _slot; } + virtual uint hash() const; virtual uint cmp( const Node &n ) const; virtual const class Type *bottom_type() const { return TypeRawPtr::BOTTOM; } virtual uint ideal_reg() const { return Op_RegP; }
--- a/src/share/vm/opto/macro.cpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/opto/macro.cpp Sun Dec 28 11:28:04 2008 -0800 @@ -59,7 +59,7 @@ for (uint i = old_dbg_start; i < oldcall->req(); i++) { Node* old_in = oldcall->in(i); // Clone old SafePointScalarObjectNodes, adjusting their field contents. - if (old_in->is_SafePointScalarObject()) { + if (old_in != NULL && old_in->is_SafePointScalarObject()) { SafePointScalarObjectNode* old_sosn = old_in->as_SafePointScalarObject(); uint old_unique = C->unique(); Node* new_in = old_sosn->clone(jvms_adj, sosn_map); @@ -1509,21 +1509,63 @@ if (!alock->is_eliminated()) { return false; } - // Mark the box lock as eliminated if all correspondent locks are eliminated - // to construct correct debug info. - BoxLockNode* box = alock->box_node()->as_BoxLock(); - if (!box->is_eliminated()) { - bool eliminate = true; - for (DUIterator_Fast imax, i = box->fast_outs(imax); i < imax; i++) { - Node *lck = box->fast_out(i); - if (lck->is_Lock() && !lck->as_AbstractLock()->is_eliminated()) { - eliminate = false; - break; - } - } - if (eliminate) - box->set_eliminated(); - } + if (alock->is_Lock() && !alock->is_coarsened()) { + // Create new "eliminated" BoxLock node and use it + // in monitor debug info for the same object. + BoxLockNode* oldbox = alock->box_node()->as_BoxLock(); + Node* obj = alock->obj_node(); + if (!oldbox->is_eliminated()) { + BoxLockNode* newbox = oldbox->clone()->as_BoxLock(); + newbox->set_eliminated(); + transform_later(newbox); + // Replace old box node with new box for all users + // of the same object. + for (uint i = 0; i < oldbox->outcnt();) { + + bool next_edge = true; + Node* u = oldbox->raw_out(i); + if (u == alock) { + i++; + continue; // It will be removed below + } + if (u->is_Lock() && + u->as_Lock()->obj_node() == obj && + // oldbox could be referenced in debug info also + u->as_Lock()->box_node() == oldbox) { + assert(u->as_Lock()->is_eliminated(), "sanity"); + _igvn.hash_delete(u); + u->set_req(TypeFunc::Parms + 1, newbox); + next_edge = false; +#ifdef ASSERT + } else if (u->is_Unlock() && u->as_Unlock()->obj_node() == obj) { + assert(u->as_Unlock()->is_eliminated(), "sanity"); +#endif + } + // Replace old box in monitor debug info. + if (u->is_SafePoint() && u->as_SafePoint()->jvms()) { + SafePointNode* sfn = u->as_SafePoint(); + JVMState* youngest_jvms = sfn->jvms(); + int max_depth = youngest_jvms->depth(); + for (int depth = 1; depth <= max_depth; depth++) { + JVMState* jvms = youngest_jvms->of_depth(depth); + int num_mon = jvms->nof_monitors(); + // Loop over monitors + for (int idx = 0; idx < num_mon; idx++) { + Node* obj_node = sfn->monitor_obj(jvms, idx); + Node* box_node = sfn->monitor_box(jvms, idx); + if (box_node == oldbox && obj_node == obj) { + int j = jvms->monitor_box_offset(idx); + _igvn.hash_delete(u); + u->set_req(j, newbox); + next_edge = false; + } + } // for (int idx = 0; + } // for (int depth = 1; + } // if (u->is_SafePoint() + if (next_edge) i++; + } // for (uint i = 0; i < oldbox->outcnt();) + } // if (!oldbox->is_eliminated()) + } // if (alock->is_Lock() && !lock->is_coarsened()) #ifndef PRODUCT if (PrintEliminateLocks) { @@ -1562,6 +1604,15 @@ _igvn.subsume_node(ctrlproj, fallthroughproj); _igvn.hash_delete(memproj); _igvn.subsume_node(memproj, memproj_fallthrough); + + // Delete FastLock node also if this Lock node is unique user + // (a loop peeling may clone a Lock node). + Node* flock = alock->as_Lock()->fastlock_node(); + if (flock->outcnt() == 1) { + assert(flock->unique_out() == alock, "sanity"); + _igvn.hash_delete(flock); + _igvn.subsume_node(flock, top()); + } } // Seach for MemBarRelease node and delete it also. @@ -1673,6 +1724,13 @@ if (klass_node == NULL) { Node* k_adr = basic_plus_adr(obj, oopDesc::klass_offset_in_bytes()); klass_node = transform_later( LoadKlassNode::make(_igvn, mem, k_adr, _igvn.type(k_adr)->is_ptr()) ); +#ifdef _LP64 + if (UseCompressedOops && klass_node->is_DecodeN()) { + assert(klass_node->in(1)->Opcode() == Op_LoadNKlass, "sanity"); + klass_node->in(1)->init_req(0, ctrl); + } else +#endif + klass_node->init_req(0, ctrl); } Node *proto_node = make_load(ctrl, mem, klass_node, Klass::prototype_header_offset_in_bytes() + sizeof(oopDesc), TypeX_X, TypeX_X->basic_type()); @@ -1887,7 +1945,7 @@ bool PhaseMacroExpand::expand_macro_nodes() { if (C->macro_count() == 0) return false; - // attempt to eliminate allocations + // First, attempt to eliminate locks bool progress = true; while (progress) { progress = false; @@ -1895,6 +1953,26 @@ Node * n = C->macro_node(i-1); bool success = false; debug_only(int old_macro_count = C->macro_count();); + if (n->is_AbstractLock()) { + success = eliminate_locking_node(n->as_AbstractLock()); + } else if (n->Opcode() == Op_Opaque1 || n->Opcode() == Op_Opaque2) { + _igvn.add_users_to_worklist(n); + _igvn.hash_delete(n); + _igvn.subsume_node(n, n->in(1)); + success = true; + } + assert(success == (C->macro_count() < old_macro_count), "elimination reduces macro count"); + progress = progress || success; + } + } + // Next, attempt to eliminate allocations + progress = true; + while (progress) { + progress = false; + for (int i = C->macro_count(); i > 0; i--) { + Node * n = C->macro_node(i-1); + bool success = false; + debug_only(int old_macro_count = C->macro_count();); switch (n->class_id()) { case Node::Class_Allocate: case Node::Class_AllocateArray: @@ -1902,17 +1980,10 @@ break; case Node::Class_Lock: case Node::Class_Unlock: - success = eliminate_locking_node(n->as_AbstractLock()); + assert(!n->as_AbstractLock()->is_eliminated(), "sanity"); break; default: - if (n->Opcode() == Op_Opaque1 || n->Opcode() == Op_Opaque2) { - _igvn.add_users_to_worklist(n); - _igvn.hash_delete(n); - _igvn.subsume_node(n, n->in(1)); - success = true; - } else { - assert(false, "unknown node type in macro list"); - } + assert(false, "unknown node type in macro list"); } assert(success == (C->macro_count() < old_macro_count), "elimination reduces macro count"); progress = progress || success;
--- a/src/share/vm/opto/output.cpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/opto/output.cpp Sun Dec 28 11:28:04 2008 -0800 @@ -849,10 +849,8 @@ // Loop over monitors and insert into array for(idx = 0; idx < num_mon; idx++) { // Grab the node that defines this monitor - Node* box_node; - Node* obj_node; - box_node = sfn->monitor_box(jvms, idx); - obj_node = sfn->monitor_obj(jvms, idx); + Node* box_node = sfn->monitor_box(jvms, idx); + Node* obj_node = sfn->monitor_obj(jvms, idx); // Create ScopeValue for object ScopeValue *scval = NULL; @@ -890,6 +888,7 @@ OptoReg::Name box_reg = BoxLockNode::stack_slot(box_node); Location basic_lock = Location::new_stk_loc(Location::normal,_regalloc->reg2offset(box_reg)); + while( !box_node->is_BoxLock() ) box_node = box_node->in(1); monarray->append(new MonitorValue(scval, basic_lock, box_node->as_BoxLock()->is_eliminated())); }
--- a/src/share/vm/opto/phase.cpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/opto/phase.cpp Sun Dec 28 11:28:04 2008 -0800 @@ -1,5 +1,5 @@ /* - * Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2008 Sun Microsystems, Inc. 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
--- a/src/share/vm/opto/phase.hpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/opto/phase.hpp Sun Dec 28 11:28:04 2008 -0800 @@ -1,5 +1,5 @@ /* - * Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2008 Sun Microsystems, Inc. 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
--- a/src/share/vm/prims/jni.cpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/prims/jni.cpp Sun Dec 28 11:28:04 2008 -0800 @@ -2173,7 +2173,8 @@ size_t size = os::vm_allocation_granularity(); bad_address = os::reserve_memory(size); if (bad_address != NULL) { - os::protect_memory(bad_address, size, os::MEM_PROT_READ); + os::protect_memory(bad_address, size, os::MEM_PROT_READ, + /*is_committed*/false); } } return bad_address;
--- a/src/share/vm/prims/jniCheck.cpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/prims/jniCheck.cpp Sun Dec 28 11:28:04 2008 -0800 @@ -1,5 +1,5 @@ /* - * Copyright 2001-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2001-2008 Sun Microsystems, Inc. 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 @@ -112,18 +112,6 @@ static const char * fatal_non_string = "JNI string operation received a non-string"; - -// Report a JNI failure caught by -Xcheck:jni. Perform a core dump. -// Note: two variations -- one to be called when in VM state (e.g. when -// within IN_VM macro), one to be called when in NATIVE state. - -// When in VM state: -static void ReportJNIFatalError(JavaThread* thr, const char *msg) { - tty->print_cr("FATAL ERROR in native method: %s", msg); - thr->print_stack(); - os::abort(true); -} - // When in VM state: static void ReportJNIWarning(JavaThread* thr, const char *msg) { tty->print_cr("WARNING in native method: %s", msg);
--- a/src/share/vm/prims/jniCheck.hpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/prims/jniCheck.hpp Sun Dec 28 11:28:04 2008 -0800 @@ -1,5 +1,5 @@ /* - * Copyright 2003-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,6 +22,19 @@ * */ +extern "C" { + // Report a JNI failure caught by -Xcheck:jni. Perform a core dump. + // Note: two variations -- one to be called when in VM state (e.g. when + // within IN_VM macro), one to be called when in NATIVE state. + + // When in VM state: + static void ReportJNIFatalError(JavaThread* thr, const char *msg) { + tty->print_cr("FATAL ERROR in native method: %s", msg); + thr->print_stack(); + os::abort(true); + } +} + // // Checked JNI routines that are useful for outside of checked JNI //
--- a/src/share/vm/prims/jvmtiEnvBase.cpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/prims/jvmtiEnvBase.cpp Sun Dec 28 11:28:04 2008 -0800 @@ -1,5 +1,5 @@ /* - * Copyright 2003-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2008 Sun Microsystems, Inc. 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
--- a/src/share/vm/prims/jvmtiTrace.cpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/prims/jvmtiTrace.cpp Sun Dec 28 11:28:04 2008 -0800 @@ -1,5 +1,5 @@ /* - * Copyright 2003-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2008 Sun Microsystems, Inc. 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
--- a/src/share/vm/runtime/arguments.cpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/runtime/arguments.cpp Sun Dec 28 11:28:04 2008 -0800 @@ -444,9 +444,9 @@ } // Parses a memory size specification string. -static bool atomll(const char *s, jlong* result) { - jlong n = 0; - int args_read = sscanf(s, os::jlong_format_specifier(), &n); +static bool atomull(const char *s, julong* result) { + julong n = 0; + int args_read = sscanf(s, os::julong_format_specifier(), &n); if (args_read != 1) { return false; } @@ -460,15 +460,20 @@ switch (*s) { case 'T': case 't': *result = n * G * K; + // Check for overflow. + if (*result/((julong)G * K) != n) return false; return true; case 'G': case 'g': *result = n * G; + if (*result/G != n) return false; return true; case 'M': case 'm': *result = n * M; + if (*result/M != n) return false; return true; case 'K': case 'k': *result = n * K; + if (*result/K != n) return false; return true; case '\0': *result = n; @@ -478,10 +483,10 @@ } } -Arguments::ArgsRange Arguments::check_memory_size(jlong size, jlong min_size) { +Arguments::ArgsRange Arguments::check_memory_size(julong size, julong min_size) { if (size < min_size) return arg_too_small; // Check that size will fit in a size_t (only relevant on 32-bit) - if ((julong) size > max_uintx) return arg_too_big; + if (size > max_uintx) return arg_too_big; return arg_in_range; } @@ -522,10 +527,10 @@ static bool set_numeric_flag(char* name, char* value, FlagValueOrigin origin) { - jlong v; + julong v; intx intx_v; bool is_neg = false; - // Check the sign first since atomll() parses only unsigned values. + // Check the sign first since atomull() parses only unsigned values. if (*value == '-') { if (!CommandLineFlags::intxAt(name, &intx_v)) { return false; @@ -533,7 +538,7 @@ value++; is_neg = true; } - if (!atomll(value, &v)) { + if (!atomull(value, &v)) { return false; } intx_v = (intx) v; @@ -1517,6 +1522,16 @@ MarkSweepAlwaysCompactCount = 1; // Move objects every gc. } + if (UseParallelOldGC && ParallelOldGCSplitALot) { + // Settings to encourage splitting. + if (!FLAG_IS_CMDLINE(NewRatio)) { + FLAG_SET_CMDLINE(intx, NewRatio, 2); + } + if (!FLAG_IS_CMDLINE(ScavengeBeforeFullGC)) { + FLAG_SET_CMDLINE(bool, ScavengeBeforeFullGC, false); + } + } + status = status && verify_percentage(GCHeapFreeLimit, "GCHeapFreeLimit"); status = status && verify_percentage(GCTimeLimit, "GCTimeLimit"); if (GCTimeLimit == 100) { @@ -1667,9 +1682,9 @@ } Arguments::ArgsRange Arguments::parse_memory_size(const char* s, - jlong* long_arg, - jlong min_size) { - if (!atomll(s, long_arg)) return arg_unreadable; + julong* long_arg, + julong min_size) { + if (!atomull(s, long_arg)) return arg_unreadable; return check_memory_size(*long_arg, min_size); } @@ -1847,7 +1862,7 @@ FLAG_SET_CMDLINE(bool, BackgroundCompilation, false); // -Xmn for compatibility with other JVM vendors } else if (match_option(option, "-Xmn", &tail)) { - jlong long_initial_eden_size = 0; + julong long_initial_eden_size = 0; ArgsRange errcode = parse_memory_size(tail, &long_initial_eden_size, 1); if (errcode != arg_in_range) { jio_fprintf(defaultStream::error_stream(), @@ -1859,7 +1874,7 @@ FLAG_SET_CMDLINE(uintx, NewSize, (size_t) long_initial_eden_size); // -Xms } else if (match_option(option, "-Xms", &tail)) { - jlong long_initial_heap_size = 0; + julong long_initial_heap_size = 0; ArgsRange errcode = parse_memory_size(tail, &long_initial_heap_size, 1); if (errcode != arg_in_range) { jio_fprintf(defaultStream::error_stream(), @@ -1872,7 +1887,7 @@ set_min_heap_size(initial_heap_size()); // -Xmx } else if (match_option(option, "-Xmx", &tail)) { - jlong long_max_heap_size = 0; + julong long_max_heap_size = 0; ArgsRange errcode = parse_memory_size(tail, &long_max_heap_size, 1); if (errcode != arg_in_range) { jio_fprintf(defaultStream::error_stream(), @@ -1905,7 +1920,7 @@ } // -Xss } else if (match_option(option, "-Xss", &tail)) { - jlong long_ThreadStackSize = 0; + julong long_ThreadStackSize = 0; ArgsRange errcode = parse_memory_size(tail, &long_ThreadStackSize, 1000); if (errcode != arg_in_range) { jio_fprintf(defaultStream::error_stream(), @@ -1921,9 +1936,9 @@ // HotSpot does not have separate native and Java stacks, ignore silently for compatibility // -Xmaxjitcodesize } else if (match_option(option, "-Xmaxjitcodesize", &tail)) { - jlong long_ReservedCodeCacheSize = 0; + julong long_ReservedCodeCacheSize = 0; ArgsRange errcode = parse_memory_size(tail, &long_ReservedCodeCacheSize, - InitialCodeCacheSize); + (size_t)InitialCodeCacheSize); if (errcode != arg_in_range) { jio_fprintf(defaultStream::error_stream(), "Invalid maximum code cache size: %s\n", @@ -2228,7 +2243,7 @@ } else if (match_option(option, "-XX:TLEFragmentationRatio=", &tail)) { // No longer used. } else if (match_option(option, "-XX:TLESize=", &tail)) { - jlong long_tlab_size = 0; + julong long_tlab_size = 0; ArgsRange errcode = parse_memory_size(tail, &long_tlab_size, 1); if (errcode != arg_in_range) { jio_fprintf(defaultStream::error_stream(), @@ -2283,7 +2298,7 @@ "-XX:ParCMSPromoteBlocksToClaim in the future\n"); } else if (match_option(option, "-XX:ParallelGCOldGenAllocBufferSize=", &tail)) { - jlong old_plab_size = 0; + julong old_plab_size = 0; ArgsRange errcode = parse_memory_size(tail, &old_plab_size, 1); if (errcode != arg_in_range) { jio_fprintf(defaultStream::error_stream(), @@ -2291,13 +2306,13 @@ describe_range_error(errcode); return JNI_EINVAL; } - FLAG_SET_CMDLINE(uintx, OldPLABSize, (julong)old_plab_size); + FLAG_SET_CMDLINE(uintx, OldPLABSize, old_plab_size); jio_fprintf(defaultStream::error_stream(), "Please use -XX:OldPLABSize in place of " "-XX:ParallelGCOldGenAllocBufferSize in the future\n"); } else if (match_option(option, "-XX:ParallelGCToSpaceAllocBufferSize=", &tail)) { - jlong young_plab_size = 0; + julong young_plab_size = 0; ArgsRange errcode = parse_memory_size(tail, &young_plab_size, 1); if (errcode != arg_in_range) { jio_fprintf(defaultStream::error_stream(), @@ -2305,7 +2320,7 @@ describe_range_error(errcode); return JNI_EINVAL; } - FLAG_SET_CMDLINE(uintx, YoungPLABSize, (julong)young_plab_size); + FLAG_SET_CMDLINE(uintx, YoungPLABSize, young_plab_size); jio_fprintf(defaultStream::error_stream(), "Please use -XX:YoungPLABSize in place of " "-XX:ParallelGCToSpaceAllocBufferSize in the future\n"); @@ -2322,7 +2337,12 @@ return JNI_ERR; } } - + // Change the default value for flags which have different default values + // when working with older JDKs. + if (JDK_Version::current().compare_major(6) <= 0 && + FLAG_IS_DEFAULT(UseVMInterruptibleIO)) { + FLAG_SET_DEFAULT(UseVMInterruptibleIO, true); + } return JNI_OK; }
--- a/src/share/vm/runtime/arguments.hpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/runtime/arguments.hpp Sun Dec 28 11:28:04 2008 -0800 @@ -339,9 +339,9 @@ } static bool verify_percentage(uintx value, const char* name); static void describe_range_error(ArgsRange errcode); - static ArgsRange check_memory_size(jlong size, jlong min_size); - static ArgsRange parse_memory_size(const char* s, jlong* long_arg, - jlong min_size); + static ArgsRange check_memory_size(julong size, julong min_size); + static ArgsRange parse_memory_size(const char* s, julong* long_arg, + julong min_size); // methods to build strings from individual args static void build_jvm_args(const char* arg);
--- a/src/share/vm/runtime/biasedLocking.cpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/runtime/biasedLocking.cpp Sun Dec 28 11:28:04 2008 -0800 @@ -582,13 +582,19 @@ if (heuristics == HR_NOT_BIASED) { return NOT_BIASED; } else if (heuristics == HR_SINGLE_REVOKE) { - if (mark->biased_locker() == THREAD) { + Klass *k = Klass::cast(obj->klass()); + markOop prototype_header = k->prototype_header(); + if (mark->biased_locker() == THREAD && + prototype_header->bias_epoch() == mark->bias_epoch()) { // A thread is trying to revoke the bias of an object biased // toward it, again likely due to an identity hash code // computation. We can again avoid a safepoint in this case // since we are only going to walk our own stack. There are no // races with revocations occurring in other threads because we // reach no safepoints in the revocation path. + // Also check the epoch because even if threads match, another thread + // can come in with a CAS to steal the bias of an object that has a + // stale epoch. ResourceMark rm; if (TraceBiasedLocking) { tty->print_cr("Revoking bias by walking my own stack:");
--- a/src/share/vm/runtime/globals.hpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/runtime/globals.hpp Sun Dec 28 11:28:04 2008 -0800 @@ -342,6 +342,9 @@ product(bool, UseNUMA, false, \ "Use NUMA if available") \ \ + product(bool, ForceNUMA, false, \ + "Force NUMA optimizations on single-node/UMA systems") \ + \ product(intx, NUMAChunkResizeWeight, 20, \ "Percentage (0-100) used to weight the current sample when " \ "computing exponentially decaying average for " \ @@ -622,6 +625,9 @@ develop(bool, CheckZapUnusedHeapArea, false, \ "Check zapping of unused heap space") \ \ + develop(bool, ZapFillerObjects, trueInDebug, \ + "Zap filler objects with 0xDEAFBABE") \ + \ develop(bool, PrintVMMessages, true, \ "Print vm messages on console") \ \ @@ -815,7 +821,7 @@ product(bool, ClassUnloading, true, \ "Do unloading of classes") \ \ - diagnostic(bool, LinkWellKnownClasses, true, \ + diagnostic(bool, LinkWellKnownClasses, false, \ "Resolve a well known class as soon as its name is seen") \ \ develop(bool, DisableStartThread, false, \ @@ -1197,11 +1203,12 @@ product(uintx, ParallelCMSThreads, 0, \ "Max number of threads CMS will use for concurrent work") \ \ - develop(bool, ParallelOldMTUnsafeMarkBitMap, false, \ - "Use the Parallel Old MT unsafe in marking the bitmap") \ - \ - develop(bool, ParallelOldMTUnsafeUpdateLiveData, false, \ - "Use the Parallel Old MT unsafe in update of live size") \ + develop(bool, ParallelOldGCSplitALot, false, \ + "Provoke splitting (copying data from a young gen space to" \ + "multiple destination spaces)") \ + \ + develop(uintx, ParallelOldGCSplitInterval, 3, \ + "How often to provoke splitting a young gen space") \ \ develop(bool, TraceRegionTasksQueuing, false, \ "Trace the queuing of the region tasks") \ @@ -1474,7 +1481,7 @@ "CMSPrecleanNumerator:CMSPrecleanDenominator yields convergence" \ " ratio") \ \ - product(bool, CMSPrecleanRefLists1, false, \ + product(bool, CMSPrecleanRefLists1, true, \ "Preclean ref lists during (initial) preclean phase") \ \ product(bool, CMSPrecleanRefLists2, false, \ @@ -3262,9 +3269,10 @@ diagnostic(bool, PrintDTraceDOF, false, \ "Print the DTrace DOF passed to the system for JSDT probes") \ \ - product(bool, UseVMInterruptibleIO, true, \ + product(bool, UseVMInterruptibleIO, false, \ "(Unstable, Solaris-specific) Thread interrupt before or with " \ - "EINTR for I/O operations results in OS_INTRPT") + "EINTR for I/O operations results in OS_INTRPT. The default value"\ + " of this flag is true for JDK 6 and earliers") /*
--- a/src/share/vm/runtime/javaCalls.cpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/runtime/javaCalls.cpp Sun Dec 28 11:28:04 2008 -0800 @@ -1,5 +1,5 @@ /* - * Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2008 Sun Microsystems, Inc. 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 @@ -309,8 +309,12 @@ CHECK_UNHANDLED_OOPS_ONLY(thread->clear_unhandled_oops();) - // Make sure that the arguments have the right type - debug_only(args->verify(method, result->get_type(), thread)); + // Verify the arguments + + if (CheckJNICalls) { + args->verify(method, result->get_type(), thread); + } + else debug_only(args->verify(method, result->get_type(), thread)); // Ignore call if method is empty if (method->is_empty_method()) { @@ -431,24 +435,26 @@ return TaggedStackInterpreter ? _parameters : _value; } -//-------------------------------------------------------------------------------------- -// Non-Product code -#ifndef PRODUCT class SignatureChekker : public SignatureIterator { private: bool *_is_oop; int _pos; BasicType _return_type; + intptr_t* _value; + Thread* _thread; public: bool _is_return; - SignatureChekker(symbolHandle signature, BasicType return_type, bool is_static, bool* is_oop) : SignatureIterator(signature) { + SignatureChekker(symbolHandle signature, BasicType return_type, bool is_static, bool* is_oop, intptr_t* value, Thread* thread) : SignatureIterator(signature) { _is_oop = is_oop; _is_return = false; _return_type = return_type; _pos = 0; + _value = value; + _thread = thread; + if (!is_static) { check_value(true); // Receiver must be an oop } @@ -489,6 +495,24 @@ check_return_type(t); return; } + + // verify handle and the oop pointed to by handle + int p = _pos; + bool bad = false; + // If argument is oop + if (_is_oop[p]) { + intptr_t v = _value[p]; + if (v != 0 ) { + size_t t = (size_t)v; + bad = (t < (size_t)os::vm_page_size() ) || !Handle::raw_resolve((oop *)v)->is_oop_or_null(true); + if (CheckJNICalls && bad) { + ReportJNIFatalError((JavaThread*)_thread, "Bad JNI oop argument"); + } + } + // for the regular debug case. + assert(!bad, "Bad JNI oop argument"); + } + check_value(true); } @@ -505,6 +529,7 @@ void do_array(int begin, int end) { check_obj(T_OBJECT); } }; + void JavaCallArguments::verify(methodHandle method, BasicType return_type, Thread *thread) { guarantee(method->size_of_parameters() == size_of_parameters(), "wrong no. of arguments pushed"); @@ -515,10 +540,9 @@ // Check that oop information is correct symbolHandle signature (thread, method->signature()); - SignatureChekker sc(signature, return_type, method->is_static(),_is_oop); + SignatureChekker sc(signature, return_type, method->is_static(),_is_oop, _value, thread); sc.iterate_parameters(); sc.check_doing_return(true); sc.iterate_returntype(); } -#endif // PRODUCT
--- a/src/share/vm/runtime/javaCalls.hpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/runtime/javaCalls.hpp Sun Dec 28 11:28:04 2008 -0800 @@ -1,5 +1,5 @@ /* - * Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2008 Sun Microsystems, Inc. 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 @@ -150,7 +150,7 @@ int size_of_parameters() const { return _size; } // Verify that pushed arguments fits a given method - void verify(methodHandle method, BasicType return_type, Thread *thread) PRODUCT_RETURN; + void verify(methodHandle method, BasicType return_type, Thread *thread); }; // All calls to Java have to go via JavaCalls. Sets up the stack frame
--- a/src/share/vm/runtime/os.cpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/runtime/os.cpp Sun Dec 28 11:28:04 2008 -0800 @@ -936,8 +936,9 @@ // the mutator thread if such case is encountered. See bug 6546278 for details. Thread::muxAcquire(&SerializePageLock, "serialize_thread_states"); os::protect_memory((char *)os::get_memory_serialize_page(), - os::vm_page_size(), MEM_PROT_READ, /*is_committed*/true ); - os::unguard_memory((char *)os::get_memory_serialize_page(), os::vm_page_size()); + os::vm_page_size(), MEM_PROT_READ); + os::protect_memory((char *)os::get_memory_serialize_page(), + os::vm_page_size(), MEM_PROT_RW); Thread::muxRelease(&SerializePageLock); }
--- a/src/share/vm/runtime/os.hpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/runtime/os.hpp Sun Dec 28 11:28:04 2008 -0800 @@ -208,7 +208,7 @@ enum ProtType { MEM_PROT_NONE, MEM_PROT_READ, MEM_PROT_RW, MEM_PROT_RWX }; static bool protect_memory(char* addr, size_t bytes, ProtType prot, - bool is_committed = false); + bool is_committed = true); static bool guard_memory(char* addr, size_t bytes); static bool unguard_memory(char* addr, size_t bytes);
--- a/src/share/vm/runtime/perfMemory.cpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/runtime/perfMemory.cpp Sun Dec 28 11:28:04 2008 -0800 @@ -1,5 +1,5 @@ /* - * Copyright 2001-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2001-2008 Sun Microsystems, Inc. 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
--- a/src/share/vm/runtime/perfMemory.hpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/runtime/perfMemory.hpp Sun Dec 28 11:28:04 2008 -0800 @@ -1,5 +1,5 @@ /* - * Copyright 2001-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2001-2008 Sun Microsystems, Inc. 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
--- a/src/share/vm/runtime/sharedRuntime.cpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/runtime/sharedRuntime.cpp Sun Dec 28 11:28:04 2008 -0800 @@ -556,7 +556,10 @@ // the caller was at a call site, it's safe to destroy all // caller-saved registers, as these entry points do. VtableStub* vt_stub = VtableStubs::stub_containing(pc); - guarantee(vt_stub != NULL, "unable to find SEGVing vtable stub"); + + // If vt_stub is NULL, then return NULL to signal handler to report the SEGV error. + if (vt_stub == NULL) return NULL; + if (vt_stub->is_abstract_method_error(pc)) { assert(!vt_stub->is_vtable_stub(), "should never see AbstractMethodErrors from vtable-type VtableStubs"); return StubRoutines::throw_AbstractMethodError_entry(); @@ -565,7 +568,9 @@ } } else { CodeBlob* cb = CodeCache::find_blob(pc); - guarantee(cb != NULL, "exception happened outside interpreter, nmethods and vtable stubs (1)"); + + // If code blob is NULL, then return NULL to signal handler to report the SEGV error. + if (cb == NULL) return NULL; // Exception happened in CodeCache. Must be either: // 1. Inline-cache check in C2I handler blob, @@ -574,7 +579,7 @@ if (!cb->is_nmethod()) { guarantee(cb->is_adapter_blob(), - "exception happened outside interpreter, nmethods and vtable stubs (2)"); + "exception happened outside interpreter, nmethods and vtable stubs (1)"); // There is no handler here, so we will simply unwind. return StubRoutines::throw_NullPointerException_at_call_entry(); }
--- a/src/share/vm/runtime/synchronizer.cpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/runtime/synchronizer.cpp Sun Dec 28 11:28:04 2008 -0800 @@ -3363,13 +3363,13 @@ // If the wakee is cold then transiently setting it's affinity // to the current CPU is a good idea. // See http://j2se.east/~dice/PERSIST/050624-PullAffinity.txt + DTRACE_MONITOR_PROBE(contended__exit, this, object(), Self); Trigger->unpark() ; // Maintain stats and report events to JVMTI if (ObjectSynchronizer::_sync_Parks != NULL) { ObjectSynchronizer::_sync_Parks->inc() ; } - DTRACE_MONITOR_PROBE(contended__exit, this, object(), Self); }
--- a/src/share/vm/runtime/thread.hpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/runtime/thread.hpp Sun Dec 28 11:28:04 2008 -0800 @@ -1,5 +1,5 @@ /* - * Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2008 Sun Microsystems, Inc. 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
--- a/src/share/vm/services/management.cpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/services/management.cpp Sun Dec 28 11:28:04 2008 -0800 @@ -694,10 +694,10 @@ -1); } - if (threshold > max_intx) { - THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(), - "Invalid threshold value > max value of size_t", - -1); + if ((size_t)threshold > max_uintx) { + stringStream st; + st.print("Invalid valid threshold value. Threshold value (" UINT64_FORMAT ") > max value of size_t (" SIZE_FORMAT ")", (size_t)threshold, max_uintx); + THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(), st.as_string(), -1); } MemoryPool* pool = get_memory_pool_from_jobject(obj, CHECK_(0L));
--- a/src/share/vm/services/threadService.hpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/services/threadService.hpp Sun Dec 28 11:28:04 2008 -0800 @@ -1,5 +1,5 @@ /* - * Copyright 2003-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2008 Sun Microsystems, Inc. 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
--- a/src/share/vm/utilities/array.hpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/utilities/array.hpp Sun Dec 28 11:28:04 2008 -0800 @@ -1,5 +1,5 @@ /* - * Copyright 2000-2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2000-2008 Sun Microsystems, Inc. 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
--- a/src/share/vm/utilities/constantTag.hpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/utilities/constantTag.hpp Sun Dec 28 11:28:04 2008 -0800 @@ -1,5 +1,5 @@ /* - * Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2008 Sun Microsystems, Inc. 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
--- a/src/share/vm/utilities/growableArray.hpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/utilities/growableArray.hpp Sun Dec 28 11:28:04 2008 -0800 @@ -1,5 +1,5 @@ /* - * Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2008 Sun Microsystems, Inc. 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
--- a/src/share/vm/utilities/hashtable.cpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/utilities/hashtable.cpp Sun Dec 28 11:28:04 2008 -0800 @@ -1,5 +1,5 @@ /* - * Copyright 2003-2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2008 Sun Microsystems, Inc. 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
--- a/src/share/vm/utilities/macros.hpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/utilities/macros.hpp Sun Dec 28 11:28:04 2008 -0800 @@ -65,8 +65,10 @@ // COMPILER2 variant #ifdef COMPILER2 #define COMPILER2_PRESENT(code) code +#define NOT_COMPILER2(code) #else // COMPILER2 #define COMPILER2_PRESENT(code) +#define NOT_COMPILER2(code) code #endif // COMPILER2
--- a/src/share/vm/utilities/taskqueue.cpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/utilities/taskqueue.cpp Sun Dec 28 11:28:04 2008 -0800 @@ -1,5 +1,5 @@ /* - * Copyright 2001-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2001-2008 Sun Microsystems, Inc. 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
--- a/src/share/vm/utilities/vmError.cpp Wed Nov 26 05:05:13 2008 -0800 +++ b/src/share/vm/utilities/vmError.cpp Sun Dec 28 11:28:04 2008 -0800 @@ -337,6 +337,8 @@ // VM version st->print_cr("#"); + JDK_Version::current().to_string(buf, sizeof(buf)); + st->print_cr("# JRE version: %s", buf); st->print_cr("# Java VM: %s (%s %s %s %s)", Abstract_VM_Version::vm_name(), Abstract_VM_Version::vm_release(),
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/6756768/Test6756768.java Sun Dec 28 11:28:04 2008 -0800 @@ -0,0 +1,55 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/** + * @test + * @bug 6756768 + * @summary C1 generates invalid code + * + * @run main/othervm -Xcomp Test6756768 + */ + +class Test6756768a +{ + static boolean var_1 = true; +} + +final class Test6756768b +{ + static boolean var_24 = false; + static int var_25 = 0; + + static boolean var_temp1 = Test6756768a.var_1 = false; +} + +public final class Test6756768 extends Test6756768a +{ + final static int var = var_1 ^ (Test6756768b.var_24 ? var_1 : var_1) ? Test6756768b.var_25 : 1; + + static public void main(String[] args) { + if (var != 0) { + throw new InternalError("var = " + var); + } + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/6756768/Test6756768_2.java Sun Dec 28 11:28:04 2008 -0800 @@ -0,0 +1,55 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/** + * @test + * @bug 6756768 + * @summary C1 generates invalid code + * + * @run main/othervm -Xcomp Test6756768_2 + */ + +class Test6756768_2a { + static int var = ++Test6756768_2.var; +} + +public class Test6756768_2 { + static int var = 1; + + static Object d2 = null; + + static void test_static_field() { + int v = var; + int v2 = Test6756768_2a.var; + int v3 = var; + var = v3; + } + + public static void main(String[] args) { + var = 1; + test_static_field(); + if (var != 2) { + throw new InternalError(); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/6757316/Test6757316.java Sun Dec 28 11:28:04 2008 -0800 @@ -0,0 +1,43 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/** + * @test + * @bug 6757316 + * @summary load_constant() produces a wrong long constant, with high a low words swapped + * @run main/othervm -Xcomp Test6757316 + */ + +public class Test6757316 { + public static void main(String[] args) { + long[] arr = { + 0x11111111aaaaaaaaL, + 0xaaaaaaaa11111111L, + 0x11111111aaaaaaaaL, + 0xaaaaaaaa11111111L + }; + if (arr[0] == arr[1]) { + throw new InternalError(); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/6758234/Test6758234.java Sun Dec 28 11:28:04 2008 -0800 @@ -0,0 +1,40 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/** + * @test + * @bug 6758234 + * @summary if (k cond (a ? : b: c)) returns reversed answer if k is constant and b and c are longs + * @run main/othervm -Xcomp -XX:CompileOnly=Test6758234.main Test6758234 + */ + +public class Test6758234 { + static int x = 0; + static int y = 1; + + public static void main(String[] args) { + if (1 != ((x < y) ? 1L : 0)) { + throw new InternalError(); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/6775880/Test.java Sun Dec 28 11:28:04 2008 -0800 @@ -0,0 +1,67 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + */ + +/* + * @test + * @bug 6775880 + * @summary EA +DeoptimizeALot: assert(mon_info->owner()->is_locked(),"object must be locked now") + * @compile -source 1.4 -target 1.4 Test.java + * @run main/othervm -server -Xbatch -XX:+DoEscapeAnalysis -XX:+DeoptimizeALot -XX:CompileCommand=exclude,java.lang.AbstractStringBuilder::append Test + */ + +public class Test { + + int cnt; + int b[]; + String s; + + String test() { + String res=""; + for (int i=0; i < cnt; i++) { + if (i != 0) { + res = res +"."; + } + res = res + b[i]; + } + return res; + } + + public static void main(String[] args) { + Test t = new Test(); + t.cnt = 3; + t.b = new int[3]; + t.b[0] = 0; + t.b[1] = 1; + t.b[2] = 2; + int j=0; + t.s = ""; + for (int i=0; i<10001; i++) { + t.s = "c"; + t.s = t.test(); + } + System.out.println("After s=" + t.s); + } +} + +