--- 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
--- 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
--- 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.
#
--- 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
--- 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)
--- /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
+
--- /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
--- /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
--- 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
--- 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());
}
--- 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;
--- 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);
--- 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;
+}
--- 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();
};
--- 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
--- 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);
--- 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;
--- 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 {
--- 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);
--- 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,
--- 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);
}
}
--- 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);
}
}
--- 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 <ver> is the protocol version (1), <cmd> is the command
// name ("load", "datadump", ...), and <arg> 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];
--- 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
--- 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
--- 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
--- 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
--- 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;
--- 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;
--- 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);
};
--- 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() {
--- 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<ciField*>* _arr;
+ ciEnv* _curEnv;
+public:
+ NonStaticFieldFiller(ciEnv* curEnv, GrowableArray<ciField*>* arr) :
+ _curEnv(curEnv), _arr(arr)
+ {}
+ void do_field(fieldDescriptor* fd) {
+ ciField* field = new (_curEnv->arena()) ciField(fd);
+ _arr->append(field);
+ }
+};
+
+GrowableArray<ciField*>* 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<ciField*>(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...)
--- 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<ciField*>* _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<ciField*>* non_static_fields();
+
// total number of nonstatic fields (including inherited):
int nof_nonstatic_fields() {
if (_nonstatic_fields == NULL)
--- 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)) {
--- 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
--- 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();
--- 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) {
--- 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);
--- /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);
+ }
+}
--- 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);
};
--- 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);
--- 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.
--- 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);
--- 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.
--- 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();
}
}
--- 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:
--- 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();
--- 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.
--- 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
--- 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;
--- 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
-}
--- 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
--- 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(" ");
}
--- 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); }
};
--- 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:
--- 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();
}
--- 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,
--- 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) {
--- 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());
+}
--- 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;
};
--- 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
--- 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()) {
--- 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());
--- 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) {
--- 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
--- 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
--- 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;
}
--- 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;
--- /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;
--- /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; }
+ )
+};
--- 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_<arch_model>.cpp adGlobals_<arch_model>.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
--- 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 <os>, <arch_model>, ... and
// makedeps has a dependency on these platform files looking like:
-// foo_<macro>.trailing_string
+// foo_<macro>.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
--- 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;
}
--- 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;
--- 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; }
- )
-};
--- 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)));
--- 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");
--- 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);
--- 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,
--- 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 {
--- 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);
+ }
}
}
--- 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() {}
--- 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 = "<no 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) {
--- 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 {
--- 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");
}
--- 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() {}
--- 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;
}
--- 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<jweak>* prev_EMCP_methods) {
+PreviousVersionNode::PreviousVersionNode(jobject prev_constant_pool,
+ bool prev_cp_is_weak, GrowableArray<jweak>* 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
}
--- 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<jweak>* _prev_EMCP_methods;
public:
- PreviousVersionNode(jweak prev_constant_pool,
+ PreviousVersionNode(jobject prev_constant_pool, bool prev_cp_is_weak,
GrowableArray<jweak>* prev_EMCP_methods);
~PreviousVersionNode();
- jweak prev_constant_pool() const {
+ jobject prev_constant_pool() const {
return _prev_constant_pool;
}
GrowableArray<jweak>* prev_EMCP_methods() const {
--- 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));
--- 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),
--- 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);
--- 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;
+}
--- 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;
};
--- 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);
--- 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; }
--- 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
--- 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(); }
--- 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 {
--- 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_<arch>.hpp
--- 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);
--- 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") \
\
--- 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().
--- 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();
--- 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 );
--- 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);
--- 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
--- 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;
--- 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
--- 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;
}
--- 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) {
--- 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);
--- 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();
--- 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?
--- 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
--- 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 );
--- 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
}
}
}
--- 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 );
--- 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
--- 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 );
}
--- 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;
--- 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 <Node *> 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();
+ }
}
}
--- 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
--- 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");
}
}
--- 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; }
--- 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;
}
--- 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,
--- 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;
}
--- 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();
--- 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;
}
--- 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
--- 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);
--- 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);
--- 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
--- 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;
}
--- 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
--- 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<ScopeValue*>* 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<ScopeValue*>* 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<MonitorValue*>* 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<MonitorValue*>* 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();
}
--- 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;
--- 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") \
--- 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);
};
--- 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
--- 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
--- 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);
--- 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;
--- 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; }
--- 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);
--- 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;
+}
--- 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();
};
--- 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) {
--- 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
--- 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.
--- 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 <stdlib.h>
# include <wchar.h>
# include <stdarg.h>
+#ifdef SOLARIS
# include <ieeefp.h>
+#endif
# include <math.h>
+#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 <time.h>
# include <fcntl.h>
# include <dlfcn.h>
# include <pthread.h>
+#ifdef SOLARIS
# include <thread.h>
+#endif
# include <limits.h>
# include <errno.h>
+#ifdef SOLARIS
# include <sys/trap.h>
# include <sys/regset.h>
# include <sys/procset.h>
# include <ucontext.h>
# include <setjmp.h>
+#endif
# ifdef SOLARIS_MUTATOR_LIBTHREAD
# include <sys/procfs.h>
# endif
+#ifdef LINUX
+# include <inttypes.h>
+# include <signal.h>
+# include <ucontext.h>
+# include <sys/time.h>
+#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