# HG changeset patch # User kamg # Date 1206022650 18000 # Node ID 735f15bdea80f09a1a760e66abce23e32ed465aa # Parent 6258c2e3adfdc1790e57f17ff75abbe24d847972# Parent 4da9c1bbc810b3bbdd65effa1d9fce852a38f8a3 Merge diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/agent/src/os/linux/ps_core.c --- a/hotspot/agent/src/os/linux/ps_core.c Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/agent/src/os/linux/ps_core.c Thu Mar 20 09:17:30 2008 -0500 @@ -518,10 +518,10 @@ } static ps_prochandle_ops core_ops = { - release: core_release, - p_pread: core_read_data, - p_pwrite: core_write_data, - get_lwp_regs: core_get_lwp_regs + .release= core_release, + .p_pread= core_read_data, + .p_pwrite= core_write_data, + .get_lwp_regs= core_get_lwp_regs }; // read regs and create thread from NT_PRSTATUS entries from core file diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/agent/src/os/linux/ps_proc.c --- a/hotspot/agent/src/os/linux/ps_proc.c Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/agent/src/os/linux/ps_proc.c Thu Mar 20 09:17:30 2008 -0500 @@ -291,10 +291,10 @@ } static ps_prochandle_ops process_ops = { - release: process_cleanup, - p_pread: process_read_data, - p_pwrite: process_write_data, - get_lwp_regs: process_get_lwp_regs + .release= process_cleanup, + .p_pread= process_read_data, + .p_pwrite= process_write_data, + .get_lwp_regs= process_get_lwp_regs }; // attach to the process. One and only one exposed stuff diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/build/linux/Makefile --- a/hotspot/build/linux/Makefile Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/build/linux/Makefile Thu Mar 20 09:17:30 2008 -0500 @@ -80,6 +80,11 @@ MFLAGS += " LP64=1 " endif +# pass USE_SUNCC further, through MFLAGS +ifdef USE_SUNCC + MFLAGS += " USE_SUNCC=1 " +endif + # The following renders pathnames in generated Makefiles valid on # machines other than the machine containing the build tree. # diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/build/linux/makefiles/amd64.make --- a/hotspot/build/linux/makefiles/amd64.make Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/build/linux/makefiles/amd64.make Thu Mar 20 09:17:30 2008 -0500 @@ -35,6 +35,8 @@ CFLAGS += -D_LP64=1 # The serviceability agent relies on frame pointer (%rbp) to walk thread stack -CFLAGS += -fno-omit-frame-pointer +ifndef USE_SUNCC + CFLAGS += -fno-omit-frame-pointer +endif OPT_CFLAGS/compactingPermGenGen.o = -O1 diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/build/linux/makefiles/buildtree.make --- a/hotspot/build/linux/makefiles/buildtree.make Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/build/linux/makefiles/buildtree.make Thu Mar 20 09:17:30 2008 -0500 @@ -63,7 +63,11 @@ # For now, until the compiler is less wobbly: TESTFLAGS = -Xbatch -showversion -PLATFORM_FILE = $(GAMMADIR)/build/$(OS_FAMILY)/platform_$(BUILDARCH) +ifdef USE_SUNCC +PLATFORM_FILE = $(GAMMADIR)/build/$(OS_FAMILY)/platform_$(BUILDARCH).suncc +else +PLATFORM_FILE = $(GAMMADIR)/build/$(OS_FAMILY)/platform_$(BUILDARCH) +endif ifdef FORCE_TIERED ifeq ($(VARIANT),tiered) diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/build/linux/makefiles/sparcWorks.make --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/build/linux/makefiles/sparcWorks.make Thu Mar 20 09:17:30 2008 -0500 @@ -0,0 +1,93 @@ +# +# Copyright 1999-2007 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. +# +# + +#------------------------------------------------------------------------ +# CC, CPP & AS + +CPP = CC +CC = cc +AS = $(CC) -c + +ARCHFLAG = $(ARCHFLAG/$(BUILDARCH)) +ARCHFLAG/i486 = -m32 +ARCHFLAG/amd64 = -m64 + +CFLAGS += $(ARCHFLAG) +AOUT_FLAGS += $(ARCHFLAG) +LFLAGS += $(ARCHFLAG) +ASFLAGS += $(ARCHFLAG) + +#------------------------------------------------------------------------ +# Compiler flags + +# position-independent code +PICFLAG = -KPIC + +CFLAGS += $(PICFLAG) +# no more exceptions +CFLAGS += -features=no%except +# Reduce code bloat by reverting back to 5.0 behavior for static initializers +CFLAGS += -features=no%split_init +# allow zero sized arrays +CFLAGS += -features=zla + +# Use C++ Interpreter +ifdef CC_INTERP + CFLAGS += -DCC_INTERP +endif + +# We don't need libCstd.so and librwtools7.so, only libCrun.so +CFLAGS += -library=Crun +LIBS += -lCrun + +CFLAGS += -mt +LFLAGS += -mt + +# Compiler warnings are treated as errors +#WARNINGS_ARE_ERRORS = -errwarn=%all +CFLAGS_WARN/DEFAULT = $(WARNINGS_ARE_ERRORS) +# Special cases +CFLAGS_WARN/BYFILE = $(CFLAGS_WARN/$@)$(CFLAGS_WARN/DEFAULT$(CFLAGS_WARN/$@)) + +# The flags to use for an Optimized build +OPT_CFLAGS+=-xO4 +OPT_CFLAGS/NOOPT=-xO0 + +#------------------------------------------------------------------------ +# Linker flags + +# Use $(MAPFLAG:FILENAME=real_file_name) to specify a map file. +MAPFLAG = -Wl,--version-script=FILENAME + +# Use $(SONAMEFLAG:SONAME=soname) to specify the intrinsic name of a shared obj +SONAMEFLAG = -h SONAME + +# Build shared library +SHARED_FLAG = -G + +#------------------------------------------------------------------------ +# Debug flags +DEBUG_CFLAGS += -g +FASTDEBUG_CFLAGS = -g0 + diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/build/linux/platform_amd64.suncc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/build/linux/platform_amd64.suncc Thu Mar 20 09:17:30 2008 -0500 @@ -0,0 +1,17 @@ +os_family = linux + +arch = x86 + +arch_model = x86_64 + +os_arch = linux_x86 + +os_arch_model = linux_x86_64 + +lib_arch = amd64 + +compiler = sparcWorks + +gnu_dis_arch = amd64 + +sysdefs = -DLINUX -DSPARC_WORKS -D_GNU_SOURCE -DAMD64 diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/build/linux/platform_i486.suncc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/build/linux/platform_i486.suncc Thu Mar 20 09:17:30 2008 -0500 @@ -0,0 +1,17 @@ +os_family = linux + +arch = x86 + +arch_model = x86_32 + +os_arch = linux_x86 + +os_arch_model = linux_x86_32 + +lib_arch = i386 + +compiler = sparcWorks + +gnu_dis_arch = i386 + +sysdefs = -DLINUX -DSPARC_WORKS -D_GNU_SOURCE -DIA32 diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/build/solaris/makefiles/amd64.make --- a/hotspot/build/solaris/makefiles/amd64.make Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/build/solaris/makefiles/amd64.make Thu Mar 20 09:17:30 2008 -0500 @@ -19,7 +19,7 @@ # 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. -# +# # # Must also specify if CPU is little endian @@ -45,6 +45,10 @@ OPT_CFLAGS/generateOptoStub.o = -xO2 OPT_CFLAGS/thread.o = -xO2 +# Work around for 6624782 +OPT_CFLAGS/instanceKlass.o = -Qoption ube -no_a2lf +OPT_CFLAGS/objArrayKlass.o = -Qoption ube -no_a2lf + else ifeq ("${Platform_compiler}", "gcc") @@ -58,6 +62,6 @@ # error _JUNK2_ := $(shell echo >&2 \ "*** ERROR: this compiler is not yet supported by this code base!") - @exit 1 + @exit 1 endif endif diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp --- a/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp Thu Mar 20 09:17:30 2008 -0500 @@ -2037,7 +2037,7 @@ int LIR_Assembler::shift_amount(BasicType t) { - int elem_size = type2aelembytes[t]; + int elem_size = type2aelembytes(t); switch (elem_size) { case 1 : return 0; case 2 : return 1; @@ -2360,7 +2360,7 @@ op->tmp2()->as_register(), op->tmp3()->as_register(), arrayOopDesc::header_size(op->type()), - type2aelembytes[op->type()], + type2aelembytes(op->type()), op->klass()->as_register(), *op->stub()->entry()); } diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/cpu/sparc/vm/c1_LIRGenerator_sparc.cpp --- a/hotspot/src/cpu/sparc/vm/c1_LIRGenerator_sparc.cpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/cpu/sparc/vm/c1_LIRGenerator_sparc.cpp Thu Mar 20 09:17:30 2008 -0500 @@ -179,7 +179,7 @@ LIR_Address* LIRGenerator::emit_array_address(LIR_Opr array_opr, LIR_Opr index_opr, BasicType type, bool needs_card_mark) { - int elem_size = type2aelembytes[type]; + int elem_size = type2aelembytes(type); int shift = exact_log2(elem_size); LIR_Opr base_opr; diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/cpu/sparc/vm/stubGenerator_sparc.cpp --- a/hotspot/src/cpu/sparc/vm/stubGenerator_sparc.cpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/cpu/sparc/vm/stubGenerator_sparc.cpp Thu Mar 20 09:17:30 2008 -0500 @@ -2911,6 +2911,7 @@ // These entry points require SharedInfo::stack0 to be set up in non-core builds StubRoutines::_throw_AbstractMethodError_entry = generate_throw_exception("AbstractMethodError throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_AbstractMethodError), false); + StubRoutines::_throw_IncompatibleClassChangeError_entry= generate_throw_exception("IncompatibleClassChangeError throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_IncompatibleClassChangeError), false); StubRoutines::_throw_ArithmeticException_entry = generate_throw_exception("ArithmeticException throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_ArithmeticException), true); StubRoutines::_throw_NullPointerException_entry = generate_throw_exception("NullPointerException throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_NullPointerException), true); StubRoutines::_throw_NullPointerException_at_call_entry= generate_throw_exception("NullPointerException at call throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_NullPointerException_at_call), false); diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp --- a/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp Thu Mar 20 09:17:30 2008 -0500 @@ -28,6 +28,12 @@ int VM_Version::_features = VM_Version::unknown_m; const char* VM_Version::_features_str = ""; +bool VM_Version::is_niagara1_plus() { + // This is a placeholder until the real test is determined. + return is_niagara1() && + (os::processor_count() > maximum_niagara1_processor_count()); +} + void VM_Version::initialize() { _features = determine_features(); PrefetchCopyIntervalInBytes = prefetch_copy_interval_in_bytes(); @@ -160,3 +166,13 @@ void VM_Version::revert() { _features = saved_features; } + +unsigned int VM_Version::calc_parallel_worker_threads() { + unsigned int result; + if (is_niagara1_plus()) { + result = nof_parallel_worker_threads(5, 16, 8); + } else { + result = nof_parallel_worker_threads(5, 8, 8); + } + return result; +} diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/cpu/sparc/vm/vm_version_sparc.hpp --- a/hotspot/src/cpu/sparc/vm/vm_version_sparc.hpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/cpu/sparc/vm/vm_version_sparc.hpp Thu Mar 20 09:17:30 2008 -0500 @@ -64,6 +64,11 @@ static bool is_niagara1(int features) { return (features & niagara1_m) == niagara1_m; } + static int maximum_niagara1_processor_count() { return 32; } + // Returns true if the platform is in the niagara line and + // newer than the niagara1. + static bool is_niagara1_plus(); + public: // Initialization static void initialize(); @@ -129,4 +134,7 @@ // Override the Abstract_VM_Version implementation. static uint page_size_count() { return is_sun4v() ? 4 : 2; } + + // Calculates the number of parallel threads + static unsigned int calc_parallel_worker_threads(); }; diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/cpu/sparc/vm/vtableStubs_sparc.cpp --- a/hotspot/src/cpu/sparc/vm/vtableStubs_sparc.cpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/cpu/sparc/vm/vtableStubs_sparc.cpp Thu Mar 20 09:17:30 2008 -0500 @@ -175,17 +175,12 @@ // %%%% Could load both offset and interface in one ldx, if they were // in the opposite order. This would save a load. __ ld_ptr(L0, base + itableOffsetEntry::interface_offset_in_bytes(), L1); -#ifdef ASSERT - Label ok; - // Check that entry is non-null and an Oop - __ bpr(Assembler::rc_nz, false, Assembler::pt, L1, ok); - __ delayed()->nop(); - __ stop("null entry point found in itable's offset table"); - __ bind(ok); - __ verify_oop(L1); -#endif // ASSERT - __ cmp(G5_interface, L1); + // If the entry is NULL then we've reached the end of the table + // without finding the expected interface, so throw an exception + Label throw_icce; + __ bpr(Assembler::rc_z, false, Assembler::pn, L1, throw_icce); + __ delayed()->cmp(G5_interface, L1); __ brx(Assembler::notEqual, true, Assembler::pn, search); __ delayed()->add(L0, itableOffsetEntry::size() * wordSize, L0); @@ -223,24 +218,30 @@ __ JMP(G3_scratch, 0); __ delayed()->nop(); + __ bind(throw_icce); + Address icce(G3_scratch, StubRoutines::throw_IncompatibleClassChangeError_entry()); + __ jump_to(icce, 0); + __ delayed()->restore(); + masm->flush(); + + guarantee(__ pc() <= s->code_end(), "overflowed buffer"); + s->set_exception_points(npe_addr, ame_addr); return s; } int VtableStub::pd_code_size_limit(bool is_vtable_stub) { - if (TraceJumps || DebugVtables || CountCompiledCalls || VerifyOops) return 999; + if (TraceJumps || DebugVtables || CountCompiledCalls || VerifyOops) return 1000; else { const int slop = 2*BytesPerInstWord; // sethi;add (needed for long offsets) if (is_vtable_stub) { const int basic = 5*BytesPerInstWord; // ld;ld;ld,jmp,nop return basic + slop; } else { -#ifdef ASSERT - return 999; -#endif // ASSERT - const int basic = 17*BytesPerInstWord; // save, ld, ld, sll, and, add, add, ld, cmp, br, add, ld, add, ld, ld, jmp, restore + // save, ld, ld, sll, and, add, add, ld, cmp, br, add, ld, add, ld, ld, jmp, restore, sethi, jmpl, restore + const int basic = (20 LP64_ONLY(+ 6)) * BytesPerInstWord; return (basic + slop); } } @@ -252,29 +253,3 @@ const unsigned int icache_line_size = 32; return icache_line_size; } - - -//Reconciliation History -// 1.2 97/12/09 17:13:31 vtableStubs_i486.cpp -// 1.4 98/01/21 19:18:37 vtableStubs_i486.cpp -// 1.5 98/02/13 16:33:55 vtableStubs_i486.cpp -// 1.7 98/03/05 17:17:28 vtableStubs_i486.cpp -// 1.9 98/05/18 09:26:17 vtableStubs_i486.cpp -// 1.10 98/05/26 16:28:13 vtableStubs_i486.cpp -// 1.11 98/05/27 08:51:35 vtableStubs_i486.cpp -// 1.12 98/06/15 15:04:12 vtableStubs_i486.cpp -// 1.13 98/07/28 18:44:22 vtableStubs_i486.cpp -// 1.15 98/08/28 11:31:19 vtableStubs_i486.cpp -// 1.16 98/09/02 12:58:31 vtableStubs_i486.cpp -// 1.17 98/09/04 12:15:52 vtableStubs_i486.cpp -// 1.18 98/11/19 11:55:24 vtableStubs_i486.cpp -// 1.19 99/01/12 14:57:56 vtableStubs_i486.cpp -// 1.20 99/01/19 17:42:52 vtableStubs_i486.cpp -// 1.22 99/01/21 10:29:25 vtableStubs_i486.cpp -// 1.30 99/06/02 15:27:39 vtableStubs_i486.cpp -// 1.26 99/06/24 14:25:07 vtableStubs_i486.cpp -// 1.23 99/02/22 14:37:52 vtableStubs_i486.cpp -// 1.28 99/06/29 18:06:17 vtableStubs_i486.cpp -// 1.29 99/07/22 17:03:44 vtableStubs_i486.cpp -// 1.30 99/08/11 09:33:27 vtableStubs_i486.cpp -//End diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/cpu/x86/vm/assembler_x86_64.cpp --- a/hotspot/src/cpu/x86/vm/assembler_x86_64.cpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/cpu/x86/vm/assembler_x86_64.cpp Thu Mar 20 09:17:30 2008 -0500 @@ -1304,7 +1304,7 @@ emit_operand(src, dst); } -void Assembler::mov64(Register dst, int64_t imm64) { +void Assembler::mov64(Register dst, intptr_t imm64) { InstructionMark im(this); int encode = prefixq_and_encode(dst->encoding()); emit_byte(0xB8 | encode); @@ -1331,7 +1331,7 @@ emit_operand(dst, src); } -void Assembler::mov64(Address dst, int64_t imm32) { +void Assembler::mov64(Address dst, intptr_t imm32) { assert(is_simm32(imm32), "lost bits"); InstructionMark im(this); prefixq(dst); diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp --- a/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp Thu Mar 20 09:17:30 2008 -0500 @@ -546,8 +546,8 @@ // set rsi.edi to the end of the arrays (arrays have same length) // negate the index - __ leal(rsi, Address(rsi, rax, Address::times_2, type2aelembytes[T_CHAR])); - __ leal(rdi, Address(rdi, rax, Address::times_2, type2aelembytes[T_CHAR])); + __ leal(rsi, Address(rsi, rax, Address::times_2, type2aelembytes(T_CHAR))); + __ leal(rdi, Address(rdi, rax, Address::times_2, type2aelembytes(T_CHAR))); __ negl(rax); // compare the strings in a loop @@ -1232,7 +1232,7 @@ NEEDS_CLEANUP; // This could be static? Address::ScaleFactor LIR_Assembler::array_element_size(BasicType type) const { - int elem_size = type2aelembytes[type]; + int elem_size = type2aelembytes(type); switch (elem_size) { case 1: return Address::times_1; case 2: return Address::times_2; @@ -2739,7 +2739,7 @@ assert(default_type != NULL && default_type->is_array_klass() && default_type->is_loaded(), "must be true at this point"); - int elem_size = type2aelembytes[basic_type]; + int elem_size = type2aelembytes(basic_type); int shift_amount; Address::ScaleFactor scale; diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/cpu/x86/vm/c1_LIRGenerator_x86.cpp --- a/hotspot/src/cpu/x86/vm/c1_LIRGenerator_x86.cpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/cpu/x86/vm/c1_LIRGenerator_x86.cpp Thu Mar 20 09:17:30 2008 -0500 @@ -151,7 +151,7 @@ LIR_Address* addr; if (index_opr->is_constant()) { - int elem_size = type2aelembytes[type]; + int elem_size = type2aelembytes(type); addr = new LIR_Address(array_opr, offset_in_bytes + index_opr->as_jint() * elem_size, type); } else { diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/cpu/x86/vm/stubGenerator_x86_32.cpp --- a/hotspot/src/cpu/x86/vm/stubGenerator_x86_32.cpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/cpu/x86/vm/stubGenerator_x86_32.cpp Thu Mar 20 09:17:30 2008 -0500 @@ -1416,8 +1416,8 @@ // ======== end loop ======== // It was a real error; we must depend on the caller to finish the job. - // Register rdx = -1 * number of *remaining* oops, r14 = *total* oops. - // Emit GC store barriers for the oops we have copied (r14 + rdx), + // Register "count" = -1 * number of *remaining* oops, length_arg = *total* oops. + // Emit GC store barriers for the oops we have copied (length_arg + count), // and report their number to the caller. __ addl(count, length_arg); // transfers = (length - remaining) __ movl(rax, count); // save the value @@ -1430,6 +1430,7 @@ // Come here on success only. __ BIND(L_do_card_marks); __ movl(count, length_arg); + __ movl(to, to_arg); // reload gen_write_ref_array_post_barrier(to, count); __ xorl(rax, rax); // return 0 on success @@ -2151,6 +2152,7 @@ // These entry points require SharedInfo::stack0 to be set up in non-core builds // and need to be relocatable, so they each fabricate a RuntimeStub internally. StubRoutines::_throw_AbstractMethodError_entry = generate_throw_exception("AbstractMethodError throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_AbstractMethodError), false); + StubRoutines::_throw_IncompatibleClassChangeError_entry= generate_throw_exception("IncompatibleClassChangeError throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_IncompatibleClassChangeError), false); StubRoutines::_throw_ArithmeticException_entry = generate_throw_exception("ArithmeticException throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_ArithmeticException), true); StubRoutines::_throw_NullPointerException_entry = generate_throw_exception("NullPointerException throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_NullPointerException), true); StubRoutines::_throw_NullPointerException_at_call_entry= generate_throw_exception("NullPointerException at call throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_NullPointerException_at_call), false); diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp --- a/hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp Thu Mar 20 09:17:30 2008 -0500 @@ -2832,6 +2832,13 @@ throw_AbstractMethodError), false); + StubRoutines::_throw_IncompatibleClassChangeError_entry = + generate_throw_exception("IncompatibleClassChangeError throw_exception", + CAST_FROM_FN_PTR(address, + SharedRuntime:: + throw_IncompatibleClassChangeError), + false); + StubRoutines::_throw_ArithmeticException_entry = generate_throw_exception("ArithmeticException throw_exception", CAST_FROM_FN_PTR(address, diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/cpu/x86/vm/vtableStubs_x86_32.cpp --- a/hotspot/src/cpu/x86/vm/vtableStubs_x86_32.cpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/cpu/x86/vm/vtableStubs_x86_32.cpp Thu Mar 20 09:17:30 2008 -0500 @@ -138,29 +138,21 @@ __ round_to(rbx, BytesPerLong); } - Label hit, next, entry; + Label hit, next, entry, throw_icce; - __ jmp(entry); + __ jmpb(entry); __ bind(next); __ addl(rbx, itableOffsetEntry::size() * wordSize); __ bind(entry); -#ifdef ASSERT - // Check that the entry is non-null - if (DebugVtables) { - Label L; - __ pushl(rbx); - __ movl(rbx, Address(rbx, itableOffsetEntry::interface_offset_in_bytes())); - __ testl(rbx, rbx); - __ jcc(Assembler::notZero, L); - __ stop("null entry point found in itable's offset table"); - __ bind(L); - __ popl(rbx); - } -#endif - __ cmpl(rax, Address(rbx, itableOffsetEntry::interface_offset_in_bytes())); + // If the entry is NULL then we've reached the end of the table + // without finding the expected interface, so throw an exception + __ movl(rdx, Address(rbx, itableOffsetEntry::interface_offset_in_bytes())); + __ testl(rdx, rdx); + __ jcc(Assembler::zero, throw_icce); + __ cmpl(rax, rdx); __ jcc(Assembler::notEqual, next); // We found a hit, move offset into rbx, @@ -194,7 +186,15 @@ address ame_addr = __ pc(); __ jmp(Address(method, methodOopDesc::from_compiled_offset())); + __ bind(throw_icce); + // Restore saved register + __ popl(rdx); + __ jump(RuntimeAddress(StubRoutines::throw_IncompatibleClassChangeError_entry())); + masm->flush(); + + guarantee(__ pc() <= s->code_end(), "overflowed buffer"); + s->set_exception_points(npe_addr, ame_addr); return s; } @@ -207,7 +207,7 @@ return (DebugVtables ? 210 : 16) + (CountCompiledCalls ? 6 : 0); } else { // Itable stub size - return (DebugVtables ? 140 : 55) + (CountCompiledCalls ? 6 : 0); + return (DebugVtables ? 144 : 64) + (CountCompiledCalls ? 6 : 0); } } diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/cpu/x86/vm/vtableStubs_x86_64.cpp --- a/hotspot/src/cpu/x86/vm/vtableStubs_x86_64.cpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/cpu/x86/vm/vtableStubs_x86_64.cpp Thu Mar 20 09:17:30 2008 -0500 @@ -153,7 +153,7 @@ // Round up to align_object_offset boundary __ round_to_q(rbx, BytesPerLong); } - Label hit, next, entry; + Label hit, next, entry, throw_icce; __ jmpb(entry); @@ -162,22 +162,13 @@ __ bind(entry); -#ifdef ASSERT - // Check that the entry is non-null - if (DebugVtables) { - Label L; - __ pushq(rbx); - __ movq(rbx, Address(rbx, itableOffsetEntry::interface_offset_in_bytes())); - __ testq(rbx, rbx); - __ jcc(Assembler::notZero, L); - __ stop("null entry point found in itable's offset table"); - __ bind(L); - __ popq(rbx); - } -#endif - - __ cmpq(rax, Address(rbx, itableOffsetEntry::interface_offset_in_bytes())); - __ jcc(Assembler::notEqual, next); + // If the entry is NULL then we've reached the end of the table + // without finding the expected interface, so throw an exception + __ movq(j_rarg1, Address(rbx, itableOffsetEntry::interface_offset_in_bytes())); + __ testq(j_rarg1, j_rarg1); + __ jcc(Assembler::zero, throw_icce); + __ cmpq(rax, j_rarg1); + __ jccb(Assembler::notEqual, next); // We found a hit, move offset into j_rarg1 __ movl(j_rarg1, Address(rbx, itableOffsetEntry::offset_offset_in_bytes())); @@ -203,23 +194,31 @@ #ifdef ASSERT - if (DebugVtables) { - Label L2; - __ cmpq(method, (int)NULL); - __ jcc(Assembler::equal, L2); - __ cmpq(Address(method, methodOopDesc::from_compiled_offset()), (int)NULL_WORD); - __ jcc(Assembler::notZero, L2); - __ stop("compiler entrypoint is null"); - __ bind(L2); - } + if (DebugVtables) { + Label L2; + __ cmpq(method, (int)NULL); + __ jcc(Assembler::equal, L2); + __ cmpq(Address(method, methodOopDesc::from_compiled_offset()), (int)NULL_WORD); + __ jcc(Assembler::notZero, L2); + __ stop("compiler entrypoint is null"); + __ bind(L2); + } #endif // ASSERT - // rbx: methodOop - // j_rarg0: receiver - address ame_addr = __ pc(); - __ jmp(Address(method, methodOopDesc::from_compiled_offset())); + // rbx: methodOop + // j_rarg0: receiver + address ame_addr = __ pc(); + __ jmp(Address(method, methodOopDesc::from_compiled_offset())); + + __ bind(throw_icce); + // Restore saved register + __ popq(j_rarg1); + __ jump(RuntimeAddress(StubRoutines::throw_IncompatibleClassChangeError_entry())); __ flush(); + + guarantee(__ pc() <= s->code_end(), "overflowed buffer"); + s->set_exception_points(npe_addr, ame_addr); return s; } @@ -230,7 +229,7 @@ return (DebugVtables ? 512 : 24) + (CountCompiledCalls ? 13 : 0); } else { // Itable stub size - return (DebugVtables ? 636 : 64) + (CountCompiledCalls ? 13 : 0); + return (DebugVtables ? 636 : 72) + (CountCompiledCalls ? 13 : 0); } } diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/os/linux/vm/attachListener_linux.cpp --- a/hotspot/src/os/linux/vm/attachListener_linux.cpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/os/linux/vm/attachListener_linux.cpp Thu Mar 20 09:17:30 2008 -0500 @@ -232,7 +232,7 @@ // where is the protocol version (1), is the command // name ("load", "datadump", ...), and is an argument int expected_str_count = 2 + AttachOperation::arg_count_max; - int max_len = (strlen(ver_str) + 1) + (AttachOperation::name_length_max + 1) + + const int max_len = (sizeof(ver_str) + 1) + (AttachOperation::name_length_max + 1) + AttachOperation::arg_count_max*(AttachOperation::arg_length_max + 1); char buf[max_len]; diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/os/linux/vm/os_linux.cpp --- a/hotspot/src/os/linux/vm/os_linux.cpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/os/linux/vm/os_linux.cpp Thu Mar 20 09:17:30 2008 -0500 @@ -116,6 +116,20 @@ return Linux::physical_memory(); } +julong os::allocatable_physical_memory(julong size) { +#ifdef _LP64 + return size; +#else + julong result = MIN2(size, (julong)3800*M); + if (!is_allocatable(result)) { + // See comments under solaris for alignment considerations + julong reasonable_size = (julong)2*G - 2 * os::vm_page_size(); + result = MIN2(size, reasonable_size); + } + return result; +#endif // _LP64 +} + //////////////////////////////////////////////////////////////////////////////// // environment support diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/os/windows/vm/os_windows.cpp --- a/hotspot/src/os/windows/vm/os_windows.cpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/os/windows/vm/os_windows.cpp Thu Mar 20 09:17:30 2008 -0500 @@ -621,7 +621,12 @@ } julong os::allocatable_physical_memory(julong size) { +#ifdef _LP64 + return size; +#else + // Limit to 1400m because of the 2gb address space wall return MIN2(size, (julong)1400*M); +#endif } // VC6 lacks DWORD_PTR diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/os_cpu/linux_x86/vm/bytes_linux_x86.inline.hpp --- a/hotspot/src/os_cpu/linux_x86/vm/bytes_linux_x86.inline.hpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/os_cpu/linux_x86/vm/bytes_linux_x86.inline.hpp Thu Mar 20 09:17:30 2008 -0500 @@ -60,7 +60,18 @@ #ifdef AMD64 inline u8 Bytes::swap_u8(u8 x) { +#ifdef SPARC_WORKS + // workaround for SunStudio12 CR6615391 + __asm__ __volatile__ ( + "bswapq %0" + :"=r" (x) // output : register 0 => x + :"0" (x) // input : x => register 0 + :"0" // clobbered register + ); + return x; +#else return bswap_64(x); +#endif } #else // Helper function for swap_u8 diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp --- a/hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp Thu Mar 20 09:17:30 2008 -0500 @@ -62,8 +62,14 @@ #endif // AMD64 address os::current_stack_pointer() { +#ifdef SPARC_WORKS + register void *esp; + __asm__("mov %%"SPELL_REG_SP", %0":"=r"(esp)); + return (address) ((char*)esp + sizeof(long)*2); +#else register void *esp __asm__ (SPELL_REG_SP); return (address) esp; +#endif } char* os::non_memory_address_word() { @@ -139,7 +145,12 @@ } intptr_t* _get_previous_fp() { +#ifdef SPARC_WORKS + register intptr_t **ebp; + __asm__("mov %%"SPELL_REG_FP", %0":"=r"(ebp)); +#else register intptr_t **ebp __asm__ (SPELL_REG_FP); +#endif return (intptr_t*) *ebp; // we want what it points to. } @@ -157,23 +168,8 @@ } } - // Utility functions -julong os::allocatable_physical_memory(julong size) { -#ifdef AMD64 - return size; -#else - julong result = MIN2(size, (julong)3800*M); - if (!is_allocatable(result)) { - // See comments under solaris for alignment considerations - julong reasonable_size = (julong)2*G - 2 * os::vm_page_size(); - result = MIN2(size, reasonable_size); - } - return result; -#endif // AMD64 -} - // From IA32 System Programming Guide enum { trap_page_fault = 0xE @@ -575,7 +571,9 @@ #else size_t os::Linux::min_stack_allowed = (48 DEBUG_ONLY(+4))*K; +#ifdef __GNUC__ #define GET_GS() ({int gs; __asm__ volatile("movw %%gs, %w0":"=q"(gs)); gs&0xffff;}) +#endif // Test if pthread library can support variable thread stack size. LinuxThreads // in fixed stack mode allocates 2M fixed slot for each thread. LinuxThreads @@ -606,7 +604,11 @@ // return true and skip _thread_safety_check(), so we may not be able to // detect stack-heap collisions. But otherwise it's harmless. // +#ifdef __GNUC__ return (GET_GS() != 0); +#else + return false; +#endif } } #endif // AMD64 diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/c1/c1_LIR.cpp --- a/hotspot/src/share/vm/c1/c1_LIR.cpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/c1/c1_LIR.cpp Thu Mar 20 09:17:30 2008 -0500 @@ -105,7 +105,7 @@ LIR_Address::Scale LIR_Address::scale(BasicType type) { - int elem_size = type2aelembytes[type]; + int elem_size = type2aelembytes(type); switch (elem_size) { case 1: return LIR_Address::times_1; case 2: return LIR_Address::times_2; diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/ci/bcEscapeAnalyzer.cpp --- a/hotspot/src/share/vm/ci/bcEscapeAnalyzer.cpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/ci/bcEscapeAnalyzer.cpp Thu Mar 20 09:17:30 2008 -0500 @@ -104,7 +104,7 @@ }; void BCEscapeAnalyzer::set_returned(ArgumentMap vars) { - for (int i = 0; i <= _arg_size; i++) { + for (int i = 0; i < _arg_size; i++) { if (vars.contains(i)) _arg_returned.set_bit(i); } @@ -112,10 +112,9 @@ _return_allocated = _return_allocated && vars.contains_allocated() && !(vars.contains_unknown() || vars.contains_vars()); } - // return true if any element of vars is an argument bool BCEscapeAnalyzer::is_argument(ArgumentMap vars) { - for (int i = 0; i <= _arg_size; i++) { + for (int i = 0; i < _arg_size; i++) { if (vars.contains(i)) return true; } @@ -126,7 +125,7 @@ bool BCEscapeAnalyzer::is_arg_stack(ArgumentMap vars){ if (_conservative) return true; - for (int i = 0; i <= _arg_size; i++) { + for (int i = 0; i < _arg_size; i++) { if (vars.contains(i) && _arg_stack.at(i)) return true; } @@ -134,12 +133,13 @@ } void BCEscapeAnalyzer::clear_bits(ArgumentMap vars, BitMap &bm) { - for (int i = 0; i <= _arg_size; i++) { + for (int i = 0; i < _arg_size; i++) { if (vars.contains(i)) { bm.clear_bit(i); } } } + void BCEscapeAnalyzer::set_method_escape(ArgumentMap vars) { clear_bits(vars, _arg_local); } @@ -155,6 +155,17 @@ clear_bits(vars, _dirty); } +void BCEscapeAnalyzer::set_modified(ArgumentMap vars, int offs, int size) { + + for (int i = 0; i < _arg_size; i++) { + if (vars.contains(i)) { + set_arg_modified(i, offs, size); + } + } + if (vars.contains_unknown()) + _unknown_modified = true; +} + bool BCEscapeAnalyzer::is_recursive_call(ciMethod* callee) { for (BCEscapeAnalyzer* scope = this; scope != NULL; scope = scope->_parent) { if (scope->method() == callee) { @@ -164,6 +175,40 @@ return false; } +bool BCEscapeAnalyzer::is_arg_modified(int arg, int offset, int size_in_bytes) { + if (offset == OFFSET_ANY) + return _arg_modified[arg] != 0; + assert(arg >= 0 && arg < _arg_size, "must be an argument."); + bool modified = false; + int l = offset / HeapWordSize; + int h = round_to(offset + size_in_bytes, HeapWordSize) / HeapWordSize; + if (l > ARG_OFFSET_MAX) + l = ARG_OFFSET_MAX; + if (h > ARG_OFFSET_MAX+1) + h = ARG_OFFSET_MAX + 1; + for (int i = l; i < h; i++) { + modified = modified || (_arg_modified[arg] & (1 << i)) != 0; + } + return modified; +} + +void BCEscapeAnalyzer::set_arg_modified(int arg, int offset, int size_in_bytes) { + if (offset == OFFSET_ANY) { + _arg_modified[arg] = (uint) -1; + return; + } + assert(arg >= 0 && arg < _arg_size, "must be an argument."); + int l = offset / HeapWordSize; + int h = round_to(offset + size_in_bytes, HeapWordSize) / HeapWordSize; + if (l > ARG_OFFSET_MAX) + l = ARG_OFFSET_MAX; + if (h > ARG_OFFSET_MAX+1) + h = ARG_OFFSET_MAX + 1; + for (int i = l; i < h; i++) { + _arg_modified[arg] |= (1 << i); + } +} + void BCEscapeAnalyzer::invoke(StateInfo &state, Bytecodes::Code code, ciMethod* target, ciKlass* holder) { int i; @@ -197,6 +242,7 @@ for (i = 0; i < arg_size; i++) { set_method_escape(state.raw_pop()); } + _unknown_modified = true; // assume the worst since we don't analyze the called method return; } @@ -224,6 +270,11 @@ ArgumentMap arg = state.raw_pop(); if (!is_argument(arg)) continue; + for (int j = 0; j < _arg_size; j++) { + if (arg.contains(j)) { + _arg_modified[j] |= analyzer._arg_modified[i]; + } + } if (!is_arg_stack(arg)) { // arguments have already been recognized as escaping } else if (analyzer.is_arg_stack(i) && !analyzer.is_arg_returned(i)) { @@ -233,6 +284,7 @@ set_global_escape(arg); } } + _unknown_modified = _unknown_modified || analyzer.has_non_arg_side_affects(); // record dependencies if at least one parameter retained stack-allocatable if (must_record_dependencies) { @@ -250,8 +302,10 @@ ArgumentMap arg = state.raw_pop(); if (!is_argument(arg)) continue; + set_modified(arg, OFFSET_ANY, type2size[T_INT]*HeapWordSize); set_global_escape(arg); } + _unknown_modified = true; // assume the worst since we don't know the called method } } @@ -421,6 +475,7 @@ state.spop(); ArgumentMap arr = state.apop(); set_method_escape(arr); + set_modified(arr, OFFSET_ANY, type2size[T_INT]*HeapWordSize); break; } case Bytecodes::_lastore: @@ -430,6 +485,7 @@ state.spop(); ArgumentMap arr = state.apop(); set_method_escape(arr); + set_modified(arr, OFFSET_ANY, type2size[T_LONG]*HeapWordSize); break; } case Bytecodes::_aastore: @@ -437,6 +493,7 @@ set_global_escape(state.apop()); state.spop(); ArgumentMap arr = state.apop(); + set_modified(arr, OFFSET_ANY, type2size[T_OBJECT]*HeapWordSize); break; } case Bytecodes::_pop: @@ -762,6 +819,7 @@ if (s.cur_bc() != Bytecodes::_putstatic) { ArgumentMap p = state.apop(); set_method_escape(p); + set_modified(p, will_link ? field->offset() : OFFSET_ANY, type2size[field_type]*HeapWordSize); } } break; @@ -872,7 +930,7 @@ } void BCEscapeAnalyzer::merge_block_states(StateInfo *blockstates, ciBlock *dest, StateInfo *s_state) { - StateInfo *d_state = blockstates+dest->index(); + StateInfo *d_state = blockstates + dest->index(); int nlocals = _method->max_locals(); // exceptions may cause transfer of control to handlers in the middle of a @@ -916,6 +974,7 @@ } for (int i = 0; i < s_state->_stack_height; i++) { ArgumentMap t; + //extra_vars |= !d_state->_vars[i] & s_state->_vars[i]; t.clear(); t = s_state->_stack[i]; t.set_difference(d_state->_stack[i]); @@ -933,7 +992,7 @@ int datacount = (numblocks + 1) * (stkSize + numLocals); int datasize = datacount * sizeof(ArgumentMap); - StateInfo *blockstates = (StateInfo *) arena->Amalloc(_methodBlocks->num_blocks() * sizeof(StateInfo)); + StateInfo *blockstates = (StateInfo *) arena->Amalloc(numblocks * sizeof(StateInfo)); ArgumentMap *statedata = (ArgumentMap *) arena->Amalloc(datasize); for (int i = 0; i < datacount; i++) ::new ((void*)&statedata[i]) ArgumentMap(); ArgumentMap *dp = statedata; @@ -961,33 +1020,35 @@ ArgumentMap allVars; // all oop arguments to method ciSignature* sig = method()->signature(); int j = 0; + ciBlock* first_blk = _methodBlocks->block_containing(0); + int fb_i = first_blk->index(); if (!method()->is_static()) { // record information for "this" - blockstates[0]._vars[j].set(j); + blockstates[fb_i]._vars[j].set(j); allVars.add(j); j++; } for (int i = 0; i < sig->count(); i++) { ciType* t = sig->type_at(i); if (!t->is_primitive_type()) { - blockstates[0]._vars[j].set(j); + blockstates[fb_i]._vars[j].set(j); allVars.add(j); } j += t->size(); } - blockstates[0]._initialized = true; + blockstates[fb_i]._initialized = true; assert(j == _arg_size, "just checking"); ArgumentMap unknown_map; unknown_map.add_unknown(); - worklist.push(_methodBlocks->block_containing(0)); + worklist.push(first_blk); while(worklist.length() > 0) { ciBlock *blk = worklist.pop(); - StateInfo *blkState = blockstates+blk->index(); + StateInfo *blkState = blockstates + blk->index(); if (blk->is_handler() || blk->is_ret_target()) { // for an exception handler or a target of a ret instruction, we assume the worst case, - // that any variable or stack slot could contain any argument + // that any variable could contain any argument for (int i = 0; i < numLocals; i++) { state._vars[i] = allVars; } @@ -997,6 +1058,7 @@ state._stack_height = blkState->_stack_height; } for (int i = 0; i < state._stack_height; i++) { +// ??? should this be unknown_map ??? state._stack[i] = allVars; } } else { @@ -1053,6 +1115,7 @@ vmIntrinsics::ID iid = method()->intrinsic_id(); if (iid == vmIntrinsics::_getClass || + iid == vmIntrinsics::_fillInStackTrace || iid == vmIntrinsics::_hashCode) return iid; else @@ -1060,12 +1123,16 @@ } bool BCEscapeAnalyzer::compute_escape_for_intrinsic(vmIntrinsics::ID iid) { - ArgumentMap empty; - empty.clear(); + ArgumentMap arg; + arg.clear(); switch (iid) { case vmIntrinsics::_getClass: _return_local = false; break; + case vmIntrinsics::_fillInStackTrace: + arg.set(0); // 'this' + set_returned(arg); + break; case vmIntrinsics::_hashCode: // initialized state is correct break; @@ -1109,15 +1176,21 @@ _return_allocated = true; } _allocated_escapes = false; + _unknown_modified = false; } void BCEscapeAnalyzer::clear_escape_info() { ciSignature* sig = method()->signature(); int arg_count = sig->count(); ArgumentMap var; + if (!method()->is_static()) { + arg_count++; // allow for "this" + } for (int i = 0; i < arg_count; i++) { + set_arg_modified(i, OFFSET_ANY, 4); var.clear(); var.set(i); + set_modified(var, OFFSET_ANY, 4); set_global_escape(var); } _arg_local.clear(); @@ -1126,6 +1199,7 @@ _return_local = false; _return_allocated = false; _allocated_escapes = true; + _unknown_modified = true; } @@ -1205,8 +1279,17 @@ } else { tty->print_cr(" non-local return values"); } + tty->print(" modified args: "); + for (int i = 0; i < _arg_size; i++) { + if (_arg_modified[i] == 0) + tty->print(" 0"); + else + tty->print(" 0x%x", _arg_modified[i]); + } tty->cr(); tty->print(" flags: "); + if (_unknown_modified) + tty->print(" unknown_modified"); if (_return_allocated) tty->print(" return_allocated"); tty->cr(); @@ -1228,6 +1311,7 @@ if (_arg_returned.at(i)) { methodData()->set_arg_returned(i); } + methodData()->set_arg_modified(i, _arg_modified[i]); } if (_return_local) { methodData()->set_eflag(methodDataOopDesc::return_local); @@ -1244,6 +1328,7 @@ _arg_local.at_put(i, methodData()->is_arg_local(i)); _arg_stack.at_put(i, methodData()->is_arg_stack(i)); _arg_returned.at_put(i, methodData()->is_arg_returned(i)); + _arg_modified[i] = methodData()->arg_modified(i); } _return_local = methodData()->eflag_set(methodDataOopDesc::return_local); @@ -1261,6 +1346,12 @@ tty->print_cr(" non-local return values"); } tty->print(" modified args: "); + for (int i = 0; i < _arg_size; i++) { + if (_arg_modified[i] == 0) + tty->print(" 0"); + else + tty->print(" 0x%x", _arg_modified[i]); + } tty->cr(); } #endif @@ -1281,6 +1372,7 @@ , _return_local(false) , _return_allocated(false) , _allocated_escapes(false) + , _unknown_modified(false) , _dependencies() , _parent(parent) , _level(parent == NULL ? 0 : parent->level() + 1) { @@ -1290,6 +1382,8 @@ _arg_returned.clear(); _dirty.clear(); Arena* arena = CURRENT_ENV->arena(); + _arg_modified = (uint *) arena->Amalloc(_arg_size * sizeof(uint)); + Copy::zero_to_bytes(_arg_modified, _arg_size * sizeof(uint)); if (methodData() == NULL) return; diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/ci/bcEscapeAnalyzer.hpp --- a/hotspot/src/share/vm/ci/bcEscapeAnalyzer.hpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/ci/bcEscapeAnalyzer.hpp Thu Mar 20 09:17:30 2008 -0500 @@ -46,9 +46,12 @@ BitMap _arg_stack; BitMap _arg_returned; BitMap _dirty; + enum{ ARG_OFFSET_MAX = 31}; + uint *_arg_modified; bool _return_local; bool _allocated_escapes; + bool _unknown_modified; bool _return_allocated; ciObjectList _dependencies; @@ -80,6 +83,7 @@ void set_method_escape(ArgumentMap vars); void set_global_escape(ArgumentMap vars); void set_dirty(ArgumentMap vars); + void set_modified(ArgumentMap vars, int offs, int size); bool is_recursive_call(ciMethod* callee); void add_dependence(ciKlass *klass, ciMethod *meth); @@ -140,6 +144,13 @@ return !_conservative && _return_allocated && !_allocated_escapes; } + // Tracking of argument modification + + enum {OFFSET_ANY = -1}; + bool is_arg_modified(int arg, int offset, int size_in_bytes); + void set_arg_modified(int arg, int offset, int size_in_bytes); + bool has_non_arg_side_affects() { return _unknown_modified; } + // Copy dependencies from this analysis into "deps" void copy_dependencies(Dependencies *deps); }; diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/ci/ciField.hpp --- a/hotspot/src/share/vm/ci/ciField.hpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/ci/ciField.hpp Thu Mar 20 09:17:30 2008 -0500 @@ -102,7 +102,7 @@ BasicType layout_type() { return type2field[(_type == NULL) ? T_OBJECT : _type->basic_type()]; } // How big is this field in memory? - int size_in_bytes() { return type2aelembytes[layout_type()]; } + int size_in_bytes() { return type2aelembytes(layout_type()); } // What is the offset of this field? int offset() { diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/ci/ciInstanceKlass.cpp --- a/hotspot/src/share/vm/ci/ciInstanceKlass.cpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/ci/ciInstanceKlass.cpp Thu Mar 20 09:17:30 2008 -0500 @@ -34,7 +34,9 @@ // ciInstanceKlass::ciInstanceKlass // // Loaded instance klass. -ciInstanceKlass::ciInstanceKlass(KlassHandle h_k) : ciKlass(h_k) { +ciInstanceKlass::ciInstanceKlass(KlassHandle h_k) : + ciKlass(h_k), _non_static_fields(NULL) +{ assert(get_Klass()->oop_is_instance(), "wrong type"); instanceKlass* ik = get_instanceKlass(); @@ -335,6 +337,37 @@ return field; } +// ------------------------------------------------------------------ +// ciInstanceKlass::non_static_fields. + +class NonStaticFieldFiller: public FieldClosure { + GrowableArray* _arr; + ciEnv* _curEnv; +public: + NonStaticFieldFiller(ciEnv* curEnv, GrowableArray* arr) : + _curEnv(curEnv), _arr(arr) + {} + void do_field(fieldDescriptor* fd) { + ciField* field = new (_curEnv->arena()) ciField(fd); + _arr->append(field); + } +}; + +GrowableArray* ciInstanceKlass::non_static_fields() { + if (_non_static_fields == NULL) { + VM_ENTRY_MARK; + ciEnv* curEnv = ciEnv::current(); + instanceKlass* ik = get_instanceKlass(); + int max_n_fields = ik->fields()->length()/instanceKlass::next_offset; + + _non_static_fields = + new (curEnv->arena()) GrowableArray(max_n_fields); + NonStaticFieldFiller filler(curEnv, _non_static_fields); + ik->do_nonstatic_fields(&filler); + } + return _non_static_fields; +} + static int sort_field_by_offset(ciField** a, ciField** b) { return (*a)->offset_in_bytes() - (*b)->offset_in_bytes(); // (no worries about 32-bit overflow...) diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/ci/ciInstanceKlass.hpp --- a/hotspot/src/share/vm/ci/ciInstanceKlass.hpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/ci/ciInstanceKlass.hpp Thu Mar 20 09:17:30 2008 -0500 @@ -46,6 +46,7 @@ bool _has_subklass; ciFlags _flags; jint _nonstatic_field_size; + jint _nonstatic_oop_map_size; // Lazy fields get filled in only upon request. ciInstanceKlass* _super; @@ -58,6 +59,8 @@ ciInstanceKlass* _implementors[implementors_limit]; jint _nof_implementors; + GrowableArray* _non_static_fields; + protected: ciInstanceKlass(KlassHandle h_k); ciInstanceKlass(ciSymbol* name, jobject loader, jobject protection_domain); @@ -129,6 +132,9 @@ jint nonstatic_field_size() { assert(is_loaded(), "must be loaded"); return _nonstatic_field_size; } + jint nonstatic_oop_map_size() { + assert(is_loaded(), "must be loaded"); + return _nonstatic_oop_map_size; } ciInstanceKlass* super(); jint nof_implementors() { assert(is_loaded(), "must be loaded"); @@ -138,6 +144,9 @@ ciInstanceKlass* get_canonical_holder(int offset); ciField* get_field_by_offset(int field_offset, bool is_static); + + GrowableArray* non_static_fields(); + // total number of nonstatic fields (including inherited): int nof_nonstatic_fields() { if (_nonstatic_fields == NULL) diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/ci/ciMethod.cpp --- a/hotspot/src/share/vm/ci/ciMethod.cpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/ci/ciMethod.cpp Thu Mar 20 09:17:30 2008 -0500 @@ -146,7 +146,7 @@ memcpy(_code, me->code_base(), code_size()); // Revert any breakpoint bytecodes in ci's copy - if (_is_compilable && me->number_of_breakpoints() > 0) { + if (me->number_of_breakpoints() > 0) { BreakpointInfo* bp = instanceKlass::cast(me->method_holder())->breakpoints(); for (; bp != NULL; bp = bp->next()) { if (bp->match(me)) { diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/ci/ciMethodBlocks.cpp --- a/hotspot/src/share/vm/ci/ciMethodBlocks.cpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/ci/ciMethodBlocks.cpp Thu Mar 20 09:17:30 2008 -0500 @@ -67,6 +67,14 @@ break; } } + // Move an exception handler information if needed. + if (former_block->is_handler()) { + int ex_start = former_block->ex_start_bci(); + int ex_end = former_block->ex_limit_bci(); + new_block->set_exception_range(ex_start, ex_end); + // Clear information in former_block. + former_block->clear_exception_handler(); + } return former_block; } @@ -102,7 +110,7 @@ // one and end the old one. assert(cur_block != NULL, "must always have a current block"); ciBlock *new_block = block_containing(bci); - if (new_block == NULL) { + if (new_block == NULL || new_block == cur_block) { // We have not marked this bci as the start of a new block. // Keep interpreting the current_range. _bci_to_block[bci] = cur_block; @@ -254,9 +262,33 @@ for(ciExceptionHandlerStream str(meth); !str.is_done(); str.next()) { ciExceptionHandler* handler = str.handler(); ciBlock *eb = make_block_at(handler->handler_bci()); - eb->set_handler(); + // + // Several exception handlers can have the same handler_bci: + // + // try { + // if (a.foo(b) < 0) { + // return a.error(); + // } + // return CoderResult.UNDERFLOW; + // } finally { + // a.position(b); + // } + // + // The try block above is divided into 2 exception blocks + // separated by 'areturn' bci. + // int ex_start = handler->start(); int ex_end = handler->limit(); + if (eb->is_handler()) { + // Extend old handler exception range to cover additional range. + int old_ex_start = eb->ex_start_bci(); + int old_ex_end = eb->ex_limit_bci(); + if (ex_start > old_ex_start) + ex_start = old_ex_start; + if (ex_end < old_ex_end) + ex_end = old_ex_end; + eb->clear_exception_handler(); // Reset exception information + } eb->set_exception_range(ex_start, ex_end); // ensure a block at the start of exception range and start of following code (void) make_block_at(ex_start); @@ -312,9 +344,10 @@ void ciBlock::set_exception_range(int start_bci, int limit_bci) { assert(limit_bci >= start_bci, "valid range"); - assert(is_handler(), "must be handler"); + assert(!is_handler() && _ex_start_bci == -1 && _ex_limit_bci == -1, "must not be handler"); _ex_start_bci = start_bci; _ex_limit_bci = limit_bci; + set_handler(); } #ifndef PRODUCT diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/ci/ciMethodBlocks.hpp --- a/hotspot/src/share/vm/ci/ciMethodBlocks.hpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/ci/ciMethodBlocks.hpp Thu Mar 20 09:17:30 2008 -0500 @@ -110,9 +110,10 @@ void set_does_jsr() { _flags |= DoesJsr; } void clear_does_jsr() { _flags &= ~DoesJsr; } void set_does_ret() { _flags |= DoesRet; } - void clear_does_ret() { _flags |= DoesRet; } + void clear_does_ret() { _flags &= ~DoesRet; } void set_is_ret_target() { _flags |= RetTarget; } void set_has_handler() { _flags |= HasHandler; } + void clear_exception_handler() { _flags &= ~Handler; _ex_start_bci = -1; _ex_limit_bci = -1; } #ifndef PRODUCT ciMethod *method() const { return _method; } void dump(); diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/ci/ciMethodData.cpp --- a/hotspot/src/share/vm/ci/ciMethodData.cpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/ci/ciMethodData.cpp Thu Mar 20 09:17:30 2008 -0500 @@ -42,6 +42,8 @@ // Set an initial hint. Don't use set_hint_di() because // first_di() may be out of bounds if data_size is 0. _hint_di = first_di(); + // Initialize the escape information (to "don't know."); + _eflags = _arg_local = _arg_stack = _arg_returned = 0; } // ------------------------------------------------------------------ @@ -59,6 +61,8 @@ // Set an initial hint. Don't use set_hint_di() because // first_di() may be out of bounds if data_size is 0. _hint_di = first_di(); + // Initialize the escape information (to "don't know."); + _eflags = _arg_local = _arg_stack = _arg_returned = 0; } void ciMethodData::load_data() { @@ -142,6 +146,8 @@ return new ciBranchData(data_layout); case DataLayout::multi_branch_data_tag: return new ciMultiBranchData(data_layout); + case DataLayout::arg_info_data_tag: + return new ciArgInfoData(data_layout); }; } @@ -172,6 +178,9 @@ _saw_free_extra_data = true; // observed an empty slot (common case) return NULL; } + if (dp->tag() == DataLayout::arg_info_data_tag) { + break; // ArgInfoData is at the end of extra data section. + } if (dp->bci() == bci) { assert(dp->tag() == DataLayout::bit_data_tag, "sane"); return new ciBitData(dp); @@ -217,8 +226,14 @@ void ciMethodData::clear_escape_info() { VM_ENTRY_MARK; methodDataOop mdo = get_methodDataOop(); - if (mdo != NULL) + if (mdo != NULL) { mdo->clear_escape_info(); + ArgInfoData *aid = arg_info(); + int arg_count = (aid == NULL) ? 0 : aid->number_of_args(); + for (int i = 0; i < arg_count; i++) { + set_arg_modified(i, 0); + } + } _eflags = _arg_local = _arg_stack = _arg_returned = 0; } @@ -231,6 +246,10 @@ mdo->set_arg_local(_arg_local); mdo->set_arg_stack(_arg_stack); mdo->set_arg_returned(_arg_returned); + int arg_count = mdo->method()->size_of_parameters(); + for (int i = 0; i < arg_count; i++) { + mdo->set_arg_modified(i, arg_modified(i)); + } } } @@ -262,6 +281,14 @@ set_nth_bit(_arg_returned, i); } +void ciMethodData::set_arg_modified(int arg, uint val) { + ArgInfoData *aid = arg_info(); + if (aid == NULL) + return; + assert(arg >= 0 && arg < aid->number_of_args(), "valid argument number"); + aid->set_arg_modified(arg, val); +} + bool ciMethodData::is_arg_local(int i) const { return is_set_nth_bit(_arg_local, i); } @@ -274,6 +301,14 @@ return is_set_nth_bit(_arg_returned, i); } +uint ciMethodData::arg_modified(int arg) const { + ArgInfoData *aid = arg_info(); + if (aid == NULL) + return 0; + assert(arg >= 0 && arg < aid->number_of_args(), "valid argument number"); + return aid->arg_modified(arg); +} + ByteSize ciMethodData::offset_of_slot(ciProfileData* data, ByteSize slot_offset_in_data) { // Get offset within methodDataOop of the data array ByteSize data_offset = methodDataOopDesc::data_offset(); @@ -287,6 +322,18 @@ return in_ByteSize(offset); } +ciArgInfoData *ciMethodData::arg_info() const { + // Should be last, have to skip all traps. + DataLayout* dp = data_layout_at(data_size()); + DataLayout* end = data_layout_at(data_size() + extra_data_size()); + for (; dp < end; dp = methodDataOopDesc::next_extra(dp)) { + if (dp->tag() == DataLayout::arg_info_data_tag) + return new ciArgInfoData(dp); + } + return NULL; +} + + // Implementation of the print method. void ciMethodData::print_impl(outputStream* st) { ciObject::print_impl(st); @@ -305,6 +352,22 @@ st->fill_to(6); data->print_data_on(st); } + st->print_cr("--- Extra data:"); + DataLayout* dp = data_layout_at(data_size()); + DataLayout* end = data_layout_at(data_size() + extra_data_size()); + for (; dp < end; dp = methodDataOopDesc::next_extra(dp)) { + if (dp->tag() == DataLayout::no_tag) continue; + if (dp->tag() == DataLayout::bit_data_tag) { + data = new BitData(dp); + } else { + assert(dp->tag() == DataLayout::arg_info_data_tag, "must be BitData or ArgInfo"); + data = new ciArgInfoData(dp); + dp = end; // ArgInfoData is at the end of extra data section. + } + st->print("%d", dp_to_di(data->dp())); + st->fill_to(6); + data->print_data_on(st); + } } void ciReceiverTypeData::print_receiver_data_on(outputStream* st) { diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/ci/ciMethodData.hpp --- a/hotspot/src/share/vm/ci/ciMethodData.hpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/ci/ciMethodData.hpp Thu Mar 20 09:17:30 2008 -0500 @@ -30,6 +30,7 @@ class ciBranchData; class ciArrayData; class ciMultiBranchData; +class ciArgInfoData; typedef ProfileData ciProfileData; @@ -121,6 +122,11 @@ ciMultiBranchData(DataLayout* layout) : MultiBranchData(layout) {}; }; +class ciArgInfoData : public ArgInfoData { +public: + ciArgInfoData(DataLayout* layout) : ArgInfoData(layout) {}; +}; + // ciMethodData // // This class represents a methodDataOop in the HotSpot virtual @@ -163,9 +169,9 @@ ciMethodData(); // Accessors - int data_size() { return _data_size; } - int extra_data_size() { return _extra_data_size; } - intptr_t * data() { return _data; } + int data_size() const { return _data_size; } + int extra_data_size() const { return _extra_data_size; } + intptr_t * data() const { return _data; } methodDataOop get_methodDataOop() const { if (handle() == NULL) return NULL; @@ -178,7 +184,7 @@ void print_impl(outputStream* st); - DataLayout* data_layout_at(int data_index) { + DataLayout* data_layout_at(int data_index) const { assert(data_index % sizeof(intptr_t) == 0, "unaligned"); return (DataLayout*) (((address)_data) + data_index); } @@ -207,6 +213,8 @@ // What is the index of the first data entry? int first_di() { return 0; } + ciArgInfoData *arg_info() const; + public: bool is_method_data() { return true; } bool is_empty() { return _state == empty_state; } @@ -270,10 +278,12 @@ void set_arg_local(int i); void set_arg_stack(int i); void set_arg_returned(int i); + void set_arg_modified(int arg, uint val); bool is_arg_local(int i) const; bool is_arg_stack(int i) const; bool is_arg_returned(int i) const; + uint arg_modified(int arg) const; // Code generation helper ByteSize offset_of_slot(ciProfileData* data, ByteSize slot_offset_in_data); diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/ci/ciObjArray.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/ci/ciObjArray.cpp Thu Mar 20 09:17:30 2008 -0500 @@ -0,0 +1,43 @@ +/* + * Copyright 1999-2007 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. + * + */ + +#include "incls/_precompiled.incl" +#include "incls/_ciObjArray.cpp.incl" + +// ciObjArray +// +// This class represents an objArrayOop in the HotSpot virtual +// machine. + +ciObject* ciObjArray::obj_at(int index) { + VM_ENTRY_MARK; + objArrayOop array = get_objArrayOop(); + if (index < 0 || index >= array->length()) return NULL; + oop o = array->obj_at(index); + if (o == NULL) { + return ciNullObject::make(); + } else { + return CURRENT_ENV->get_object(o); + } +} diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/ci/ciObjArray.hpp --- a/hotspot/src/share/vm/ci/ciObjArray.hpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/ci/ciObjArray.hpp Thu Mar 20 09:17:30 2008 -0500 @@ -43,4 +43,6 @@ public: // What kind of ciObject is this? bool is_obj_array() { return true; } + + ciObject* obj_at(int index); }; diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/classfile/dictionary.cpp --- a/hotspot/src/share/vm/classfile/dictionary.cpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/classfile/dictionary.cpp Thu Mar 20 09:17:30 2008 -0500 @@ -155,8 +155,8 @@ for (int i = ik->previous_versions()->length() - 1; i >= 0; i--) { // check the previous versions array for GC'ed weak refs PreviousVersionNode * pv_node = ik->previous_versions()->at(i); - jweak cp_ref = pv_node->prev_constant_pool(); - assert(cp_ref != NULL, "weak cp ref was unexpectedly cleared"); + jobject cp_ref = pv_node->prev_constant_pool(); + assert(cp_ref != NULL, "cp ref was unexpectedly cleared"); if (cp_ref == NULL) { delete pv_node; ik->previous_versions()->remove_at(i); diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/classfile/javaClasses.cpp --- a/hotspot/src/share/vm/classfile/javaClasses.cpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/classfile/javaClasses.cpp Thu Mar 20 09:17:30 2008 -0500 @@ -143,13 +143,43 @@ jstring js = NULL; { JavaThread* thread = (JavaThread*)THREAD; assert(thread->is_Java_thread(), "must be java thread"); + HandleMark hm(thread); ThreadToNativeFromVM ttn(thread); - HandleMark hm(thread); js = (_to_java_string_fn)(thread->jni_environment(), str); } return Handle(THREAD, JNIHandles::resolve(js)); } +// Converts a Java String to a native C string that can be used for +// native OS calls. +char* java_lang_String::as_platform_dependent_str(Handle java_string, TRAPS) { + + typedef char* (*to_platform_string_fn_t)(JNIEnv*, jstring, bool*); + static to_platform_string_fn_t _to_platform_string_fn = NULL; + + if (_to_platform_string_fn == NULL) { + void *lib_handle = os::native_java_library(); + _to_platform_string_fn = CAST_TO_FN_PTR(to_platform_string_fn_t, hpi::dll_lookup(lib_handle, "GetStringPlatformChars")); + if (_to_platform_string_fn == NULL) { + fatal("GetStringPlatformChars missing"); + } + } + + char *native_platform_string; + { JavaThread* thread = (JavaThread*)THREAD; + assert(thread->is_Java_thread(), "must be java thread"); + JNIEnv *env = thread->jni_environment(); + jstring js = (jstring) JNIHandles::make_local(env, java_string()); + bool is_copy; + HandleMark hm(thread); + ThreadToNativeFromVM ttn(thread); + native_platform_string = (_to_platform_string_fn)(env, js, &is_copy); + assert(is_copy == JNI_TRUE, "is_copy value changed"); + JNIHandles::destroy_local(js); + } + return native_platform_string; +} + Handle java_lang_String::char_converter(Handle java_string, jchar from_char, jchar to_char, TRAPS) { oop obj = java_string(); // Typical usage is to convert all '/' to '.' in string. diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/classfile/javaClasses.hpp --- a/hotspot/src/share/vm/classfile/javaClasses.hpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/classfile/javaClasses.hpp Thu Mar 20 09:17:30 2008 -0500 @@ -96,6 +96,7 @@ // String converters static char* as_utf8_string(oop java_string); static char* as_utf8_string(oop java_string, int start, int len); + static char* as_platform_dependent_str(Handle java_string, TRAPS); static jchar* as_unicode_string(oop java_string, int& length); static bool equals(oop java_string, jchar* chars, int len); diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/classfile/systemDictionary.cpp --- a/hotspot/src/share/vm/classfile/systemDictionary.cpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/classfile/systemDictionary.cpp Thu Mar 20 09:17:30 2008 -0500 @@ -1242,7 +1242,9 @@ oop obj = (oop) result.get_jobject(); if (obj == NULL) { return nk; } - char* new_class_name = java_lang_String::as_utf8_string(obj); + Handle h_obj(THREAD, obj); + char* new_class_name = java_lang_String::as_platform_dependent_str(h_obj, + CHECK_(nk)); // lock the loader // we use this lock because JVMTI does. diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/classfile/vmSymbols.cpp --- a/hotspot/src/share/vm/classfile/vmSymbols.cpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/classfile/vmSymbols.cpp Thu Mar 20 09:17:30 2008 -0500 @@ -318,6 +318,11 @@ const int neg = JVM_ACC_SYNCHRONIZED; return (flags & (req | neg)) == req; } +inline bool match_F_RNY(jshort flags) { + const int req = JVM_ACC_NATIVE | JVM_ACC_SYNCHRONIZED; + const int neg = JVM_ACC_STATIC; + return (flags & (req | neg)) == req; +} // These are for forming case labels: #define ID3(x, y, z) (( jint)(z) + \ @@ -359,6 +364,7 @@ case F_RN: fname = "native "; break; case F_SN: fname = "native static "; break; case F_S: fname = "static "; break; + case F_RNY:fname = "native synchronized "; break; } const char* kptr = strrchr(kname, '/'); if (kptr != NULL) kname = kptr + 1; @@ -485,7 +491,7 @@ if (PrintMiscellaneous && (WizardMode || Verbose)) { tty->print_cr("*** misidentified method; %s(%d) should be %s(%d):", declared_name, declared_id, actual_name, actual_id); - m->print_short_name(tty); + mh()->print_short_name(tty); tty->cr(); } } diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/classfile/vmSymbols.hpp --- a/hotspot/src/share/vm/classfile/vmSymbols.hpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/classfile/vmSymbols.hpp Thu Mar 20 09:17:30 2008 -0500 @@ -58,12 +58,17 @@ template(java_lang_ThreadDeath, "java/lang/ThreadDeath") \ template(java_lang_Boolean, "java/lang/Boolean") \ template(java_lang_Character, "java/lang/Character") \ + template(java_lang_Character_CharacterCache, "java/lang/Character$CharacterCache") \ template(java_lang_Float, "java/lang/Float") \ template(java_lang_Double, "java/lang/Double") \ template(java_lang_Byte, "java/lang/Byte") \ + template(java_lang_Byte_Cache, "java/lang/Byte$ByteCache") \ template(java_lang_Short, "java/lang/Short") \ + template(java_lang_Short_ShortCache, "java/lang/Short$ShortCache") \ template(java_lang_Integer, "java/lang/Integer") \ + template(java_lang_Integer_IntegerCache, "java/lang/Integer$IntegerCache") \ template(java_lang_Long, "java/lang/Long") \ + template(java_lang_Long_LongCache, "java/lang/Long$LongCache") \ template(java_lang_Shutdown, "java/lang/Shutdown") \ template(java_lang_ref_Reference, "java/lang/ref/Reference") \ template(java_lang_ref_SoftReference, "java/lang/ref/SoftReference") \ @@ -91,10 +96,11 @@ template(java_util_Vector, "java/util/Vector") \ template(java_util_AbstractList, "java/util/AbstractList") \ template(java_util_Hashtable, "java/util/Hashtable") \ + template(java_util_HashMap, "java/util/HashMap") \ template(java_lang_Compiler, "java/lang/Compiler") \ template(sun_misc_Signal, "sun/misc/Signal") \ template(java_lang_AssertionStatusDirectives, "java/lang/AssertionStatusDirectives") \ - template(sun_jkernel_DownloadManager, "sun/jkernel/DownloadManager") \ + template(sun_jkernel_DownloadManager, "sun/jkernel/DownloadManager") \ template(getBootClassPathEntryForClass_name, "getBootClassPathEntryForClass") \ \ /* class file format tags */ \ @@ -274,7 +280,9 @@ template(exclusive_owner_thread_name, "exclusiveOwnerThread") \ template(park_blocker_name, "parkBlocker") \ template(park_event_name, "nativeParkEventPointer") \ + template(cache_field_name, "cache") \ template(value_name, "value") \ + template(frontCacheEnabled_name, "frontCacheEnabled") \ \ /* non-intrinsic name/signature pairs: */ \ template(register_method_name, "register") \ @@ -576,6 +584,8 @@ do_name( attemptUpdate_name, "attemptUpdate") \ do_signature(attemptUpdate_signature, "(JJ)Z") \ \ + do_intrinsic(_fillInStackTrace, java_lang_Throwable, fillInStackTrace_name, void_throwable_signature, F_RNY) \ + \ /* support for sun.misc.Unsafe */ \ do_class(sun_misc_Unsafe, "sun/misc/Unsafe") \ \ @@ -863,7 +873,8 @@ F_R, // !static !synchronized (R="regular") F_S, // static !synchronized F_RN, // !static native !synchronized - F_SN // static native !synchronized + F_SN, // static native !synchronized + F_RNY // !static native synchronized }; public: diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/code/debugInfo.cpp --- a/hotspot/src/share/vm/code/debugInfo.cpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/code/debugInfo.cpp Thu Mar 20 09:17:30 2008 -0500 @@ -47,7 +47,8 @@ } #endif ObjectValue* result = new ObjectValue(id); - _obj_pool->append(result); + // Cache the object since an object field could reference it. + _obj_pool->push(result); result->read_object(this); return result; } @@ -56,9 +57,9 @@ int id = read_int(); assert(_obj_pool != NULL, "object pool does not exist"); for (int i = _obj_pool->length() - 1; i >= 0; i--) { - ObjectValue* sv = (ObjectValue*) _obj_pool->at(i); - if (sv->id() == id) { - return sv; + ObjectValue* ov = (ObjectValue*) _obj_pool->at(i); + if (ov->id() == id) { + return ov; } } ShouldNotReachHere(); diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/code/dependencies.cpp --- a/hotspot/src/share/vm/code/dependencies.cpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/code/dependencies.cpp Thu Mar 20 09:17:30 2008 -0500 @@ -882,6 +882,14 @@ // Must not move the class hierarchy during this check: assert_locked_or_safepoint(Compile_lock); + int nof_impls = instanceKlass::cast(context_type)->nof_implementors(); + if (nof_impls > 1) { + // Avoid this case: *I.m > { A.m, C }; B.m > C + // %%% Until this is fixed more systematically, bail out. + // See corresponding comment in find_witness_anywhere. + return context_type; + } + assert(!is_participant(new_type), "only old classes are participants"); if (participants_hide_witnesses) { // If the new type is a subtype of a participant, we are done. diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/code/nmethod.cpp --- a/hotspot/src/share/vm/code/nmethod.cpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/code/nmethod.cpp Thu Mar 20 09:17:30 2008 -0500 @@ -1971,7 +1971,7 @@ if (ctxk != NULL) { Klass* k = Klass::cast(ctxk); if (k->oop_is_instance() && ((instanceKlass*)k)->is_dependent_nmethod(this)) { - tty->print(" [nmethod<=klass]%s", k->external_name()); + tty->print_cr(" [nmethod<=klass]%s", k->external_name()); } } deps.log_dependency(); // put it into the xml log also diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/code/scopeDesc.cpp --- a/hotspot/src/share/vm/code/scopeDesc.cpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/code/scopeDesc.cpp Thu Mar 20 09:17:30 2008 -0500 @@ -91,7 +91,9 @@ DebugInfoReadStream* stream = new DebugInfoReadStream(_code, decode_offset, result); int length = stream->read_int(); for (int index = 0; index < length; index++) { - result->push(ScopeValue::read_from(stream)); + // Objects values are pushed to 'result' array during read so that + // object's fields could reference it (OBJECT_ID_CODE). + (void)ScopeValue::read_from(stream); } assert(result->length() == length, "inconsistent debug information"); return result; diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/code/vmreg.cpp --- a/hotspot/src/share/vm/code/vmreg.cpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/code/vmreg.cpp Thu Mar 20 09:17:30 2008 -0500 @@ -36,16 +36,16 @@ // Register names const char *VMRegImpl::regName[ConcreteRegisterImpl::number_of_registers]; -void VMRegImpl::print() { #ifndef PRODUCT +void VMRegImpl::print_on(outputStream* st) const { if( is_reg() ) { assert( VMRegImpl::regName[value()], "" ); - tty->print("%s",VMRegImpl::regName[value()]); + st->print("%s",VMRegImpl::regName[value()]); } else if (is_stack()) { int stk = value() - stack0->value(); - tty->print("[%d]", stk*4); + st->print("[%d]", stk*4); } else { - tty->print("BAD!"); + st->print("BAD!"); } +} #endif // PRODUCT -} diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/code/vmreg.hpp --- a/hotspot/src/share/vm/code/vmreg.hpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/code/vmreg.hpp Thu Mar 20 09:17:30 2008 -0500 @@ -66,9 +66,9 @@ } } static VMReg Bad() { return (VMReg) (intptr_t) BAD; } - bool is_valid() { return ((intptr_t) this) != BAD; } - bool is_stack() { return (intptr_t) this >= (intptr_t) stack0; } - bool is_reg() { return is_valid() && !is_stack(); } + bool is_valid() const { return ((intptr_t) this) != BAD; } + bool is_stack() const { return (intptr_t) this >= (intptr_t) stack0; } + bool is_reg() const { return is_valid() && !is_stack(); } // A concrete register is a value that returns true for is_reg() and is // also a register you could use in the assembler. On machines with @@ -96,7 +96,8 @@ intptr_t value() const {return (intptr_t) this; } - void print(); + void print_on(outputStream* st) const PRODUCT_RETURN; + void print() const { print_on(tty); } // bias a stack slot. // Typically used to adjust a virtual frame slots by amounts that are offset by diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/compiler/oopMap.cpp --- a/hotspot/src/share/vm/compiler/oopMap.cpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/compiler/oopMap.cpp Thu Mar 20 09:17:30 2008 -0500 @@ -506,27 +506,27 @@ } -void print_register_type(OopMapValue::oop_types x, VMReg optional) { +static void print_register_type(OopMapValue::oop_types x, VMReg optional, outputStream* st) { switch( x ) { case OopMapValue::oop_value: - tty->print("Oop"); + st->print("Oop"); break; case OopMapValue::value_value: - tty->print("Value" ); + st->print("Value" ); break; case OopMapValue::dead_value: - tty->print("Dead" ); + st->print("Dead" ); break; case OopMapValue::callee_saved_value: - tty->print("Callers_" ); - optional->print(); + st->print("Callers_" ); + optional->print_on(st); break; case OopMapValue::derived_oop_value: - tty->print("Derived_oop_" ); - optional->print(); + st->print("Derived_oop_" ); + optional->print_on(st); break; case OopMapValue::stack_obj: - tty->print("Stack"); + st->print("Stack"); break; default: ShouldNotReachHere(); @@ -534,11 +534,11 @@ } -void OopMapValue::print() const { - reg()->print(); - tty->print("="); - print_register_type(type(),content_reg()); - tty->print(" "); +void OopMapValue::print_on(outputStream* st) const { + reg()->print_on(st); + st->print("="); + print_register_type(type(),content_reg(),st); + st->print(" "); } diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/compiler/oopMap.hpp --- a/hotspot/src/share/vm/compiler/oopMap.hpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/compiler/oopMap.hpp Thu Mar 20 09:17:30 2008 -0500 @@ -129,7 +129,8 @@ return reg()->reg2stack(); } - void print( ) const PRODUCT_RETURN; + void print_on(outputStream* st) const PRODUCT_RETURN; + void print() const { print_on(tty); } }; diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/binaryTreeDictionary.cpp --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/binaryTreeDictionary.cpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/binaryTreeDictionary.cpp Thu Mar 20 09:17:30 2008 -0500 @@ -1071,85 +1071,56 @@ // for each list in the tree. Also print some summary // information. class printTreeCensusClosure : public AscendTreeCensusClosure { + int _print_line; size_t _totalFree; - AllocationStats _totals; - size_t _count; + FreeList _total; public: printTreeCensusClosure() { + _print_line = 0; _totalFree = 0; - _count = 0; - _totals.initialize(); } - AllocationStats* totals() { return &_totals; } - size_t count() { return _count; } - void increment_count_by(size_t v) { _count += v; } + FreeList* total() { return &_total; } size_t totalFree() { return _totalFree; } - void increment_totalFree_by(size_t v) { _totalFree += v; } void do_list(FreeList* fl) { - bool nl = false; // "maybe this is not needed" isNearLargestChunk(fl->head()); - - gclog_or_tty->print("%c %4d\t\t" "%7d\t" "%7d\t" - "%7d\t" "%7d\t" "%7d\t" "%7d\t" - "%7d\t" "%7d\t" "%7d\t" - "%7d\t" "\n", - " n"[nl], fl->size(), fl->bfrSurp(), fl->surplus(), - fl->desired(), fl->prevSweep(), fl->beforeSweep(), fl->count(), - fl->coalBirths(), fl->coalDeaths(), fl->splitBirths(), - fl->splitDeaths()); - - increment_totalFree_by(fl->count() * fl->size()); - increment_count_by(fl->count()); - totals()->set_bfrSurp(totals()->bfrSurp() + fl->bfrSurp()); - totals()->set_surplus(totals()->splitDeaths() + fl->surplus()); - totals()->set_prevSweep(totals()->prevSweep() + fl->prevSweep()); - totals()->set_beforeSweep(totals()->beforeSweep() + fl->beforeSweep()); - totals()->set_coalBirths(totals()->coalBirths() + fl->coalBirths()); - totals()->set_coalDeaths(totals()->coalDeaths() + fl->coalDeaths()); - totals()->set_splitBirths(totals()->splitBirths() + fl->splitBirths()); - totals()->set_splitDeaths(totals()->splitDeaths() + fl->splitDeaths()); + if (++_print_line >= 40) { + FreeList::print_labels_on(gclog_or_tty, "size"); + _print_line = 0; + } + fl->print_on(gclog_or_tty); + _totalFree += fl->count() * fl->size() ; + total()->set_count( total()->count() + fl->count() ); + total()->set_bfrSurp( total()->bfrSurp() + fl->bfrSurp() ); + total()->set_surplus( total()->splitDeaths() + fl->surplus() ); + total()->set_desired( total()->desired() + fl->desired() ); + total()->set_prevSweep( total()->prevSweep() + fl->prevSweep() ); + total()->set_beforeSweep(total()->beforeSweep() + fl->beforeSweep()); + total()->set_coalBirths( total()->coalBirths() + fl->coalBirths() ); + total()->set_coalDeaths( total()->coalDeaths() + fl->coalDeaths() ); + total()->set_splitBirths(total()->splitBirths() + fl->splitBirths()); + total()->set_splitDeaths(total()->splitDeaths() + fl->splitDeaths()); } }; void BinaryTreeDictionary::printDictCensus(void) const { gclog_or_tty->print("\nBinaryTree\n"); - gclog_or_tty->print( - "%4s\t\t" "%7s\t" "%7s\t" "%7s\t" "%7s\t" "%7s\t" - "%7s\t" "%7s\t" "%7s\t" "%7s\t" "%7s\t" "\n", - "size", "bfrsurp", "surplus", "desired", "prvSwep", "bfrSwep", - "count", "cBirths", "cDeaths", "sBirths", "sDeaths"); - + FreeList::print_labels_on(gclog_or_tty, "size"); printTreeCensusClosure ptc; ptc.do_tree(root()); - gclog_or_tty->print( - "\t\t" "%7s\t" "%7s\t" "%7s\t" "%7s\t" - "%7s\t" "%7s\t" "%7s\t" "%7s\t" "%7s\t" "\n", - "bfrsurp", "surplus", "prvSwep", "bfrSwep", - "count", "cBirths", "cDeaths", "sBirths", "sDeaths"); + FreeList* total = ptc.total(); + FreeList::print_labels_on(gclog_or_tty, " "); + total->print_on(gclog_or_tty, "TOTAL\t"); gclog_or_tty->print( - "%s\t\t" "%7d\t" "%7d\t" "%7d\t" "%7d\t" - "%7d\t" "%7d\t" "%7d\t" "%7d\t" "%7d\t" "\n", - "totl", - ptc.totals()->bfrSurp(), - ptc.totals()->surplus(), - ptc.totals()->prevSweep(), - ptc.totals()->beforeSweep(), - ptc.count(), - ptc.totals()->coalBirths(), - ptc.totals()->coalDeaths(), - ptc.totals()->splitBirths(), - ptc.totals()->splitDeaths()); - gclog_or_tty->print("totalFree(words): %7d growth: %8.5f deficit: %8.5f\n", + "totalFree(words): " SIZE_FORMAT_W(16) + " growth: %8.5f deficit: %8.5f\n", ptc.totalFree(), - (double)(ptc.totals()->splitBirths()+ptc.totals()->coalBirths() - -ptc.totals()->splitDeaths()-ptc.totals()->coalDeaths()) - /(ptc.totals()->prevSweep() != 0 ? - (double)ptc.totals()->prevSweep() : 1.0), - (double)(ptc.totals()->desired() - ptc.count()) - /(ptc.totals()->desired() != 0 ? - (double)ptc.totals()->desired() : 1.0)); + (double)(total->splitBirths() + total->coalBirths() + - total->splitDeaths() - total->coalDeaths()) + /(total->prevSweep() != 0 ? (double)total->prevSweep() : 1.0), + (double)(total->desired() - total->count()) + /(total->desired() != 0 ? (double)total->desired() : 1.0)); } // Verify the following tree invariants: diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp Thu Mar 20 09:17:30 2008 -0500 @@ -1835,7 +1835,7 @@ guarantee(false, "NYI"); } -bool CompactibleFreeListSpace::linearAllocationWouldFail() { +bool CompactibleFreeListSpace::linearAllocationWouldFail() const { return _smallLinearAllocBlock._word_size == 0; } @@ -1906,6 +1906,13 @@ } } +// Support for concurrent collection policy decisions. +bool CompactibleFreeListSpace::should_concurrent_collect() const { + // In the future we might want to add in frgamentation stats -- + // including erosion of the "mountain" into this decision as well. + return !adaptive_freelists() && linearAllocationWouldFail(); +} + // Support for compaction void CompactibleFreeListSpace::prepare_for_compaction(CompactPoint* cp) { @@ -2013,11 +2020,11 @@ } } -void CompactibleFreeListSpace::endSweepFLCensus(int sweepCt) { +void CompactibleFreeListSpace::endSweepFLCensus(size_t sweep_count) { setFLSurplus(); setFLHints(); if (PrintGC && PrintFLSCensus > 0) { - printFLCensus(sweepCt); + printFLCensus(sweep_count); } clearFLCensus(); assert_locked(); @@ -2293,59 +2300,37 @@ } #endif -void CompactibleFreeListSpace::printFLCensus(int sweepCt) const { +void CompactibleFreeListSpace::printFLCensus(size_t sweep_count) const { assert_lock_strong(&_freelistLock); - ssize_t bfrSurp = 0; - ssize_t surplus = 0; - ssize_t desired = 0; - ssize_t prevSweep = 0; - ssize_t beforeSweep = 0; - ssize_t count = 0; - ssize_t coalBirths = 0; - ssize_t coalDeaths = 0; - ssize_t splitBirths = 0; - ssize_t splitDeaths = 0; - gclog_or_tty->print("end sweep# %d\n", sweepCt); - gclog_or_tty->print("%4s\t" "%7s\t" "%7s\t" "%7s\t" "%7s\t" - "%7s\t" "%7s\t" "%7s\t" "%7s\t" "%7s\t" - "%7s\t" "\n", - "size", "bfrsurp", "surplus", "desired", "prvSwep", - "bfrSwep", "count", "cBirths", "cDeaths", "sBirths", - "sDeaths"); - + FreeList total; + gclog_or_tty->print("end sweep# " SIZE_FORMAT "\n", sweep_count); + FreeList::print_labels_on(gclog_or_tty, "size"); size_t totalFree = 0; for (size_t i = IndexSetStart; i < IndexSetSize; i += IndexSetStride) { const FreeList *fl = &_indexedFreeList[i]; - totalFree += fl->count() * fl->size(); - - gclog_or_tty->print("%4d\t" "%7d\t" "%7d\t" "%7d\t" - "%7d\t" "%7d\t" "%7d\t" "%7d\t" - "%7d\t" "%7d\t" "%7d\t" "\n", - fl->size(), fl->bfrSurp(), fl->surplus(), fl->desired(), - fl->prevSweep(), fl->beforeSweep(), fl->count(), fl->coalBirths(), - fl->coalDeaths(), fl->splitBirths(), fl->splitDeaths()); - bfrSurp += fl->bfrSurp(); - surplus += fl->surplus(); - desired += fl->desired(); - prevSweep += fl->prevSweep(); - beforeSweep += fl->beforeSweep(); - count += fl->count(); - coalBirths += fl->coalBirths(); - coalDeaths += fl->coalDeaths(); - splitBirths += fl->splitBirths(); - splitDeaths += fl->splitDeaths(); + totalFree += fl->count() * fl->size(); + if (i % (40*IndexSetStride) == 0) { + FreeList::print_labels_on(gclog_or_tty, "size"); + } + fl->print_on(gclog_or_tty); + total.set_bfrSurp( total.bfrSurp() + fl->bfrSurp() ); + total.set_surplus( total.surplus() + fl->surplus() ); + total.set_desired( total.desired() + fl->desired() ); + total.set_prevSweep( total.prevSweep() + fl->prevSweep() ); + total.set_beforeSweep(total.beforeSweep() + fl->beforeSweep()); + total.set_count( total.count() + fl->count() ); + total.set_coalBirths( total.coalBirths() + fl->coalBirths() ); + total.set_coalDeaths( total.coalDeaths() + fl->coalDeaths() ); + total.set_splitBirths(total.splitBirths() + fl->splitBirths()); + total.set_splitDeaths(total.splitDeaths() + fl->splitDeaths()); } - gclog_or_tty->print("%4s\t" - "%7d\t" "%7d\t" "%7d\t" "%7d\t" "%7d\t" - "%7d\t" "%7d\t" "%7d\t" "%7d\t" "%7d\t" "\n", - "totl", - bfrSurp, surplus, desired, prevSweep, beforeSweep, - count, coalBirths, coalDeaths, splitBirths, splitDeaths); - gclog_or_tty->print_cr("Total free in indexed lists %d words", totalFree); + total.print_on(gclog_or_tty, "TOTAL"); + gclog_or_tty->print_cr("Total free in indexed lists " + SIZE_FORMAT " words", totalFree); gclog_or_tty->print("growth: %8.5f deficit: %8.5f\n", - (double)(splitBirths+coalBirths-splitDeaths-coalDeaths)/ - (prevSweep != 0 ? (double)prevSweep : 1.0), - (double)(desired - count)/(desired != 0 ? (double)desired : 1.0)); + (double)(total.splitBirths()+total.coalBirths()-total.splitDeaths()-total.coalDeaths())/ + (total.prevSweep() != 0 ? (double)total.prevSweep() : 1.0), + (double)(total.desired() - total.count())/(total.desired() != 0 ? (double)total.desired() : 1.0)); _dictionary->printDictCensus(); } diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp Thu Mar 20 09:17:30 2008 -0500 @@ -418,7 +418,7 @@ // chunk exists, return NULL. FreeChunk* find_chunk_at_end(); - bool adaptive_freelists() { return _adaptive_freelists; } + bool adaptive_freelists() const { return _adaptive_freelists; } void set_collector(CMSCollector* collector) { _collector = collector; } @@ -566,7 +566,7 @@ FreeChunk* allocateScratch(size_t size); // returns true if either the small or large linear allocation buffer is empty. - bool linearAllocationWouldFail(); + bool linearAllocationWouldFail() const; // Adjust the chunk for the minimum size. This version is called in // most cases in CompactibleFreeListSpace methods. @@ -585,6 +585,9 @@ void addChunkAndRepairOffsetTable(HeapWord* chunk, size_t size, bool coalesced); + // Support for decisions regarding concurrent collection policy + bool should_concurrent_collect() const; + // Support for compaction void prepare_for_compaction(CompactPoint* cp); void adjust_pointers(); @@ -622,7 +625,7 @@ // coalescing of chunks during the sweep of garbage. // Print the statistics for the free lists. - void printFLCensus(int sweepCt) const; + void printFLCensus(size_t sweep_count) const; // Statistics functions // Initialize census for lists before the sweep. @@ -635,12 +638,11 @@ // Clear the census for each of the free lists. void clearFLCensus(); // Perform functions for the census after the end of the sweep. - void endSweepFLCensus(int sweepCt); + void endSweepFLCensus(size_t sweep_count); // Return true if the count of free chunks is greater // than the desired number of free chunks. bool coalOverPopulated(size_t size); - // Record (for each size): // // split-births = #chunks added due to splits in (prev-sweep-end, diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp Thu Mar 20 09:17:30 2008 -0500 @@ -3121,12 +3121,7 @@ if (GCExpandToAllocateDelayMillis > 0) { os::sleep(Thread::current(), GCExpandToAllocateDelayMillis, false); } - size_t adj_word_sz = CompactibleFreeListSpace::adjustObjectSize(word_size); - if (parallel) { - return cmsSpace()->par_allocate(adj_word_sz); - } else { - return cmsSpace()->allocate(adj_word_sz); - } + return have_lock_and_allocate(word_size, tlab); } // YSR: All of this generation expansion/shrinking stuff is an exact copy of @@ -5732,13 +5727,19 @@ // in the perm_gen_verify_bit_map. In order to do that we traverse // all blocks in perm gen and mark all dead objects. if (verifying() && !cms_should_unload_classes()) { - CMSTokenSyncWithLocks ts(true, _permGen->freelistLock(), - bitMapLock()); assert(perm_gen_verify_bit_map()->sizeInBits() != 0, "Should have already been allocated"); MarkDeadObjectsClosure mdo(this, _permGen->cmsSpace(), markBitMap(), perm_gen_verify_bit_map()); - _permGen->cmsSpace()->blk_iterate(&mdo); + if (asynch) { + CMSTokenSyncWithLocks ts(true, _permGen->freelistLock(), + bitMapLock()); + _permGen->cmsSpace()->blk_iterate(&mdo); + } else { + // In the case of synchronous sweep, we already have + // the requisite locks/tokens. + _permGen->cmsSpace()->blk_iterate(&mdo); + } } if (asynch) { diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/freeList.cpp --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/freeList.cpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/freeList.cpp Thu Mar 20 09:17:30 2008 -0500 @@ -302,3 +302,29 @@ #endif } #endif + +// Print the "label line" for free list stats. +void FreeList::print_labels_on(outputStream* st, const char* c) { + st->print("%16s\t", c); + st->print("%14s\t" "%14s\t" "%14s\t" "%14s\t" "%14s\t" + "%14s\t" "%14s\t" "%14s\t" "%14s\t" "%14s\t" "\n", + "bfrsurp", "surplus", "desired", "prvSwep", "bfrSwep", + "count", "cBirths", "cDeaths", "sBirths", "sDeaths"); +} + +// Print the AllocationStats for the given free list. If the second argument +// to the call is a non-null string, it is printed in the first column; +// otherwise, if the argument is null (the default), then the size of the +// (free list) block is printed in the first column. +void FreeList::print_on(outputStream* st, const char* c) const { + if (c != NULL) { + st->print("%16s", c); + } else { + st->print(SIZE_FORMAT_W(16), size()); + } + st->print("\t" + SSIZE_FORMAT_W(14) "\t" SSIZE_FORMAT_W(14) "\t" SSIZE_FORMAT_W(14) "\t" SSIZE_FORMAT_W(14) "\t" SSIZE_FORMAT_W(14) "\t" + SSIZE_FORMAT_W(14) "\t" SSIZE_FORMAT_W(14) "\t" SSIZE_FORMAT_W(14) "\t" SSIZE_FORMAT_W(14) "\t" SSIZE_FORMAT_W(14) "\n", + bfrSurp(), surplus(), desired(), prevSweep(), beforeSweep(), + count(), coalBirths(), coalDeaths(), splitBirths(), splitDeaths()); +} diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/freeList.hpp --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/freeList.hpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/freeList.hpp Thu Mar 20 09:17:30 2008 -0500 @@ -38,6 +38,7 @@ class FreeList VALUE_OBJ_CLASS_SPEC { friend class CompactibleFreeListSpace; + friend class printTreeCensusClosure; FreeChunk* _head; // List of free chunks FreeChunk* _tail; // Tail of list of free chunks size_t _size; // Size in Heap words of each chunks @@ -63,10 +64,11 @@ protected: void init_statistics(); void set_count(ssize_t v) { _count = v;} - void increment_count() { _count++; } + void increment_count() { _count++; } void decrement_count() { _count--; - assert(_count >= 0, "Count should not be negative"); } + assert(_count >= 0, "Count should not be negative"); + } public: // Constructor @@ -159,6 +161,10 @@ ssize_t desired() const { return _allocation_stats.desired(); } + void set_desired(ssize_t v) { + assert_proper_lock_protection(); + _allocation_stats.set_desired(v); + } void compute_desired(float inter_sweep_current, float inter_sweep_estimate) { assert_proper_lock_protection(); @@ -298,4 +304,8 @@ // Verify that the chunk is in the list. // found. Return NULL if "fc" is not found. bool verifyChunkInFreeLists(FreeChunk* fc) const; + + // Printing support + static void print_labels_on(outputStream* st, const char* c); + void print_on(outputStream* st, const char* c = NULL) const; }; diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/gc_implementation/includeDB_gc_shared --- a/hotspot/src/share/vm/gc_implementation/includeDB_gc_shared Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/gc_implementation/includeDB_gc_shared Thu Mar 20 09:17:30 2008 -0500 @@ -19,15 +19,22 @@ // 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. -// +// // // NOTE: DO NOT CHANGE THIS COPYRIGHT TO NEW STYLE - IT WILL BREAK makeDeps! -gcAdaptivePolicyCounters.hpp adaptiveSizePolicy.hpp -gcAdaptivePolicyCounters.hpp gcPolicyCounters.hpp +allocationStats.cpp allocationStats.hpp +allocationStats.cpp ostream.hpp -gcAdaptivePolicyCounters.cpp resourceArea.hpp +allocationStats.hpp allocation.hpp +allocationStats.hpp gcUtil.hpp +allocationStats.hpp globalDefinitions.hpp + +gcAdaptivePolicyCounters.hpp adaptiveSizePolicy.hpp +gcAdaptivePolicyCounters.hpp gcPolicyCounters.hpp + +gcAdaptivePolicyCounters.cpp resourceArea.hpp gcAdaptivePolicyCounters.cpp gcAdaptivePolicyCounters.hpp gSpaceCounters.cpp generation.hpp @@ -44,7 +51,7 @@ isGCActiveMark.hpp parallelScavengeHeap.hpp -markSweep.inline.hpp psParallelCompact.hpp +markSweep.inline.hpp psParallelCompact.hpp mutableNUMASpace.cpp mutableNUMASpace.hpp mutableNUMASpace.cpp sharedHeap.hpp diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/gc_implementation/parNew/asParNewGeneration.cpp --- a/hotspot/src/share/vm/gc_implementation/parNew/asParNewGeneration.cpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/gc_implementation/parNew/asParNewGeneration.cpp Thu Mar 20 09:17:30 2008 -0500 @@ -74,8 +74,8 @@ #ifdef SHRINKS_AT_END_OF_EDEN size_t delta_in_survivor = 0; ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); - const size_t space_alignment = heap->intra_generation_alignment(); - const size_t gen_alignment = heap->generation_alignment(); + const size_t space_alignment = heap->intra_heap_alignment(); + const size_t gen_alignment = heap->object_heap_alignment(); MutableSpace* space_shrinking = NULL; if (from_space()->end() > to_space()->end()) { diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp --- a/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp Thu Mar 20 09:17:30 2008 -0500 @@ -785,6 +785,9 @@ swap_spaces(); // Make life simpler for CMS || rescan; see 6483690. from()->set_next_compaction_space(to()); gch->set_incremental_collection_will_fail(); + + // Reset the PromotionFailureALot counters. + NOT_PRODUCT(Universe::heap()->reset_promotion_should_fail();) } // set new iteration safe limit for the survivor spaces from()->set_concurrent_iteration_safe_limit(from()->top()); diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/gc_implementation/parallelScavenge/asPSYoungGen.cpp --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/asPSYoungGen.cpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/asPSYoungGen.cpp Thu Mar 20 09:17:30 2008 -0500 @@ -86,7 +86,7 @@ if (eden_space()->is_empty()) { // Respect the minimum size for eden and for the young gen as a whole. ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); - const size_t eden_alignment = heap->intra_generation_alignment(); + const size_t eden_alignment = heap->intra_heap_alignment(); const size_t gen_alignment = heap->young_gen_alignment(); assert(eden_space()->capacity_in_bytes() >= eden_alignment, @@ -124,7 +124,7 @@ // to_space can be. size_t ASPSYoungGen::available_to_live() { ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); - const size_t alignment = heap->intra_generation_alignment(); + const size_t alignment = heap->intra_heap_alignment(); // Include any space that is committed but is not in eden. size_t available = pointer_delta(eden_space()->bottom(), @@ -275,7 +275,7 @@ assert(eden_start < from_start, "Cannot push into from_space"); ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); - const size_t alignment = heap->intra_generation_alignment(); + const size_t alignment = heap->intra_heap_alignment(); // Check whether from space is below to space if (from_start < to_start) { diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/gc_implementation/parallelScavenge/generationSizer.hpp --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/generationSizer.hpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/generationSizer.hpp Thu Mar 20 09:17:30 2008 -0500 @@ -39,10 +39,10 @@ // If the user hasn't explicitly set the number of worker // threads, set the count. - if (ParallelGCThreads == 0) { - assert(UseParallelGC, "Setting ParallelGCThreads without UseParallelGC"); - ParallelGCThreads = os::active_processor_count(); - } + assert(UseSerialGC || + !FLAG_IS_DEFAULT(ParallelGCThreads) || + (ParallelGCThreads > 0), + "ParallelGCThreads should be set before flag initialization"); // The survivor ratio's are calculated "raw", unlike the // default gc, which adds 2 to the ratio value. We need to diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp Thu Mar 20 09:17:30 2008 -0500 @@ -173,7 +173,7 @@ new PSAdaptiveSizePolicy(eden_capacity, initial_promo_size, young_gen()->to_space()->capacity_in_bytes(), - intra_generation_alignment(), + intra_heap_alignment(), max_gc_pause_sec, max_gc_minor_pause_sec, GCTimeRatio diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.hpp --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.hpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.hpp Thu Mar 20 09:17:30 2008 -0500 @@ -58,9 +58,9 @@ public: ParallelScavengeHeap() : CollectedHeap() { - set_alignment(_perm_gen_alignment, intra_generation_alignment()); - set_alignment(_young_gen_alignment, intra_generation_alignment()); - set_alignment(_old_gen_alignment, intra_generation_alignment()); + set_alignment(_perm_gen_alignment, intra_heap_alignment()); + set_alignment(_young_gen_alignment, intra_heap_alignment()); + set_alignment(_old_gen_alignment, intra_heap_alignment()); } // For use by VM operations @@ -92,14 +92,14 @@ void post_initialize(); void update_counters(); - // The alignment used for the various generations. size_t perm_gen_alignment() const { return _perm_gen_alignment; } size_t young_gen_alignment() const { return _young_gen_alignment; } size_t old_gen_alignment() const { return _old_gen_alignment; } - // The alignment used for eden and survivors within the young gen. - size_t intra_generation_alignment() const { return 64 * K; } + // The alignment used for eden and survivors within the young gen + // and for boundary between young gen and old gen. + size_t intra_heap_alignment() const { return 64 * K; } size_t capacity() const; size_t used() const; @@ -217,6 +217,6 @@ inline size_t ParallelScavengeHeap::set_alignment(size_t& var, size_t val) { assert(is_power_of_2((intptr_t)val), "must be a power of 2"); - var = round_to(val, intra_generation_alignment()); + var = round_to(val, intra_heap_alignment()); return var; } diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/gc_implementation/parallelScavenge/psYoungGen.cpp --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psYoungGen.cpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psYoungGen.cpp Thu Mar 20 09:17:30 2008 -0500 @@ -88,7 +88,7 @@ // Compute maximum space sizes for performance counters ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); - size_t alignment = heap->intra_generation_alignment(); + size_t alignment = heap->intra_heap_alignment(); size_t size = _virtual_space->reserved_size(); size_t max_survivor_size; @@ -141,7 +141,7 @@ assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); // Compute sizes - size_t alignment = heap->intra_generation_alignment(); + size_t alignment = heap->intra_heap_alignment(); size_t size = _virtual_space->committed_size(); size_t survivor_size = size / InitialSurvivorRatio; @@ -192,7 +192,7 @@ #ifndef PRODUCT void PSYoungGen::space_invariants() { ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); - const size_t alignment = heap->intra_generation_alignment(); + const size_t alignment = heap->intra_heap_alignment(); // Currently, our eden size cannot shrink to zero guarantee(eden_space()->capacity_in_bytes() >= alignment, "eden too small"); @@ -392,7 +392,7 @@ char* to_end = (char*)to_space()->end(); ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); - const size_t alignment = heap->intra_generation_alignment(); + const size_t alignment = heap->intra_heap_alignment(); const bool maintain_minimum = (requested_eden_size + 2 * requested_survivor_size) <= min_gen_size(); @@ -708,7 +708,7 @@ size_t PSYoungGen::available_to_live() { size_t delta_in_survivor = 0; ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); - const size_t space_alignment = heap->intra_generation_alignment(); + const size_t space_alignment = heap->intra_heap_alignment(); const size_t gen_alignment = heap->young_gen_alignment(); MutableSpace* space_shrinking = NULL; diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/gc_implementation/shared/allocationStats.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/gc_implementation/shared/allocationStats.cpp Thu Mar 20 09:17:30 2008 -0500 @@ -0,0 +1,30 @@ +/* + * Copyright 2005 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. + * + */ + +# include "incls/_precompiled.incl" +# include "incls/_allocationStats.cpp.incl" + +// Technically this should be derived from machine speed, and +// ideally it would be dynamically adjusted. +float AllocationStats::_threshold = ((float)CMS_SweepTimerThresholdMillis)/1000; diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/gc_implementation/shared/allocationStats.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/gc_implementation/shared/allocationStats.hpp Thu Mar 20 09:17:30 2008 -0500 @@ -0,0 +1,138 @@ +/* + * Copyright 2001-2005 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. + * + */ + +class AllocationStats VALUE_OBJ_CLASS_SPEC { + // A duration threshold (in ms) used to filter + // possibly unreliable samples. + static float _threshold; + + // We measure the demand between the end of the previous sweep and + // beginning of this sweep: + // Count(end_last_sweep) - Count(start_this_sweep) + // + splitBirths(between) - splitDeaths(between) + // The above number divided by the time since the start [END???] of the + // previous sweep gives us a time rate of demand for blocks + // of this size. We compute a padded average of this rate as + // our current estimate for the time rate of demand for blocks + // of this size. Similarly, we keep a padded average for the time + // between sweeps. Our current estimate for demand for blocks of + // this size is then simply computed as the product of these two + // estimates. + AdaptivePaddedAverage _demand_rate_estimate; + + ssize_t _desired; // Estimate computed as described above + ssize_t _coalDesired; // desired +/- small-percent for tuning coalescing + + ssize_t _surplus; // count - (desired +/- small-percent), + // used to tune splitting in best fit + ssize_t _bfrSurp; // surplus at start of current sweep + ssize_t _prevSweep; // count from end of previous sweep + ssize_t _beforeSweep; // count from before current sweep + ssize_t _coalBirths; // additional chunks from coalescing + ssize_t _coalDeaths; // loss from coalescing + ssize_t _splitBirths; // additional chunks from splitting + ssize_t _splitDeaths; // loss from splitting + size_t _returnedBytes; // number of bytes returned to list. + public: + void initialize() { + AdaptivePaddedAverage* dummy = + new (&_demand_rate_estimate) AdaptivePaddedAverage(CMS_FLSWeight, + CMS_FLSPadding); + _desired = 0; + _coalDesired = 0; + _surplus = 0; + _bfrSurp = 0; + _prevSweep = 0; + _beforeSweep = 0; + _coalBirths = 0; + _coalDeaths = 0; + _splitBirths = 0; + _splitDeaths = 0; + _returnedBytes = 0; + } + + AllocationStats() { + initialize(); + } + // The rate estimate is in blocks per second. + void compute_desired(size_t count, + float inter_sweep_current, + float inter_sweep_estimate) { + // If the latest inter-sweep time is below our granularity + // of measurement, we may call in here with + // inter_sweep_current == 0. However, even for suitably small + // but non-zero inter-sweep durations, we may not trust the accuracy + // of accumulated data, since it has not been "integrated" + // (read "low-pass-filtered") long enough, and would be + // vulnerable to noisy glitches. In such cases, we + // ignore the current sample and use currently available + // historical estimates. + if (inter_sweep_current > _threshold) { + ssize_t demand = prevSweep() - count + splitBirths() - splitDeaths(); + float rate = ((float)demand)/inter_sweep_current; + _demand_rate_estimate.sample(rate); + _desired = (ssize_t)(_demand_rate_estimate.padded_average() + *inter_sweep_estimate); + } + } + + ssize_t desired() const { return _desired; } + void set_desired(ssize_t v) { _desired = v; } + + ssize_t coalDesired() const { return _coalDesired; } + void set_coalDesired(ssize_t v) { _coalDesired = v; } + + ssize_t surplus() const { return _surplus; } + void set_surplus(ssize_t v) { _surplus = v; } + void increment_surplus() { _surplus++; } + void decrement_surplus() { _surplus--; } + + ssize_t bfrSurp() const { return _bfrSurp; } + void set_bfrSurp(ssize_t v) { _bfrSurp = v; } + ssize_t prevSweep() const { return _prevSweep; } + void set_prevSweep(ssize_t v) { _prevSweep = v; } + ssize_t beforeSweep() const { return _beforeSweep; } + void set_beforeSweep(ssize_t v) { _beforeSweep = v; } + + ssize_t coalBirths() const { return _coalBirths; } + void set_coalBirths(ssize_t v) { _coalBirths = v; } + void increment_coalBirths() { _coalBirths++; } + + ssize_t coalDeaths() const { return _coalDeaths; } + void set_coalDeaths(ssize_t v) { _coalDeaths = v; } + void increment_coalDeaths() { _coalDeaths++; } + + ssize_t splitBirths() const { return _splitBirths; } + void set_splitBirths(ssize_t v) { _splitBirths = v; } + void increment_splitBirths() { _splitBirths++; } + + ssize_t splitDeaths() const { return _splitDeaths; } + void set_splitDeaths(ssize_t v) { _splitDeaths = v; } + void increment_splitDeaths() { _splitDeaths++; } + + NOT_PRODUCT( + size_t returnedBytes() const { return _returnedBytes; } + void set_returnedBytes(size_t v) { _returnedBytes = v; } + ) +}; diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/includeDB_compiler2 --- a/hotspot/src/share/vm/includeDB_compiler2 Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/includeDB_compiler2 Thu Mar 20 09:17:30 2008 -0500 @@ -19,7 +19,7 @@ // 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. -// +// // ad_.cpp adGlobals_.hpp @@ -410,6 +410,7 @@ escape.cpp allocation.hpp escape.cpp bcEscapeAnalyzer.hpp +escape.cpp c2compiler.hpp escape.cpp callnode.hpp escape.cpp cfgnode.hpp escape.cpp compile.hpp @@ -990,6 +991,7 @@ subnode.cpp addnode.hpp subnode.cpp allocation.inline.hpp +subnode.cpp callnode.hpp subnode.cpp cfgnode.hpp subnode.cpp compileLog.hpp subnode.cpp connode.hpp @@ -1086,7 +1088,7 @@ idealGraphPrinter.hpp ostream.hpp idealGraphPrinter.cpp idealGraphPrinter.hpp -idealGraphPrinter.cpp chaitin.hpp +idealGraphPrinter.cpp chaitin.hpp idealGraphPrinter.cpp machnode.hpp idealGraphPrinter.cpp parse.hpp idealGraphPrinter.cpp threadCritical.hpp @@ -1098,4 +1100,4 @@ parse1.cpp idealGraphPrinter.hpp matcher.cpp idealGraphPrinter.hpp loopnode.cpp idealGraphPrinter.hpp -chaitin.cpp idealGraphPrinter.hpp +chaitin.cpp idealGraphPrinter.hpp diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/includeDB_core --- a/hotspot/src/share/vm/includeDB_core Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/includeDB_core Thu Mar 20 09:17:30 2008 -0500 @@ -19,7 +19,7 @@ // 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. -// +// // // NOTE: DO NOT CHANGE THIS COPYRIGHT TO NEW STYLE - IT WILL BREAK makeDeps! @@ -46,13 +46,13 @@ // as dependencies. Header files named H.inline.hpp generally contain // bodies for inline functions declared in H.hpp. // -// NOTE: Files that use the token "generate_platform_dependent_include" +// NOTE: Files that use the token "generate_platform_dependent_include" // are expected to contain macro references like , , ... and // makedeps has a dependency on these platform files looking like: -// foo_.trailing_string +// foo_.trailing_string // (where "trailing_string" can be any legal filename strings but typically // is "hpp" or "inline.hpp"). -// +// // The dependency in makedeps (and enforced) is that an underscore // will precedure the macro invocation. Note that this restriction // is only enforced on filenames that have the dependency token @@ -148,12 +148,6 @@ allocation.inline.hpp os.hpp -allocationStats.cpp allocationStats.hpp - -allocationStats.hpp allocation.hpp -allocationStats.hpp gcUtil.hpp -allocationStats.hpp globalDefinitions.hpp - aprofiler.cpp aprofiler.hpp aprofiler.cpp collectedHeap.inline.hpp aprofiler.cpp oop.inline.hpp @@ -720,6 +714,11 @@ ciObjArray.hpp ciClassList.hpp ciObjArray.hpp objArrayOop.hpp +ciObjArray.cpp ciObjArray.hpp +ciObjArray.cpp ciNullObject.hpp +ciObjArray.cpp ciUtilities.hpp +ciObjArray.cpp objArrayOop.hpp + ciObjArrayKlass.cpp ciInstanceKlass.hpp ciObjArrayKlass.cpp ciObjArrayKlass.hpp ciObjArrayKlass.cpp ciObjArrayKlassKlass.hpp @@ -1935,7 +1934,7 @@ init.cpp bytecodes.hpp init.cpp collectedHeap.hpp -init.cpp handles.inline.hpp +init.cpp handles.inline.hpp init.cpp icBuffer.hpp init.cpp icache.hpp init.cpp init.hpp @@ -3068,6 +3067,7 @@ oopMapCache.cpp allocation.inline.hpp oopMapCache.cpp handles.inline.hpp +oopMapCache.cpp jvmtiRedefineClassesTrace.hpp oopMapCache.cpp oop.inline.hpp oopMapCache.cpp oopMapCache.hpp oopMapCache.cpp resourceArea.hpp diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/interpreter/oopMapCache.cpp --- a/hotspot/src/share/vm/interpreter/oopMapCache.cpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/interpreter/oopMapCache.cpp Thu Mar 20 09:17:30 2008 -0500 @@ -532,6 +532,10 @@ if (!_array[i].is_empty() && _array[i].method()->is_old()) { // Cache entry is occupied by an old redefined method and we don't want // to pin it down so flush the entry. + RC_TRACE(0x08000000, ("flush: %s(%s): cached entry @%d", + _array[i].method()->name()->as_C_string(), + _array[i].method()->signature()->as_C_string(), i)); + _array[i].flush(); } } @@ -577,6 +581,15 @@ // Entry is not in hashtable. // Compute entry and return it + if (method->should_not_be_cached()) { + // It is either not safe or not a good idea to cache this methodOop + // at this time. We give the caller of lookup() a copy of the + // interesting info via parameter entry_for, but we don't add it to + // the cache. See the gory details in methodOop.cpp. + compute_one_oop_map(method, bci, entry_for); + return; + } + // First search for an empty slot for(i = 0; i < _probe_depth; i++) { entry = entry_at(probe + i); @@ -584,12 +597,6 @@ entry->fill(method, bci); entry_for->resource_copy(entry); assert(!entry_for->is_empty(), "A non-empty oop map should be returned"); - if (method->is_old()) { - // The caller of lookup() will receive a copy of the interesting - // info via entry_for, but we don't keep an old redefined method in - // the cache to avoid pinning down the method. - entry->flush(); - } return; } } @@ -623,13 +630,6 @@ } assert(!entry_for->is_empty(), "A non-empty oop map should be returned"); - if (method->is_old()) { - // The caller of lookup() will receive a copy of the interesting - // info via entry_for, but we don't keep an old redefined method in - // the cache to avoid pinning down the method. - entry->flush(); - } - return; } diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/memory/allocationStats.cpp --- a/hotspot/src/share/vm/memory/allocationStats.cpp Wed Mar 19 09:58:01 2008 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,30 +0,0 @@ -/* - * Copyright 2005 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. - * - */ - -# include "incls/_precompiled.incl" -# include "incls/_allocationStats.cpp.incl" - -// Technically this should be derived from machine speed, and -// ideally it would be dynamically adjusted. -float AllocationStats::_threshold = ((float)CMS_SweepTimerThresholdMillis)/1000; diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/memory/allocationStats.hpp --- a/hotspot/src/share/vm/memory/allocationStats.hpp Wed Mar 19 09:58:01 2008 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,136 +0,0 @@ -/* - * Copyright 2001-2005 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. - * - */ - -class AllocationStats VALUE_OBJ_CLASS_SPEC { - // A duration threshold (in ms) used to filter - // possibly unreliable samples. - static float _threshold; - - // We measure the demand between the end of the previous sweep and - // beginning of this sweep: - // Count(end_last_sweep) - Count(start_this_sweep) - // + splitBirths(between) - splitDeaths(between) - // The above number divided by the time since the start [END???] of the - // previous sweep gives us a time rate of demand for blocks - // of this size. We compute a padded average of this rate as - // our current estimate for the time rate of demand for blocks - // of this size. Similarly, we keep a padded average for the time - // between sweeps. Our current estimate for demand for blocks of - // this size is then simply computed as the product of these two - // estimates. - AdaptivePaddedAverage _demand_rate_estimate; - - ssize_t _desired; // Estimate computed as described above - ssize_t _coalDesired; // desired +/- small-percent for tuning coalescing - - ssize_t _surplus; // count - (desired +/- small-percent), - // used to tune splitting in best fit - ssize_t _bfrSurp; // surplus at start of current sweep - ssize_t _prevSweep; // count from end of previous sweep - ssize_t _beforeSweep; // count from before current sweep - ssize_t _coalBirths; // additional chunks from coalescing - ssize_t _coalDeaths; // loss from coalescing - ssize_t _splitBirths; // additional chunks from splitting - ssize_t _splitDeaths; // loss from splitting - size_t _returnedBytes; // number of bytes returned to list. - public: - void initialize() { - AdaptivePaddedAverage* dummy = - new (&_demand_rate_estimate) AdaptivePaddedAverage(CMS_FLSWeight, - CMS_FLSPadding); - _desired = 0; - _coalDesired = 0; - _surplus = 0; - _bfrSurp = 0; - _prevSweep = 0; - _beforeSweep = 0; - _coalBirths = 0; - _coalDeaths = 0; - _splitBirths = 0; - _splitDeaths = 0; - _returnedBytes = 0; - } - - AllocationStats() { - initialize(); - } - // The rate estimate is in blocks per second. - void compute_desired(size_t count, - float inter_sweep_current, - float inter_sweep_estimate) { - // If the latest inter-sweep time is below our granularity - // of measurement, we may call in here with - // inter_sweep_current == 0. However, even for suitably small - // but non-zero inter-sweep durations, we may not trust the accuracy - // of accumulated data, since it has not been "integrated" - // (read "low-pass-filtered") long enough, and would be - // vulnerable to noisy glitches. In such cases, we - // ignore the current sample and use currently available - // historical estimates. - if (inter_sweep_current > _threshold) { - ssize_t demand = prevSweep() - count + splitBirths() - splitDeaths(); - float rate = ((float)demand)/inter_sweep_current; - _demand_rate_estimate.sample(rate); - _desired = (ssize_t)(_demand_rate_estimate.padded_average() - *inter_sweep_estimate); - } - } - - ssize_t desired() const { return _desired; } - ssize_t coalDesired() const { return _coalDesired; } - void set_coalDesired(ssize_t v) { _coalDesired = v; } - - ssize_t surplus() const { return _surplus; } - void set_surplus(ssize_t v) { _surplus = v; } - void increment_surplus() { _surplus++; } - void decrement_surplus() { _surplus--; } - - ssize_t bfrSurp() const { return _bfrSurp; } - void set_bfrSurp(ssize_t v) { _bfrSurp = v; } - ssize_t prevSweep() const { return _prevSweep; } - void set_prevSweep(ssize_t v) { _prevSweep = v; } - ssize_t beforeSweep() const { return _beforeSweep; } - void set_beforeSweep(ssize_t v) { _beforeSweep = v; } - - ssize_t coalBirths() const { return _coalBirths; } - void set_coalBirths(ssize_t v) { _coalBirths = v; } - void increment_coalBirths() { _coalBirths++; } - - ssize_t coalDeaths() const { return _coalDeaths; } - void set_coalDeaths(ssize_t v) { _coalDeaths = v; } - void increment_coalDeaths() { _coalDeaths++; } - - ssize_t splitBirths() const { return _splitBirths; } - void set_splitBirths(ssize_t v) { _splitBirths = v; } - void increment_splitBirths() { _splitBirths++; } - - ssize_t splitDeaths() const { return _splitDeaths; } - void set_splitDeaths(ssize_t v) { _splitDeaths = v; } - void increment_splitDeaths() { _splitDeaths++; } - - NOT_PRODUCT( - size_t returnedBytes() const { return _returnedBytes; } - void set_returnedBytes(size_t v) { _returnedBytes = v; } - ) -}; diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/memory/cardTableModRefBS.cpp --- a/hotspot/src/share/vm/memory/cardTableModRefBS.cpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/memory/cardTableModRefBS.cpp Thu Mar 20 09:17:30 2008 -0500 @@ -51,7 +51,7 @@ _whole_heap(whole_heap), _guard_index(cards_required(whole_heap.word_size()) - 1), _last_valid_index(_guard_index - 1), - _page_size(os::page_size_for_region(_guard_index + 1, _guard_index + 1, 1)), + _page_size(os::vm_page_size()), _byte_map_size(compute_byte_map_size()) { _kind = BarrierSet::CardTableModRef; @@ -196,8 +196,8 @@ assert(_whole_heap.contains(new_region), "attempt to cover area not in reserved area"); debug_only(verify_guard();) - int ind = find_covering_region_by_base(new_region.start()); - MemRegion old_region = _covered[ind]; + int const ind = find_covering_region_by_base(new_region.start()); + MemRegion const old_region = _covered[ind]; assert(old_region.start() == new_region.start(), "just checking"); if (new_region.word_size() != old_region.word_size()) { // Commit new or uncommit old pages, if necessary. @@ -205,21 +205,21 @@ // Extend the end of this _commited region // to cover the end of any lower _committed regions. // This forms overlapping regions, but never interior regions. - HeapWord* max_prev_end = largest_prev_committed_end(ind); + HeapWord* const max_prev_end = largest_prev_committed_end(ind); if (max_prev_end > cur_committed.end()) { cur_committed.set_end(max_prev_end); } // Align the end up to a page size (starts are already aligned). - jbyte* new_end = byte_after(new_region.last()); - HeapWord* new_end_aligned = - (HeapWord*)align_size_up((uintptr_t)new_end, _page_size); + jbyte* const new_end = byte_after(new_region.last()); + HeapWord* const new_end_aligned = + (HeapWord*) align_size_up((uintptr_t)new_end, _page_size); assert(new_end_aligned >= (HeapWord*) new_end, "align up, but less"); // The guard page is always committed and should not be committed over. - HeapWord* new_end_for_commit = MIN2(new_end_aligned, _guard_region.start()); + HeapWord* const new_end_for_commit = MIN2(new_end_aligned, _guard_region.start()); if (new_end_for_commit > cur_committed.end()) { // Must commit new pages. - MemRegion new_committed = + MemRegion const new_committed = MemRegion(cur_committed.end(), new_end_for_commit); assert(!new_committed.is_empty(), "Region should not be empty here"); @@ -233,7 +233,7 @@ // the cur_committed region may include the guard region. } else if (new_end_aligned < cur_committed.end()) { // Must uncommit pages. - MemRegion uncommit_region = + MemRegion const uncommit_region = committed_unique_to_self(ind, MemRegion(new_end_aligned, cur_committed.end())); if (!uncommit_region.is_empty()) { @@ -257,7 +257,7 @@ } assert(index_for(new_region.last()) < (int) _guard_index, "The guard card will be overwritten"); - jbyte* end = byte_after(new_region.last()); + jbyte* const end = byte_after(new_region.last()); // do nothing if we resized downward. if (entry < end) { memset(entry, clean_card, pointer_delta(end, entry, sizeof(jbyte))); diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/memory/cardTableRS.cpp --- a/hotspot/src/share/vm/memory/cardTableRS.cpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/memory/cardTableRS.cpp Thu Mar 20 09:17:30 2008 -0500 @@ -556,10 +556,16 @@ } -void CardTableRS::verify_empty(MemRegion mr) { +void CardTableRS::verify_aligned_region_empty(MemRegion mr) { if (!mr.is_empty()) { jbyte* cur_entry = byte_for(mr.start()); jbyte* limit = byte_after(mr.last()); + // The region mr may not start on a card boundary so + // the first card may reflect a write to the space + // just prior to mr. + if (!is_aligned(mr.start())) { + cur_entry++; + } for (;cur_entry < limit; cur_entry++) { guarantee(*cur_entry == CardTableModRefBS::clean_card, "Unexpected dirty card found"); diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/memory/cardTableRS.hpp --- a/hotspot/src/share/vm/memory/cardTableRS.hpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/memory/cardTableRS.hpp Thu Mar 20 09:17:30 2008 -0500 @@ -126,7 +126,7 @@ } void verify(); - void verify_empty(MemRegion mr); + void verify_aligned_region_empty(MemRegion mr); void clear(MemRegion mr) { _ct_bs.clear(mr); } void clear_into_younger(Generation* gen, bool clear_perm); diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/memory/collectorPolicy.cpp --- a/hotspot/src/share/vm/memory/collectorPolicy.cpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/memory/collectorPolicy.cpp Thu Mar 20 09:17:30 2008 -0500 @@ -57,45 +57,51 @@ // User inputs from -mx and ms are aligned _initial_heap_byte_size = align_size_up(Arguments::initial_heap_size(), min_alignment()); - _min_heap_byte_size = align_size_up(Arguments::min_heap_size(), - min_alignment()); - _max_heap_byte_size = align_size_up(MaxHeapSize, max_alignment()); + set_min_heap_byte_size(align_size_up(Arguments::min_heap_size(), + min_alignment())); + set_max_heap_byte_size(align_size_up(MaxHeapSize, max_alignment())); // Check validity of heap parameters from launcher - if (_initial_heap_byte_size == 0) { - _initial_heap_byte_size = NewSize + OldSize; + if (initial_heap_byte_size() == 0) { + set_initial_heap_byte_size(NewSize + OldSize); } else { - Universe::check_alignment(_initial_heap_byte_size, min_alignment(), + Universe::check_alignment(initial_heap_byte_size(), min_alignment(), "initial heap"); } - if (_min_heap_byte_size == 0) { - _min_heap_byte_size = NewSize + OldSize; + if (min_heap_byte_size() == 0) { + set_min_heap_byte_size(NewSize + OldSize); } else { - Universe::check_alignment(_min_heap_byte_size, min_alignment(), + Universe::check_alignment(min_heap_byte_size(), min_alignment(), "initial heap"); } // Check heap parameter properties - if (_initial_heap_byte_size < M) { + if (initial_heap_byte_size() < M) { vm_exit_during_initialization("Too small initial heap"); } // Check heap parameter properties - if (_min_heap_byte_size < M) { + if (min_heap_byte_size() < M) { vm_exit_during_initialization("Too small minimum heap"); } - if (_initial_heap_byte_size <= NewSize) { + if (initial_heap_byte_size() <= NewSize) { // make sure there is at least some room in old space vm_exit_during_initialization("Too small initial heap for new size specified"); } - if (_max_heap_byte_size < _min_heap_byte_size) { + if (max_heap_byte_size() < min_heap_byte_size()) { vm_exit_during_initialization("Incompatible minimum and maximum heap sizes specified"); } - if (_initial_heap_byte_size < _min_heap_byte_size) { + if (initial_heap_byte_size() < min_heap_byte_size()) { vm_exit_during_initialization("Incompatible minimum and initial heap sizes specified"); } - if (_max_heap_byte_size < _initial_heap_byte_size) { + if (max_heap_byte_size() < initial_heap_byte_size()) { vm_exit_during_initialization("Incompatible initial and maximum heap sizes specified"); } + + if (PrintGCDetails && Verbose) { + gclog_or_tty->print_cr("Minimum heap " SIZE_FORMAT " Initial heap " + SIZE_FORMAT " Maximum heap " SIZE_FORMAT, + min_heap_byte_size(), initial_heap_byte_size(), max_heap_byte_size()); + } } void CollectorPolicy::initialize_perm_generation(PermGen::Name pgnm) { @@ -128,10 +134,26 @@ // GenCollectorPolicy methods. +size_t GenCollectorPolicy::scale_by_NewRatio_aligned(size_t base_size) { + size_t x = base_size / (NewRatio+1); + size_t new_gen_size = x > min_alignment() ? + align_size_down(x, min_alignment()) : + min_alignment(); + return new_gen_size; +} + +size_t GenCollectorPolicy::bound_minus_alignment(size_t desired_size, + size_t maximum_size) { + size_t alignment = min_alignment(); + size_t max_minus = maximum_size - alignment; + return desired_size < max_minus ? desired_size : max_minus; +} + + void GenCollectorPolicy::initialize_size_policy(size_t init_eden_size, size_t init_promo_size, size_t init_survivor_size) { - double max_gc_minor_pause_sec = ((double) MaxGCMinorPauseMillis)/1000.0; + const double max_gc_minor_pause_sec = ((double) MaxGCMinorPauseMillis)/1000.0; _size_policy = new AdaptiveSizePolicy(init_eden_size, init_promo_size, init_survivor_size, @@ -210,74 +232,260 @@ assert(MaxHeapSize % max_alignment() == 0, "maximum heap alignment"); } +// Values set on the command line win over any ergonomically +// set command line parameters. +// Ergonomic choice of parameters are done before this +// method is called. Values for command line parameters such as NewSize +// and MaxNewSize feed those ergonomic choices into this method. +// This method makes the final generation sizings consistent with +// themselves and with overall heap sizings. +// In the absence of explicitly set command line flags, policies +// such as the use of NewRatio are used to size the generation. void GenCollectorPolicy::initialize_size_info() { CollectorPolicy::initialize_size_info(); - // Minimum sizes of the generations may be different than - // the initial sizes. - if (!FLAG_IS_DEFAULT(NewSize)) { - _min_gen0_size = NewSize; + // min_alignment() is used for alignment within a generation. + // There is additional alignment done down stream for some + // collectors that sometimes causes unwanted rounding up of + // generations sizes. + + // Determine maximum size of gen0 + + size_t max_new_size = 0; + if (FLAG_IS_CMDLINE(MaxNewSize)) { + if (MaxNewSize < min_alignment()) { + max_new_size = min_alignment(); + } else if (MaxNewSize >= max_heap_byte_size()) { + max_new_size = align_size_down(max_heap_byte_size() - min_alignment(), + min_alignment()); + warning("MaxNewSize (" SIZE_FORMAT "k) is equal to or " + "greater than the entire heap (" SIZE_FORMAT "k). A " + "new generation size of " SIZE_FORMAT "k will be used.", + MaxNewSize/K, max_heap_byte_size()/K, max_new_size/K); + } else { + max_new_size = align_size_down(MaxNewSize, min_alignment()); + } + + // The case for FLAG_IS_ERGO(MaxNewSize) could be treated + // specially at this point to just use an ergonomically set + // MaxNewSize to set max_new_size. For cases with small + // heaps such a policy often did not work because the MaxNewSize + // was larger than the entire heap. The interpretation given + // to ergonomically set flags is that the flags are set + // by different collectors for their own special needs but + // are not allowed to badly shape the heap. This allows the + // different collectors to decide what's best for themselves + // without having to factor in the overall heap shape. It + // can be the case in the future that the collectors would + // only make "wise" ergonomics choices and this policy could + // just accept those choices. The choices currently made are + // not always "wise". } else { - _min_gen0_size = align_size_down(_min_heap_byte_size / (NewRatio+1), - min_alignment()); - // We bound the minimum size by NewSize below (since it historically + max_new_size = scale_by_NewRatio_aligned(max_heap_byte_size()); + // Bound the maximum size by NewSize below (since it historically // would have been NewSize and because the NewRatio calculation could // yield a size that is too small) and bound it by MaxNewSize above. - // This is not always best. The NewSize calculated by CMS (which has - // a fixed minimum of 16m) can sometimes be "too" large. Consider - // the case where -Xmx32m. The CMS calculated NewSize would be about - // half the entire heap which seems too large. But the counter - // example is seen when the client defaults for NewRatio are used. - // An initial young generation size of 640k was observed - // with -Xmx128m -XX:MaxNewSize=32m when NewSize was not used - // as a lower bound as with - // _min_gen0_size = MIN2(_min_gen0_size, MaxNewSize); - // and 640k seemed too small a young generation. - _min_gen0_size = MIN2(MAX2(_min_gen0_size, NewSize), MaxNewSize); + // Ergonomics plays here by previously calculating the desired + // NewSize and MaxNewSize. + max_new_size = MIN2(MAX2(max_new_size, NewSize), MaxNewSize); + } + assert(max_new_size > 0, "All paths should set max_new_size"); + + // Given the maximum gen0 size, determine the initial and + // minimum sizes. + + if (max_heap_byte_size() == min_heap_byte_size()) { + // The maximum and minimum heap sizes are the same so + // the generations minimum and initial must be the + // same as its maximum. + set_min_gen0_size(max_new_size); + set_initial_gen0_size(max_new_size); + set_max_gen0_size(max_new_size); + } else { + size_t desired_new_size = 0; + if (!FLAG_IS_DEFAULT(NewSize)) { + // If NewSize is set ergonomically (for example by cms), it + // would make sense to use it. If it is used, also use it + // to set the initial size. Although there is no reason + // the minimum size and the initial size have to be the same, + // the current implementation gets into trouble during the calculation + // of the tenured generation sizes if they are different. + // Note that this makes the initial size and the minimum size + // generally small compared to the NewRatio calculation. + _min_gen0_size = NewSize; + desired_new_size = NewSize; + max_new_size = MAX2(max_new_size, NewSize); + } else { + // For the case where NewSize is the default, use NewRatio + // to size the minimum and initial generation sizes. + // Use the default NewSize as the floor for these values. If + // NewRatio is overly large, the resulting sizes can be too + // small. + _min_gen0_size = MAX2(scale_by_NewRatio_aligned(min_heap_byte_size()), + NewSize); + desired_new_size = + MAX2(scale_by_NewRatio_aligned(initial_heap_byte_size()), + NewSize); + } + + assert(_min_gen0_size > 0, "Sanity check"); + set_initial_gen0_size(desired_new_size); + set_max_gen0_size(max_new_size); + + // At this point the desirable initial and minimum sizes have been + // determined without regard to the maximum sizes. + + // Bound the sizes by the corresponding overall heap sizes. + set_min_gen0_size( + bound_minus_alignment(_min_gen0_size, min_heap_byte_size())); + set_initial_gen0_size( + bound_minus_alignment(_initial_gen0_size, initial_heap_byte_size())); + set_max_gen0_size( + bound_minus_alignment(_max_gen0_size, max_heap_byte_size())); + + // At this point all three sizes have been checked against the + // maximum sizes but have not been checked for consistency + // amoung the three. + + // Final check min <= initial <= max + set_min_gen0_size(MIN2(_min_gen0_size, _max_gen0_size)); + set_initial_gen0_size( + MAX2(MIN2(_initial_gen0_size, _max_gen0_size), _min_gen0_size)); + set_min_gen0_size(MIN2(_min_gen0_size, _initial_gen0_size)); } - // Parameters are valid, compute area sizes. - size_t max_new_size = align_size_down(_max_heap_byte_size / (NewRatio+1), - min_alignment()); - max_new_size = MIN2(MAX2(max_new_size, _min_gen0_size), MaxNewSize); + if (PrintGCDetails && Verbose) { + gclog_or_tty->print_cr("Minimum gen0 " SIZE_FORMAT " Initial gen0 " + SIZE_FORMAT " Maximum gen0 " SIZE_FORMAT, + min_gen0_size(), initial_gen0_size(), max_gen0_size()); + } +} - // desired_new_size is used to set the initial size. The - // initial size must be greater than the minimum size. - size_t desired_new_size = - align_size_down(_initial_heap_byte_size / (NewRatio+1), - min_alignment()); +// Call this method during the sizing of the gen1 to make +// adjustments to gen0 because of gen1 sizing policy. gen0 initially has +// the most freedom in sizing because it is done before the +// policy for gen1 is applied. Once gen1 policies have been applied, +// there may be conflicts in the shape of the heap and this method +// is used to make the needed adjustments. The application of the +// policies could be more sophisticated (iterative for example) but +// keeping it simple also seems a worthwhile goal. +bool TwoGenerationCollectorPolicy::adjust_gen0_sizes(size_t* gen0_size_ptr, + size_t* gen1_size_ptr, + size_t heap_size, + size_t min_gen0_size) { + bool result = false; + if ((*gen1_size_ptr + *gen0_size_ptr) > heap_size) { + if (((*gen0_size_ptr + OldSize) > heap_size) && + (heap_size - min_gen0_size) >= min_alignment()) { + // Adjust gen0 down to accomodate OldSize + *gen0_size_ptr = heap_size - min_gen0_size; + *gen0_size_ptr = + MAX2((uintx)align_size_down(*gen0_size_ptr, min_alignment()), + min_alignment()); + assert(*gen0_size_ptr > 0, "Min gen0 is too large"); + result = true; + } else { + *gen1_size_ptr = heap_size - *gen0_size_ptr; + *gen1_size_ptr = + MAX2((uintx)align_size_down(*gen1_size_ptr, min_alignment()), + min_alignment()); + } + } + return result; +} - size_t new_size = MIN2(MAX2(desired_new_size, _min_gen0_size), max_new_size); - - _initial_gen0_size = new_size; - _max_gen0_size = max_new_size; -} +// Minimum sizes of the generations may be different than +// the initial sizes. An inconsistently is permitted here +// in the total size that can be specified explicitly by +// command line specification of OldSize and NewSize and +// also a command line specification of -Xms. Issue a warning +// but allow the values to pass. void TwoGenerationCollectorPolicy::initialize_size_info() { GenCollectorPolicy::initialize_size_info(); - // Minimum sizes of the generations may be different than - // the initial sizes. An inconsistently is permitted here - // in the total size that can be specified explicitly by - // command line specification of OldSize and NewSize and - // also a command line specification of -Xms. Issue a warning - // but allow the values to pass. - if (!FLAG_IS_DEFAULT(OldSize)) { - _min_gen1_size = OldSize; + // At this point the minimum, initial and maximum sizes + // of the overall heap and of gen0 have been determined. + // The maximum gen1 size can be determined from the maximum gen0 + // and maximum heap size since not explicit flags exits + // for setting the gen1 maximum. + _max_gen1_size = max_heap_byte_size() - _max_gen0_size; + _max_gen1_size = + MAX2((uintx)align_size_down(_max_gen1_size, min_alignment()), + min_alignment()); + // If no explicit command line flag has been set for the + // gen1 size, use what is left for gen1. + if (FLAG_IS_DEFAULT(OldSize) || FLAG_IS_ERGO(OldSize)) { + // The user has not specified any value or ergonomics + // has chosen a value (which may or may not be consistent + // with the overall heap size). In either case make + // the minimum, maximum and initial sizes consistent + // with the gen0 sizes and the overall heap sizes. + assert(min_heap_byte_size() > _min_gen0_size, + "gen0 has an unexpected minimum size"); + set_min_gen1_size(min_heap_byte_size() - min_gen0_size()); + set_min_gen1_size( + MAX2((uintx)align_size_down(_min_gen1_size, min_alignment()), + min_alignment())); + set_initial_gen1_size(initial_heap_byte_size() - initial_gen0_size()); + set_initial_gen1_size( + MAX2((uintx)align_size_down(_initial_gen1_size, min_alignment()), + min_alignment())); + + } else { + // It's been explicitly set on the command line. Use the + // OldSize and then determine the consequences. + set_min_gen1_size(OldSize); + set_initial_gen1_size(OldSize); + + // If the user has explicitly set an OldSize that is inconsistent + // with other command line flags, issue a warning. // The generation minimums and the overall heap mimimum should // be within one heap alignment. - if ((_min_gen1_size + _min_gen0_size + max_alignment()) < - _min_heap_byte_size) { + if ((_min_gen1_size + _min_gen0_size + min_alignment()) < + min_heap_byte_size()) { warning("Inconsistency between minimum heap size and minimum " - "generation sizes: using min heap = " SIZE_FORMAT, - _min_heap_byte_size); + "generation sizes: using minimum heap = " SIZE_FORMAT, + min_heap_byte_size()); + } + if ((OldSize > _max_gen1_size)) { + warning("Inconsistency between maximum heap size and maximum " + "generation sizes: using maximum heap = " SIZE_FORMAT + " -XX:OldSize flag is being ignored", + max_heap_byte_size()); + } + // If there is an inconsistency between the OldSize and the minimum and/or + // initial size of gen0, since OldSize was explicitly set, OldSize wins. + if (adjust_gen0_sizes(&_min_gen0_size, &_min_gen1_size, + min_heap_byte_size(), OldSize)) { + if (PrintGCDetails && Verbose) { + gclog_or_tty->print_cr("Minimum gen0 " SIZE_FORMAT " Initial gen0 " + SIZE_FORMAT " Maximum gen0 " SIZE_FORMAT, + min_gen0_size(), initial_gen0_size(), max_gen0_size()); + } } - } else { - _min_gen1_size = _min_heap_byte_size - _min_gen0_size; + // Initial size + if (adjust_gen0_sizes(&_initial_gen0_size, &_initial_gen1_size, + initial_heap_byte_size(), OldSize)) { + if (PrintGCDetails && Verbose) { + gclog_or_tty->print_cr("Minimum gen0 " SIZE_FORMAT " Initial gen0 " + SIZE_FORMAT " Maximum gen0 " SIZE_FORMAT, + min_gen0_size(), initial_gen0_size(), max_gen0_size()); + } + } } + // Enforce the maximum gen1 size. + set_min_gen1_size(MIN2(_min_gen1_size, _max_gen1_size)); - _initial_gen1_size = _initial_heap_byte_size - _initial_gen0_size; - _max_gen1_size = _max_heap_byte_size - _max_gen0_size; + // Check that min gen1 <= initial gen1 <= max gen1 + set_initial_gen1_size(MAX2(_initial_gen1_size, _min_gen1_size)); + set_initial_gen1_size(MIN2(_initial_gen1_size, _max_gen1_size)); + + if (PrintGCDetails && Verbose) { + gclog_or_tty->print_cr("Minimum gen1 " SIZE_FORMAT " Initial gen1 " + SIZE_FORMAT " Maximum gen1 " SIZE_FORMAT, + min_gen1_size(), initial_gen1_size(), max_gen1_size()); + } } HeapWord* GenCollectorPolicy::mem_allocate_work(size_t size, diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/memory/collectorPolicy.hpp --- a/hotspot/src/share/vm/memory/collectorPolicy.hpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/memory/collectorPolicy.hpp Thu Mar 20 09:17:30 2008 -0500 @@ -82,8 +82,11 @@ size_t max_alignment() { return _max_alignment; } size_t initial_heap_byte_size() { return _initial_heap_byte_size; } + void set_initial_heap_byte_size(size_t v) { _initial_heap_byte_size = v; } size_t max_heap_byte_size() { return _max_heap_byte_size; } + void set_max_heap_byte_size(size_t v) { _max_heap_byte_size = v; } size_t min_heap_byte_size() { return _min_heap_byte_size; } + void set_min_heap_byte_size(size_t v) { _min_heap_byte_size = v; } enum Name { CollectorPolicyKind, @@ -182,8 +185,24 @@ // compute max heap alignment size_t compute_max_alignment(); + // Scale the base_size by NewRation according to + // result = base_size / (NewRatio + 1) + // and align by min_alignment() + size_t scale_by_NewRatio_aligned(size_t base_size); + + // Bound the value by the given maximum minus the + // min_alignment. + size_t bound_minus_alignment(size_t desired_size, size_t maximum_size); public: + // Accessors + size_t min_gen0_size() { return _min_gen0_size; } + void set_min_gen0_size(size_t v) { _min_gen0_size = v; } + size_t initial_gen0_size() { return _initial_gen0_size; } + void set_initial_gen0_size(size_t v) { _initial_gen0_size = v; } + size_t max_gen0_size() { return _max_gen0_size; } + void set_max_gen0_size(size_t v) { _max_gen0_size = v; } + virtual int number_of_generations() = 0; virtual GenerationSpec **generations() { @@ -236,6 +255,14 @@ void initialize_generations() { ShouldNotReachHere(); } public: + // Accessors + size_t min_gen1_size() { return _min_gen1_size; } + void set_min_gen1_size(size_t v) { _min_gen1_size = v; } + size_t initial_gen1_size() { return _initial_gen1_size; } + void set_initial_gen1_size(size_t v) { _initial_gen1_size = v; } + size_t max_gen1_size() { return _max_gen1_size; } + void set_max_gen1_size(size_t v) { _max_gen1_size = v; } + // Inherited methods TwoGenerationCollectorPolicy* as_two_generation_policy() { return this; } @@ -246,6 +273,10 @@ virtual CollectorPolicy::Name kind() { return CollectorPolicy::TwoGenerationCollectorPolicyKind; } + + // Returns true is gen0 sizes were adjusted + bool adjust_gen0_sizes(size_t* gen0_size_ptr, size_t* gen1_size_ptr, + size_t heap_size, size_t min_gen1_size); }; class MarkSweepPolicy : public TwoGenerationCollectorPolicy { diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/memory/compactingPermGenGen.cpp --- a/hotspot/src/share/vm/memory/compactingPermGenGen.cpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/memory/compactingPermGenGen.cpp Thu Mar 20 09:17:30 2008 -0500 @@ -26,9 +26,27 @@ #include "incls/_compactingPermGenGen.cpp.incl" -// Recursively adjust all pointers in an object and all objects by -// referenced it. Clear marks on objects in order to prevent visiting -// any object twice. +// An ObjectClosure helper: Recursively adjust all pointers in an object +// and all objects by referenced it. Clear marks on objects in order to +// prevent visiting any object twice. This helper is used when the +// RedefineClasses() API has been called. + +class AdjustSharedObjectClosure : public ObjectClosure { +public: + void do_object(oop obj) { + if (obj->is_shared_readwrite()) { + if (obj->mark()->is_marked()) { + obj->init_mark(); // Don't revisit this object. + obj->adjust_pointers(); // Adjust this object's references. + } + } + } +}; + + +// An OopClosure helper: Recursively adjust all pointers in an object +// and all objects by referenced it. Clear marks on objects in order +// to prevent visiting any object twice. class RecursiveAdjustSharedObjectClosure : public OopClosure { public: @@ -274,15 +292,34 @@ // objects in the space will page in more objects than we need. // Instead, use the system dictionary as strong roots into the read // write space. +// +// If a RedefineClasses() call has been made, then we have to iterate +// over the entire shared read-write space in order to find all the +// objects that need to be forwarded. For example, it is possible for +// an nmethod to be found and marked in GC phase-1 only for the nmethod +// to be freed by the time we reach GC phase-3. The underlying method +// is still marked, but we can't (easily) find it in GC phase-3 so we +// blow up in GC phase-4. With RedefineClasses() we want replaced code +// (EMCP or obsolete) to go away (i.e., be collectible) once it is no +// longer being executed by any thread so we keep minimal attachments +// to the replaced code. However, we can't guarantee when those EMCP +// or obsolete methods will be collected so they may still be out there +// even after we've severed our minimal attachments. void CompactingPermGenGen::pre_adjust_pointers() { if (spec()->enable_shared_spaces()) { - RecursiveAdjustSharedObjectClosure blk; - Universe::oops_do(&blk); - StringTable::oops_do(&blk); - SystemDictionary::always_strong_classes_do(&blk); - TraversePlaceholdersClosure tpc; - SystemDictionary::placeholders_do(&tpc); + if (JvmtiExport::has_redefined_a_class()) { + // RedefineClasses() requires a brute force approach + AdjustSharedObjectClosure blk; + rw_space()->object_iterate(&blk); + } else { + RecursiveAdjustSharedObjectClosure blk; + Universe::oops_do(&blk); + StringTable::oops_do(&blk); + SystemDictionary::always_strong_classes_do(&blk); + TraversePlaceholdersClosure tpc; + SystemDictionary::placeholders_do(&tpc); + } } } diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/memory/genRemSet.hpp --- a/hotspot/src/share/vm/memory/genRemSet.hpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/memory/genRemSet.hpp Thu Mar 20 09:17:30 2008 -0500 @@ -91,8 +91,15 @@ virtual void verify() = 0; // Verify that the remembered set has no entries for - // the heap interval denoted by mr. - virtual void verify_empty(MemRegion mr) = 0; + // the heap interval denoted by mr. If there are any + // alignment constraints on the remembered set, only the + // part of the region that is aligned is checked. + // + // alignment boundaries + // +--------+-------+--------+-------+ + // [ region mr ) + // [ part checked ) + virtual void verify_aligned_region_empty(MemRegion mr) = 0; // If appropriate, print some information about the remset on "tty". virtual void print() {} diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/memory/heapInspection.cpp --- a/hotspot/src/share/vm/memory/heapInspection.cpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/memory/heapInspection.cpp Thu Mar 20 09:17:30 2008 -0500 @@ -65,7 +65,7 @@ name = ""; } // simplify the formatting (ILP32 vs LP64) - always cast the numbers to 64-bit - st->print_cr("%13" FORMAT64_MODIFIER "d %13" FORMAT64_MODIFIER "u %s", + st->print_cr(INT64_FORMAT_W(13) " " UINT64_FORMAT_W(13) " %s", (jlong) _instance_count, (julong) _instance_words * HeapWordSize, name); @@ -80,7 +80,10 @@ elt = elt->next(); } elt = new KlassInfoEntry(k, list()); - set_list(elt); + // We may be out of space to allocate the new entry. + if (elt != NULL) { + set_list(elt); + } return elt; } @@ -103,21 +106,25 @@ } KlassInfoTable::KlassInfoTable(int size, HeapWord* ref) { - _size = size; + _size = 0; _ref = ref; - _buckets = NEW_C_HEAP_ARRAY(KlassInfoBucket, _size); - - for (int index = 0; index < _size; index++) { - _buckets[index].initialize(); + _buckets = NEW_C_HEAP_ARRAY(KlassInfoBucket, size); + if (_buckets != NULL) { + _size = size; + for (int index = 0; index < _size; index++) { + _buckets[index].initialize(); + } } } KlassInfoTable::~KlassInfoTable() { - for (int index = 0; index < _size; index++) { - _buckets[index].empty(); + if (_buckets != NULL) { + for (int index = 0; index < _size; index++) { + _buckets[index].empty(); + } + FREE_C_HEAP_ARRAY(KlassInfoBucket, _buckets); + _size = 0; } - FREE_C_HEAP_ARRAY(KlassInfoBucket, _buckets); - _size = 0; } uint KlassInfoTable::hash(klassOop p) { @@ -127,19 +134,32 @@ KlassInfoEntry* KlassInfoTable::lookup(const klassOop k) { uint idx = hash(k) % _size; + assert(_buckets != NULL, "Allocation failure should have been caught"); KlassInfoEntry* e = _buckets[idx].lookup(k); - assert(k == e->klass(), "must be equal"); + // Lookup may fail if this is a new klass for which we + // could not allocate space for an new entry. + assert(e == NULL || k == e->klass(), "must be equal"); return e; } -void KlassInfoTable::record_instance(const oop obj) { +// Return false if the entry could not be recorded on account +// of running out of space required to create a new entry. +bool KlassInfoTable::record_instance(const oop obj) { klassOop k = obj->klass(); KlassInfoEntry* elt = lookup(k); - elt->set_count(elt->count() + 1); - elt->set_words(elt->words() + obj->size()); + // elt may be NULL if it's a new klass for which we + // could not allocate space for a new entry in the hashtable. + if (elt != NULL) { + elt->set_count(elt->count() + 1); + elt->set_words(elt->words() + obj->size()); + return true; + } else { + return false; + } } void KlassInfoTable::iterate(KlassInfoClosure* cic) { + assert(_size == 0 || _buckets != NULL, "Allocation failure should have been caught"); for (int index = 0; index < _size; index++) { _buckets[index].iterate(cic); } @@ -176,7 +196,7 @@ total += elements()->at(i)->count(); totalw += elements()->at(i)->words(); } - st->print_cr("Total %13" FORMAT64_MODIFIER "d %13" FORMAT64_MODIFIER "u", + st->print_cr("Total " INT64_FORMAT_W(13) " " UINT64_FORMAT_W(13), total, totalw * HeapWordSize); } @@ -199,12 +219,18 @@ class RecordInstanceClosure : public ObjectClosure { private: KlassInfoTable* _cit; + size_t _missed_count; public: - RecordInstanceClosure(KlassInfoTable* cit) : _cit(cit) {} + RecordInstanceClosure(KlassInfoTable* cit) : + _cit(cit), _missed_count(0) {} void do_object(oop obj) { - _cit->record_instance(obj); + if (!_cit->record_instance(obj)) { + _missed_count++; + } } + + size_t missed_count() { return _missed_count; } }; void HeapInspection::heap_inspection(outputStream* st) { @@ -230,21 +256,32 @@ ShouldNotReachHere(); // Unexpected heap kind for this op } // Collect klass instance info - - // Iterate over objects in the heap KlassInfoTable cit(KlassInfoTable::cit_size, ref); - RecordInstanceClosure ric(&cit); - Universe::heap()->object_iterate(&ric); + if (!cit.allocation_failed()) { + // Iterate over objects in the heap + RecordInstanceClosure ric(&cit); + Universe::heap()->object_iterate(&ric); - // Sort and print klass instance info - KlassInfoHisto histo("\n" - " num #instances #bytes class name\n" - "----------------------------------------------", - KlassInfoHisto::histo_initial_size); - HistoClosure hc(&histo); - cit.iterate(&hc); - histo.sort(); - histo.print_on(st); + // Report if certain classes are not counted because of + // running out of C-heap for the histogram. + size_t missed_count = ric.missed_count(); + if (missed_count != 0) { + st->print_cr("WARNING: Ran out of C-heap; undercounted " SIZE_FORMAT + " total instances in data below", + missed_count); + } + // Sort and print klass instance info + KlassInfoHisto histo("\n" + " num #instances #bytes class name\n" + "----------------------------------------------", + KlassInfoHisto::histo_initial_size); + HistoClosure hc(&histo); + cit.iterate(&hc); + histo.sort(); + histo.print_on(st); + } else { + st->print_cr("WARNING: Ran out of C-heap; histogram not generated"); + } st->flush(); if (Universe::heap()->kind() == CollectedHeap::GenCollectedHeap) { diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/memory/heapInspection.hpp --- a/hotspot/src/share/vm/memory/heapInspection.hpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/memory/heapInspection.hpp Thu Mar 20 09:17:30 2008 -0500 @@ -98,8 +98,9 @@ }; KlassInfoTable(int size, HeapWord* ref); ~KlassInfoTable(); - void record_instance(const oop obj); + bool record_instance(const oop obj); void iterate(KlassInfoClosure* cic); + bool allocation_failed() { return _buckets == NULL; } }; class KlassInfoHisto : public StackObj { diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/memory/referenceProcessor.cpp --- a/hotspot/src/share/vm/memory/referenceProcessor.cpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/memory/referenceProcessor.cpp Thu Mar 20 09:17:30 2008 -0500 @@ -85,7 +85,7 @@ ReferenceProcessor* rp = new ReferenceProcessor(span, atomic_discovery, mt_discovery, mt_degree, - mt_processing); + mt_processing && (parallel_gc_threads > 0)); if (rp == NULL) { vm_exit_during_initialization("Could not allocate ReferenceProcessor object"); } diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/memory/tenuredGeneration.cpp --- a/hotspot/src/share/vm/memory/tenuredGeneration.cpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/memory/tenuredGeneration.cpp Thu Mar 20 09:17:30 2008 -0500 @@ -409,10 +409,11 @@ void TenuredGeneration::verify_alloc_buffers_clean() { if (UseParNewGC) { for (uint i = 0; i < ParallelGCThreads; i++) { - _rs->verify_empty(_alloc_buffers[i]->range()); + _rs->verify_aligned_region_empty(_alloc_buffers[i]->range()); } } } + #else // SERIALGC void TenuredGeneration::retire_alloc_buffers_before_full_gc() {} void TenuredGeneration::verify_alloc_buffers_clean() {} diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/oops/arrayOop.hpp --- a/hotspot/src/share/vm/oops/arrayOop.hpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/oops/arrayOop.hpp Thu Mar 20 09:17:30 2008 -0500 @@ -58,11 +58,11 @@ // alignments. It gets the scale from the type2aelembytes array. static int32_t max_array_length(BasicType type) { assert(type >= 0 && type < T_CONFLICT, "wrong type"); - assert(type2aelembytes[type] != 0, "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 = (type == T_OBJECT) ? T_OBJECT_aelem_bytes : type2aelembytes[type]; + int elembytes = (type == T_OBJECT) ? T_OBJECT_aelem_bytes : type2aelembytes(type); jlong len = ((jlong)max_words * HeapWordSize) / elembytes; return (len > max_jint) ? max_jint : (int32_t)len; } diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/oops/instanceKlass.cpp --- a/hotspot/src/share/vm/oops/instanceKlass.cpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/oops/instanceKlass.cpp Thu Mar 20 09:17:30 2008 -0500 @@ -791,17 +791,39 @@ } +static int compare_fields_by_offset(int* a, int* b) { + return a[0] - b[0]; +} + void instanceKlass::do_nonstatic_fields(FieldClosure* cl) { - fieldDescriptor fd; instanceKlass* super = superklass(); if (super != NULL) { super->do_nonstatic_fields(cl); } + fieldDescriptor fd; int length = fields()->length(); + // In DebugInfo nonstatic fields are sorted by offset. + int* fields_sorted = NEW_C_HEAP_ARRAY(int, 2*(length+1)); + int j = 0; for (int i = 0; i < length; i += next_offset) { fd.initialize(as_klassOop(), i); - if (!(fd.is_static())) cl->do_field(&fd); + if (!fd.is_static()) { + fields_sorted[j + 0] = fd.offset(); + fields_sorted[j + 1] = i; + j += 2; + } } + if (j > 0) { + length = j; + // _sort_Fn is defined in growableArray.hpp. + qsort(fields_sorted, length/2, 2*sizeof(int), (_sort_Fn)compare_fields_by_offset); + for (int i = 0; i < length; i += 2) { + fd.initialize(as_klassOop(), fields_sorted[i + 1]); + assert(!fd.is_static() && fd.offset() == fields_sorted[i], "only nonstatic fields"); + cl->do_field(&fd); + } + } + FREE_C_HEAP_ARRAY(int, fields_sorted); } @@ -950,7 +972,6 @@ // These allocations will have to be freed if they are unused. // Allocate a new array of methods. - jmethodID* to_dealloc_jmeths = NULL; jmethodID* new_jmeths = NULL; if (length <= idnum) { // A new array will be needed (unless some other thread beats us to it) @@ -961,7 +982,6 @@ } // Allocate a new method ID. - jmethodID to_dealloc_id = NULL; jmethodID new_id = NULL; if (method_h->is_old() && !method_h->is_obsolete()) { // The method passed in is old (but not obsolete), we need to use the current version @@ -975,40 +995,51 @@ new_id = JNIHandles::make_jmethod_id(method_h); } - { + if (Threads::number_of_threads() == 0 || SafepointSynchronize::is_at_safepoint()) { + // No need and unsafe to lock the JmethodIdCreation_lock at safepoint. + id = get_jmethod_id(ik_h, idnum, new_id, new_jmeths); + } else { MutexLocker ml(JmethodIdCreation_lock); + id = get_jmethod_id(ik_h, idnum, new_id, new_jmeths); + } + } + return id; +} - // We must not go to a safepoint while holding this lock. - debug_only(No_Safepoint_Verifier nosafepoints;) + +jmethodID instanceKlass::get_jmethod_id(instanceKlassHandle ik_h, size_t idnum, + jmethodID new_id, jmethodID* new_jmeths) { + // Retry lookup after we got the lock or ensured we are at safepoint + jmethodID* jmeths = ik_h->methods_jmethod_ids_acquire(); + jmethodID id = NULL; + jmethodID to_dealloc_id = NULL; + jmethodID* to_dealloc_jmeths = NULL; + size_t length; - // Retry lookup after we got the lock - jmeths = ik_h->methods_jmethod_ids_acquire(); - if (jmeths == NULL || (length = (size_t)jmeths[0]) <= idnum) { - if (jmeths != NULL) { - // We have grown the array: copy the existing entries, and delete the old array - for (size_t index = 0; index < length; index++) { - new_jmeths[index+1] = jmeths[index+1]; - } - to_dealloc_jmeths = jmeths; // using the new jmeths, deallocate the old one - } - ik_h->release_set_methods_jmethod_ids(jmeths = new_jmeths); - } else { - id = jmeths[idnum+1]; - to_dealloc_jmeths = new_jmeths; // using the old jmeths, deallocate the new one + if (jmeths == NULL || (length = (size_t)jmeths[0]) <= idnum) { + if (jmeths != NULL) { + // We have grown the array: copy the existing entries, and delete the old array + for (size_t index = 0; index < length; index++) { + new_jmeths[index+1] = jmeths[index+1]; } - if (id == NULL) { - id = new_id; - jmeths[idnum+1] = id; // install the new method ID - } else { - to_dealloc_id = new_id; // the new id wasn't used, mark it for deallocation - } + to_dealloc_jmeths = jmeths; // using the new jmeths, deallocate the old one } + ik_h->release_set_methods_jmethod_ids(jmeths = new_jmeths); + } else { + id = jmeths[idnum+1]; + to_dealloc_jmeths = new_jmeths; // using the old jmeths, deallocate the new one + } + if (id == NULL) { + id = new_id; + jmeths[idnum+1] = id; // install the new method ID + } else { + to_dealloc_id = new_id; // the new id wasn't used, mark it for deallocation + } - // Free up unneeded or no longer needed resources - FreeHeap(to_dealloc_jmeths); - if (to_dealloc_id != NULL) { - JNIHandles::destroy_jmethod_id(to_dealloc_id); - } + // Free up unneeded or no longer needed resources + FreeHeap(to_dealloc_jmeths); + if (to_dealloc_id != NULL) { + JNIHandles::destroy_jmethod_id(to_dealloc_id); } return id; } @@ -2165,12 +2196,20 @@ RC_TRACE(0x00000100, ("adding previous version ref for %s @%d, EMCP_cnt=%d", ikh->external_name(), _previous_versions->length(), emcp_method_count)); constantPoolHandle cp_h(ikh->constants()); - jweak cp_ref = JNIHandles::make_weak_global(cp_h); + jobject cp_ref; + if (cp_h->is_shared()) { + // a shared ConstantPool requires a regular reference; a weak + // reference would be collectible + cp_ref = JNIHandles::make_global(cp_h); + } else { + cp_ref = JNIHandles::make_weak_global(cp_h); + } PreviousVersionNode * pv_node = NULL; objArrayOop old_methods = ikh->methods(); if (emcp_method_count == 0) { - pv_node = new PreviousVersionNode(cp_ref, NULL); + // non-shared ConstantPool gets a weak reference + pv_node = new PreviousVersionNode(cp_ref, !cp_h->is_shared(), NULL); RC_TRACE(0x00000400, ("add: all methods are obsolete; flushing any EMCP weak refs")); } else { @@ -2190,7 +2229,8 @@ } } } - pv_node = new PreviousVersionNode(cp_ref, method_refs); + // non-shared ConstantPool gets a weak reference + pv_node = new PreviousVersionNode(cp_ref, !cp_h->is_shared(), method_refs); } _previous_versions->append(pv_node); @@ -2208,7 +2248,7 @@ // check the previous versions array for a GC'ed weak refs pv_node = _previous_versions->at(i); cp_ref = pv_node->prev_constant_pool(); - assert(cp_ref != NULL, "weak cp ref was unexpectedly cleared"); + assert(cp_ref != NULL, "cp ref was unexpectedly cleared"); if (cp_ref == NULL) { delete pv_node; _previous_versions->remove_at(i); @@ -2281,7 +2321,7 @@ // check the previous versions array for a GC'ed weak refs pv_node = _previous_versions->at(j); cp_ref = pv_node->prev_constant_pool(); - assert(cp_ref != NULL, "weak cp ref was unexpectedly cleared"); + assert(cp_ref != NULL, "cp ref was unexpectedly cleared"); if (cp_ref == NULL) { delete pv_node; _previous_versions->remove_at(j); @@ -2379,8 +2419,8 @@ // been GC'ed PreviousVersionNode * pv_node = _previous_versions->at(i); - jweak cp_ref = pv_node->prev_constant_pool(); - assert(cp_ref != NULL, "weak reference was unexpectedly cleared"); + jobject cp_ref = pv_node->prev_constant_pool(); + assert(cp_ref != NULL, "cp reference was unexpectedly cleared"); if (cp_ref == NULL) { continue; // robustness } @@ -2440,10 +2480,11 @@ // Construct a PreviousVersionNode entry for the array hung off // the instanceKlass. -PreviousVersionNode::PreviousVersionNode(jweak prev_constant_pool, - GrowableArray* prev_EMCP_methods) { +PreviousVersionNode::PreviousVersionNode(jobject prev_constant_pool, + bool prev_cp_is_weak, GrowableArray* prev_EMCP_methods) { _prev_constant_pool = prev_constant_pool; + _prev_cp_is_weak = prev_cp_is_weak; _prev_EMCP_methods = prev_EMCP_methods; } @@ -2451,7 +2492,11 @@ // Destroy a PreviousVersionNode PreviousVersionNode::~PreviousVersionNode() { if (_prev_constant_pool != NULL) { - JNIHandles::destroy_weak_global(_prev_constant_pool); + if (_prev_cp_is_weak) { + JNIHandles::destroy_weak_global(_prev_constant_pool); + } else { + JNIHandles::destroy_global(_prev_constant_pool); + } } if (_prev_EMCP_methods != NULL) { @@ -2471,8 +2516,8 @@ _prev_constant_pool_handle = constantPoolHandle(); // NULL handle _prev_EMCP_method_handles = NULL; - jweak cp_ref = pv_node->prev_constant_pool(); - assert(cp_ref != NULL, "weak constant pool ref was unexpectedly cleared"); + jobject cp_ref = pv_node->prev_constant_pool(); + assert(cp_ref != NULL, "constant pool ref was unexpectedly cleared"); if (cp_ref == NULL) { return; // robustness } diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/oops/instanceKlass.hpp --- a/hotspot/src/share/vm/oops/instanceKlass.hpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/oops/instanceKlass.hpp Thu Mar 20 09:17:30 2008 -0500 @@ -432,6 +432,8 @@ _enclosing_method_method_index = method_index; } // jmethodID support + static jmethodID get_jmethod_id(instanceKlassHandle ik_h, size_t idnum, + jmethodID new_id, jmethodID* new_jmeths); static jmethodID jmethod_id_for_impl(instanceKlassHandle ik_h, methodHandle method_h); jmethodID jmethod_id_or_null(methodOop method); @@ -838,11 +840,20 @@ // A collection point for interesting information about the previous // version(s) of an instanceKlass. This class uses weak references to // the information so that the information may be collected as needed -// by the system. A GrowableArray of PreviousVersionNodes is attached +// by the system. If the information is shared, then a regular +// reference must be used because a weak reference would be seen as +// collectible. A GrowableArray of PreviousVersionNodes is attached // to the instanceKlass as needed. See PreviousVersionWalker below. class PreviousVersionNode : public CHeapObj { private: - jweak _prev_constant_pool; + // A shared ConstantPool is never collected so we'll always have + // a reference to it so we can update items in the cache. We'll + // have a weak reference to a non-shared ConstantPool until all + // of the methods (EMCP or obsolete) have been collected; the + // non-shared ConstantPool becomes collectible at that point. + jobject _prev_constant_pool; // regular or weak reference + bool _prev_cp_is_weak; // true if not a shared ConstantPool + // If the previous version of the instanceKlass doesn't have any // EMCP methods, then _prev_EMCP_methods will be NULL. If all the // EMCP methods have been collected, then _prev_EMCP_methods can @@ -850,10 +861,10 @@ GrowableArray* _prev_EMCP_methods; public: - PreviousVersionNode(jweak prev_constant_pool, + PreviousVersionNode(jobject prev_constant_pool, bool prev_cp_is_weak, GrowableArray* prev_EMCP_methods); ~PreviousVersionNode(); - jweak prev_constant_pool() const { + jobject prev_constant_pool() const { return _prev_constant_pool; } GrowableArray* prev_EMCP_methods() const { diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/oops/klass.cpp --- a/hotspot/src/share/vm/oops/klass.cpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/oops/klass.cpp Thu Mar 20 09:17:30 2008 -0500 @@ -182,7 +182,7 @@ assert(etype >= T_BOOLEAN && etype <= T_OBJECT, "valid etype"); // Note that T_ARRAY is not allowed here. int hsize = arrayOopDesc::base_offset_in_bytes(etype); - int esize = type2aelembytes[etype]; + int esize = type2aelembytes(etype); bool isobj = (etype == T_OBJECT); int tag = isobj ? _lh_array_tag_obj_value : _lh_array_tag_type_value; int lh = array_layout_helper(tag, hsize, etype, exact_log2(esize)); diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/oops/klassVtable.cpp --- a/hotspot/src/share/vm/oops/klassVtable.cpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/oops/klassVtable.cpp Thu Mar 20 09:17:30 2008 -0500 @@ -735,7 +735,7 @@ } } - // This lenght of the itable was either zero, or it has not yet been initialized. + // The length of the itable was either zero, or it has not yet been initialized. _table_offset = 0; _size_offset_table = 0; _size_method_table = 0; @@ -870,16 +870,19 @@ // Initialization void klassItable::initialize_itable(bool checkconstraints, TRAPS) { - // Cannot be setup doing bootstrapping - if (Universe::is_bootstrapping()) return; + // Cannot be setup doing bootstrapping, interfaces don't have + // itables, and klass with only ones entry have empty itables + if (Universe::is_bootstrapping() || + _klass->is_interface() || + _klass->itable_length() == itableOffsetEntry::size()) return; - int num_interfaces = nof_interfaces(); + // There's alway an extra itable entry so we can null-terminate it. + guarantee(size_offset_table() >= 1, "too small"); + int num_interfaces = size_offset_table() - 1; if (num_interfaces > 0) { - if (TraceItables) tty->print_cr("%3d: Initializing itables for %s", ++initialize_count, _klass->name()->as_C_string()); + if (TraceItables) tty->print_cr("%3d: Initializing itables for %s", ++initialize_count, + _klass->name()->as_C_string()); - // In debug mode, we got an extra NULL/NULL entry - debug_only(num_interfaces--); - assert(num_interfaces > 0, "to few interfaces in offset itable"); // Interate through all interfaces int i; @@ -890,12 +893,10 @@ initialize_itable_for_interface(ioe->offset(), interf_h, checkconstraints, CHECK); } -#ifdef ASSERT - // Check that the last entry is empty - itableOffsetEntry* ioe = offset_entry(i); - assert(ioe->interface_klass() == NULL && ioe->offset() == 0, "terminator entry missing"); -#endif } + // Check that the last entry is empty + itableOffsetEntry* ioe = offset_entry(size_offset_table() - 1); + guarantee(ioe->interface_klass() == NULL && ioe->offset() == 0, "terminator entry missing"); } @@ -972,7 +973,7 @@ } } -// Update entry for specic methodOop +// Update entry for specific methodOop void klassItable::initialize_with_method(methodOop m) { itableMethodEntry* ime = method_entry(0); for(int i = 0; i < _size_method_table; i++) { @@ -1085,12 +1086,8 @@ CountInterfacesClosure cic; visit_all_interfaces(transitive_interfaces(), &cic); - // Add one extra entry in debug mode, so we can null-terminate the table - int nof_methods = cic.nof_methods(); - int nof_interfaces = cic.nof_interfaces(); - debug_only(if (nof_interfaces > 0) nof_interfaces++); - - int itable_size = calc_itable_size(nof_interfaces, nof_methods); + // There's alway an extra itable entry so we can null-terminate it. + int itable_size = calc_itable_size(cic.nof_interfaces() + 1, cic.nof_methods()); // Statistics update_stats(itable_size * HeapWordSize); @@ -1110,8 +1107,8 @@ int nof_methods = cic.nof_methods(); int nof_interfaces = cic.nof_interfaces(); - // Add one extra entry in debug mode, so we can null-terminate the table - debug_only(if (nof_interfaces > 0) nof_interfaces++); + // Add one extra entry so we can null-terminate the table + nof_interfaces++; assert(compute_itable_size(objArrayHandle(klass->transitive_interfaces())) == calc_itable_size(nof_interfaces, nof_methods), diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/oops/klassVtable.hpp --- a/hotspot/src/share/vm/oops/klassVtable.hpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/oops/klassVtable.hpp Thu Mar 20 09:17:30 2008 -0500 @@ -259,7 +259,7 @@ itableMethodEntry* method_entry(int i) { assert(0 <= i && i <= _size_method_table, "index out of bounds"); return &((itableMethodEntry*)method_start())[i]; } - int nof_interfaces() { return _size_offset_table; } + int size_offset_table() { return _size_offset_table; } // Initialization void initialize_itable(bool checkconstraints, TRAPS); diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/oops/markOop.cpp --- a/hotspot/src/share/vm/oops/markOop.cpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/oops/markOop.cpp Thu Mar 20 09:17:30 2008 -0500 @@ -37,3 +37,32 @@ st->print("age %d)", age()); } } + + +// Give advice about whether the oop that contains this markOop +// should be cached or not. +bool markOopDesc::should_not_be_cached() const { + // the cast is because decode_pointer() isn't marked const + if (is_marked() && ((markOopDesc *)this)->decode_pointer() != NULL) { + // If the oop containing this markOop is being forwarded, then + // we are in the middle of GC and we do not want the containing + // oop to be added to a cache. We have no way of knowing whether + // the cache has already been visited by the current GC phase so + // we don't know whether the forwarded oop will be properly + // processed in this phase. If the forwarded oop is not properly + // processed, then we'll see strange crashes or asserts during + // the next GC run because the markOop will contain an unexpected + // value. + // + // This situation has been seen when we are GC'ing a methodOop + // because we use the methodOop while we're GC'ing it. Scary + // stuff. Some of the uses the methodOop cause the methodOop to + // be added to the OopMapCache in the instanceKlass as a side + // effect. This check lets the cache maintainer know when a + // cache addition would not be safe. + return true; + } + + // caching the containing oop should be just fine + return false; +} diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/oops/markOop.hpp --- a/hotspot/src/share/vm/oops/markOop.hpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/oops/markOop.hpp Thu Mar 20 09:17:30 2008 -0500 @@ -357,4 +357,7 @@ // Recover address of oop from encoded form used in mark inline void* decode_pointer() { if (UseBiasedLocking && has_bias_pattern()) return NULL; return clear_lock_bits(); } + + // see the definition in markOop.cpp for the gory details + bool should_not_be_cached() const; }; diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/oops/methodDataOop.cpp --- a/hotspot/src/share/vm/oops/methodDataOop.cpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/oops/methodDataOop.cpp Thu Mar 20 09:17:30 2008 -0500 @@ -32,7 +32,7 @@ // Some types of data layouts need a length field. bool DataLayout::needs_array_len(u1 tag) { - return (tag == multi_branch_data_tag); + return (tag == multi_branch_data_tag) || (tag == arg_info_data_tag); } // Perform generic initialization of the data. More specific @@ -404,6 +404,17 @@ } #endif +#ifndef PRODUCT +void ArgInfoData::print_data_on(outputStream* st) { + print_shared(st, "ArgInfoData"); + int nargs = number_of_args(); + for (int i = 0; i < nargs; i++) { + st->print(" 0x%x", arg_modified(i)); + } + st->cr(); +} + +#endif // ================================================================== // methodDataOop // @@ -508,6 +519,9 @@ int extra_data_count = compute_extra_data_count(data_size, empty_bc_count); object_size += extra_data_count * DataLayout::compute_size_in_bytes(0); + // Add a cell to record information about modified arguments. + int arg_size = method->size_of_parameters(); + object_size += DataLayout::compute_size_in_bytes(arg_size+1); return object_size; } @@ -626,6 +640,8 @@ return new BranchData(data_layout); case DataLayout::multi_branch_data_tag: return new MultiBranchData(data_layout); + case DataLayout::arg_info_data_tag: + return new ArgInfoData(data_layout); }; } @@ -681,7 +697,17 @@ // Add some extra DataLayout cells (at least one) to track stray traps. int extra_data_count = compute_extra_data_count(data_size, empty_bc_count); - object_size += extra_data_count * DataLayout::compute_size_in_bytes(0); + int extra_size = extra_data_count * DataLayout::compute_size_in_bytes(0); + + // Add a cell to record information about modified arguments. + // Set up _args_modified array after traps cells so that + // the code for traps cells works. + DataLayout *dp = data_layout_at(data_size + extra_size); + + int arg_size = method->size_of_parameters(); + dp->initialize(DataLayout::arg_info_data_tag, 0, arg_size+1); + + object_size += extra_size + DataLayout::compute_size_in_bytes(arg_size+1); // Set an initial hint. Don't use set_hint_di() because // first_di() may be out of bounds if data_size is 0. @@ -764,6 +790,10 @@ // No need for "OrderAccess::load_acquire" ops, // since the data structure is monotonic. if (dp->tag() == DataLayout::no_tag) break; + if (dp->tag() == DataLayout::arg_info_data_tag) { + dp = end; // ArgInfoData is at the end of extra data section. + break; + } if (dp->bci() == bci) { assert(dp->tag() == DataLayout::bit_data_tag, "sane"); return new BitData(dp); @@ -785,6 +815,16 @@ return NULL; } +ArgInfoData *methodDataOopDesc::arg_info() { + DataLayout* dp = extra_data_base(); + DataLayout* end = extra_data_limit(); + for (; dp < end; dp = next_extra(dp)) { + if (dp->tag() == DataLayout::arg_info_data_tag) + return new ArgInfoData(dp); + } + return NULL; +} + #ifndef PRODUCT void methodDataOopDesc::print_data_on(outputStream* st) { ResourceMark rm; @@ -794,15 +834,20 @@ st->fill_to(6); data->print_data_on(st); } + st->print_cr("--- Extra data:"); DataLayout* dp = extra_data_base(); DataLayout* end = extra_data_limit(); for (; dp < end; dp = next_extra(dp)) { // No need for "OrderAccess::load_acquire" ops, // since the data structure is monotonic. - if (dp->tag() == DataLayout::no_tag) break; - if (dp == extra_data_base()) - st->print_cr("--- Extra data:"); - data = new BitData(dp); + if (dp->tag() == DataLayout::no_tag) continue; + if (dp->tag() == DataLayout::bit_data_tag) { + data = new BitData(dp); + } else { + assert(dp->tag() == DataLayout::arg_info_data_tag, "must be BitData or ArgInfo"); + data = new ArgInfoData(dp); + dp = end; // ArgInfoData is at the end of extra data section. + } st->print("%d", dp_to_di(data->dp())); st->fill_to(6); data->print_data_on(st); diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/oops/methodDataOop.hpp --- a/hotspot/src/share/vm/oops/methodDataOop.hpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/oops/methodDataOop.hpp Thu Mar 20 09:17:30 2008 -0500 @@ -101,7 +101,8 @@ virtual_call_data_tag, ret_data_tag, branch_data_tag, - multi_branch_data_tag + multi_branch_data_tag, + arg_info_data_tag }; enum { @@ -245,6 +246,7 @@ class BranchData; class ArrayData; class MultiBranchData; +class ArgInfoData; // ProfileData @@ -376,6 +378,8 @@ virtual bool is_BranchData() { return false; } virtual bool is_ArrayData() { return false; } virtual bool is_MultiBranchData() { return false; } + virtual bool is_ArgInfoData() { return false; } + BitData* as_BitData() { assert(is_BitData(), "wrong type"); @@ -413,6 +417,10 @@ assert(is_MultiBranchData(), "wrong type"); return is_MultiBranchData() ? (MultiBranchData*)this : NULL; } + ArgInfoData* as_ArgInfoData() { + assert(is_ArgInfoData(), "wrong type"); + return is_ArgInfoData() ? (ArgInfoData*)this : NULL; + } // Subclass specific initialization @@ -1047,6 +1055,33 @@ #endif }; +class ArgInfoData : public ArrayData { + +public: + ArgInfoData(DataLayout* layout) : ArrayData(layout) { + assert(layout->tag() == DataLayout::arg_info_data_tag, "wrong type"); + } + + virtual bool is_ArgInfoData() { return true; } + + + int number_of_args() { + return array_len(); + } + + uint arg_modified(int arg) { + return array_uint_at(arg); + } + + void set_arg_modified(int arg, uint val) { + array_set_int_at(arg, val); + } + +#ifndef PRODUCT + void print_data_on(outputStream* st); +#endif +}; + // methodDataOop // // A methodDataOop holds information which has been collected about @@ -1183,6 +1218,9 @@ // Find or create an extra ProfileData: ProfileData* bci_to_extra_data(int bci, bool create_if_missing); + // return the argument info cell + ArgInfoData *arg_info(); + public: static int header_size() { return sizeof(methodDataOopDesc)/wordSize; @@ -1222,11 +1260,18 @@ intx arg_local() { return _arg_local; } intx arg_stack() { return _arg_stack; } intx arg_returned() { return _arg_returned; } + uint arg_modified(int a) { ArgInfoData *aid = arg_info(); + assert(a >= 0 && a < aid->number_of_args(), "valid argument number"); + return aid->arg_modified(a); } void set_eflags(intx v) { _eflags = v; } void set_arg_local(intx v) { _arg_local = v; } void set_arg_stack(intx v) { _arg_stack = v; } void set_arg_returned(intx v) { _arg_returned = v; } + void set_arg_modified(int a, uint v) { ArgInfoData *aid = arg_info(); + assert(a >= 0 && a < aid->number_of_args(), "valid argument number"); + + aid->set_arg_modified(a, v); } void clear_escape_info() { _eflags = _arg_local = _arg_stack = _arg_returned = 0; } diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/oops/methodOop.cpp --- a/hotspot/src/share/vm/oops/methodOop.cpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/oops/methodOop.cpp Thu Mar 20 09:17:30 2008 -0500 @@ -765,6 +765,28 @@ } +// give advice about whether this methodOop should be cached or not +bool methodOopDesc::should_not_be_cached() const { + if (is_old()) { + // This method has been redefined. It is either EMCP or obsolete + // and we don't want to cache it because that would pin the method + // down and prevent it from being collectible if and when it + // finishes executing. + return true; + } + + if (mark()->should_not_be_cached()) { + // It is either not safe or not a good idea to cache this + // method at this time because of the state of the embedded + // markOop. See markOop.cpp for the gory details. + return true; + } + + // caching this method should be just fine + return false; +} + + methodHandle methodOopDesc:: clone_with_new_data(methodHandle m, u_char* new_code, int new_code_length, u_char* new_compressed_linenumber_table, int new_compressed_linenumber_size, TRAPS) { // Code below does not work for native methods - they should never get rewritten anyway diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/oops/methodOop.hpp --- a/hotspot/src/share/vm/oops/methodOop.hpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/oops/methodOop.hpp Thu Mar 20 09:17:30 2008 -0500 @@ -524,6 +524,8 @@ void set_is_old() { _access_flags.set_is_old(); } bool is_obsolete() const { return access_flags().is_obsolete(); } void set_is_obsolete() { _access_flags.set_is_obsolete(); } + // see the definition in methodOop.cpp for the gory details + bool should_not_be_cached() const; // JVMTI Native method prefixing support: bool is_prefixed_native() const { return access_flags().is_prefixed_native(); } diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/opto/addnode.cpp --- a/hotspot/src/share/vm/opto/addnode.cpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/opto/addnode.cpp Thu Mar 20 09:17:30 2008 -0500 @@ -505,15 +505,25 @@ const Type *temp_t2 = phase->type( in(Offset) ); if( temp_t2 == Type::TOP ) return NULL; const TypeX *t2 = temp_t2->is_intptr_t(); + Node* address; + Node* offset; if( t2->is_con() ) { // The Add of the flattened expression - set_req(Address, addp->in(Address)); - set_req(Offset , phase->MakeConX(t2->get_con() + t12->get_con())); - return this; // Made progress + address = addp->in(Address); + offset = phase->MakeConX(t2->get_con() + t12->get_con()); + } else { + // Else move the constant to the right. ((A+con)+B) into ((A+B)+con) + address = phase->transform(new (phase->C, 4) AddPNode(in(Base),addp->in(Address),in(Offset))); + offset = addp->in(Offset); } - // Else move the constant to the right. ((A+con)+B) into ((A+B)+con) - set_req(Address, phase->transform(new (phase->C, 4) AddPNode(in(Base),addp->in(Address),in(Offset)))); - set_req(Offset , addp->in(Offset)); + PhaseIterGVN *igvn = phase->is_IterGVN(); + if( igvn ) { + set_req_X(Address,address,igvn); + set_req_X(Offset,offset,igvn); + } else { + set_req(Address,address); + set_req(Offset,offset); + } return this; } } @@ -608,6 +618,28 @@ return NULL; } +//------------------------------unpack_offsets---------------------------------- +// Collect the AddP offset values into the elements array, giving up +// if there are more than length. +int AddPNode::unpack_offsets(Node* elements[], int length) { + int count = 0; + Node* addr = this; + Node* base = addr->in(AddPNode::Base); + while (addr->is_AddP()) { + if (addr->in(AddPNode::Base) != base) { + // give up + return -1; + } + elements[count++] = addr->in(AddPNode::Offset); + if (count == length) { + // give up + return -1; + } + addr = addr->in(AddPNode::Address); + } + return count; +} + //------------------------------match_edge------------------------------------- // Do we Match on this edge index or not? Do not match base pointer edge uint AddPNode::match_edge(uint idx) const { diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/opto/addnode.hpp --- a/hotspot/src/share/vm/opto/addnode.hpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/opto/addnode.hpp Thu Mar 20 09:17:30 2008 -0500 @@ -144,6 +144,11 @@ static Node* Ideal_base_and_offset(Node* ptr, PhaseTransform* phase, // second return value: intptr_t& offset); + + // Collect the AddP offset values into the elements array, giving up + // if there are more than length. + int unpack_offsets(Node* elements[], int length); + // Do not match base-ptr edge virtual uint match_edge(uint idx) const; static const Type *mach_bottom_type(const MachNode* n); // used by ad_.hpp diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/opto/bytecodeInfo.cpp --- a/hotspot/src/share/vm/opto/bytecodeInfo.cpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/opto/bytecodeInfo.cpp Thu Mar 20 09:17:30 2008 -0500 @@ -79,8 +79,20 @@ for (int i = depth; i != 0; --i) tty->print(" "); } +static bool is_init_with_ea(ciMethod* callee_method, + ciMethod* caller_method, Compile* C) { + // True when EA is ON and a java constructor is called or + // a super constructor is called from an inlined java constructor. + return DoEscapeAnalysis && EliminateAllocations && + ( callee_method->is_initializer() || + (caller_method->is_initializer() && + caller_method != C->method() && + caller_method->holder()->is_subclass_of(callee_method->holder())) + ); +} + // positive filter: should send be inlined? returns NULL, if yes, or rejection msg -const char* InlineTree::shouldInline(ciMethod* callee_method, int caller_bci, ciCallProfile& profile, WarmCallInfo* wci_result) const { +const char* InlineTree::shouldInline(ciMethod* callee_method, ciMethod* caller_method, int caller_bci, ciCallProfile& profile, WarmCallInfo* wci_result) const { // Allows targeted inlining if(callee_method->should_inline()) { *wci_result = *(WarmCallInfo::always_hot()); @@ -97,7 +109,8 @@ int size = callee_method->code_size(); // Check for too many throws (and not too huge) - if(callee_method->interpreter_throwout_count() > InlineThrowCount && size < InlineThrowMaxSize ) { + if(callee_method->interpreter_throwout_count() > InlineThrowCount && + size < InlineThrowMaxSize ) { wci_result->set_profit(wci_result->profit() * 100); if (PrintInlining && Verbose) { print_indent(inline_depth()); @@ -114,8 +127,12 @@ int invoke_count = method()->interpreter_invocation_count(); assert( invoke_count != 0, "Require invokation count greater than zero"); int freq = call_site_count/invoke_count; + // bump the max size if the call is frequent - if ((freq >= InlineFrequencyRatio) || (call_site_count >= InlineFrequencyCount)) { + if ((freq >= InlineFrequencyRatio) || + (call_site_count >= InlineFrequencyCount) || + is_init_with_ea(callee_method, caller_method, C)) { + max_size = C->freq_inline_size(); if (size <= max_size && TraceFrequencyInlining) { print_indent(inline_depth()); @@ -126,7 +143,8 @@ } } else { // Not hot. Check for medium-sized pre-existing nmethod at cold sites. - if (callee_method->has_compiled_code() && callee_method->instructions_size() > InlineSmallCode/4) + if (callee_method->has_compiled_code() && + callee_method->instructions_size() > InlineSmallCode/4) return "already compiled into a medium method"; } if (size > max_size) { @@ -139,7 +157,7 @@ // negative filter: should send NOT be inlined? returns NULL, ok to inline, or rejection msg -const char* InlineTree::shouldNotInline(ciMethod *callee_method, WarmCallInfo* wci_result) const { +const char* InlineTree::shouldNotInline(ciMethod *callee_method, ciMethod* caller_method, WarmCallInfo* wci_result) const { // negative filter: should send NOT be inlined? returns NULL (--> inline) or rejection msg if (!UseOldInlining) { const char* fail = NULL; @@ -204,9 +222,23 @@ // use frequency-based objections only for non-trivial methods if (callee_method->code_size() <= MaxTrivialSize) return NULL; - if (UseInterpreter && !CompileTheWorld) { // don't use counts with -Xcomp or CTW - if (!callee_method->has_compiled_code() && !callee_method->was_executed_more_than(0)) return "never executed"; - if (!callee_method->was_executed_more_than(MIN2(MinInliningThreshold, CompileThreshold >> 1))) return "executed < MinInliningThreshold times"; + + // don't use counts with -Xcomp or CTW + if (UseInterpreter && !CompileTheWorld) { + + if (!callee_method->has_compiled_code() && + !callee_method->was_executed_more_than(0)) { + return "never executed"; + } + + if (is_init_with_ea(callee_method, caller_method, C)) { + + // Escape Analysis: inline all executed constructors + + } else if (!callee_method->was_executed_more_than(MIN2(MinInliningThreshold, + CompileThreshold >> 1))) { + return "executed < MinInliningThreshold times"; + } } if (callee_method->should_not_inline()) { @@ -219,8 +251,7 @@ //-----------------------------try_to_inline----------------------------------- // return NULL if ok, reason for not inlining otherwise // Relocated from "InliningClosure::try_to_inline" -const char* InlineTree::try_to_inline(ciMethod* callee_method, int caller_bci, ciCallProfile& profile, WarmCallInfo* wci_result) { - ciMethod* caller_method = method(); +const char* InlineTree::try_to_inline(ciMethod* callee_method, ciMethod* caller_method, int caller_bci, ciCallProfile& profile, WarmCallInfo* wci_result) { // Old algorithm had funny accumulating BC-size counters if (UseOldInlining && ClipInlining @@ -229,25 +260,47 @@ } const char *msg = NULL; - if ((msg = shouldInline(callee_method, caller_bci, profile, wci_result)) != NULL) return msg; - if ((msg = shouldNotInline(callee_method, wci_result)) != NULL) return msg; + if ((msg = shouldInline(callee_method, caller_method, caller_bci, + profile, wci_result)) != NULL) { + return msg; + } + if ((msg = shouldNotInline(callee_method, caller_method, + wci_result)) != NULL) { + return msg; + } bool is_accessor = InlineAccessors && callee_method->is_accessor(); // suppress a few checks for accessors and trivial methods if (!is_accessor && callee_method->code_size() > MaxTrivialSize) { + // don't inline into giant methods - if (C->unique() > (uint)NodeCountInliningCutoff) return "NodeCountInliningCutoff"; + if (C->unique() > (uint)NodeCountInliningCutoff) { + return "NodeCountInliningCutoff"; + } - // don't inline unreached call sites - if (profile.count() == 0) return "call site not reached"; + if ((!UseInterpreter || CompileTheWorld) && + is_init_with_ea(callee_method, caller_method, C)) { + + // Escape Analysis stress testing when running Xcomp or CTW: + // inline constructors even if they are not reached. + + } else if (profile.count() == 0) { + // don't inline unreached call sites + return "call site not reached"; + } } - if (!C->do_inlining() && InlineAccessors && !is_accessor) return "not an accessor"; - - if( inline_depth() > MaxInlineLevel ) return "inlining too deep"; + if (!C->do_inlining() && InlineAccessors && !is_accessor) { + return "not an accessor"; + } + if( inline_depth() > MaxInlineLevel ) { + return "inlining too deep"; + } if( method() == callee_method && - inline_depth() > MaxRecursiveInlineLevel ) return "recursively inlining too deep"; + inline_depth() > MaxRecursiveInlineLevel ) { + return "recursively inlining too deep"; + } int size = callee_method->code_size(); @@ -336,7 +389,7 @@ // Check if inlining policy says no. WarmCallInfo wci = *(initial_wci); - failure_msg = try_to_inline(callee_method, caller_bci, profile, &wci); + failure_msg = try_to_inline(callee_method, caller_method, caller_bci, profile, &wci); if (failure_msg != NULL && C->log() != NULL) { C->log()->begin_elem("inline_fail reason='"); C->log()->text("%s", failure_msg); diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/opto/c2_globals.hpp --- a/hotspot/src/share/vm/opto/c2_globals.hpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/opto/c2_globals.hpp Thu Mar 20 09:17:30 2008 -0500 @@ -367,6 +367,12 @@ notproduct(bool, PrintEliminateLocks, false, \ "Print out when locks are eliminated") \ \ + diagnostic(bool, EliminateAutoBox, false, \ + "Private flag to control optimizations for autobox elimination") \ + \ + product(intx, AutoBoxCacheMax, 128, \ + "Sets max value cached by the java.lang.Integer autobox cache") \ + \ product(bool, DoEscapeAnalysis, false, \ "Perform escape analysis") \ \ diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/opto/c2compiler.cpp --- a/hotspot/src/share/vm/opto/c2compiler.cpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/opto/c2compiler.cpp Thu Mar 20 09:17:30 2008 -0500 @@ -35,6 +35,9 @@ const char* C2Compiler::retry_no_subsuming_loads() { return "retry without subsuming loads"; } +const char* C2Compiler::retry_no_escape_analysis() { + return "retry without escape analysis"; +} void C2Compiler::initialize_runtime() { // Check assumptions used while running ADLC @@ -101,17 +104,23 @@ initialize(); } bool subsume_loads = true; + bool do_escape_analysis = DoEscapeAnalysis; while (!env->failing()) { // Attempt to compile while subsuming loads into machine instructions. - Compile C(env, this, target, entry_bci, subsume_loads); + Compile C(env, this, target, entry_bci, subsume_loads, do_escape_analysis); // Check result and retry if appropriate. if (C.failure_reason() != NULL) { - if (C.failure_reason_is(retry_no_subsuming_loads())) { + if (C.failure_reason_is(retry_no_subsuming_loads())) { assert(subsume_loads, "must make progress"); subsume_loads = false; continue; // retry } + if (C.failure_reason_is(retry_no_escape_analysis())) { + assert(do_escape_analysis, "must make progress"); + do_escape_analysis = false; + continue; // retry + } // Pass any other failure reason up to the ciEnv. // Note that serious, irreversible failures are already logged // on the ciEnv via env->record_method_not_compilable(). diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/opto/c2compiler.hpp --- a/hotspot/src/share/vm/opto/c2compiler.hpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/opto/c2compiler.hpp Thu Mar 20 09:17:30 2008 -0500 @@ -50,6 +50,7 @@ // sentinel value used to trigger backtracking in compile_method(). static const char* retry_no_subsuming_loads(); + static const char* retry_no_escape_analysis(); // Print compilation timers and statistics void print_timers(); diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/opto/callnode.cpp --- a/hotspot/src/share/vm/opto/callnode.cpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/opto/callnode.cpp Thu Mar 20 09:17:30 2008 -0500 @@ -832,6 +832,7 @@ { init_class_id(Class_Allocate); init_flags(Flag_is_macro); + _is_scalar_replaceable = false; Node *topnode = C->top(); init_req( TypeFunc::Control , ctrl ); diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/opto/callnode.hpp --- a/hotspot/src/share/vm/opto/callnode.hpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/opto/callnode.hpp Thu Mar 20 09:17:30 2008 -0500 @@ -38,7 +38,7 @@ class CallLeafNode; class CallLeafNoFPNode; class AllocateNode; -class AllocateArrayNode; +class AllocateArrayNode; class LockNode; class UnlockNode; class JVMState; @@ -91,7 +91,9 @@ class ParmNode : public ProjNode { static const char * const names[TypeFunc::Parms+1]; public: - ParmNode( StartNode *src, uint con ) : ProjNode(src,con) {} + ParmNode( StartNode *src, uint con ) : ProjNode(src,con) { + init_class_id(Class_Parm); + } virtual int Opcode() const; virtual bool is_CFG() const { return (_con == TypeFunc::Control); } virtual uint ideal_reg() const; @@ -624,6 +626,8 @@ return TypeFunc::make(domain, range); } + bool _is_scalar_replaceable; // Result of Escape Analysis + virtual uint size_of() const; // Size is bigger AllocateNode(Compile* C, const TypeFunc *atype, Node *ctrl, Node *mem, Node *abio, Node *size, Node *klass_node, Node *initial_test); diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/opto/cfgnode.hpp --- a/hotspot/src/share/vm/opto/cfgnode.hpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/opto/cfgnode.hpp Thu Mar 20 09:17:30 2008 -0500 @@ -310,8 +310,14 @@ virtual const RegMask &out_RegMask() const; void dominated_by(Node* prev_dom, PhaseIterGVN* igvn); int is_range_check(Node* &range, Node* &index, jint &offset); + Node* fold_compares(PhaseGVN* phase); static Node* up_one_dom(Node* curr, bool linear_only = false); + // Takes the type of val and filters it through the test represented + // by if_proj and returns a more refined type if one is produced. + // Returns NULL is it couldn't improve the type. + static const TypeInt* filtered_int_type(PhaseGVN* phase, Node* val, Node* if_proj); + #ifndef PRODUCT virtual void dump_spec(outputStream *st) const; #endif diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/opto/compile.cpp --- a/hotspot/src/share/vm/opto/compile.cpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/opto/compile.cpp Thu Mar 20 09:17:30 2008 -0500 @@ -333,6 +333,12 @@ tty->print_cr("** Bailout: Recompile without subsuming loads **"); tty->print_cr("*********************************************************"); } + if (_do_escape_analysis != DoEscapeAnalysis && PrintOpto) { + // Recompiling without escape analysis + tty->print_cr("*********************************************************"); + tty->print_cr("** Bailout: Recompile without escape analysis **"); + tty->print_cr("*********************************************************"); + } if (env()->break_at_compile()) { // Open the debugger when compiing this method. tty->print("### Breaking when compiling: "); @@ -415,7 +421,7 @@ // the continuation bci for on stack replacement. -Compile::Compile( ciEnv* ci_env, C2Compiler* compiler, ciMethod* target, int osr_bci, bool subsume_loads ) +Compile::Compile( ciEnv* ci_env, C2Compiler* compiler, ciMethod* target, int osr_bci, bool subsume_loads, bool do_escape_analysis ) : Phase(Compiler), _env(ci_env), _log(ci_env->log()), @@ -430,6 +436,7 @@ _for_igvn(NULL), _warm_calls(NULL), _subsume_loads(subsume_loads), + _do_escape_analysis(do_escape_analysis), _failure_reason(NULL), _code_buffer("Compile::Fill_buffer"), _orig_pc_slot(0), @@ -487,7 +494,7 @@ PhaseGVN gvn(node_arena(), estimated_size); set_initial_gvn(&gvn); - if (DoEscapeAnalysis) + if (_do_escape_analysis) _congraph = new ConnectionGraph(this); { // Scope for timing the parser @@ -577,6 +584,8 @@ if (_congraph != NULL) { NOT_PRODUCT( TracePhase t2("escapeAnalysis", &_t_escapeAnalysis, TimeCompiler); ) _congraph->compute_escape(); + if (failing()) return; + #ifndef PRODUCT if (PrintEscapeAnalysis) { _congraph->dump(); @@ -675,6 +684,7 @@ _orig_pc_slot(0), _orig_pc_slot_offset_in_bytes(0), _subsume_loads(true), + _do_escape_analysis(false), _failure_reason(NULL), _code_buffer("Compile::Fill_buffer"), _node_bundling_limit(0), @@ -822,7 +832,7 @@ // Type::update_loaded_types(_method, _method->constants()); // Init alias_type map. - if (!DoEscapeAnalysis && aliaslevel == 3) + if (!_do_escape_analysis && aliaslevel == 3) aliaslevel = 2; // No unique types without escape analysis _AliasLevel = aliaslevel; const int grow_ats = 16; diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/opto/compile.hpp --- a/hotspot/src/share/vm/opto/compile.hpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/opto/compile.hpp Thu Mar 20 09:17:30 2008 -0500 @@ -31,6 +31,7 @@ class Int_Array; class Matcher; class MachNode; +class MachSafePointNode; class Node; class Node_Array; class Node_Notes; @@ -52,9 +53,6 @@ class Unique_Node_List; class nmethod; class WarmCallInfo; -#ifdef ENABLE_ZAP_DEAD_LOCALS -class MachSafePointNode; -#endif //------------------------------Compile---------------------------------------- // This class defines a top-level Compiler invocation. @@ -127,6 +125,7 @@ const int _compile_id; const bool _save_argument_registers; // save/restore arg regs for trampolines const bool _subsume_loads; // Load can be matched as part of a larger op. + const bool _do_escape_analysis; // Do escape analysis. ciMethod* _method; // The method being compiled. int _entry_bci; // entry bci for osr methods. const TypeFunc* _tf; // My kind of signature @@ -260,6 +259,8 @@ // instructions that subsume a load may result in an unschedulable // instruction sequence. bool subsume_loads() const { return _subsume_loads; } + // Do escape analysis. + bool do_escape_analysis() const { return _do_escape_analysis; } bool save_argument_registers() const { return _save_argument_registers; } @@ -560,7 +561,7 @@ // replacement, entry_bci indicates the bytecode for which to compile a // continuation. Compile(ciEnv* ci_env, C2Compiler* compiler, ciMethod* target, - int entry_bci, bool subsume_loads); + int entry_bci, bool subsume_loads, bool do_escape_analysis); // Second major entry point. From the TypeFunc signature, generate code // to pass arguments from the Java calling convention to the C calling diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/opto/connode.cpp --- a/hotspot/src/share/vm/opto/connode.cpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/opto/connode.cpp Thu Mar 20 09:17:30 2008 -0500 @@ -982,34 +982,9 @@ return new (phase->C, 3) AddINode(add1,add2); } - // Fold up with a prior LoadL: LoadL->ConvL2I ==> LoadI - // Requires we understand the 'endianess' of Longs. - if( andl_op == Op_LoadL ) { - Node *adr = andl->in(MemNode::Address); - // VM_LITTLE_ENDIAN is #defined appropriately in the Makefiles -#ifndef VM_LITTLE_ENDIAN - // The transformation can cause problems on BIG_ENDIAN architectures - // where the jint is not the same address as the jlong. Specifically, we - // will fail to insert an anti-dependence in GCM between the LoadI and a - // subsequent StoreL because different memory offsets provoke - // flatten_alias_type() into indicating two different types. See bug - // 4755222. - - // Node *base = adr->is_AddP() ? adr->in(AddPNode::Base) : adr; - // adr = phase->transform( new (phase->C, 4) AddPNode(base,adr,phase->MakeConX(sizeof(jint)))); - return NULL; -#else - if (phase->C->alias_type(andl->adr_type())->is_volatile()) { - // Picking up the low half by itself bypasses the atomic load and we could - // end up with more than one non-atomic load. See bugs 4432655 and 4526490. - // We could go to the trouble of iterating over andl's output edges and - // punting only if there's more than one real use, but we don't bother. - return NULL; - } - return new (phase->C, 3) LoadINode(andl->in(MemNode::Control),andl->in(MemNode::Memory),adr,((LoadLNode*)andl)->raw_adr_type()); -#endif - } - + // Disable optimization: LoadL->ConvL2I ==> LoadI. + // It causes problems (sizes of Load and Store nodes do not match) + // in objects initialization code and Escape Analysis. return NULL; } diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/opto/escape.cpp --- a/hotspot/src/share/vm/opto/escape.cpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/opto/escape.cpp Thu Mar 20 09:17:30 2008 -0500 @@ -395,6 +395,15 @@ if (result != NULL && C->get_alias_index(result->adr_type()) == alias_idx) { return result; } + if ((int)C->unique() + 2*NodeLimitFudgeFactor > MaxNodeLimit) { + if (C->do_escape_analysis() == true && !C->failing()) { + // Retry compilation without escape analysis. + // If this is the first failure, the sentinel string will "stick" + // to the Compile object, and the C2Compiler will see it and retry. + C->record_failure(C2Compiler::retry_no_escape_analysis()); + } + return NULL; + } orig_phi_worklist.append_if_missing(orig_phi); result = PhiNode::make(orig_phi->in(0), NULL, Type::MEMORY, atype); @@ -443,6 +452,9 @@ mem = nphi; } } + if (C->failing()) { + return NULL; + } result->set_req(idx++, mem); } #ifdef ASSERT @@ -589,6 +601,11 @@ if (es != PointsToNode::NoEscape || !ptn._unique_type) { continue; // can't make a unique type } + if (alloc->is_Allocate()) { + // Set the scalar_replaceable flag before the next check. + alloc->as_Allocate()->_is_scalar_replaceable = true; + } + set_map(alloc->_idx, n); set_map(n->_idx, alloc); const TypeInstPtr *t = igvn->type(n)->isa_instptr(); @@ -672,6 +689,9 @@ if (mem->is_Phi()) { mem = split_memory_phi(mem->as_Phi(), alias_idx, orig_phis, igvn); } + if (_compile->failing()) { + return; + } if (mem != n->in(MemNode::Memory)) set_map(n->_idx, mem); if (n->is_Load()) { @@ -742,7 +762,11 @@ if((uint)_compile->get_general_index(ni) == i) { Node *m = (ni >= nmm->req()) ? nmm->empty_memory() : nmm->in(ni); if (nmm->is_empty_memory(m)) { - nmm->set_memory_at(ni, split_memory_phi(mem->as_Phi(), ni, orig_phis, igvn)); + m = split_memory_phi(mem->as_Phi(), ni, orig_phis, igvn); + if (_compile->failing()) { + return; + } + nmm->set_memory_at(ni, m); } } } @@ -881,6 +905,11 @@ // Now use the escape information to create unique types for // unescaped objects split_unique_types(alloc_worklist); + if (_compile->failing()) return; + + // Clean up after split unique types. + ResourceMark rm; + PhaseRemoveUseless pru(_compile->initial_gvn(), _compile->for_igvn()); } Node * ConnectionGraph::skip_casts(Node *n) { diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/opto/gcm.cpp --- a/hotspot/src/share/vm/opto/gcm.cpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/opto/gcm.cpp Thu Mar 20 09:17:30 2008 -0500 @@ -448,9 +448,9 @@ ResourceArea *area = Thread::current()->resource_area(); Node_List worklist_mem(area); // prior memory state to store Node_List worklist_store(area); // possible-def to explore + Node_List worklist_visited(area); // visited mergemem nodes Node_List non_early_stores(area); // all relevant stores outside of early bool must_raise_LCA = false; - DEBUG_ONLY(VectorSet should_not_repeat(area)); #ifdef TRACK_PHI_INPUTS // %%% This extra checking fails because MergeMem nodes are not GVNed. @@ -479,8 +479,8 @@ Node* initial_mem = load->in(MemNode::Memory); worklist_store.push(initial_mem); + worklist_visited.push(initial_mem); worklist_mem.push(NULL); - DEBUG_ONLY(should_not_repeat.test_set(initial_mem->_idx)); while (worklist_store.size() > 0) { // Examine a nearby store to see if it might interfere with our load. Node* mem = worklist_mem.pop(); @@ -494,18 +494,20 @@ || op == Op_MergeMem // internal node of tree we are searching ) { mem = store; // It's not a possibly interfering store. + if (store == initial_mem) + initial_mem = NULL; // only process initial memory once + for (DUIterator_Fast imax, i = mem->fast_outs(imax); i < imax; i++) { store = mem->fast_out(i); if (store->is_MergeMem()) { // Be sure we don't get into combinatorial problems. // (Allow phis to be repeated; they can merge two relevant states.) - uint i = worklist_store.size(); - for (; i > 0; i--) { - if (worklist_store.at(i-1) == store) break; + uint j = worklist_visited.size(); + for (; j > 0; j--) { + if (worklist_visited.at(j-1) == store) break; } - if (i > 0) continue; // already on work list; do not repeat - DEBUG_ONLY(int repeated = should_not_repeat.test_set(store->_idx)); - assert(!repeated, "do not walk merges twice"); + if (j > 0) continue; // already on work list; do not repeat + worklist_visited.push(store); } worklist_mem.push(mem); worklist_store.push(store); diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/opto/graphKit.cpp --- a/hotspot/src/share/vm/opto/graphKit.cpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/opto/graphKit.cpp Thu Mar 20 09:17:30 2008 -0500 @@ -1447,7 +1447,7 @@ //-------------------------array_element_address------------------------- Node* GraphKit::array_element_address(Node* ary, Node* idx, BasicType elembt, const TypeInt* sizetype) { - uint shift = exact_log2(type2aelembytes[elembt]); + uint shift = exact_log2(type2aelembytes(elembt)); uint header = arrayOopDesc::base_offset_in_bytes(elembt); // short-circuit a common case (saves lots of confusing waste motion) @@ -2808,7 +2808,7 @@ ciInstanceKlass* ik = oop_type->klass()->as_instance_klass(); for (int i = 0, len = ik->nof_nonstatic_fields(); i < len; i++) { ciField* field = ik->nonstatic_field_at(i); - if (field->offset() >= TrackedInitializationLimit) + if (field->offset() >= TrackedInitializationLimit * HeapWordSize) continue; // do not bother to track really large numbers of fields // Find (or create) the alias category for this field: int fieldidx = C->alias_type(field)->index(); diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/opto/ifnode.cpp --- a/hotspot/src/share/vm/opto/ifnode.cpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/opto/ifnode.cpp Thu Mar 20 09:17:30 2008 -0500 @@ -543,6 +543,159 @@ return NULL; // Dead loop? Or hit root? } + +//------------------------------filtered_int_type-------------------------------- +// Return a possibly more restrictive type for val based on condition control flow for an if +const TypeInt* IfNode::filtered_int_type(PhaseGVN* gvn, Node *val, Node* if_proj) { + assert(if_proj && + (if_proj->Opcode() == Op_IfTrue || if_proj->Opcode() == Op_IfFalse), "expecting an if projection"); + if (if_proj->in(0) && if_proj->in(0)->is_If()) { + IfNode* iff = if_proj->in(0)->as_If(); + if (iff->in(1) && iff->in(1)->is_Bool()) { + BoolNode* bol = iff->in(1)->as_Bool(); + if (bol->in(1) && bol->in(1)->is_Cmp()) { + const CmpNode* cmp = bol->in(1)->as_Cmp(); + if (cmp->in(1) == val) { + const TypeInt* cmp2_t = gvn->type(cmp->in(2))->isa_int(); + if (cmp2_t != NULL) { + jint lo = cmp2_t->_lo; + jint hi = cmp2_t->_hi; + BoolTest::mask msk = if_proj->Opcode() == Op_IfTrue ? bol->_test._test : bol->_test.negate(); + switch (msk) { + case BoolTest::ne: + // Can't refine type + return NULL; + case BoolTest::eq: + return cmp2_t; + case BoolTest::lt: + lo = TypeInt::INT->_lo; + if (hi - 1 < hi) { + hi = hi - 1; + } + break; + case BoolTest::le: + lo = TypeInt::INT->_lo; + break; + case BoolTest::gt: + if (lo + 1 > lo) { + lo = lo + 1; + } + hi = TypeInt::INT->_hi; + break; + case BoolTest::ge: + // lo unchanged + hi = TypeInt::INT->_hi; + break; + } + const TypeInt* rtn_t = TypeInt::make(lo, hi, cmp2_t->_widen); + return rtn_t; + } + } + } + } + } + return NULL; +} + +//------------------------------fold_compares---------------------------- +// See if a pair of CmpIs can be converted into a CmpU. In some cases +// the direction of this if is determined by the preciding if so it +// can be eliminate entirely. Given an if testing (CmpI n c) check +// for an immediately control dependent if that is testing (CmpI n c2) +// and has one projection leading to this if and the other projection +// leading to a region that merges one of this ifs control +// projections. +// +// If +// / | +// / | +// / | +// If | +// /\ | +// / \ | +// / \ | +// / Region +// +Node* IfNode::fold_compares(PhaseGVN* phase) { + if (!EliminateAutoBox || Opcode() != Op_If) return NULL; + + Node* this_cmp = in(1)->in(1); + if (this_cmp != NULL && this_cmp->Opcode() == Op_CmpI && + this_cmp->in(2)->is_Con() && this_cmp->in(2) != phase->C->top()) { + Node* ctrl = in(0); + BoolNode* this_bool = in(1)->as_Bool(); + Node* n = this_cmp->in(1); + int hi = this_cmp->in(2)->get_int(); + if (ctrl != NULL && ctrl->is_Proj() && ctrl->outcnt() == 1 && + ctrl->in(0)->is_If() && + ctrl->in(0)->outcnt() == 2 && + ctrl->in(0)->in(1)->is_Bool() && + ctrl->in(0)->in(1)->in(1)->Opcode() == Op_CmpI && + ctrl->in(0)->in(1)->in(1)->in(2)->is_Con() && + ctrl->in(0)->in(1)->in(1)->in(1) == n) { + IfNode* dom_iff = ctrl->in(0)->as_If(); + Node* otherproj = dom_iff->proj_out(!ctrl->as_Proj()->_con); + if (otherproj->outcnt() == 1 && otherproj->unique_out()->is_Region() && + this_bool->_test._test != BoolTest::ne && this_bool->_test._test != BoolTest::eq) { + // Identify which proj goes to the region and which continues on + RegionNode* region = otherproj->unique_out()->as_Region(); + Node* success = NULL; + Node* fail = NULL; + for (int i = 0; i < 2; i++) { + Node* proj = proj_out(i); + if (success == NULL && proj->outcnt() == 1 && proj->unique_out() == region) { + success = proj; + } else if (fail == NULL) { + fail = proj; + } else { + success = fail = NULL; + } + } + if (success != NULL && fail != NULL && !region->has_phi()) { + int lo = dom_iff->in(1)->in(1)->in(2)->get_int(); + BoolNode* dom_bool = dom_iff->in(1)->as_Bool(); + Node* dom_cmp = dom_bool->in(1); + const TypeInt* failtype = filtered_int_type(phase, n, ctrl); + if (failtype != NULL) { + const TypeInt* type2 = filtered_int_type(phase, n, fail); + if (type2 != NULL) { + failtype = failtype->join(type2)->is_int(); + } else { + failtype = NULL; + } + } + + if (failtype != NULL && + dom_bool->_test._test != BoolTest::ne && dom_bool->_test._test != BoolTest::eq) { + int bound = failtype->_hi - failtype->_lo + 1; + if (failtype->_hi != max_jint && failtype->_lo != min_jint && bound > 1) { + // Merge the two compares into a single unsigned compare by building (CmpU (n - lo) hi) + BoolTest::mask cond = fail->as_Proj()->_con ? BoolTest::lt : BoolTest::ge; + Node* adjusted = phase->transform(new (phase->C, 3) SubINode(n, phase->intcon(failtype->_lo))); + Node* newcmp = phase->transform(new (phase->C, 3) CmpUNode(adjusted, phase->intcon(bound))); + Node* newbool = phase->transform(new (phase->C, 2) BoolNode(newcmp, cond)); + phase->hash_delete(dom_iff); + dom_iff->set_req(1, phase->intcon(ctrl->as_Proj()->_con)); + phase->is_IterGVN()->_worklist.push(dom_iff); + phase->hash_delete(this); + set_req(1, newbool); + return this; + } + if (failtype->_lo > failtype->_hi) { + // previous if determines the result of this if so + // replace Bool with constant + phase->hash_delete(this); + set_req(1, phase->intcon(success->as_Proj()->_con)); + return this; + } + } + } + } + } + } + return NULL; +} + //------------------------------remove_useless_bool---------------------------- // Check for people making a useless boolean: things like // if( (x < y ? true : false) ) { ... } @@ -744,6 +897,11 @@ // Normal equivalent-test check. if( !dom ) return NULL; // Dead loop? + Node* result = fold_compares(phase); + if (result != NULL) { + return result; + } + // Search up the dominator tree for an If with an identical test while( dom->Opcode() != op || // Not same opcode? dom->in(1) != in(1) || // Not same input 1? diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/opto/library_call.cpp --- a/hotspot/src/share/vm/opto/library_call.cpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/opto/library_call.cpp Thu Mar 20 09:17:30 2008 -0500 @@ -2097,7 +2097,7 @@ int type_words = type2size[type]; // Cannot inline wide CAS on machines that don't support it natively - if (type2aelembytes[type] > BytesPerInt && !VM_Version::supports_cx8()) + if (type2aelembytes(type) > BytesPerInt && !VM_Version::supports_cx8()) return false; C->set_has_unsafe_access(true); // Mark eventual nmethod as "unsafe". @@ -3975,7 +3975,7 @@ // both indices are constants int s_offs = src_offset_inttype->get_con(); int d_offs = dest_offset_inttype->get_con(); - int element_size = type2aelembytes[t]; + int element_size = type2aelembytes(t); aligned = ((arrayOopDesc::base_offset_in_bytes(t) + s_offs * element_size) % HeapWordSize == 0) && ((arrayOopDesc::base_offset_in_bytes(t) + d_offs * element_size) % HeapWordSize == 0); if (s_offs >= d_offs) disjoint = true; @@ -4170,6 +4170,7 @@ && !_gvn.eqv_uncast(src, dest) && ((alloc = tightly_coupled_allocation(dest, slow_region)) != NULL) + && _gvn.find_int_con(alloc->in(AllocateNode::ALength), 1) > 0 && alloc->maybe_set_complete(&_gvn)) { // "You break it, you buy it." InitializeNode* init = alloc->initialization(); @@ -4389,7 +4390,7 @@ if (alloc != NULL && use_ReduceInitialCardMarks()) { // If we do not need card marks, copy using the jint or jlong stub. copy_type = LP64_ONLY(T_LONG) NOT_LP64(T_INT); - assert(type2aelembytes[basic_elem_type] == type2aelembytes[copy_type], + assert(type2aelembytes(basic_elem_type) == type2aelembytes(copy_type), "sizes agree"); } } @@ -4659,7 +4660,7 @@ Node* mem = memory(adr_type); // memory slice to operate on // scaling and rounding of indexes: - int scale = exact_log2(type2aelembytes[basic_elem_type]); + int scale = exact_log2(type2aelembytes(basic_elem_type)); int abase = arrayOopDesc::base_offset_in_bytes(basic_elem_type); int clear_low = (-1 << scale) & (BytesPerInt - 1); int bump_bit = (-1 << scale) & BytesPerInt; @@ -4753,7 +4754,7 @@ Node* dest, Node* dest_offset, Node* dest_size) { // See if there is an advantage from block transfer. - int scale = exact_log2(type2aelembytes[basic_elem_type]); + int scale = exact_log2(type2aelembytes(basic_elem_type)); if (scale >= LogBytesPerLong) return false; // it is already a block transfer diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/opto/loopTransform.cpp --- a/hotspot/src/share/vm/opto/loopTransform.cpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/opto/loopTransform.cpp Thu Mar 20 09:17:30 2008 -0500 @@ -1714,6 +1714,7 @@ // Gate unrolling, RCE and peeling efforts. if( !_child && // If not an inner loop, do not split !_irreducible && + _allow_optimizations && !tail()->is_top() ) { // Also ignore the occasional dead backedge if (!_has_call) { iteration_split_impl( phase, old_new ); diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/opto/loopnode.cpp --- a/hotspot/src/share/vm/opto/loopnode.cpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/opto/loopnode.cpp Thu Mar 20 09:17:30 2008 -0500 @@ -651,7 +651,7 @@ while (if_cnt < if_limit) { if ((pred->Opcode() == Op_IfTrue || pred->Opcode() == Op_IfFalse)) { if_cnt++; - const TypeInt* if_t = filtered_type_at_if(val, pred); + const TypeInt* if_t = IfNode::filtered_int_type(&_igvn, val, pred); if (if_t != NULL) { if (rtn_t == NULL) { rtn_t = if_t; @@ -674,59 +674,6 @@ } -//------------------------------filtered_type_at_if-------------------------------- -// Return a possibly more restrictive type for val based on condition control flow for an if -const TypeInt* PhaseIdealLoop::filtered_type_at_if( Node* val, Node *if_proj) { - assert(if_proj && - (if_proj->Opcode() == Op_IfTrue || if_proj->Opcode() == Op_IfFalse), "expecting an if projection"); - if (if_proj->in(0) && if_proj->in(0)->is_If()) { - IfNode* iff = if_proj->in(0)->as_If(); - if (iff->in(1) && iff->in(1)->is_Bool()) { - BoolNode* bol = iff->in(1)->as_Bool(); - if (bol->in(1) && bol->in(1)->is_Cmp()) { - const CmpNode* cmp = bol->in(1)->as_Cmp(); - if (cmp->in(1) == val) { - const TypeInt* cmp2_t = _igvn.type(cmp->in(2))->isa_int(); - if (cmp2_t != NULL) { - jint lo = cmp2_t->_lo; - jint hi = cmp2_t->_hi; - BoolTest::mask msk = if_proj->Opcode() == Op_IfTrue ? bol->_test._test : bol->_test.negate(); - switch (msk) { - case BoolTest::ne: - // Can't refine type - return NULL; - case BoolTest::eq: - return cmp2_t; - case BoolTest::lt: - lo = TypeInt::INT->_lo; - if (hi - 1 < hi) { - hi = hi - 1; - } - break; - case BoolTest::le: - lo = TypeInt::INT->_lo; - break; - case BoolTest::gt: - if (lo + 1 > lo) { - lo = lo + 1; - } - hi = TypeInt::INT->_hi; - break; - case BoolTest::ge: - // lo unchanged - hi = TypeInt::INT->_hi; - break; - } - const TypeInt* rtn_t = TypeInt::make(lo, hi, cmp2_t->_widen); - return rtn_t; - } - } - } - } - } - return NULL; -} - //------------------------------dump_spec-------------------------------------- // Dump special per-node info #ifndef PRODUCT @@ -1614,7 +1561,7 @@ // on just their loop-phi's for this pass of loop opts if( SplitIfBlocks && do_split_ifs ) { if (lpt->policy_range_check(this)) { - lpt->_rce_candidate = true; + lpt->_rce_candidate = 1; // = true } } } @@ -2198,7 +2145,7 @@ // as well? If so, then I found another entry into the loop. while( is_postvisited(l->_head) ) { // found irreducible - l->_irreducible = true; + l->_irreducible = 1; // = true l = l->_parent; _has_irreducible_loops = true; // Check for bad CFG here to prevent crash, and bailout of compile @@ -2252,6 +2199,12 @@ (iff->as_If()->_prob >= 0.01) ) innermost->_has_call = 1; } + } else if( n->is_Allocate() && n->as_Allocate()->_is_scalar_replaceable ) { + // Disable loop optimizations if the loop has a scalar replaceable + // allocation. This disabling may cause a potential performance lost + // if the allocation is not eliminated for some reason. + innermost->_allow_optimizations = false; + innermost->_has_call = 1; // = true } } } diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/opto/loopnode.hpp --- a/hotspot/src/share/vm/opto/loopnode.hpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/opto/loopnode.hpp Thu Mar 20 09:17:30 2008 -0500 @@ -289,13 +289,15 @@ _has_sfpt:1, // True if has non-call safepoint _rce_candidate:1; // True if candidate for range check elimination - Node_List* _required_safept; // A inner loop cannot delete these safepts; + Node_List* _required_safept; // A inner loop cannot delete these safepts; + bool _allow_optimizations; // Allow loop optimizations IdealLoopTree( PhaseIdealLoop* phase, Node *head, Node *tail ) : _parent(0), _next(0), _child(0), _head(head), _tail(tail), _phase(phase), _required_safept(NULL), + _allow_optimizations(true), _nest(0), _irreducible(0), _has_call(0), _has_sfpt(0), _rce_candidate(0) { } @@ -850,7 +852,6 @@ const TypeInt* filtered_type( Node *n ) { return filtered_type(n, NULL); } // Helpers for filtered type const TypeInt* filtered_type_from_dominators( Node* val, Node *val_ctrl); - const TypeInt* filtered_type_at_if( Node* val, Node *if_proj); // Helper functions void register_new_node( Node *n, Node *blk ); diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/opto/loopopts.cpp --- a/hotspot/src/share/vm/opto/loopopts.cpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/opto/loopopts.cpp Thu Mar 20 09:17:30 2008 -0500 @@ -435,9 +435,11 @@ // Check profitability int cost = 0; + int phis = 0; for (DUIterator_Fast imax, i = region->fast_outs(imax); i < imax; i++) { Node *out = region->fast_out(i); if( !out->is_Phi() ) continue; // Ignore other control edges, etc + phis++; PhiNode* phi = out->as_Phi(); switch (phi->type()->basic_type()) { case T_LONG: @@ -489,6 +491,12 @@ } } if( cost >= ConditionalMoveLimit ) return NULL; // Too much goo + Node* bol = iff->in(1); + assert( bol->Opcode() == Op_Bool, "" ); + int cmp_op = bol->in(1)->Opcode(); + // It is expensive to generate flags from a float compare. + // Avoid duplicated float compare. + if( phis > 1 && (cmp_op == Op_CmpF || cmp_op == Op_CmpD)) return NULL; // -------------- // Now replace all Phis with CMOV's diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/opto/memnode.cpp --- a/hotspot/src/share/vm/opto/memnode.cpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/opto/memnode.cpp Thu Mar 20 09:17:30 2008 -0500 @@ -108,19 +108,13 @@ // Avoid independent memory operations Node* old_mem = mem; - if (mem->is_Proj() && mem->in(0)->is_Initialize()) { - InitializeNode* init = mem->in(0)->as_Initialize(); - if (init->is_complete()) { // i.e., after macro expansion - const TypePtr* tp = t_adr->is_ptr(); - uint alias_idx = phase->C->get_alias_index(tp); - // Free this slice from the init. It was hooked, temporarily, - // by GraphKit::set_output_for_allocation. - if (alias_idx > Compile::AliasIdxRaw) { - mem = init->memory(alias_idx); - // ...but not with the raw-pointer slice. - } - } - } + // The code which unhooks non-raw memories from complete (macro-expanded) + // initializations was removed. After macro-expansion all stores catched + // by Initialize node became raw stores and there is no information + // which memory slices they modify. So it is unsafe to move any memory + // operation above these stores. Also in most cases hooked non-raw memories + // were already unhooked by using information from detect_ptr_independence() + // and find_previous_store(). if (mem->is_MergeMem()) { MergeMemNode* mmem = mem->as_MergeMem(); @@ -634,6 +628,46 @@ Node* MemNode::can_see_stored_value(Node* st, PhaseTransform* phase) const { Node* ld_adr = in(MemNode::Address); + const TypeInstPtr* tp = phase->type(ld_adr)->isa_instptr(); + Compile::AliasType* atp = tp != NULL ? phase->C->alias_type(tp) : NULL; + if (EliminateAutoBox && atp != NULL && atp->index() >= Compile::AliasIdxRaw && + atp->field() != NULL && !atp->field()->is_volatile()) { + uint alias_idx = atp->index(); + bool final = atp->field()->is_final(); + Node* result = NULL; + Node* current = st; + // Skip through chains of MemBarNodes checking the MergeMems for + // new states for the slice of this load. Stop once any other + // kind of node is encountered. Loads from final memory can skip + // through any kind of MemBar but normal loads shouldn't skip + // through MemBarAcquire since the could allow them to move out of + // a synchronized region. + while (current->is_Proj()) { + int opc = current->in(0)->Opcode(); + if ((final && opc == Op_MemBarAcquire) || + opc == Op_MemBarRelease || opc == Op_MemBarCPUOrder) { + Node* mem = current->in(0)->in(TypeFunc::Memory); + if (mem->is_MergeMem()) { + MergeMemNode* merge = mem->as_MergeMem(); + Node* new_st = merge->memory_at(alias_idx); + if (new_st == merge->base_memory()) { + // Keep searching + current = merge->base_memory(); + continue; + } + // Save the new memory state for the slice and fall through + // to exit. + result = new_st; + } + } + break; + } + if (result != NULL) { + st = result; + } + } + + // Loop around twice in the case Load -> Initialize -> Store. // (See PhaseIterGVN::add_users_to_worklist, which knows about this case.) for (int trip = 0; trip <= 1; trip++) { @@ -723,6 +757,168 @@ return this; } + +// Returns true if the AliasType refers to the field that holds the +// cached box array. Currently only handles the IntegerCache case. +static bool is_autobox_cache(Compile::AliasType* atp) { + if (atp != NULL && atp->field() != NULL) { + ciField* field = atp->field(); + ciSymbol* klass = field->holder()->name(); + if (field->name() == ciSymbol::cache_field_name() && + field->holder()->uses_default_loader() && + klass == ciSymbol::java_lang_Integer_IntegerCache()) { + return true; + } + } + return false; +} + +// Fetch the base value in the autobox array +static bool fetch_autobox_base(Compile::AliasType* atp, int& cache_offset) { + if (atp != NULL && atp->field() != NULL) { + ciField* field = atp->field(); + ciSymbol* klass = field->holder()->name(); + if (field->name() == ciSymbol::cache_field_name() && + field->holder()->uses_default_loader() && + klass == ciSymbol::java_lang_Integer_IntegerCache()) { + assert(field->is_constant(), "what?"); + ciObjArray* array = field->constant_value().as_object()->as_obj_array(); + // Fetch the box object at the base of the array and get its value + ciInstance* box = array->obj_at(0)->as_instance(); + ciInstanceKlass* ik = box->klass()->as_instance_klass(); + if (ik->nof_nonstatic_fields() == 1) { + // This should be true nonstatic_field_at requires calling + // nof_nonstatic_fields so check it anyway + ciConstant c = box->field_value(ik->nonstatic_field_at(0)); + cache_offset = c.as_int(); + } + return true; + } + } + return false; +} + +// Returns true if the AliasType refers to the value field of an +// autobox object. Currently only handles Integer. +static bool is_autobox_object(Compile::AliasType* atp) { + if (atp != NULL && atp->field() != NULL) { + ciField* field = atp->field(); + ciSymbol* klass = field->holder()->name(); + if (field->name() == ciSymbol::value_name() && + field->holder()->uses_default_loader() && + klass == ciSymbol::java_lang_Integer()) { + return true; + } + } + return false; +} + + +// We're loading from an object which has autobox behaviour. +// If this object is result of a valueOf call we'll have a phi +// merging a newly allocated object and a load from the cache. +// We want to replace this load with the original incoming +// argument to the valueOf call. +Node* LoadNode::eliminate_autobox(PhaseGVN* phase) { + Node* base = in(Address)->in(AddPNode::Base); + if (base->is_Phi() && base->req() == 3) { + AllocateNode* allocation = NULL; + int allocation_index = -1; + int load_index = -1; + for (uint i = 1; i < base->req(); i++) { + allocation = AllocateNode::Ideal_allocation(base->in(i), phase); + if (allocation != NULL) { + allocation_index = i; + load_index = 3 - allocation_index; + break; + } + } + LoadNode* load = NULL; + if (allocation != NULL && base->in(load_index)->is_Load()) { + load = base->in(load_index)->as_Load(); + } + if (load != NULL && in(Memory)->is_Phi() && in(Memory)->in(0) == base->in(0)) { + // Push the loads from the phi that comes from valueOf up + // through it to allow elimination of the loads and the recovery + // of the original value. + Node* mem_phi = in(Memory); + Node* offset = in(Address)->in(AddPNode::Offset); + + Node* in1 = clone(); + Node* in1_addr = in1->in(Address)->clone(); + in1_addr->set_req(AddPNode::Base, base->in(allocation_index)); + in1_addr->set_req(AddPNode::Address, base->in(allocation_index)); + in1_addr->set_req(AddPNode::Offset, offset); + in1->set_req(0, base->in(allocation_index)); + in1->set_req(Address, in1_addr); + in1->set_req(Memory, mem_phi->in(allocation_index)); + + Node* in2 = clone(); + Node* in2_addr = in2->in(Address)->clone(); + in2_addr->set_req(AddPNode::Base, base->in(load_index)); + in2_addr->set_req(AddPNode::Address, base->in(load_index)); + in2_addr->set_req(AddPNode::Offset, offset); + in2->set_req(0, base->in(load_index)); + in2->set_req(Address, in2_addr); + in2->set_req(Memory, mem_phi->in(load_index)); + + in1_addr = phase->transform(in1_addr); + in1 = phase->transform(in1); + in2_addr = phase->transform(in2_addr); + in2 = phase->transform(in2); + + PhiNode* result = PhiNode::make_blank(base->in(0), this); + result->set_req(allocation_index, in1); + result->set_req(load_index, in2); + return result; + } + } else if (base->is_Load()) { + // Eliminate the load of Integer.value for integers from the cache + // array by deriving the value from the index into the array. + // Capture the offset of the load and then reverse the computation. + Node* load_base = base->in(Address)->in(AddPNode::Base); + if (load_base != NULL) { + Compile::AliasType* atp = phase->C->alias_type(load_base->adr_type()); + intptr_t cache_offset; + int shift = -1; + Node* cache = NULL; + if (is_autobox_cache(atp)) { + shift = exact_log2(type2aelembytes(T_OBJECT)); + cache = AddPNode::Ideal_base_and_offset(load_base->in(Address), phase, cache_offset); + } + if (cache != NULL && base->in(Address)->is_AddP()) { + Node* elements[4]; + int count = base->in(Address)->as_AddP()->unpack_offsets(elements, ARRAY_SIZE(elements)); + int cache_low; + if (count > 0 && fetch_autobox_base(atp, cache_low)) { + int offset = arrayOopDesc::base_offset_in_bytes(memory_type()) - (cache_low << shift); + // Add up all the offsets making of the address of the load + Node* result = elements[0]; + for (int i = 1; i < count; i++) { + result = phase->transform(new (phase->C, 3) AddXNode(result, elements[i])); + } + // Remove the constant offset from the address and then + // remove the scaling of the offset to recover the original index. + result = phase->transform(new (phase->C, 3) AddXNode(result, phase->MakeConX(-offset))); + if (result->Opcode() == Op_LShiftX && result->in(2) == phase->intcon(shift)) { + // Peel the shift off directly but wrap it in a dummy node + // since Ideal can't return existing nodes + result = new (phase->C, 3) RShiftXNode(result->in(1), phase->intcon(0)); + } else { + result = new (phase->C, 3) RShiftXNode(result, phase->intcon(shift)); + } +#ifdef _LP64 + result = new (phase->C, 2) ConvL2INode(phase->transform(result)); +#endif + return result; + } + } + } + } + return NULL; +} + + //------------------------------Ideal------------------------------------------ // If the load is from Field memory and the pointer is non-null, we can // zero out the control input. @@ -755,6 +951,17 @@ } } + if (EliminateAutoBox && can_reshape && in(Address)->is_AddP()) { + Node* base = in(Address)->in(AddPNode::Base); + if (base != NULL) { + Compile::AliasType* atp = phase->C->alias_type(adr_type()); + if (is_autobox_object(atp)) { + Node* result = eliminate_autobox(phase); + if (result != NULL) return result; + } + } + } + // Check for prior store with a different base or offset; make Load // independent. Skip through any number of them. Bail out if the stores // are in an endless dead cycle and report no progress. This is a key @@ -858,6 +1065,17 @@ // This can happen if a interface-typed array narrows to a class type. jt = _type; } + + if (EliminateAutoBox) { + // The pointers in the autobox arrays are always non-null + Node* base = in(Address)->in(AddPNode::Base); + if (base != NULL) { + Compile::AliasType* atp = phase->C->alias_type(base->adr_type()); + if (is_autobox_cache(atp)) { + return jt->join(TypePtr::NOTNULL)->is_ptr(); + } + } + } return jt; } } @@ -1553,9 +1771,16 @@ //------------------------------Value----------------------------------------- const Type *StoreCMNode::Value( PhaseTransform *phase ) const { + // Either input is TOP ==> the result is TOP + const Type *t = phase->type( in(MemNode::Memory) ); + if( t == Type::TOP ) return Type::TOP; + t = phase->type( in(MemNode::Address) ); + if( t == Type::TOP ) return Type::TOP; + t = phase->type( in(MemNode::ValueIn) ); + if( t == Type::TOP ) return Type::TOP; // If extra input is TOP ==> the result is TOP - const Type *t1 = phase->type( in(MemNode::OopStore) ); - if( t1 == Type::TOP ) return Type::TOP; + t = phase->type( in(MemNode::OopStore) ); + if( t == Type::TOP ) return Type::TOP; return StoreNode::Value( phase ); } diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/opto/memnode.hpp --- a/hotspot/src/share/vm/opto/memnode.hpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/opto/memnode.hpp Thu Mar 20 09:17:30 2008 -0500 @@ -60,13 +60,13 @@ debug_only(_adr_type=at; adr_type();) } +public: // Helpers for the optimizer. Documented in memnode.cpp. static bool detect_ptr_independence(Node* p1, AllocateNode* a1, Node* p2, AllocateNode* a2, PhaseTransform* phase); static bool adr_phi_is_loop_invariant(Node* adr_phi, Node* cast); -public: // This one should probably be a phase-specific function: static bool detect_dominating_control(Node* dom, Node* sub); @@ -97,7 +97,13 @@ // What is the type of the value in memory? (T_VOID mean "unspecified".) virtual BasicType memory_type() const = 0; - virtual int memory_size() const { return type2aelembytes[memory_type()]; } + virtual int memory_size() const { +#ifdef ASSERT + return type2aelembytes(memory_type(), true); +#else + return type2aelembytes(memory_type()); +#endif + } // Search through memory states which precede this node (load or store). // Look for an exact match for the address, with no intervening @@ -141,6 +147,9 @@ // zero out the control input. virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); + // Recover original value from boxed values + Node *eliminate_autobox(PhaseGVN *phase); + // Compute a new Type for this node. Basically we just do the pre-check, // then call the virtual add() to set the type. virtual const Type *Value( PhaseTransform *phase ) const; diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/opto/node.cpp --- a/hotspot/src/share/vm/opto/node.cpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/opto/node.cpp Thu Mar 20 09:17:30 2008 -0500 @@ -1462,97 +1462,48 @@ } //------------------------------dump_nodes------------------------------------- - -// Helper class for dump_nodes. Wraps an old and new VectorSet. -class OldNewVectorSet : public StackObj { - Arena* _node_arena; - VectorSet _old_vset, _new_vset; - VectorSet* select(Node* n) { - return _node_arena->contains(n) ? &_new_vset : &_old_vset; - } - public: - OldNewVectorSet(Arena* node_arena, ResourceArea* area) : - _node_arena(node_arena), - _old_vset(area), _new_vset(area) {} - - void set(Node* n) { select(n)->set(n->_idx); } - bool test_set(Node* n) { return select(n)->test_set(n->_idx) != 0; } - bool test(Node* n) { return select(n)->test(n->_idx) != 0; } - void del(Node* n) { (*select(n)) >>= n->_idx; } -}; - - static void dump_nodes(const Node* start, int d, bool only_ctrl) { Node* s = (Node*)start; // remove const if (NotANode(s)) return; + uint depth = (uint)ABS(d); + int direction = d; Compile* C = Compile::current(); - ResourceArea *area = Thread::current()->resource_area(); - Node_Stack stack(area, MIN2((uint)ABS(d), C->unique() >> 1)); - OldNewVectorSet visited(C->node_arena(), area); - OldNewVectorSet on_stack(C->node_arena(), area); - - visited.set(s); - on_stack.set(s); - stack.push(s, 0); - if (d < 0) s->dump(); - - // Do a depth first walk over edges - while (stack.is_nonempty()) { - Node* tp = stack.node(); - uint idx = stack.index(); - uint limit = d > 0 ? tp->len() : tp->outcnt(); - if (idx >= limit) { - // no more arcs to visit - if (d > 0) tp->dump(); - on_stack.del(tp); - stack.pop(); - } else { - // process the "idx"th arc - stack.set_index(idx + 1); - Node* n = d > 0 ? tp->in(idx) : tp->raw_out(idx); - - if (NotANode(n)) continue; - // do not recurse through top or the root (would reach unrelated stuff) - if (n->is_Root() || n->is_top()) continue; - if (only_ctrl && !n->is_CFG()) continue; + GrowableArray nstack(C->unique()); - if (!visited.test_set(n)) { // forward arc - // Limit depth - if (stack.size() < (uint)ABS(d)) { - if (d < 0) n->dump(); - stack.push(n, 0); - on_stack.set(n); - } - } else { // back or cross arc - if (on_stack.test(n)) { // back arc - // print loop if there are no phis or regions in the mix - bool found_loop_breaker = false; - int k; - for (k = stack.size() - 1; k >= 0; k--) { - Node* m = stack.node_at(k); - if (m->is_Phi() || m->is_Region() || m->is_Root() || m->is_Start()) { - found_loop_breaker = true; - break; - } - if (m == n) // Found loop head - break; - } - assert(k >= 0, "n must be on stack"); + nstack.append(s); + int begin = 0; + int end = 0; + for(uint i = 0; i < depth; i++) { + end = nstack.length(); + for(int j = begin; j < end; j++) { + Node* tp = nstack.at(j); + uint limit = direction > 0 ? tp->len() : tp->outcnt(); + for(uint k = 0; k < limit; k++) { + Node* n = direction > 0 ? tp->in(k) : tp->raw_out(k); - if (!found_loop_breaker) { - tty->print("# %s LOOP FOUND:", only_ctrl ? "CONTROL" : "DATA"); - for (int i = stack.size() - 1; i >= k; i--) { - Node* m = stack.node_at(i); - bool mnew = C->node_arena()->contains(m); - tty->print(" %s%d:%s", (mnew? "": "o"), m->_idx, m->Name()); - if (i != 0) tty->print(d > 0? " <-": " ->"); - } - tty->cr(); - } + if (NotANode(n)) continue; + // do not recurse through top or the root (would reach unrelated stuff) + if (n->is_Root() || n->is_top()) continue; + if (only_ctrl && !n->is_CFG()) continue; + + bool on_stack = nstack.contains(n); + if (!on_stack) { + nstack.append(n); } } } + begin = end; + } + end = nstack.length(); + if (direction > 0) { + for(int j = end-1; j >= 0; j--) { + nstack.at(j)->dump(); + } + } else { + for(int j = 0; j < end; j++) { + nstack.at(j)->dump(); + } } } diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/opto/node.hpp --- a/hotspot/src/share/vm/opto/node.hpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/opto/node.hpp Thu Mar 20 09:17:30 2008 -0500 @@ -91,6 +91,7 @@ class Node_Stack; class NullCheckNode; class OopMap; +class ParmNode; class PCTableNode; class PhaseCCP; class PhaseGVN; @@ -557,6 +558,7 @@ DEFINE_CLASS_ID(JumpProj, Proj, 1) DEFINE_CLASS_ID(IfTrue, Proj, 2) DEFINE_CLASS_ID(IfFalse, Proj, 3) + DEFINE_CLASS_ID(Parm, Proj, 4) DEFINE_CLASS_ID(Region, Node, 3) DEFINE_CLASS_ID(Loop, Region, 0) @@ -712,6 +714,7 @@ DEFINE_CLASS_QUERY(Mul) DEFINE_CLASS_QUERY(Multi) DEFINE_CLASS_QUERY(MultiBranch) + DEFINE_CLASS_QUERY(Parm) DEFINE_CLASS_QUERY(PCTable) DEFINE_CLASS_QUERY(Phi) DEFINE_CLASS_QUERY(Proj) @@ -1381,7 +1384,7 @@ _inode_top->indx = i; } uint size_max() const { return (uint)pointer_delta(_inode_max, _inodes, sizeof(INode)); } // Max size - uint size() const { return (uint)pointer_delta(_inode_top, _inodes, sizeof(INode)) + 1; } // Current size + uint size() const { return (uint)pointer_delta((_inode_top+1), _inodes, sizeof(INode)); } // Current size bool is_nonempty() const { return (_inode_top >= _inodes); } bool is_empty() const { return (_inode_top < _inodes); } void clear() { _inode_top = _inodes - 1; } // retain storage diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/opto/output.cpp --- a/hotspot/src/share/vm/opto/output.cpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/opto/output.cpp Thu Mar 20 09:17:30 2008 -0500 @@ -921,11 +921,8 @@ // blown the code cache size. C->record_failure("excessive request to CodeCache"); } else { - UseInterpreter = true; - UseCompiler = false; - AlwaysCompileLoopMethods = false; + // Let CompilerBroker disable further compilations. C->record_failure("CodeCache is full"); - warning("CodeCache is full. Compiling has been disabled"); } } diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/opto/parse.hpp --- a/hotspot/src/share/vm/opto/parse.hpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/opto/parse.hpp Thu Mar 20 09:17:30 2008 -0500 @@ -54,9 +54,9 @@ InlineTree *build_inline_tree_for_callee(ciMethod* callee_method, JVMState* caller_jvms, int caller_bci); - const char* try_to_inline(ciMethod* callee_method, int caller_bci, ciCallProfile& profile, WarmCallInfo* wci_result); - const char* shouldInline(ciMethod* callee_method, int caller_bci, ciCallProfile& profile, WarmCallInfo* wci_result) const; - const char* shouldNotInline(ciMethod* callee_method, WarmCallInfo* wci_result) const; + const char* try_to_inline(ciMethod* callee_method, ciMethod* caller_method, int caller_bci, ciCallProfile& profile, WarmCallInfo* wci_result); + const char* shouldInline(ciMethod* callee_method, ciMethod* caller_method, int caller_bci, ciCallProfile& profile, WarmCallInfo* wci_result) const; + const char* shouldNotInline(ciMethod* callee_method, ciMethod* caller_method, WarmCallInfo* wci_result) const; void print_inlining(ciMethod *callee_method, int caller_bci, const char *failure_msg) const PRODUCT_RETURN; InlineTree *caller_tree() const { return _caller_tree; } diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/opto/parse1.cpp --- a/hotspot/src/share/vm/opto/parse1.cpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/opto/parse1.cpp Thu Mar 20 09:17:30 2008 -0500 @@ -1836,7 +1836,7 @@ PhiNode* phi = PhiNode::make(region, o, t); gvn().set_type(phi, t); - if (DoEscapeAnalysis) record_for_igvn(phi); + if (C->do_escape_analysis()) record_for_igvn(phi); map->set_req(idx, phi); return phi; } diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/opto/parse2.cpp --- a/hotspot/src/share/vm/opto/parse2.cpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/opto/parse2.cpp Thu Mar 20 09:17:30 2008 -0500 @@ -885,6 +885,9 @@ void Parse::do_ifnull(BoolTest::mask btest) { int target_bci = iter().get_dest(); + Block* branch_block = successor_for_bci(target_bci); + Block* next_block = successor_for_bci(iter().next_bci()); + float cnt; float prob = branch_prediction(cnt, btest, target_bci); if (prob == PROB_UNKNOWN) { @@ -902,13 +905,16 @@ uncommon_trap(Deoptimization::Reason_unreached, Deoptimization::Action_reinterpret, NULL, "cold"); + if (EliminateAutoBox) { + // Mark the successor blocks as parsed + branch_block->next_path_num(); + next_block->next_path_num(); + } return; } // If this is a backwards branch in the bytecodes, add Safepoint maybe_add_safepoint(target_bci); - Block* branch_block = successor_for_bci(target_bci); - Block* next_block = successor_for_bci(iter().next_bci()); explicit_null_checks_inserted++; Node* a = null(); @@ -935,6 +941,10 @@ if (stopped()) { // Path is dead? explicit_null_checks_elided++; + if (EliminateAutoBox) { + // Mark the successor block as parsed + branch_block->next_path_num(); + } } else { // Path is live. // Update method data profile_taken_branch(target_bci); @@ -950,6 +960,10 @@ if (stopped()) { // Path is dead? explicit_null_checks_elided++; + if (EliminateAutoBox) { + // Mark the successor block as parsed + next_block->next_path_num(); + } } else { // Path is live. // Update method data profile_not_taken_branch(); @@ -962,6 +976,9 @@ void Parse::do_if(BoolTest::mask btest, Node* c) { int target_bci = iter().get_dest(); + Block* branch_block = successor_for_bci(target_bci); + Block* next_block = successor_for_bci(iter().next_bci()); + float cnt; float prob = branch_prediction(cnt, btest, target_bci); float untaken_prob = 1.0 - prob; @@ -980,6 +997,11 @@ uncommon_trap(Deoptimization::Reason_unreached, Deoptimization::Action_reinterpret, NULL, "cold"); + if (EliminateAutoBox) { + // Mark the successor blocks as parsed + branch_block->next_path_num(); + next_block->next_path_num(); + } return; } @@ -1000,10 +1022,27 @@ Node* tst = _gvn.transform(tst0); BoolTest::mask taken_btest = BoolTest::illegal; BoolTest::mask untaken_btest = BoolTest::illegal; - if (btest == BoolTest::ne) { - // For now, these are the only cases of btest that matter. (More later.) - taken_btest = taken_if_true ? btest : BoolTest::eq; - untaken_btest = taken_if_true ? BoolTest::eq : btest; + + if (tst->is_Bool()) { + // Refresh c from the transformed bool node, since it may be + // simpler than the original c. Also re-canonicalize btest. + // This wins when (Bool ne (Conv2B p) 0) => (Bool ne (CmpP p NULL)). + // That can arise from statements like: if (x instanceof C) ... + if (tst != tst0) { + // Canonicalize one more time since transform can change it. + btest = tst->as_Bool()->_test._test; + if (!BoolTest(btest).is_canonical()) { + // Reverse edges one more time... + tst = _gvn.transform( tst->as_Bool()->negate(&_gvn) ); + btest = tst->as_Bool()->_test._test; + assert(BoolTest(btest).is_canonical(), "sanity"); + taken_if_true = !taken_if_true; + } + c = tst->in(1); + } + BoolTest::mask neg_btest = BoolTest(btest).negate(); + taken_btest = taken_if_true ? btest : neg_btest; + untaken_btest = taken_if_true ? neg_btest : btest; } // Generate real control flow @@ -1018,15 +1057,17 @@ untaken_branch = tmp; } - Block* branch_block = successor_for_bci(target_bci); - Block* next_block = successor_for_bci(iter().next_bci()); - // Branch is taken: { PreserveJVMState pjvms(this); taken_branch = _gvn.transform(taken_branch); set_control(taken_branch); - if (!stopped()) { + if (stopped()) { + if (EliminateAutoBox) { + // Mark the successor block as parsed + branch_block->next_path_num(); + } + } else { // Update method data profile_taken_branch(target_bci); adjust_map_after_if(taken_btest, c, prob, branch_block, next_block); @@ -1039,7 +1080,12 @@ set_control(untaken_branch); // Branch not taken. - if (!stopped()) { + if (stopped()) { + if (EliminateAutoBox) { + // Mark the successor block as parsed + next_block->next_path_num(); + } + } else { // Update method data profile_not_taken_branch(); adjust_map_after_if(untaken_btest, c, untaken_prob, diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/opto/phaseX.cpp --- a/hotspot/src/share/vm/opto/phaseX.cpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/opto/phaseX.cpp Thu Mar 20 09:17:30 2008 -0500 @@ -648,79 +648,9 @@ //============================================================================= //------------------------------transform-------------------------------------- // Return a node which computes the same function as this node, but in a -// faster or cheaper fashion. The Node passed in here must have no other -// pointers to it, as its storage will be reclaimed if the Node can be -// optimized away. +// faster or cheaper fashion. Node *PhaseGVN::transform( Node *n ) { - NOT_PRODUCT( set_transforms(); ) - - // Apply the Ideal call in a loop until it no longer applies - Node *k = n; - NOT_PRODUCT( uint loop_count = 0; ) - while( 1 ) { - Node *i = k->Ideal(this, /*can_reshape=*/false); - if( !i ) break; - assert( i->_idx >= k->_idx, "Idealize should return new nodes, use Identity to return old nodes" ); - // Can never reclaim storage for Ideal calls, because the Ideal call - // returns a new Node, bumping the High Water Mark and our old Node - // is caught behind the new one. - //if( k != i ) { - //k->destruct(); // Reclaim storage for recent node - k = i; - //} - assert(loop_count++ < K, "infinite loop in PhaseGVN::transform"); - } - NOT_PRODUCT( if( loop_count != 0 ) { set_progress(); } ) - - // If brand new node, make space in type array. - ensure_type_or_null(k); - - // Cache result of Value call since it can be expensive - // (abstract interpretation of node 'k' using phase->_types[ inputs ]) - const Type *t = k->Value(this); // Get runtime Value set - assert(t != NULL, "value sanity"); - if (type_or_null(k) != t) { -#ifndef PRODUCT - // Do not record transformation or value construction on first visit - if (type_or_null(k) == NULL) { - inc_new_values(); - set_progress(); - } -#endif - set_type(k, t); - // If k is a TypeNode, capture any more-precise type permanently into Node - k->raise_bottom_type(t); - } - - if( t->singleton() && !k->is_Con() ) { - //k->destruct(); // Reclaim storage for recent node - NOT_PRODUCT( set_progress(); ) - return makecon(t); // Turn into a constant - } - - // Now check for Identities - Node *i = k->Identity(this); // Look for a nearby replacement - if( i != k ) { // Found? Return replacement! - //k->destruct(); // Reclaim storage for recent node - NOT_PRODUCT( set_progress(); ) - return i; - } - - // Try Global Value Numbering - i = hash_find_insert(k); // Found older value when i != NULL - if( i && i != k ) { // Hit? Return the old guy - NOT_PRODUCT( set_progress(); ) - return i; - } - - // Collect points-to information for escape analysys - ConnectionGraph *cgr = C->congraph(); - if (cgr != NULL) { - cgr->record_escape(k, this); - } - - // Return Idealized original - return k; + return transform_no_reclaim(n); } //------------------------------transform-------------------------------------- @@ -784,6 +714,12 @@ return i; } + // Collect points-to information for escape analysys + ConnectionGraph *cgr = C->congraph(); + if (cgr != NULL) { + cgr->record_escape(k, this); + } + // Return Idealized original return k; } diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/opto/subnode.cpp --- a/hotspot/src/share/vm/opto/subnode.cpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/opto/subnode.cpp Thu Mar 20 09:17:30 2008 -0500 @@ -614,6 +614,13 @@ const TypeOopPtr* p0 = r0->isa_oopptr(); const TypeOopPtr* p1 = r1->isa_oopptr(); if (p0 && p1) { + Node* in1 = in(1)->uncast(); + Node* in2 = in(2)->uncast(); + AllocateNode* alloc1 = AllocateNode::Ideal_allocation(in1, NULL); + AllocateNode* alloc2 = AllocateNode::Ideal_allocation(in2, NULL); + if (MemNode::detect_ptr_independence(in1, alloc1, in2, alloc2, NULL)) { + return TypeInt::CC_GT; // different pointers + } ciKlass* klass0 = p0->klass(); bool xklass0 = p0->klass_is_exact(); ciKlass* klass1 = p1->klass(); diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/opto/superword.cpp --- a/hotspot/src/share/vm/opto/superword.cpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/opto/superword.cpp Thu Mar 20 09:17:30 2008 -0500 @@ -159,7 +159,8 @@ Node_List memops; for (int i = 0; i < _block.length(); i++) { Node* n = _block.at(i); - if (n->is_Mem() && in_bb(n)) { + if (n->is_Mem() && in_bb(n) && + is_java_primitive(n->as_Mem()->memory_type())) { int align = memory_alignment(n->as_Mem(), 0); if (align != bottom_align) { memops.push(n); @@ -570,7 +571,7 @@ int SuperWord::data_size(Node* s) { const Type* t = velt_type(s); BasicType bt = t->array_element_basic_type(); - int bsize = type2aelembytes[bt]; + int bsize = type2aelembytes(bt); assert(bsize != 0, "valid size"); return bsize; } diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/opto/type.hpp --- a/hotspot/src/share/vm/opto/type.hpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/opto/type.hpp Thu Mar 20 09:17:30 2008 -0500 @@ -1070,6 +1070,7 @@ #define LShiftXNode LShiftLNode // For object size computation: #define AddXNode AddLNode +#define RShiftXNode RShiftLNode // For card marks and hashcodes #define URShiftXNode URShiftLNode // Opcodes @@ -1108,6 +1109,7 @@ #define LShiftXNode LShiftINode // For object size computation: #define AddXNode AddINode +#define RShiftXNode RShiftINode // For card marks and hashcodes #define URShiftXNode URShiftINode // Opcodes diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/opto/vectornode.cpp --- a/hotspot/src/share/vm/opto/vectornode.cpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/opto/vectornode.cpp Thu Mar 20 09:17:30 2008 -0500 @@ -135,7 +135,7 @@ int mid = lo + ct/2; Node* n1 = ct == 2 ? in(lo) : binaryTreePack(C, lo, mid); Node* n2 = ct == 2 ? in(lo+1) : binaryTreePack(C, mid, hi ); - int rslt_bsize = ct * type2aelembytes[elt_basic_type()]; + int rslt_bsize = ct * type2aelembytes(elt_basic_type()); if (bottom_type()->is_floatingpoint()) { switch (rslt_bsize) { case 8: return new (C, 3) PackFNode(n1, n2); diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/opto/vectornode.hpp --- a/hotspot/src/share/vm/opto/vectornode.hpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/opto/vectornode.hpp Thu Mar 20 09:17:30 2008 -0500 @@ -48,7 +48,7 @@ uint length() const { return _length; } // Vector length static uint max_vlen(BasicType bt) { // max vector length - return (uint)(Matcher::vector_width_in_bytes() / type2aelembytes[bt]); + return (uint)(Matcher::vector_width_in_bytes() / type2aelembytes(bt)); } // Element and vector type @@ -392,7 +392,7 @@ virtual uint ideal_reg() const { return Matcher::vector_ideal_reg(); } virtual BasicType memory_type() const { return T_VOID; } - virtual int memory_size() const { return length()*type2aelembytes[elt_basic_type()]; } + virtual int memory_size() const { return length()*type2aelembytes(elt_basic_type()); } // Vector opcode from scalar opcode static int opcode(int sopc, uint vlen); @@ -620,7 +620,7 @@ virtual uint ideal_reg() const { return Matcher::vector_ideal_reg(); } virtual BasicType memory_type() const { return T_VOID; } - virtual int memory_size() const { return length()*type2aelembytes[elt_basic_type()]; } + virtual int memory_size() const { return length()*type2aelembytes(elt_basic_type()); } // Vector opcode from scalar opcode static int opcode(int sopc, uint vlen); diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/prims/jvmtiRedefineClassesTrace.hpp --- a/hotspot/src/share/vm/prims/jvmtiRedefineClassesTrace.hpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/prims/jvmtiRedefineClassesTrace.hpp Thu Mar 20 09:17:30 2008 -0500 @@ -64,7 +64,7 @@ // 0x01000000 | 16777216 - impl details: nmethod evolution info // 0x02000000 | 33554432 - impl details: annotation updates // 0x04000000 | 67108864 - impl details: StackMapTable updates -// 0x08000000 | 134217728 - unused +// 0x08000000 | 134217728 - impl details: OopMapCache updates // 0x10000000 | 268435456 - unused // 0x20000000 | 536870912 - unused // 0x40000000 | 1073741824 - unused diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/runtime/arguments.cpp --- a/hotspot/src/share/vm/runtime/arguments.cpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/runtime/arguments.cpp Thu Mar 20 09:17:30 2008 -0500 @@ -924,10 +924,18 @@ void Arguments::set_parnew_gc_flags() { assert(!UseSerialGC && !UseParallelGC, "control point invariant"); + // Turn off AdaptiveSizePolicy by default for parnew until it is + // complete. + if (UseParNewGC && + FLAG_IS_DEFAULT(UseAdaptiveSizePolicy)) { + FLAG_SET_DEFAULT(UseAdaptiveSizePolicy, false); + } + if (FLAG_IS_DEFAULT(UseParNewGC) && ParallelGCThreads > 1) { FLAG_SET_DEFAULT(UseParNewGC, true); } else if (UseParNewGC && ParallelGCThreads == 0) { - FLAG_SET_DEFAULT(ParallelGCThreads, nof_parallel_gc_threads()); + FLAG_SET_DEFAULT(ParallelGCThreads, + Abstract_VM_Version::parallel_worker_threads()); if (FLAG_IS_DEFAULT(ParallelGCThreads) && ParallelGCThreads == 1) { FLAG_SET_DEFAULT(UseParNewGC, false); } @@ -956,25 +964,6 @@ } } -// CAUTION: this code is currently shared by UseParallelGC, UseParNewGC and -// UseconcMarkSweepGC. Further tuning of individual collectors might -// dictate refinement on a per-collector basis. -int Arguments::nof_parallel_gc_threads() { - if (FLAG_IS_DEFAULT(ParallelGCThreads)) { - // For very large machines, there are diminishing returns - // for large numbers of worker threads. Instead of - // hogging the whole system, use 5/8ths of a worker for every - // processor after the first 8. For example, on a 72 cpu - // machine use 8 + (72 - 8) * (5/8) == 48 worker threads. - // This is just a start and needs further tuning and study in - // Tiger. - int ncpus = os::active_processor_count(); - return (ncpus <= 8) ? ncpus : 3 + ((ncpus * 5) / 8); - } else { - return ParallelGCThreads; - } -} - // Adjust some sizes to suit CMS and/or ParNew needs; these work well on // sparc/solaris for certain applications, but would gain from // further optimization and tuning efforts, and would almost @@ -984,26 +973,24 @@ return; } + assert(UseConcMarkSweepGC, "CMS is expected to be on here"); + // If we are using CMS, we prefer to UseParNewGC, // unless explicitly forbidden. - if (UseConcMarkSweepGC && !UseParNewGC && FLAG_IS_DEFAULT(UseParNewGC)) { - FLAG_SET_DEFAULT(UseParNewGC, true); + if (!UseParNewGC && FLAG_IS_DEFAULT(UseParNewGC)) { + FLAG_SET_ERGO(bool, UseParNewGC, true); } // Turn off AdaptiveSizePolicy by default for cms until it is - // complete. Also turn it off in general if the - // parnew collector has been selected. - if ((UseConcMarkSweepGC || UseParNewGC) && - FLAG_IS_DEFAULT(UseAdaptiveSizePolicy)) { + // complete. + if (FLAG_IS_DEFAULT(UseAdaptiveSizePolicy)) { FLAG_SET_DEFAULT(UseAdaptiveSizePolicy, false); } // In either case, adjust ParallelGCThreads and/or UseParNewGC // as needed. - set_parnew_gc_flags(); - - if (!UseConcMarkSweepGC) { - return; + if (UseParNewGC) { + set_parnew_gc_flags(); } // Now make adjustments for CMS @@ -1013,7 +1000,7 @@ intx tenuring_default; if (CMSUseOldDefaults) { // old defaults: "old" as of 6.0 if FLAG_IS_DEFAULT(CMSYoungGenPerWorker) { - FLAG_SET_DEFAULT(CMSYoungGenPerWorker, 4*M); + FLAG_SET_ERGO(intx, CMSYoungGenPerWorker, 4*M); } young_gen_per_worker = 4*M; new_ratio = (intx)15; @@ -1038,16 +1025,20 @@ // for "short" pauses ~ 4M*ParallelGCThreads if (FLAG_IS_DEFAULT(MaxNewSize)) { // MaxNewSize not set at command-line if (!FLAG_IS_DEFAULT(NewSize)) { // NewSize explicitly set at command-line - FLAG_SET_DEFAULT(MaxNewSize, MAX2(NewSize, preferred_max_new_size)); + FLAG_SET_ERGO(uintx, MaxNewSize, MAX2(NewSize, preferred_max_new_size)); } else { - FLAG_SET_DEFAULT(MaxNewSize, preferred_max_new_size); + FLAG_SET_ERGO(uintx, MaxNewSize, preferred_max_new_size); } + if(PrintGCDetails && Verbose) { + // Too early to use gclog_or_tty + tty->print_cr("Ergo set MaxNewSize: " SIZE_FORMAT, MaxNewSize); + } } // Unless explicitly requested otherwise, prefer a large // Old to Young gen size so as to shift the collection load // to the old generation concurrent collector if (FLAG_IS_DEFAULT(NewRatio)) { - FLAG_SET_DEFAULT(NewRatio, MAX2(NewRatio, new_ratio)); + FLAG_SET_ERGO(intx, NewRatio, MAX2(NewRatio, new_ratio)); size_t min_new = align_size_up(ScaleForWordSize(min_new_default), os::vm_page_size()); size_t prev_initial_size = initial_heap_size(); @@ -1065,19 +1056,34 @@ size_t max_heap = align_size_down(MaxHeapSize, CardTableRS::ct_max_alignment_constraint()); + if(PrintGCDetails && Verbose) { + // Too early to use gclog_or_tty + tty->print_cr("CMS set min_heap_size: " SIZE_FORMAT + " initial_heap_size: " SIZE_FORMAT + " max_heap: " SIZE_FORMAT, + min_heap_size(), initial_heap_size(), max_heap); + } if (max_heap > min_new) { // Unless explicitly requested otherwise, make young gen // at least min_new, and at most preferred_max_new_size. if (FLAG_IS_DEFAULT(NewSize)) { - FLAG_SET_DEFAULT(NewSize, MAX2(NewSize, min_new)); - FLAG_SET_DEFAULT(NewSize, MIN2(preferred_max_new_size, NewSize)); + FLAG_SET_ERGO(uintx, NewSize, MAX2(NewSize, min_new)); + FLAG_SET_ERGO(uintx, NewSize, MIN2(preferred_max_new_size, NewSize)); + if(PrintGCDetails && Verbose) { + // Too early to use gclog_or_tty + tty->print_cr("Ergo set NewSize: " SIZE_FORMAT, NewSize); + } } // Unless explicitly requested otherwise, size old gen // so that it's at least 3X of NewSize to begin with; // later NewRatio will decide how it grows; see above. if (FLAG_IS_DEFAULT(OldSize)) { if (max_heap > NewSize) { - FLAG_SET_DEFAULT(OldSize, MIN2(3*NewSize, max_heap - NewSize)); + FLAG_SET_ERGO(uintx, OldSize, MIN2(3*NewSize, max_heap - NewSize)); + if(PrintGCDetails && Verbose) { + // Too early to use gclog_or_tty + tty->print_cr("Ergo set OldSize: " SIZE_FORMAT, OldSize); + } } } } @@ -1086,14 +1092,14 @@ // promote all objects surviving "tenuring_default" scavenges. if (FLAG_IS_DEFAULT(MaxTenuringThreshold) && FLAG_IS_DEFAULT(SurvivorRatio)) { - FLAG_SET_DEFAULT(MaxTenuringThreshold, tenuring_default); + FLAG_SET_ERGO(intx, MaxTenuringThreshold, tenuring_default); } // If we decided above (or user explicitly requested) // `promote all' (via MaxTenuringThreshold := 0), // prefer minuscule survivor spaces so as not to waste // space for (non-existent) survivors if (FLAG_IS_DEFAULT(SurvivorRatio) && MaxTenuringThreshold == 0) { - FLAG_SET_DEFAULT(SurvivorRatio, MAX2((intx)1024, SurvivorRatio)); + FLAG_SET_ERGO(intx, SurvivorRatio, MAX2((intx)1024, SurvivorRatio)); } // If OldPLABSize is set and CMSParPromoteBlocksToClaim is not, // set CMSParPromoteBlocksToClaim equal to OldPLABSize. @@ -1102,7 +1108,11 @@ // See CR 6362902. if (!FLAG_IS_DEFAULT(OldPLABSize)) { if (FLAG_IS_DEFAULT(CMSParPromoteBlocksToClaim)) { - FLAG_SET_CMDLINE(uintx, CMSParPromoteBlocksToClaim, OldPLABSize); + // OldPLABSize is not the default value but CMSParPromoteBlocksToClaim + // is. In this situtation let CMSParPromoteBlocksToClaim follow + // the value (either from the command line or ergonomics) of + // OldPLABSize. Following OldPLABSize is an ergonomics decision. + FLAG_SET_ERGO(uintx, CMSParPromoteBlocksToClaim, OldPLABSize); } else { // OldPLABSize and CMSParPromoteBlocksToClaim are both set. @@ -1147,17 +1157,11 @@ FLAG_IS_DEFAULT(UseParallelGC)) { if (should_auto_select_low_pause_collector()) { FLAG_SET_ERGO(bool, UseConcMarkSweepGC, true); - set_cms_and_parnew_gc_flags(); } else { FLAG_SET_ERGO(bool, UseParallelGC, true); } no_shared_spaces(); } - - // This is here because the parallel collector could - // have been selected so this initialization should - // still be done. - set_parallel_gc_flags(); } } @@ -1170,6 +1174,9 @@ // If no heap maximum was requested explicitly, use some reasonable fraction // of the physical memory, up to a maximum of 1GB. if (UseParallelGC) { + FLAG_SET_ERGO(uintx, ParallelGCThreads, + Abstract_VM_Version::parallel_worker_threads()); + if (FLAG_IS_DEFAULT(MaxHeapSize)) { const uint64_t reasonable_fraction = os::physical_memory() / DefaultMaxRAMFraction; @@ -1227,12 +1234,13 @@ if (UseParallelOldGC) { // Par compact uses lower default values since they are treated as - // minimums. + // minimums. These are different defaults because of the different + // interpretation and are not ergonomically set. if (FLAG_IS_DEFAULT(MarkSweepDeadRatio)) { - MarkSweepDeadRatio = 1; + FLAG_SET_DEFAULT(MarkSweepDeadRatio, 1); } if (FLAG_IS_DEFAULT(PermMarkSweepDeadRatio)) { - PermMarkSweepDeadRatio = 5; + FLAG_SET_DEFAULT(PermMarkSweepDeadRatio, 5); } } } @@ -1254,6 +1262,22 @@ // Aggressive optimization flags -XX:+AggressiveOpts void Arguments::set_aggressive_opts_flags() { +#ifdef COMPILER2 + if (AggressiveOpts || !FLAG_IS_DEFAULT(AutoBoxCacheMax)) { + if (FLAG_IS_DEFAULT(EliminateAutoBox)) { + FLAG_SET_DEFAULT(EliminateAutoBox, true); + } + if (FLAG_IS_DEFAULT(AutoBoxCacheMax)) { + FLAG_SET_DEFAULT(AutoBoxCacheMax, 20000); + } + + // Feed the cache size setting into the JDK + char buffer[1024]; + sprintf(buffer, "java.lang.Integer.IntegerCache.high=%d", AutoBoxCacheMax); + add_property(buffer); + } +#endif + if (AggressiveOpts) { // Sample flag setting code // if (FLAG_IS_DEFAULT(EliminateZeroing)) { @@ -1310,6 +1334,31 @@ UseParallelOldGC)); } +// Check consistency of GC selection +bool Arguments::check_gc_consistency() { + bool status = true; + // Ensure that the user has not selected conflicting sets + // of collectors. [Note: this check is merely a user convenience; + // collectors over-ride each other so that only a non-conflicting + // set is selected; however what the user gets is not what they + // may have expected from the combination they asked for. It's + // better to reduce user confusion by not allowing them to + // select conflicting combinations. + uint i = 0; + if (UseSerialGC) i++; + if (UseConcMarkSweepGC || UseParNewGC) i++; + if (UseParallelGC || UseParallelOldGC) i++; + if (i > 1) { + jio_fprintf(defaultStream::error_stream(), + "Conflicting collector combinations in option list; " + "please refer to the release notes for the combinations " + "allowed\n"); + status = false; + } + + return status; +} + // Check the consistency of vm_init_args bool Arguments::check_vm_args_consistency() { // Method for adding checks for flag consistency. @@ -1352,14 +1401,14 @@ status = false; } - status &= verify_percentage(MaxLiveObjectEvacuationRatio, + status = status && verify_percentage(MaxLiveObjectEvacuationRatio, "MaxLiveObjectEvacuationRatio"); - status &= verify_percentage(AdaptiveSizePolicyWeight, + status = status && verify_percentage(AdaptiveSizePolicyWeight, "AdaptiveSizePolicyWeight"); - status &= verify_percentage(AdaptivePermSizeWeight, "AdaptivePermSizeWeight"); - status &= verify_percentage(ThresholdTolerance, "ThresholdTolerance"); - status &= verify_percentage(MinHeapFreeRatio, "MinHeapFreeRatio"); - status &= verify_percentage(MaxHeapFreeRatio, "MaxHeapFreeRatio"); + status = status && verify_percentage(AdaptivePermSizeWeight, "AdaptivePermSizeWeight"); + status = status && verify_percentage(ThresholdTolerance, "ThresholdTolerance"); + status = status && verify_percentage(MinHeapFreeRatio, "MinHeapFreeRatio"); + status = status && verify_percentage(MaxHeapFreeRatio, "MaxHeapFreeRatio"); if (MinHeapFreeRatio > MaxHeapFreeRatio) { jio_fprintf(defaultStream::error_stream(), @@ -1375,14 +1424,14 @@ MarkSweepAlwaysCompactCount = 1; // Move objects every gc. } - status &= verify_percentage(GCHeapFreeLimit, "GCHeapFreeLimit"); - status &= verify_percentage(GCTimeLimit, "GCTimeLimit"); + status = status && verify_percentage(GCHeapFreeLimit, "GCHeapFreeLimit"); + status = status && verify_percentage(GCTimeLimit, "GCTimeLimit"); if (GCTimeLimit == 100) { // Turn off gc-overhead-limit-exceeded checks FLAG_SET_DEFAULT(UseGCOverheadLimit, false); } - status &= verify_percentage(GCHeapFreeLimit, "GCHeapFreeLimit"); + status = status && verify_percentage(GCHeapFreeLimit, "GCHeapFreeLimit"); // Check user specified sharing option conflict with Parallel GC bool cannot_share = (UseConcMarkSweepGC || UseParallelGC || @@ -1400,24 +1449,7 @@ } } - // Ensure that the user has not selected conflicting sets - // of collectors. [Note: this check is merely a user convenience; - // collectors over-ride each other so that only a non-conflicting - // set is selected; however what the user gets is not what they - // may have expected from the combination they asked for. It's - // better to reduce user confusion by not allowing them to - // select conflicting combinations. - uint i = 0; - if (UseSerialGC) i++; - if (UseConcMarkSweepGC || UseParNewGC) i++; - if (UseParallelGC || UseParallelOldGC) i++; - if (i > 1) { - jio_fprintf(defaultStream::error_stream(), - "Conflicting collector combinations in option list; " - "please refer to the release notes for the combinations " - "allowed\n"); - status = false; - } + status = status && check_gc_consistency(); if (_has_alloc_profile) { if (UseParallelGC || UseParallelOldGC) { @@ -1449,15 +1481,15 @@ "allocation buffers\n(-XX:+UseTLAB).\n"); status = false; } else { - status &= verify_percentage(CMSIncrementalDutyCycle, + status = status && verify_percentage(CMSIncrementalDutyCycle, "CMSIncrementalDutyCycle"); - status &= verify_percentage(CMSIncrementalDutyCycleMin, + status = status && verify_percentage(CMSIncrementalDutyCycleMin, "CMSIncrementalDutyCycleMin"); - status &= verify_percentage(CMSIncrementalSafetyFactor, + status = status && verify_percentage(CMSIncrementalSafetyFactor, "CMSIncrementalSafetyFactor"); - status &= verify_percentage(CMSIncrementalOffset, + status = status && verify_percentage(CMSIncrementalOffset, "CMSIncrementalOffset"); - status &= verify_percentage(CMSExpAvgFactor, + status = status && verify_percentage(CMSExpAvgFactor, "CMSExpAvgFactor"); // If it was not set on the command line, set // CMSInitiatingOccupancyFraction to 1 so icms can initiate cycles early. @@ -2062,7 +2094,8 @@ // Enable parallel GC and adaptive generation sizing FLAG_SET_CMDLINE(bool, UseParallelGC, true); - FLAG_SET_DEFAULT(ParallelGCThreads, nof_parallel_gc_threads()); + FLAG_SET_DEFAULT(ParallelGCThreads, + Abstract_VM_Version::parallel_worker_threads()); // Encourage steady state memory management FLAG_SET_CMDLINE(uintx, ThresholdTolerance, 100); @@ -2449,15 +2482,25 @@ no_shared_spaces(); #endif // KERNEL - // Set some flags for ParallelGC if needed. - set_parallel_gc_flags(); - - // Set some flags for CMS and/or ParNew collectors, as needed. - set_cms_and_parnew_gc_flags(); - // Set flags based on ergonomics. set_ergonomics_flags(); + // Check the GC selections again. + if (!check_gc_consistency()) { + return JNI_EINVAL; + } + + if (UseParallelGC || UseParallelOldGC) { + // Set some flags for ParallelGC if needed. + set_parallel_gc_flags(); + } else if (UseConcMarkSweepGC) { + // Set some flags for CMS + set_cms_and_parnew_gc_flags(); + } else if (UseParNewGC) { + // Set some flags for ParNew + set_parnew_gc_flags(); + } + #ifdef SERIALGC assert(verify_serial_gc_flags(), "SerialGC unset"); #endif // SERIALGC @@ -2477,6 +2520,12 @@ CommandLineFlags::printSetFlags(); } +#ifdef ASSERT + if (PrintFlagsFinal) { + CommandLineFlags::printFlags(); + } +#endif + return JNI_OK; } diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/runtime/arguments.hpp --- a/hotspot/src/share/vm/runtime/arguments.hpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/runtime/arguments.hpp Thu Mar 20 09:17:30 2008 -0500 @@ -291,8 +291,6 @@ static bool _CIDynamicCompilePriority; static intx _Tier2CompileThreshold; - // GC processing - static int nof_parallel_gc_threads(); // CMS/ParNew garbage collectors static void set_parnew_gc_flags(); static void set_cms_and_parnew_gc_flags(); @@ -385,6 +383,8 @@ public: // Parses the arguments static jint parse(const JavaVMInitArgs* args); + // Check for consistency in the selection of the garbage collector. + static bool check_gc_consistency(); // Check consistecy or otherwise of VM argument settings static bool check_vm_args_consistency(); // Used by os_solaris diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/runtime/deoptimization.cpp --- a/hotspot/src/share/vm/runtime/deoptimization.cpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/runtime/deoptimization.cpp Thu Mar 20 09:17:30 2008 -0500 @@ -141,41 +141,45 @@ #ifdef COMPILER2 // Reallocate the non-escaping objects and restore their fields. Then // relock objects if synchronization on them was eliminated. - if (DoEscapeAnalysis && EliminateAllocations) { - GrowableArray* objects = chunk->at(0)->scope()->objects(); - bool reallocated = false; - if (objects != NULL) { - JRT_BLOCK - reallocated = realloc_objects(thread, &deoptee, objects, THREAD); - JRT_END - } - if (reallocated) { - reassign_fields(&deoptee, &map, objects); -#ifndef PRODUCT - if (TraceDeoptimization) { - ttyLocker ttyl; - tty->print_cr("REALLOC OBJECTS in thread " INTPTR_FORMAT, thread); - print_objects(objects); + if (DoEscapeAnalysis) { + if (EliminateAllocations) { + GrowableArray* objects = chunk->at(0)->scope()->objects(); + bool reallocated = false; + if (objects != NULL) { + JRT_BLOCK + reallocated = realloc_objects(thread, &deoptee, objects, THREAD); + JRT_END } -#endif - } - for (int i = 0; i < chunk->length(); i++) { - GrowableArray* monitors = chunk->at(i)->scope()->monitors(); - if (monitors != NULL) { - relock_objects(&deoptee, &map, monitors); + if (reallocated) { + reassign_fields(&deoptee, &map, objects); #ifndef PRODUCT if (TraceDeoptimization) { ttyLocker ttyl; - tty->print_cr("RELOCK OBJECTS in thread " INTPTR_FORMAT, thread); - for (int j = 0; i < monitors->length(); i++) { - MonitorValue* mv = monitors->at(i); - if (mv->eliminated()) { - StackValue* owner = StackValue::create_stack_value(&deoptee, &map, mv->owner()); - tty->print_cr(" object <" INTPTR_FORMAT "> locked", owner->get_obj()()); + tty->print_cr("REALLOC OBJECTS in thread " INTPTR_FORMAT, thread); + print_objects(objects); + } +#endif + } + } + if (EliminateLocks) { + for (int i = 0; i < chunk->length(); i++) { + GrowableArray* monitors = chunk->at(i)->scope()->monitors(); + if (monitors != NULL) { + relock_objects(&deoptee, &map, monitors); +#ifndef PRODUCT + if (TraceDeoptimization) { + ttyLocker ttyl; + tty->print_cr("RELOCK OBJECTS in thread " INTPTR_FORMAT, thread); + for (int j = 0; j < monitors->length(); j++) { + MonitorValue* mv = monitors->at(j); + if (mv->eliminated()) { + StackValue* owner = StackValue::create_stack_value(&deoptee, &map, mv->owner()); + tty->print_cr(" object <" INTPTR_FORMAT "> locked", owner->get_obj()()); + } } } +#endif } -#endif } } } @@ -656,6 +660,7 @@ void do_field(fieldDescriptor* fd) { + intptr_t val; StackValue* value = StackValue::create_stack_value(_fr, _reg_map, _sv->field_at(i())); int offset = fd->offset(); @@ -669,24 +674,36 @@ assert(value->type() == T_INT, "Agreement."); StackValue* low = StackValue::create_stack_value(_fr, _reg_map, _sv->field_at(++_i)); +#ifdef _LP64 + jlong res = (jlong)low->get_int(); +#else +#ifdef SPARC + // For SPARC we have to swap high and low words. + jlong res = jlong_from((jint)low->get_int(), (jint)value->get_int()); +#else jlong res = jlong_from((jint)value->get_int(), (jint)low->get_int()); +#endif //SPARC +#endif _obj->long_field_put(offset, res); break; } - + // Have to cast to INT (32 bits) pointer to avoid little/big-endian problem. case T_INT: case T_FLOAT: // 4 bytes. assert(value->type() == T_INT, "Agreement."); - _obj->int_field_put(offset, (jint)value->get_int()); + val = value->get_int(); + _obj->int_field_put(offset, (jint)*((jint*)&val)); break; case T_SHORT: case T_CHAR: // 2 bytes assert(value->type() == T_INT, "Agreement."); - _obj->short_field_put(offset, (jshort)value->get_int()); + val = value->get_int(); + _obj->short_field_put(offset, (jshort)*((jint*)&val)); break; - case T_BOOLEAN: // 1 byte + case T_BOOLEAN: case T_BYTE: // 1 byte assert(value->type() == T_INT, "Agreement."); - _obj->bool_field_put(offset, (jboolean)value->get_int()); + val = value->get_int(); + _obj->bool_field_put(offset, (jboolean)*((jint*)&val)); break; default: @@ -698,25 +715,49 @@ // restore elements of an eliminated type array void Deoptimization::reassign_type_array_elements(frame* fr, RegisterMap* reg_map, ObjectValue* sv, typeArrayOop obj, BasicType type) { - StackValue* low; - jlong lval; int index = 0; + intptr_t val; for (int i = 0; i < sv->field_size(); i++) { StackValue* value = StackValue::create_stack_value(fr, reg_map, sv->field_at(i)); switch(type) { - case T_BOOLEAN: obj->bool_at_put (index, (jboolean) value->get_int()); break; - case T_BYTE: obj->byte_at_put (index, (jbyte) value->get_int()); break; - case T_CHAR: obj->char_at_put (index, (jchar) value->get_int()); break; - case T_SHORT: obj->short_at_put(index, (jshort) value->get_int()); break; - case T_INT: obj->int_at_put (index, (jint) value->get_int()); break; - case T_FLOAT: obj->float_at_put(index, (jfloat) value->get_int()); break; - case T_LONG: - case T_DOUBLE: - low = StackValue::create_stack_value(fr, reg_map, sv->field_at(++i)); - lval = jlong_from((jint)value->get_int(), (jint)low->get_int()); - sv->value()->long_field_put(index, lval); - break; + case T_LONG: case T_DOUBLE: { + assert(value->type() == T_INT, "Agreement."); + StackValue* low = + StackValue::create_stack_value(fr, reg_map, sv->field_at(++i)); +#ifdef _LP64 + jlong res = (jlong)low->get_int(); +#else +#ifdef SPARC + // For SPARC we have to swap high and low words. + jlong res = jlong_from((jint)low->get_int(), (jint)value->get_int()); +#else + jlong res = jlong_from((jint)value->get_int(), (jint)low->get_int()); +#endif //SPARC +#endif + obj->long_at_put(index, res); + break; + } + + // Have to cast to INT (32 bits) pointer to avoid little/big-endian problem. + case T_INT: case T_FLOAT: // 4 bytes. + assert(value->type() == T_INT, "Agreement."); + val = value->get_int(); + obj->int_at_put(index, (jint)*((jint*)&val)); + break; + + case T_SHORT: case T_CHAR: // 2 bytes + assert(value->type() == T_INT, "Agreement."); + val = value->get_int(); + obj->short_at_put(index, (jshort)*((jint*)&val)); + break; + + case T_BOOLEAN: case T_BYTE: // 1 byte + assert(value->type() == T_INT, "Agreement."); + val = value->get_int(); + obj->bool_at_put(index, (jboolean)*((jint*)&val)); + break; + default: ShouldNotReachHere(); } diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/runtime/globals.cpp --- a/hotspot/src/share/vm/runtime/globals.cpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/runtime/globals.cpp Thu Mar 20 09:17:30 2008 -0500 @@ -205,6 +205,18 @@ return (f->origin == DEFAULT); } +bool CommandLineFlagsEx::is_ergo(CommandLineFlag flag) { + assert((size_t)flag < Flag::numFlags, "bad command line flag index"); + Flag* f = &Flag::flags[flag]; + return (f->origin == ERGONOMIC); +} + +bool CommandLineFlagsEx::is_cmdline(CommandLineFlag flag) { + assert((size_t)flag < Flag::numFlags, "bad command line flag index"); + Flag* f = &Flag::flags[flag]; + return (f->origin == COMMAND_LINE); +} + bool CommandLineFlags::wasSetOnCmdline(const char* name, bool* value) { Flag* result = Flag::find_flag((char*)name, strlen(name)); if (result == NULL) return false; diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/runtime/globals.hpp --- a/hotspot/src/share/vm/runtime/globals.hpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/runtime/globals.hpp Thu Mar 20 09:17:30 2008 -0500 @@ -580,7 +580,7 @@ develop(bool, ZapJNIHandleArea, trueInDebug, \ "Zap freed JNI handle space with 0xFEFEFEFE") \ \ - develop(bool, ZapUnusedHeapArea, trueInDebug, \ + develop(bool, ZapUnusedHeapArea, false, \ "Zap unused heap space with 0xBAADBABE") \ \ develop(bool, PrintVMMessages, true, \ @@ -1788,6 +1788,9 @@ "number of times a GC thread (minus the coordinator) " \ "will sleep while yielding before giving up and resuming GC") \ \ + notproduct(bool, PrintFlagsFinal, false, \ + "Print all command line flags after argument processing") \ + \ /* gc tracing */ \ manageable(bool, PrintGC, false, \ "Print message at garbage collect") \ diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/runtime/globals_extension.hpp --- a/hotspot/src/share/vm/runtime/globals_extension.hpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/runtime/globals_extension.hpp Thu Mar 20 09:17:30 2008 -0500 @@ -154,6 +154,8 @@ } CommandLineFlagWithType; #define FLAG_IS_DEFAULT(name) (CommandLineFlagsEx::is_default(FLAG_MEMBER(name))) +#define FLAG_IS_ERGO(name) (CommandLineFlagsEx::is_ergo(FLAG_MEMBER(name))) +#define FLAG_IS_CMDLINE(name) (CommandLineFlagsEx::is_cmdline(FLAG_MEMBER(name))) #define FLAG_SET_DEFAULT(name, value) ((name) = (value)) @@ -171,4 +173,6 @@ static void ccstrAtPut(CommandLineFlagWithType flag, ccstr value, FlagValueOrigin origin); static bool is_default(CommandLineFlag flag); + static bool is_ergo(CommandLineFlag flag); + static bool is_cmdline(CommandLineFlag flag); }; diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/runtime/reflection.cpp --- a/hotspot/src/share/vm/runtime/reflection.cpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/runtime/reflection.cpp Thu Mar 20 09:17:30 2008 -0500 @@ -1548,10 +1548,11 @@ } instanceKlassHandle klass(THREAD, java_lang_Class::as_klassOop(mirror)); - if (!klass->methods()->is_within_bounds(slot)) { + methodOop m = klass->method_with_idnum(slot); + if (m == NULL) { THROW_MSG_0(vmSymbols::java_lang_InternalError(), "invoke"); } - methodHandle method(THREAD, methodOop(klass->methods()->obj_at(slot))); + methodHandle method(THREAD, m); return invoke(klass, method, receiver, override, ptypes, rtype, args, true, THREAD); } @@ -1564,10 +1565,11 @@ objArrayHandle ptypes(THREAD, objArrayOop(java_lang_reflect_Constructor::parameter_types(constructor_mirror))); instanceKlassHandle klass(THREAD, java_lang_Class::as_klassOop(mirror)); - if (!klass->methods()->is_within_bounds(slot)) { + methodOop m = klass->method_with_idnum(slot); + if (m == NULL) { THROW_MSG_0(vmSymbols::java_lang_InternalError(), "invoke"); } - methodHandle method(THREAD, methodOop(klass->methods()->obj_at(slot))); + methodHandle method(THREAD, m); assert(method->name() == vmSymbols::object_initializer_name(), "invalid constructor"); // Make sure klass gets initialize diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/runtime/sharedRuntime.cpp --- a/hotspot/src/share/vm/runtime/sharedRuntime.cpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/runtime/sharedRuntime.cpp Thu Mar 20 09:17:30 2008 -0500 @@ -467,6 +467,11 @@ throw_and_post_jvmti_exception(thread, vmSymbols::java_lang_AbstractMethodError()); JRT_END +JRT_ENTRY(void, SharedRuntime::throw_IncompatibleClassChangeError(JavaThread* thread)) + // These errors occur only at call sites + throw_and_post_jvmti_exception(thread, vmSymbols::java_lang_IncompatibleClassChangeError(), "vtable stub"); +JRT_END + JRT_ENTRY(void, SharedRuntime::throw_ArithmeticException(JavaThread* thread)) throw_and_post_jvmti_exception(thread, vmSymbols::java_lang_ArithmeticException(), "/ by zero"); JRT_END @@ -1832,7 +1837,25 @@ regs); B = BufferBlob::create(AdapterHandlerEntry::name, &buffer); - if (B == NULL) return -2; // Out of CodeCache space + if (B == NULL) { + // CodeCache is full, disable compilation + // Ought to log this but compile log is only per compile thread + // and we're some non descript Java thread. + UseInterpreter = true; + if (UseCompiler || AlwaysCompileLoopMethods ) { +#ifndef PRODUCT + warning("CodeCache is full. Compiler has been disabled"); + if (CompileTheWorld || ExitOnFullCodeCache) { + before_exit(JavaThread::current()); + exit_globals(); // will delete tty + vm_direct_exit(CompileTheWorld ? 0 : 1); + } +#endif + UseCompiler = false; + AlwaysCompileLoopMethods = false; + } + return 0; // Out of CodeCache space (_handlers[0] == NULL) + } entry->relocate(B->instructions_begin()); #ifndef PRODUCT // debugging suppport diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/runtime/sharedRuntime.hpp --- a/hotspot/src/share/vm/runtime/sharedRuntime.hpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/runtime/sharedRuntime.hpp Thu Mar 20 09:17:30 2008 -0500 @@ -104,6 +104,7 @@ STACK_OVERFLOW }; static void throw_AbstractMethodError(JavaThread* thread); + static void throw_IncompatibleClassChangeError(JavaThread* thread); static void throw_ArithmeticException(JavaThread* thread); static void throw_NullPointerException(JavaThread* thread); static void throw_NullPointerException_at_call(JavaThread* thread); diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/runtime/stubRoutines.cpp --- a/hotspot/src/share/vm/runtime/stubRoutines.cpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/runtime/stubRoutines.cpp Thu Mar 20 09:17:30 2008 -0500 @@ -40,6 +40,7 @@ address StubRoutines::_catch_exception_entry = NULL; address StubRoutines::_forward_exception_entry = NULL; address StubRoutines::_throw_AbstractMethodError_entry = NULL; +address StubRoutines::_throw_IncompatibleClassChangeError_entry = NULL; address StubRoutines::_throw_ArithmeticException_entry = NULL; address StubRoutines::_throw_NullPointerException_entry = NULL; address StubRoutines::_throw_NullPointerException_at_call_entry = NULL; diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/runtime/stubRoutines.hpp --- a/hotspot/src/share/vm/runtime/stubRoutines.hpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/runtime/stubRoutines.hpp Thu Mar 20 09:17:30 2008 -0500 @@ -84,6 +84,7 @@ static address _forward_exception_entry; static address _catch_exception_entry; static address _throw_AbstractMethodError_entry; + static address _throw_IncompatibleClassChangeError_entry; static address _throw_ArithmeticException_entry; static address _throw_NullPointerException_entry; static address _throw_NullPointerException_at_call_entry; @@ -184,6 +185,7 @@ static address forward_exception_entry() { return _forward_exception_entry; } // Implicit exceptions static address throw_AbstractMethodError_entry() { return _throw_AbstractMethodError_entry; } + static address throw_IncompatibleClassChangeError_entry(){ return _throw_IncompatibleClassChangeError_entry; } static address throw_ArithmeticException_entry() { return _throw_ArithmeticException_entry; } static address throw_NullPointerException_entry() { return _throw_NullPointerException_entry; } static address throw_NullPointerException_at_call_entry(){ return _throw_NullPointerException_at_call_entry; } diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/runtime/thread.cpp --- a/hotspot/src/share/vm/runtime/thread.cpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/runtime/thread.cpp Thu Mar 20 09:17:30 2008 -0500 @@ -1317,10 +1317,6 @@ ThreadSafepointState::destroy(this); if (_thread_profiler != NULL) delete _thread_profiler; if (_thread_stat != NULL) delete _thread_stat; - - if (jvmti_thread_state() != NULL) { - JvmtiExport::cleanup_thread(this); - } } @@ -1571,6 +1567,10 @@ tlab().make_parsable(true); // retire TLAB } + if (jvmti_thread_state() != NULL) { + JvmtiExport::cleanup_thread(this); + } + // Remove from list of active threads list, and notify VM thread if we are the last non-daemon thread Threads::remove(this); } @@ -2925,6 +2925,25 @@ warning("java.lang.String not initialized"); } + if (AggressiveOpts) { + // Forcibly initialize java/util/HashMap and mutate the private + // static final "frontCacheEnabled" field before we start creating instances +#ifdef ASSERT + klassOop tmp_k = SystemDictionary::find(vmSymbolHandles::java_util_HashMap(), Handle(), Handle(), CHECK_0); + assert(tmp_k == NULL, "java/util/HashMap should not be loaded yet"); +#endif + klassOop k_o = SystemDictionary::resolve_or_null(vmSymbolHandles::java_util_HashMap(), Handle(), Handle(), CHECK_0); + KlassHandle k = KlassHandle(THREAD, k_o); + guarantee(k.not_null(), "Must find java/util/HashMap"); + instanceKlassHandle ik = instanceKlassHandle(THREAD, k()); + ik->initialize(CHECK_0); + fieldDescriptor fd; + // Possible we might not find this field; if so, don't break + if (ik->find_local_field(vmSymbols::frontCacheEnabled_name(), vmSymbols::bool_signature(), &fd)) { + k()->bool_field_put(fd.offset(), true); + } + } + // Initialize java_lang.System (needed before creating the thread) if (InitializeJavaLangSystem) { initialize_class(vmSymbolHandles::java_lang_System(), CHECK_0); diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/runtime/vm_version.cpp --- a/hotspot/src/share/vm/runtime/vm_version.cpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/runtime/vm_version.cpp Thu Mar 20 09:17:30 2008 -0500 @@ -52,6 +52,8 @@ int Abstract_VM_Version::_vm_minor_version = 0; int Abstract_VM_Version::_vm_build_number = 0; bool Abstract_VM_Version::_initialized = false; +int Abstract_VM_Version::_parallel_worker_threads = 0; +bool Abstract_VM_Version::_parallel_worker_threads_initialized = false; void Abstract_VM_Version::initialize() { if (_initialized) { @@ -210,3 +212,43 @@ } #endif } + +unsigned int Abstract_VM_Version::nof_parallel_worker_threads( + unsigned int num, + unsigned int den, + unsigned int switch_pt) { + if (FLAG_IS_DEFAULT(ParallelGCThreads)) { + assert(ParallelGCThreads == 0, "Default ParallelGCThreads is not 0"); + // For very large machines, there are diminishing returns + // for large numbers of worker threads. Instead of + // hogging the whole system, use a fraction of the workers for every + // processor after the first 8. For example, on a 72 cpu machine + // and a chosen fraction of 5/8 + // use 8 + (72 - 8) * (5/8) == 48 worker threads. + unsigned int ncpus = (unsigned int) os::active_processor_count(); + return (ncpus <= switch_pt) ? + ncpus : + (switch_pt + ((ncpus - switch_pt) * num) / den); + } else { + return ParallelGCThreads; + } +} + +unsigned int Abstract_VM_Version::calc_parallel_worker_threads() { + return nof_parallel_worker_threads(5, 8, 8); +} + + +// Does not set the _initialized flag since it is +// a global flag. +unsigned int Abstract_VM_Version::parallel_worker_threads() { + if (!_parallel_worker_threads_initialized) { + if (FLAG_IS_DEFAULT(ParallelGCThreads)) { + _parallel_worker_threads = VM_Version::calc_parallel_worker_threads(); + } else { + _parallel_worker_threads = ParallelGCThreads; + } + _parallel_worker_threads_initialized = true; + } + return _parallel_worker_threads; +} diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/runtime/vm_version.hpp --- a/hotspot/src/share/vm/runtime/vm_version.hpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/runtime/vm_version.hpp Thu Mar 20 09:17:30 2008 -0500 @@ -36,6 +36,12 @@ static int _vm_minor_version; static int _vm_build_number; static bool _initialized; + static int _parallel_worker_threads; + static bool _parallel_worker_threads_initialized; + + static unsigned int nof_parallel_worker_threads(unsigned int num, + unsigned int dem, + unsigned int switch_pt); public: static void initialize(); @@ -69,4 +75,13 @@ // subclasses should define new versions to hide this one as needed. Note // that the O/S may support more sizes, but at most this many are used. static uint page_size_count() { return 2; } + + // Returns the number of parallel threads to be used for VM + // work. If that number has not been calculated, do so and + // save it. Returns ParallelGCThreads if it is set on the + // command line. + static unsigned int parallel_worker_threads(); + // Calculates and returns the number of parallel threads. May + // be VM version specific. + static unsigned int calc_parallel_worker_threads(); }; diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/services/heapDumper.cpp --- a/hotspot/src/share/vm/services/heapDumper.cpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/services/heapDumper.cpp Thu Mar 20 09:17:30 2008 -0500 @@ -997,7 +997,7 @@ } // If the byte ordering is big endian then we can copy most types directly - int length_in_bytes = array->length() * type2aelembytes[type]; + int length_in_bytes = array->length() * type2aelembytes(type); assert(length_in_bytes > 0, "nothing to copy"); switch (type) { diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/utilities/globalDefinitions.cpp --- a/hotspot/src/share/vm/utilities/globalDefinitions.cpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/utilities/globalDefinitions.cpp Thu Mar 20 09:17:30 2008 -0500 @@ -214,7 +214,7 @@ }; -int type2aelembytes[T_CONFLICT+1] = { +int _type2aelembytes[T_CONFLICT+1] = { 0, // 0 0, // 1 0, // 2 @@ -230,10 +230,16 @@ T_OBJECT_aelem_bytes, // T_OBJECT = 12, T_ARRAY_aelem_bytes, // T_ARRAY = 13, 0, // T_VOID = 14, - T_INT_aelem_bytes, // T_ADDRESS = 15, + T_OBJECT_aelem_bytes, // T_ADDRESS = 15, 0 // T_CONFLICT = 16, }; +#ifdef ASSERT +int type2aelembytes(BasicType t, bool allow_address) { + assert(allow_address || t != T_ADDRESS, " "); + return _type2aelembytes[t]; +} +#endif // Support for 64-bit integer arithmetic diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/utilities/globalDefinitions.hpp --- a/hotspot/src/share/vm/utilities/globalDefinitions.hpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/utilities/globalDefinitions.hpp Thu Mar 20 09:17:30 2008 -0500 @@ -392,6 +392,10 @@ T_ILLEGAL = 99 }; +inline bool is_java_primitive(BasicType t) { + return T_BOOLEAN <= t && t <= T_LONG; +} + // Convert a char from a classfile signature to a BasicType inline BasicType char2type(char c) { switch( c ) { @@ -464,7 +468,12 @@ T_VOID_aelem_bytes = 0 }; -extern int type2aelembytes[T_CONFLICT+1]; // maps a BasicType to nof bytes used by its array element +extern int _type2aelembytes[T_CONFLICT+1]; // maps a BasicType to nof bytes used by its array element +#ifdef ASSERT +extern int type2aelembytes(BasicType t, bool allow_address = false); // asserts +#else +inline int type2aelembytes(BasicType t) { return _type2aelembytes[t]; } +#endif // JavaValue serves as a container for arbitrary Java values. diff -r 4da9c1bbc810 -r 735f15bdea80 hotspot/src/share/vm/utilities/globalDefinitions_sparcWorks.hpp --- a/hotspot/src/share/vm/utilities/globalDefinitions_sparcWorks.hpp Wed Mar 19 09:58:01 2008 -0400 +++ b/hotspot/src/share/vm/utilities/globalDefinitions_sparcWorks.hpp Thu Mar 20 09:17:30 2008 -0500 @@ -37,23 +37,45 @@ # include # include # include +#ifdef SOLARIS # include +#endif # include +#ifdef LINUX +#ifndef FP_PZERO + // Linux doesn't have positive/negative zero + #define FP_PZERO FP_ZERO +#endif +#ifndef fpclass + #define fpclass fpclassify +#endif +#endif # include # include # include # include +#ifdef SOLARIS # include +#endif # include # include +#ifdef SOLARIS # include # include # include # include # include +#endif # ifdef SOLARIS_MUTATOR_LIBTHREAD # include # endif +#ifdef LINUX +# include +# include +# include +# include +#endif + // 4810578: varargs unsafe on 32-bit integer/64-bit pointer architectures // When __cplusplus is defined, NULL is defined as 0 (32-bit constant) in @@ -68,6 +90,11 @@ // pointer when it extracts the argument, then we have a problem. // // Solution: For 64-bit architectures, redefine NULL as 64-bit constant 0. +// +// Note: this fix doesn't work well on Linux because NULL will be overwritten +// whenever a system header file is included. Linux handles NULL correctly +// through a special type '__null'. +#ifdef SOLARIS #ifdef _LP64 #undef NULL #define NULL 0L @@ -76,13 +103,25 @@ #define NULL 0 #endif #endif +#endif // NULL vs NULL_WORD: // On Linux NULL is defined as a special type '__null'. Assigning __null to // integer variable will cause gcc warning. Use NULL_WORD in places where a -// pointer is stored as integer value. -#define NULL_WORD NULL +// pointer is stored as integer value. On some platforms, sizeof(intptr_t) > +// sizeof(void*), so here we want something which is integer type, but has the +// same size as a pointer. +#ifdef LINUX + #ifdef _LP64 + #define NULL_WORD 0L + #else + #define NULL_WORD 0 + #endif +#else + #define NULL_WORD NULL +#endif +#ifndef LINUX // Compiler-specific primitive types typedef unsigned short uint16_t; #ifndef _UINT32_T @@ -100,6 +139,7 @@ // If this gets an error, figure out a symbol XXX that implies the // prior definition of intptr_t, and add "&& !defined(XXX)" above. #endif +#endif // Additional Java basic types @@ -128,7 +168,7 @@ const jlong min_jlong = CONST64(0x8000000000000000); const jlong max_jlong = CONST64(0x7fffffffffffffff); - +#ifdef SOLARIS //---------------------------------------------------------------------------------------------------- // ANSI C++ fixes // NOTE:In the ANSI committee's continuing attempt to make each version @@ -162,7 +202,7 @@ typedef int (*int_fnP_cond_tP_i_vP)(cond_t *cv, int scope, void *arg); typedef int (*int_fnP_cond_tP)(cond_t *cv); }; - +#endif //---------------------------------------------------------------------------------------------------- // Debugging @@ -173,7 +213,7 @@ #define BREAKPOINT ::breakpoint() // checking for nanness - +#ifdef SOLARIS #ifdef SPARC inline int g_isnan(float f) { return isnanf(f); } #else @@ -182,6 +222,12 @@ #endif inline int g_isnan(double f) { return isnand(f); } +#elif LINUX +inline int g_isnan(float f) { return isnanf(f); } +inline int g_isnan(double f) { return isnan(f); } +#else +#error "missing platform-specific definition here" +#endif // Checking for finiteness @@ -195,9 +241,11 @@ // Misc +// NOTE: This one leads to an infinite recursion on Linux +#ifndef LINUX int local_vsnprintf(char* buf, size_t count, const char* fmt, va_list argptr); #define vsnprintf local_vsnprintf - +#endif // Portability macros #define PRAGMA_INTERFACE