diff --git a/agent/src/os/bsd/MacosxDebuggerLocal.m b/agent/src/os/bsd/MacosxDebuggerLocal.m index 98ace91a2c6af30666194449a84edc82d45b5e4e..c14c6b7bc4bc1b4c002de94cea33195e82accc85 100644 --- a/agent/src/os/bsd/MacosxDebuggerLocal.m +++ b/agent/src/os/bsd/MacosxDebuggerLocal.m @@ -160,7 +160,7 @@ Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_readBytesFromProcess0( CHECK_EXCEPTION_(0); unsigned long alignedAddress; - unsigned long alignedLength; + unsigned long alignedLength = 0; kern_return_t result; vm_offset_t *pages; int *mapped; @@ -630,7 +630,7 @@ Java_sun_jvm_hotspot_asm_Disassembler_load_1library( /* Couldn't find entry point. error_message should contain some * platform dependent error message. */ - THROW_NEW_DEBUGGER_EXCEPTION(error_message); + THROW_NEW_DEBUGGER_EXCEPTION_(error_message, (jlong)func); } return (jlong)func; } diff --git a/src/os/bsd/vm/os_bsd.cpp b/src/os/bsd/vm/os_bsd.cpp index fdf5772a764ce34fa6939e6e995dde1d528f669f..b407b4251fd02dcc5c5b3619b4ac10a599cc3dfd 100644 --- a/src/os/bsd/vm/os_bsd.cpp +++ b/src/os/bsd/vm/os_bsd.cpp @@ -3903,15 +3903,27 @@ bool os::pd_unmap_memory(char* addr, size_t bytes) { jlong os::current_thread_cpu_time() { #ifdef __APPLE__ return os::thread_cpu_time(Thread::current(), true /* user + sys */); +#else + Unimplemented(); + return 0; #endif } jlong os::thread_cpu_time(Thread* thread) { +#ifdef __APPLE__ + return os::thread_cpu_time(thread, true /* user + sys */); +#else + Unimplemented(); + return 0; +#endif } jlong os::current_thread_cpu_time(bool user_sys_cpu_time) { #ifdef __APPLE__ return os::thread_cpu_time(Thread::current(), user_sys_cpu_time); +#else + Unimplemented(); + return 0; #endif } @@ -3935,6 +3947,9 @@ jlong os::thread_cpu_time(Thread *thread, bool user_sys_cpu_time) { } else { return ((jlong)tinfo.user_time.seconds * 1000000000) + ((jlong)tinfo.user_time.microseconds * (jlong)1000); } +#else + Unimplemented(); + return 0; #endif } diff --git a/src/share/vm/oops/instanceKlass.cpp b/src/share/vm/oops/instanceKlass.cpp index f492b895605dfdf5bb778811b4607418d5ddb295..fd66a276c8ce837bfbb70d0a598c8bb29f98dc8c 100644 --- a/src/share/vm/oops/instanceKlass.cpp +++ b/src/share/vm/oops/instanceKlass.cpp @@ -2170,7 +2170,11 @@ void InstanceKlass::clean_implementors_list(BoolObjectClosure* is_alive) { if (impl != NULL) { if (!impl->is_loader_alive(is_alive)) { // remove this guy - *adr_implementor() = NULL; + Klass** klass = adr_implementor(); + assert(klass != NULL, "null klass"); + if (klass != NULL) { + *klass = NULL; + } } } } @@ -3151,9 +3155,10 @@ void InstanceKlass::verify_on(outputStream* st) { if (protection_domain() != NULL) { guarantee(protection_domain()->is_oop(), "should be oop"); } - if (host_klass() != NULL) { - guarantee(host_klass()->is_metadata(), "should be in metaspace"); - guarantee(host_klass()->is_klass(), "should be klass"); + const Klass* host = host_klass(); + if (host != NULL) { + guarantee(host->is_metadata(), "should be in metaspace"); + guarantee(host->is_klass(), "should be klass"); } if (signers() != NULL) { guarantee(signers()->is_objArray(), "should be obj array"); diff --git a/src/share/vm/oops/instanceKlass.hpp b/src/share/vm/oops/instanceKlass.hpp index 600cb56465c598fb942e578aeeed6578e8f622d9..ef2f446d14fbee4b8a8517172e7cd1630cc8efb6 100644 --- a/src/share/vm/oops/instanceKlass.hpp +++ b/src/share/vm/oops/instanceKlass.hpp @@ -536,7 +536,9 @@ class InstanceKlass: public Klass { assert(is_anonymous(), "not anonymous"); Klass** addr = (Klass**)adr_host_klass(); assert(addr != NULL, "no reversed space"); - *addr = host; + if (addr != NULL) { + *addr = host; + } } bool is_anonymous() const { return (_misc_flags & _misc_is_anonymous) != 0; @@ -758,7 +760,10 @@ class InstanceKlass: public Klass { void set_implementor(Klass* k) { assert(is_interface(), "not interface"); Klass** addr = adr_implementor(); - *addr = k; + assert(addr != NULL, "null addr"); + if (addr != NULL) { + *addr = k; + } } int nof_implementors() const { diff --git a/src/share/vm/opto/c2_globals.hpp b/src/share/vm/opto/c2_globals.hpp index 43895fc6ed28cd3b2803c2febff97c31e898161e..f01101cd4bbc474d10aa5e6b61b5b8316effa32e 100644 --- a/src/share/vm/opto/c2_globals.hpp +++ b/src/share/vm/opto/c2_globals.hpp @@ -54,6 +54,12 @@ #define C2_FLAGS(develop, develop_pd, product, product_pd, diagnostic, experimental, notproduct) \ \ + develop(bool, StressLCM, false, \ + "Randomize instruction scheduling in LCM") \ + \ + develop(bool, StressGCM, false, \ + "Randomize instruction scheduling in GCM") \ + \ notproduct(intx, CompileZapFirst, 0, \ "If +ZapDeadCompiledLocals, " \ "skip this many before compiling in zap calls") \ diff --git a/src/share/vm/opto/compile.cpp b/src/share/vm/opto/compile.cpp index 4b80483865d340e28eaba4270ef2525dbc233155..568af91f127f0757a75f614675354c95893f2b80 100644 --- a/src/share/vm/opto/compile.cpp +++ b/src/share/vm/opto/compile.cpp @@ -2899,6 +2899,13 @@ void Compile::final_graph_reshaping_impl( Node *n, Final_Reshape_Counts &frc) { } } break; + case Op_MemBarStoreStore: + // Break the link with AllocateNode: it is no longer useful and + // confuses register allocation. + if (n->req() > MemBarNode::Precedent) { + n->set_req(MemBarNode::Precedent, top()); + } + break; default: assert( !n->is_Call(), "" ); assert( !n->is_Mem(), "" ); @@ -3669,3 +3676,38 @@ void Compile::add_expensive_node(Node * n) { n->set_req(0, NULL); } } + +// Auxiliary method to support randomized stressing/fuzzing. +// +// This method can be called the arbitrary number of times, with current count +// as the argument. The logic allows selecting a single candidate from the +// running list of candidates as follows: +// int count = 0; +// Cand* selected = null; +// while(cand = cand->next()) { +// if (randomized_select(++count)) { +// selected = cand; +// } +// } +// +// Including count equalizes the chances any candidate is "selected". +// This is useful when we don't have the complete list of candidates to choose +// from uniformly. In this case, we need to adjust the randomicity of the +// selection, or else we will end up biasing the selection towards the latter +// candidates. +// +// Quick back-envelope calculation shows that for the list of n candidates +// the equal probability for the candidate to persist as "best" can be +// achieved by replacing it with "next" k-th candidate with the probability +// of 1/k. It can be easily shown that by the end of the run, the +// probability for any candidate is converged to 1/n, thus giving the +// uniform distribution among all the candidates. +// +// We don't care about the domain size as long as (RANDOMIZED_DOMAIN / count) is large. +#define RANDOMIZED_DOMAIN_POW 29 +#define RANDOMIZED_DOMAIN (1 << RANDOMIZED_DOMAIN_POW) +#define RANDOMIZED_DOMAIN_MASK ((1 << (RANDOMIZED_DOMAIN_POW + 1)) - 1) +bool Compile::randomized_select(int count) { + assert(count > 0, "only positive"); + return (os::random() & RANDOMIZED_DOMAIN_MASK) < (RANDOMIZED_DOMAIN / count); +} diff --git a/src/share/vm/opto/compile.hpp b/src/share/vm/opto/compile.hpp index 2cb12fa2e09e518f0f0b414f07b4726e4ea58dcb..d951fbf5f94cc6eeed4848bbb80b95034c5fe619 100644 --- a/src/share/vm/opto/compile.hpp +++ b/src/share/vm/opto/compile.hpp @@ -678,6 +678,7 @@ class Compile : public Phase { void record_dead_node(uint idx) { if (_dead_node_list.test_set(idx)) return; _dead_node_count++; } + bool is_dead_node(uint idx) { return _dead_node_list.test(idx) != 0; } uint dead_node_count() { return _dead_node_count; } void reset_dead_node_list() { _dead_node_list.Reset(); _dead_node_count = 0; @@ -1086,6 +1087,9 @@ class Compile : public Phase { // Definitions of pd methods static void pd_compiler2_init(); + + // Auxiliary method for randomized fuzzing/stressing + static bool randomized_select(int count); }; #endif // SHARE_VM_OPTO_COMPILE_HPP diff --git a/src/share/vm/opto/gcm.cpp b/src/share/vm/opto/gcm.cpp index 4fffeeb80d3229d19b47999b10956d7c8d3315d8..811dc5c6c87ea5152ff5f19913a2c72b1e95dca8 100644 --- a/src/share/vm/opto/gcm.cpp +++ b/src/share/vm/opto/gcm.cpp @@ -1046,6 +1046,8 @@ Block* PhaseCFG::hoist_to_cheaper_block(Block* LCA, Block* early, Node* self) { } #endif + int cand_cnt = 0; // number of candidates tried + // Walk up the dominator tree from LCA (Lowest common ancestor) to // the earliest legal location. Capture the least execution frequency. while (LCA != early) { @@ -1071,8 +1073,11 @@ Block* PhaseCFG::hoist_to_cheaper_block(Block* LCA, Block* early, Node* self) { LCA->_pre_order, LCA->_nodes[0]->_idx, start_lat, end_idx, end_lat, LCA_freq); } #endif + cand_cnt++; if (LCA_freq < least_freq || // Better Frequency - ( !in_latency && // No block containing latency + (StressGCM && Compile::randomized_select(cand_cnt)) || // Should be randomly accepted in stress mode + (!StressGCM && // Otherwise, choose with latency + !in_latency && // No block containing latency LCA_freq < least_freq * delta && // No worse frequency target >= end_lat && // within latency range !self->is_iteratively_computed() ) // But don't hoist IV increments @@ -1210,7 +1215,8 @@ void PhaseCFG::schedule_late(VectorSet &visited, Node_List &stack) { } // If there is no opportunity to hoist, then we're done. - bool try_to_hoist = (LCA != early); + // In stress mode, try to hoist even the single operations. + bool try_to_hoist = StressGCM || (LCA != early); // Must clone guys stay next to use; no hoisting allowed. // Also cannot hoist guys that alter memory or are otherwise not diff --git a/src/share/vm/opto/lcm.cpp b/src/share/vm/opto/lcm.cpp index 35006ff23b4b25d22737354268a80388c44f7d68..ddb55d30e623f2a10ace3110c6b901f4ad8cfbf8 100644 --- a/src/share/vm/opto/lcm.cpp +++ b/src/share/vm/opto/lcm.cpp @@ -421,6 +421,7 @@ Node *Block::select(PhaseCFG *cfg, Node_List &worklist, GrowableArray &read uint latency = 0; // Bigger is scheduled first uint score = 0; // Bigger is better int idx = -1; // Index in worklist + int cand_cnt = 0; // Candidate count for( uint i=0; i &read uint n_score = n->req(); // Many inputs get high score to break ties // Keep best latency found - if( choice < n_choice || - ( choice == n_choice && - ( latency < n_latency || - ( latency == n_latency && - ( score < n_score ))))) { + cand_cnt++; + if (choice < n_choice || + (choice == n_choice && + ((StressLCM && Compile::randomized_select(cand_cnt)) || + (!StressLCM && + (latency < n_latency || + (latency == n_latency && + (score < n_score))))))) { choice = n_choice; latency = n_latency; score = n_score; diff --git a/src/share/vm/opto/macro.cpp b/src/share/vm/opto/macro.cpp index 2dde491380ccdcc21d489fbed4acd65c8cea37d6..aeb1b6226be39ab0c36539a876af193442b00aba 100644 --- a/src/share/vm/opto/macro.cpp +++ b/src/share/vm/opto/macro.cpp @@ -1101,12 +1101,6 @@ void PhaseMacroExpand::expand_allocate_common( Node* klass_node = alloc->in(AllocateNode::KlassNode); Node* initial_slow_test = alloc->in(AllocateNode::InitialTest); - Node* storestore = alloc->storestore(); - if (storestore != NULL) { - // Break this link that is no longer useful and confuses register allocation - storestore->set_req(MemBarNode::Precedent, top()); - } - assert(ctrl != NULL, "must have control"); // We need a Region and corresponding Phi's to merge the slow-path and fast-path results. // they will not be used if "always_slow" is set @@ -1324,7 +1318,7 @@ void PhaseMacroExpand::expand_allocate_common( // No InitializeNode or no stores captured by zeroing // elimination. Simply add the MemBarStoreStore after object // initialization. - MemBarNode* mb = MemBarNode::make(C, Op_MemBarStoreStore, Compile::AliasIdxBot, fast_oop_rawmem); + MemBarNode* mb = MemBarNode::make(C, Op_MemBarStoreStore, Compile::AliasIdxBot); transform_later(mb); mb->init_req(TypeFunc::Memory, fast_oop_rawmem); diff --git a/src/share/vm/opto/memnode.cpp b/src/share/vm/opto/memnode.cpp index 8030d7c4d2ec94edd34eab3ec5874c8f5c5b2c85..a4dcdb7c9a89ad56788e5e5d7ac43e6de8b3465f 100644 --- a/src/share/vm/opto/memnode.cpp +++ b/src/share/vm/opto/memnode.cpp @@ -238,7 +238,7 @@ Node *MemNode::Ideal_common(PhaseGVN *phase, bool can_reshape) { return this; ctl = in(MemNode::Control); // Don't bother trying to transform a dead node - if( ctl && ctl->is_top() ) return NodeSentinel; + if (ctl && ctl->is_top()) return NodeSentinel; PhaseIterGVN *igvn = phase->is_IterGVN(); // Wait if control on the worklist. @@ -262,8 +262,8 @@ Node *MemNode::Ideal_common(PhaseGVN *phase, bool can_reshape) { } // Ignore if memory is dead, or self-loop Node *mem = in(MemNode::Memory); - if( phase->type( mem ) == Type::TOP ) return NodeSentinel; // caller will return NULL - assert( mem != this, "dead loop in MemNode::Ideal" ); + if (phase->type( mem ) == Type::TOP) return NodeSentinel; // caller will return NULL + assert(mem != this, "dead loop in MemNode::Ideal"); if (can_reshape && igvn != NULL && igvn->_worklist.member(mem)) { // This memory slice may be dead. @@ -273,12 +273,12 @@ Node *MemNode::Ideal_common(PhaseGVN *phase, bool can_reshape) { } Node *address = in(MemNode::Address); - const Type *t_adr = phase->type( address ); - if( t_adr == Type::TOP ) return NodeSentinel; // caller will return NULL + const Type *t_adr = phase->type(address); + if (t_adr == Type::TOP) return NodeSentinel; // caller will return NULL - if( can_reshape && igvn != NULL && + if (can_reshape && igvn != NULL && (igvn->_worklist.member(address) || - igvn->_worklist.size() > 0 && (phase->type(address) != adr_type())) ) { + igvn->_worklist.size() > 0 && (t_adr != adr_type())) ) { // The address's base and type may change when the address is processed. // Delay this mem node transformation until the address is processed. phase->is_IterGVN()->_worklist.push(this); @@ -288,7 +288,7 @@ Node *MemNode::Ideal_common(PhaseGVN *phase, bool can_reshape) { // Do NOT remove or optimize the next lines: ensure a new alias index // is allocated for an oop pointer type before Escape Analysis. // Note: C++ will not remove it since the call has side effect. - if ( t_adr->isa_oopptr() ) { + if (t_adr->isa_oopptr()) { int alias_idx = phase->C->get_alias_index(t_adr->is_ptr()); } @@ -296,6 +296,26 @@ Node *MemNode::Ideal_common(PhaseGVN *phase, bool can_reshape) { Node* base = NULL; if (address->is_AddP()) base = address->in(AddPNode::Base); + if (base != NULL && phase->type(base)->higher_equal(TypePtr::NULL_PTR) && + !t_adr->isa_rawptr()) { + // Note: raw address has TOP base and top->higher_equal(TypePtr::NULL_PTR) is true. + Compile* C = phase->C; + tty->cr(); + tty->print_cr("===== NULL+offs not RAW address ====="); + if (C->is_dead_node(this->_idx)) tty->print_cr("'this' is dead"); + if ((ctl != NULL) && C->is_dead_node(ctl->_idx)) tty->print_cr("'ctl' is dead"); + if (C->is_dead_node(mem->_idx)) tty->print_cr("'mem' is dead"); + if (C->is_dead_node(address->_idx)) tty->print_cr("'address' is dead"); + if (C->is_dead_node(base->_idx)) tty->print_cr("'base' is dead"); + tty->cr(); + base->dump(1); + tty->cr(); + this->dump(2); + tty->print("this->adr_type(): "); adr_type()->dump(); tty->cr(); + tty->print("phase->type(address): "); t_adr->dump(); tty->cr(); + tty->print("phase->type(base): "); phase->type(address)->dump(); tty->cr(); + tty->cr(); + } assert(base == NULL || t_adr->isa_rawptr() || !phase->type(base)->higher_equal(TypePtr::NULL_PTR), "NULL+offs not RAW address?"); #endif diff --git a/src/share/vm/runtime/frame.cpp b/src/share/vm/runtime/frame.cpp index f20fca0154c8dda9b1b4ecff2a260e395ee12ce9..e1913829702a92af08805568d613d69057d28ccf 100644 --- a/src/share/vm/runtime/frame.cpp +++ b/src/share/vm/runtime/frame.cpp @@ -1070,7 +1070,12 @@ oop frame::retrieve_receiver(RegisterMap* reg_map) { // First consult the ADLC on where it puts parameter 0 for this signature. VMReg reg = SharedRuntime::name_for_receiver(); - oop r = *caller.oopmapreg_to_location(reg, reg_map); + oop* oop_adr = caller.oopmapreg_to_location(reg, reg_map); + if (oop_adr == NULL) { + guarantee(oop_adr != NULL, "bad register save location"); + return NULL; + } + oop r = *oop_adr; assert(Universe::heap()->is_in_or_null(r), err_msg("bad receiver: " INTPTR_FORMAT " (" INTX_FORMAT ")", (intptr_t) r, (intptr_t) r)); return r; }