# HG changeset patch # User kvn # Date 1390940897 28800 # Node ID 45467c53f1788bb13b72be15a298550aade58612 # Parent abec000618bfa0554ee8d93d9b8969e6c2058673# Parent c84312468f5c8c31857ad889383baed5c24d3e51 Merge diff -r abec000618bf -r 45467c53f178 src/cpu/sparc/vm/sparc.ad --- a/src/cpu/sparc/vm/sparc.ad Tue Jan 28 12:25:34 2014 -0800 +++ b/src/cpu/sparc/vm/sparc.ad Tue Jan 28 12:28:17 2014 -0800 @@ -3369,8 +3369,8 @@ interface(CONST_INTER); %} -// Unsigned (positive) Integer Immediate: 13-bit -operand immU13() %{ +// Unsigned Integer Immediate: 12-bit (non-negative that fits in simm13) +operand immU12() %{ predicate((0 <= n->get_int()) && Assembler::is_simm13(n->get_int())); match(ConI); op_cost(0); @@ -3406,6 +3406,17 @@ interface(CONST_INTER); %} +// Int Immediate non-negative +operand immU31() +%{ + predicate(n->get_int() >= 0); + match(ConI); + + op_cost(0); + format %{ %} + interface(CONST_INTER); +%} + // Integer Immediate: 0-bit operand immI0() %{ predicate(n->get_int() == 0); @@ -5734,7 +5745,6 @@ effect(TEMP dst, TEMP tmp); ins_cost(MEMORY_REF_COST + 2*DEFAULT_COST); - size((3+1)*4); // set may use two instructions. format %{ "LDUH $mem,$dst\t! ushort/char & 16-bit mask -> long\n\t" "SET $mask,$tmp\n\t" "AND $dst,$tmp,$dst" %} @@ -5856,13 +5866,13 @@ ins_pipe(iload_mem); %} -// Load Integer with a 13-bit mask into a Long Register -instruct loadI2L_immI13(iRegL dst, memory mem, immI13 mask) %{ +// Load Integer with a 12-bit mask into a Long Register +instruct loadI2L_immU12(iRegL dst, memory mem, immU12 mask) %{ match(Set dst (ConvI2L (AndI (LoadI mem) mask))); ins_cost(MEMORY_REF_COST + DEFAULT_COST); size(2*4); - format %{ "LDUW $mem,$dst\t! int & 13-bit mask -> long\n\t" + format %{ "LDUW $mem,$dst\t! int & 12-bit mask -> long\n\t" "AND $dst,$mask,$dst" %} ins_encode %{ Register Rdst = $dst$$Register; @@ -5872,14 +5882,13 @@ ins_pipe(iload_mem); %} -// Load Integer with a 32-bit mask into a Long Register -instruct loadI2L_immI(iRegL dst, memory mem, immI mask, iRegL tmp) %{ +// Load Integer with a 31-bit mask into a Long Register +instruct loadI2L_immU31(iRegL dst, memory mem, immU31 mask, iRegL tmp) %{ match(Set dst (ConvI2L (AndI (LoadI mem) mask))); effect(TEMP dst, TEMP tmp); ins_cost(MEMORY_REF_COST + 2*DEFAULT_COST); - size((3+1)*4); // set may use two instructions. - format %{ "LDUW $mem,$dst\t! int & 32-bit mask -> long\n\t" + format %{ "LDUW $mem,$dst\t! int & 31-bit mask -> long\n\t" "SET $mask,$tmp\n\t" "AND $dst,$tmp,$dst" %} ins_encode %{ @@ -8976,7 +8985,7 @@ ins_pipe(ialu_cconly_reg_reg); %} -instruct compU_iReg_imm13(flagsRegU icc, iRegI op1, immU13 op2 ) %{ +instruct compU_iReg_imm13(flagsRegU icc, iRegI op1, immU12 op2 ) %{ match(Set icc (CmpU op1 op2)); size(4); diff -r abec000618bf -r 45467c53f178 src/cpu/x86/vm/x86_32.ad --- a/src/cpu/x86/vm/x86_32.ad Tue Jan 28 12:25:34 2014 -0800 +++ b/src/cpu/x86/vm/x86_32.ad Tue Jan 28 12:28:17 2014 -0800 @@ -3897,6 +3897,17 @@ interface(CONST_INTER); %} +// Int Immediate non-negative +operand immU31() +%{ + predicate(n->get_int() >= 0); + match(ConI); + + op_cost(0); + format %{ %} + interface(CONST_INTER); +%} + // Constant for long shifts operand immI_32() %{ predicate( n->get_int() == 32 ); @@ -6127,12 +6138,12 @@ ins_pipe(ialu_reg_mem); %} -// Load Integer with 32-bit mask into Long Register -instruct loadI2L_immI(eRegL dst, memory mem, immI mask, eFlagsReg cr) %{ +// Load Integer with 31-bit mask into Long Register +instruct loadI2L_immU31(eRegL dst, memory mem, immU31 mask, eFlagsReg cr) %{ match(Set dst (ConvI2L (AndI (LoadI mem) mask))); effect(KILL cr); - format %{ "MOV $dst.lo,$mem\t# int & 32-bit mask -> long\n\t" + format %{ "MOV $dst.lo,$mem\t# int & 31-bit mask -> long\n\t" "XOR $dst.hi,$dst.hi\n\t" "AND $dst.lo,$mask" %} ins_encode %{ diff -r abec000618bf -r 45467c53f178 src/cpu/x86/vm/x86_64.ad --- a/src/cpu/x86/vm/x86_64.ad Tue Jan 28 12:25:34 2014 -0800 +++ b/src/cpu/x86/vm/x86_64.ad Tue Jan 28 12:28:17 2014 -0800 @@ -3094,6 +3094,17 @@ interface(CONST_INTER); %} +// Int Immediate non-negative +operand immU31() +%{ + predicate(n->get_int() >= 0); + match(ConI); + + op_cost(0); + format %{ %} + interface(CONST_INTER); +%} + // Constant for long shifts operand immI_32() %{ @@ -5050,12 +5061,12 @@ ins_pipe(ialu_reg_mem); %} -// Load Integer with a 32-bit mask into Long Register -instruct loadI2L_immI(rRegL dst, memory mem, immI mask, rFlagsReg cr) %{ +// Load Integer with a 31-bit mask into Long Register +instruct loadI2L_immU31(rRegL dst, memory mem, immU31 mask, rFlagsReg cr) %{ match(Set dst (ConvI2L (AndI (LoadI mem) mask))); effect(KILL cr); - format %{ "movl $dst, $mem\t# int & 32-bit mask -> long\n\t" + format %{ "movl $dst, $mem\t# int & 31-bit mask -> long\n\t" "andl $dst, $mask" %} ins_encode %{ Register Rdst = $dst$$Register; diff -r abec000618bf -r 45467c53f178 src/share/vm/code/dependencies.cpp --- a/src/share/vm/code/dependencies.cpp Tue Jan 28 12:25:34 2014 -0800 +++ b/src/share/vm/code/dependencies.cpp Tue Jan 28 12:28:17 2014 -0800 @@ -1221,11 +1221,9 @@ // We could also return false if m does not yet appear to be // executed, if the VM version supports this distinction also. + // Default methods are considered "concrete" as well. return !m->is_abstract() && - !InstanceKlass::cast(m->method_holder())->is_interface(); - // TODO: investigate whether default methods should be - // considered as "concrete" in this situation. For now they - // are not. + !m->is_overpass(); // error functions aren't concrete } diff -r abec000618bf -r 45467c53f178 src/share/vm/opto/bytecodeInfo.cpp --- a/src/share/vm/opto/bytecodeInfo.cpp Tue Jan 28 12:25:34 2014 -0800 +++ b/src/share/vm/opto/bytecodeInfo.cpp Tue Jan 28 12:28:17 2014 -0800 @@ -63,34 +63,14 @@ assert(_caller_jvms->same_calls_as(caller_jvms), "consistent JVMS"); assert((caller_tree == NULL ? 0 : caller_tree->stack_depth() + 1) == stack_depth(), "correct (redundant) depth parameter"); assert(caller_bci == this->caller_bci(), "correct (redundant) bci parameter"); - if (UseOldInlining) { - // Update hierarchical counts, count_inline_bcs() and count_inlines() - InlineTree *caller = (InlineTree *)caller_tree; - for( ; caller != NULL; caller = ((InlineTree *)(caller->caller_tree())) ) { - caller->_count_inline_bcs += count_inline_bcs(); - NOT_PRODUCT(caller->_count_inlines++;) - } + // Update hierarchical counts, count_inline_bcs() and count_inlines() + InlineTree *caller = (InlineTree *)caller_tree; + for( ; caller != NULL; caller = ((InlineTree *)(caller->caller_tree())) ) { + caller->_count_inline_bcs += count_inline_bcs(); + NOT_PRODUCT(caller->_count_inlines++;) } } -InlineTree::InlineTree(Compile* c, ciMethod* callee_method, JVMState* caller_jvms, - float site_invoke_ratio, int max_inline_level) : - C(c), - _caller_jvms(caller_jvms), - _caller_tree(NULL), - _method(callee_method), - _site_invoke_ratio(site_invoke_ratio), - _max_inline_level(max_inline_level), - _count_inline_bcs(method()->code_size()), - _msg(NULL) -{ -#ifndef PRODUCT - _count_inlines = 0; - _forced_inline = false; -#endif - assert(!UseOldInlining, "do not use for old stuff"); -} - /** * Return true when EA is ON and a java constructor is called or * a super constructor is called from an inlined java constructor. @@ -161,11 +141,6 @@ return true; } - if (!UseOldInlining) { - set_msg("!UseOldInlining"); - return true; // size and frequency are represented in a new way - } - int default_max_inline_size = C->max_inline_size(); int inline_small_code_size = InlineSmallCode / 4; int max_inline_size = default_max_inline_size; @@ -229,35 +204,6 @@ fail_msg = "don't inline by annotation"; } - if (!UseOldInlining) { - if (fail_msg != NULL) { - *wci_result = *(WarmCallInfo::always_cold()); - set_msg(fail_msg); - return true; - } - - if (callee_method->has_unloaded_classes_in_signature()) { - wci_result->set_profit(wci_result->profit() * 0.1); - } - - // don't inline exception code unless the top method belongs to an - // exception class - if (callee_method->holder()->is_subclass_of(C->env()->Throwable_klass())) { - ciMethod* top_method = jvms->caller() != NULL ? jvms->caller()->of_depth(1)->method() : method(); - if (!top_method->holder()->is_subclass_of(C->env()->Throwable_klass())) { - wci_result->set_profit(wci_result->profit() * 0.1); - } - } - - if (callee_method->has_compiled_code() && - callee_method->instructions_size() > InlineSmallCode) { - wci_result->set_profit(wci_result->profit() * 0.1); - // %%% adjust wci_result->size()? - } - - return false; - } - // one more inlining restriction if (fail_msg == NULL && callee_method->has_unloaded_classes_in_signature()) { fail_msg = "unloaded signature classes"; @@ -360,9 +306,7 @@ int caller_bci, JVMState* jvms, ciCallProfile& profile, WarmCallInfo* wci_result, bool& should_delay) { - // Old algorithm had funny accumulating BC-size counters - if (UseOldInlining && ClipInlining - && (int)count_inline_bcs() >= DesiredMethodLimit) { + if (ClipInlining && (int)count_inline_bcs() >= DesiredMethodLimit) { if (!callee_method->force_inline() || !IncrementalInline) { set_msg("size > DesiredMethodLimit"); return false; @@ -465,8 +409,7 @@ int size = callee_method->code_size_for_inlining(); - if (UseOldInlining && ClipInlining - && (int)count_inline_bcs() + size >= DesiredMethodLimit) { + if (ClipInlining && (int)count_inline_bcs() + size >= DesiredMethodLimit) { if (!callee_method->force_inline() || !IncrementalInline) { set_msg("size > DesiredMethodLimit"); return false; @@ -584,8 +527,7 @@ jvms, profile, &wci, should_delay); #ifndef PRODUCT - if (UseOldInlining && InlineWarmCalls - && (PrintOpto || C->print_inlining())) { + if (InlineWarmCalls && (PrintOpto || C->print_inlining())) { bool cold = wci.is_cold(); bool hot = !cold && wci.is_hot(); bool old_cold = !success; @@ -599,13 +541,12 @@ } } #endif - if (UseOldInlining) { - if (success) { - wci = *(WarmCallInfo::always_hot()); - } else { - wci = *(WarmCallInfo::always_cold()); - } + if (success) { + wci = *(WarmCallInfo::always_hot()); + } else { + wci = *(WarmCallInfo::always_cold()); } + if (!InlineWarmCalls) { if (!wci.is_cold() && !wci.is_hot()) { // Do not inline the warm calls. @@ -619,8 +560,7 @@ set_msg("inline (hot)"); } print_inlining(callee_method, caller_bci, true /* success */); - if (UseOldInlining) - build_inline_tree_for_callee(callee_method, jvms, caller_bci); + build_inline_tree_for_callee(callee_method, jvms, caller_bci); if (InlineWarmCalls && !wci.is_hot()) return new (C) WarmCallInfo(wci); // copy to heap return WarmCallInfo::always_hot(); diff -r abec000618bf -r 45467c53f178 src/share/vm/opto/c2_globals.hpp --- a/src/share/vm/opto/c2_globals.hpp Tue Jan 28 12:25:34 2014 -0800 +++ b/src/share/vm/opto/c2_globals.hpp Tue Jan 28 12:28:17 2014 -0800 @@ -357,9 +357,6 @@ "File to dump ideal graph to. If set overrides the " \ "use of the network") \ \ - product(bool, UseOldInlining, true, \ - "Enable the 1.3 inlining strategy") \ - \ product(bool, UseBimorphicInlining, true, \ "Profiling based inlining for two receivers") \ \ diff -r abec000618bf -r 45467c53f178 src/share/vm/opto/callGenerator.cpp --- a/src/share/vm/opto/callGenerator.cpp Tue Jan 28 12:25:34 2014 -0800 +++ b/src/share/vm/opto/callGenerator.cpp Tue Jan 28 12:28:17 2014 -0800 @@ -722,7 +722,7 @@ Node* m = kit.map()->in(i); Node* n = slow_map->in(i); if (m != n) { - const Type* t = gvn.type(m)->meet(gvn.type(n)); + const Type* t = gvn.type(m)->meet_speculative(gvn.type(n)); Node* phi = PhiNode::make(region, m, t); phi->set_req(2, n); kit.map()->set_req(i, gvn.transform(phi)); @@ -975,7 +975,7 @@ Node* m = kit.map()->in(i); Node* n = slow_map->in(i); if (m != n) { - const Type* t = gvn.type(m)->meet(gvn.type(n)); + const Type* t = gvn.type(m)->meet_speculative(gvn.type(n)); Node* phi = PhiNode::make(region, m, t); phi->set_req(2, n); kit.map()->set_req(i, gvn.transform(phi)); diff -r abec000618bf -r 45467c53f178 src/share/vm/opto/cfgnode.cpp --- a/src/share/vm/opto/cfgnode.cpp Tue Jan 28 12:25:34 2014 -0800 +++ b/src/share/vm/opto/cfgnode.cpp Tue Jan 28 12:28:17 2014 -0800 @@ -951,7 +951,7 @@ if (is_intf != ti_is_intf) { t = _type; break; } } - t = t->meet(ti); + t = t->meet_speculative(ti); } } @@ -968,11 +968,11 @@ // // It is not possible to see Type::BOTTOM values as phi inputs, // because the ciTypeFlow pre-pass produces verifier-quality types. - const Type* ft = t->filter(_type); // Worst case type + const Type* ft = t->filter_speculative(_type); // Worst case type #ifdef ASSERT // The following logic has been moved into TypeOopPtr::filter. - const Type* jt = t->join(_type); + const Type* jt = t->join_speculative(_type); if( jt->empty() ) { // Emptied out??? // Check for evil case of 't' being a class and '_type' expecting an @@ -1757,7 +1757,7 @@ break; } // Accumulate type for resulting Phi - type = type->meet(in(i)->in(AddPNode::Base)->bottom_type()); + type = type->meet_speculative(in(i)->in(AddPNode::Base)->bottom_type()); } Node* base = NULL; if (doit) { diff -r abec000618bf -r 45467c53f178 src/share/vm/opto/chaitin.hpp --- a/src/share/vm/opto/chaitin.hpp Tue Jan 28 12:25:34 2014 -0800 +++ b/src/share/vm/opto/chaitin.hpp Tue Jan 28 12:28:17 2014 -0800 @@ -98,6 +98,12 @@ } // Compute the degree between 2 live ranges int compute_degree( LRG &l ) const; + bool mask_is_nonempty_and_up() const { + return mask().is_UP() && mask_size(); + } + bool is_float_or_vector() const { + return _is_float || _is_vector; + } private: RegMask _mask; // Allowed registers for this LRG @@ -129,6 +135,7 @@ void SUBTRACT( const RegMask &rm ) { _mask.SUBTRACT(rm); debug_only(_msize_valid=0;)} void Clear() { _mask.Clear() ; debug_only(_msize_valid=1); _mask_size = 0; } void Set_All() { _mask.Set_All(); debug_only(_msize_valid=1); _mask_size = RegMask::CHUNK_SIZE; } + void Insert( OptoReg::Name reg ) { _mask.Insert(reg); debug_only(_msize_valid=0;) } void Remove( OptoReg::Name reg ) { _mask.Remove(reg); debug_only(_msize_valid=0;) } void clear_to_pairs() { _mask.clear_to_pairs(); debug_only(_msize_valid=0;) } @@ -483,15 +490,75 @@ // Same as _ifg->add_vector(reg,live) EXCEPT use the RegMask // information to trim the set of interferences. Return the // count of edges added. - void interfere_with_live( uint reg, IndexSet *live ); + void interfere_with_live(uint lid, IndexSet* liveout); +#ifdef ASSERT // Count register pressure for asserts - uint count_int_pressure( IndexSet *liveout ); - uint count_float_pressure( IndexSet *liveout ); + uint count_int_pressure(IndexSet* liveout); + uint count_float_pressure(IndexSet* liveout); +#endif // Build the interference graph using virtual registers only. // Used for aggressive coalescing. void build_ifg_virtual( ); + class Pressure { + public: + // keeps track of the register pressure at the current + // instruction (used when stepping backwards in the block) + uint _current_pressure; + + // keeps track of the instruction index of the first low to high register pressure + // transition (starting from the top) in the block + // if high_pressure_index == 0 then the whole block is high pressure + // if high_pressure_index = b.end_idx() + 1 then the whole block is low pressure + uint _high_pressure_index; + + // stores the highest pressure we find + uint _final_pressure; + + // number of live ranges that constitute high register pressure + const uint _high_pressure_limit; + + // lower the register pressure and look for a low to high pressure + // transition + void lower(LRG& lrg, uint& location) { + _current_pressure -= lrg.reg_pressure(); + if (_current_pressure == _high_pressure_limit) { + _high_pressure_index = location; + if (_current_pressure > _final_pressure) { + _final_pressure = _current_pressure + 1; + } + } + } + + // raise the pressure and store the pressure if it's the biggest + // pressure so far + void raise(LRG &lrg) { + _current_pressure += lrg.reg_pressure(); + if (_current_pressure > _final_pressure) { + _final_pressure = _current_pressure; + } + } + + Pressure(uint high_pressure_index, uint high_pressure_limit) + : _current_pressure(0) + , _high_pressure_index(high_pressure_index) + , _high_pressure_limit(high_pressure_limit) + , _final_pressure(0) {} + }; + + void lower_pressure(Block* b, uint location, LRG& lrg, IndexSet* liveout, Pressure& int_pressure, Pressure& float_pressure); + void raise_pressure(Block* b, LRG& lrg, Pressure& int_pressure, Pressure& float_pressure); + void check_for_high_pressure_transition_at_fatproj(uint& block_reg_pressure, uint location, LRG& lrg, Pressure& pressure, const int op_regtype); + void add_input_to_liveout(Block* b, Node* n, IndexSet* liveout, double cost, Pressure& int_pressure, Pressure& float_pressure); + void compute_initial_block_pressure(Block* b, IndexSet* liveout, Pressure& int_pressure, Pressure& float_pressure, double cost); + bool remove_node_if_not_used(Block* b, uint location, Node* n, uint lid, IndexSet* liveout); + void assign_high_score_to_immediate_copies(Block* b, Node* n, LRG& lrg, uint next_inst, uint last_inst); + void remove_interference_from_copy(Block* b, uint location, uint lid_copy, IndexSet* liveout, double cost, Pressure& int_pressure, Pressure& float_pressure); + void remove_bound_register_from_interfering_live_ranges(LRG& lrg, IndexSet* liveout, uint& must_spill); + void check_for_high_pressure_block(Pressure& pressure); + void adjust_high_pressure_index(Block* b, uint& hrp_index, Pressure& pressure); + // Build the interference graph using physical registers when available. // That is, if 2 live ranges are simultaneously alive but in their // acceptable register sets do not overlap, then they do not interfere. @@ -554,7 +621,7 @@ // Replace the old node with the current live version of that value // and yank the old value if it's dead. int replace_and_yank_if_dead( Node *old, OptoReg::Name nreg, - Block *current_block, Node_List& value, Node_List& regnd ) { + Block *current_block, Node_List& value, Node_List& regnd ) { Node* v = regnd[nreg]; assert(v->outcnt() != 0, "no dead values"); old->replace_by(v); @@ -565,7 +632,7 @@ return yank_if_dead_recurse(old, old, current_block, value, regnd); } int yank_if_dead_recurse(Node *old, Node *orig_old, Block *current_block, - Node_List *value, Node_List *regnd); + Node_List *value, Node_List *regnd); int yank( Node *old, Block *current_block, Node_List *value, Node_List *regnd ); int elide_copy( Node *n, int k, Block *current_block, Node_List &value, Node_List ®nd, bool can_change_regs ); int use_prior_register( Node *copy, uint idx, Node *def, Block *current_block, Node_List &value, Node_List ®nd ); @@ -573,8 +640,8 @@ // If nreg already contains the same constant as val then eliminate it bool eliminate_copy_of_constant(Node* val, Node* n, - Block *current_block, Node_List& value, Node_List ®nd, - OptoReg::Name nreg, OptoReg::Name nreg2); + Block *current_block, Node_List& value, Node_List ®nd, + OptoReg::Name nreg, OptoReg::Name nreg2); // Extend the node to LRG mapping void add_reference( const Node *node, const Node *old_node); diff -r abec000618bf -r 45467c53f178 src/share/vm/opto/compile.cpp --- a/src/share/vm/opto/compile.cpp Tue Jan 28 12:25:34 2014 -0800 +++ b/src/share/vm/opto/compile.cpp Tue Jan 28 12:28:17 2014 -0800 @@ -705,10 +705,7 @@ print_compile_messages(); - if (UseOldInlining || PrintCompilation NOT_PRODUCT( || PrintOpto) ) - _ilt = InlineTree::build_inline_tree_root(); - else - _ilt = NULL; + _ilt = InlineTree::build_inline_tree_root(); // Even if NO memory addresses are used, MergeMem nodes must have at least 1 slice assert(num_alias_types() >= AliasIdxRaw, ""); @@ -3948,16 +3945,18 @@ // which may optimize it out. for (uint next = 0; next < worklist.size(); ++next) { Node *n = worklist.at(next); - if (n->is_Type() && n->as_Type()->type()->isa_oopptr() != NULL && - n->as_Type()->type()->is_oopptr()->speculative() != NULL) { + if (n->is_Type()) { TypeNode* tn = n->as_Type(); - const TypeOopPtr* t = tn->type()->is_oopptr(); - bool in_hash = igvn.hash_delete(n); - assert(in_hash, "node should be in igvn hash table"); - tn->set_type(t->remove_speculative()); - igvn.hash_insert(n); - igvn._worklist.push(n); // give it a chance to go away - modified++; + const Type* t = tn->type(); + const Type* t_no_spec = t->remove_speculative(); + if (t_no_spec != t) { + bool in_hash = igvn.hash_delete(n); + assert(in_hash, "node should be in igvn hash table"); + tn->set_type(t_no_spec); + igvn.hash_insert(n); + igvn._worklist.push(n); // give it a chance to go away + modified++; + } } uint max = n->len(); for( uint i = 0; i < max; ++i ) { @@ -3971,6 +3970,27 @@ if (modified > 0) { igvn.optimize(); } +#ifdef ASSERT + // Verify that after the IGVN is over no speculative type has resurfaced + worklist.clear(); + worklist.push(root()); + for (uint next = 0; next < worklist.size(); ++next) { + Node *n = worklist.at(next); + const Type* t = igvn.type(n); + assert(t == t->remove_speculative(), "no more speculative types"); + if (n->is_Type()) { + t = n->as_Type()->type(); + assert(t == t->remove_speculative(), "no more speculative types"); + } + uint max = n->len(); + for( uint i = 0; i < max; ++i ) { + Node *m = n->in(i); + if (not_a_node(m)) continue; + worklist.push(m); + } + } + igvn.check_no_speculative_types(); +#endif } } diff -r abec000618bf -r 45467c53f178 src/share/vm/opto/connode.cpp --- a/src/share/vm/opto/connode.cpp Tue Jan 28 12:25:34 2014 -0800 +++ b/src/share/vm/opto/connode.cpp Tue Jan 28 12:28:17 2014 -0800 @@ -188,7 +188,7 @@ const Type *CMoveNode::Value( PhaseTransform *phase ) const { if( phase->type(in(Condition)) == Type::TOP ) return Type::TOP; - return phase->type(in(IfFalse))->meet(phase->type(in(IfTrue))); + return phase->type(in(IfFalse))->meet_speculative(phase->type(in(IfTrue))); } //------------------------------make------------------------------------------- @@ -392,14 +392,14 @@ //============================================================================= // If input is already higher or equal to cast type, then this is an identity. Node *ConstraintCastNode::Identity( PhaseTransform *phase ) { - return phase->type(in(1))->higher_equal(_type) ? in(1) : this; + return phase->type(in(1))->higher_equal_speculative(_type) ? in(1) : this; } //------------------------------Value------------------------------------------ // Take 'join' of input and cast-up type const Type *ConstraintCastNode::Value( PhaseTransform *phase ) const { if( in(0) && phase->type(in(0)) == Type::TOP ) return Type::TOP; - const Type* ft = phase->type(in(1))->filter(_type); +const Type* ft = phase->type(in(1))->filter_speculative(_type); #ifdef ASSERT // Previous versions of this function had some special case logic, @@ -409,7 +409,7 @@ { const Type* t1 = phase->type(in(1)); if( t1 == Type::TOP ) assert(ft == Type::TOP, "special case #1"); - const Type* rt = t1->join(_type); + const Type* rt = t1->join_speculative(_type); if (rt->empty()) assert(ft == Type::TOP, "special case #2"); break; } diff -r abec000618bf -r 45467c53f178 src/share/vm/opto/connode.hpp --- a/src/share/vm/opto/connode.hpp Tue Jan 28 12:25:34 2014 -0800 +++ b/src/share/vm/opto/connode.hpp Tue Jan 28 12:28:17 2014 -0800 @@ -36,7 +36,7 @@ // Simple constants class ConNode : public TypeNode { public: - ConNode( const Type *t ) : TypeNode(t,1) { + ConNode( const Type *t ) : TypeNode(t->remove_speculative(),1) { init_req(0, (Node*)Compile::current()->root()); init_flags(Flag_is_Con); } diff -r abec000618bf -r 45467c53f178 src/share/vm/opto/doCall.cpp --- a/src/share/vm/opto/doCall.cpp Tue Jan 28 12:25:34 2014 -0800 +++ b/src/share/vm/opto/doCall.cpp Tue Jan 28 12:28:17 2014 -0800 @@ -161,19 +161,8 @@ // Try inlining a bytecoded method: if (!call_does_dispatch) { - InlineTree* ilt; - if (UseOldInlining) { - ilt = InlineTree::find_subtree_from_root(this->ilt(), jvms->caller(), jvms->method()); - } else { - // Make a disembodied, stateless ILT. - // TO DO: When UseOldInlining is removed, copy the ILT code elsewhere. - float site_invoke_ratio = prof_factor; - // Note: ilt is for the root of this parse, not the present call site. - ilt = new InlineTree(this, jvms->method(), jvms->caller(), site_invoke_ratio, MaxInlineLevel); - } + InlineTree* ilt = InlineTree::find_subtree_from_root(this->ilt(), jvms->caller(), jvms->method()); WarmCallInfo scratch_ci; - if (!UseOldInlining) - scratch_ci.init(jvms, callee, profile, prof_factor); bool should_delay = false; WarmCallInfo* ci = ilt->ok_to_inline(callee, jvms, profile, &scratch_ci, should_delay); assert(ci != &scratch_ci, "do not let this pointer escape"); diff -r abec000618bf -r 45467c53f178 src/share/vm/opto/graphKit.cpp --- a/src/share/vm/opto/graphKit.cpp Tue Jan 28 12:25:34 2014 -0800 +++ b/src/share/vm/opto/graphKit.cpp Tue Jan 28 12:28:17 2014 -0800 @@ -420,7 +420,7 @@ } const Type* srctype = _gvn.type(src); if (phi->type() != srctype) { - const Type* dsttype = phi->type()->meet(srctype); + const Type* dsttype = phi->type()->meet_speculative(srctype); if (phi->type() != dsttype) { phi->set_type(dsttype); _gvn.set_type(phi, dsttype); @@ -1224,7 +1224,7 @@ // See if mixing in the NULL pointer changes type. // If so, then the NULL pointer was not allowed in the original // type. In other words, "value" was not-null. - if (t->meet(TypePtr::NULL_PTR) != t) { + if (t->meet(TypePtr::NULL_PTR) != t->remove_speculative()) { // same as: if (!TypePtr::NULL_PTR->higher_equal(t)) ... explicit_null_checks_elided++; return value; // Elided null check quickly! @@ -1357,7 +1357,7 @@ // Cast obj to not-null on this path Node* GraphKit::cast_not_null(Node* obj, bool do_replace_in_map) { const Type *t = _gvn.type(obj); - const Type *t_not_null = t->join(TypePtr::NOTNULL); + const Type *t_not_null = t->join_speculative(TypePtr::NOTNULL); // Object is already not-null? if( t == t_not_null ) return obj; @@ -3014,7 +3014,7 @@ if (failure_control != NULL) // failure is now impossible (*failure_control) = top(); // adjust the type of the phi to the exact klass: - phi->raise_bottom_type(_gvn.type(cast_obj)->meet(TypePtr::NULL_PTR)); + phi->raise_bottom_type(_gvn.type(cast_obj)->meet_speculative(TypePtr::NULL_PTR)); } } diff -r abec000618bf -r 45467c53f178 src/share/vm/opto/ifg.cpp --- a/src/share/vm/opto/ifg.cpp Tue Jan 28 12:25:34 2014 -0800 +++ b/src/share/vm/opto/ifg.cpp Tue Jan 28 12:28:17 2014 -0800 @@ -281,20 +281,23 @@ } #endif -// Interfere this register with everything currently live. Use the RegMasks -// to trim the set of possible interferences. Return a count of register-only -// interferences as an estimate of register pressure. -void PhaseChaitin::interfere_with_live( uint r, IndexSet *liveout ) { - uint retval = 0; - // Interfere with everything live. - const RegMask &rm = lrgs(r).mask(); - // Check for interference by checking overlap of regmasks. - // Only interfere if acceptable register masks overlap. +/* + * Interfere this register with everything currently live. + * Check for interference by checking overlap of regmasks. + * Only interfere if acceptable register masks overlap. + */ +void PhaseChaitin::interfere_with_live(uint lid, IndexSet* liveout) { + LRG& lrg = lrgs(lid); + const RegMask& rm = lrg.mask(); IndexSetIterator elements(liveout); - uint l; - while( (l = elements.next()) != 0 ) - if( rm.overlap( lrgs(l).mask() ) ) - _ifg->add_edge( r, l ); + uint interfering_lid = elements.next(); + while (interfering_lid != 0) { + LRG& interfering_lrg = lrgs(interfering_lid); + if (rm.overlap(interfering_lrg.mask())) { + _ifg->add_edge(lid, interfering_lid); + } + interfering_lid = elements.next(); + } } // Actually build the interference graph. Uses virtual registers only, no @@ -333,7 +336,7 @@ // Copies do not define a new value and so do not interfere. // Remove the copies source from the liveout set before interfering. uint idx = n->is_Copy(); - if (idx) { + if (idx != 0) { liveout->remove(_lrg_map.live_range_id(n->in(idx))); } @@ -389,418 +392,465 @@ } // End of forall blocks } -uint PhaseChaitin::count_int_pressure( IndexSet *liveout ) { +#ifdef ASSERT +uint PhaseChaitin::count_int_pressure(IndexSet* liveout) { IndexSetIterator elements(liveout); - uint lidx; + uint lidx = elements.next(); uint cnt = 0; - while ((lidx = elements.next()) != 0) { - if( lrgs(lidx).mask().is_UP() && - lrgs(lidx).mask_size() && - !lrgs(lidx)._is_float && - !lrgs(lidx)._is_vector && - lrgs(lidx).mask().overlap(*Matcher::idealreg2regmask[Op_RegI]) ) - cnt += lrgs(lidx).reg_pressure(); + while (lidx != 0) { + LRG& lrg = lrgs(lidx); + if (lrg.mask_is_nonempty_and_up() && + !lrg.is_float_or_vector() && + lrg.mask().overlap(*Matcher::idealreg2regmask[Op_RegI])) { + cnt += lrg.reg_pressure(); + } + lidx = elements.next(); } return cnt; } -uint PhaseChaitin::count_float_pressure( IndexSet *liveout ) { +uint PhaseChaitin::count_float_pressure(IndexSet* liveout) { IndexSetIterator elements(liveout); - uint lidx; + uint lidx = elements.next(); uint cnt = 0; - while ((lidx = elements.next()) != 0) { - if( lrgs(lidx).mask().is_UP() && - lrgs(lidx).mask_size() && - (lrgs(lidx)._is_float || lrgs(lidx)._is_vector)) - cnt += lrgs(lidx).reg_pressure(); + while (lidx != 0) { + LRG& lrg = lrgs(lidx); + if (lrg.mask_is_nonempty_and_up() && lrg.is_float_or_vector()) { + cnt += lrg.reg_pressure(); + } + lidx = elements.next(); } return cnt; } +#endif -// Adjust register pressure down by 1. Capture last hi-to-low transition, -static void lower_pressure( LRG *lrg, uint where, Block *b, uint *pressure, uint *hrp_index ) { - if (lrg->mask().is_UP() && lrg->mask_size()) { - if (lrg->_is_float || lrg->_is_vector) { - pressure[1] -= lrg->reg_pressure(); - if( pressure[1] == (uint)FLOATPRESSURE ) { - hrp_index[1] = where; - if( pressure[1] > b->_freg_pressure ) - b->_freg_pressure = pressure[1]+1; +/* + * Adjust register pressure down by 1. Capture last hi-to-low transition, + */ +void PhaseChaitin::lower_pressure(Block* b, uint location, LRG& lrg, IndexSet* liveout, Pressure& int_pressure, Pressure& float_pressure) { + if (lrg.mask_is_nonempty_and_up()) { + if (lrg.is_float_or_vector()) { + float_pressure.lower(lrg, location); + } else { + // Do not count the SP and flag registers + const RegMask& r = lrg.mask(); + if (r.overlap(*Matcher::idealreg2regmask[Op_RegI])) { + int_pressure.lower(lrg, location); } - } else if( lrg->mask().overlap(*Matcher::idealreg2regmask[Op_RegI]) ) { - pressure[0] -= lrg->reg_pressure(); - if( pressure[0] == (uint)INTPRESSURE ) { - hrp_index[0] = where; - if( pressure[0] > b->_reg_pressure ) - b->_reg_pressure = pressure[0]+1; + } + } + assert(int_pressure._current_pressure == count_int_pressure(liveout), "the int pressure is incorrect"); + assert(float_pressure._current_pressure == count_float_pressure(liveout), "the float pressure is incorrect"); +} + +/* Go to the first non-phi index in a block */ +static uint first_nonphi_index(Block* b) { + uint i; + uint end_idx = b->end_idx(); + for (i = 1; i < end_idx; i++) { + Node* n = b->get_node(i); + if (!n->is_Phi()) { + break; + } + } + return i; +} + +/* + * Spills could be inserted before a CreateEx node which should be the first + * instruction in a block after Phi nodes. If so, move the CreateEx node up. + */ +static void move_exception_node_up(Block* b, uint first_inst, uint last_inst) { + for (uint i = first_inst; i < last_inst; i++) { + Node* ex = b->get_node(i); + if (ex->is_SpillCopy()) { + continue; + } + + if (i > first_inst && + ex->is_Mach() && ex->as_Mach()->ideal_Opcode() == Op_CreateEx) { + b->remove_node(i); + b->insert_node(ex, first_inst); + } + // Stop once a CreateEx or any other node is found + break; + } +} + +/* + * When new live ranges are live, we raise the register pressure + */ +void PhaseChaitin::raise_pressure(Block* b, LRG& lrg, Pressure& int_pressure, Pressure& float_pressure) { + if (lrg.mask_is_nonempty_and_up()) { + if (lrg.is_float_or_vector()) { + float_pressure.raise(lrg); + } else { + // Do not count the SP and flag registers + const RegMask& rm = lrg.mask(); + if (rm.overlap(*Matcher::idealreg2regmask[Op_RegI])) { + int_pressure.raise(lrg); } } } } -// Build the interference graph using physical registers when available. -// That is, if 2 live ranges are simultaneously alive but in their acceptable -// register sets do not overlap, then they do not interfere. -uint PhaseChaitin::build_ifg_physical( ResourceArea *a ) { - NOT_PRODUCT( Compile::TracePhase t3("buildIFG", &_t_buildIFGphysical, TimeCompiler); ) + +/* + * Computes the initial register pressure of a block, looking at all live + * ranges in the liveout. The register pressure is computed for both float + * and int/pointer registers. + * Live ranges in the liveout are presumed live for the whole block. + * We add the cost for the whole block to the area of the live ranges initially. + * If a live range gets killed in the block, we'll subtract the unused part of + * the block from the area. + */ +void PhaseChaitin::compute_initial_block_pressure(Block* b, IndexSet* liveout, Pressure& int_pressure, Pressure& float_pressure, double cost) { + IndexSetIterator elements(liveout); + uint lid = elements.next(); + while (lid != 0) { + LRG& lrg = lrgs(lid); + lrg._area += cost; + raise_pressure(b, lrg, int_pressure, float_pressure); + lid = elements.next(); + } + assert(int_pressure._current_pressure == count_int_pressure(liveout), "the int pressure is incorrect"); + assert(float_pressure._current_pressure == count_float_pressure(liveout), "the float pressure is incorrect"); +} - uint must_spill = 0; +/* + * Remove dead node if it's not used. + * We only remove projection nodes if the node "defining" the projection is + * dead, for example on x86, if we have a dead Add node we remove its + * RFLAGS node. + */ +bool PhaseChaitin::remove_node_if_not_used(Block* b, uint location, Node* n, uint lid, IndexSet* liveout) { + Node* def = n->in(0); + if (!n->is_Proj() || + (_lrg_map.live_range_id(def) && !liveout->member(_lrg_map.live_range_id(def)))) { + b->remove_node(location); + LRG& lrg = lrgs(lid); + if (lrg._def == n) { + lrg._def = 0; + } + n->disconnect_inputs(NULL, C); + _cfg.unmap_node_from_block(n); + n->replace_by(C->top()); + return true; + } + return false; +} + +/* + * When encountering a fat projection, we might go from a low to high to low + * (since the fat proj only lives at this instruction) going backwards in the + * block. If we find a low to high transition, we record it. + */ +void PhaseChaitin::check_for_high_pressure_transition_at_fatproj(uint& block_reg_pressure, uint location, LRG& lrg, Pressure& pressure, const int op_regtype) { + RegMask mask_tmp = lrg.mask(); + mask_tmp.AND(*Matcher::idealreg2regmask[op_regtype]); + // this pressure is only valid at this instruction, i.e. we don't need to lower + // the register pressure since the fat proj was never live before (going backwards) + uint new_pressure = pressure._current_pressure + mask_tmp.Size(); + if (new_pressure > pressure._final_pressure) { + pressure._final_pressure = new_pressure; + } + // if we were at a low pressure and now at the fat proj is at high pressure, record the fat proj location + // as coming from a low to high (to low again) + if (pressure._current_pressure <= pressure._high_pressure_limit && new_pressure > pressure._high_pressure_limit) { + pressure._high_pressure_index = location; + } +} - // For all blocks (in any order) do... - for (uint i = 0; i < _cfg.number_of_blocks(); i++) { - Block* block = _cfg.get_block(i); - // Clone (rather than smash in place) the liveout info, so it is alive - // for the "collect_gc_info" phase later. - IndexSet liveout(_live->live(block)); - uint last_inst = block->end_idx(); - // Compute first nonphi node index - uint first_inst; - for (first_inst = 1; first_inst < last_inst; first_inst++) { - if (!block->get_node(first_inst)->is_Phi()) { - break; +/* + * Insure high score for immediate-use spill copies so they get a color. + * All single-use MachSpillCopy(s) that immediately precede their + * use must color early. If a longer live range steals their + * color, the spill copy will split and may push another spill copy + * further away resulting in an infinite spill-split-retry cycle. + * Assigning a zero area results in a high score() and a good + * location in the simplify list. + */ +void PhaseChaitin::assign_high_score_to_immediate_copies(Block* b, Node* n, LRG& lrg, uint next_inst, uint last_inst) { + if (n->is_SpillCopy() && + lrg.is_singledef() && // A multi defined live range can still split + n->outcnt() == 1 && // and use must be in this block + _cfg.get_block_for_node(n->unique_out()) == b) { + + Node* single_use = n->unique_out(); + assert(b->find_node(single_use) >= next_inst, "Use must be later in block"); + // Use can be earlier in block if it is a Phi, but then I should be a MultiDef + + // Find first non SpillCopy 'm' that follows the current instruction + // (current_inst - 1) is index for current instruction 'n' + Node* m = n; + for (uint i = next_inst; i <= last_inst && m->is_SpillCopy(); ++i) { + m = b->get_node(i); + } + if (m == single_use) { + lrg._area = 0.0; + } + } +} + +/* + * Copies do not define a new value and so do not interfere. + * Remove the copies source from the liveout set before interfering. + */ +void PhaseChaitin::remove_interference_from_copy(Block* b, uint location, uint lid_copy, IndexSet* liveout, double cost, Pressure& int_pressure, Pressure& float_pressure) { + if (liveout->remove(lid_copy)) { + LRG& lrg_copy = lrgs(lid_copy); + lrg_copy._area -= cost; + + // Lower register pressure since copy and definition can share the same register + lower_pressure(b, location, lrg_copy, liveout, int_pressure, float_pressure); + } +} + +/* + * The defined value must go in a particular register. Remove that register from + * all conflicting parties and avoid the interference. + */ +void PhaseChaitin::remove_bound_register_from_interfering_live_ranges(LRG& lrg, IndexSet* liveout, uint& must_spill) { + // Check for common case + const RegMask& rm = lrg.mask(); + int r_size = lrg.num_regs(); + // Smear odd bits + IndexSetIterator elements(liveout); + uint l = elements.next(); + while (l != 0) { + LRG& interfering_lrg = lrgs(l); + // If 'l' must spill already, do not further hack his bits. + // He'll get some interferences and be forced to spill later. + if (interfering_lrg._must_spill) { + l = elements.next(); + continue; + } + + // Remove bound register(s) from 'l's choices + RegMask old = interfering_lrg.mask(); + uint old_size = interfering_lrg.mask_size(); + + // Remove the bits from LRG 'rm' from LRG 'l' so 'l' no + // longer interferes with 'rm'. If 'l' requires aligned + // adjacent pairs, subtract out bit pairs. + assert(!interfering_lrg._is_vector || !interfering_lrg._fat_proj, "sanity"); + + if (interfering_lrg.num_regs() > 1 && !interfering_lrg._fat_proj) { + RegMask r2mask = rm; + // Leave only aligned set of bits. + r2mask.smear_to_sets(interfering_lrg.num_regs()); + // It includes vector case. + interfering_lrg.SUBTRACT(r2mask); + interfering_lrg.compute_set_mask_size(); + } else if (r_size != 1) { + // fat proj + interfering_lrg.SUBTRACT(rm); + interfering_lrg.compute_set_mask_size(); + } else { + // Common case: size 1 bound removal + OptoReg::Name r_reg = rm.find_first_elem(); + if (interfering_lrg.mask().Member(r_reg)) { + interfering_lrg.Remove(r_reg); + interfering_lrg.set_mask_size(interfering_lrg.mask().is_AllStack() ? LRG::AllStack_size : old_size - 1); } } - // Spills could be inserted before CreateEx node which should be - // first instruction in block after Phis. Move CreateEx up. - for (uint insidx = first_inst; insidx < last_inst; insidx++) { - Node *ex = block->get_node(insidx); - if (ex->is_SpillCopy()) { - continue; - } - if (insidx > first_inst && ex->is_Mach() && ex->as_Mach()->ideal_Opcode() == Op_CreateEx) { - // If the CreateEx isn't above all the MachSpillCopies - // then move it to the top. - block->remove_node(insidx); - block->insert_node(ex, first_inst); - } - // Stop once a CreateEx or any other node is found - break; + // If 'l' goes completely dry, it must spill. + if (interfering_lrg.not_free()) { + // Give 'l' some kind of reasonable mask, so it picks up + // interferences (and will spill later). + interfering_lrg.set_mask(old); + interfering_lrg.set_mask_size(old_size); + must_spill++; + interfering_lrg._must_spill = 1; + interfering_lrg.set_reg(OptoReg::Name(LRG::SPILL_REG)); + } + l = elements.next(); + } +} + +/* + * Start loop at 1 (skip control edge) for most Nodes. SCMemProj's might be the + * sole use of a StoreLConditional. While StoreLConditionals set memory (the + * SCMemProj use) they also def flags; if that flag def is unused the allocator + * sees a flag-setting instruction with no use of the flags and assumes it's + * dead. This keeps the (useless) flag-setting behavior alive while also + * keeping the (useful) memory update effect. + */ +void PhaseChaitin::add_input_to_liveout(Block* b, Node* n, IndexSet* liveout, double cost, Pressure& int_pressure, Pressure& float_pressure) { + JVMState* jvms = n->jvms(); + uint debug_start = jvms ? jvms->debug_start() : 999999; + + for (uint k = ((n->Opcode() == Op_SCMemProj) ? 0:1); k < n->req(); k++) { + Node* def = n->in(k); + uint lid = _lrg_map.live_range_id(def); + if (!lid) { + continue; + } + LRG& lrg = lrgs(lid); + + // No use-side cost for spilling debug info + if (k < debug_start) { + // A USE costs twice block frequency (once for the Load, once + // for a Load-delay). Rematerialized uses only cost once. + lrg._cost += (def->rematerialize() ? b->_freq : (b->_freq * 2)); } - // Reset block's register pressure values for each ifg construction - uint pressure[2], hrp_index[2]; - pressure[0] = pressure[1] = 0; - hrp_index[0] = hrp_index[1] = last_inst+1; - block->_reg_pressure = block->_freg_pressure = 0; - // Liveout things are presumed live for the whole block. We accumulate - // 'area' accordingly. If they get killed in the block, we'll subtract - // the unused part of the block from the area. + if (liveout->insert(lid)) { + // Newly live things assumed live from here to top of block + lrg._area += cost; + raise_pressure(b, lrg, int_pressure, float_pressure); + assert(int_pressure._current_pressure == count_int_pressure(liveout), "the int pressure is incorrect"); + assert(float_pressure._current_pressure == count_float_pressure(liveout), "the float pressure is incorrect"); + } + assert(!(lrg._area < 0.0), "negative spill area" ); + } +} + +/* + * If we run off the top of the block with high pressure just record that the + * whole block is high pressure. (Even though we might have a transition + * lower down in the block) + */ +void PhaseChaitin::check_for_high_pressure_block(Pressure& pressure) { + // current pressure now means the pressure before the first instruction in the block + // (since we have stepped through all instructions backwards) + if (pressure._current_pressure > pressure._high_pressure_limit) { + pressure._high_pressure_index = 0; + } +} + +/* + * Compute high pressure indice; avoid landing in the middle of projnodes + * and set the high pressure index for the block + */ +void PhaseChaitin::adjust_high_pressure_index(Block* b, uint& block_hrp_index, Pressure& pressure) { + uint i = pressure._high_pressure_index; + if (i < b->number_of_nodes() && i < b->end_idx() + 1) { + Node* cur = b->get_node(i); + while (cur->is_Proj() || (cur->is_MachNullCheck()) || cur->is_Catch()) { + cur = b->get_node(--i); + } + } + block_hrp_index = i; +} + +/* Build an interference graph: + * That is, if 2 live ranges are simultaneously alive but in their acceptable + * register sets do not overlap, then they do not interfere. The IFG is built + * by a single reverse pass over each basic block. Starting with the known + * live-out set, we remove things that get defined and add things that become + * live (essentially executing one pass of a standard LIVE analysis). Just + * before a Node defines a value (and removes it from the live-ness set) that + * value is certainly live. The defined value interferes with everything + * currently live. The value is then removed from the live-ness set and it's + * inputs are added to the live-ness set. + * Compute register pressure for each block: + * We store the biggest register pressure for each block and also the first + * low to high register pressure transition within the block (if any). + */ +uint PhaseChaitin::build_ifg_physical( ResourceArea *a ) { + NOT_PRODUCT(Compile::TracePhase t3("buildIFG", &_t_buildIFGphysical, TimeCompiler);) + + uint must_spill = 0; + for (uint i = 0; i < _cfg.number_of_blocks(); i++) { + Block* block = _cfg.get_block(i); + + // Clone (rather than smash in place) the liveout info, so it is alive + // for the "collect_gc_info" phase later. + IndexSet liveout(_live->live(block)); + + uint first_inst = first_nonphi_index(block); + uint last_inst = block->end_idx(); + + move_exception_node_up(block, first_inst, last_inst); + + Pressure int_pressure(last_inst + 1, INTPRESSURE); + Pressure float_pressure(last_inst + 1, FLOATPRESSURE); + block->_reg_pressure = 0; + block->_freg_pressure = 0; + int inst_count = last_inst - first_inst; double cost = (inst_count <= 0) ? 0.0 : block->_freq * double(inst_count); assert(!(cost < 0.0), "negative spill cost" ); - IndexSetIterator elements(&liveout); - uint lidx; - while ((lidx = elements.next()) != 0) { - LRG &lrg = lrgs(lidx); - lrg._area += cost; - // Compute initial register pressure - if (lrg.mask().is_UP() && lrg.mask_size()) { - if (lrg._is_float || lrg._is_vector) { // Count float pressure - pressure[1] += lrg.reg_pressure(); - if (pressure[1] > block->_freg_pressure) { - block->_freg_pressure = pressure[1]; - } - // Count int pressure, but do not count the SP, flags - } else if(lrgs(lidx).mask().overlap(*Matcher::idealreg2regmask[Op_RegI])) { - pressure[0] += lrg.reg_pressure(); - if (pressure[0] > block->_reg_pressure) { - block->_reg_pressure = pressure[0]; - } - } - } - } - assert( pressure[0] == count_int_pressure (&liveout), "" ); - assert( pressure[1] == count_float_pressure(&liveout), "" ); + + compute_initial_block_pressure(block, &liveout, int_pressure, float_pressure, cost); - // The IFG is built by a single reverse pass over each basic block. - // Starting with the known live-out set, we remove things that get - // defined and add things that become live (essentially executing one - // pass of a standard LIVE analysis). Just before a Node defines a value - // (and removes it from the live-ness set) that value is certainly live. - // The defined value interferes with everything currently live. The - // value is then removed from the live-ness set and it's inputs are added - // to the live-ness set. - uint j; - for (j = last_inst + 1; j > 1; j--) { - Node* n = block->get_node(j - 1); + for (uint location = last_inst; location > 0; location--) { + Node* n = block->get_node(location); + uint lid = _lrg_map.live_range_id(n); - // Get value being defined - uint r = _lrg_map.live_range_id(n); + if(lid) { + LRG& lrg = lrgs(lid); - // Some special values do not allocate - if(r) { // A DEF normally costs block frequency; rematerialized values are // removed from the DEF sight, so LOWER costs here. - lrgs(r)._cost += n->rematerialize() ? 0 : block->_freq; + lrg._cost += n->rematerialize() ? 0 : block->_freq; - // If it is not live, then this instruction is dead. Probably caused - // by spilling and rematerialization. Who cares why, yank this baby. - if( !liveout.member(r) && n->Opcode() != Op_SafePoint ) { - Node *def = n->in(0); - if( !n->is_Proj() || - // Could also be a flags-projection of a dead ADD or such. - (_lrg_map.live_range_id(def) && !liveout.member(_lrg_map.live_range_id(def)))) { - block->remove_node(j - 1); - if (lrgs(r)._def == n) { - lrgs(r)._def = 0; - } - n->disconnect_inputs(NULL, C); - _cfg.unmap_node_from_block(n); - n->replace_by(C->top()); - // Since yanking a Node from block, high pressure moves up one - hrp_index[0]--; - hrp_index[1]--; + if (!liveout.member(lid) && n->Opcode() != Op_SafePoint) { + if (remove_node_if_not_used(block, location, n, lid, &liveout)) { + float_pressure._high_pressure_index--; + int_pressure._high_pressure_index--; continue; } - - // Fat-projections kill many registers which cannot be used to - // hold live ranges. - if (lrgs(r)._fat_proj) { - // Count the int-only registers - RegMask itmp = lrgs(r).mask(); - itmp.AND(*Matcher::idealreg2regmask[Op_RegI]); - int iregs = itmp.Size(); - if (pressure[0]+iregs > block->_reg_pressure) { - block->_reg_pressure = pressure[0] + iregs; - } - if (pressure[0] <= (uint)INTPRESSURE && pressure[0] + iregs > (uint)INTPRESSURE) { - hrp_index[0] = j - 1; - } - // Count the float-only registers - RegMask ftmp = lrgs(r).mask(); - ftmp.AND(*Matcher::idealreg2regmask[Op_RegD]); - int fregs = ftmp.Size(); - if (pressure[1] + fregs > block->_freg_pressure) { - block->_freg_pressure = pressure[1] + fregs; - } - if(pressure[1] <= (uint)FLOATPRESSURE && pressure[1]+fregs > (uint)FLOATPRESSURE) { - hrp_index[1] = j - 1; - } + if (lrg._fat_proj) { + check_for_high_pressure_transition_at_fatproj(block->_reg_pressure, location, lrg, int_pressure, Op_RegI); + check_for_high_pressure_transition_at_fatproj(block->_freg_pressure, location, lrg, float_pressure, Op_RegD); } - - } else { // Else it is live - // A DEF also ends 'area' partway through the block. - lrgs(r)._area -= cost; - assert(!(lrgs(r)._area < 0.0), "negative spill area" ); + } else { + // A live range ends at its definition, remove the remaining area. + lrg._area -= cost; + assert(lrg._area >= 0.0, "negative spill area" ); - // Insure high score for immediate-use spill copies so they get a color - if( n->is_SpillCopy() - && lrgs(r).is_singledef() // MultiDef live range can still split - && n->outcnt() == 1 // and use must be in this block - && _cfg.get_block_for_node(n->unique_out()) == block) { - // All single-use MachSpillCopy(s) that immediately precede their - // use must color early. If a longer live range steals their - // color, the spill copy will split and may push another spill copy - // further away resulting in an infinite spill-split-retry cycle. - // Assigning a zero area results in a high score() and a good - // location in the simplify list. - // - - Node *single_use = n->unique_out(); - assert(block->find_node(single_use) >= j, "Use must be later in block"); - // Use can be earlier in block if it is a Phi, but then I should be a MultiDef - - // Find first non SpillCopy 'm' that follows the current instruction - // (j - 1) is index for current instruction 'n' - Node *m = n; - for (uint i = j; i <= last_inst && m->is_SpillCopy(); ++i) { - m = block->get_node(i); - } - if (m == single_use) { - lrgs(r)._area = 0.0; - } - } - - // Remove from live-out set - if( liveout.remove(r) ) { - // Adjust register pressure. - // Capture last hi-to-lo pressure transition - lower_pressure(&lrgs(r), j - 1, block, pressure, hrp_index); - assert( pressure[0] == count_int_pressure (&liveout), "" ); - assert( pressure[1] == count_float_pressure(&liveout), "" ); - } + assign_high_score_to_immediate_copies(block, n, lrg, location + 1, last_inst); - // Copies do not define a new value and so do not interfere. - // Remove the copies source from the liveout set before interfering. - uint idx = n->is_Copy(); - if (idx) { - uint x = _lrg_map.live_range_id(n->in(idx)); - if (liveout.remove(x)) { - lrgs(x)._area -= cost; - // Adjust register pressure. - lower_pressure(&lrgs(x), j - 1, block, pressure, hrp_index); - assert( pressure[0] == count_int_pressure (&liveout), "" ); - assert( pressure[1] == count_float_pressure(&liveout), "" ); - } + if (liveout.remove(lid)) { + lower_pressure(block, location, lrg, &liveout, int_pressure, float_pressure); } - } // End of if live or not - - // Interfere with everything live. If the defined value must - // go in a particular register, just remove that register from - // all conflicting parties and avoid the interference. + uint copy_idx = n->is_Copy(); + if (copy_idx) { + uint lid_copy = _lrg_map.live_range_id(n->in(copy_idx)); + remove_interference_from_copy(block, location, lid_copy, &liveout, cost, int_pressure, float_pressure); + } + } - // Make exclusions for rematerializable defs. Since rematerializable - // DEFs are not bound but the live range is, some uses must be bound. - // If we spill live range 'r', it can rematerialize at each use site - // according to its bindings. - const RegMask &rmask = lrgs(r).mask(); - if( lrgs(r).is_bound() && !(n->rematerialize()) && rmask.is_NotEmpty() ) { - // Check for common case - int r_size = lrgs(r).num_regs(); - OptoReg::Name r_reg = (r_size == 1) ? rmask.find_first_elem() : OptoReg::Physical; - // Smear odd bits - IndexSetIterator elements(&liveout); - uint l; - while ((l = elements.next()) != 0) { - LRG &lrg = lrgs(l); - // If 'l' must spill already, do not further hack his bits. - // He'll get some interferences and be forced to spill later. - if( lrg._must_spill ) continue; - // Remove bound register(s) from 'l's choices - RegMask old = lrg.mask(); - uint old_size = lrg.mask_size(); - // Remove the bits from LRG 'r' from LRG 'l' so 'l' no - // longer interferes with 'r'. If 'l' requires aligned - // adjacent pairs, subtract out bit pairs. - assert(!lrg._is_vector || !lrg._fat_proj, "sanity"); - if (lrg.num_regs() > 1 && !lrg._fat_proj) { - RegMask r2mask = rmask; - // Leave only aligned set of bits. - r2mask.smear_to_sets(lrg.num_regs()); - // It includes vector case. - lrg.SUBTRACT( r2mask ); - lrg.compute_set_mask_size(); - } else if( r_size != 1 ) { // fat proj - lrg.SUBTRACT( rmask ); - lrg.compute_set_mask_size(); - } else { // Common case: size 1 bound removal - if( lrg.mask().Member(r_reg) ) { - lrg.Remove(r_reg); - lrg.set_mask_size(lrg.mask().is_AllStack() ? LRG::AllStack_size : old_size - 1); - } - } - // If 'l' goes completely dry, it must spill. - if( lrg.not_free() ) { - // Give 'l' some kind of reasonable mask, so he picks up - // interferences (and will spill later). - lrg.set_mask( old ); - lrg.set_mask_size(old_size); - must_spill++; - lrg._must_spill = 1; - lrg.set_reg(OptoReg::Name(LRG::SPILL_REG)); - } - } - } // End of if bound - - // Now interference with everything that is live and has - // compatible register sets. - interfere_with_live(r,&liveout); - - } // End of if normal register-allocated value + // Since rematerializable DEFs are not bound but the live range is, + // some uses must be bound. If we spill live range 'r', it can + // rematerialize at each use site according to its bindings. + if (lrg.is_bound() && !n->rematerialize() && lrg.mask().is_NotEmpty()) { + remove_bound_register_from_interfering_live_ranges(lrg, &liveout, must_spill); + } + interfere_with_live(lid, &liveout); + } // Area remaining in the block inst_count--; cost = (inst_count <= 0) ? 0.0 : block->_freq * double(inst_count); - // Make all inputs live - if( !n->is_Phi() ) { // Phi function uses come from prior block - JVMState* jvms = n->jvms(); - uint debug_start = jvms ? jvms->debug_start() : 999999; - // Start loop at 1 (skip control edge) for most Nodes. - // SCMemProj's might be the sole use of a StoreLConditional. - // While StoreLConditionals set memory (the SCMemProj use) - // they also def flags; if that flag def is unused the - // allocator sees a flag-setting instruction with no use of - // the flags and assumes it's dead. This keeps the (useless) - // flag-setting behavior alive while also keeping the (useful) - // memory update effect. - for (uint k = ((n->Opcode() == Op_SCMemProj) ? 0:1); k < n->req(); k++) { - Node *def = n->in(k); - uint x = _lrg_map.live_range_id(def); - if (!x) { - continue; - } - LRG &lrg = lrgs(x); - // No use-side cost for spilling debug info - if (k < debug_start) { - // A USE costs twice block frequency (once for the Load, once - // for a Load-delay). Rematerialized uses only cost once. - lrg._cost += (def->rematerialize() ? block->_freq : (block->_freq + block->_freq)); - } - // It is live now - if (liveout.insert(x)) { - // Newly live things assumed live from here to top of block - lrg._area += cost; - // Adjust register pressure - if (lrg.mask().is_UP() && lrg.mask_size()) { - if (lrg._is_float || lrg._is_vector) { - pressure[1] += lrg.reg_pressure(); - if (pressure[1] > block->_freg_pressure) { - block->_freg_pressure = pressure[1]; - } - } else if( lrg.mask().overlap(*Matcher::idealreg2regmask[Op_RegI]) ) { - pressure[0] += lrg.reg_pressure(); - if (pressure[0] > block->_reg_pressure) { - block->_reg_pressure = pressure[0]; - } - } - } - assert( pressure[0] == count_int_pressure (&liveout), "" ); - assert( pressure[1] == count_float_pressure(&liveout), "" ); - } - assert(!(lrg._area < 0.0), "negative spill area" ); - } - } - } // End of reverse pass over all instructions in block - - // If we run off the top of the block with high pressure and - // never see a hi-to-low pressure transition, just record that - // the whole block is high pressure. - if (pressure[0] > (uint)INTPRESSURE) { - hrp_index[0] = 0; - if (pressure[0] > block->_reg_pressure) { - block->_reg_pressure = pressure[0]; - } - } - if (pressure[1] > (uint)FLOATPRESSURE) { - hrp_index[1] = 0; - if (pressure[1] > block->_freg_pressure) { - block->_freg_pressure = pressure[1]; + if (!n->is_Phi()) { + add_input_to_liveout(block, n, &liveout, cost, int_pressure, float_pressure); } } - // Compute high pressure indice; avoid landing in the middle of projnodes - j = hrp_index[0]; - if (j < block->number_of_nodes() && j < block->end_idx() + 1) { - Node* cur = block->get_node(j); - while (cur->is_Proj() || (cur->is_MachNullCheck()) || cur->is_Catch()) { - j--; - cur = block->get_node(j); - } - } - block->_ihrp_index = j; - j = hrp_index[1]; - if (j < block->number_of_nodes() && j < block->end_idx() + 1) { - Node* cur = block->get_node(j); - while (cur->is_Proj() || (cur->is_MachNullCheck()) || cur->is_Catch()) { - j--; - cur = block->get_node(j); - } - } - block->_fhrp_index = j; + check_for_high_pressure_block(int_pressure); + check_for_high_pressure_block(float_pressure); + adjust_high_pressure_index(block, block->_ihrp_index, int_pressure); + adjust_high_pressure_index(block, block->_fhrp_index, float_pressure); + // set the final_pressure as the register pressure for the block + block->_reg_pressure = int_pressure._final_pressure; + block->_freg_pressure = float_pressure._final_pressure; #ifndef PRODUCT // Gather Register Pressure Statistics - if( PrintOptoStatistics ) { - if (block->_reg_pressure > (uint)INTPRESSURE || block->_freg_pressure > (uint)FLOATPRESSURE) { + if (PrintOptoStatistics) { + if (block->_reg_pressure > int_pressure._high_pressure_limit || block->_freg_pressure > float_pressure._high_pressure_limit) { _high_pressure++; } else { _low_pressure++; } } #endif - } // End of for all blocks + } return must_spill; } diff -r abec000618bf -r 45467c53f178 src/share/vm/opto/loopopts.cpp --- a/src/share/vm/opto/loopopts.cpp Tue Jan 28 12:25:34 2014 -0800 +++ b/src/share/vm/opto/loopopts.cpp Tue Jan 28 12:28:17 2014 -0800 @@ -1115,8 +1115,8 @@ Node *n2 = phi->in(i)->in(1)->in(2); phi1->set_req( i, n1 ); phi2->set_req( i, n2 ); - phi1->set_type( phi1->type()->meet(n1->bottom_type()) ); - phi2->set_type( phi2->type()->meet(n2->bottom_type()) ); + phi1->set_type( phi1->type()->meet_speculative(n1->bottom_type())); + phi2->set_type( phi2->type()->meet_speculative(n2->bottom_type())); } // See if these Phis have been made before. // Register with optimizer @@ -1189,8 +1189,8 @@ } phi1->set_req( j, n1 ); phi2->set_req( j, n2 ); - phi1->set_type( phi1->type()->meet(n1->bottom_type()) ); - phi2->set_type( phi2->type()->meet(n2->bottom_type()) ); + phi1->set_type(phi1->type()->meet_speculative(n1->bottom_type())); + phi2->set_type(phi2->type()->meet_speculative(n2->bottom_type())); } // See if these Phis have been made before. diff -r abec000618bf -r 45467c53f178 src/share/vm/opto/memnode.cpp --- a/src/share/vm/opto/memnode.cpp Tue Jan 28 12:25:34 2014 -0800 +++ b/src/share/vm/opto/memnode.cpp Tue Jan 28 12:28:17 2014 -0800 @@ -657,7 +657,7 @@ // disregarding "null"-ness. // (We make an exception for TypeRawPtr::BOTTOM, which is a bit bucket.) const TypePtr* tp_notnull = tp->join(TypePtr::NOTNULL)->is_ptr(); - assert(cross_check->meet(tp_notnull) == cross_check, + assert(cross_check->meet(tp_notnull) == cross_check->remove_speculative(), "real address must not escape from expected memory type"); } #endif @@ -1685,7 +1685,7 @@ // t might actually be lower than _type, if _type is a unique // concrete subclass of abstract class t. if (off_beyond_header) { // is the offset beyond the header? - const Type* jt = t->join(_type); + const Type* jt = t->join_speculative(_type); // In any case, do not allow the join, per se, to empty out the type. if (jt->empty() && !t->empty()) { // This can happen if a interface-typed array narrows to a class type. diff -r abec000618bf -r 45467c53f178 src/share/vm/opto/multnode.cpp --- a/src/share/vm/opto/multnode.cpp Tue Jan 28 12:25:34 2014 -0800 +++ b/src/share/vm/opto/multnode.cpp Tue Jan 28 12:28:17 2014 -0800 @@ -94,7 +94,7 @@ if ((_con == TypeFunc::Parms) && n->is_CallStaticJava() && n->as_CallStaticJava()->is_boxing_method()) { // The result of autoboxing is always non-null on normal path. - t = t->join(TypePtr::NOTNULL); + t = t->join_speculative(TypePtr::NOTNULL); } return t; } diff -r abec000618bf -r 45467c53f178 src/share/vm/opto/node.cpp --- a/src/share/vm/opto/node.cpp Tue Jan 28 12:25:34 2014 -0800 +++ b/src/share/vm/opto/node.cpp Tue Jan 28 12:28:17 2014 -0800 @@ -995,13 +995,13 @@ if (is_Type()) { TypeNode *n = this->as_Type(); if (VerifyAliases) { - assert(new_type->higher_equal(n->type()), "new type must refine old type"); + assert(new_type->higher_equal_speculative(n->type()), "new type must refine old type"); } n->set_type(new_type); } else if (is_Load()) { LoadNode *n = this->as_Load(); if (VerifyAliases) { - assert(new_type->higher_equal(n->type()), "new type must refine old type"); + assert(new_type->higher_equal_speculative(n->type()), "new type must refine old type"); } n->set_type(new_type); } diff -r abec000618bf -r 45467c53f178 src/share/vm/opto/parse1.cpp --- a/src/share/vm/opto/parse1.cpp Tue Jan 28 12:25:34 2014 -0800 +++ b/src/share/vm/opto/parse1.cpp Tue Jan 28 12:28:17 2014 -0800 @@ -1656,7 +1656,7 @@ assert(bt1 != Type::BOTTOM, "should not be building conflict phis"); map()->set_req(j, _gvn.transform_no_reclaim(phi)); debug_only(const Type* bt2 = phi->bottom_type()); - assert(bt2->higher_equal(bt1), "must be consistent with type-flow"); + assert(bt2->higher_equal_speculative(bt1), "must be consistent with type-flow"); record_for_igvn(phi); } } @@ -2029,7 +2029,7 @@ !tp->klass()->is_interface()) { // sharpen the type eagerly; this eases certain assert checking if (tp->higher_equal(TypeInstPtr::NOTNULL)) - tr = tr->join(TypeInstPtr::NOTNULL)->is_instptr(); + tr = tr->join_speculative(TypeInstPtr::NOTNULL)->is_instptr(); value = _gvn.transform(new (C) CheckCastPPNode(0,value,tr)); } } diff -r abec000618bf -r 45467c53f178 src/share/vm/opto/parse2.cpp --- a/src/share/vm/opto/parse2.cpp Tue Jan 28 12:25:34 2014 -0800 +++ b/src/share/vm/opto/parse2.cpp Tue Jan 28 12:28:17 2014 -0800 @@ -88,7 +88,7 @@ if (toop->klass()->as_instance_klass()->unique_concrete_subklass()) { // If we load from "AbstractClass[]" we must see "ConcreteSubClass". const Type* subklass = Type::get_const_type(toop->klass()); - elemtype = subklass->join(el); + elemtype = subklass->join_speculative(el); } } } @@ -1278,7 +1278,7 @@ // Bool(CmpP(LoadKlass(obj._klass), ConP(Foo.klass)), [eq]) // or the narrowOop equivalent. const Type* obj_type = _gvn.type(obj); - const TypeOopPtr* tboth = obj_type->join(con_type)->isa_oopptr(); + const TypeOopPtr* tboth = obj_type->join_speculative(con_type)->isa_oopptr(); if (tboth != NULL && tboth->klass_is_exact() && tboth != obj_type && tboth->higher_equal(obj_type)) { // obj has to be of the exact type Foo if the CmpP succeeds. @@ -1288,7 +1288,7 @@ (jvms->is_loc(obj_in_map) || jvms->is_stk(obj_in_map))) { TypeNode* ccast = new (C) CheckCastPPNode(control(), obj, tboth); const Type* tcc = ccast->as_Type()->type(); - assert(tcc != obj_type && tcc->higher_equal(obj_type), "must improve"); + assert(tcc != obj_type && tcc->higher_equal_speculative(obj_type), "must improve"); // Delay transform() call to allow recovery of pre-cast value // at the control merge. _gvn.set_type_bottom(ccast); @@ -1318,7 +1318,7 @@ switch (btest) { case BoolTest::eq: // Constant test? { - const Type* tboth = tcon->join(tval); + const Type* tboth = tcon->join_speculative(tval); if (tboth == tval) break; // Nothing to gain. if (tcon->isa_int()) { ccast = new (C) CastIINode(val, tboth); @@ -1352,7 +1352,7 @@ if (ccast != NULL) { const Type* tcc = ccast->as_Type()->type(); - assert(tcc != tval && tcc->higher_equal(tval), "must improve"); + assert(tcc != tval && tcc->higher_equal_speculative(tval), "must improve"); // Delay transform() call to allow recovery of pre-cast value // at the control merge. ccast->set_req(0, control()); diff -r abec000618bf -r 45467c53f178 src/share/vm/opto/parse3.cpp --- a/src/share/vm/opto/parse3.cpp Tue Jan 28 12:25:34 2014 -0800 +++ b/src/share/vm/opto/parse3.cpp Tue Jan 28 12:28:17 2014 -0800 @@ -361,7 +361,7 @@ // should_be_constant = (oop not scavengable || ScavengeRootsInCode >= 2) // An oop is not scavengable if it is in the perm gen. if (stable_type != NULL && con_type != NULL && con_type->isa_oopptr()) - con_type = con_type->join(stable_type); + con_type = con_type->join_speculative(stable_type); break; case T_ILLEGAL: diff -r abec000618bf -r 45467c53f178 src/share/vm/opto/phaseX.cpp --- a/src/share/vm/opto/phaseX.cpp Tue Jan 28 12:25:34 2014 -0800 +++ b/src/share/vm/opto/phaseX.cpp Tue Jan 28 12:28:17 2014 -0800 @@ -323,6 +323,23 @@ } } + +void NodeHash::check_no_speculative_types() { +#ifdef ASSERT + uint max = size(); + Node *sentinel_node = sentinel(); + for (uint i = 0; i < max; ++i) { + Node *n = at(i); + if(n != NULL && n != sentinel_node && n->is_Type()) { + TypeNode* tn = n->as_Type(); + const Type* t = tn->type(); + const Type* t_no_spec = t->remove_speculative(); + assert(t == t_no_spec, "dead node in hash table or missed node during speculative cleanup"); + } + } +#endif +} + #ifndef PRODUCT //------------------------------dump------------------------------------------- // Dump statistics for the hash table @@ -1392,11 +1409,11 @@ assert(UseTypeSpeculation, "speculation is off"); for (uint i = 0; i < _types.Size(); i++) { const Type* t = _types.fast_lookup(i); - if (t != NULL && t->isa_oopptr()) { - const TypeOopPtr* to = t->is_oopptr(); - _types.map(i, to->remove_speculative()); + if (t != NULL) { + _types.map(i, t->remove_speculative()); } } + _table.check_no_speculative_types(); } //============================================================================= diff -r abec000618bf -r 45467c53f178 src/share/vm/opto/phaseX.hpp --- a/src/share/vm/opto/phaseX.hpp Tue Jan 28 12:25:34 2014 -0800 +++ b/src/share/vm/opto/phaseX.hpp Tue Jan 28 12:28:17 2014 -0800 @@ -92,7 +92,8 @@ } void remove_useless_nodes(VectorSet &useful); // replace with sentinel - void replace_with(NodeHash* nh); + void replace_with(NodeHash* nh); + void check_no_speculative_types(); // Check no speculative part for type nodes in table Node *sentinel() { return _sentinel; } @@ -501,6 +502,9 @@ Deoptimization::DeoptReason reason); void remove_speculative_types(); + void check_no_speculative_types() { + _table.check_no_speculative_types(); + } #ifndef PRODUCT protected: diff -r abec000618bf -r 45467c53f178 src/share/vm/opto/type.cpp --- a/src/share/vm/opto/type.cpp Tue Jan 28 12:25:34 2014 -0800 +++ b/src/share/vm/opto/type.cpp Tue Jan 28 12:28:17 2014 -0800 @@ -241,6 +241,13 @@ return !t1->eq(t2); // Return ZERO if equal } +const Type* Type::maybe_remove_speculative(bool include_speculative) const { + if (!include_speculative) { + return remove_speculative(); + } + return this; +} + //------------------------------hash------------------------------------------- int Type::uhash( const Type *const t ) { return t->hash(); @@ -633,41 +640,44 @@ //------------------------------meet------------------------------------------- // Compute the MEET of two types. NOT virtual. It enforces that meet is // commutative and the lattice is symmetric. -const Type *Type::meet( const Type *t ) const { +const Type *Type::meet_helper(const Type *t, bool include_speculative) const { if (isa_narrowoop() && t->isa_narrowoop()) { - const Type* result = make_ptr()->meet(t->make_ptr()); + const Type* result = make_ptr()->meet_helper(t->make_ptr(), include_speculative); return result->make_narrowoop(); } if (isa_narrowklass() && t->isa_narrowklass()) { - const Type* result = make_ptr()->meet(t->make_ptr()); + const Type* result = make_ptr()->meet_helper(t->make_ptr(), include_speculative); return result->make_narrowklass(); } - const Type *mt = xmeet(t); + const Type *this_t = maybe_remove_speculative(include_speculative); + t = t->maybe_remove_speculative(include_speculative); + + const Type *mt = this_t->xmeet(t); if (isa_narrowoop() || t->isa_narrowoop()) return mt; if (isa_narrowklass() || t->isa_narrowklass()) return mt; #ifdef ASSERT - assert( mt == t->xmeet(this), "meet not commutative" ); + assert(mt == t->xmeet(this_t), "meet not commutative"); const Type* dual_join = mt->_dual; const Type *t2t = dual_join->xmeet(t->_dual); - const Type *t2this = dual_join->xmeet( _dual); + const Type *t2this = dual_join->xmeet(this_t->_dual); // Interface meet Oop is Not Symmetric: // Interface:AnyNull meet Oop:AnyNull == Interface:AnyNull // Interface:NotNull meet Oop:NotNull == java/lang/Object:NotNull - if( !interface_vs_oop(t) && (t2t != t->_dual || t2this != _dual) ) { + if( !interface_vs_oop(t) && (t2t != t->_dual || t2this != this_t->_dual) ) { tty->print_cr("=== Meet Not Symmetric ==="); - tty->print("t = "); t->dump(); tty->cr(); - tty->print("this= "); dump(); tty->cr(); - tty->print("mt=(t meet this)= "); mt->dump(); tty->cr(); - - tty->print("t_dual= "); t->_dual->dump(); tty->cr(); - tty->print("this_dual= "); _dual->dump(); tty->cr(); - tty->print("mt_dual= "); mt->_dual->dump(); tty->cr(); - - tty->print("mt_dual meet t_dual= "); t2t ->dump(); tty->cr(); - tty->print("mt_dual meet this_dual= "); t2this ->dump(); tty->cr(); + tty->print("t = "); t->dump(); tty->cr(); + tty->print("this= "); this_t->dump(); tty->cr(); + tty->print("mt=(t meet this)= "); mt->dump(); tty->cr(); + + tty->print("t_dual= "); t->_dual->dump(); tty->cr(); + tty->print("this_dual= "); this_t->_dual->dump(); tty->cr(); + tty->print("mt_dual= "); mt->_dual->dump(); tty->cr(); + + tty->print("mt_dual meet t_dual= "); t2t ->dump(); tty->cr(); + tty->print("mt_dual meet this_dual= "); t2this ->dump(); tty->cr(); fatal("meet not symmetric" ); } @@ -759,8 +769,8 @@ } //-----------------------------filter------------------------------------------ -const Type *Type::filter( const Type *kills ) const { - const Type* ft = join(kills); +const Type *Type::filter_helper(const Type *kills, bool include_speculative) const { + const Type* ft = join_helper(kills, include_speculative); if (ft->empty()) return Type::TOP; // Canonical empty value return ft; @@ -1314,8 +1324,8 @@ } //-----------------------------filter------------------------------------------ -const Type *TypeInt::filter( const Type *kills ) const { - const TypeInt* ft = join(kills)->isa_int(); +const Type *TypeInt::filter_helper(const Type *kills, bool include_speculative) const { + const TypeInt* ft = join_helper(kills, include_speculative)->isa_int(); if (ft == NULL || ft->empty()) return Type::TOP; // Canonical empty value if (ft->_widen < this->_widen) { @@ -1575,8 +1585,8 @@ } //-----------------------------filter------------------------------------------ -const Type *TypeLong::filter( const Type *kills ) const { - const TypeLong* ft = join(kills)->isa_long(); +const Type *TypeLong::filter_helper(const Type *kills, bool include_speculative) const { + const TypeLong* ft = join_helper(kills, include_speculative)->isa_long(); if (ft == NULL || ft->empty()) return Type::TOP; // Canonical empty value if (ft->_widen < this->_widen) { @@ -1731,7 +1741,7 @@ total_fields++; field_array = fields(total_fields); // Use get_const_type here because it respects UseUniqueSubclasses: - field_array[pos++] = get_const_type(recv)->join(TypePtr::NOTNULL); + field_array[pos++] = get_const_type(recv)->join_speculative(TypePtr::NOTNULL); } else { field_array = fields(total_fields); } @@ -1921,7 +1931,7 @@ case Array: { // Meeting 2 arrays? const TypeAry *a = t->is_ary(); - return TypeAry::make(_elem->meet(a->_elem), + return TypeAry::make(_elem->meet_speculative(a->_elem), _size->xmeet(a->_size)->is_int(), _stable & a->_stable); } @@ -1954,6 +1964,13 @@ return (intptr_t)_elem + (intptr_t)_size + (_stable ? 43 : 0); } +/** + * Return same type without a speculative part in the element + */ +const Type* TypeAry::remove_speculative() const { + return make(_elem->remove_speculative(), _size, _stable); +} + //----------------------interface_vs_oop--------------------------------------- #ifdef ASSERT bool TypeAry::interface_vs_oop(const Type *t) const { @@ -2566,14 +2583,14 @@ return res; } - if (res->isa_oopptr() != NULL) { + const TypeOopPtr* res_oopptr = res->is_oopptr(); + if (res_oopptr->speculative() != NULL) { // type->speculative() == NULL means that speculation is no better // than type, i.e. type->speculative() == type. So there are 2 // ways to represent the fact that we have no useful speculative // data and we should use a single one to be able to test for // equality between types. Check whether type->speculative() == // type and set speculative to NULL if it is the case. - const TypeOopPtr* res_oopptr = res->is_oopptr(); if (res_oopptr->remove_speculative() == res_oopptr->speculative()) { return res_oopptr->remove_speculative(); } @@ -2639,7 +2656,7 @@ case OopPtr: { // Meeting to other OopPtrs const TypeOopPtr *tp = t->is_oopptr(); int instance_id = meet_instance_id(tp->instance_id()); - const TypeOopPtr* speculative = meet_speculative(tp); + const TypeOopPtr* speculative = xmeet_speculative(tp); return make(meet_ptr(tp->ptr()), meet_offset(tp->offset()), instance_id, speculative); } @@ -2793,9 +2810,9 @@ //-----------------------------filter------------------------------------------ // Do not allow interface-vs.-noninterface joins to collapse to top. -const Type *TypeOopPtr::filter(const Type *kills) const { - - const Type* ft = join(kills); +const Type *TypeOopPtr::filter_helper(const Type *kills, bool include_speculative) const { + + const Type* ft = join_helper(kills, include_speculative); const TypeInstPtr* ftip = ft->isa_instptr(); const TypeInstPtr* ktip = kills->isa_instptr(); @@ -2907,7 +2924,10 @@ /** * Return same type without a speculative part */ -const TypeOopPtr* TypeOopPtr::remove_speculative() const { +const Type* TypeOopPtr::remove_speculative() const { + if (_speculative == NULL) { + return this; + } return make(_ptr, _offset, _instance_id, NULL); } @@ -2933,7 +2953,7 @@ * * @param other type to meet with */ -const TypeOopPtr* TypeOopPtr::meet_speculative(const TypeOopPtr* other) const { +const TypeOopPtr* TypeOopPtr::xmeet_speculative(const TypeOopPtr* other) const { bool this_has_spec = (_speculative != NULL); bool other_has_spec = (other->speculative() != NULL); @@ -2958,7 +2978,7 @@ other_spec = other; } - return this_spec->meet(other_spec)->is_oopptr(); + return this_spec->meet_speculative(other_spec)->is_oopptr(); } /** @@ -3117,7 +3137,7 @@ int off = meet_offset(tinst->offset()); PTR ptr = meet_ptr(tinst->ptr()); int instance_id = meet_instance_id(tinst->instance_id()); - const TypeOopPtr* speculative = meet_speculative(tinst); + const TypeOopPtr* speculative = xmeet_speculative(tinst); const TypeInstPtr *loaded = is_loaded() ? this : tinst; const TypeInstPtr *unloaded = is_loaded() ? tinst : this; @@ -3194,7 +3214,7 @@ int offset = meet_offset(tp->offset()); PTR ptr = meet_ptr(tp->ptr()); int instance_id = meet_instance_id(tp->instance_id()); - const TypeOopPtr* speculative = meet_speculative(tp); + const TypeOopPtr* speculative = xmeet_speculative(tp); switch (ptr) { case TopPTR: case AnyNull: // Fall 'down' to dual of object klass @@ -3244,14 +3264,14 @@ case TopPTR: case AnyNull: { int instance_id = meet_instance_id(InstanceTop); - const TypeOopPtr* speculative = meet_speculative(tp); + const TypeOopPtr* speculative = xmeet_speculative(tp); return make(ptr, klass(), klass_is_exact(), (ptr == Constant ? const_oop() : NULL), offset, instance_id, speculative); } case NotNull: case BotPTR: { int instance_id = meet_instance_id(tp->instance_id()); - const TypeOopPtr* speculative = meet_speculative(tp); + const TypeOopPtr* speculative = xmeet_speculative(tp); return TypeOopPtr::make(ptr, offset, instance_id, speculative); } default: typerr(t); @@ -3303,7 +3323,7 @@ int off = meet_offset( tinst->offset() ); PTR ptr = meet_ptr( tinst->ptr() ); int instance_id = meet_instance_id(tinst->instance_id()); - const TypeOopPtr* speculative = meet_speculative(tinst); + const TypeOopPtr* speculative = xmeet_speculative(tinst); // Check for easy case; klasses are equal (and perhaps not loaded!) // If we have constants, then we created oops so classes are loaded @@ -3552,7 +3572,10 @@ return make(_ptr, klass(), klass_is_exact(), const_oop(), xadd_offset(offset), _instance_id, add_offset_speculative(offset)); } -const TypeOopPtr *TypeInstPtr::remove_speculative() const { +const Type *TypeInstPtr::remove_speculative() const { + if (_speculative == NULL) { + return this; + } return make(_ptr, klass(), klass_is_exact(), const_oop(), _offset, _instance_id, NULL); } @@ -3754,14 +3777,14 @@ case TopPTR: case AnyNull: { int instance_id = meet_instance_id(InstanceTop); - const TypeOopPtr* speculative = meet_speculative(tp); + const TypeOopPtr* speculative = xmeet_speculative(tp); return make(ptr, (ptr == Constant ? const_oop() : NULL), _ary, _klass, _klass_is_exact, offset, instance_id, speculative); } case BotPTR: case NotNull: { int instance_id = meet_instance_id(tp->instance_id()); - const TypeOopPtr* speculative = meet_speculative(tp); + const TypeOopPtr* speculative = xmeet_speculative(tp); return TypeOopPtr::make(ptr, offset, instance_id, speculative); } default: ShouldNotReachHere(); @@ -3799,10 +3822,10 @@ case AryPtr: { // Meeting 2 references? const TypeAryPtr *tap = t->is_aryptr(); int off = meet_offset(tap->offset()); - const TypeAry *tary = _ary->meet(tap->_ary)->is_ary(); + const TypeAry *tary = _ary->meet_speculative(tap->_ary)->is_ary(); PTR ptr = meet_ptr(tap->ptr()); int instance_id = meet_instance_id(tap->instance_id()); - const TypeOopPtr* speculative = meet_speculative(tap); + const TypeOopPtr* speculative = xmeet_speculative(tap); ciKlass* lazy_klass = NULL; if (tary->_elem->isa_int()) { // Integral array element types have irrelevant lattice relations. @@ -3882,7 +3905,7 @@ int offset = meet_offset(tp->offset()); PTR ptr = meet_ptr(tp->ptr()); int instance_id = meet_instance_id(tp->instance_id()); - const TypeOopPtr* speculative = meet_speculative(tp); + const TypeOopPtr* speculative = xmeet_speculative(tp); switch (ptr) { case TopPTR: case AnyNull: // Fall 'down' to dual of object klass @@ -3996,8 +4019,8 @@ return make(_ptr, _const_oop, _ary, _klass, _klass_is_exact, xadd_offset(offset), _instance_id, add_offset_speculative(offset)); } -const TypeOopPtr *TypeAryPtr::remove_speculative() const { - return make(_ptr, _const_oop, _ary, _klass, _klass_is_exact, _offset, _instance_id, NULL); +const Type *TypeAryPtr::remove_speculative() const { + return make(_ptr, _const_oop, _ary->remove_speculative()->is_ary(), _klass, _klass_is_exact, _offset, _instance_id, NULL); } //============================================================================= @@ -4037,9 +4060,9 @@ } -const Type *TypeNarrowPtr::filter( const Type *kills ) const { +const Type *TypeNarrowPtr::filter_helper(const Type *kills, bool include_speculative) const { if (isa_same_narrowptr(kills)) { - const Type* ft =_ptrtype->filter(is_same_narrowptr(kills)->_ptrtype); + const Type* ft =_ptrtype->filter_helper(is_same_narrowptr(kills)->_ptrtype, include_speculative); if (ft->empty()) return Type::TOP; // Canonical empty value if (ft->isa_ptr()) { @@ -4047,7 +4070,7 @@ } return ft; } else if (kills->isa_ptr()) { - const Type* ft = _ptrtype->join(kills); + const Type* ft = _ptrtype->join_helper(kills, include_speculative); if (ft->empty()) return Type::TOP; // Canonical empty value return ft; @@ -4177,8 +4200,8 @@ //-----------------------------filter------------------------------------------ // Do not allow interface-vs.-noninterface joins to collapse to top. -const Type *TypeMetadataPtr::filter( const Type *kills ) const { - const TypeMetadataPtr* ft = join(kills)->isa_metadataptr(); +const Type *TypeMetadataPtr::filter_helper(const Type *kills, bool include_speculative) const { + const TypeMetadataPtr* ft = join_helper(kills, include_speculative)->isa_metadataptr(); if (ft == NULL || ft->empty()) return Type::TOP; // Canonical empty value return ft; @@ -4380,10 +4403,10 @@ } // Do not allow interface-vs.-noninterface joins to collapse to top. -const Type *TypeKlassPtr::filter(const Type *kills) const { +const Type *TypeKlassPtr::filter_helper(const Type *kills, bool include_speculative) const { // logic here mirrors the one from TypeOopPtr::filter. See comments // there. - const Type* ft = join(kills); + const Type* ft = join_helper(kills, include_speculative); const TypeKlassPtr* ftkp = ft->isa_klassptr(); const TypeKlassPtr* ktkp = kills->isa_klassptr(); diff -r abec000618bf -r 45467c53f178 src/share/vm/opto/type.hpp --- a/src/share/vm/opto/type.hpp Tue Jan 28 12:25:34 2014 -0800 +++ b/src/share/vm/opto/type.hpp Tue Jan 28 12:28:17 2014 -0800 @@ -164,6 +164,8 @@ virtual bool interface_vs_oop_helper(const Type *t) const; #endif + const Type *meet_helper(const Type *t, bool include_speculative) const; + protected: // Each class of type is also identified by its base. const TYPES _base; // Enum of Types type @@ -171,6 +173,10 @@ Type( TYPES t ) : _dual(NULL), _base(t) {} // Simple types // ~Type(); // Use fast deallocation const Type *hashcons(); // Hash-cons the type + virtual const Type *filter_helper(const Type *kills, bool include_speculative) const; + const Type *join_helper(const Type *t, bool include_speculative) const { + return dual()->meet_helper(t->dual(), include_speculative)->dual(); + } public: @@ -202,10 +208,24 @@ // Test for equivalence of types static int cmp( const Type *const t1, const Type *const t2 ); // Test for higher or equal in lattice - int higher_equal( const Type *t ) const { return !cmp(meet(t),t); } + // Variant that drops the speculative part of the types + int higher_equal(const Type *t) const { + return !cmp(meet(t),t->remove_speculative()); + } + // Variant that keeps the speculative part of the types + int higher_equal_speculative(const Type *t) const { + return !cmp(meet_speculative(t),t); + } // MEET operation; lower in lattice. - const Type *meet( const Type *t ) const; + // Variant that drops the speculative part of the types + const Type *meet(const Type *t) const { + return meet_helper(t, false); + } + // Variant that keeps the speculative part of the types + const Type *meet_speculative(const Type *t) const { + return meet_helper(t, true); + } // WIDEN: 'widens' for Ints and other range types virtual const Type *widen( const Type *old, const Type* limit ) const { return this; } // NARROW: complement for widen, used by pessimistic phases @@ -221,13 +241,26 @@ // JOIN operation; higher in lattice. Done by finding the dual of the // meet of the dual of the 2 inputs. - const Type *join( const Type *t ) const { - return dual()->meet(t->dual())->dual(); } + // Variant that drops the speculative part of the types + const Type *join(const Type *t) const { + return join_helper(t, false); + } + // Variant that keeps the speculative part of the types + const Type *join_speculative(const Type *t) const { + return join_helper(t, true); + } // Modified version of JOIN adapted to the needs Node::Value. // Normalizes all empty values to TOP. Does not kill _widen bits. // Currently, it also works around limitations involving interface types. - virtual const Type *filter( const Type *kills ) const; + // Variant that drops the speculative part of the types + const Type *filter(const Type *kills) const { + return filter_helper(kills, false); + } + // Variant that keeps the speculative part of the types + const Type *filter_speculative(const Type *kills) const { + return filter_helper(kills, true); + } #ifdef ASSERT // One type is interface, the other is oop @@ -383,6 +416,8 @@ // Speculative type. See TypeInstPtr virtual ciKlass* speculative_type() const { return NULL; } + const Type* maybe_remove_speculative(bool include_speculative) const; + virtual const Type* remove_speculative() const { return this; } private: // support arrays @@ -450,12 +485,14 @@ // upper bound, inclusive. class TypeInt : public Type { TypeInt( jint lo, jint hi, int w ); +protected: + virtual const Type *filter_helper(const Type *kills, bool include_speculative) const; + public: virtual bool eq( const Type *t ) const; virtual int hash() const; // Type specific hashing virtual bool singleton(void) const; // TRUE if type is a singleton virtual bool empty(void) const; // TRUE if type is vacuous -public: const jint _lo, _hi; // Lower bound, upper bound const short _widen; // Limit on times we widen this sucker @@ -475,7 +512,6 @@ virtual const Type *widen( const Type *t, const Type* limit_type ) const; virtual const Type *narrow( const Type *t ) const; // Do not kill _widen bits. - virtual const Type *filter( const Type *kills ) const; // Convenience common pre-built types. static const TypeInt *MINUS_1; static const TypeInt *ZERO; @@ -506,6 +542,9 @@ // an upper bound, inclusive. class TypeLong : public Type { TypeLong( jlong lo, jlong hi, int w ); +protected: + // Do not kill _widen bits. + virtual const Type *filter_helper(const Type *kills, bool include_speculative) const; public: virtual bool eq( const Type *t ) const; virtual int hash() const; // Type specific hashing @@ -533,8 +572,6 @@ virtual const Type *xdual() const; // Compute dual right now. virtual const Type *widen( const Type *t, const Type* limit_type ) const; virtual const Type *narrow( const Type *t ) const; - // Do not kill _widen bits. - virtual const Type *filter( const Type *kills ) const; // Convenience common pre-built types. static const TypeLong *MINUS_1; static const TypeLong *ZERO; @@ -625,6 +662,7 @@ virtual const Type *xmeet( const Type *t ) const; virtual const Type *xdual() const; // Compute dual right now. bool ary_must_be_exact() const; // true if arrays of such are never generic + virtual const Type* remove_speculative() const; #ifdef ASSERT // One type is interface, the other is oop virtual bool interface_vs_oop(const Type *t) const; @@ -835,7 +873,7 @@ // utility methods to work on the speculative part of the type const TypeOopPtr* dual_speculative() const; - const TypeOopPtr* meet_speculative(const TypeOopPtr* other) const; + const TypeOopPtr* xmeet_speculative(const TypeOopPtr* other) const; bool eq_speculative(const TypeOopPtr* other) const; int hash_speculative() const; const TypeOopPtr* add_offset_speculative(intptr_t offset) const; @@ -843,6 +881,9 @@ void dump_speculative(outputStream *st) const; #endif + // Do not allow interface-vs.-noninterface joins to collapse to top. + virtual const Type *filter_helper(const Type *kills, bool include_speculative) const; + public: // Creates a type given a klass. Correctly handles multi-dimensional arrays // Respects UseUniqueSubclasses. @@ -898,16 +939,13 @@ virtual const TypePtr *add_offset( intptr_t offset ) const; // Return same type without a speculative part - virtual const TypeOopPtr* remove_speculative() const; + virtual const Type* remove_speculative() const; virtual const Type *xmeet(const Type *t) const; virtual const Type *xdual() const; // Compute dual right now. // the core of the computation of the meet for TypeOopPtr and for its subclasses virtual const Type *xmeet_helper(const Type *t) const; - // Do not allow interface-vs.-noninterface joins to collapse to top. - virtual const Type *filter( const Type *kills ) const; - // Convenience common pre-built type. static const TypeOopPtr *BOTTOM; #ifndef PRODUCT @@ -984,7 +1022,7 @@ virtual const TypePtr *add_offset( intptr_t offset ) const; // Return same type without a speculative part - virtual const TypeOopPtr* remove_speculative() const; + virtual const Type* remove_speculative() const; // the core of the computation of the meet of 2 types virtual const Type *xmeet_helper(const Type *t) const; @@ -1062,7 +1100,7 @@ virtual bool empty(void) const; // TRUE if type is vacuous virtual const TypePtr *add_offset( intptr_t offset ) const; // Return same type without a speculative part - virtual const TypeOopPtr* remove_speculative() const; + virtual const Type* remove_speculative() const; // the core of the computation of the meet of 2 types virtual const Type *xmeet_helper(const Type *t) const; @@ -1103,6 +1141,8 @@ class TypeMetadataPtr : public TypePtr { protected: TypeMetadataPtr(PTR ptr, ciMetadata* metadata, int offset); + // Do not allow interface-vs.-noninterface joins to collapse to top. + virtual const Type *filter_helper(const Type *kills, bool include_speculative) const; public: virtual bool eq( const Type *t ) const; virtual int hash() const; // Type specific hashing @@ -1128,9 +1168,6 @@ virtual intptr_t get_con() const; - // Do not allow interface-vs.-noninterface joins to collapse to top. - virtual const Type *filter( const Type *kills ) const; - // Convenience common pre-built types. static const TypeMetadataPtr *BOTTOM; @@ -1144,6 +1181,8 @@ class TypeKlassPtr : public TypePtr { TypeKlassPtr( PTR ptr, ciKlass* klass, int offset ); +protected: + virtual const Type *filter_helper(const Type *kills, bool include_speculative) const; public: virtual bool eq( const Type *t ) const; virtual int hash() const; // Type specific hashing @@ -1205,9 +1244,6 @@ virtual intptr_t get_con() const; - // Do not allow interface-vs.-noninterface joins to collapse to top. - virtual const Type *filter( const Type *kills ) const; - // Convenience common pre-built types. static const TypeKlassPtr* OBJECT; // Not-null object klass or below static const TypeKlassPtr* OBJECT_OR_NULL; // Maybe-null version of same @@ -1231,6 +1267,8 @@ virtual const TypeNarrowPtr *is_same_narrowptr(const Type *t) const = 0; virtual const TypeNarrowPtr *make_same_narrowptr(const TypePtr *t) const = 0; virtual const TypeNarrowPtr *make_hash_same_narrowptr(const TypePtr *t) const = 0; + // Do not allow interface-vs.-noninterface joins to collapse to top. + virtual const Type *filter_helper(const Type *kills, bool include_speculative) const; public: virtual bool eq( const Type *t ) const; virtual int hash() const; // Type specific hashing @@ -1241,9 +1279,6 @@ virtual intptr_t get_con() const; - // Do not allow interface-vs.-noninterface joins to collapse to top. - virtual const Type *filter( const Type *kills ) const; - virtual bool empty(void) const; // TRUE if type is vacuous // returns the equivalent ptr type for this compressed pointer @@ -1294,6 +1329,10 @@ static const TypeNarrowOop *BOTTOM; static const TypeNarrowOop *NULL_PTR; + virtual const Type* remove_speculative() const { + return make(_ptrtype->remove_speculative()->is_ptr()); + } + #ifndef PRODUCT virtual void dump2( Dict &d, uint depth, outputStream *st ) const; #endif diff -r abec000618bf -r 45467c53f178 src/share/vm/runtime/arguments.cpp --- a/src/share/vm/runtime/arguments.cpp Tue Jan 28 12:25:34 2014 -0800 +++ b/src/share/vm/runtime/arguments.cpp Tue Jan 28 12:28:17 2014 -0800 @@ -293,6 +293,7 @@ { "UsePermISM", JDK_Version::jdk(8), JDK_Version::jdk(9) }, { "UseMPSS", JDK_Version::jdk(8), JDK_Version::jdk(9) }, { "UseStringCache", JDK_Version::jdk(8), JDK_Version::jdk(9) }, + { "UseOldInlining", JDK_Version::jdk(9), JDK_Version::jdk(10) }, #ifdef PRODUCT { "DesiredMethodLimit", JDK_Version::jdk_update(7, 2), JDK_Version::jdk(8) }, diff -r abec000618bf -r 45467c53f178 test/compiler/6826736/Test.java --- a/test/compiler/6826736/Test.java Tue Jan 28 12:25:34 2014 -0800 +++ b/test/compiler/6826736/Test.java Tue Jan 28 12:28:17 2014 -0800 @@ -27,7 +27,7 @@ * @bug 6826736 * @summary CMS: core dump with -XX:+UseCompressedOops * - * @run main/othervm/timeout=600 -XX:+IgnoreUnrecognizedVMOptions -Xbatch -XX:+ScavengeALot -XX:+UseCompressedOops -XX:HeapBaseMinAddress=32g -XX:CompileThreshold=100 -XX:CompileOnly=Test.test -XX:-BlockLayoutRotateLoops -XX:LoopUnrollLimit=0 Test + * @run main/othervm/timeout=600 -XX:+IgnoreUnrecognizedVMOptions -Xbatch -XX:+ScavengeALot -XX:+UseCompressedOops -XX:HeapBaseMinAddress=32g -XX:CompileThreshold=100 -XX:CompileOnly=Test.test -XX:-BlockLayoutRotateLoops -XX:LoopUnrollLimit=0 -Xmx256m -XX:ParallelGCThreads=4 Test */ public class Test { diff -r abec000618bf -r 45467c53f178 test/compiler/codegen/LoadWithMask.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/codegen/LoadWithMask.java Tue Jan 28 12:28:17 2014 -0800 @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2014, 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 8032207 + * @summary Invalid node sizing for loadUS2L_immI16 and loadI2L_immI + * @run main/othervm -server -Xbatch -XX:-TieredCompilation -XX:CompileCommand=compileonly,LoadWithMask.foo LoadWithMask + * + */ +public class LoadWithMask { + static int x[] = new int[1]; + static long foo() { + return x[0] & 0xfff0ffff; + } + + public static void main(String[] args) { + x[0] = -1; + long l = 0; + for (int i = 0; i < 100000; ++i) { + l = foo(); + } + } +} diff -r abec000618bf -r 45467c53f178 test/compiler/codegen/LoadWithMask2.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/codegen/LoadWithMask2.java Tue Jan 28 12:28:17 2014 -0800 @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2014, 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 8031743 + * @summary loadI2L_immI broken for negative memory values + * @run main/othervm -server -Xbatch -XX:-TieredCompilation -XX:CompileCommand=compileonly,*.foo* LoadWithMask2 + * + */ +public class LoadWithMask2 { + static int x; + static long foo1() { + return x & 0xfffffffe; + } + static long foo2() { + return x & 0xff000000; + } + static long foo3() { + return x & 0x8abcdef1; + } + + public static void main(String[] args) { + x = -1; + long l = 0; + for (int i = 0; i < 100000; ++i) { + l = foo1() & foo2() & foo3(); + } + if (l > 0) { + System.out.println("FAILED"); + System.exit(97); + } + System.out.println("PASSED"); + } +} diff -r abec000618bf -r 45467c53f178 test/compiler/inlining/DefaultAndConcreteMethodsCHA.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/inlining/DefaultAndConcreteMethodsCHA.java Tue Jan 28 12:28:17 2014 -0800 @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2014, 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 8031695 + * @summary CHA ignores default methods during analysis leading to incorrect code generation + * + * @run main/othervm -Xbatch DefaultAndConcreteMethodsCHA + */ +interface I { + default int m() { return 0; } +} + +class A implements I {} + +class C extends A { } +class D extends A { public int m() { return 1; } } + +public class DefaultAndConcreteMethodsCHA { + public static int test(A obj) { + return obj.m(); + } + public static void main(String[] args) { + for (int i = 0; i < 10000; i++) { + int idC = test(new C()); + if (idC != 0) { + throw new Error("C.m didn't invoke I.m: id "+idC); + } + + int idD = test(new D()); + if (idD != 1) { + throw new Error("D.m didn't invoke D.m: id "+idD); + } + } + + } +} diff -r abec000618bf -r 45467c53f178 test/compiler/types/TestSpeculationFailedHigherEqual.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/types/TestSpeculationFailedHigherEqual.java Tue Jan 28 12:28:17 2014 -0800 @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2014, 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 8027422 + * @summary type methods shouldn't always operate on speculative part + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:TypeProfileLevel=222 -XX:+UnlockExperimentalVMOptions -XX:+UseTypeSpeculation -XX:-BackgroundCompilation TestSpeculationFailedHigherEqual + * + */ + +public class TestSpeculationFailedHigherEqual { + + static class A { + void m() {} + int i; + } + + static class C extends A { + } + + static C c; + + static A m1(A a, boolean cond) { + // speculative type for a is C not null + if (cond ) { + a = c; + } + // speculative type for a is C (may be null) + int i = a.i; + return a; + } + + static public void main(String[] args) { + C c = new C(); + TestSpeculationFailedHigherEqual.c = c; + for (int i = 0; i < 20000; i++) { + m1(c, i%2 == 0); + } + + System.out.println("TEST PASSED"); + } +}