From 0170e9ad0885d28b718dd947babc73e2c444647a Mon Sep 17 00:00:00 2001 From: twisti Date: Tue, 14 Dec 2010 12:44:30 -0800 Subject: 7006044: materialize cheap non-oop pointers on 64-bit SPARC Summary: After 6961690 we load non-oop pointers for the constant table which could easily be materialized in a few instructions. Reviewed-by: never, kvn --- src/cpu/sparc/vm/assembler_sparc.cpp | 65 +++++++++++++++++++++++------------- src/cpu/sparc/vm/assembler_sparc.hpp | 13 ++++---- src/cpu/sparc/vm/sparc.ad | 43 ++++++++++++++++++------ 3 files changed, 82 insertions(+), 39 deletions(-) diff --git a/src/cpu/sparc/vm/assembler_sparc.cpp b/src/cpu/sparc/vm/assembler_sparc.cpp index 8512afcba..7b3d82db3 100644 --- a/src/cpu/sparc/vm/assembler_sparc.cpp +++ b/src/cpu/sparc/vm/assembler_sparc.cpp @@ -23,6 +23,7 @@ */ #include "precompiled.hpp" +#include "asm/assembler.hpp" #include "assembler_sparc.inline.hpp" #include "gc_interface/collectedHeap.inline.hpp" #include "interpreter/interpreter.hpp" @@ -1327,37 +1328,38 @@ void MacroAssembler::patchable_sethi(const AddressLiteral& addrlit, Register d) } -int MacroAssembler::size_of_sethi(address a, bool worst_case) { +int MacroAssembler::insts_for_sethi(address a, bool worst_case) { #ifdef _LP64 - if (worst_case) return 7; - intptr_t iaddr = (intptr_t)a; - int hi32 = (int)(iaddr >> 32); - int lo32 = (int)(iaddr); - int inst_count; - if (hi32 == 0 && lo32 >= 0) - inst_count = 1; - else if (hi32 == -1) - inst_count = 2; + if (worst_case) return 7; + intptr_t iaddr = (intptr_t) a; + int msb32 = (int) (iaddr >> 32); + int lsb32 = (int) (iaddr); + int count; + if (msb32 == 0 && lsb32 >= 0) + count = 1; + else if (msb32 == -1) + count = 2; else { - inst_count = 2; - if ( hi32 & 0x3ff ) - inst_count++; - if ( lo32 & 0xFFFFFC00 ) { - if( (lo32 >> 20) & 0xfff ) inst_count += 2; - if( (lo32 >> 10) & 0x3ff ) inst_count += 2; + count = 2; + if (msb32 & 0x3ff) + count++; + if (lsb32 & 0xFFFFFC00 ) { + if ((lsb32 >> 20) & 0xfff) count += 2; + if ((lsb32 >> 10) & 0x3ff) count += 2; } } - return BytesPerInstWord * inst_count; + return count; #else - return BytesPerInstWord; + return 1; #endif } -int MacroAssembler::worst_case_size_of_set() { - return size_of_sethi(NULL, true) + 1; +int MacroAssembler::worst_case_insts_for_set() { + return insts_for_sethi(NULL, true) + 1; } +// Keep in sync with MacroAssembler::insts_for_internal_set void MacroAssembler::internal_set(const AddressLiteral& addrlit, Register d, bool ForceRelocatable) { intptr_t value = addrlit.value(); @@ -1379,6 +1381,23 @@ void MacroAssembler::internal_set(const AddressLiteral& addrlit, Register d, boo } } +// Keep in sync with MacroAssembler::internal_set +int MacroAssembler::insts_for_internal_set(intptr_t value) { + // can optimize + if (-4096 <= value && value <= 4095) { + return 1; + } + if (inv_hi22(hi22(value)) == value) { + return insts_for_sethi((address) value); + } + int count = insts_for_sethi((address) value); + AddressLiteral al(value); + if (al.low10() != 0) { + count++; + } + return count; +} + void MacroAssembler::set(const AddressLiteral& al, Register d) { internal_set(al, d, false); } @@ -1443,11 +1462,11 @@ void MacroAssembler::set64(jlong value, Register d, Register tmp) { } } -int MacroAssembler::size_of_set64(jlong value) { +int MacroAssembler::insts_for_set64(jlong value) { v9_dep(); - int hi = (int)(value >> 32); - int lo = (int)(value & ~0); + int hi = (int) (value >> 32); + int lo = (int) (value & ~0); int count = 0; // (Matcher::isSimpleConstant64 knows about the following optimizations.) diff --git a/src/cpu/sparc/vm/assembler_sparc.hpp b/src/cpu/sparc/vm/assembler_sparc.hpp index ae4357edd..253193868 100644 --- a/src/cpu/sparc/vm/assembler_sparc.hpp +++ b/src/cpu/sparc/vm/assembler_sparc.hpp @@ -1884,23 +1884,24 @@ public: void sethi(const AddressLiteral& addrlit, Register d); void patchable_sethi(const AddressLiteral& addrlit, Register d); - // compute the size of a sethi/set - static int size_of_sethi( address a, bool worst_case = false ); - static int worst_case_size_of_set(); + // compute the number of instructions for a sethi/set + static int insts_for_sethi( address a, bool worst_case = false ); + static int worst_case_insts_for_set(); // set may be either setsw or setuw (high 32 bits may be zero or sign) private: void internal_set(const AddressLiteral& al, Register d, bool ForceRelocatable); + static int insts_for_internal_set(intptr_t value); public: void set(const AddressLiteral& addrlit, Register d); void set(intptr_t value, Register d); void set(address addr, Register d, RelocationHolder const& rspec); + static int insts_for_set(intptr_t value) { return insts_for_internal_set(value); } + void patchable_set(const AddressLiteral& addrlit, Register d); void patchable_set(intptr_t value, Register d); void set64(jlong value, Register d, Register tmp); - - // Compute size of set64. - static int size_of_set64(jlong value); + static int insts_for_set64(jlong value); // sign-extend 32 to 64 inline void signx( Register s, Register d ) { sra( s, G0, d); } diff --git a/src/cpu/sparc/vm/sparc.ad b/src/cpu/sparc/vm/sparc.ad index 018fe70b9..1909d010b 100644 --- a/src/cpu/sparc/vm/sparc.ad +++ b/src/cpu/sparc/vm/sparc.ad @@ -1086,9 +1086,9 @@ void MachConstantBaseNode::emit(CodeBuffer& cbuf, PhaseRegAlloc* ra_) const { uint MachConstantBaseNode::size(PhaseRegAlloc*) const { if (UseRDPCForConstantTableBase) { // This is really the worst case but generally it's only 1 instruction. - return 4 /*rdpc*/ + 4 /*sub*/ + MacroAssembler::worst_case_size_of_set(); + return (1 /*rdpc*/ + 1 /*sub*/ + MacroAssembler::worst_case_insts_for_set()) * BytesPerInstWord; } else { - return MacroAssembler::worst_case_size_of_set(); + return MacroAssembler::worst_case_insts_for_set() * BytesPerInstWord; } } @@ -1240,7 +1240,7 @@ const Pipeline * MachEpilogNode::pipeline() const { int MachEpilogNode::safepoint_offset() const { assert( do_polling(), "no return for this epilog node"); - return MacroAssembler::size_of_sethi(os::get_polling_page()); + return MacroAssembler::insts_for_sethi(os::get_polling_page()) * BytesPerInstWord; } //============================================================================= @@ -3553,7 +3553,8 @@ operand immP() %{ interface(CONST_INTER); %} -// Pointer Immediate: 32 or 64-bit +#ifdef _LP64 +// Pointer Immediate: 64-bit operand immP_set() %{ predicate(!VM_Version::is_niagara1_plus()); match(ConP); @@ -3564,10 +3565,21 @@ operand immP_set() %{ interface(CONST_INTER); %} -// Pointer Immediate: 32 or 64-bit +// Pointer Immediate: 64-bit // From Niagara2 processors on a load should be better than materializing. operand immP_load() %{ - predicate(VM_Version::is_niagara1_plus()); + predicate(VM_Version::is_niagara1_plus() && (n->bottom_type()->isa_oop_ptr() || (MacroAssembler::insts_for_set(n->get_ptr()) > 3))); + match(ConP); + + op_cost(5); + // formats are generated automatically for constants and base registers + format %{ %} + interface(CONST_INTER); +%} + +// Pointer Immediate: 64-bit +operand immP_no_oop_cheap() %{ + predicate(VM_Version::is_niagara1_plus() && !n->bottom_type()->isa_oop_ptr() && (MacroAssembler::insts_for_set(n->get_ptr()) <= 3)); match(ConP); op_cost(5); @@ -3575,6 +3587,7 @@ operand immP_load() %{ format %{ %} interface(CONST_INTER); %} +#endif operand immP13() %{ predicate((-4096 < n->get_ptr()) && (n->get_ptr() <= 4095)); @@ -3673,7 +3686,7 @@ operand immL_32bits() %{ // Long Immediate: cheap (materialize in <= 3 instructions) operand immL_cheap() %{ - predicate(!VM_Version::is_niagara1_plus() || MacroAssembler::size_of_set64(n->get_long()) <= 3); + predicate(!VM_Version::is_niagara1_plus() || MacroAssembler::insts_for_set64(n->get_long()) <= 3); match(ConL); op_cost(0); @@ -3683,7 +3696,7 @@ operand immL_cheap() %{ // Long Immediate: expensive (materialize in > 3 instructions) operand immL_expensive() %{ - predicate(VM_Version::is_niagara1_plus() && MacroAssembler::size_of_set64(n->get_long()) > 3); + predicate(VM_Version::is_niagara1_plus() && MacroAssembler::insts_for_set64(n->get_long()) > 3); match(ConL); op_cost(0); @@ -6094,8 +6107,18 @@ instruct loadConP_load(iRegP dst, immP_load con) %{ ins_cost(MEMORY_REF_COST); format %{ "LD [$constanttablebase + $constantoffset],$dst\t! load from constant table: ptr=$con" %} ins_encode %{ - RegisterOrConstant con_offset = __ ensure_simm13_or_reg($constantoffset($con), $dst$$Register); - __ ld_ptr($constanttablebase, con_offset, $dst$$Register); + RegisterOrConstant con_offset = __ ensure_simm13_or_reg($constantoffset($con), $dst$$Register); + __ ld_ptr($constanttablebase, con_offset, $dst$$Register); + %} + ins_pipe(loadConP); +%} + +instruct loadConP_no_oop_cheap(iRegP dst, immP_no_oop_cheap con) %{ + match(Set dst con); + ins_cost(DEFAULT_COST * 3/2); + format %{ "SET $con,$dst\t! non-oop ptr" %} + ins_encode %{ + __ set($con$$constant, $dst$$Register); %} ins_pipe(loadConP); %} -- cgit v1.2.3 From 462f2df177b529e6b8655c6392818424ebca9fa2 Mon Sep 17 00:00:00 2001 From: never Date: Tue, 14 Dec 2010 23:17:00 -0800 Subject: 6765546: Wrong sscanf used to parse CompilerOracle command >= 32 characters could lead to crash Reviewed-by: kvn, iveresov --- src/share/vm/compiler/compilerOracle.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/share/vm/compiler/compilerOracle.cpp b/src/share/vm/compiler/compilerOracle.cpp index 3bc679fdd..314648961 100644 --- a/src/share/vm/compiler/compilerOracle.cpp +++ b/src/share/vm/compiler/compilerOracle.cpp @@ -332,7 +332,7 @@ static OracleCommand parse_command_name(const char * line, int* bytes_read) { "command_names size mismatch"); *bytes_read = 0; - char command[32]; + char command[33]; int result = sscanf(line, "%32[a-z]%n", command, bytes_read); for (uint i = 0; i < ARRAY_SIZE(command_names); i++) { if (strcmp(command, command_names[i]) == 0) { @@ -470,6 +470,12 @@ void CompilerOracle::parse_from_line(char* line) { OracleCommand command = parse_command_name(line, &bytes_read); line += bytes_read; + if (command == UnknownCommand) { + tty->print_cr("CompilerOracle: unrecognized line"); + tty->print_cr(" \"%s\"", original_line); + return; + } + if (command == QuietCommand) { _quiet = true; return; @@ -498,7 +504,7 @@ void CompilerOracle::parse_from_line(char* line) { line += bytes_read; // there might be a signature following the method. // signatures always begin with ( so match that by hand - if (1 == sscanf(line, "%*[ \t](%254[);/" RANGEBASE "]%n", sig + 1, &bytes_read)) { + if (1 == sscanf(line, "%*[ \t](%254[[);/" RANGEBASE "]%n", sig + 1, &bytes_read)) { sig[0] = '('; line += bytes_read; signature = oopFactory::new_symbol_handle(sig, CHECK); -- cgit v1.2.3 From 8ce3533ea21bd95f93b9f06a0475ae5ed5073a2e Mon Sep 17 00:00:00 2001 From: never Date: Thu, 16 Dec 2010 12:47:52 -0800 Subject: 6839888: Array overrun in vm adlc Reviewed-by: kvn, iveresov --- src/share/vm/adlc/dict2.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/share/vm/adlc/dict2.cpp b/src/share/vm/adlc/dict2.cpp index c9423df2e..22ec13d2c 100644 --- a/src/share/vm/adlc/dict2.cpp +++ b/src/share/vm/adlc/dict2.cpp @@ -34,7 +34,7 @@ #define MAXID 20 static char initflag = 0; // True after 1st initialization static char shft[MAXID] = {1,2,3,4,5,6,7,1,2,3,4,5,6,7,1,2,3,4,5,6}; -static short xsum[MAXID + 1]; +static short xsum[MAXID]; //------------------------------bucket--------------------------------------- class bucket { @@ -66,7 +66,7 @@ void Dict::init() { // Precompute table of null character hashes if( !initflag ) { // Not initializated yet? xsum[0] = (1<> 1); // Hash key, un-modulo'd table size } -- cgit v1.2.3 From 84141a1121014a5a3ddd8714e0144939b389eddb Mon Sep 17 00:00:00 2001 From: kvn Date: Thu, 16 Dec 2010 14:15:12 -0800 Subject: 7006505: Use kstat info to identify SPARC processor Summary: read Solaris kstat data to get more precise CPU information Reviewed-by: iveresov, never, twisti, dholmes --- make/solaris/makefiles/buildtree.make | 2 +- make/solaris/makefiles/vm.make | 4 ++ src/cpu/sparc/vm/sparc.ad | 10 +-- src/cpu/sparc/vm/vm_version_sparc.cpp | 49 +++++++-------- src/cpu/sparc/vm/vm_version_sparc.hpp | 38 ++++++++---- src/os/solaris/vm/os_solaris.cpp | 2 +- .../solaris_sparc/vm/vm_version_solaris_sparc.cpp | 71 +++++++++++++++++++++- src/share/vm/memory/universe.cpp | 11 ++-- 8 files changed, 136 insertions(+), 51 deletions(-) diff --git a/make/solaris/makefiles/buildtree.make b/make/solaris/makefiles/buildtree.make index c0c7831e0..2dbeac167 100644 --- a/make/solaris/makefiles/buildtree.make +++ b/make/solaris/makefiles/buildtree.make @@ -61,7 +61,7 @@ include $(GAMMADIR)/make/scm.make QUIETLY$(MAKE_VERBOSE) = @ # For now, until the compiler is less wobbly: -TESTFLAGS = -Xbatch -showversion +TESTFLAGS = -Xbatch -Xmx32m -showversion ### maye ARCH_XXX instead? ifdef USE_GCC diff --git a/make/solaris/makefiles/vm.make b/make/solaris/makefiles/vm.make index 508b1d878..fb7a1db86 100644 --- a/make/solaris/makefiles/vm.make +++ b/make/solaris/makefiles/vm.make @@ -119,6 +119,10 @@ else LIBS += -lsocket -lsched -ldl $(LIBM) -lthread -lc endif # sparcWorks +ifeq ("${Platform_arch}", "sparc") +LIBS += -lkstat +endif + # By default, link the *.o into the library, not the executable. LINK_INTO$(LINK_INTO) = LIBJVM diff --git a/src/cpu/sparc/vm/sparc.ad b/src/cpu/sparc/vm/sparc.ad index 1909d010b..25117f205 100644 --- a/src/cpu/sparc/vm/sparc.ad +++ b/src/cpu/sparc/vm/sparc.ad @@ -3556,7 +3556,7 @@ operand immP() %{ #ifdef _LP64 // Pointer Immediate: 64-bit operand immP_set() %{ - predicate(!VM_Version::is_niagara1_plus()); + predicate(!VM_Version::is_niagara_plus()); match(ConP); op_cost(5); @@ -3568,7 +3568,7 @@ operand immP_set() %{ // Pointer Immediate: 64-bit // From Niagara2 processors on a load should be better than materializing. operand immP_load() %{ - predicate(VM_Version::is_niagara1_plus() && (n->bottom_type()->isa_oop_ptr() || (MacroAssembler::insts_for_set(n->get_ptr()) > 3))); + predicate(VM_Version::is_niagara_plus() && (n->bottom_type()->isa_oop_ptr() || (MacroAssembler::insts_for_set(n->get_ptr()) > 3))); match(ConP); op_cost(5); @@ -3579,7 +3579,7 @@ operand immP_load() %{ // Pointer Immediate: 64-bit operand immP_no_oop_cheap() %{ - predicate(VM_Version::is_niagara1_plus() && !n->bottom_type()->isa_oop_ptr() && (MacroAssembler::insts_for_set(n->get_ptr()) <= 3)); + predicate(VM_Version::is_niagara_plus() && !n->bottom_type()->isa_oop_ptr() && (MacroAssembler::insts_for_set(n->get_ptr()) <= 3)); match(ConP); op_cost(5); @@ -3686,7 +3686,7 @@ operand immL_32bits() %{ // Long Immediate: cheap (materialize in <= 3 instructions) operand immL_cheap() %{ - predicate(!VM_Version::is_niagara1_plus() || MacroAssembler::insts_for_set64(n->get_long()) <= 3); + predicate(!VM_Version::is_niagara_plus() || MacroAssembler::insts_for_set64(n->get_long()) <= 3); match(ConL); op_cost(0); @@ -3696,7 +3696,7 @@ operand immL_cheap() %{ // Long Immediate: expensive (materialize in > 3 instructions) operand immL_expensive() %{ - predicate(VM_Version::is_niagara1_plus() && MacroAssembler::insts_for_set64(n->get_long()) > 3); + predicate(VM_Version::is_niagara_plus() && MacroAssembler::insts_for_set64(n->get_long()) > 3); match(ConL); op_cost(0); diff --git a/src/cpu/sparc/vm/vm_version_sparc.cpp b/src/cpu/sparc/vm/vm_version_sparc.cpp index 9e1928619..6db8c7ad1 100644 --- a/src/cpu/sparc/vm/vm_version_sparc.cpp +++ b/src/cpu/sparc/vm/vm_version_sparc.cpp @@ -38,12 +38,6 @@ 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(); @@ -69,11 +63,21 @@ void VM_Version::initialize() { _supports_cx8 = has_v9(); - if (is_niagara1()) { + if (is_niagara()) { // Indirect branch is the same cost as direct if (FLAG_IS_DEFAULT(UseInlineCaches)) { FLAG_SET_DEFAULT(UseInlineCaches, false); } + // Align loops on a single instruction boundary. + if (FLAG_IS_DEFAULT(OptoLoopAlignment)) { + FLAG_SET_DEFAULT(OptoLoopAlignment, 4); + } + // When using CMS, we cannot use memset() in BOT updates because + // the sun4v/CMT version in libc_psr uses BIS which exposes + // "phantom zeros" to concurrent readers. See 6948537. + if (FLAG_IS_DEFAULT(UseMemSetInBOT) && UseConcMarkSweepGC) { + FLAG_SET_DEFAULT(UseMemSetInBOT, false); + } #ifdef _LP64 // 32-bit oops don't make sense for the 64-bit VM on sparc // since the 32-bit VM has the same registers and smaller objects. @@ -89,7 +93,7 @@ void VM_Version::initialize() { if (FLAG_IS_DEFAULT(InteriorEntryAlignment)) { FLAG_SET_DEFAULT(InteriorEntryAlignment, 4); } - if (is_niagara1_plus()) { + if (is_niagara_plus()) { if (has_blk_init() && AllocatePrefetchStyle > 0 && FLAG_IS_DEFAULT(AllocatePrefetchStyle)) { // Use BIS instruction for allocation prefetch. @@ -105,15 +109,6 @@ void VM_Version::initialize() { } } #endif - if (FLAG_IS_DEFAULT(OptoLoopAlignment)) { - FLAG_SET_DEFAULT(OptoLoopAlignment, 4); - } - // When using CMS, we cannot use memset() in BOT updates because - // the sun4v/CMT version in libc_psr uses BIS which exposes - // "phantom zeros" to concurrent readers. See 6948537. - if (FLAG_IS_DEFAULT(UseMemSetInBOT) && UseConcMarkSweepGC) { - FLAG_SET_DEFAULT(UseMemSetInBOT, false); - } } // Use hardware population count instruction if available. @@ -129,17 +124,18 @@ void VM_Version::initialize() { #endif char buf[512]; - jio_snprintf(buf, sizeof(buf), "%s%s%s%s%s%s%s%s%s%s%s%s%s%s", + jio_snprintf(buf, sizeof(buf), "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", (has_v8() ? ", has_v8" : ""), (has_v9() ? ", has_v9" : ""), (has_hardware_popc() ? ", popc" : ""), (has_vis1() ? ", has_vis1" : ""), (has_vis2() ? ", has_vis2" : ""), + (has_vis3() ? ", has_vis3" : ""), (has_blk_init() ? ", has_blk_init" : ""), (is_ultra3() ? ", is_ultra3" : ""), (is_sun4v() ? ", is_sun4v" : ""), - (is_niagara1() ? ", is_niagara1" : ""), - (is_niagara1_plus() ? ", is_niagara1_plus" : ""), + (is_niagara() ? ", is_niagara" : ""), + (is_niagara_plus() ? ", is_niagara_plus" : ""), (is_sparc64() ? ", is_sparc64" : ""), (!has_hardware_mul32() ? ", no-mul32" : ""), (!has_hardware_div32() ? ", no-div32" : ""), @@ -190,17 +186,18 @@ int VM_Version::determine_features() { warning("Cannot recognize SPARC version. Default to V9"); } - if (UseNiagaraInstrs) { - if (is_niagara1(features)) { + assert(is_T_family(features) == is_niagara(features), "Niagara should be T series"); + if (UseNiagaraInstrs) { // Force code generation for Niagara + if (is_T_family(features)) { // Happy to accomodate... } else { NOT_PRODUCT(if (PrintMiscellaneous && Verbose) tty->print_cr("Version is Forced-Niagara");) - features = niagara1_m; + features |= T_family_m; } } else { - if (is_niagara1(features) && !FLAG_IS_DEFAULT(UseNiagaraInstrs)) { + if (is_T_family(features) && !FLAG_IS_DEFAULT(UseNiagaraInstrs)) { NOT_PRODUCT(if (PrintMiscellaneous && Verbose) tty->print_cr("Version is Forced-Not-Niagara");) - features &= ~niagara1_unique_m; + features &= ~(T_family_m | T1_model_m); } else { // Happy to accomodate... } @@ -222,7 +219,7 @@ void VM_Version::revert() { unsigned int VM_Version::calc_parallel_worker_threads() { unsigned int result; - if (is_niagara1_plus()) { + if (is_niagara_plus()) { result = nof_parallel_worker_threads(5, 16, 8); } else { result = nof_parallel_worker_threads(5, 8, 8); diff --git a/src/cpu/sparc/vm/vm_version_sparc.hpp b/src/cpu/sparc/vm/vm_version_sparc.hpp index 5ae1fcbc3..c83d2de99 100644 --- a/src/cpu/sparc/vm/vm_version_sparc.hpp +++ b/src/cpu/sparc/vm/vm_version_sparc.hpp @@ -41,7 +41,12 @@ protected: vis2_instructions = 7, sun4v_instructions = 8, blk_init_instructions = 9, - fmaf_instructions = 10 + fmaf_instructions = 10, + fmau_instructions = 11, + vis3_instructions = 12, + sparc64_family = 13, + T_family = 14, + T1_model = 15 }; enum Feature_Flag_Set { @@ -59,6 +64,11 @@ protected: sun4v_m = 1 << sun4v_instructions, blk_init_instructions_m = 1 << blk_init_instructions, fmaf_instructions_m = 1 << fmaf_instructions, + fmau_instructions_m = 1 << fmau_instructions, + vis3_instructions_m = 1 << vis3_instructions, + sparc64_family_m = 1 << sparc64_family, + T_family_m = 1 << T_family, + T1_model_m = 1 << T1_model, generic_v8_m = v8_instructions_m | hardware_mul32_m | hardware_div32_m | hardware_fsmuld_m, generic_v9_m = generic_v8_m | v9_instructions_m, @@ -76,8 +86,13 @@ protected: static int determine_features(); static int platform_features(int features); - static bool is_niagara1(int features) { return (features & sun4v_m) != 0; } - static bool is_sparc64(int features) { return (features & fmaf_instructions_m) != 0; } + // Returns true if the platform is in the niagara line (T series) + static bool is_T_family(int features) { return (features & T_family_m) != 0; } + static bool is_niagara() { return is_T_family(_features); } + DEBUG_ONLY( static bool is_niagara(int features) { return (features & sun4v_m) != 0; } ) + + // Returns true if it is niagara1 (T1). + static bool is_T1_model(int features) { return is_T_family(features) && ((features & T1_model_m) != 0); } static int maximum_niagara1_processor_count() { return 32; } @@ -94,6 +109,7 @@ public: static bool has_hardware_popc() { return (_features & hardware_popc_m) != 0; } static bool has_vis1() { return (_features & vis1_instructions_m) != 0; } static bool has_vis2() { return (_features & vis2_instructions_m) != 0; } + static bool has_vis3() { return (_features & vis3_instructions_m) != 0; } static bool has_blk_init() { return (_features & blk_init_instructions_m) != 0; } static bool supports_compare_and_exchange() @@ -101,14 +117,14 @@ public: static bool is_ultra3() { return (_features & ultra3_m) == ultra3_m; } static bool is_sun4v() { return (_features & sun4v_m) != 0; } - static bool is_niagara1() { return is_niagara1(_features); } - // Returns true if the platform is in the niagara line and - // newer than the niagara1. - static bool is_niagara1_plus(); - static bool is_sparc64() { return is_sparc64(_features); } - - static bool has_fast_fxtof() { return has_v9() && !is_ultra3(); } - static bool has_fast_idiv() { return is_niagara1_plus() || is_sparc64(); } + // Returns true if the platform is in the niagara line (T series) + // and newer than the niagara1. + static bool is_niagara_plus() { return is_T_family(_features) && !is_T1_model(_features); } + // Fujitsu SPARC64 + static bool is_sparc64() { return (_features & sparc64_family_m) != 0; } + + static bool has_fast_fxtof() { return is_niagara() || is_sparc64() || has_v9() && !is_ultra3(); } + static bool has_fast_idiv() { return is_niagara_plus() || is_sparc64(); } static const char* cpu_features() { return _features_str; } diff --git a/src/os/solaris/vm/os_solaris.cpp b/src/os/solaris/vm/os_solaris.cpp index f9898d332..4d5673f54 100644 --- a/src/os/solaris/vm/os_solaris.cpp +++ b/src/os/solaris/vm/os_solaris.cpp @@ -3065,7 +3065,7 @@ char* os::attempt_reserve_memory_at(size_t bytes, char* requested_addr) { if (addr == NULL) { jio_snprintf(buf, sizeof(buf), ": %s", strerror(err)); } - warning("attempt_reserve_memory_at: couldn't reserve %d bytes at " + warning("attempt_reserve_memory_at: couldn't reserve " SIZE_FORMAT " bytes at " PTR_FORMAT ": reserve_memory_helper returned " PTR_FORMAT "%s", bytes, requested_addr, addr, buf); } diff --git a/src/os_cpu/solaris_sparc/vm/vm_version_solaris_sparc.cpp b/src/os_cpu/solaris_sparc/vm/vm_version_solaris_sparc.cpp index 982f987c3..855e9a965 100644 --- a/src/os_cpu/solaris_sparc/vm/vm_version_solaris_sparc.cpp +++ b/src/os_cpu/solaris_sparc/vm/vm_version_solaris_sparc.cpp @@ -29,6 +29,7 @@ # include # include # include +# include // We need to keep these here as long as we have to build on Solaris // versions before 10. @@ -96,11 +97,23 @@ int VM_Version::platform_features(int features) { #ifndef AV_SPARC_ASI_BLK_INIT #define AV_SPARC_ASI_BLK_INIT 0x0080 /* ASI_BLK_INIT_xxx ASI */ #endif + if (av & AV_SPARC_ASI_BLK_INIT) features |= blk_init_instructions_m; + #ifndef AV_SPARC_FMAF -#define AV_SPARC_FMAF 0x0100 /* Sparc64 Fused Multiply-Add */ +#define AV_SPARC_FMAF 0x0100 /* Fused Multiply-Add */ #endif - if (av & AV_SPARC_ASI_BLK_INIT) features |= blk_init_instructions_m; if (av & AV_SPARC_FMAF) features |= fmaf_instructions_m; + +#ifndef AV_SPARC_FMAU +#define AV_SPARC_FMAU 0x0200 /* Unfused Multiply-Add */ +#endif + if (av & AV_SPARC_FMAU) features |= fmau_instructions_m; + +#ifndef AV_SPARC_VIS3 +#define AV_SPARC_VIS3 0x0400 /* VIS3 instruction set extensions */ +#endif + if (av & AV_SPARC_VIS3) features |= vis3_instructions_m; + } else { // getisax(2) failed, use the old legacy code. #ifndef PRODUCT @@ -140,5 +153,59 @@ int VM_Version::platform_features(int features) { // Determine the machine type. do_sysinfo(SI_MACHINE, "sun4v", &features, sun4v_m); + { + // Using kstat to determine the machine type. + kstat_ctl_t* kc = kstat_open(); + kstat_t* ksp = kstat_lookup(kc, (char*)"cpu_info", -1, NULL); + const char* implementation = "UNKNOWN"; + if (ksp != NULL) { + if (kstat_read(kc, ksp, NULL) != -1 && ksp->ks_data != NULL) { + kstat_named_t* knm = (kstat_named_t *)ksp->ks_data; + for (int i = 0; i < ksp->ks_ndata; i++) { + if (strcmp((const char*)&(knm[i].name),"implementation") == 0) { +#ifndef KSTAT_DATA_STRING +#define KSTAT_DATA_STRING 9 +#endif + if (knm[i].data_type == KSTAT_DATA_CHAR) { + // VM is running on Solaris 8 which does not have value.str. + implementation = &(knm[i].value.c[0]); + } else if (knm[i].data_type == KSTAT_DATA_STRING) { + // VM is running on Solaris 10. +#ifndef KSTAT_NAMED_STR_PTR + // Solaris 8 was used to build VM, define the structure it misses. + struct str_t { + union { + char *ptr; /* NULL-term string */ + char __pad[8]; /* 64-bit padding */ + } addr; + uint32_t len; /* # bytes for strlen + '\0' */ + }; +#define KSTAT_NAMED_STR_PTR(knptr) (( (str_t*)&((knptr)->value) )->addr.ptr) +#endif + implementation = KSTAT_NAMED_STR_PTR(&knm[i]); + } +#ifndef PRODUCT + if (PrintMiscellaneous && Verbose) { + tty->print_cr("cpu_info.implementation: %s", implementation); + } +#endif + if (strncmp(implementation, "SPARC64", 7) == 0) { + features |= sparc64_family_m; + } else if (strncmp(implementation, "UltraSPARC-T", 12) == 0) { + features |= T_family_m; + if (strncmp(implementation, "UltraSPARC-T1", 13) == 0) { + features |= T1_model_m; + } + } + break; + } + } // for( + } + } + assert(strcmp(implementation, "UNKNOWN") != 0, + "unknown cpu info (changed kstat interface?)"); + kstat_close(kc); + } + return features; } diff --git a/src/share/vm/memory/universe.cpp b/src/share/vm/memory/universe.cpp index 9909e8035..9d5af98fd 100644 --- a/src/share/vm/memory/universe.cpp +++ b/src/share/vm/memory/universe.cpp @@ -934,7 +934,8 @@ jint Universe::initialize_heap() { // See needs_explicit_null_check. // Only set the heap base for compressed oops because it indicates // compressed oops for pstack code. - if (PrintCompressedOopsMode) { + bool verbose = PrintCompressedOopsMode || (PrintMiscellaneous && Verbose); + if (verbose) { tty->cr(); tty->print("heap address: " PTR_FORMAT ", size: " SIZE_FORMAT " MB", Universe::heap()->base(), Universe::heap()->reserved_region().byte_size()/M); @@ -943,12 +944,12 @@ jint Universe::initialize_heap() { // Can't reserve heap below 32Gb. Universe::set_narrow_oop_base(Universe::heap()->base() - os::vm_page_size()); Universe::set_narrow_oop_shift(LogMinObjAlignmentInBytes); - if (PrintCompressedOopsMode) { + if (verbose) { tty->print(", Compressed Oops with base: "PTR_FORMAT, Universe::narrow_oop_base()); } } else { Universe::set_narrow_oop_base(0); - if (PrintCompressedOopsMode) { + if (verbose) { tty->print(", zero based Compressed Oops"); } #ifdef _WIN64 @@ -963,12 +964,12 @@ jint Universe::initialize_heap() { Universe::set_narrow_oop_shift(LogMinObjAlignmentInBytes); } else { Universe::set_narrow_oop_shift(0); - if (PrintCompressedOopsMode) { + if (verbose) { tty->print(", 32-bits Oops"); } } } - if (PrintCompressedOopsMode) { + if (verbose) { tty->cr(); tty->cr(); } -- cgit v1.2.3 From 7c17b2cb4ec9bd5fcec0efb5ca22c73c43f64370 Mon Sep 17 00:00:00 2001 From: kevinw Date: Fri, 17 Dec 2010 12:14:48 +0000 Subject: 7003487: clhsdbproc stacktrace fails on x64 Reviewed-by: phh --- .../share/classes/sun/jvm/hotspot/ui/classbrowser/HTMLGenerator.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/agent/src/share/classes/sun/jvm/hotspot/ui/classbrowser/HTMLGenerator.java b/agent/src/share/classes/sun/jvm/hotspot/ui/classbrowser/HTMLGenerator.java index 49c101fe6..759e6d101 100644 --- a/agent/src/share/classes/sun/jvm/hotspot/ui/classbrowser/HTMLGenerator.java +++ b/agent/src/share/classes/sun/jvm/hotspot/ui/classbrowser/HTMLGenerator.java @@ -30,6 +30,7 @@ import sun.jvm.hotspot.asm.*; import sun.jvm.hotspot.asm.sparc.*; import sun.jvm.hotspot.asm.x86.*; import sun.jvm.hotspot.asm.ia64.*; +import sun.jvm.hotspot.asm.amd64.*; import sun.jvm.hotspot.code.*; import sun.jvm.hotspot.compiler.*; import sun.jvm.hotspot.debugger.*; @@ -198,6 +199,8 @@ public class HTMLGenerator implements /* imports */ ClassConstants { cpuHelper = new SPARCHelper(); } else if (cpu.equals("x86")) { cpuHelper = new X86Helper(); + } else if (cpu.equals("amd64")) { + cpuHelper = new AMD64Helper(); } else if (cpu.equals("ia64")) { cpuHelper = new IA64Helper(); } else { -- cgit v1.2.3 From 0bb093501df11ae04bb90ea330f25db6810ad354 Mon Sep 17 00:00:00 2001 From: never Date: Fri, 17 Dec 2010 15:55:32 -0800 Subject: 6579789: Internal error "c1_LinearScan.cpp:1429 Error: assert(false,"")" in debuggee with fastdebug VM Reviewed-by: kvn, iveresov --- src/share/vm/c1/c1_LinearScan.cpp | 23 +++++++++++++++- src/share/vm/c1/c1_LinearScan.hpp | 1 + test/compiler/6579789/Test6579789.java | 49 ++++++++++++++++++++++++++++++++++ 3 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 test/compiler/6579789/Test6579789.java diff --git a/src/share/vm/c1/c1_LinearScan.cpp b/src/share/vm/c1/c1_LinearScan.cpp index fe118944a..7419f9e8f 100644 --- a/src/share/vm/c1/c1_LinearScan.cpp +++ b/src/share/vm/c1/c1_LinearScan.cpp @@ -90,6 +90,7 @@ LinearScan::LinearScan(IR* ir, LIRGenerator* gen, FrameMap* frame_map) , _intervals(0) // initialized later with correct length , _new_intervals_from_allocation(new IntervalList()) , _sorted_intervals(NULL) + , _needs_full_resort(false) , _lir_ops(0) // initialized later with correct length , _block_of_op(0) // initialized later with correct length , _has_info(0) @@ -1520,6 +1521,14 @@ void LinearScan::create_unhandled_lists(Interval** list1, Interval** list2, bool void LinearScan::sort_intervals_before_allocation() { TIME_LINEAR_SCAN(timer_sort_intervals_before); + if (_needs_full_resort) { + // There is no known reason why this should occur but just in case... + assert(false, "should never occur"); + // Re-sort existing interval list because an Interval::from() has changed + _sorted_intervals->sort(interval_cmp); + _needs_full_resort = false; + } + IntervalList* unsorted_list = &_intervals; int unsorted_len = unsorted_list->length(); int sorted_len = 0; @@ -1559,11 +1568,18 @@ void LinearScan::sort_intervals_before_allocation() { } } _sorted_intervals = sorted_list; + assert(is_sorted(_sorted_intervals), "intervals unsorted"); } void LinearScan::sort_intervals_after_allocation() { TIME_LINEAR_SCAN(timer_sort_intervals_after); + if (_needs_full_resort) { + // Re-sort existing interval list because an Interval::from() has changed + _sorted_intervals->sort(interval_cmp); + _needs_full_resort = false; + } + IntervalArray* old_list = _sorted_intervals; IntervalList* new_list = _new_intervals_from_allocation; int old_len = old_list->length(); @@ -1571,6 +1587,7 @@ void LinearScan::sort_intervals_after_allocation() { if (new_len == 0) { // no intervals have been added during allocation, so sorted list is already up to date + assert(is_sorted(_sorted_intervals), "intervals unsorted"); return; } @@ -1593,6 +1610,7 @@ void LinearScan::sort_intervals_after_allocation() { } _sorted_intervals = combined_list; + assert(is_sorted(_sorted_intervals), "intervals unsorted"); } @@ -1825,6 +1843,8 @@ void LinearScan::resolve_exception_entry(BlockBegin* block, int reg_num, MoveRes interval = interval->split(from_op_id); interval->assign_reg(reg, regHi); append_interval(interval); + } else { + _needs_full_resort = true; } assert(interval->from() == from_op_id, "must be true now"); @@ -4492,7 +4512,8 @@ void Interval::print(outputStream* out) const { } } else { type_name = type2name(type()); - if (assigned_reg() != -1) { + if (assigned_reg() != -1 && + (LinearScan::num_physical_regs(type()) == 1 || assigned_regHi() != -1)) { opr = LinearScan::calc_operand_for_interval(this); } } diff --git a/src/share/vm/c1/c1_LinearScan.hpp b/src/share/vm/c1/c1_LinearScan.hpp index 97f4043c1..018570f9c 100644 --- a/src/share/vm/c1/c1_LinearScan.hpp +++ b/src/share/vm/c1/c1_LinearScan.hpp @@ -148,6 +148,7 @@ class LinearScan : public CompilationResourceObj { IntervalList _intervals; // mapping from register number to interval IntervalList* _new_intervals_from_allocation; // list with all intervals created during allocation when an existing interval is split IntervalArray* _sorted_intervals; // intervals sorted by Interval::from() + bool _needs_full_resort; // set to true if an Interval::from() is changed and _sorted_intervals must be resorted LIR_OpArray _lir_ops; // mapping from LIR_Op id to LIR_Op node BlockBeginArray _block_of_op; // mapping from LIR_Op id to the BlockBegin containing this instruction diff --git a/test/compiler/6579789/Test6579789.java b/test/compiler/6579789/Test6579789.java new file mode 100644 index 000000000..344a08fae --- /dev/null +++ b/test/compiler/6579789/Test6579789.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/** + * @test + * @bug 6579789 + * @summary Internal error "c1_LinearScan.cpp:1429 Error: assert(false,"")" in debuggee with fastdebug VM + * @run main/othervm -Xcomp -XX:UseSSE=0 -XX:CompileOnly=Test6579789.bug Test6579789 + */ + +public class Test6579789 { + public static void main(String[] args) { + bug(4); + } + public static void bug(int n) { + float f = 1; + int i = 1; + try { + int x = 1 / n; // instruction that can trap + f = 2; + i = 2; + int y = 2 / n; // instruction that can trap + } catch (Exception ex) { + f++; + i++; + } + } +} -- cgit v1.2.3 From 5ed601e92b9c14dcc297cd90f38b8303407e5d94 Mon Sep 17 00:00:00 2001 From: twisti Date: Sat, 18 Dec 2010 01:15:01 -0800 Subject: 6990933: assert(sender_cb) failed: sanity in frame::sender_for_interpreter_frame Reviewed-by: never --- src/share/vm/code/nmethod.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/share/vm/code/nmethod.cpp b/src/share/vm/code/nmethod.cpp index 089586bac..3f5d66f85 100644 --- a/src/share/vm/code/nmethod.cpp +++ b/src/share/vm/code/nmethod.cpp @@ -811,9 +811,11 @@ nmethod::nmethod( _stub_offset = content_offset() + code_buffer->total_offset_of(code_buffer->stubs()); // Exception handler and deopt handler are in the stub section + assert(offsets->value(CodeOffsets::Exceptions) != -1, "must be set"); + assert(offsets->value(CodeOffsets::Deopt ) != -1, "must be set"); _exception_offset = _stub_offset + offsets->value(CodeOffsets::Exceptions); _deoptimize_offset = _stub_offset + offsets->value(CodeOffsets::Deopt); - if (has_method_handle_invokes()) { + if (offsets->value(CodeOffsets::DeoptMH) != -1) { _deoptimize_mh_offset = _stub_offset + offsets->value(CodeOffsets::DeoptMH); } else { _deoptimize_mh_offset = -1; @@ -1909,6 +1911,7 @@ void nmethod::copy_scopes_pcs(PcDesc* pcs, int count) { break; } } + assert(has_method_handle_invokes() == (_deoptimize_mh_offset != -1), "must have deopt mh handler"); int size = count * sizeof(PcDesc); assert(scopes_pcs_size() >= size, "oob"); -- cgit v1.2.3 From 6882f9d5a7e6a78e767a06d4083d98fda6595a48 Mon Sep 17 00:00:00 2001 From: bobv Date: Mon, 20 Dec 2010 14:30:24 -0500 Subject: 7007769: VM crashes with SIGBUS writing PerfData if tmp space is full Summary: Fill perfdata file with zeros to verify available disk space Reviewed-by: coleenp, kamg --- src/os/linux/vm/perfMemory_linux.cpp | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/src/os/linux/vm/perfMemory_linux.cpp b/src/os/linux/vm/perfMemory_linux.cpp index db5340f9d..1cd430cfb 100644 --- a/src/os/linux/vm/perfMemory_linux.cpp +++ b/src/os/linux/vm/perfMemory_linux.cpp @@ -635,7 +635,29 @@ static int create_sharedmem_resources(const char* dirname, const char* filename, return -1; } - return fd; + // Verify that we have enough disk space for this file. + // We'll get random SIGBUS crashes on memory accesses if + // we don't. + + for (size_t seekpos = 0; seekpos < size; seekpos += os::vm_page_size()) { + int zero_int = 0; + result = (int)os::seek_to_file_offset(fd, (jlong)(seekpos)); + if (result == -1 ) break; + RESTARTABLE(::write(fd, &zero_int, 1), result); + if (result != 1) { + if (errno == ENOSPC) { + warning("Insufficient space for shared memory file:\n %s\nTry using the -Djava.io.tmpdir= option to select an alternate temp location.\n", filename); + } + break; + } + } + + if (result != -1) { + return fd; + } else { + RESTARTABLE(::close(fd), result); + return -1; + } } // open the shared memory file for the given user and vmid. returns -- cgit v1.2.3 From 086c9b6ef8cfbfcbdd815bec65f50c377238be65 Mon Sep 17 00:00:00 2001 From: twisti Date: Tue, 21 Dec 2010 04:37:30 -0800 Subject: 7008165: Garbage in ClassFormatError message Summary: When bootstrap_method_ref in BootstrapMethods attribute points to a wrong CP entry (non-MethodHandle), JVM throws ClassFormatError with a message, where method index and class file name is garbage. Reviewed-by: iveresov --- src/share/vm/classfile/classFileParser.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/share/vm/classfile/classFileParser.cpp b/src/share/vm/classfile/classFileParser.cpp index 3712c8ae4..3779fc7d6 100644 --- a/src/share/vm/classfile/classFileParser.cpp +++ b/src/share/vm/classfile/classFileParser.cpp @@ -2386,19 +2386,21 @@ void ClassFileParser::parse_classfile_bootstrap_methods_attribute(constantPoolHa valid_cp_range(bootstrap_method_index, cp_size) && cp->tag_at(bootstrap_method_index).is_method_handle(), "bootstrap_method_index %u has bad constant type in class file %s", + bootstrap_method_index, CHECK); operands->short_at_put(operand_fill_index++, bootstrap_method_index); operands->short_at_put(operand_fill_index++, argument_count); cfs->guarantee_more(sizeof(u2) * argument_count, CHECK); // argv[argc] for (int j = 0; j < argument_count; j++) { - u2 arg_index = cfs->get_u2_fast(); + u2 argument_index = cfs->get_u2_fast(); check_property( - valid_cp_range(arg_index, cp_size) && - cp->tag_at(arg_index).is_loadable_constant(), + valid_cp_range(argument_index, cp_size) && + cp->tag_at(argument_index).is_loadable_constant(), "argument_index %u has bad constant type in class file %s", + argument_index, CHECK); - operands->short_at_put(operand_fill_index++, arg_index); + operands->short_at_put(operand_fill_index++, argument_index); } } -- cgit v1.2.3 From a91816c9d8d13122450b19b6f696da8976f16650 Mon Sep 17 00:00:00 2001 From: kvn Date: Tue, 21 Dec 2010 13:56:40 -0800 Subject: 7003130: assert(iterations Date: Tue, 21 Dec 2010 23:39:42 -0500 Subject: 7008444: Remove unnecessary include of stdint.h in java_md.c Summary: Remove unnecessary include of stdint.h in java_md.c Reviewed-by: brutisso, kvn --- src/os/posix/launcher/java_md.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/os/posix/launcher/java_md.c b/src/os/posix/launcher/java_md.c index 78a1ca33a..3ee0f20a7 100644 --- a/src/os/posix/launcher/java_md.c +++ b/src/os/posix/launcher/java_md.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include #include -- cgit v1.2.3 From b2ae5eeeec6889c1c33afe3e88e861fab9fe4545 Mon Sep 17 00:00:00 2001 From: iveresov Date: Tue, 21 Dec 2010 22:57:17 -0800 Subject: 7008466: Tiered: Enable testing of tiered compilation in JPRT Summary: Add running specjvm98 and specjbb2005 with tiered compilation enabled with JPRT. Reviewed-by: kvn --- make/jprt.properties | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/make/jprt.properties b/make/jprt.properties index 04554aabe..cea29d4b5 100644 --- a/make/jprt.properties +++ b/make/jprt.properties @@ -150,6 +150,7 @@ jprt.build.targets= \ jprt.my.solaris.sparc.test.targets= \ ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-jvm98, \ + ${jprt.my.solaris.sparc}-{product|fastdebug}-c2-jvm98_tiered, \ ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-scimark, \ ${jprt.my.solaris.sparc}-product-{c1|c2}-runThese, \ ${jprt.my.solaris.sparc}-fastdebug-c1-runThese_Xshare, \ @@ -168,6 +169,7 @@ jprt.my.solaris.sparc.test.targets= \ ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-GCOld_G1, \ ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-GCOld_ParOldGC, \ ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-jbb_default, \ + ${jprt.my.solaris.sparc}-{product|fastdebug}-c2-jbb_default_tiered, \ ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-jbb_SerialGC, \ ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-jbb_ParallelGC, \ ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-jbb_CMS, \ @@ -176,6 +178,7 @@ jprt.my.solaris.sparc.test.targets= \ jprt.my.solaris.sparcv9.test.targets= \ ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-jvm98, \ + ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-jvm98_tiered, \ ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-scimark, \ ${jprt.my.solaris.sparcv9}-product-c2-runThese, \ ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-GCBasher_default, \ @@ -193,6 +196,7 @@ jprt.my.solaris.sparcv9.test.targets= \ ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-GCOld_G1, \ ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-GCOld_ParOldGC, \ ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-jbb_default, \ + ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-jbb_default_tiered, \ ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-jbb_SerialGC, \ ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-jbb_ParallelGC, \ ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-jbb_CMS, \ @@ -201,6 +205,7 @@ jprt.my.solaris.sparcv9.test.targets= \ jprt.my.solaris.x64.test.targets= \ ${jprt.my.solaris.x64}-{product|fastdebug}-c2-jvm98, \ + ${jprt.my.solaris.x64}-{product|fastdebug}-c2-jvm98_tiered, \ ${jprt.my.solaris.x64}-{product|fastdebug}-c2-scimark, \ ${jprt.my.solaris.x64}-product-c2-runThese, \ ${jprt.my.solaris.x64}-product-c2-runThese_Xcomp, \ @@ -219,6 +224,7 @@ jprt.my.solaris.x64.test.targets= \ ${jprt.my.solaris.x64}-{product|fastdebug}-c2-GCOld_G1, \ ${jprt.my.solaris.x64}-{product|fastdebug}-c2-GCOld_ParOldGC, \ ${jprt.my.solaris.x64}-{product|fastdebug}-c2-jbb_default, \ + ${jprt.my.solaris.x64}-{product|fastdebug}-c2-jbb_default_tiered, \ ${jprt.my.solaris.x64}-{product|fastdebug}-c2-jbb_SerialGC, \ ${jprt.my.solaris.x64}-{product|fastdebug}-c2-jbb_ParallelGC, \ ${jprt.my.solaris.x64}-{product|fastdebug}-c2-GCOld_CMS, \ @@ -227,6 +233,7 @@ jprt.my.solaris.x64.test.targets= \ jprt.my.solaris.i586.test.targets= \ ${jprt.my.solaris.i586}-{product|fastdebug}-{c1|c2}-jvm98, \ + ${jprt.my.solaris.i586}-{product|fastdebug}-c2-jvm98_tiered, \ ${jprt.my.solaris.i586}-{product|fastdebug}-{c1|c2}-scimark, \ ${jprt.my.solaris.i586}-product-{c1|c2}-runThese_Xcomp, \ ${jprt.my.solaris.i586}-fastdebug-c1-runThese_Xcomp, \ @@ -253,6 +260,7 @@ jprt.my.solaris.i586.test.targets= \ ${jprt.my.solaris.i586}-product-c1-GCOld_G1, \ ${jprt.my.solaris.i586}-product-c1-GCOld_ParOldGC, \ ${jprt.my.solaris.i586}-fastdebug-c2-jbb_default, \ + ${jprt.my.solaris.i586}-fastdebug-c2-jbb_default_tiered, \ ${jprt.my.solaris.i586}-fastdebug-c2-jbb_ParallelGC, \ ${jprt.my.solaris.i586}-fastdebug-c2-jbb_CMS, \ ${jprt.my.solaris.i586}-fastdebug-c2-jbb_G1, \ @@ -260,6 +268,7 @@ jprt.my.solaris.i586.test.targets= \ jprt.my.linux.i586.test.targets = \ ${jprt.my.linux.i586}-{product|fastdebug}-{c1|c2}-jvm98, \ + ${jprt.my.linux.i586}-{product|fastdebug}-c2-jvm98_tiered, \ ${jprt.my.linux.i586}-{product|fastdebug}-{c1|c2}-scimark, \ ${jprt.my.linux.i586}-product-c1-runThese_Xcomp, \ ${jprt.my.linux.i586}-fastdebug-c1-runThese_Xshare, \ @@ -279,6 +288,7 @@ jprt.my.linux.i586.test.targets = \ ${jprt.my.linux.i586}-product-{c1|c2}-GCOld_G1, \ ${jprt.my.linux.i586}-product-{c1|c2}-GCOld_ParOldGC, \ ${jprt.my.linux.i586}-{product|fastdebug}-c1-jbb_default, \ + ${jprt.my.linux.i586}-{product|fastdebug}-c2-jbb_default_tiered, \ ${jprt.my.linux.i586}-{product|fastdebug}-c1-jbb_ParallelGC, \ ${jprt.my.linux.i586}-{product|fastdebug}-c1-jbb_CMS, \ ${jprt.my.linux.i586}-{product|fastdebug}-c1-jbb_G1, \ @@ -286,6 +296,7 @@ jprt.my.linux.i586.test.targets = \ jprt.my.linux.x64.test.targets = \ ${jprt.my.linux.x64}-{product|fastdebug}-c2-jvm98, \ + ${jprt.my.linux.x64}-{product|fastdebug}-c2-jvm98_tiered, \ ${jprt.my.linux.x64}-{product|fastdebug}-c2-scimark, \ ${jprt.my.linux.x64}-{product|fastdebug}-c2-GCBasher_default, \ ${jprt.my.linux.x64}-{product|fastdebug}-c2-GCBasher_SerialGC, \ @@ -302,12 +313,14 @@ jprt.my.linux.x64.test.targets = \ ${jprt.my.linux.x64}-{product|fastdebug}-c2-GCOld_G1, \ ${jprt.my.linux.x64}-{product|fastdebug}-c2-GCOld_ParOldGC, \ ${jprt.my.linux.x64}-{product|fastdebug}-c2-jbb_default, \ + ${jprt.my.linux.x64}-{product|fastdebug}-c2-jbb_default_tiered, \ ${jprt.my.linux.x64}-{product|fastdebug}-c2-jbb_ParallelGC, \ ${jprt.my.linux.x64}-{product|fastdebug}-c2-jbb_G1, \ ${jprt.my.linux.x64}-{product|fastdebug}-c2-jbb_ParOldGC jprt.my.windows.i586.test.targets = \ ${jprt.my.windows.i586}-{product|fastdebug}-{c1|c2}-jvm98, \ + ${jprt.my.windows.i586}-{product|fastdebug}-c2-jvm98_tiered, \ ${jprt.my.windows.i586}-{product|fastdebug}-{c1|c2}-scimark, \ ${jprt.my.windows.i586}-product-{c1|c2}-runThese, \ ${jprt.my.windows.i586}-product-{c1|c2}-runThese_Xcomp, \ @@ -327,6 +340,7 @@ jprt.my.windows.i586.test.targets = \ ${jprt.my.windows.i586}-product-{c1|c2}-GCOld_G1, \ ${jprt.my.windows.i586}-product-{c1|c2}-GCOld_ParOldGC, \ ${jprt.my.windows.i586}-{product|fastdebug}-{c1|c2}-jbb_default, \ + ${jprt.my.windows.i586}-{product|fastdebug}-c2-jbb_default_tiered, \ ${jprt.my.windows.i586}-product-{c1|c2}-jbb_ParallelGC, \ ${jprt.my.windows.i586}-product-{c1|c2}-jbb_CMS, \ ${jprt.my.windows.i586}-product-{c1|c2}-jbb_G1, \ @@ -334,6 +348,7 @@ jprt.my.windows.i586.test.targets = \ jprt.my.windows.x64.test.targets = \ ${jprt.my.windows.x64}-{product|fastdebug}-c2-jvm98, \ + ${jprt.my.windows.x64}-{product|fastdebug}-c2-jvm98_tiered, \ ${jprt.my.windows.x64}-{product|fastdebug}-c2-scimark, \ ${jprt.my.windows.x64}-product-c2-runThese, \ ${jprt.my.windows.x64}-product-c2-runThese_Xcomp, \ @@ -351,6 +366,7 @@ jprt.my.windows.x64.test.targets = \ ${jprt.my.windows.x64}-{product|fastdebug}-c2-GCOld_G1, \ ${jprt.my.windows.x64}-{product|fastdebug}-c2-GCOld_ParOldGC, \ ${jprt.my.windows.x64}-{product|fastdebug}-c2-jbb_default, \ + ${jprt.my.windows.x64}-{product|fastdebug}-c2-jbb_default_tiered, \ ${jprt.my.windows.x64}-product-c2-jbb_CMS, \ ${jprt.my.windows.x64}-product-c2-jbb_ParallelGC, \ ${jprt.my.windows.x64}-product-c2-jbb_G1, \ -- cgit v1.2.3 From 6e1f63bf8286194d847981fd2090be83f35744fe Mon Sep 17 00:00:00 2001 From: twisti Date: Wed, 22 Dec 2010 02:02:53 -0800 Subject: 7007377: JSR 292 MethodHandlesTest.testCastFailure fails on SPARC with -Xcomp +DeoptimizeALot Reviewed-by: kvn, jrose --- src/cpu/sparc/vm/methodHandles_sparc.cpp | 70 +++++++++----------- src/cpu/x86/vm/methodHandles_x86.cpp | 106 +++++++++++++++++-------------- src/share/vm/prims/methodHandles.cpp | 13 ++-- src/share/vm/prims/methodHandles.hpp | 6 +- src/share/vm/runtime/init.cpp | 3 - 5 files changed, 100 insertions(+), 98 deletions(-) diff --git a/src/cpu/sparc/vm/methodHandles_sparc.cpp b/src/cpu/sparc/vm/methodHandles_sparc.cpp index 699f9151b..2fb2e56d8 100644 --- a/src/cpu/sparc/vm/methodHandles_sparc.cpp +++ b/src/cpu/sparc/vm/methodHandles_sparc.cpp @@ -395,18 +395,23 @@ int MethodHandles::adapter_conversion_ops_supported_mask() { // // Generate an "entry" field for a method handle. // This determines how the method handle will respond to calls. -void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHandles::EntryKind ek) { +void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHandles::EntryKind ek, TRAPS) { // Here is the register state during an interpreted call, // as set up by generate_method_handle_interpreter_entry(): // - G5: garbage temp (was MethodHandle.invoke methodOop, unused) // - G3: receiver method handle // - O5_savedSP: sender SP (must preserve) - Register O0_argslot = O0; - Register O1_scratch = O1; - Register O2_scratch = O2; - Register O3_scratch = O3; - Register G5_index = G5; + const Register O0_argslot = O0; + const Register O1_scratch = O1; + const Register O2_scratch = O2; + const Register O3_scratch = O3; + const Register G5_index = G5; + + // Argument registers for _raise_exception. + const Register O0_code = O0; + const Register O1_actual = O1; + const Register O2_required = O2; guarantee(java_dyn_MethodHandle::vmentry_offset_in_bytes() != 0, "must have offsets"); @@ -439,48 +444,36 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan case _raise_exception: { // Not a real MH entry, but rather shared code for raising an - // exception. Extra local arguments are passed in scratch - // registers, as required type in O3, failing object (or NULL) - // in O2, failing bytecode type in O1. + // exception. Since we use a C2I adapter to set up the + // interpreter state, arguments are expected in compiler + // argument registers. + methodHandle mh(raise_exception_method()); + address c2i_entry = methodOopDesc::make_adapters(mh, CATCH); __ mov(O5_savedSP, SP); // Cut the stack back to where the caller started. - // Push arguments as if coming from the interpreter. - Register O0_scratch = O0_argslot; - int stackElementSize = Interpreter::stackElementSize; - - // Make space on the stack for the arguments and set Gargs - // correctly. - __ sub(SP, 4*stackElementSize, SP); // Keep stack aligned. - __ add(SP, (frame::varargs_offset)*wordSize - 1*Interpreter::stackElementSize + STACK_BIAS + BytesPerWord, Gargs); - - // void raiseException(int code, Object actual, Object required) - __ st( O1_scratch, Address(Gargs, 2*stackElementSize)); // code - __ st_ptr(O2_scratch, Address(Gargs, 1*stackElementSize)); // actual - __ st_ptr(O3_scratch, Address(Gargs, 0*stackElementSize)); // required - - Label no_method; + Label L_no_method; // FIXME: fill in _raise_exception_method with a suitable sun.dyn method __ set(AddressLiteral((address) &_raise_exception_method), G5_method); __ ld_ptr(Address(G5_method, 0), G5_method); __ tst(G5_method); - __ brx(Assembler::zero, false, Assembler::pn, no_method); + __ brx(Assembler::zero, false, Assembler::pn, L_no_method); __ delayed()->nop(); - int jobject_oop_offset = 0; + const int jobject_oop_offset = 0; __ ld_ptr(Address(G5_method, jobject_oop_offset), G5_method); __ tst(G5_method); - __ brx(Assembler::zero, false, Assembler::pn, no_method); + __ brx(Assembler::zero, false, Assembler::pn, L_no_method); __ delayed()->nop(); __ verify_oop(G5_method); - __ jump_indirect_to(G5_method_fie, O1_scratch); + __ jump_to(AddressLiteral(c2i_entry), O3_scratch); __ delayed()->nop(); // If we get here, the Java runtime did not do its job of creating the exception. // Do something that is at least causes a valid throw from the interpreter. - __ bind(no_method); - __ unimplemented("_raise_exception no method"); + __ bind(L_no_method); + __ unimplemented("call throw_WrongMethodType_entry"); } break; @@ -570,10 +563,10 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan // Throw an exception. // For historical reasons, it will be IncompatibleClassChangeError. __ unimplemented("not tested yet"); - __ ld_ptr(Address(O1_intf, java_mirror_offset), O3_scratch); // required interface - __ mov(O0_klass, O2_scratch); // bad receiver - __ jump_to(AddressLiteral(from_interpreted_entry(_raise_exception)), O0_argslot); - __ delayed()->mov(Bytecodes::_invokeinterface, O1_scratch); // who is complaining? + __ ld_ptr(Address(O1_intf, java_mirror_offset), O2_required); // required interface + __ mov( O0_klass, O1_actual); // bad receiver + __ jump_to(AddressLiteral(from_interpreted_entry(_raise_exception)), O3_scratch); + __ delayed()->mov(Bytecodes::_invokeinterface, O0_code); // who is complaining? } break; @@ -663,11 +656,10 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan __ check_klass_subtype(O1_scratch, G5_klass, O0_argslot, O2_scratch, done); // If we get here, the type check failed! - __ ldsw(G3_amh_vmargslot, O0_argslot); // reload argslot field - __ load_heap_oop(G3_amh_argument, O3_scratch); // required class - __ ld_ptr(vmarg, O2_scratch); // bad object - __ jump_to(AddressLiteral(from_interpreted_entry(_raise_exception)), O0_argslot); - __ delayed()->mov(Bytecodes::_checkcast, O1_scratch); // who is complaining? + __ load_heap_oop(G3_amh_argument, O2_required); // required class + __ ld_ptr( vmarg, O1_actual); // bad object + __ jump_to(AddressLiteral(from_interpreted_entry(_raise_exception)), O3_scratch); + __ delayed()->mov(Bytecodes::_checkcast, O0_code); // who is complaining? __ bind(done); // Get the new MH: diff --git a/src/cpu/x86/vm/methodHandles_x86.cpp b/src/cpu/x86/vm/methodHandles_x86.cpp index 5c707fec0..f92beb483 100644 --- a/src/cpu/x86/vm/methodHandles_x86.cpp +++ b/src/cpu/x86/vm/methodHandles_x86.cpp @@ -385,9 +385,12 @@ int MethodHandles::adapter_conversion_ops_supported_mask() { // FIXME: MethodHandlesTest gets a crash if we enable OP_SPREAD_ARGS. } +//------------------------------------------------------------------------------ +// MethodHandles::generate_method_handle_stub +// // Generate an "entry" field for a method handle. // This determines how the method handle will respond to calls. -void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHandles::EntryKind ek) { +void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHandles::EntryKind ek, TRAPS) { // Here is the register state during an interpreted call, // as set up by generate_method_handle_interpreter_entry(): // - rbx: garbage temp (was MethodHandle.invoke methodOop, unused) @@ -396,14 +399,21 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan // - rsi/r13: sender SP (must preserve; see prepare_to_jump_from_interpreted) // - rdx: garbage temp, can blow away - Register rcx_recv = rcx; - Register rax_argslot = rax; - Register rbx_temp = rbx; - Register rdx_temp = rdx; + const Register rcx_recv = rcx; + const Register rax_argslot = rax; + const Register rbx_temp = rbx; + const Register rdx_temp = rdx; // This guy is set up by prepare_to_jump_from_interpreted (from interpreted calls) // and gen_c2i_adapter (from compiled calls): - Register saved_last_sp = LP64_ONLY(r13) NOT_LP64(rsi); + const Register saved_last_sp = LP64_ONLY(r13) NOT_LP64(rsi); + + // Argument registers for _raise_exception. + // 32-bit: Pass first two oop/int args in registers ECX and EDX. + const Register rarg0_code = LP64_ONLY(j_rarg0) NOT_LP64(rcx); + const Register rarg1_actual = LP64_ONLY(j_rarg1) NOT_LP64(rdx); + const Register rarg2_required = LP64_ONLY(j_rarg2) NOT_LP64(rdi); + assert_different_registers(rarg0_code, rarg1_actual, rarg2_required, saved_last_sp); guarantee(java_dyn_MethodHandle::vmentry_offset_in_bytes() != 0, "must have offsets"); @@ -437,47 +447,41 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan switch ((int) ek) { case _raise_exception: { - // Not a real MH entry, but rather shared code for raising an exception. - // Extra local arguments are pushed on stack, as required type at TOS+8, - // failing object (or NULL) at TOS+4, failing bytecode type at TOS. - // Beyond those local arguments are the PC, of course. - Register rdx_code = rdx_temp; - Register rcx_fail = rcx_recv; - Register rax_want = rax_argslot; - Register rdi_pc = rdi; - __ pop(rdx_code); // TOS+0 - __ pop(rcx_fail); // TOS+4 - __ pop(rax_want); // TOS+8 - __ pop(rdi_pc); // caller PC - - __ mov(rsp, rsi); // cut the stack back to where the caller started - - // Repush the arguments as if coming from the interpreter. - __ push(rdx_code); - __ push(rcx_fail); - __ push(rax_want); + // Not a real MH entry, but rather shared code for raising an + // exception. Since we use a C2I adapter to set up the + // interpreter state, arguments are expected in compiler + // argument registers. + methodHandle mh(raise_exception_method()); + address c2i_entry = methodOopDesc::make_adapters(mh, CHECK); + + const Register rdi_pc = rax; + __ pop(rdi_pc); // caller PC + __ mov(rsp, saved_last_sp); // cut the stack back to where the caller started Register rbx_method = rbx_temp; - Label no_method; + Label L_no_method; // FIXME: fill in _raise_exception_method with a suitable sun.dyn method __ movptr(rbx_method, ExternalAddress((address) &_raise_exception_method)); __ testptr(rbx_method, rbx_method); - __ jccb(Assembler::zero, no_method); - int jobject_oop_offset = 0; + __ jccb(Assembler::zero, L_no_method); + + const int jobject_oop_offset = 0; __ movptr(rbx_method, Address(rbx_method, jobject_oop_offset)); // dereference the jobject __ testptr(rbx_method, rbx_method); - __ jccb(Assembler::zero, no_method); + __ jccb(Assembler::zero, L_no_method); __ verify_oop(rbx_method); - __ push(rdi_pc); // and restore caller PC - __ jmp(rbx_method_fie); + + // 32-bit: push remaining arguments as if coming from the compiler. + NOT_LP64(__ push(rarg2_required)); + + __ push(rdi_pc); // restore caller PC + __ jump(ExternalAddress(c2i_entry)); // do C2I transition // If we get here, the Java runtime did not do its job of creating the exception. // Do something that is at least causes a valid throw from the interpreter. - __ bind(no_method); - __ pop(rax_want); - __ pop(rcx_fail); - __ push(rax_want); - __ push(rcx_fail); + __ bind(L_no_method); + __ push(rarg2_required); + __ push(rarg1_actual); __ jump(ExternalAddress(Interpreter::throw_WrongMethodType_entry())); } break; @@ -572,9 +576,11 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan __ bind(no_such_interface); // Throw an exception. // For historical reasons, it will be IncompatibleClassChangeError. - __ pushptr(Address(rdx_intf, java_mirror_offset)); // required interface - __ push(rcx_recv); // bad receiver - __ push((int)Bytecodes::_invokeinterface); // who is complaining? + __ mov(rbx_temp, rcx_recv); // rarg2_required might be RCX + assert_different_registers(rarg2_required, rbx_temp); + __ movptr(rarg2_required, Address(rdx_intf, java_mirror_offset)); // required interface + __ mov( rarg1_actual, rbx_temp); // bad receiver + __ movl( rarg0_code, (int) Bytecodes::_invokeinterface); // who is complaining? __ jump(ExternalAddress(from_interpreted_entry(_raise_exception))); } break; @@ -669,10 +675,10 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan __ movl(rax_argslot, rcx_amh_vmargslot); // reload argslot field __ movptr(rdx_temp, vmarg); - __ load_heap_oop(rbx_klass, rcx_amh_argument); // required class - __ push(rbx_klass); - __ push(rdx_temp); // bad object - __ push((int)Bytecodes::_checkcast); // who is complaining? + assert_different_registers(rarg2_required, rdx_temp); + __ load_heap_oop(rarg2_required, rcx_amh_argument); // required class + __ mov( rarg1_actual, rdx_temp); // bad object + __ movl( rarg0_code, (int) Bytecodes::_checkcast); // who is complaining? __ jump(ExternalAddress(from_interpreted_entry(_raise_exception))); __ bind(done); @@ -1189,16 +1195,18 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan __ bind(bad_array_klass); UNPUSH_RSI_RDI; - __ pushptr(Address(rdx_array_klass, java_mirror_offset)); // required type - __ pushptr(vmarg); // bad array - __ push((int)Bytecodes::_aaload); // who is complaining? + assert(!vmarg.uses(rarg2_required), "must be different registers"); + __ movptr(rarg2_required, Address(rdx_array_klass, java_mirror_offset)); // required type + __ movptr(rarg1_actual, vmarg); // bad array + __ movl( rarg0_code, (int) Bytecodes::_aaload); // who is complaining? __ jump(ExternalAddress(from_interpreted_entry(_raise_exception))); __ bind(bad_array_length); UNPUSH_RSI_RDI; - __ push(rcx_recv); // AMH requiring a certain length - __ pushptr(vmarg); // bad array - __ push((int)Bytecodes::_arraylength); // who is complaining? + assert(!vmarg.uses(rarg2_required), "must be different registers"); + __ mov (rarg2_required, rcx_recv); // AMH requiring a certain length + __ movptr(rarg1_actual, vmarg); // bad array + __ movl( rarg0_code, (int) Bytecodes::_arraylength); // who is complaining? __ jump(ExternalAddress(from_interpreted_entry(_raise_exception))); #undef UNPUSH_RSI_RDI diff --git a/src/share/vm/prims/methodHandles.cpp b/src/share/vm/prims/methodHandles.cpp index 6c3318656..1b2c3c60d 100644 --- a/src/share/vm/prims/methodHandles.cpp +++ b/src/share/vm/prims/methodHandles.cpp @@ -111,7 +111,7 @@ bool MethodHandles::spot_check_entry_names() { //------------------------------------------------------------------------------ // MethodHandles::generate_adapters // -void MethodHandles::generate_adapters() { +void MethodHandles::generate_adapters(TRAPS) { if (!EnableMethodHandles || SystemDictionary::MethodHandle_klass() == NULL) return; assert(_adapter_code == NULL, "generate only once"); @@ -123,20 +123,20 @@ void MethodHandles::generate_adapters() { vm_exit_out_of_memory(_adapter_code_size, "CodeCache: no room for MethodHandles adapters"); CodeBuffer code(_adapter_code); MethodHandlesAdapterGenerator g(&code); - g.generate(); + g.generate(CHECK); } //------------------------------------------------------------------------------ // MethodHandlesAdapterGenerator::generate // -void MethodHandlesAdapterGenerator::generate() { +void MethodHandlesAdapterGenerator::generate(TRAPS) { // Generate generic method handle adapters. for (MethodHandles::EntryKind ek = MethodHandles::_EK_FIRST; ek < MethodHandles::_EK_LIMIT; ek = MethodHandles::EntryKind(1 + (int)ek)) { StubCodeMark mark(this, "MethodHandle", MethodHandles::entry_name(ek)); - MethodHandles::generate_method_handle_stub(_masm, ek); + MethodHandles::generate_method_handle_stub(_masm, ek, CHECK); } } @@ -2645,5 +2645,10 @@ JVM_ENTRY(void, JVM_RegisterMethodHandleMethods(JNIEnv *env, jclass MHN_class)) MethodHandles::set_enabled(true); } } + + // Generate method handles adapters if enabled. + if (MethodHandles::enabled()) { + MethodHandles::generate_adapters(CHECK); + } } JVM_END diff --git a/src/share/vm/prims/methodHandles.hpp b/src/share/vm/prims/methodHandles.hpp index 351dc33f6..f66f0e026 100644 --- a/src/share/vm/prims/methodHandles.hpp +++ b/src/share/vm/prims/methodHandles.hpp @@ -294,11 +294,11 @@ class MethodHandles: AllStatic { enum { _suppress_defc = 1, _suppress_name = 2, _suppress_type = 4 }; // Generate MethodHandles adapters. - static void generate_adapters(); + static void generate_adapters(TRAPS); // Called from InterpreterGenerator and MethodHandlesAdapterGenerator. static address generate_method_handle_interpreter_entry(MacroAssembler* _masm); - static void generate_method_handle_stub(MacroAssembler* _masm, EntryKind ek); + static void generate_method_handle_stub(MacroAssembler* _masm, EntryKind ek, TRAPS); // argument list parsing static int argument_slot(oop method_type, int arg); @@ -530,7 +530,7 @@ class MethodHandlesAdapterGenerator : public StubCodeGenerator { public: MethodHandlesAdapterGenerator(CodeBuffer* code) : StubCodeGenerator(code) {} - void generate(); + void generate(TRAPS); }; #endif // SHARE_VM_PRIMS_METHODHANDLES_HPP diff --git a/src/share/vm/runtime/init.cpp b/src/share/vm/runtime/init.cpp index 7c1904693..1f09c3683 100644 --- a/src/share/vm/runtime/init.cpp +++ b/src/share/vm/runtime/init.cpp @@ -125,9 +125,6 @@ jint init_globals() { javaClasses_init(); // must happen after vtable initialization stubRoutines_init2(); // note: StubRoutines need 2-phase init - // Generate MethodHandles adapters. - MethodHandles::generate_adapters(); - // Although we'd like to, we can't easily do a heap verify // here because the main thread isn't yet a JavaThread, so // its TLAB may not be made parseable from the usual interfaces. -- cgit v1.2.3 From 9096adc58b5ac4676acc2d43968ce45d41b4601e Mon Sep 17 00:00:00 2001 From: zgu Date: Wed, 22 Dec 2010 11:24:21 -0500 Subject: 6961186: Better VM handling of unexpected exceptions from application native code Summary: Trap uncaught C++ exception on Windows and Solaris and generate hs_err report. Reviewed-by: coleenp, bobv, dholmes --- src/os/solaris/vm/os_solaris.cpp | 9 +++++++++ src/os/windows/vm/os_windows.cpp | 20 ++++++++++++++++---- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/src/os/solaris/vm/os_solaris.cpp b/src/os/solaris/vm/os_solaris.cpp index 014176321..7b08e979d 100644 --- a/src/os/solaris/vm/os_solaris.cpp +++ b/src/os/solaris/vm/os_solaris.cpp @@ -80,6 +80,7 @@ // put OS-includes here # include # include +# include # include # include # include @@ -1475,6 +1476,13 @@ sigset_t* os::Solaris::allowdebug_blocked_signals() { return &allowdebug_blocked_sigs; } + +void _handle_uncaught_cxx_exception() { + VMError err("An uncaught C++ exception"); + err.report_and_die(); +} + + // First crack at OS-specific initialization, from inside the new thread. void os::initialize_thread() { int r = thr_main() ; @@ -1564,6 +1572,7 @@ void os::initialize_thread() { // use the dynamic check for T2 libthread. os::Solaris::init_thread_fpu_state(); + std::set_terminate(_handle_uncaught_cxx_exception); } diff --git a/src/os/windows/vm/os_windows.cpp b/src/os/windows/vm/os_windows.cpp index 1cc90f7b6..e6fd1a6b2 100644 --- a/src/os/windows/vm/os_windows.cpp +++ b/src/os/windows/vm/os_windows.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * CopyrighT (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -2007,6 +2007,16 @@ struct siglabel { int number; }; +// All Visual C++ exceptions thrown from code generated by the Microsoft Visual +// C++ compiler contain this error code. Because this is a compiler-generated +// error, the code is not listed in the Win32 API header files. +// The code is actually a cryptic mnemonic device, with the initial "E" +// standing for "exception" and the final 3 bytes (0x6D7363) representing the +// ASCII values of "msc". + +#define EXCEPTION_UNCAUGHT_CXX_EXCEPTION 0xE06D7363 + + struct siglabel exceptlabels[] = { def_excpt(EXCEPTION_ACCESS_VIOLATION), def_excpt(EXCEPTION_DATATYPE_MISALIGNMENT), @@ -2031,6 +2041,7 @@ struct siglabel exceptlabels[] = { def_excpt(EXCEPTION_INVALID_DISPOSITION), def_excpt(EXCEPTION_GUARD_PAGE), def_excpt(EXCEPTION_INVALID_HANDLE), + def_excpt(EXCEPTION_UNCAUGHT_CXX_EXCEPTION), NULL, 0 }; @@ -2264,7 +2275,6 @@ LONG WINAPI topLevelExceptionFilter(struct _EXCEPTION_POINTERS* exceptionInfo) { } } - if (t != NULL && t->is_Java_thread()) { JavaThread* thread = (JavaThread*) t; bool in_java = thread->thread_state() == _thread_in_Java; @@ -2468,8 +2478,9 @@ LONG WINAPI topLevelExceptionFilter(struct _EXCEPTION_POINTERS* exceptionInfo) { } // switch } #ifndef _WIN64 - if ((thread->thread_state() == _thread_in_Java) || - (thread->thread_state() == _thread_in_native) ) + if (((thread->thread_state() == _thread_in_Java) || + (thread->thread_state() == _thread_in_native)) && + exception_code != EXCEPTION_UNCAUGHT_CXX_EXCEPTION) { LONG result=Handle_FLT_Exception(exceptionInfo); if (result==EXCEPTION_CONTINUE_EXECUTION) return result; @@ -2493,6 +2504,7 @@ LONG WINAPI topLevelExceptionFilter(struct _EXCEPTION_POINTERS* exceptionInfo) { case EXCEPTION_ILLEGAL_INSTRUCTION_2: case EXCEPTION_INT_OVERFLOW: case EXCEPTION_INT_DIVIDE_BY_ZERO: + case EXCEPTION_UNCAUGHT_CXX_EXCEPTION: { report_error(t, exception_code, pc, exceptionInfo->ExceptionRecord, exceptionInfo->ContextRecord); } -- cgit v1.2.3 From 072973d3340d6add31f0df4e5dd015f0c2c95ded Mon Sep 17 00:00:00 2001 From: dcubed Date: Thu, 23 Dec 2010 07:58:35 -0800 Subject: 6987812: 2/3 SAJDI: "gHotSpotVMTypes was not initialized properly in the remote process" Summary: Change ExportDirectoryTableImpl to return the 'Export RVA' field without modification. Read 'Base Of Data' field in optional header when PE32 format COFF file is read. Refine search for dbgeng.dll and dbghelp.dll. Other cleanups. Reviewed-by: swamyv, poonam --- .../sun/jvm/hotspot/HotSpotTypeDataBase.java | 21 +-- .../debugger/win32/coff/COFFFileParser.java | 59 +++++-- .../hotspot/debugger/win32/coff/DumpExports.java | 57 +++--- .../hotspot/debugger/win32/coff/TestParser.java | 6 +- .../debugger/windbg/WindbgDebuggerLocal.java | 191 ++++++++++++++------- 5 files changed, 219 insertions(+), 115 deletions(-) diff --git a/agent/src/share/classes/sun/jvm/hotspot/HotSpotTypeDataBase.java b/agent/src/share/classes/sun/jvm/hotspot/HotSpotTypeDataBase.java index 967f8a4f1..9cf6122c7 100644 --- a/agent/src/share/classes/sun/jvm/hotspot/HotSpotTypeDataBase.java +++ b/agent/src/share/classes/sun/jvm/hotspot/HotSpotTypeDataBase.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -99,15 +99,8 @@ public class HotSpotTypeDataBase extends BasicTypeDataBase { long typeEntrySizeOffset; long typeEntryArrayStride; - typeEntryTypeNameOffset = getLongValueFromProcess("gHotSpotVMTypeEntryTypeNameOffset"); - typeEntrySuperclassNameOffset = getLongValueFromProcess("gHotSpotVMTypeEntrySuperclassNameOffset"); - typeEntryIsOopTypeOffset = getLongValueFromProcess("gHotSpotVMTypeEntryIsOopTypeOffset"); - typeEntryIsIntegerTypeOffset = getLongValueFromProcess("gHotSpotVMTypeEntryIsIntegerTypeOffset"); - typeEntryIsUnsignedOffset = getLongValueFromProcess("gHotSpotVMTypeEntryIsUnsignedOffset"); - typeEntrySizeOffset = getLongValueFromProcess("gHotSpotVMTypeEntrySizeOffset"); - typeEntryArrayStride = getLongValueFromProcess("gHotSpotVMTypeEntryArrayStride"); - - // Fetch the address of the VMTypeEntry* + // Fetch the address of the VMTypeEntry*. We get this symbol first + // and try to use it to make sure that symbol lookup is working. Address entryAddr = lookupInProcess("gHotSpotVMTypes"); // System.err.println("gHotSpotVMTypes address = " + entryAddr); // Dereference this once to get the pointer to the first VMTypeEntry @@ -118,6 +111,14 @@ public class HotSpotTypeDataBase extends BasicTypeDataBase { throw new RuntimeException("gHotSpotVMTypes was not initialized properly in the remote process; can not continue"); } + typeEntryTypeNameOffset = getLongValueFromProcess("gHotSpotVMTypeEntryTypeNameOffset"); + typeEntrySuperclassNameOffset = getLongValueFromProcess("gHotSpotVMTypeEntrySuperclassNameOffset"); + typeEntryIsOopTypeOffset = getLongValueFromProcess("gHotSpotVMTypeEntryIsOopTypeOffset"); + typeEntryIsIntegerTypeOffset = getLongValueFromProcess("gHotSpotVMTypeEntryIsIntegerTypeOffset"); + typeEntryIsUnsignedOffset = getLongValueFromProcess("gHotSpotVMTypeEntryIsUnsignedOffset"); + typeEntrySizeOffset = getLongValueFromProcess("gHotSpotVMTypeEntrySizeOffset"); + typeEntryArrayStride = getLongValueFromProcess("gHotSpotVMTypeEntryArrayStride"); + // Start iterating down it until we find an entry with no name Address typeNameAddr = null; do { diff --git a/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/COFFFileParser.java b/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/COFFFileParser.java index b2c988224..d29a62659 100644 --- a/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/COFFFileParser.java +++ b/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/COFFFileParser.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2004, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -122,10 +122,14 @@ public class COFFFileParser { private MemoizedObject[] sectionHeaders; private MemoizedObject[] symbols; + // Init stringTable at decl time since other fields init'ed in the + // constructor need the String Table. private MemoizedObject stringTable = new MemoizedObject() { public Object computeValue() { + // the String Table follows the Symbol Table int ptr = getPointerToSymbolTable(); if (ptr == 0) { + // no Symbol Table so no String Table return new StringTable(0); } else { return new StringTable(ptr + SYMBOL_SIZE * getNumberOfSymbols()); @@ -140,6 +144,8 @@ public class COFFFileParser { timeDateStamp = readInt(); pointerToSymbolTable = readInt(); numberOfSymbols = readInt(); + // String Table can be accessed at this point because + // pointerToSymbolTable and numberOfSymbols fields are set. sizeOfOptionalHeader = readShort(); characteristics = readShort(); @@ -222,6 +228,8 @@ public class COFFFileParser { private MemoizedObject windowsSpecificFields; private MemoizedObject dataDirectories; + // We use an offset of 2 because OptionalHeaderStandardFieldsImpl doesn't + // include the 'magic' field. private static final int STANDARD_FIELDS_OFFSET = 2; private static final int PE32_WINDOWS_SPECIFIC_FIELDS_OFFSET = 28; private static final int PE32_DATA_DIRECTORIES_OFFSET = 96; @@ -288,7 +296,7 @@ public class COFFFileParser { private int sizeOfUninitializedData; private int addressOfEntryPoint; private int baseOfCode; - private int baseOfData; + private int baseOfData; // only set in PE32 OptionalHeaderStandardFieldsImpl(int offset, boolean isPE32Plus) { @@ -301,7 +309,8 @@ public class COFFFileParser { sizeOfUninitializedData = readInt(); addressOfEntryPoint = readInt(); baseOfCode = readInt(); - if (isPE32Plus) { + if (!isPE32Plus) { + // only available in PE32 baseOfData = readInt(); } } @@ -433,7 +442,10 @@ public class COFFFileParser { if (dir.getRVA() == 0 || dir.getSize() == 0) { return null; } - return new ExportDirectoryTableImpl(rvaToFileOffset(dir.getRVA()), dir.getSize()); + // ExportDirectoryTableImpl needs both the RVA and the + // RVA converted to a file offset. + return new + ExportDirectoryTableImpl(dir.getRVA(), dir.getSize()); } }; @@ -526,6 +538,7 @@ public class COFFFileParser { } class ExportDirectoryTableImpl implements ExportDirectoryTable { + private int exportDataDirRVA; private int offset; private int size; @@ -548,8 +561,9 @@ public class COFFFileParser { private MemoizedObject exportOrdinalTable; private MemoizedObject exportAddressTable; - ExportDirectoryTableImpl(int offset, int size) { - this.offset = offset; + ExportDirectoryTableImpl(int exportDataDirRVA, int size) { + this.exportDataDirRVA = exportDataDirRVA; + offset = rvaToFileOffset(exportDataDirRVA); this.size = size; seek(offset); exportFlags = readInt(); @@ -595,6 +609,7 @@ public class COFFFileParser { exportOrdinalTable = new MemoizedObject() { public Object computeValue() { + // number of ordinals is same as the number of name pointers short[] ordinals = new short[getNumberOfNamePointers()]; seek(rvaToFileOffset(getOrdinalTableRVA())); for (int i = 0; i < ordinals.length; i++) { @@ -608,14 +623,18 @@ public class COFFFileParser { public Object computeValue() { int[] addresses = new int[getNumberOfAddressTableEntries()]; seek(rvaToFileOffset(getExportAddressTableRVA())); - // Must make two passes to avoid rvaToFileOffset - // destroying seek() position + // The Export Address Table values are a union of two + // possible values: + // Export RVA - The address of the exported symbol when + // loaded into memory, relative to the image base. + // This value doesn't get converted into a file offset. + // Forwarder RVA - The pointer to a null-terminated ASCII + // string in the export section. This value gets + // converted into a file offset because we have to + // fetch the string. for (int i = 0; i < addresses.length; i++) { addresses[i] = readInt(); } - for (int i = 0; i < addresses.length; i++) { - addresses[i] = rvaToFileOffset(addresses[i]); - } return addresses; } }; @@ -648,11 +667,12 @@ public class COFFFileParser { public boolean isExportAddressForwarder(short ordinal) { int addr = getExportAddress(ordinal); - return ((offset <= addr) && (addr < (offset + size))); + return ((exportDataDirRVA <= addr) && + (addr < (exportDataDirRVA + size))); } public String getExportAddressForwarder(short ordinal) { - seek(getExportAddress(ordinal)); + seek(rvaToFileOffset(getExportAddress(ordinal))); return readCString(); } @@ -3371,10 +3391,17 @@ public class COFFFileParser { throw new COFFException(e); } // Look up in string table + // FIXME: this index value is assumed to be in the valid range name = getStringTable().get(index); } else { try { - name = new String(tmpName, US_ASCII); + int length = 0; + // find last non-NULL + for (; length < tmpName.length && tmpName[length] != '\0';) { + length++; + } + // don't include NULL chars in returned name String + name = new String(tmpName, 0, length, US_ASCII); } catch (UnsupportedEncodingException e) { throw new COFFException(e); } @@ -3487,6 +3514,7 @@ public class COFFFileParser { tmpName[5] << 16 | tmpName[6] << 8 | tmpName[7]); + // FIXME: stringOffset is assumed to be in the valid range name = getStringTable().getAtOffset(stringOffset); } @@ -3698,12 +3726,13 @@ public class COFFFileParser { StringTable(int offset) { if (offset == 0) { + // no String Table strings = new COFFString[0]; return; } seek(offset); - int length = readInt(); + int length = readInt(); // length includes itself byte[] data = new byte[length - 4]; int numBytesRead = readBytes(data); if (numBytesRead != data.length) { diff --git a/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DumpExports.java b/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DumpExports.java index ec563f1d6..fd9d39aa5 100644 --- a/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DumpExports.java +++ b/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DumpExports.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,35 +37,48 @@ public class DumpExports { String filename = args[0]; COFFFile file = COFFFileParser.getParser().parse(filename); - ExportDirectoryTable exports = - file.getHeader(). - getOptionalHeader(). - getDataDirectories(). - getExportDirectoryTable(); + + // get common point for both things we want to dump + OptionalHeaderDataDirectories dataDirs = file.getHeader().getOptionalHeader(). + getDataDirectories(); + + // dump the header data directory for the Export Table: + DataDirectory dir = dataDirs.getExportTable(); + System.out.println("Export table: RVA = " + dir.getRVA() + "/0x" + + Integer.toHexString(dir.getRVA()) + ", size = " + dir.getSize() + "/0x" + + Integer.toHexString(dir.getSize())); + + System.out.println(file.getHeader().getNumberOfSections() + " sections in file"); + for (int i = 1; i <= file.getHeader().getNumberOfSections(); i++) { + SectionHeader sec = file.getHeader().getSectionHeader(i); + System.out.println(" Section " + i + ":"); + System.out.println(" Name = '" + sec.getName() + "'"); + System.out.println(" VirtualSize = " + sec.getSize() + "/0x" + + Integer.toHexString(sec.getSize())); + System.out.println(" VirtualAddress = " + sec.getVirtualAddress() + "/0x" + + Integer.toHexString(sec.getVirtualAddress())); + System.out.println(" SizeOfRawData = " + sec.getSizeOfRawData() + "/0x" + + Integer.toHexString(sec.getSizeOfRawData())); + System.out.println(" PointerToRawData = " + sec.getPointerToRawData() + "/0x" + + Integer.toHexString(sec.getPointerToRawData())); + } + + ExportDirectoryTable exports = dataDirs.getExportDirectoryTable(); if (exports == null) { System.out.println("No exports found."); } else { - System.out.println(file.getHeader().getNumberOfSections() + " sections in file"); - for (int i = 0; i < file.getHeader().getNumberOfSections(); i++) { - System.out.println(" Section " + i + ": " + file.getHeader().getSectionHeader(1 + i).getName()); - } - - DataDirectory dir = file.getHeader().getOptionalHeader().getDataDirectories().getExportTable(); - System.out.println("Export table: RVA = 0x" + Integer.toHexString(dir.getRVA()) + - ", size = 0x" + Integer.toHexString(dir.getSize())); - System.out.println("DLL name: " + exports.getDLLName()); System.out.println("Time/date stamp 0x" + Integer.toHexString(exports.getTimeDateStamp())); System.out.println("Major version 0x" + Integer.toHexString(exports.getMajorVersion() & 0xFFFF)); System.out.println("Minor version 0x" + Integer.toHexString(exports.getMinorVersion() & 0xFFFF)); - System.out.println(exports.getNumberOfNamePointers() + " functions found"); + System.out.println(exports.getNumberOfNamePointers() + " exports found"); for (int i = 0; i < exports.getNumberOfNamePointers(); i++) { - System.out.println(" 0x" + - Integer.toHexString(exports.getExportAddress(exports.getExportOrdinal(i))) + - " " + - (exports.isExportAddressForwarder(exports.getExportOrdinal(i)) ? - ("Forwarded to " + exports.getExportAddressForwarder(exports.getExportOrdinal(i))) : - exports.getExportName(i))); + short ordinal = exports.getExportOrdinal(i); + System.out.print("[" + i + "] '" + exports.getExportName(i) + "': [" + + ordinal + "] = 0x" + Integer.toHexString(exports.getExportAddress(ordinal))); + System.out.println(exports.isExportAddressForwarder(ordinal) + ? " Forwarded to '" + exports.getExportAddressForwarder(ordinal) + "'" + : ""); } } } diff --git a/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/TestParser.java b/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/TestParser.java index 6f026838d..e6f42df3a 100644 --- a/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/TestParser.java +++ b/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/TestParser.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -42,8 +42,8 @@ public class TestParser { COFFHeader header = file.getHeader(); int numSections = header.getNumberOfSections(); System.out.println(numSections + " sections detected."); - for (int i = 0; i < numSections; i++) { - SectionHeader secHeader = header.getSectionHeader(1 + i); + for (int i = 1; i <= numSections; i++) { + SectionHeader secHeader = header.getSectionHeader(i); System.out.println(secHeader.getName()); } diff --git a/agent/src/share/classes/sun/jvm/hotspot/debugger/windbg/WindbgDebuggerLocal.java b/agent/src/share/classes/sun/jvm/hotspot/debugger/windbg/WindbgDebuggerLocal.java index 53141a6d2..3e5a6aa96 100644 --- a/agent/src/share/classes/sun/jvm/hotspot/debugger/windbg/WindbgDebuggerLocal.java +++ b/agent/src/share/classes/sun/jvm/hotspot/debugger/windbg/WindbgDebuggerLocal.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -506,7 +506,6 @@ public class WindbgDebuggerLocal extends DebuggerBase implements WindbgDebugger throw new DebuggerException("Unimplemented"); } - private static String DTFWHome; private static String imagePath; private static String symbolPath; private static boolean useNativeLookup; @@ -514,81 +513,143 @@ public class WindbgDebuggerLocal extends DebuggerBase implements WindbgDebugger static { /* - * sawindbg.dll depends on dbgeng.dll which - * itself depends on dbghelp.dll. dbgeng.dll and dbghelp.dll. - * On systems newer than Windows 2000, these two .dlls are - * in the standard system directory so we will find them there. - * On Windows 2000 and earlier, these files do not exist. - * The user must download Debugging Tools For Windows (DTFW) - * and install it in order to use SA. + * sawindbg.dll depends on dbgeng.dll which itself depends on + * dbghelp.dll. We have to make sure that the dbgeng.dll and + * dbghelp.dll that we load are compatible with each other. We + * load both of those libraries from the same directory based + * on the theory that co-located libraries are compatible. * - * We have to make sure we use the two files from the same directory - * in case there are more than one copy on the system because - * one version of dbgeng.dll might not be compatible with a - * different version of dbghelp.dll. - * We first look for them in the directory pointed at by - * env. var. DEBUGGINGTOOLSFORWINDOWS, next in the default - * installation dir for DTFW, and lastly in the standard - * system directory. We expect that that we will find - * them in the standard system directory on all systems - * newer than Windows 2000. + * On Windows 2000 and earlier, dbgeng.dll and dbghelp.dll were + * not included as part of the standard system directory. On + * systems newer than Windows 2000, dbgeng.dll and dbghelp.dll + * are included in the standard system directory. However, the + * versions included in the standard system directory may not + * be able to handle symbol information for the newer compilers. + * + * We search for and explicitly load the libraries using the + * following directory search order: + * + * - java.home/bin (same as $JAVA_HOME/jre/bin) + * - dir named by DEBUGGINGTOOLSFORWINDOWS environment variable + * - various "Debugging Tools For Windows" program directories + * - the system directory ($SYSROOT/system32) + * + * If SA is invoked with -Dsun.jvm.hotspot.loadLibrary.DEBUG=1, + * then debug messages about library loading are printed to + * System.err. */ - String dirName = null; - DTFWHome = System.getenv("DEBUGGINGTOOLSFORWINDOWS"); - if (DTFWHome == null) { - // See if we have the files in the default location. + String dbgengPath = null; + String dbghelpPath = null; + String sawindbgPath = null; + List searchList = new ArrayList(); + + boolean loadLibraryDEBUG = + System.getProperty("sun.jvm.hotspot.loadLibrary.DEBUG") != null; + + { + // First place to search is co-located with sawindbg.dll in + // $JAVA_HOME/jre/bin (java.home property is set to $JAVA_HOME/jre): + searchList.add(System.getProperty("java.home") + File.separator + "bin"); + sawindbgPath = (String) searchList.get(0) + File.separator + + "sawindbg.dll"; + + // second place to search is specified by an environment variable: + String DTFWHome = System.getenv("DEBUGGINGTOOLSFORWINDOWS"); + if (DTFWHome != null) { + searchList.add(DTFWHome); + } + + // The third place to search is the install directory for the + // "Debugging Tools For Windows" package; so far there are three + // name variations that we know of: String sysRoot = System.getenv("SYSTEMROOT"); - DTFWHome = sysRoot + File.separator + - ".." + File.separator + "Program Files" + - File.separator + "Debugging Tools For Windows"; + DTFWHome = sysRoot + File.separator + ".." + File.separator + + "Program Files" + File.separator + "Debugging Tools For Windows"; + searchList.add(DTFWHome); + searchList.add(DTFWHome + " (x86)"); + searchList.add(DTFWHome + " (x64)"); + + // The last place to search is the system directory: + searchList.add(sysRoot + File.separator + "system32"); } - { - String dbghelp = DTFWHome + File.separator + "dbghelp.dll"; - String dbgeng = DTFWHome + File.separator + "dbgeng.dll"; - File fhelp = new File(dbghelp); - File feng = new File(dbgeng); - if (fhelp.exists() && feng.exists()) { - // found both, we are happy. - // NOTE: The order of loads is important! If we load dbgeng.dll - // first, then the dependency - dbghelp.dll - will be loaded - // from usual DLL search thereby defeating the purpose! - System.load(dbghelp); - System.load(dbgeng); - } else if (! fhelp.exists() && ! feng.exists()) { - // neither exist. We will ignore this dir and assume - // they are in the system dir. - DTFWHome = null; - } else { - // one exists but not the other - //System.err.println("Error: Both files dbghelp.dll and dbgeng.dll " - // "must exist in directory " + DTFWHome); - throw new UnsatisfiedLinkError("Both files dbghelp.dll and " + - "dbgeng.dll must exist in " + - "directory " + DTFWHome); + for (int i = 0; i < searchList.size(); i++) { + File dir = new File((String) searchList.get(i)); + if (!dir.exists()) { + if (loadLibraryDEBUG) { + System.err.println("DEBUG: '" + searchList.get(i) + + "': directory does not exist."); + } + // this search directory doesn't exist so skip it + continue; } + + dbgengPath = (String) searchList.get(i) + File.separator + "dbgeng.dll"; + dbghelpPath = (String) searchList.get(i) + File.separator + "dbghelp.dll"; + + File feng = new File(dbgengPath); + File fhelp = new File(dbghelpPath); + if (feng.exists() && fhelp.exists()) { + // both files exist so we have a match + break; + } + + // At least one of the files does not exist; no warning if both + // don't exist. If just one doesn't exist then we don't check + // loadLibraryDEBUG because we have a mis-configured system. + if (feng.exists()) { + System.err.println("WARNING: found '" + dbgengPath + + "' but did not find '" + dbghelpPath + "'; ignoring '" + + dbgengPath + "'."); + } else if (fhelp.exists()) { + System.err.println("WARNING: found '" + dbghelpPath + + "' but did not find '" + dbgengPath + "'; ignoring '" + + dbghelpPath + "'."); + } else if (loadLibraryDEBUG) { + System.err.println("DEBUG: searched '" + searchList.get(i) + + "': dbgeng.dll and dbghelp.dll were not found."); + } + dbgengPath = null; + dbghelpPath = null; } - if (DTFWHome == null) { - // The files better be in the system dir. - String sysDir = System.getenv("SYSTEMROOT") + - File.separator + "system32"; - - File feng = new File(sysDir + File.separator + "dbgeng.dll"); - if (!feng.exists()) { - throw new UnsatisfiedLinkError("File dbgeng.dll does not exist in " + - sysDir + ". Please search microsoft.com " + - "for Debugging Tools For Windows, and " + - "either download it to the default " + - "location, or download it to a custom " + - "location and set environment variable " + - " DEBUGGINGTOOLSFORWINDOWS " + - "to the pathname of that location."); + + if (dbgengPath == null || dbghelpPath == null) { + // at least one of the files wasn't found anywhere we searched + String mesg = null; + + if (dbgengPath == null && dbghelpPath == null) { + mesg = "dbgeng.dll and dbghelp.dll cannot be found. "; + } else if (dbgengPath == null) { + mesg = "dbgeng.dll cannot be found (dbghelp.dll was found). "; + } else { + mesg = "dbghelp.dll cannot be found (dbgeng.dll was found). "; } + throw new UnsatisfiedLinkError(mesg + + "Please search microsoft.com for 'Debugging Tools For Windows', " + + "and either download it to the default location, or download it " + + "to a custom location and set environment variable " + + "'DEBUGGINGTOOLSFORWINDOWS' to the pathname of that location."); } + // NOTE: The order of loads is important! If we load dbgeng.dll + // first, then the dependency - dbghelp.dll - will be loaded + // from usual DLL search thereby defeating the purpose! + if (loadLibraryDEBUG) { + System.err.println("DEBUG: loading '" + dbghelpPath + "'."); + } + System.load(dbghelpPath); + if (loadLibraryDEBUG) { + System.err.println("DEBUG: loading '" + dbgengPath + "'."); + } + System.load(dbgengPath); + // Now, load sawindbg.dll - System.loadLibrary("sawindbg"); + if (loadLibraryDEBUG) { + System.err.println("DEBUG: loading '" + sawindbgPath + "'."); + } + System.load(sawindbgPath); + // where do I find '.exe', '.dll' files? imagePath = System.getProperty("sun.jvm.hotspot.debugger.windbg.imagePath"); if (imagePath == null) { -- cgit v1.2.3 From 1cb102b54e8878d8c32b3a7ab9389836412c439b Mon Sep 17 00:00:00 2001 From: zgu Date: Mon, 27 Dec 2010 09:30:20 -0500 Subject: 6975480: VS2010 says _STATIC_CPPLIB is deprecated, may need to change this usage Summary: Disabled the warning message during compiling. Reviewed-by: coleenp, dholmes --- make/windows/makefiles/compile.make | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/make/windows/makefiles/compile.make b/make/windows/makefiles/compile.make index 7d7cb8642..a4cfd742e 100644 --- a/make/windows/makefiles/compile.make +++ b/make/windows/makefiles/compile.make @@ -138,7 +138,7 @@ MS_RUNTIME_OPTION = /MTd /D "_DEBUG" !endif # Always add the _STATIC_CPPLIB flag -STATIC_CPPLIB_OPTION = /D _STATIC_CPPLIB +STATIC_CPPLIB_OPTION = /D _STATIC_CPPLIB /D _DISABLE_DEPRECATE_STATIC_CPPLIB MS_RUNTIME_OPTION = $(MS_RUNTIME_OPTION) $(STATIC_CPPLIB_OPTION) CPP_FLAGS=$(CPP_FLAGS) $(MS_RUNTIME_OPTION) -- cgit v1.2.3 From ad3cea5a20c85ca87b2cd807731a86179a34406d Mon Sep 17 00:00:00 2001 From: iveresov Date: Mon, 27 Dec 2010 21:51:31 -0800 Subject: 7009231: C1: Incorrect CAS code for longs on SPARC 32bit Summary: Fix CAS of longs on SPARC 32bit and cmove on SPARC 64bit. Reviewed-by: kvn --- src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp | 23 +++++-- src/cpu/sparc/vm/c1_LIRGenerator_sparc.cpp | 6 +- src/cpu/x86/vm/c1_LIRAssembler_x86.cpp | 2 +- src/cpu/x86/vm/c1_LIRGenerator_x86.cpp | 5 +- src/share/vm/c1/c1_LIR.hpp | 9 +-- src/share/vm/c1/c1_LIRAssembler.cpp | 2 +- src/share/vm/c1/c1_LIRAssembler.hpp | 2 +- src/share/vm/c1/c1_LIRGenerator.cpp | 4 +- test/compiler/7009231/Test7009231.java | 100 +++++++++++++++++++++++++++++ 9 files changed, 133 insertions(+), 20 deletions(-) create mode 100644 test/compiler/7009231/Test7009231.java diff --git a/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp b/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp index 1e02e0a68..15ca82f28 100644 --- a/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp +++ b/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp @@ -1705,8 +1705,7 @@ void LIR_Assembler::comp_fl2i(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Op } -void LIR_Assembler::cmove(LIR_Condition condition, LIR_Opr opr1, LIR_Opr opr2, LIR_Opr result) { - +void LIR_Assembler::cmove(LIR_Condition condition, LIR_Opr opr1, LIR_Opr opr2, LIR_Opr result, BasicType type) { Assembler::Condition acond; switch (condition) { case lir_cond_equal: acond = Assembler::equal; break; @@ -1737,7 +1736,12 @@ void LIR_Assembler::cmove(LIR_Condition condition, LIR_Opr opr1, LIR_Opr opr2, L ShouldNotReachHere(); } Label skip; - __ br(acond, false, Assembler::pt, skip); +#ifdef _LP64 + if (type == T_INT) { + __ br(acond, false, Assembler::pt, skip); + } else +#endif + __ brx(acond, false, Assembler::pt, skip); // checks icc on 32bit and xcc on 64bit if (opr1->is_constant() && opr1->type() == T_INT) { Register dest = result->as_register(); if (Assembler::is_simm13(opr1->as_jint())) { @@ -2688,6 +2692,11 @@ void LIR_Assembler::emit_compare_and_swap(LIR_OpCompareAndSwap* op) { #ifdef _LP64 __ mov(cmp_value_lo, t1); __ mov(new_value_lo, t2); + // perform the compare and swap operation + __ casx(addr, t1, t2); + // generate condition code - if the swap succeeded, t2 ("new value" reg) was + // overwritten with the original value in "addr" and will be equal to t1. + __ cmp(t1, t2); #else // move high and low halves of long values into single registers __ sllx(cmp_value_hi, 32, t1); // shift high half into temp reg @@ -2696,13 +2705,15 @@ void LIR_Assembler::emit_compare_and_swap(LIR_OpCompareAndSwap* op) { __ sllx(new_value_hi, 32, t2); __ srl(new_value_lo, 0, new_value_lo); __ or3(t2, new_value_lo, t2); // t2 holds 64-bit value to swap -#endif // perform the compare and swap operation __ casx(addr, t1, t2); // generate condition code - if the swap succeeded, t2 ("new value" reg) was // overwritten with the original value in "addr" and will be equal to t1. - __ cmp(t1, t2); - + // Produce icc flag for 32bit. + __ sub(t1, t2, t2); + __ srlx(t2, 32, t1); + __ orcc(t2, t1, G0); +#endif } else if (op->code() == lir_cas_int || op->code() == lir_cas_obj) { Register addr = op->addr()->as_pointer_register(); Register cmp_value = op->cmp_value()->as_register(); diff --git a/src/cpu/sparc/vm/c1_LIRGenerator_sparc.cpp b/src/cpu/sparc/vm/c1_LIRGenerator_sparc.cpp index 1abbdb51d..8869de5e8 100644 --- a/src/cpu/sparc/vm/c1_LIRGenerator_sparc.cpp +++ b/src/cpu/sparc/vm/c1_LIRGenerator_sparc.cpp @@ -662,7 +662,7 @@ void LIRGenerator::do_AttemptUpdate(Intrinsic* x) { // generate conditional move of boolean result LIR_Opr result = rlock_result(x); - __ cmove(lir_cond_equal, LIR_OprFact::intConst(1), LIR_OprFact::intConst(0), result); + __ cmove(lir_cond_equal, LIR_OprFact::intConst(1), LIR_OprFact::intConst(0), result, T_LONG); } @@ -699,10 +699,10 @@ void LIRGenerator::do_CompareAndSwap(Intrinsic* x, ValueType* type) { else { ShouldNotReachHere(); } - // generate conditional move of boolean result LIR_Opr result = rlock_result(x); - __ cmove(lir_cond_equal, LIR_OprFact::intConst(1), LIR_OprFact::intConst(0), result); + __ cmove(lir_cond_equal, LIR_OprFact::intConst(1), LIR_OprFact::intConst(0), + result, as_BasicType(type)); if (type == objectType) { // Write-barrier needed for Object fields. // Precise card mark since could either be object or array post_barrier(addr, val.result()); diff --git a/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp b/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp index 724d8411b..f3ba0a2ce 100644 --- a/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp +++ b/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp @@ -2036,7 +2036,7 @@ void LIR_Assembler::emit_compare_and_swap(LIR_OpCompareAndSwap* op) { } } -void LIR_Assembler::cmove(LIR_Condition condition, LIR_Opr opr1, LIR_Opr opr2, LIR_Opr result) { +void LIR_Assembler::cmove(LIR_Condition condition, LIR_Opr opr1, LIR_Opr opr2, LIR_Opr result, BasicType type) { Assembler::Condition acond, ncond; switch (condition) { case lir_cond_equal: acond = Assembler::equal; ncond = Assembler::notEqual; break; diff --git a/src/cpu/x86/vm/c1_LIRGenerator_x86.cpp b/src/cpu/x86/vm/c1_LIRGenerator_x86.cpp index d792a0f62..cdea66f38 100644 --- a/src/cpu/x86/vm/c1_LIRGenerator_x86.cpp +++ b/src/cpu/x86/vm/c1_LIRGenerator_x86.cpp @@ -741,7 +741,7 @@ void LIRGenerator::do_AttemptUpdate(Intrinsic* x) { // generate conditional move of boolean result LIR_Opr result = rlock_result(x); - __ cmove(lir_cond_equal, LIR_OprFact::intConst(1), LIR_OprFact::intConst(0), result); + __ cmove(lir_cond_equal, LIR_OprFact::intConst(1), LIR_OprFact::intConst(0), result, T_LONG); } @@ -810,7 +810,8 @@ void LIRGenerator::do_CompareAndSwap(Intrinsic* x, ValueType* type) { // generate conditional move of boolean result LIR_Opr result = rlock_result(x); - __ cmove(lir_cond_equal, LIR_OprFact::intConst(1), LIR_OprFact::intConst(0), result); + __ cmove(lir_cond_equal, LIR_OprFact::intConst(1), LIR_OprFact::intConst(0), + result, as_BasicType(type)); if (type == objectType) { // Write-barrier needed for Object fields. // Seems to be precise post_barrier(addr, val.result()); diff --git a/src/share/vm/c1/c1_LIR.hpp b/src/share/vm/c1/c1_LIR.hpp index 7a3574cfa..50bf4c4e9 100644 --- a/src/share/vm/c1/c1_LIR.hpp +++ b/src/share/vm/c1/c1_LIR.hpp @@ -1568,15 +1568,16 @@ class LIR_Op2: public LIR_Op { assert(code == lir_cmp, "code check"); } - LIR_Op2(LIR_Code code, LIR_Condition condition, LIR_Opr opr1, LIR_Opr opr2, LIR_Opr result) + LIR_Op2(LIR_Code code, LIR_Condition condition, LIR_Opr opr1, LIR_Opr opr2, LIR_Opr result, BasicType type) : LIR_Op(code, result, NULL) , _opr1(opr1) , _opr2(opr2) - , _type(T_ILLEGAL) + , _type(type) , _condition(condition) , _fpu_stack_size(0) , _tmp(LIR_OprFact::illegalOpr) { assert(code == lir_cmove, "code check"); + assert(type != T_ILLEGAL, "cmove should have type"); } LIR_Op2(LIR_Code code, LIR_Opr opr1, LIR_Opr opr2, LIR_Opr result = LIR_OprFact::illegalOpr, @@ -1993,8 +1994,8 @@ class LIR_List: public CompilationResourceObj { void cmp_mem_int(LIR_Condition condition, LIR_Opr base, int disp, int c, CodeEmitInfo* info); void cmp_reg_mem(LIR_Condition condition, LIR_Opr reg, LIR_Address* addr, CodeEmitInfo* info); - void cmove(LIR_Condition condition, LIR_Opr src1, LIR_Opr src2, LIR_Opr dst) { - append(new LIR_Op2(lir_cmove, condition, src1, src2, dst)); + void cmove(LIR_Condition condition, LIR_Opr src1, LIR_Opr src2, LIR_Opr dst, BasicType type) { + append(new LIR_Op2(lir_cmove, condition, src1, src2, dst, type)); } void cas_long(LIR_Opr addr, LIR_Opr cmp_value, LIR_Opr new_value, diff --git a/src/share/vm/c1/c1_LIRAssembler.cpp b/src/share/vm/c1/c1_LIRAssembler.cpp index c42281997..1b57ea2f0 100644 --- a/src/share/vm/c1/c1_LIRAssembler.cpp +++ b/src/share/vm/c1/c1_LIRAssembler.cpp @@ -685,7 +685,7 @@ void LIR_Assembler::emit_op2(LIR_Op2* op) { break; case lir_cmove: - cmove(op->condition(), op->in_opr1(), op->in_opr2(), op->result_opr()); + cmove(op->condition(), op->in_opr1(), op->in_opr2(), op->result_opr(), op->type()); break; case lir_shl: diff --git a/src/share/vm/c1/c1_LIRAssembler.hpp b/src/share/vm/c1/c1_LIRAssembler.hpp index 24f62862c..bb18c253e 100644 --- a/src/share/vm/c1/c1_LIRAssembler.hpp +++ b/src/share/vm/c1/c1_LIRAssembler.hpp @@ -217,7 +217,7 @@ class LIR_Assembler: public CompilationResourceObj { void volatile_move_op(LIR_Opr src, LIR_Opr result, BasicType type, CodeEmitInfo* info); void comp_mem_op(LIR_Opr src, LIR_Opr result, BasicType type, CodeEmitInfo* info); // info set for null exceptions void comp_fl2i(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Opr result, LIR_Op2* op); - void cmove(LIR_Condition code, LIR_Opr left, LIR_Opr right, LIR_Opr result); + void cmove(LIR_Condition code, LIR_Opr left, LIR_Opr right, LIR_Opr result, BasicType type); void call( LIR_OpJavaCall* op, relocInfo::relocType rtype); void ic_call( LIR_OpJavaCall* op); diff --git a/src/share/vm/c1/c1_LIRGenerator.cpp b/src/share/vm/c1/c1_LIRGenerator.cpp index 56b22f686..8dc579d0d 100644 --- a/src/share/vm/c1/c1_LIRGenerator.cpp +++ b/src/share/vm/c1/c1_LIRGenerator.cpp @@ -856,7 +856,7 @@ void LIRGenerator::profile_branch(If* if_instr, If::Condition cond) { __ cmove(lir_cond(cond), LIR_OprFact::intptrConst(taken_count_offset), LIR_OprFact::intptrConst(not_taken_count_offset), - data_offset_reg); + data_offset_reg, as_BasicType(if_instr->x()->type())); // MDO cells are intptr_t, so the data_reg width is arch-dependent. LIR_Opr data_reg = new_pointer_register(); @@ -2591,7 +2591,7 @@ void LIRGenerator::do_IfOp(IfOp* x) { LIR_Opr reg = rlock_result(x); __ cmp(lir_cond(x->cond()), left.result(), right.result()); - __ cmove(lir_cond(x->cond()), t_val.result(), f_val.result(), reg); + __ cmove(lir_cond(x->cond()), t_val.result(), f_val.result(), reg, as_BasicType(x->x()->type())); } diff --git a/test/compiler/7009231/Test7009231.java b/test/compiler/7009231/Test7009231.java new file mode 100644 index 000000000..64afc6601 --- /dev/null +++ b/test/compiler/7009231/Test7009231.java @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/** + * @test + * @bug 7009231 + * @summary C1: Incorrect CAS code for longs on SPARC 32bit + * + * @run main/othervm -Xbatch Test7009231 + * + */ + +import java.util.Random; +import java.util.concurrent.atomic.AtomicLong; + + +public class Test7009231 { + public static void main(String[] args) throws InterruptedException { + doTest(8); + } + + private static void doTest(int nThreads) throws InterruptedException { + Thread[] aThreads = new Thread[nThreads]; + final AtomicLong atl = new AtomicLong(); + + for (int i = 0; i < nThreads; i++) { + aThreads[i] = new RunnerThread(atl, 1L << (8 * i)); + } + + for (int i = 0; i < nThreads; i++) { + aThreads[i].start(); + } + + for (int i = 0; i < nThreads; i++) { + aThreads[i].join(); + } + } + + public static class RunnerThread extends Thread { + public RunnerThread(AtomicLong atomic, long lMask) { + m_lMask = lMask; + m_atomic = atomic; + } + + public void run() { + AtomicLong atomic = m_atomic; + long lMask = m_lMask; + for (int i = 0; i < 100000; i++) { + setBit(atomic, lMask); + clearBit(atomic, lMask); + } + } + + protected void setBit(AtomicLong atomic, long lMask) { + long lWord; + do { + lWord = atomic.get(); + } while (!atomic.compareAndSet(lWord, lWord | lMask)); + + if ((atomic.get() & lMask) == 0L) { + throw new InternalError(); + } + } + + protected void clearBit(AtomicLong atomic, long lMask) { + long lWord; + do { + lWord = atomic.get(); + } while (!atomic.compareAndSet(lWord, lWord & ~lMask)); + + if ((atomic.get() & lMask) != 0L) { + throw new InternalError(); + } + } + + private long m_lMask; + private AtomicLong m_atomic; + } +} -- cgit v1.2.3 From e3b83934a052a6271ce58f987f21ca32baa7fcda Mon Sep 17 00:00:00 2001 From: kvn Date: Tue, 28 Dec 2010 17:34:02 -0800 Subject: 7009359: HS with -XX:+AggressiveOpts optimize new StringBuffer(null) so it does not throw NPE as expected Summary: Bailout StringConcat optimization if null is passed to StringBuffer constructor. Reviewed-by: iveresov --- src/share/vm/opto/stringopts.cpp | 43 ++++++++++++++++++++++++++-- test/compiler/7009359/Test7009359.java | 52 ++++++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+), 3 deletions(-) create mode 100644 test/compiler/7009359/Test7009359.java diff --git a/src/share/vm/opto/stringopts.cpp b/src/share/vm/opto/stringopts.cpp index 93516d5d0..658fc05b1 100644 --- a/src/share/vm/opto/stringopts.cpp +++ b/src/share/vm/opto/stringopts.cpp @@ -59,7 +59,8 @@ class StringConcat : public ResourceObj { enum { StringMode, IntMode, - CharMode + CharMode, + StringNullCheckMode }; StringConcat(PhaseStringOpts* stringopts, CallStaticJavaNode* end): @@ -114,6 +115,9 @@ class StringConcat : public ResourceObj { void push_string(Node* value) { push(value, StringMode); } + void push_string_null_check(Node* value) { + push(value, StringNullCheckMode); + } void push_int(Node* value) { push(value, IntMode); } @@ -416,7 +420,19 @@ StringConcat* PhaseStringOpts::build_candidate(CallStaticJavaNode* call) { if (sig == ciSymbol::string_void_signature()) { // StringBuilder(String) so pick this up as the first argument assert(use->in(TypeFunc::Parms + 1) != NULL, "what?"); - sc->push_string(use->in(TypeFunc::Parms + 1)); + const Type* type = _gvn->type(use->in(TypeFunc::Parms + 1)); + if (type == TypePtr::NULL_PTR) { + // StringBuilder(null) throws exception. +#ifndef PRODUCT + if (PrintOptimizeStringConcat) { + tty->print("giving up because StringBuilder(null) throws exception"); + alloc->jvms()->dump_spec(tty); tty->cr(); + } +#endif + return NULL; + } + // StringBuilder(str) argument needs null check. + sc->push_string_null_check(use->in(TypeFunc::Parms + 1)); } // The int variant takes an initial size for the backing // array so just treat it like the void version. @@ -436,7 +452,7 @@ StringConcat* PhaseStringOpts::build_candidate(CallStaticJavaNode* call) { #ifndef PRODUCT if (PrintOptimizeStringConcat) { tty->print("giving up because couldn't find constructor "); - alloc->jvms()->dump_spec(tty); + alloc->jvms()->dump_spec(tty); tty->cr(); } #endif break; @@ -1269,6 +1285,25 @@ void PhaseStringOpts::replace_string_concat(StringConcat* sc) { string_sizes->init_req(argi, string_size); break; } + case StringConcat::StringNullCheckMode: { + const Type* type = kit.gvn().type(arg); + assert(type != TypePtr::NULL_PTR, "missing check"); + if (!type->higher_equal(TypeInstPtr::NOTNULL)) { + // Null check with uncommont trap since + // StringBuilder(null) throws exception. + // Use special uncommon trap instead of + // calling normal do_null_check(). + Node* p = __ Bool(__ CmpP(arg, kit.null()), BoolTest::ne); + IfNode* iff = kit.create_and_map_if(kit.control(), p, PROB_MIN, COUNT_UNKNOWN); + overflow->add_req(__ IfFalse(iff)); + Node* notnull = __ IfTrue(iff); + kit.set_control(notnull); // set control for the cast_not_null + arg = kit.cast_not_null(arg, false); + sc->set_argument(argi, arg); + } + assert(kit.gvn().type(arg)->higher_equal(TypeInstPtr::NOTNULL), "sanity"); + // Fallthrough to add string length. + } case StringConcat::StringMode: { const Type* type = kit.gvn().type(arg); if (type == TypePtr::NULL_PTR) { @@ -1328,6 +1363,7 @@ void PhaseStringOpts::replace_string_concat(StringConcat* sc) { // Hook PreserveJVMState pjvms(&kit); kit.set_control(overflow); + C->record_for_igvn(overflow); kit.uncommon_trap(Deoptimization::Reason_intrinsic, Deoptimization::Action_make_not_entrant); } @@ -1363,6 +1399,7 @@ void PhaseStringOpts::replace_string_concat(StringConcat* sc) { start = end; break; } + case StringConcat::StringNullCheckMode: case StringConcat::StringMode: { start = copy_string(kit, arg, char_array, start); break; diff --git a/test/compiler/7009359/Test7009359.java b/test/compiler/7009359/Test7009359.java new file mode 100644 index 000000000..408fd713e --- /dev/null +++ b/test/compiler/7009359/Test7009359.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/** + * @test + * @bug 7009359 + * @summary HS with -XX:+AggressiveOpts optimize new StringBuffer(null) so it does not throw NPE as expected + * + * @run main/othervm -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:+OptimizeStringConcat -XX:CompileCommand=exclude,Test7009359,main Test7009359 + * + */ + +public class Test7009359 { + public static void main (String[] args) { + for(int i = 0; i < 1000000; i++) { + if(!stringmakerBUG(null).equals("NPE")) { + System.out.println("StringBuffer(null) does not throw NPE"); + System.exit(97); + } + } + } + + public static String stringmakerBUG(String str) { + try { + return new StringBuffer(str).toString(); + } catch (NullPointerException e) { + return "NPE"; + } + } +} + -- cgit v1.2.3 From 4a8fbbf6f613b0d06f5ef6efa16495121b7a333e Mon Sep 17 00:00:00 2001 From: kvn Date: Wed, 29 Dec 2010 10:41:43 -0800 Subject: 7008325: CodeCache exhausted on sparc starting from hs20b04 Summary: remove clear_scratch_buffer_blob and let init_scratch_buffer_blob free and allocate a new blob if required. Reviewed-by: twisti --- src/share/vm/code/codeCache.cpp | 6 ++++-- src/share/vm/code/codeCache.hpp | 1 + src/share/vm/memory/heap.cpp | 9 ++++++++ src/share/vm/memory/heap.hpp | 1 + src/share/vm/opto/compile.cpp | 47 ++++++++++++++++++++++------------------- src/share/vm/opto/output.cpp | 3 --- 6 files changed, 40 insertions(+), 27 deletions(-) diff --git a/src/share/vm/code/codeCache.cpp b/src/share/vm/code/codeCache.cpp index f7e09b258..db35aea6e 100644 --- a/src/share/vm/code/codeCache.cpp +++ b/src/share/vm/code/codeCache.cpp @@ -939,7 +939,9 @@ void CodeCache::print_bounds(outputStream* st) { _heap->high(), _heap->high_boundary()); st->print_cr(" total_blobs=" UINT32_FORMAT " nmethods=" UINT32_FORMAT - " adapters=" UINT32_FORMAT " free_code_cache=" SIZE_FORMAT, + " adapters=" UINT32_FORMAT " free_code_cache=" SIZE_FORMAT + " largest_free_block=" SIZE_FORMAT, CodeCache::nof_blobs(), CodeCache::nof_nmethods(), - CodeCache::nof_adapters(), CodeCache::unallocated_capacity()); + CodeCache::nof_adapters(), CodeCache::unallocated_capacity(), + CodeCache::largest_free_block()); } diff --git a/src/share/vm/code/codeCache.hpp b/src/share/vm/code/codeCache.hpp index acb288efe..df8de7f3f 100644 --- a/src/share/vm/code/codeCache.hpp +++ b/src/share/vm/code/codeCache.hpp @@ -158,6 +158,7 @@ class CodeCache : AllStatic { static size_t capacity() { return _heap->capacity(); } static size_t max_capacity() { return _heap->max_capacity(); } static size_t unallocated_capacity() { return _heap->unallocated_capacity(); } + static size_t largest_free_block() { return _heap->largest_free_block(); } static bool needs_flushing() { return unallocated_capacity() < CodeCacheFlushingMinimumFreeSpace; } static bool needs_cache_clean() { return _needs_cache_clean; } diff --git a/src/share/vm/memory/heap.cpp b/src/share/vm/memory/heap.cpp index b6d6484f0..94676f78d 100644 --- a/src/share/vm/memory/heap.cpp +++ b/src/share/vm/memory/heap.cpp @@ -315,6 +315,15 @@ size_t CodeHeap::allocated_capacity() const { return l; } +size_t CodeHeap::largest_free_block() const { + size_t len = 0; + for (FreeBlock* b = _freelist; b != NULL; b = b->link()) { + if (b->length() > len) + len = b->length(); + } + return size(len); +} + // Free list management FreeBlock *CodeHeap::following_block(FreeBlock *b) { diff --git a/src/share/vm/memory/heap.hpp b/src/share/vm/memory/heap.hpp index 95199aac9..4f592a20c 100644 --- a/src/share/vm/memory/heap.hpp +++ b/src/share/vm/memory/heap.hpp @@ -161,6 +161,7 @@ class CodeHeap : public CHeapObj { size_t max_capacity() const; size_t allocated_capacity() const; size_t unallocated_capacity() const { return max_capacity() - allocated_capacity(); } + size_t largest_free_block() const; // Debugging void verify(); diff --git a/src/share/vm/opto/compile.cpp b/src/share/vm/opto/compile.cpp index 0ca15e168..cad5224e6 100644 --- a/src/share/vm/opto/compile.cpp +++ b/src/share/vm/opto/compile.cpp @@ -444,22 +444,32 @@ void Compile::print_compile_messages() { } +//-----------------------init_scratch_buffer_blob------------------------------ +// Construct a temporary BufferBlob and cache it for this compile. void Compile::init_scratch_buffer_blob(int const_size) { - if (scratch_buffer_blob() != NULL) return; - - // Construct a temporary CodeBuffer to have it construct a BufferBlob - // Cache this BufferBlob for this compile. - ResourceMark rm; - _scratch_const_size = const_size; - int size = (MAX_inst_size + MAX_stubs_size + _scratch_const_size); - BufferBlob* blob = BufferBlob::create("Compile::scratch_buffer", size); - // Record the buffer blob for next time. - set_scratch_buffer_blob(blob); - // Have we run out of code space? - if (scratch_buffer_blob() == NULL) { - // Let CompilerBroker disable further compilations. - record_failure("Not enough space for scratch buffer in CodeCache"); - return; + // If there is already a scratch buffer blob allocated and the + // constant section is big enough, use it. Otherwise free the + // current and allocate a new one. + BufferBlob* blob = scratch_buffer_blob(); + if ((blob != NULL) && (const_size <= _scratch_const_size)) { + // Use the current blob. + } else { + if (blob != NULL) { + BufferBlob::free(blob); + } + + ResourceMark rm; + _scratch_const_size = const_size; + int size = (MAX_inst_size + MAX_stubs_size + _scratch_const_size); + blob = BufferBlob::create("Compile::scratch_buffer", size); + // Record the buffer blob for next time. + set_scratch_buffer_blob(blob); + // Have we run out of code space? + if (scratch_buffer_blob() == NULL) { + // Let CompilerBroker disable further compilations. + record_failure("Not enough space for scratch buffer in CodeCache"); + return; + } } // Initialize the relocation buffers @@ -468,13 +478,6 @@ void Compile::init_scratch_buffer_blob(int const_size) { } -void Compile::clear_scratch_buffer_blob() { - assert(scratch_buffer_blob(), "no BufferBlob set"); - set_scratch_buffer_blob(NULL); - set_scratch_locs_memory(NULL); -} - - //-----------------------scratch_emit_size------------------------------------- // Helper function that computes size by emitting code uint Compile::scratch_emit_size(const Node* n) { diff --git a/src/share/vm/opto/output.cpp b/src/share/vm/opto/output.cpp index e2ddd974f..de2942316 100644 --- a/src/share/vm/opto/output.cpp +++ b/src/share/vm/opto/output.cpp @@ -1746,9 +1746,6 @@ void Compile::ScheduleAndBundle() { // Walk backwards over each basic block, computing the needed alignment // Walk over all the basic blocks scheduling.DoScheduling(); - - // Clear the BufferBlob used for scheduling. - clear_scratch_buffer_blob(); } //------------------------------ComputeLocalLatenciesForward------------------- -- cgit v1.2.3 From 4a639331de3d2caba6d14ccce0cbad2605ebb035 Mon Sep 17 00:00:00 2001 From: kvn Date: Thu, 30 Dec 2010 09:36:03 -0800 Subject: 6928562: Assert(_no_handle_mark_nesting==0,"allocating handle inside NoHandleMark") Summary: reset NoHandleMark before going into VM. Reviewed-by: iveresov --- src/share/vm/compiler/abstractCompiler.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/share/vm/compiler/abstractCompiler.cpp b/src/share/vm/compiler/abstractCompiler.cpp index 5594d1afa..942c168e5 100644 --- a/src/share/vm/compiler/abstractCompiler.cpp +++ b/src/share/vm/compiler/abstractCompiler.cpp @@ -33,6 +33,7 @@ void AbstractCompiler::initialize_runtimes(initializer f, volatile int* state) { bool do_initialization = false; { ThreadInVMfromNative tv(thread); + ResetNoHandleMark rnhm; MutexLocker only_one(CompileThread_lock, thread); if ( *state == uninitialized) { do_initialization = true; @@ -53,6 +54,7 @@ void AbstractCompiler::initialize_runtimes(initializer f, volatile int* state) { // To in_vm so we can use the lock ThreadInVMfromNative tv(thread); + ResetNoHandleMark rnhm; MutexLocker only_one(CompileThread_lock, thread); assert(*state == initializing, "wrong state"); *state = initialized; -- cgit v1.2.3 From 6bb89f4d93cdd96311dd8ba676c7a2c04586331d Mon Sep 17 00:00:00 2001 From: iveresov Date: Thu, 30 Dec 2010 23:44:45 -0800 Subject: 7009849: C1: Incorrect frame size computation Summary: Fix frame size computation Reviewed-by: phh, kvn --- src/share/vm/c1/c1_FrameMap.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/share/vm/c1/c1_FrameMap.cpp b/src/share/vm/c1/c1_FrameMap.cpp index 75975bb2b..5b10b966d 100644 --- a/src/share/vm/c1/c1_FrameMap.cpp +++ b/src/share/vm/c1/c1_FrameMap.cpp @@ -92,7 +92,7 @@ CallingConvention* FrameMap::java_calling_convention(const BasicTypeArray* signa if (opr->is_address()) { LIR_Address* addr = opr->as_address_ptr(); assert(addr->disp() == (int)addr->disp(), "out of range value"); - out_preserve = MAX2(out_preserve, (intptr_t)addr->disp() / 4); + out_preserve = MAX2(out_preserve, (intptr_t)(addr->disp() - STACK_BIAS) / 4); } i += type2size[t]; } @@ -143,7 +143,7 @@ CallingConvention* FrameMap::c_calling_convention(const BasicTypeArray* signatur args->append(opr); if (opr->is_address()) { LIR_Address* addr = opr->as_address_ptr(); - out_preserve = MAX2(out_preserve, (intptr_t)addr->disp() / 4); + out_preserve = MAX2(out_preserve, (intptr_t)(addr->disp() - STACK_BIAS) / 4); } i += type2size[t]; } -- cgit v1.2.3 From 05f7d277ddbf90a3272f79a152940eee9127508a Mon Sep 17 00:00:00 2001 From: coleenp Date: Mon, 3 Jan 2011 14:09:11 -0500 Subject: 6302804: Hotspot VM dies ungraceful death when C heap is exhausted in various places. Summary: enhance the error reporting mechanism to help user to fix the problem rather than making it look like a VM error. Reviewed-by: kvn, kamg --- src/os_cpu/solaris_sparc/vm/os_solaris_sparc.cpp | 7 +++ src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp | 7 +++ src/share/vm/runtime/arguments.cpp | 7 +-- src/share/vm/utilities/debug.cpp | 2 +- src/share/vm/utilities/vmError.cpp | 67 +++++++++++++++++------- src/share/vm/utilities/vmError.hpp | 4 +- 6 files changed, 71 insertions(+), 23 deletions(-) diff --git a/src/os_cpu/solaris_sparc/vm/os_solaris_sparc.cpp b/src/os_cpu/solaris_sparc/vm/os_solaris_sparc.cpp index 889f7549f..3b83be3eb 100644 --- a/src/os_cpu/solaris_sparc/vm/os_solaris_sparc.cpp +++ b/src/os_cpu/solaris_sparc/vm/os_solaris_sparc.cpp @@ -585,6 +585,13 @@ int JVM_handle_solaris_signal(int sig, siginfo_t* info, void* ucVoid, int abort_ sigaddset(&newset, sig); sigprocmask(SIG_UNBLOCK, &newset, NULL); + // Determine which sort of error to throw. Out of swap may signal + // on the thread stack, which could get a mapping error when touched. + address addr = (address) info->si_addr; + if (sig == SIGBUS && info->si_code == BUS_OBJERR && info->si_errno == ENOMEM) { + vm_exit_out_of_memory(0, "Out of swap space to map in thread stack."); + } + VMError err(t, sig, pc, info, ucVoid); err.report_and_die(); diff --git a/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp b/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp index 91c7e75a0..d9bb0eb58 100644 --- a/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp +++ b/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp @@ -742,6 +742,13 @@ int JVM_handle_solaris_signal(int sig, siginfo_t* info, void* ucVoid, int abort_ sigaddset(&newset, sig); sigprocmask(SIG_UNBLOCK, &newset, NULL); + // Determine which sort of error to throw. Out of swap may signal + // on the thread stack, which could get a mapping error when touched. + address addr = (address) info->si_addr; + if (sig == SIGBUS && info->si_code == BUS_OBJERR && info->si_errno == ENOMEM) { + vm_exit_out_of_memory(0, "Out of swap space to map in thread stack."); + } + VMError err(t, sig, pc, info, ucVoid); err.report_and_die(); diff --git a/src/share/vm/runtime/arguments.cpp b/src/share/vm/runtime/arguments.cpp index 0a3f9207f..09b41b5b0 100644 --- a/src/share/vm/runtime/arguments.cpp +++ b/src/share/vm/runtime/arguments.cpp @@ -2297,14 +2297,15 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, } else if (match_option(option, "-Xoss", &tail)) { // HotSpot does not have separate native and Java stacks, ignore silently for compatibility // -Xmaxjitcodesize - } else if (match_option(option, "-Xmaxjitcodesize", &tail)) { + } else if (match_option(option, "-Xmaxjitcodesize", &tail) || + match_option(option, "-XX:ReservedCodeCacheSize=", &tail)) { julong long_ReservedCodeCacheSize = 0; ArgsRange errcode = parse_memory_size(tail, &long_ReservedCodeCacheSize, (size_t)InitialCodeCacheSize); if (errcode != arg_in_range) { jio_fprintf(defaultStream::error_stream(), - "Invalid maximum code cache size: %s\n", - option->optionString); + "Invalid maximum code cache size: %s. Should be greater than InitialCodeCacheSize=%dK\n", + option->optionString, InitialCodeCacheSize/K); describe_range_error(errcode); return JNI_EINVAL; } diff --git a/src/share/vm/utilities/debug.cpp b/src/share/vm/utilities/debug.cpp index 484dcf581..cb44189fd 100644 --- a/src/share/vm/utilities/debug.cpp +++ b/src/share/vm/utilities/debug.cpp @@ -226,7 +226,7 @@ static jint _exiting_out_of_mem = 0; void report_vm_out_of_memory(const char* file, int line, size_t size, const char* message) { - if (Debugging || error_is_suppressed(file, line)) return; + if (Debugging) return; // We try to gather additional information for the first out of memory // error only; gathering additional data might cause an allocation and a diff --git a/src/share/vm/utilities/vmError.cpp b/src/share/vm/utilities/vmError.cpp index 371115036..4b8e055d4 100644 --- a/src/share/vm/utilities/vmError.cpp +++ b/src/share/vm/utilities/vmError.cpp @@ -67,7 +67,7 @@ const char *env_list[] = { // threads are blocked forever inside report_and_die(). // Constructor for crashes -VMError::VMError(Thread* thread, int sig, address pc, void* siginfo, void* context) { +VMError::VMError(Thread* thread, unsigned int sig, address pc, void* siginfo, void* context) { _thread = thread; _id = sig; _pc = pc; @@ -322,29 +322,51 @@ void VMError::report(outputStream* st) { STEP(10, "(printing fatal error message)") - st->print_cr("#"); - st->print_cr("# A fatal error has been detected by the Java Runtime Environment:"); + st->print_cr("#"); + if (should_report_bug(_id)) { + st->print_cr("# A fatal error has been detected by the Java Runtime Environment:"); + } else { + st->print_cr("# There is insufficient memory for the Java " + "Runtime Environment to continue."); + } STEP(15, "(printing type of error)") switch(_id) { case oom_error: - st->print_cr("#"); - st->print("# java.lang.OutOfMemoryError: "); if (_size) { - st->print("requested "); - sprintf(buf,SIZE_FORMAT,_size); + st->print("# Native memory allocation (malloc) failed to allocate "); + jio_snprintf(buf, sizeof(buf), SIZE_FORMAT, _size); st->print(buf); st->print(" bytes"); if (_message != NULL) { st->print(" for "); st->print(_message); } - st->print_cr(". Out of swap space?"); + st->cr(); } else { if (_message != NULL) + st->print("# "); st->print_cr(_message); } + // In error file give some solutions + if (_verbose) { + st->print_cr("# Possible reasons:"); + st->print_cr("# The system is out of physical RAM or swap space"); + st->print_cr("# In 32 bit mode, the process size limit was hit"); + st->print_cr("# Possible solutions:"); + st->print_cr("# Reduce memory load on the system"); + st->print_cr("# Increase physical memory or swap space"); + st->print_cr("# Check if swap backing store is full"); + st->print_cr("# Use 64 bit Java on a 64 bit OS"); + st->print_cr("# Decrease Java heap size (-Xmx/-Xms)"); + st->print_cr("# Decrease number of Java threads"); + st->print_cr("# Decrease Java thread stack sizes (-Xss)"); + st->print_cr("# Set larger code cache with -XX:ReservedCodeCacheSize="); + st->print_cr("# This output file may be truncated or incomplete."); + } else { + return; // that's enough for the screen + } break; case internal_error: default: @@ -361,7 +383,11 @@ void VMError::report(outputStream* st) { st->print(" (0x%x)", _id); // signal number st->print(" at pc=" PTR_FORMAT, _pc); } else { - st->print("Internal Error"); + if (should_report_bug(_id)) { + st->print("Internal Error"); + } else { + st->print("Out of Memory Error"); + } if (_filename != NULL && _lineno > 0) { #ifdef PRODUCT // In product mode chop off pathname? @@ -393,12 +419,14 @@ void VMError::report(outputStream* st) { STEP(40, "(printing error message)") - // error message - if (_detail_msg) { - st->print_cr("# %s: %s", _message ? _message : "Error", _detail_msg); - } else if (_message) { - st->print_cr("# Error: %s", _message); - } + if (should_report_bug(_id)) { // already printed the message. + // error message + if (_detail_msg) { + st->print_cr("# %s: %s", _message ? _message : "Error", _detail_msg); + } else if (_message) { + st->print_cr("# Error: %s", _message); + } + } STEP(50, "(printing Java version string)") @@ -428,7 +456,9 @@ void VMError::report(outputStream* st) { STEP(65, "(printing bug submit message)") - if (_verbose) print_bug_submit_message(st, _thread); + if (should_report_bug(_id) && _verbose) { + print_bug_submit_message(st, _thread); + } STEP(70, "(printing thread)" ) @@ -906,7 +936,7 @@ void VMError::report_and_die() { OnError = NULL; } - static bool skip_bug_url = false; + static bool skip_bug_url = !should_report_bug(first_error->_id); if (!skip_bug_url) { skip_bug_url = true; @@ -919,7 +949,8 @@ void VMError::report_and_die() { static bool skip_os_abort = false; if (!skip_os_abort) { skip_os_abort = true; - os::abort(); + bool dump_core = should_report_bug(first_error->_id); + os::abort(dump_core); } // if os::abort() doesn't abort, try os::die(); diff --git a/src/share/vm/utilities/vmError.hpp b/src/share/vm/utilities/vmError.hpp index 3d80ce321..e9d60b3a1 100644 --- a/src/share/vm/utilities/vmError.hpp +++ b/src/share/vm/utilities/vmError.hpp @@ -87,10 +87,12 @@ class VMError : public StackObj { // accessor const char* message() const { return _message; } const char* detail_msg() const { return _detail_msg; } + bool should_report_bug(unsigned int id) { return id != oom_error; } public: // Constructor for crashes - VMError(Thread* thread, int sig, address pc, void* siginfo, void* context); + VMError(Thread* thread, unsigned int sig, address pc, void* siginfo, + void* context); // Constructor for VM internal errors VMError(Thread* thread, const char* filename, int lineno, const char* message, const char * detail_msg); -- cgit v1.2.3 From ecdb5867728ba294f96d836250faf0bcc2284e56 Mon Sep 17 00:00:00 2001 From: coleenp Date: Wed, 5 Jan 2011 21:23:15 -0500 Subject: 6583275: Hotspot crash in vm_perform_shutdown_actions due to uninitialized TLS during out of memory handling Summary: Call get_thread_slow() in vm_perform_shutdown actions and add null check. Reviewed-by: kvn, dholmes, jcoomes --- src/share/vm/runtime/java.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/share/vm/runtime/java.cpp b/src/share/vm/runtime/java.cpp index 6abdd64d5..f6b20a7b7 100644 --- a/src/share/vm/runtime/java.cpp +++ b/src/share/vm/runtime/java.cpp @@ -515,8 +515,8 @@ void before_exit(JavaThread * thread) { } void vm_exit(int code) { - Thread* thread = ThreadLocalStorage::thread_index() == -1 ? NULL - : ThreadLocalStorage::get_thread_slow(); + Thread* thread = ThreadLocalStorage::is_initialized() ? + ThreadLocalStorage::get_thread_slow() : NULL; if (thread == NULL) { // we have serious problems -- just exit vm_direct_exit(code); @@ -553,8 +553,9 @@ void vm_perform_shutdown_actions() { // Calling 'exit_globals()' will disable thread-local-storage and cause all // kinds of assertions to trigger in debug mode. if (is_init_completed()) { - Thread* thread = Thread::current(); - if (thread->is_Java_thread()) { + Thread* thread = ThreadLocalStorage::is_initialized() ? + ThreadLocalStorage::get_thread_slow() : NULL; + if (thread != NULL && thread->is_Java_thread()) { // We are leaving the VM, set state to native (in case any OS exit // handlers call back to the VM) JavaThread* jt = (JavaThread*)thread; -- cgit v1.2.3 From 6adead9d8e343cf81ffe597a63ac33b970f812bd Mon Sep 17 00:00:00 2001 From: alanb Date: Fri, 7 Jan 2011 03:38:19 -0800 Subject: 7009975: Large file support broken in hs20-b04 Reviewed-by: phh, acorn, kamg --- src/os/solaris/vm/os_solaris.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/os/solaris/vm/os_solaris.cpp b/src/os/solaris/vm/os_solaris.cpp index 7b08e979d..dd8ea2c60 100644 --- a/src/os/solaris/vm/os_solaris.cpp +++ b/src/os/solaris/vm/os_solaris.cpp @@ -5197,7 +5197,7 @@ int os::open(const char *path, int oflag, int mode) { int o_delete = (oflag & O_DELETE); oflag = oflag & ~O_DELETE; - fd = ::open(path, oflag, mode); + fd = ::open64(path, oflag, mode); if (fd == -1) return -1; //If the open succeeded, the file might still be a directory -- cgit v1.2.3 From 4745af87f6cd043d8b74e812be93b381ff7c9476 Mon Sep 17 00:00:00 2001 From: phh Date: Fri, 7 Jan 2011 10:42:32 -0500 Subject: 7003271: Hotspot should track cumulative Java heap bytes allocated on a per-thread basis Summary: Track allocated bytes in Thread's, update on TLAB retirement and direct allocation in Eden and tenured, add JNI methods for ThreadMXBean. Reviewed-by: coleenp, kvn, dholmes, ysr --- src/cpu/sparc/vm/assembler_sparc.cpp | 24 ++++- src/cpu/sparc/vm/assembler_sparc.hpp | 3 +- src/cpu/sparc/vm/c1_MacroAssembler_sparc.cpp | 5 +- src/cpu/sparc/vm/c1_MacroAssembler_sparc.hpp | 2 +- src/cpu/sparc/vm/c1_Runtime1_sparc.cpp | 7 +- src/cpu/sparc/vm/templateTable_sparc.cpp | 27 ++--- src/cpu/x86/vm/assembler_x86.cpp | 108 ++++++++++++-------- src/cpu/x86/vm/assembler_x86.hpp | 31 +++--- src/cpu/x86/vm/c1_MacroAssembler_x86.cpp | 5 +- src/cpu/x86/vm/c1_Runtime1_x86.cpp | 19 ++-- src/cpu/x86/vm/templateTable_x86_32.cpp | 18 ++-- src/cpu/x86/vm/templateTable_x86_64.cpp | 4 +- src/os/solaris/vm/os_solaris.cpp | 4 +- src/os/solaris/vm/thread_solaris.inline.hpp | 8 +- src/share/vm/gc_interface/collectedHeap.inline.hpp | 3 +- src/share/vm/memory/threadLocalAllocBuffer.cpp | 7 +- src/share/vm/memory/threadLocalAllocBuffer.hpp | 4 +- src/share/vm/opto/macro.cpp | 111 +++++++++++++-------- src/share/vm/prims/jvmti.xml | 4 +- src/share/vm/prims/jvmtiEnv.cpp | 10 +- src/share/vm/runtime/thread.cpp | 18 ++-- src/share/vm/runtime/thread.hpp | 78 +++++++++------ src/share/vm/services/jmm.h | 33 ++++-- src/share/vm/services/management.cpp | 106 +++++++++++++++++--- src/share/vm/services/threadService.cpp | 14 ++- src/share/vm/services/threadService.hpp | 6 +- 26 files changed, 447 insertions(+), 212 deletions(-) diff --git a/src/cpu/sparc/vm/assembler_sparc.cpp b/src/cpu/sparc/vm/assembler_sparc.cpp index 8512afcba..0436b4e2e 100644 --- a/src/cpu/sparc/vm/assembler_sparc.cpp +++ b/src/cpu/sparc/vm/assembler_sparc.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -4083,11 +4083,15 @@ void MacroAssembler::tlab_refill(Label& retry, Label& try_eden, Label& slow_case store_klass(t2, top); verify_oop(top); + ld_ptr(G2_thread, in_bytes(JavaThread::tlab_start_offset()), t1); + sub(top, t1, t1); // size of tlab's allocated portion + incr_allocated_bytes(t1, 0, t2); + // refill the tlab with an eden allocation bind(do_refill); ld_ptr(G2_thread, in_bytes(JavaThread::tlab_size_offset()), t1); sll_ptr(t1, LogHeapWordSize, t1); - // add object_size ?? + // allocate new tlab, address returned in top eden_allocate(top, t1, 0, t2, t3, slow_case); st_ptr(top, G2_thread, in_bytes(JavaThread::tlab_start_offset())); @@ -4115,6 +4119,22 @@ void MacroAssembler::tlab_refill(Label& retry, Label& try_eden, Label& slow_case delayed()->nop(); } +void MacroAssembler::incr_allocated_bytes(Register var_size_in_bytes, + int con_size_in_bytes, + Register t1) { + // Bump total bytes allocated by this thread + assert(t1->is_global(), "must be global reg"); // so all 64 bits are saved on a context switch + assert_different_registers(var_size_in_bytes, t1); + // v8 support has gone the way of the dodo + ldx(G2_thread, in_bytes(JavaThread::allocated_bytes_offset()), t1); + if (var_size_in_bytes->is_valid()) { + add(t1, var_size_in_bytes, t1); + } else { + add(t1, con_size_in_bytes, t1); + } + stx(t1, G2_thread, in_bytes(JavaThread::allocated_bytes_offset())); +} + Assembler::Condition MacroAssembler::negate_condition(Assembler::Condition cond) { switch (cond) { // Note some conditions are synonyms for others diff --git a/src/cpu/sparc/vm/assembler_sparc.hpp b/src/cpu/sparc/vm/assembler_sparc.hpp index ae4357edd..e50e1784b 100644 --- a/src/cpu/sparc/vm/assembler_sparc.hpp +++ b/src/cpu/sparc/vm/assembler_sparc.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -2388,6 +2388,7 @@ public: Label& slow_case // continuation point if fast allocation fails ); void tlab_refill(Label& retry_tlab, Label& try_eden, Label& slow_case); + void incr_allocated_bytes(Register var_size_in_bytes, int con_size_in_bytes, Register t1); // interface method calling void lookup_interface_method(Register recv_klass, diff --git a/src/cpu/sparc/vm/c1_MacroAssembler_sparc.cpp b/src/cpu/sparc/vm/c1_MacroAssembler_sparc.cpp index 6340156f7..85eb66833 100644 --- a/src/cpu/sparc/vm/c1_MacroAssembler_sparc.cpp +++ b/src/cpu/sparc/vm/c1_MacroAssembler_sparc.cpp @@ -166,7 +166,7 @@ void C1_MacroAssembler::try_allocate( Register obj, // result: pointer to object after successful allocation Register var_size_in_bytes, // object size in bytes if unknown at compile time; invalid otherwise int con_size_in_bytes, // object size in bytes if known at compile time - Register t1, // temp register + Register t1, // temp register, must be global register for incr_allocated_bytes Register t2, // temp register Label& slow_case // continuation point if fast allocation fails ) { @@ -174,6 +174,7 @@ void C1_MacroAssembler::try_allocate( tlab_allocate(obj, var_size_in_bytes, con_size_in_bytes, t1, slow_case); } else { eden_allocate(obj, var_size_in_bytes, con_size_in_bytes, t1, t2, slow_case); + incr_allocated_bytes(var_size_in_bytes, con_size_in_bytes, t1); } } @@ -214,7 +215,7 @@ void C1_MacroAssembler::initialize_body(Register base, Register index) { void C1_MacroAssembler::allocate_object( Register obj, // result: pointer to object after successful allocation Register t1, // temp register - Register t2, // temp register + Register t2, // temp register, must be a global register for try_allocate Register t3, // temp register int hdr_size, // object header size in words int obj_size, // object size in words diff --git a/src/cpu/sparc/vm/c1_MacroAssembler_sparc.hpp b/src/cpu/sparc/vm/c1_MacroAssembler_sparc.hpp index b8b063928..c0178e5e0 100644 --- a/src/cpu/sparc/vm/c1_MacroAssembler_sparc.hpp +++ b/src/cpu/sparc/vm/c1_MacroAssembler_sparc.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/cpu/sparc/vm/c1_Runtime1_sparc.cpp b/src/cpu/sparc/vm/c1_Runtime1_sparc.cpp index 7dabe35c2..7ce9a73b6 100644 --- a/src/cpu/sparc/vm/c1_Runtime1_sparc.cpp +++ b/src/cpu/sparc/vm/c1_Runtime1_sparc.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -448,7 +448,9 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { // get the instance size __ ld(G5_klass, klassOopDesc::header_size() * HeapWordSize + Klass::layout_helper_offset_in_bytes(), G1_obj_size); + __ tlab_allocate(O0_obj, G1_obj_size, 0, G3_t1, slow_path); + __ initialize_object(O0_obj, G5_klass, G1_obj_size, 0, G3_t1, G4_t2); __ verify_oop(O0_obj); __ mov(O0, I0); @@ -459,6 +461,8 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { // get the instance size __ ld(G5_klass, klassOopDesc::header_size() * HeapWordSize + Klass::layout_helper_offset_in_bytes(), G1_obj_size); __ eden_allocate(O0_obj, G1_obj_size, 0, G3_t1, G4_t2, slow_path); + __ incr_allocated_bytes(G1_obj_size, 0, G3_t1); + __ initialize_object(O0_obj, G5_klass, G1_obj_size, 0, G3_t1, G4_t2); __ verify_oop(O0_obj); __ mov(O0, I0); @@ -573,6 +577,7 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { __ and3(G1_arr_size, ~MinObjAlignmentInBytesMask, G1_arr_size); __ eden_allocate(O0_obj, G1_arr_size, 0, G3_t1, O1_t2, slow_path); // preserves G1_arr_size + __ incr_allocated_bytes(G1_arr_size, 0, G3_t1); __ initialize_header(O0_obj, G5_klass, G4_length, G3_t1, O1_t2); __ ldub(klass_lh, G3_t1, klass_lh_header_size_offset); diff --git a/src/cpu/sparc/vm/templateTable_sparc.cpp b/src/cpu/sparc/vm/templateTable_sparc.cpp index 896372237..6bfaccd64 100644 --- a/src/cpu/sparc/vm/templateTable_sparc.cpp +++ b/src/cpu/sparc/vm/templateTable_sparc.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -3393,21 +3393,21 @@ void TemplateTable::_new() { __ delayed()->st_ptr(RnewTopValue, G2_thread, in_bytes(JavaThread::tlab_top_offset())); if (allow_shared_alloc) { - // Check if tlab should be discarded (refill_waste_limit >= free) - __ ld_ptr(G2_thread, in_bytes(JavaThread::tlab_refill_waste_limit_offset()), RtlabWasteLimitValue); - __ sub(RendValue, RoldTopValue, RfreeValue); + // Check if tlab should be discarded (refill_waste_limit >= free) + __ ld_ptr(G2_thread, in_bytes(JavaThread::tlab_refill_waste_limit_offset()), RtlabWasteLimitValue); + __ sub(RendValue, RoldTopValue, RfreeValue); #ifdef _LP64 - __ srlx(RfreeValue, LogHeapWordSize, RfreeValue); + __ srlx(RfreeValue, LogHeapWordSize, RfreeValue); #else - __ srl(RfreeValue, LogHeapWordSize, RfreeValue); + __ srl(RfreeValue, LogHeapWordSize, RfreeValue); #endif - __ cmp(RtlabWasteLimitValue, RfreeValue); - __ brx(Assembler::greaterEqualUnsigned, false, Assembler::pt, slow_case); // tlab waste is small - __ delayed()->nop(); + __ cmp(RtlabWasteLimitValue, RfreeValue); + __ brx(Assembler::greaterEqualUnsigned, false, Assembler::pt, slow_case); // tlab waste is small + __ delayed()->nop(); - // increment waste limit to prevent getting stuck on this slow path - __ add(RtlabWasteLimitValue, ThreadLocalAllocBuffer::refill_waste_limit_increment(), RtlabWasteLimitValue); - __ st_ptr(RtlabWasteLimitValue, G2_thread, in_bytes(JavaThread::tlab_refill_waste_limit_offset())); + // increment waste limit to prevent getting stuck on this slow path + __ add(RtlabWasteLimitValue, ThreadLocalAllocBuffer::refill_waste_limit_increment(), RtlabWasteLimitValue); + __ st_ptr(RtlabWasteLimitValue, G2_thread, in_bytes(JavaThread::tlab_refill_waste_limit_offset())); } else { // No allocation in the shared eden. __ br(Assembler::always, false, Assembler::pt, slow_case); @@ -3445,6 +3445,9 @@ void TemplateTable::_new() { __ cmp(RoldTopValue, RnewTopValue); __ brx(Assembler::notEqual, false, Assembler::pn, retry); __ delayed()->nop(); + + // bump total bytes allocated by this thread + __ incr_allocated_bytes(Roffset, 0, G1_scratch); } if (UseTLAB || Universe::heap()->supports_inline_contig_alloc()) { diff --git a/src/cpu/x86/vm/assembler_x86.cpp b/src/cpu/x86/vm/assembler_x86.cpp index 85dc5411f..4c87f23cd 100644 --- a/src/cpu/x86/vm/assembler_x86.cpp +++ b/src/cpu/x86/vm/assembler_x86.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -820,7 +820,20 @@ void Assembler::emit_farith(int b1, int b2, int i) { } -// Now the Assembler instruction (identical for 32/64 bits) +// Now the Assembler instructions (identical for 32/64 bits) + +void Assembler::adcl(Address dst, int32_t imm32) { + InstructionMark im(this); + prefix(dst); + emit_arith_operand(0x81, rdx, dst, imm32); +} + +void Assembler::adcl(Address dst, Register src) { + InstructionMark im(this); + prefix(dst, src); + emit_byte(0x11); + emit_operand(src, dst); +} void Assembler::adcl(Register dst, int32_t imm32) { prefix(dst); @@ -2195,9 +2208,7 @@ void Assembler::notl(Register dst) { void Assembler::orl(Address dst, int32_t imm32) { InstructionMark im(this); prefix(dst); - emit_byte(0x81); - emit_operand(rcx, dst, 4); - emit_long(imm32); + emit_arith_operand(0x81, rcx, dst, imm32); } void Assembler::orl(Register dst, int32_t imm32) { @@ -2205,7 +2216,6 @@ void Assembler::orl(Register dst, int32_t imm32) { emit_arith(0x81, 0xC8, dst, imm32); } - void Assembler::orl(Register dst, Address src) { InstructionMark im(this); prefix(src, dst); @@ -2213,7 +2223,6 @@ void Assembler::orl(Register dst, Address src) { emit_operand(dst, src); } - void Assembler::orl(Register dst, Register src) { (void) prefix_and_encode(dst->encoding(), src->encoding()); emit_arith(0x0B, 0xC0, dst, src); @@ -2692,20 +2701,7 @@ void Assembler::stmxcsr( Address dst) { void Assembler::subl(Address dst, int32_t imm32) { InstructionMark im(this); prefix(dst); - if (is8bit(imm32)) { - emit_byte(0x83); - emit_operand(rbp, dst, 1); - emit_byte(imm32 & 0xFF); - } else { - emit_byte(0x81); - emit_operand(rbp, dst, 4); - emit_long(imm32); - } -} - -void Assembler::subl(Register dst, int32_t imm32) { - prefix(dst); - emit_arith(0x81, 0xE8, dst, imm32); + emit_arith_operand(0x81, rbp, dst, imm32); } void Assembler::subl(Address dst, Register src) { @@ -2715,6 +2711,11 @@ void Assembler::subl(Address dst, Register src) { emit_operand(src, dst); } +void Assembler::subl(Register dst, int32_t imm32) { + prefix(dst); + emit_arith(0x81, 0xE8, dst, imm32); +} + void Assembler::subl(Register dst, Address src) { InstructionMark im(this); prefix(src, dst); @@ -4333,6 +4334,7 @@ void Assembler::sarq(Register dst) { emit_byte(0xD3); emit_byte(0xF8 | encode); } + void Assembler::sbbq(Address dst, int32_t imm32) { InstructionMark im(this); prefixq(dst); @@ -4392,20 +4394,7 @@ void Assembler::shrq(Register dst) { void Assembler::subq(Address dst, int32_t imm32) { InstructionMark im(this); prefixq(dst); - if (is8bit(imm32)) { - emit_byte(0x83); - emit_operand(rbp, dst, 1); - emit_byte(imm32 & 0xFF); - } else { - emit_byte(0x81); - emit_operand(rbp, dst, 4); - emit_long(imm32); - } -} - -void Assembler::subq(Register dst, int32_t imm32) { - (void) prefixq_and_encode(dst->encoding()); - emit_arith(0x81, 0xE8, dst, imm32); + emit_arith_operand(0x81, rbp, dst, imm32); } void Assembler::subq(Address dst, Register src) { @@ -4415,6 +4404,11 @@ void Assembler::subq(Address dst, Register src) { emit_operand(src, dst); } +void Assembler::subq(Register dst, int32_t imm32) { + (void) prefixq_and_encode(dst->encoding()); + emit_arith(0x81, 0xE8, dst, imm32); +} + void Assembler::subq(Register dst, Address src) { InstructionMark im(this); prefixq(src, dst); @@ -7136,9 +7130,9 @@ void MacroAssembler::tlab_allocate(Register obj, } // Preserves rbx, and rdx. -void MacroAssembler::tlab_refill(Label& retry, - Label& try_eden, - Label& slow_case) { +Register MacroAssembler::tlab_refill(Label& retry, + Label& try_eden, + Label& slow_case) { Register top = rax; Register t1 = rcx; Register t2 = rsi; @@ -7185,7 +7179,7 @@ void MacroAssembler::tlab_refill(Label& retry, // if tlab is currently allocated (top or end != null) then // fill [top, end + alignment_reserve) with array object - testptr (top, top); + testptr(top, top); jcc(Assembler::zero, do_refill); // set up the mark word @@ -7197,16 +7191,20 @@ void MacroAssembler::tlab_refill(Label& retry, movl(Address(top, arrayOopDesc::length_offset_in_bytes()), t1); // set klass to intArrayKlass // dubious reloc why not an oop reloc? - movptr(t1, ExternalAddress((address) Universe::intArrayKlassObj_addr())); + movptr(t1, ExternalAddress((address)Universe::intArrayKlassObj_addr())); // store klass last. concurrent gcs assumes klass length is valid if // klass field is not null. store_klass(top, t1); + movptr(t1, top); + subptr(t1, Address(thread_reg, in_bytes(JavaThread::tlab_start_offset()))); + incr_allocated_bytes(thread_reg, t1, 0); + // refill the tlab with an eden allocation bind(do_refill); movptr(t1, Address(thread_reg, in_bytes(JavaThread::tlab_size_offset()))); shlptr(t1, LogHeapWordSize); - // add object_size ?? + // allocate new tlab, address returned in top eden_allocate(top, t1, 0, t2, slow_case); // Check that t1 was preserved in eden_allocate. @@ -7234,6 +7232,34 @@ void MacroAssembler::tlab_refill(Label& retry, movptr(Address(thread_reg, in_bytes(JavaThread::tlab_end_offset())), top); verify_tlab(); jmp(retry); + + return thread_reg; // for use by caller +} + +void MacroAssembler::incr_allocated_bytes(Register thread, + Register var_size_in_bytes, + int con_size_in_bytes, + Register t1) { +#ifdef _LP64 + if (var_size_in_bytes->is_valid()) { + addq(Address(thread, in_bytes(JavaThread::allocated_bytes_offset())), var_size_in_bytes); + } else { + addq(Address(thread, in_bytes(JavaThread::allocated_bytes_offset())), con_size_in_bytes); + } +#else + if (!thread->is_valid()) { + assert(t1->is_valid(), "need temp reg"); + thread = t1; + get_thread(thread); + } + + if (var_size_in_bytes->is_valid()) { + addl(Address(thread, in_bytes(JavaThread::allocated_bytes_offset())), var_size_in_bytes); + } else { + addl(Address(thread, in_bytes(JavaThread::allocated_bytes_offset())), con_size_in_bytes); + } + adcl(Address(thread, in_bytes(JavaThread::allocated_bytes_offset())+4), 0); +#endif } static const double pi_4 = 0.7853981633974483; diff --git a/src/cpu/x86/vm/assembler_x86.hpp b/src/cpu/x86/vm/assembler_x86.hpp index b9fcc2eff..a1a8a96de 100644 --- a/src/cpu/x86/vm/assembler_x86.hpp +++ b/src/cpu/x86/vm/assembler_x86.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -674,12 +674,14 @@ private: // Utilities #ifdef _LP64 - static bool is_simm(int64_t x, int nbits) { return -( CONST64(1) << (nbits-1) ) <= x && x < ( CONST64(1) << (nbits-1) ); } + static bool is_simm(int64_t x, int nbits) { return -(CONST64(1) << (nbits-1)) <= x && + x < (CONST64(1) << (nbits-1)); } static bool is_simm32(int64_t x) { return x == (int64_t)(int32_t)x; } #else - static bool is_simm(int32_t x, int nbits) { return -( 1 << (nbits-1) ) <= x && x < ( 1 << (nbits-1) ); } + static bool is_simm(int32_t x, int nbits) { return -(1 << (nbits-1)) <= x && + x < (1 << (nbits-1)); } static bool is_simm32(int32_t x) { return true; } -#endif // LP64 +#endif // _LP64 // Generic instructions // Does 32bit or 64bit as needed for the platform. In some sense these @@ -705,7 +707,6 @@ private: void push(void* v); void pop(void* v); - // These do register sized moves/scans void rep_mov(); void rep_set(); @@ -716,6 +717,8 @@ private: // Vanilla instructions in lexical order + void adcl(Address dst, int32_t imm32); + void adcl(Address dst, Register src); void adcl(Register dst, int32_t imm32); void adcl(Register dst, Address src); void adcl(Register dst, Register src); @@ -724,7 +727,6 @@ private: void adcq(Register dst, Address src); void adcq(Register dst, Register src); - void addl(Address dst, int32_t imm32); void addl(Address dst, Register src); void addl(Register dst, int32_t imm32); @@ -737,7 +739,6 @@ private: void addq(Register dst, Address src); void addq(Register dst, Register src); - void addr_nop_4(); void addr_nop_5(); void addr_nop_7(); @@ -759,7 +760,6 @@ private: void andq(Register dst, Address src); void andq(Register dst, Register src); - // Bitwise Logical AND of Packed Double-Precision Floating-Point Values void andpd(XMMRegister dst, Address src); void andpd(XMMRegister dst, XMMRegister src); @@ -1151,7 +1151,7 @@ private: #ifdef _LP64 void movq(Register dst, Register src); void movq(Register dst, Address src); - void movq(Address dst, Register src); + void movq(Address dst, Register src); #endif void movq(Address dst, MMXRegister src ); @@ -1177,7 +1177,7 @@ private: void movsbq(Register dst, Register src); // Move signed 32bit immediate to 64bit extending sign - void movslq(Address dst, int32_t imm64); + void movslq(Address dst, int32_t imm64); void movslq(Register dst, int32_t imm64); void movslq(Register dst, Address src); @@ -1857,7 +1857,10 @@ class MacroAssembler: public Assembler { Register t2, // temp register Label& slow_case // continuation point if fast allocation fails ); - void tlab_refill(Label& retry_tlab, Label& try_eden, Label& slow_case); + Register tlab_refill(Label& retry_tlab, Label& try_eden, Label& slow_case); // returns TLS address + void incr_allocated_bytes(Register thread, + Register var_size_in_bytes, int con_size_in_bytes, + Register t1 = noreg); // interface method calling void lookup_interface_method(Register recv_klass, @@ -2180,9 +2183,9 @@ public: void divss(XMMRegister dst, Address src) { Assembler::divss(dst, src); } void divss(XMMRegister dst, AddressLiteral src) { Assembler::divss(dst, as_Address(src)); } - void movsd(XMMRegister dst, XMMRegister src) { Assembler::movsd(dst, src); } - void movsd(Address dst, XMMRegister src) { Assembler::movsd(dst, src); } - void movsd(XMMRegister dst, Address src) { Assembler::movsd(dst, src); } + void movsd(XMMRegister dst, XMMRegister src) { Assembler::movsd(dst, src); } + void movsd(Address dst, XMMRegister src) { Assembler::movsd(dst, src); } + void movsd(XMMRegister dst, Address src) { Assembler::movsd(dst, src); } void movsd(XMMRegister dst, AddressLiteral src) { Assembler::movsd(dst, as_Address(src)); } void mulsd(XMMRegister dst, XMMRegister src) { Assembler::mulsd(dst, src); } diff --git a/src/cpu/x86/vm/c1_MacroAssembler_x86.cpp b/src/cpu/x86/vm/c1_MacroAssembler_x86.cpp index 48d117b3f..d386a99a0 100644 --- a/src/cpu/x86/vm/c1_MacroAssembler_x86.cpp +++ b/src/cpu/x86/vm/c1_MacroAssembler_x86.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -141,6 +141,7 @@ void C1_MacroAssembler::try_allocate(Register obj, Register var_size_in_bytes, i tlab_allocate(obj, var_size_in_bytes, con_size_in_bytes, t1, t2, slow_case); } else { eden_allocate(obj, var_size_in_bytes, con_size_in_bytes, t1, slow_case); + incr_allocated_bytes(noreg, var_size_in_bytes, con_size_in_bytes, t1); } } @@ -234,7 +235,7 @@ void C1_MacroAssembler::initialize_body(Register obj, Register len_in_bytes, int void C1_MacroAssembler::allocate_object(Register obj, Register t1, Register t2, int header_size, int object_size, Register klass, Label& slow_case) { assert(obj == rax, "obj must be in rax, for cmpxchg"); - assert(obj != t1 && obj != t2 && t1 != t2, "registers must be different"); // XXX really? + assert_different_registers(obj, t1, t2); // XXX really? assert(header_size >= 0 && object_size >= header_size, "illegal sizes"); try_allocate(obj, noreg, object_size * BytesPerWord, t1, t2, slow_case); diff --git a/src/cpu/x86/vm/c1_Runtime1_x86.cpp b/src/cpu/x86/vm/c1_Runtime1_x86.cpp index ce51fea3a..0a5680425 100644 --- a/src/cpu/x86/vm/c1_Runtime1_x86.cpp +++ b/src/cpu/x86/vm/c1_Runtime1_x86.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -977,7 +977,6 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { // verify that that there is really a valid exception in rax, __ verify_not_null_oop(exception_oop); - oop_maps = new OopMapSet(); OopMap* oop_map = generate_oop_map(sasm, 1); generate_handle_exception(sasm, oop_maps, oop_map); @@ -1037,13 +1036,16 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { // if we got here then the TLAB allocation failed, so try // refilling the TLAB or allocating directly from eden. Label retry_tlab, try_eden; - __ tlab_refill(retry_tlab, try_eden, slow_path); // does not destroy rdx (klass) + const Register thread = + __ tlab_refill(retry_tlab, try_eden, slow_path); // does not destroy rdx (klass), returns rdi __ bind(retry_tlab); // get the instance size (size is postive so movl is fine for 64bit) __ movl(obj_size, Address(klass, klassOopDesc::header_size() * HeapWordSize + Klass::layout_helper_offset_in_bytes())); + __ tlab_allocate(obj, obj_size, 0, t1, t2, slow_path); + __ initialize_object(obj, klass, obj_size, 0, t1, t2); __ verify_oop(obj); __ pop(rbx); @@ -1053,7 +1055,10 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { __ bind(try_eden); // get the instance size (size is postive so movl is fine for 64bit) __ movl(obj_size, Address(klass, klassOopDesc::header_size() * HeapWordSize + Klass::layout_helper_offset_in_bytes())); + __ eden_allocate(obj, obj_size, 0, t1, slow_path); + __ incr_allocated_bytes(thread, obj_size, 0); + __ initialize_object(obj, klass, obj_size, 0, t1, t2); __ verify_oop(obj); __ pop(rbx); @@ -1143,12 +1148,13 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { // if we got here then the TLAB allocation failed, so try // refilling the TLAB or allocating directly from eden. Label retry_tlab, try_eden; - __ tlab_refill(retry_tlab, try_eden, slow_path); // preserves rbx, & rdx + const Register thread = + __ tlab_refill(retry_tlab, try_eden, slow_path); // preserves rbx & rdx, returns rdi __ bind(retry_tlab); // get the allocation size: round_up(hdr + length << (layout_helper & 0x1F)) - // since size is postive movl does right thing on 64bit + // since size is positive movl does right thing on 64bit __ movl(t1, Address(klass, klassOopDesc::header_size() * HeapWordSize + Klass::layout_helper_offset_in_bytes())); // since size is postive movl does right thing on 64bit __ movl(arr_size, length); @@ -1175,7 +1181,7 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { __ bind(try_eden); // get the allocation size: round_up(hdr + length << (layout_helper & 0x1F)) - // since size is postive movl does right thing on 64bit + // since size is positive movl does right thing on 64bit __ movl(t1, Address(klass, klassOopDesc::header_size() * HeapWordSize + Klass::layout_helper_offset_in_bytes())); // since size is postive movl does right thing on 64bit __ movl(arr_size, length); @@ -1188,6 +1194,7 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { __ andptr(arr_size, ~MinObjAlignmentInBytesMask); __ eden_allocate(obj, arr_size, 0, t1, slow_path); // preserves arr_size + __ incr_allocated_bytes(thread, arr_size, 0); __ initialize_header(obj, klass, length, t1, t2); __ movb(t1, Address(klass, klassOopDesc::header_size() * HeapWordSize + Klass::layout_helper_offset_in_bytes() + (Klass::_lh_header_size_shift / BitsPerByte))); diff --git a/src/cpu/x86/vm/templateTable_x86_32.cpp b/src/cpu/x86/vm/templateTable_x86_32.cpp index 898069bc9..345b5f62c 100644 --- a/src/cpu/x86/vm/templateTable_x86_32.cpp +++ b/src/cpu/x86/vm/templateTable_x86_32.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -3203,10 +3203,12 @@ void TemplateTable::_new() { const bool allow_shared_alloc = Universe::heap()->supports_inline_contig_alloc() && !CMSIncrementalMode; - if (UseTLAB) { - const Register thread = rcx; - + const Register thread = rcx; + if (UseTLAB || allow_shared_alloc) { __ get_thread(thread); + } + + if (UseTLAB) { __ movptr(rax, Address(thread, in_bytes(JavaThread::tlab_top_offset()))); __ lea(rbx, Address(rax, rdx, Address::times_1)); __ cmpptr(rbx, Address(thread, in_bytes(JavaThread::tlab_end_offset()))); @@ -3247,6 +3249,8 @@ void TemplateTable::_new() { // if someone beat us on the allocation, try again, otherwise continue __ jcc(Assembler::notEqual, retry); + + __ incr_allocated_bytes(thread, rdx, 0); } if (UseTLAB || Universe::heap()->supports_inline_contig_alloc()) { @@ -3256,12 +3260,12 @@ void TemplateTable::_new() { __ decrement(rdx, sizeof(oopDesc)); __ jcc(Assembler::zero, initialize_header); - // Initialize topmost object field, divide rdx by 8, check if odd and - // test if zero. + // Initialize topmost object field, divide rdx by 8, check if odd and + // test if zero. __ xorl(rcx, rcx); // use zero reg to clear memory (shorter code) __ shrl(rdx, LogBytesPerLong); // divide by 2*oopSize and set carry flag if odd - // rdx must have been multiple of 8 + // rdx must have been multiple of 8 #ifdef ASSERT // make sure rdx was multiple of 8 Label L; diff --git a/src/cpu/x86/vm/templateTable_x86_64.cpp b/src/cpu/x86/vm/templateTable_x86_64.cpp index a396e88da..cd45253d5 100644 --- a/src/cpu/x86/vm/templateTable_x86_64.cpp +++ b/src/cpu/x86/vm/templateTable_x86_64.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -3266,6 +3266,8 @@ void TemplateTable::_new() { // if someone beat us on the allocation, try again, otherwise continue __ jcc(Assembler::notEqual, retry); + + __ incr_allocated_bytes(r15_thread, rdx, 0); } if (UseTLAB || Universe::heap()->supports_inline_contig_alloc()) { diff --git a/src/os/solaris/vm/os_solaris.cpp b/src/os/solaris/vm/os_solaris.cpp index dd8ea2c60..79a030b5f 100644 --- a/src/os/solaris/vm/os_solaris.cpp +++ b/src/os/solaris/vm/os_solaris.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -283,7 +283,7 @@ Thread* ThreadLocalStorage::get_thread_via_cache_slowly(uintptr_t raw_id, is_error_reported(), "sp must be inside of selected thread stack"); - thread->_self_raw_id = raw_id; // mark for quick retrieval + thread->set_self_raw_id(raw_id); // mark for quick retrieval _get_thread_cache[ index ] = thread; } return thread; diff --git a/src/os/solaris/vm/thread_solaris.inline.hpp b/src/os/solaris/vm/thread_solaris.inline.hpp index 94c51676d..903be9ddc 100644 --- a/src/os/solaris/vm/thread_solaris.inline.hpp +++ b/src/os/solaris/vm/thread_solaris.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -53,10 +53,10 @@ inline Thread* ThreadLocalStorage::thread() { uintptr_t raw = pd_raw_thread_id(); int ix = pd_cache_index(raw); - Thread *Candidate = ThreadLocalStorage::_get_thread_cache[ix]; - if (Candidate->_self_raw_id == raw) { + Thread* candidate = ThreadLocalStorage::_get_thread_cache[ix]; + if (candidate->self_raw_id() == raw) { // hit - return Candidate; + return candidate; } else { return ThreadLocalStorage::get_thread_via_cache_slowly(raw, ix); } diff --git a/src/share/vm/gc_interface/collectedHeap.inline.hpp b/src/share/vm/gc_interface/collectedHeap.inline.hpp index c9f5f0111..73f54d981 100644 --- a/src/share/vm/gc_interface/collectedHeap.inline.hpp +++ b/src/share/vm/gc_interface/collectedHeap.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -153,6 +153,7 @@ HeapWord* CollectedHeap::common_mem_allocate_noinit(size_t size, bool is_noref, check_for_non_bad_heap_word_value(result, size)); assert(!HAS_PENDING_EXCEPTION, "Unexpected exception, will result in uninitialized storage"); + THREAD->incr_allocated_bytes(size * HeapWordSize); return result; } diff --git a/src/share/vm/memory/threadLocalAllocBuffer.cpp b/src/share/vm/memory/threadLocalAllocBuffer.cpp index f3eec576c..74f2c44d4 100644 --- a/src/share/vm/memory/threadLocalAllocBuffer.cpp +++ b/src/share/vm/memory/threadLocalAllocBuffer.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -114,6 +114,11 @@ void ThreadLocalAllocBuffer::accumulate_statistics() { void ThreadLocalAllocBuffer::make_parsable(bool retire) { if (end() != NULL) { invariants(); + + if (retire) { + myThread()->incr_allocated_bytes(used_bytes()); + } + CollectedHeap::fill_with_object(top(), hard_end(), retire); if (retire || ZeroTLAB) { // "Reset" the TLAB diff --git a/src/share/vm/memory/threadLocalAllocBuffer.hpp b/src/share/vm/memory/threadLocalAllocBuffer.hpp index 2d091f693..4b88835db 100644 --- a/src/share/vm/memory/threadLocalAllocBuffer.hpp +++ b/src/share/vm/memory/threadLocalAllocBuffer.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -112,6 +112,8 @@ public: HeapWord* top() const { return _top; } HeapWord* pf_top() const { return _pf_top; } size_t desired_size() const { return _desired_size; } + size_t used() const { return pointer_delta(top(), start()); } + size_t used_bytes() const { return pointer_delta(top(), start(), 1); } size_t free() const { return pointer_delta(end(), top()); } // Don't discard tlab if remaining space is larger than this. size_t refill_waste_limit() const { return _refill_waste_limit; } diff --git a/src/share/vm/opto/macro.cpp b/src/share/vm/opto/macro.cpp index 3c95bf0ea..465c8babd 100644 --- a/src/share/vm/opto/macro.cpp +++ b/src/share/vm/opto/macro.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1158,7 +1158,7 @@ void PhaseMacroExpand::expand_allocate_common( // Note: We set the control input on "eden_end" and "old_eden_top" when using // a TLAB to work around a bug where these values were being moved across // a safepoint. These are not oops, so they cannot be include in the oop - // map, but the can be changed by a GC. The proper way to fix this would + // map, but they can be changed by a GC. The proper way to fix this would // be to set the raw memory state when generating a SafepointNode. However // this will require extensive changes to the loop optimization in order to // prevent a degradation of the optimization. @@ -1167,24 +1167,24 @@ void PhaseMacroExpand::expand_allocate_common( // allocate the Region and Phi nodes for the result result_region = new (C, 3) RegionNode(3); - result_phi_rawmem = new (C, 3) PhiNode( result_region, Type::MEMORY, TypeRawPtr::BOTTOM ); - result_phi_rawoop = new (C, 3) PhiNode( result_region, TypeRawPtr::BOTTOM ); - result_phi_i_o = new (C, 3) PhiNode( result_region, Type::ABIO ); // I/O is used for Prefetch + result_phi_rawmem = new (C, 3) PhiNode(result_region, Type::MEMORY, TypeRawPtr::BOTTOM); + result_phi_rawoop = new (C, 3) PhiNode(result_region, TypeRawPtr::BOTTOM); + result_phi_i_o = new (C, 3) PhiNode(result_region, Type::ABIO); // I/O is used for Prefetch // We need a Region for the loop-back contended case. enum { fall_in_path = 1, contended_loopback_path = 2 }; Node *contended_region; Node *contended_phi_rawmem; - if( UseTLAB ) { + if (UseTLAB) { contended_region = toobig_false; contended_phi_rawmem = mem; } else { contended_region = new (C, 3) RegionNode(3); - contended_phi_rawmem = new (C, 3) PhiNode( contended_region, Type::MEMORY, TypeRawPtr::BOTTOM); + contended_phi_rawmem = new (C, 3) PhiNode(contended_region, Type::MEMORY, TypeRawPtr::BOTTOM); // Now handle the passing-too-big test. We fall into the contended // loop-back merge point. - contended_region ->init_req( fall_in_path, toobig_false ); - contended_phi_rawmem->init_req( fall_in_path, mem ); + contended_region ->init_req(fall_in_path, toobig_false); + contended_phi_rawmem->init_req(fall_in_path, mem); transform_later(contended_region); transform_later(contended_phi_rawmem); } @@ -1192,78 +1192,101 @@ void PhaseMacroExpand::expand_allocate_common( // Load(-locked) the heap top. // See note above concerning the control input when using a TLAB Node *old_eden_top = UseTLAB - ? new (C, 3) LoadPNode ( ctrl, contended_phi_rawmem, eden_top_adr, TypeRawPtr::BOTTOM, TypeRawPtr::BOTTOM ) - : new (C, 3) LoadPLockedNode( contended_region, contended_phi_rawmem, eden_top_adr ); + ? new (C, 3) LoadPNode (ctrl, contended_phi_rawmem, eden_top_adr, TypeRawPtr::BOTTOM, TypeRawPtr::BOTTOM) + : new (C, 3) LoadPLockedNode(contended_region, contended_phi_rawmem, eden_top_adr); transform_later(old_eden_top); // Add to heap top to get a new heap top - Node *new_eden_top = new (C, 4) AddPNode( top(), old_eden_top, size_in_bytes ); + Node *new_eden_top = new (C, 4) AddPNode(top(), old_eden_top, size_in_bytes); transform_later(new_eden_top); // Check for needing a GC; compare against heap end - Node *needgc_cmp = new (C, 3) CmpPNode( new_eden_top, eden_end ); + Node *needgc_cmp = new (C, 3) CmpPNode(new_eden_top, eden_end); transform_later(needgc_cmp); - Node *needgc_bol = new (C, 2) BoolNode( needgc_cmp, BoolTest::ge ); + Node *needgc_bol = new (C, 2) BoolNode(needgc_cmp, BoolTest::ge); transform_later(needgc_bol); - IfNode *needgc_iff = new (C, 2) IfNode(contended_region, needgc_bol, PROB_UNLIKELY_MAG(4), COUNT_UNKNOWN ); + IfNode *needgc_iff = new (C, 2) IfNode(contended_region, needgc_bol, PROB_UNLIKELY_MAG(4), COUNT_UNKNOWN); transform_later(needgc_iff); // Plug the failing-heap-space-need-gc test into the slow-path region - Node *needgc_true = new (C, 1) IfTrueNode( needgc_iff ); + Node *needgc_true = new (C, 1) IfTrueNode(needgc_iff); transform_later(needgc_true); - if( initial_slow_test ) { - slow_region ->init_req( need_gc_path, needgc_true ); + if (initial_slow_test) { + slow_region->init_req(need_gc_path, needgc_true); // This completes all paths into the slow merge point transform_later(slow_region); } else { // No initial slow path needed! // Just fall from the need-GC path straight into the VM call. - slow_region = needgc_true; + slow_region = needgc_true; } // No need for a GC. Setup for the Store-Conditional - Node *needgc_false = new (C, 1) IfFalseNode( needgc_iff ); + Node *needgc_false = new (C, 1) IfFalseNode(needgc_iff); transform_later(needgc_false); // Grab regular I/O before optional prefetch may change it. // Slow-path does no I/O so just set it to the original I/O. - result_phi_i_o->init_req( slow_result_path, i_o ); + result_phi_i_o->init_req(slow_result_path, i_o); i_o = prefetch_allocation(i_o, needgc_false, contended_phi_rawmem, old_eden_top, new_eden_top, length); + // Name successful fast-path variables + Node* fast_oop = old_eden_top; + Node* fast_oop_ctrl; + Node* fast_oop_rawmem; + // Store (-conditional) the modified eden top back down. // StorePConditional produces flags for a test PLUS a modified raw // memory state. - Node *store_eden_top; - Node *fast_oop_ctrl; - if( UseTLAB ) { - store_eden_top = new (C, 4) StorePNode( needgc_false, contended_phi_rawmem, eden_top_adr, TypeRawPtr::BOTTOM, new_eden_top ); + if (UseTLAB) { + Node* store_eden_top = + new (C, 4) StorePNode(needgc_false, contended_phi_rawmem, eden_top_adr, + TypeRawPtr::BOTTOM, new_eden_top); transform_later(store_eden_top); fast_oop_ctrl = needgc_false; // No contention, so this is the fast path + fast_oop_rawmem = store_eden_top; } else { - store_eden_top = new (C, 5) StorePConditionalNode( needgc_false, contended_phi_rawmem, eden_top_adr, new_eden_top, old_eden_top ); + Node* store_eden_top = + new (C, 5) StorePConditionalNode(needgc_false, contended_phi_rawmem, eden_top_adr, + new_eden_top, fast_oop/*old_eden_top*/); transform_later(store_eden_top); - Node *contention_check = new (C, 2) BoolNode( store_eden_top, BoolTest::ne ); + Node *contention_check = new (C, 2) BoolNode(store_eden_top, BoolTest::ne); transform_later(contention_check); store_eden_top = new (C, 1) SCMemProjNode(store_eden_top); transform_later(store_eden_top); // If not using TLABs, check to see if there was contention. - IfNode *contention_iff = new (C, 2) IfNode ( needgc_false, contention_check, PROB_MIN, COUNT_UNKNOWN ); + IfNode *contention_iff = new (C, 2) IfNode (needgc_false, contention_check, PROB_MIN, COUNT_UNKNOWN); transform_later(contention_iff); - Node *contention_true = new (C, 1) IfTrueNode( contention_iff ); + Node *contention_true = new (C, 1) IfTrueNode(contention_iff); transform_later(contention_true); // If contention, loopback and try again. - contended_region->init_req( contended_loopback_path, contention_true ); - contended_phi_rawmem->init_req( contended_loopback_path, store_eden_top ); + contended_region->init_req(contended_loopback_path, contention_true); + contended_phi_rawmem->init_req(contended_loopback_path, store_eden_top); // Fast-path succeeded with no contention! - Node *contention_false = new (C, 1) IfFalseNode( contention_iff ); + Node *contention_false = new (C, 1) IfFalseNode(contention_iff); transform_later(contention_false); fast_oop_ctrl = contention_false; + + // Bump total allocated bytes for this thread + Node* thread = new (C, 1) ThreadLocalNode(); + transform_later(thread); + Node* alloc_bytes_adr = basic_plus_adr(top()/*not oop*/, thread, + in_bytes(JavaThread::allocated_bytes_offset())); + Node* alloc_bytes = make_load(fast_oop_ctrl, store_eden_top, alloc_bytes_adr, + 0, TypeLong::LONG, T_LONG); +#ifdef _LP64 + Node* alloc_size = size_in_bytes; +#else + Node* alloc_size = new (C, 2) ConvI2LNode(size_in_bytes); + transform_later(alloc_size); +#endif + Node* new_alloc_bytes = new (C, 3) AddLNode(alloc_bytes, alloc_size); + transform_later(new_alloc_bytes); + fast_oop_rawmem = make_store(fast_oop_ctrl, store_eden_top, alloc_bytes_adr, + 0, new_alloc_bytes, T_LONG); } - // Rename successful fast-path variables to make meaning more obvious - Node* fast_oop = old_eden_top; - Node* fast_oop_rawmem = store_eden_top; fast_oop_rawmem = initialize_object(alloc, fast_oop_ctrl, fast_oop_rawmem, fast_oop, klass_node, length, size_in_bytes); @@ -1282,11 +1305,11 @@ void PhaseMacroExpand::expand_allocate_common( call->init_req(TypeFunc::Parms+0, thread); call->init_req(TypeFunc::Parms+1, fast_oop); - call->init_req( TypeFunc::Control, fast_oop_ctrl ); - call->init_req( TypeFunc::I_O , top() ) ; // does no i/o - call->init_req( TypeFunc::Memory , fast_oop_rawmem ); - call->init_req( TypeFunc::ReturnAdr, alloc->in(TypeFunc::ReturnAdr) ); - call->init_req( TypeFunc::FramePtr, alloc->in(TypeFunc::FramePtr) ); + call->init_req(TypeFunc::Control, fast_oop_ctrl); + call->init_req(TypeFunc::I_O , top()); // does no i/o + call->init_req(TypeFunc::Memory , fast_oop_rawmem); + call->init_req(TypeFunc::ReturnAdr, alloc->in(TypeFunc::ReturnAdr)); + call->init_req(TypeFunc::FramePtr, alloc->in(TypeFunc::FramePtr)); transform_later(call); fast_oop_ctrl = new (C, 1) ProjNode(call,TypeFunc::Control); transform_later(fast_oop_ctrl); @@ -1295,10 +1318,10 @@ void PhaseMacroExpand::expand_allocate_common( } // Plug in the successful fast-path into the result merge point - result_region ->init_req( fast_result_path, fast_oop_ctrl ); - result_phi_rawoop->init_req( fast_result_path, fast_oop ); - result_phi_i_o ->init_req( fast_result_path, i_o ); - result_phi_rawmem->init_req( fast_result_path, fast_oop_rawmem ); + result_region ->init_req(fast_result_path, fast_oop_ctrl); + result_phi_rawoop->init_req(fast_result_path, fast_oop); + result_phi_i_o ->init_req(fast_result_path, i_o); + result_phi_rawmem->init_req(fast_result_path, fast_oop_rawmem); } else { slow_region = ctrl; } diff --git a/src/share/vm/prims/jvmti.xml b/src/share/vm/prims/jvmti.xml index 672a59380..9e24fb64b 100644 --- a/src/share/vm/prims/jvmti.xml +++ b/src/share/vm/prims/jvmti.xml @@ -1,7 +1,7 @@