--- old/src/share/vm/opto/loopopts.cpp 2013-11-18 21:54:03.572472695 +0100 +++ new/src/share/vm/opto/loopopts.cpp 2013-11-18 21:54:03.230944692 +0100 @@ -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(n1->bottom_type(), true)); + phi2->set_type( phi2->type()->meet(n2->bottom_type(), true)); } // 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(n1->bottom_type(), true)); + phi2->set_type(phi2->type()->meet(n2->bottom_type(), true)); } // See if these Phis have been made before. --- old/src/share/vm/opto/graphKit.cpp 2013-11-18 21:54:03.562336529 +0100 +++ new/src/share/vm/opto/graphKit.cpp 2013-11-18 21:54:03.120051697 +0100 @@ -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(srctype, true); if (phi->type() != dsttype) { phi->set_type(dsttype); _gvn.set_type(phi, dsttype); @@ -1223,7 +1223,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! @@ -1356,7 +1356,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(TypePtr::NOTNULL, true); // Object is already not-null? if( t == t_not_null ) return obj; @@ -3009,7 +3009,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(TypePtr::NULL_PTR, true)); } } --- old/src/share/vm/opto/multnode.cpp 2013-11-18 21:54:03.616153222 +0100 +++ new/src/share/vm/opto/multnode.cpp 2013-11-18 21:54:03.150383148 +0100 @@ -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(TypePtr::NOTNULL, true); } return t; } --- old/src/share/vm/opto/parse1.cpp 2013-11-18 21:54:03.578195892 +0100 +++ new/src/share/vm/opto/parse1.cpp 2013-11-18 21:54:03.187875529 +0100 @@ -1649,7 +1649,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(bt1, true), "must be consistent with type-flow"); record_for_igvn(phi); } } @@ -2022,7 +2022,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(TypeInstPtr::NOTNULL, true)->is_instptr(); value = _gvn.transform(new (C) CheckCastPPNode(0,value,tr)); } } --- old/src/share/vm/opto/connode.cpp 2013-11-18 21:54:03.637976684 +0100 +++ new/src/share/vm/opto/connode.cpp 2013-11-18 21:54:03.289749601 +0100 @@ -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(phase->type(in(IfTrue)), true); } //------------------------------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(_type, true) ? 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(_type, true); #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(_type, true); if (rt->empty()) assert(ft == Type::TOP, "special case #2"); break; } --- old/src/share/vm/opto/parse3.cpp 2013-11-18 21:54:03.695118244 +0100 +++ new/src/share/vm/opto/parse3.cpp 2013-11-18 21:54:03.257422543 +0100 @@ -337,7 +337,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(stable_type, true); break; case T_ILLEGAL: --- old/src/share/vm/opto/memnode.cpp 2013-11-18 21:54:03.712164720 +0100 +++ new/src/share/vm/opto/memnode.cpp 2013-11-18 21:54:03.336225456 +0100 @@ -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 @@ -1681,7 +1681,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(_type, true); // 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. --- old/src/share/vm/opto/callGenerator.cpp 2013-11-18 21:54:03.656935308 +0100 +++ new/src/share/vm/opto/callGenerator.cpp 2013-11-18 21:54:03.374140256 +0100 @@ -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(gvn.type(n), true); 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(gvn.type(n), true); Node* phi = PhiNode::make(region, m, t); phi->set_req(2, n); kit.map()->set_req(i, gvn.transform(phi)); --- old/src/share/vm/opto/node.cpp 2013-11-18 21:54:03.834404815 +0100 +++ new/src/share/vm/opto/node.cpp 2013-11-18 21:54:03.510880536 +0100 @@ -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(n->type(), true), "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(n->type(), true), "new type must refine old type"); } n->set_type(new_type); } --- old/src/share/vm/opto/parse2.cpp 2013-11-18 21:54:03.755500443 +0100 +++ new/src/share/vm/opto/parse2.cpp 2013-11-18 21:54:03.395944016 +0100 @@ -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(el, true); } } } @@ -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(con_type, true)->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(obj_type, true), "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(tval, true); 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(tval, true), "must improve"); // Delay transform() call to allow recovery of pre-cast value // at the control merge. ccast->set_req(0, control()); --- old/src/share/vm/opto/cfgnode.cpp 2013-11-18 21:54:03.817620100 +0100 +++ new/src/share/vm/opto/cfgnode.cpp 2013-11-18 21:54:03.428825446 +0100 @@ -951,7 +951,7 @@ if (is_intf != ti_is_intf) { t = _type; break; } } - t = t->meet(ti); + t = t->meet(ti, true); } } @@ -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(_type, true); // 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(_type, true); 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(in(i)->in(AddPNode::Base)->bottom_type(), true); } Node* base = NULL; if (doit) { --- old/src/share/vm/opto/compile.cpp 2013-11-18 21:54:03.792045089 +0100 +++ new/src/share/vm/opto/compile.cpp 2013-11-18 21:54:03.469690863 +0100 @@ -3893,16 +3893,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 ) { @@ -3916,6 +3918,19 @@ if (modified > 0) { igvn.optimize(); } +#ifdef ASSERT + 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"); + } + } +#endif } } --- old/src/share/vm/opto/type.hpp 2013-11-18 21:54:08.477441723 +0100 +++ new/src/share/vm/opto/type.hpp 2013-11-18 21:54:08.292221143 +0100 @@ -202,10 +202,12 @@ // 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); } + int higher_equal(const Type *t, bool include_speculative = false) const { + return !cmp(meet(t, include_speculative),t->maybe_remove_speculative(include_speculative)); + } // MEET operation; lower in lattice. - const Type *meet( const Type *t ) const; + const Type *meet(const Type *t, bool include_speculative = false) const; // 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 +223,14 @@ // 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(); } + const Type *join(const Type *t, bool include_speculative = false) const { + return dual()->meet(t->dual(), include_speculative)->dual(); + } // 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; + virtual const Type *filter(const Type *kills, bool include_speculative = false) const; #ifdef ASSERT // One type is interface, the other is oop @@ -383,6 +386,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 @@ -475,7 +480,7 @@ 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; + virtual const Type *filter(const Type *kills, bool include_speculative = false) const; // Convenience common pre-built types. static const TypeInt *MINUS_1; static const TypeInt *ZERO; @@ -531,7 +536,7 @@ 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; + virtual const Type *filter(const Type *kills, bool include_speculative = false) const; // Convenience common pre-built types. static const TypeLong *MINUS_1; static const TypeLong *ZERO; @@ -895,7 +900,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; virtual const Type *xmeet(const Type *t) const; virtual const Type *xdual() const; // Compute dual right now. @@ -903,7 +908,7 @@ 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; + virtual const Type *filter(const Type *kills, bool include_speculative = false) const; // Convenience common pre-built type. static const TypeOopPtr *BOTTOM; @@ -981,7 +986,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; @@ -1059,7 +1064,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; @@ -1126,7 +1131,7 @@ 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 const Type *filter(const Type *kills, bool include_speculative = false) const; // Convenience common pre-built types. static const TypeMetadataPtr *BOTTOM; @@ -1203,7 +1208,7 @@ 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 const Type *filter(const Type *kills, bool include_speculative = false) const; // Convenience common pre-built types. static const TypeKlassPtr* OBJECT; // Not-null object klass or below @@ -1239,7 +1244,7 @@ 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 const Type *filter(const Type *kills, bool include_speculative = false) const; virtual bool empty(void) const; // TRUE if type is vacuous @@ -1291,6 +1296,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 --- old/src/share/vm/opto/type.cpp 2013-11-18 21:54:08.493200244 +0100 +++ new/src/share/vm/opto/type.cpp 2013-11-18 21:54:07.995606222 +0100 @@ -236,6 +236,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(); @@ -628,37 +635,40 @@ //------------------------------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(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(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(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("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= "); _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(); @@ -754,8 +764,8 @@ } //-----------------------------filter------------------------------------------ -const Type *Type::filter( const Type *kills ) const { - const Type* ft = join(kills); +const Type *Type::filter(const Type *kills, bool include_speculative) const { + const Type* ft = join(kills, include_speculative); if (ft->empty()) return Type::TOP; // Canonical empty value return ft; @@ -1309,8 +1319,8 @@ } //-----------------------------filter------------------------------------------ -const Type *TypeInt::filter( const Type *kills ) const { - const TypeInt* ft = join(kills)->isa_int(); +const Type *TypeInt::filter(const Type *kills, bool include_speculative) const { + const TypeInt* ft = join(kills, include_speculative)->isa_int(); if (ft == NULL || ft->empty()) return Type::TOP; // Canonical empty value if (ft->_widen < this->_widen) { @@ -1570,8 +1580,8 @@ } //-----------------------------filter------------------------------------------ -const Type *TypeLong::filter( const Type *kills ) const { - const TypeLong* ft = join(kills)->isa_long(); +const Type *TypeLong::filter(const Type *kills, bool include_speculative) const { + const TypeLong* ft = join(kills, include_speculative)->isa_long(); if (ft == NULL || ft->empty()) return Type::TOP; // Canonical empty value if (ft->_widen < this->_widen) { @@ -1726,7 +1736,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(TypePtr::NOTNULL, true); } else { field_array = fields(total_fields); } @@ -1916,7 +1926,7 @@ case Array: { // Meeting 2 arrays? const TypeAry *a = t->is_ary(); - return TypeAry::make(_elem->meet(a->_elem), + return TypeAry::make(_elem->meet(a->_elem, true), _size->xmeet(a->_size)->is_int(), _stable & a->_stable); } @@ -2560,14 +2570,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(); } @@ -2787,9 +2797,9 @@ //-----------------------------filter------------------------------------------ // Do not allow interface-vs.-noninterface joins to collapse to top. -const Type *TypeOopPtr::filter(const Type *kills) const { +const Type *TypeOopPtr::filter(const Type *kills, bool include_speculative) const { - const Type* ft = join(kills); + const Type* ft = join(kills, include_speculative); const TypeInstPtr* ftip = ft->isa_instptr(); const TypeInstPtr* ktip = kills->isa_instptr(); @@ -2901,7 +2911,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); } @@ -2952,7 +2965,7 @@ other_spec = other; } - return this_spec->meet(other_spec)->is_oopptr(); + return this_spec->meet(other_spec, true)->is_oopptr(); } /** @@ -3546,7 +3559,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); } @@ -3793,7 +3809,7 @@ 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(tap->_ary, true)->is_ary(); PTR ptr = meet_ptr(tap->ptr()); int instance_id = meet_instance_id(tap->instance_id()); const TypeOopPtr* speculative = meet_speculative(tap); @@ -3990,7 +4006,10 @@ 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 { +const Type *TypeAryPtr::remove_speculative() const { + if (_speculative == NULL) { + return this; + } return make(_ptr, _const_oop, _ary, _klass, _klass_is_exact, _offset, _instance_id, NULL); } @@ -4031,9 +4050,9 @@ } -const Type *TypeNarrowPtr::filter( const Type *kills ) const { +const Type *TypeNarrowPtr::filter(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(is_same_narrowptr(kills)->_ptrtype, include_speculative); if (ft->empty()) return Type::TOP; // Canonical empty value if (ft->isa_ptr()) { @@ -4041,7 +4060,7 @@ } return ft; } else if (kills->isa_ptr()) { - const Type* ft = _ptrtype->join(kills); + const Type* ft = _ptrtype->join(kills, include_speculative); if (ft->empty()) return Type::TOP; // Canonical empty value return ft; @@ -4171,8 +4190,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(const Type *kills, bool include_speculative) const { + const TypeMetadataPtr* ft = join(kills, include_speculative)->isa_metadataptr(); if (ft == NULL || ft->empty()) return Type::TOP; // Canonical empty value return ft; @@ -4374,10 +4393,10 @@ } // Do not allow interface-vs.-noninterface joins to collapse to top. -const Type *TypeKlassPtr::filter(const Type *kills) const { +const Type *TypeKlassPtr::filter(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(kills, include_speculative); const TypeKlassPtr* ftkp = ft->isa_klassptr(); const TypeKlassPtr* ktkp = kills->isa_klassptr(); --- /dev/null 2013-10-28 22:52:38.620463208 +0100 +++ new/test/compiler/types/TestSpeculationFailedHigherEqual.java 2013-11-18 21:54:08.520450278 +0100 @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2013, 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"); + } +} --- old/src/share/vm/opto/phaseX.cpp 2013-11-18 21:54:08.674088703 +0100 +++ new/src/share/vm/opto/phaseX.cpp 2013-11-18 21:54:08.313295779 +0100 @@ -1392,9 +1392,8 @@ 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()); } } }