# HG changeset patch # User andrew # Date 1580953385 0 # Node ID b7f0b616a070dd9dd46d5c3911964335b3105b9e # Parent 08794bf98f9f7619da2bb9142fd08bb1fa1a656a# Parent d92c52b180e485c227faace4bc430a45377e43fb Merge jdk7u251-b02 diff -r 08794bf98f9f -r b7f0b616a070 .hgtags --- a/.hgtags Wed Nov 20 06:36:50 2019 +0000 +++ b/.hgtags Thu Feb 06 01:43:05 2020 +0000 @@ -953,3 +953,7 @@ c6a8482b1d38cb24fada6a4de0038a577f384cb7 jdk7u241-b01 059e07856d09dcb1017565f5a8c21a11c25b88e6 icedtea-2.6.20 8145b03db545c7be2a8243b785d9bf20caae706b icedtea-2.6.21pre00 +c6a8482b1d38cb24fada6a4de0038a577f384cb7 jdk7u241-ga +c6a8482b1d38cb24fada6a4de0038a577f384cb7 jdk7u251-b00 +cea2195191744b01d089f12d0264fc572fb35690 jdk7u251-b01 +69946653069110a57f9d49e40a05147c574966ca jdk7u251-b02 diff -r 08794bf98f9f -r b7f0b616a070 src/share/vm/oops/klassVtable.cpp --- a/src/share/vm/oops/klassVtable.cpp Wed Nov 20 06:36:50 2019 +0000 +++ b/src/share/vm/oops/klassVtable.cpp Thu Feb 06 01:43:05 2020 +0000 @@ -224,21 +224,24 @@ int vtable_index, Handle target_loader, Symbol* target_classname, Thread * THREAD) { instanceKlass* superk = initialsuper; while (superk != NULL && superk->super() != NULL) { - instanceKlass* supersuperklass = instanceKlass::cast(superk->super()); - klassVtable* ssVtable = supersuperklass->vtable(); + klassVtable* ssVtable = instanceKlass::cast((superk->super()))->vtable(); if (vtable_index < ssVtable->length()) { methodOop super_method = ssVtable->method_at(vtable_index); + // get the class holding the matching method + // make sure you use that class for is_override + instanceKlass* supermethodholder = instanceKlass::cast(super_method->method_holder()); #ifndef PRODUCT Symbol* name= target_method()->name(); Symbol* signature = target_method()->signature(); assert(super_method->name() == name && super_method->signature() == signature, "vtable entry name/sig mismatch"); #endif - if (supersuperklass->is_override(super_method, target_loader, target_classname, THREAD)) { + + if (supermethodholder->is_override(super_method, target_loader, target_classname, THREAD)) { #ifndef PRODUCT if (PrintVtables && Verbose) { ResourceMark rm(THREAD); tty->print("transitive overriding superclass %s with %s::%s index %d, original flags: ", - supersuperklass->internal_name(), + supermethodholder->internal_name(), _klass->internal_name(), (target_method() != NULL) ? target_method()->name()->as_C_string() : "", vtable_index); super_method->access_flags().print_on(tty); @@ -456,7 +459,7 @@ // search through the super class hierarchy to see if we need // a new entry - ResourceMark rm; + ResourceMark rm(THREAD); Symbol* name = target_method()->name(); Symbol* signature = target_method()->signature(); klassOop k = super; diff -r 08794bf98f9f -r b7f0b616a070 src/share/vm/opto/compile.cpp --- a/src/share/vm/opto/compile.cpp Wed Nov 20 06:36:50 2019 +0000 +++ b/src/share/vm/opto/compile.cpp Thu Feb 06 01:43:05 2020 +0000 @@ -437,6 +437,13 @@ remove_macro_node(n); } } + // Remove useless CastII nodes with range check dependency + for (int i = range_check_cast_count() - 1; i >= 0; i--) { + Node* cast = range_check_cast_node(i); + if (!useful.member(cast)) { + remove_range_check_cast(cast); + } + } // Remove useless expensive node for (int i = C->expensive_count()-1; i >= 0; i--) { Node* n = C->expensive_node(i); @@ -1171,6 +1178,7 @@ _macro_nodes = new(comp_arena()) GrowableArray(comp_arena(), 8, 0, NULL); _predicate_opaqs = new(comp_arena()) GrowableArray(comp_arena(), 8, 0, NULL); _expensive_nodes = new(comp_arena()) GrowableArray(comp_arena(), 8, 0, NULL); + _range_check_casts = new(comp_arena()) GrowableArray(comp_arena(), 8, 0, NULL); register_library_intrinsics(); } @@ -1881,6 +1889,22 @@ assert(predicate_count()==0, "should be clean!"); } +void Compile::add_range_check_cast(Node* n) { + assert(n->isa_CastII()->has_range_check(), "CastII should have range check dependency"); + assert(!_range_check_casts->contains(n), "duplicate entry in range check casts"); + _range_check_casts->append(n); +} + +// Remove all range check dependent CastIINodes. +void Compile::remove_range_check_casts(PhaseIterGVN &igvn) { + for (int i = range_check_cast_count(); i > 0; i--) { + Node* cast = range_check_cast_node(i-1); + assert(cast->isa_CastII()->has_range_check(), "CastII should have range check dependency"); + igvn.replace_node(cast, cast->in(1)); + } + assert(range_check_cast_count() == 0, "should be empty"); +} + // StringOpts and late inlining of string methods void Compile::inline_string_calls(bool parse_time) { { @@ -2197,6 +2221,12 @@ PhaseIdealLoop::verify(igvn); } + if (range_check_cast_count() > 0) { + // No more loop optimizations. Remove all range check dependent CastIINodes. + C->remove_range_check_casts(igvn); + igvn.optimize(); + } + { NOT_PRODUCT( TracePhase t2("macroExpand", &_t_macroExpand, TimeCompiler); ) PhaseMacroExpand mex(igvn); @@ -2948,6 +2978,16 @@ #endif +#ifdef ASSERT + case Op_CastII: + // Verify that all range check dependent CastII nodes were removed. + if (n->isa_CastII()->has_range_check()) { + n->dump(3); + assert(false, "Range check dependent CastII node was not removed"); + } + break; +#endif + case Op_ModI: if (UseDivMod) { // Check if a%b and a/b both exist @@ -3877,3 +3917,21 @@ n->set_req(0, NULL); } } + +// Convert integer value to a narrowed long type dependent on ctrl (for example, a range check) +Node* Compile::constrained_convI2L(PhaseGVN* phase, Node* value, const TypeInt* itype, Node* ctrl) { + if (ctrl != NULL) { + // Express control dependency by a CastII node with a narrow type. + value = new (phase->C) CastIINode(value, itype, false, true /* range check dependency */); + // Make the CastII node dependent on the control input to prevent the narrowed ConvI2L + // node from floating above the range check during loop optimizations. Otherwise, the + // ConvI2L node may be eliminated independently of the range check, causing the data path + // to become TOP while the control path is still there (although it's unreachable). + value->set_req(0, ctrl); + // Save CastII node to remove it after loop optimizations. + phase->C->add_range_check_cast(value); + value = phase->transform(value); + } + const TypeLong* ltype = TypeLong::make(itype->_lo, itype->_hi, itype->_widen); + return phase->transform(new (phase->C) ConvI2LNode(value, ltype)); +} diff -r 08794bf98f9f -r b7f0b616a070 src/share/vm/opto/compile.hpp --- a/src/share/vm/opto/compile.hpp Wed Nov 20 06:36:50 2019 +0000 +++ b/src/share/vm/opto/compile.hpp Thu Feb 06 01:43:05 2020 +0000 @@ -75,6 +75,7 @@ class SafePointNode; class JVMState; class TypeData; +class TypeInt; class TypePtr; class TypeOopPtr; class TypeFunc; @@ -309,6 +310,7 @@ GrowableArray* _macro_nodes; // List of nodes which need to be expanded before matching. GrowableArray* _predicate_opaqs; // List of Opaque1 nodes for the loop predicates. GrowableArray* _expensive_nodes; // List of nodes that are expensive to compute and that we'd better not let the GVN freely common + GrowableArray* _range_check_casts; // List of CastII nodes with a range check dependency ConnectionGraph* _congraph; #ifndef PRODUCT IdealGraphPrinter* _printer; @@ -627,7 +629,7 @@ void set_congraph(ConnectionGraph* congraph) { _congraph = congraph;} void add_macro_node(Node * n) { //assert(n->is_macro(), "must be a macro node"); - assert(!_macro_nodes->contains(n), " duplicate entry in expand list"); + assert(!_macro_nodes->contains(n), "duplicate entry in expand list"); _macro_nodes->append(n); } void remove_macro_node(Node * n) { @@ -647,10 +649,23 @@ } } void add_predicate_opaq(Node * n) { - assert(!_predicate_opaqs->contains(n), " duplicate entry in predicate opaque1"); + assert(!_predicate_opaqs->contains(n), "duplicate entry in predicate opaque1"); assert(_macro_nodes->contains(n), "should have already been in macro list"); _predicate_opaqs->append(n); } + + // Range check dependent CastII nodes that can be removed after loop optimizations + void add_range_check_cast(Node* n); + void remove_range_check_cast(Node* n) { + if (_range_check_casts->contains(n)) { + _range_check_casts->remove(n); + } + } + Node* range_check_cast_node(int idx) const { return _range_check_casts->at(idx); } + int range_check_cast_count() const { return _range_check_casts->length(); } + // Remove all range check dependent CastIINodes. + void remove_range_check_casts(PhaseIterGVN &igvn); + // remove the opaque nodes that protect the predicates so that the unused checks and // uncommon traps will be eliminated from the graph. void cleanup_loop_predicates(PhaseIterGVN &igvn); @@ -1148,6 +1163,9 @@ // Definitions of pd methods static void pd_compiler2_init(); + + // Convert integer value to a narrowed long type dependent on ctrl (for example, a range check) + static Node* constrained_convI2L(PhaseGVN* phase, Node* value, const TypeInt* itype, Node* ctrl); }; #endif // SHARE_VM_OPTO_COMPILE_HPP diff -r 08794bf98f9f -r b7f0b616a070 src/share/vm/opto/connode.cpp --- a/src/share/vm/opto/connode.cpp Wed Nov 20 06:36:50 2019 +0000 +++ b/src/share/vm/opto/connode.cpp Thu Feb 06 01:43:05 2020 +0000 @@ -444,7 +444,9 @@ } uint CastIINode::cmp(const Node &n) const { - return TypeNode::cmp(n) && ((CastIINode&)n)._carry_dependency == _carry_dependency; + return TypeNode::cmp(n) && + ((CastIINode&)n)._carry_dependency == _carry_dependency && + ((CastIINode&)n)._range_check_dependency == _range_check_dependency; } Node *CastIINode::Identity(PhaseTransform *phase) { @@ -521,7 +523,7 @@ } Node *CastIINode::Ideal_DU_postCCP(PhaseCCP *ccp) { - if (_carry_dependency) { + if (_carry_dependency || _range_check_dependency) { return NULL; } return ConstraintCastNode::Ideal_DU_postCCP(ccp); @@ -533,6 +535,9 @@ if (_carry_dependency) { st->print(" carry dependency"); } + if (_range_check_dependency) { + st->print(" range check dependency"); + } } #endif @@ -974,7 +979,7 @@ } #ifdef _LP64 - // Convert ConvI2L(AddI(x, y)) to AddL(ConvI2L(x), ConvI2L(y)) , + // Convert ConvI2L(AddI(x, y)) to AddL(ConvI2L(x), ConvI2L(y)) // but only if x and y have subranges that cannot cause 32-bit overflow, // under the assumption that x+y is in my own subrange this->type(). @@ -1055,9 +1060,10 @@ rylo = -ryhi; ryhi = -rylo0; } - - Node* cx = phase->transform( new (phase->C) ConvI2LNode(x, TypeLong::make(rxlo, rxhi, widen)) ); - Node* cy = phase->transform( new (phase->C) ConvI2LNode(y, TypeLong::make(rylo, ryhi, widen)) ); + assert(rxlo == (int)rxlo && rxhi == (int)rxhi, "x should not overflow"); + assert(rylo == (int)rylo && ryhi == (int)ryhi, "y should not overflow"); + Node* cx = phase->C->constrained_convI2L(phase, x, TypeInt::make(rxlo, rxhi, widen), NULL); + Node* cy = phase->C->constrained_convI2L(phase, y, TypeInt::make(rylo, ryhi, widen), NULL); switch (op) { case Op_AddI: return new (phase->C) AddLNode(cx, cy); case Op_SubI: return new (phase->C) SubLNode(cx, cy); diff -r 08794bf98f9f -r b7f0b616a070 src/share/vm/opto/connode.hpp --- a/src/share/vm/opto/connode.hpp Wed Nov 20 06:36:50 2019 +0000 +++ b/src/share/vm/opto/connode.hpp Thu Feb 06 01:43:05 2020 +0000 @@ -236,19 +236,31 @@ private: // Can this node be removed post CCP or does it carry a required dependency? const bool _carry_dependency; + // Is this node dependent on a range check? + const bool _range_check_dependency; protected: virtual uint cmp( const Node &n ) const; virtual uint size_of() const; public: - CastIINode(Node *n, const Type *t, bool carry_dependency = false) - : ConstraintCastNode(n,t), _carry_dependency(carry_dependency) {} + CastIINode(Node *n, const Type *t, bool carry_dependency = false, bool range_check_dependency = false) + : ConstraintCastNode(n,t), _carry_dependency(carry_dependency), _range_check_dependency(range_check_dependency) { + init_class_id(Class_CastII); + } virtual int Opcode() const; virtual uint ideal_reg() const { return Op_RegI; } virtual Node *Identity( PhaseTransform *phase ); virtual const Type *Value( PhaseTransform *phase ) const; virtual Node *Ideal_DU_postCCP( PhaseCCP * ); + const bool has_range_check() { + #ifdef _LP64 + return _range_check_dependency; + #else + assert(!_range_check_dependency, "Should not have range check dependency"); + return false; + #endif + } #ifndef PRODUCT virtual void dump_spec(outputStream *st) const; #endif diff -r 08794bf98f9f -r b7f0b616a070 src/share/vm/opto/graphKit.cpp --- a/src/share/vm/opto/graphKit.cpp Wed Nov 20 06:36:50 2019 +0000 +++ b/src/share/vm/opto/graphKit.cpp Thu Feb 06 01:43:05 2020 +0000 @@ -1621,7 +1621,7 @@ //-------------------------array_element_address------------------------- Node* GraphKit::array_element_address(Node* ary, Node* idx, BasicType elembt, - const TypeInt* sizetype) { + const TypeInt* sizetype, Node* ctrl) { uint shift = exact_log2(type2aelembytes(elembt)); uint header = arrayOopDesc::base_offset_in_bytes(elembt); @@ -1646,9 +1646,9 @@ // number. (The prior range check has ensured this.) // This assertion is used by ConvI2LNode::Ideal. int index_max = max_jint - 1; // array size is max_jint, index is one less - if (sizetype != NULL) index_max = sizetype->_hi - 1; - const TypeLong* lidxtype = TypeLong::make(CONST64(0), index_max, Type::WidenMax); - idx = _gvn.transform( new (C) ConvI2LNode(idx, lidxtype) ); + if (sizetype != NULL) index_max = sizetype->_hi - 1; + const TypeInt* iidxtype = TypeInt::make(0, index_max, Type::WidenMax); + idx = C->constrained_convI2L(&_gvn, idx, iidxtype, ctrl); #endif Node* scale = _gvn.transform( new (C) LShiftXNode(idx, intcon(shift)) ); return basic_plus_adr(ary, base, scale); @@ -3253,10 +3253,6 @@ Node* initial_slow_cmp = _gvn.transform( new (C) CmpUNode( length, intcon( fast_size_limit ) ) ); Node* initial_slow_test = _gvn.transform( new (C) BoolNode( initial_slow_cmp, BoolTest::gt ) ); - if (initial_slow_test->is_Bool()) { - // Hide it behind a CMoveI, or else PhaseIdealLoop::split_up will get sick. - initial_slow_test = initial_slow_test->as_Bool()->as_int_value(&_gvn); - } // --- Size Computation --- // array_size = round_to_heap(array_header + (length << elem_shift)); @@ -3302,13 +3298,35 @@ Node* lengthx = ConvI2X(length); Node* headerx = ConvI2X(header_size); #ifdef _LP64 - { const TypeLong* tllen = _gvn.find_long_type(lengthx); - if (tllen != NULL && tllen->_lo < 0) { + { const TypeInt* tilen = _gvn.find_int_type(length); + if (tilen != NULL && tilen->_lo < 0) { // Add a manual constraint to a positive range. Cf. array_element_address. - jlong size_max = arrayOopDesc::max_array_length(T_BYTE); - if (size_max > tllen->_hi) size_max = tllen->_hi; - const TypeLong* tlcon = TypeLong::make(CONST64(0), size_max, Type::WidenMin); - lengthx = _gvn.transform( new (C) ConvI2LNode(length, tlcon)); + jlong size_max = fast_size_limit; + if (size_max > tilen->_hi) size_max = tilen->_hi; + const TypeInt* tlcon = TypeInt::make(0, size_max, Type::WidenMin); + + // Only do a narrow I2L conversion if the range check passed. + IfNode* iff = new (C) IfNode(control(), initial_slow_test, PROB_MIN, COUNT_UNKNOWN); + _gvn.transform(iff); + RegionNode* region = new (C) RegionNode(3); + _gvn.set_type(region, Type::CONTROL); + lengthx = new (C) PhiNode(region, TypeLong::LONG); + _gvn.set_type(lengthx, TypeLong::LONG); + + // Range check passed. Use ConvI2L node with narrow type. + Node* passed = IfFalse(iff); + region->init_req(1, passed); + // Make I2L conversion control dependent to prevent it from + // floating above the range check during loop optimizations. + lengthx->init_req(1, C->constrained_convI2L(&_gvn, length, tlcon, passed)); + + // Range check failed. Use ConvI2L with wide type because length may be invalid. + region->init_req(2, IfTrue(iff)); + lengthx->init_req(2, ConvI2X(length)); + + set_control(region); + record_for_igvn(region); + record_for_igvn(lengthx); } } #endif @@ -3339,6 +3357,11 @@ Node *mem = reset_memory(); set_all_memory(mem); // Create new memory state + if (initial_slow_test->is_Bool()) { + // Hide it behind a CMoveI, or else PhaseIdealLoop::split_up will get sick. + initial_slow_test = initial_slow_test->as_Bool()->as_int_value(&_gvn); + } + // Create the AllocateArrayNode and its result projections AllocateArrayNode* alloc = new (C) AllocateArrayNode(C, AllocateArrayNode::alloc_type(TypeInt::INT), diff -r 08794bf98f9f -r b7f0b616a070 src/share/vm/opto/graphKit.hpp --- a/src/share/vm/opto/graphKit.hpp Wed Nov 20 06:36:50 2019 +0000 +++ b/src/share/vm/opto/graphKit.hpp Thu Feb 06 01:43:05 2020 +0000 @@ -598,7 +598,9 @@ // Return addressing for an array element. Node* array_element_address(Node* ary, Node* idx, BasicType elembt, // Optional constraint on the array size: - const TypeInt* sizetype = NULL); + const TypeInt* sizetype = NULL, + // Optional control dependency (for example, on range check) + Node* ctrl = NULL); // Return a load of array element at idx. Node* load_array_element(Node* ctl, Node* ary, Node* idx, const TypeAryPtr* arytype); diff -r 08794bf98f9f -r b7f0b616a070 src/share/vm/opto/loopTransform.cpp --- a/src/share/vm/opto/loopTransform.cpp Wed Nov 20 06:36:50 2019 +0000 +++ b/src/share/vm/opto/loopTransform.cpp Thu Feb 06 01:43:05 2020 +0000 @@ -2410,7 +2410,7 @@ //============================================================================= // Process all the loops in the loop tree and replace any fill -// patterns with an intrisc version. +// patterns with an intrinsic version. bool PhaseIdealLoop::do_intrinsify_fill() { bool changed = false; for (LoopTreeIterator iter(_ltree_root); !iter.done(); iter.next()) { @@ -2508,8 +2508,9 @@ } // Make sure the address expression can be handled. It should be - // head->phi * elsize + con. head->phi might have a ConvI2L. + // head->phi * elsize + con. head->phi might have a ConvI2L(CastII()). Node* elements[4]; + Node* cast = NULL; Node* conv = NULL; bool found_index = false; int count = store->in(MemNode::Address)->as_AddP()->unpack_offsets(elements, ARRAY_SIZE(elements)); @@ -2524,6 +2525,12 @@ conv = value; value = value->in(1); } + if (value->Opcode() == Op_CastII && + value->as_CastII()->has_range_check()) { + // Skip range check dependent CastII nodes + cast = value; + value = value->in(1); + } #endif if (value != head->phi()) { msg = "unhandled shift in address"; @@ -2536,9 +2543,16 @@ } } } else if (n->Opcode() == Op_ConvI2L && conv == NULL) { - if (n->in(1) == head->phi()) { + conv = n; + n = n->in(1); + if (n->Opcode() == Op_CastII && + n->as_CastII()->has_range_check()) { + // Skip range check dependent CastII nodes + cast = n; + n = n->in(1); + } + if (n == head->phi()) { found_index = true; - conv = n; } else { msg = "unhandled input to ConvI2L"; } @@ -2594,6 +2608,7 @@ // Address elements are ok if (con) ok.set(con->_idx); if (shift) ok.set(shift->_idx); + if (cast) ok.set(cast->_idx); if (conv) ok.set(conv->_idx); for (uint i = 0; msg == NULL && i < lpt->_body.size(); i++) { diff -r 08794bf98f9f -r b7f0b616a070 src/share/vm/opto/loopopts.cpp --- a/src/share/vm/opto/loopopts.cpp Wed Nov 20 06:36:50 2019 +0000 +++ b/src/share/vm/opto/loopopts.cpp Thu Feb 06 01:43:05 2020 +0000 @@ -42,6 +42,15 @@ // so disable this for now return NULL; } + + // Splitting range check CastIIs through a loop induction Phi can + // cause new Phis to be created that are left unrelated to the loop + // induction Phi and prevent optimizations (vectorization) + if (n->Opcode() == Op_CastII && n->as_CastII()->has_range_check() && + region->is_CountedLoop() && n->in(1) == region->as_CountedLoop()->phi()) { + return NULL; + } + int wins = 0; assert(!n->is_CFG(), ""); assert(region->is_Region(), ""); @@ -767,6 +776,9 @@ #ifdef _LP64 if (m->Opcode() == Op_ConvI2L) return false; + if (m->is_CastII() && m->isa_CastII()->has_range_check()) { + return false; + } #endif } } diff -r 08794bf98f9f -r b7f0b616a070 src/share/vm/opto/node.cpp --- a/src/share/vm/opto/node.cpp Wed Nov 20 06:36:50 2019 +0000 +++ b/src/share/vm/opto/node.cpp Thu Feb 06 01:43:05 2020 +0000 @@ -497,6 +497,11 @@ C->add_macro_node(n); if (is_expensive()) C->add_expensive_node(n); + // If the cloned node is a range check dependent CastII, add it to the list. + CastIINode* cast = n->isa_CastII(); + if (cast != NULL && cast->has_range_check()) { + C->add_range_check_cast(cast); + } n->set_idx(C->next_unique()); // Get new unique index as well debug_only( n->verify_construction() ); @@ -625,6 +630,11 @@ if (is_expensive()) { compile->remove_expensive_node(this); } + CastIINode* cast = isa_CastII(); + if (cast != NULL && cast->has_range_check()) { + compile->remove_range_check_cast(cast); + } + if (is_SafePoint()) { as_SafePoint()->delete_replaced_nodes(); } @@ -1305,6 +1315,10 @@ if (dead->is_expensive()) { igvn->C->remove_expensive_node(dead); } + CastIINode* cast = dead->isa_CastII(); + if (cast != NULL && cast->has_range_check()) { + igvn->C->remove_range_check_cast(cast); + } igvn->C->record_dead_node(dead->_idx); // Kill all inputs to the dead guy for (uint i=0; i < dead->req(); i++) { diff -r 08794bf98f9f -r b7f0b616a070 src/share/vm/opto/node.hpp --- a/src/share/vm/opto/node.hpp Wed Nov 20 06:36:50 2019 +0000 +++ b/src/share/vm/opto/node.hpp Thu Feb 06 01:43:05 2020 +0000 @@ -54,6 +54,7 @@ class CatchNode; class CatchProjNode; class CheckCastPPNode; +class CastIINode; class ClearArrayNode; class CmpNode; class CodeBuffer; @@ -592,6 +593,7 @@ DEFINE_CLASS_ID(Type, Node, 2) DEFINE_CLASS_ID(Phi, Type, 0) DEFINE_CLASS_ID(ConstraintCast, Type, 1) + DEFINE_CLASS_ID(CastII, ConstraintCast, 0) DEFINE_CLASS_ID(CheckCastPP, Type, 2) DEFINE_CLASS_ID(CMove, Type, 3) DEFINE_CLASS_ID(SafePointScalarObject, Type, 4) @@ -711,6 +713,7 @@ DEFINE_CLASS_QUERY(Catch) DEFINE_CLASS_QUERY(CatchProj) DEFINE_CLASS_QUERY(CheckCastPP) + DEFINE_CLASS_QUERY(CastII) DEFINE_CLASS_QUERY(ConstraintCast) DEFINE_CLASS_QUERY(ClearArray) DEFINE_CLASS_QUERY(CMove) diff -r 08794bf98f9f -r b7f0b616a070 src/share/vm/opto/parse2.cpp --- a/src/share/vm/opto/parse2.cpp Wed Nov 20 06:36:50 2019 +0000 +++ b/src/share/vm/opto/parse2.cpp Thu Feb 06 01:43:05 2020 +0000 @@ -158,7 +158,9 @@ // Check for always knowing you are throwing a range-check exception if (stopped()) return top(); - Node* ptr = array_element_address(ary, idx, type, sizetype); + // Make array address computation control dependent to prevent it + // from floating above the range check during loop optimizations. + Node* ptr = array_element_address(ary, idx, type, sizetype, control()); if (result2 != NULL) *result2 = elemtype; @@ -461,9 +463,12 @@ #ifdef _LP64 // Clean the 32-bit int into a real 64-bit offset. // Otherwise, the jint value 0 might turn into an offset of 0x0800000000. - const TypeLong* lkeytype = TypeLong::make(CONST64(0), num_cases-1, Type::WidenMin); - key_val = _gvn.transform( new (C) ConvI2LNode(key_val, lkeytype) ); + const TypeInt* ikeytype = TypeInt::make(0, num_cases-1, Type::WidenMin); + // Make I2L conversion control dependent to prevent it from + // floating above the range check during loop optimizations. + key_val = C->constrained_convI2L(&_gvn, key_val, ikeytype, control()); #endif + // Shift the value by wordsize so we have an index into the table, rather // than a switch value Node *shiftWord = _gvn.MakeConX(wordSize); diff -r 08794bf98f9f -r b7f0b616a070 src/share/vm/opto/phaseX.cpp --- a/src/share/vm/opto/phaseX.cpp Wed Nov 20 06:36:50 2019 +0000 +++ b/src/share/vm/opto/phaseX.cpp Thu Feb 06 01:43:05 2020 +0000 @@ -1242,6 +1242,10 @@ if (dead->is_expensive()) { C->remove_expensive_node(dead); } + CastIINode* cast = dead->isa_CastII(); + if (cast != NULL && cast->has_range_check()) { + C->remove_range_check_cast(cast); + } } } // while (_stack.is_nonempty()) } diff -r 08794bf98f9f -r b7f0b616a070 src/share/vm/opto/subnode.cpp --- a/src/share/vm/opto/subnode.cpp Wed Nov 20 06:36:50 2019 +0000 +++ b/src/share/vm/opto/subnode.cpp Thu Feb 06 01:43:05 2020 +0000 @@ -537,8 +537,12 @@ // All unsigned values are LE -1 and GE 0. if (lo0 == 0 && hi0 == 0) { return TypeInt::CC_LE; // 0 <= bot + } else if ((jint)lo0 == -1 && (jint)hi0 == -1) { + return TypeInt::CC_GE; // -1 >= bot } else if (lo1 == 0 && hi1 == 0) { return TypeInt::CC_GE; // bot >= 0 + } else if ((jint)lo1 == -1 && (jint)hi1 == -1) { + return TypeInt::CC_LE; // bot <= -1 } } else { // We can use ranges of the form [lo..hi] if signs are the same. diff -r 08794bf98f9f -r b7f0b616a070 src/share/vm/opto/superword.cpp --- a/src/share/vm/opto/superword.cpp Wed Nov 20 06:36:50 2019 +0000 +++ b/src/share/vm/opto/superword.cpp Thu Feb 06 01:43:05 2020 +0000 @@ -2315,6 +2315,11 @@ return true; } } else if (opc == Op_ConvI2L) { + if (n->in(1)->Opcode() == Op_CastII && + n->in(1)->as_CastII()->has_range_check()) { + // Skip range check dependent CastII nodes + n = n->in(1); + } if (scaled_iv_plus_offset(n->in(1))) { return true; } diff -r 08794bf98f9f -r b7f0b616a070 test/compiler/loopopts/TestLoopPeeling.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/loopopts/TestLoopPeeling.java Thu Feb 06 01:43:05 2020 +0000 @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2017, 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 8078262 8177095 + * @summary Tests correct dominator information after loop peeling. + * + * @run main/othervm -Xcomp + * -XX:CompileCommand=compileonly,compiler.loopopts.TestLoopPeeling::test* + * compiler.loopopts.TestLoopPeeling + */ + +package compiler.loopopts; + +public class TestLoopPeeling { + + public int[] array = new int[100]; + + public static void main(String args[]) { + TestLoopPeeling test = new TestLoopPeeling(); + try { + test.testArrayAccess1(0, 1); + test.testArrayAccess2(0); + test.testArrayAccess3(0, false); + test.testArrayAllocation(0, 1); + } catch (Exception e) { + // Ignore exceptions + } + } + + public void testArrayAccess1(int index, int inc) { + int storeIndex = -1; + + for (; index < 10; index += inc) { + // This loop invariant check triggers loop peeling because it can + // be moved out of the loop (see 'IdealLoopTree::policy_peeling'). + if (inc == 42) return; + + // This loop variant usage of LShiftL( ConvI2L( Phi(storeIndex) ) ) + // prevents the split if optimization that would otherwise clone the + // LShiftL and ConvI2L nodes and assign them to their corresponding array + // address computation (see 'PhaseIdealLoop::split_if_with_blocks_post'). + if (storeIndex > 0 && array[storeIndex] == 42) return; + + if (index == 42) { + // This store and the corresponding range check are moved out of the + // loop and both used after main loop and the peeled iteration exit. + // For the peeled iteration, storeIndex is always -1 and the ConvI2L + // is replaced by TOP. However, the range check is not folded because + // we don't do the split if optimization in PhaseIdealLoop2. + // As a result, we have a (dead) control path from the peeled iteration + // to the StoreI but the data path is removed. + array[storeIndex] = 1; + return; + } + + storeIndex++; + } + } + + public int testArrayAccess2(int index) { + // Load1 and the corresponding range check are moved out of the loop + // and both are used after the main loop and the peeled iteration exit. + // For the peeled iteration, storeIndex is always Integer.MIN_VALUE and + // for the main loop it is 0. Hence, the merging phi has type int:<=0. + // Load1 reads the array at index ConvI2L(CastII(AddI(storeIndex, -1))) + // where the CastII is range check dependent and has type int:>=0. + // The CastII gets pushed through the AddI and its type is changed to int:>=1 + // which does not overlap with the input type of storeIndex (int:<=0). + // The CastII is replaced by TOP causing a cascade of other eliminations. + // Since the control path through the range check CmpU(AddI(storeIndex, -1)) + // is not eliminated, the graph is in a corrupted state. We fail once we merge + // with the result of Load2 because we get data from a non-dominating region. + int storeIndex = Integer.MIN_VALUE; + for (; index < 10; ++index) { + if (index == 42) { + return array[storeIndex-1]; // Load1 + } + storeIndex = 0; + } + return array[42]; // Load2 + } + + public int testArrayAccess3(int index, boolean b) { + // Same as testArrayAccess2 but manifests as crash in register allocator. + int storeIndex = Integer.MIN_VALUE; + for (; index < 10; ++index) { + if (b) { + return 0; + } + if (index == 42) { + return array[storeIndex-1]; // Load1 + } + storeIndex = 0; + } + return array[42]; // Load2 + } + + public byte[] testArrayAllocation(int index, int inc) { + int allocationCount = -1; + byte[] result; + + for (; index < 10; index += inc) { + // This loop invariant check triggers loop peeling because it can + // be moved out of the loop (see 'IdealLoopTree::policy_peeling'). + if (inc == 42) return null; + + if (index == 42) { + // This allocation and the corresponding size check are moved out of the + // loop and both used after main loop and the peeled iteration exit. + // For the peeled iteration, allocationCount is always -1 and the ConvI2L + // is replaced by TOP. However, the size check is not folded because + // we don't do the split if optimization in PhaseIdealLoop2. + // As a result, we have a (dead) control path from the peeled iteration + // to the allocation but the data path is removed. + result = new byte[allocationCount]; + return result; + } + + allocationCount++; + } + return null; + } +} +