# HG changeset patch # User zmajo # Date 1415636099 -3600 # Node ID e7b3d177adda6fe20fe25e1be3ff21b8e6bf5317 # Parent 1a2069ede1395bd88611fa98d56f4de5256fdbbc 8057622: java/util/stream/test/org/openjdk/tests/java/util/stream/InfiniteStreamWithLimitOpTest: SEGV inside compiled code (sparc) Summary: In Parse::array_store_check(), add control edge FROM IfTrue branch of runtime type check of the destination array TO loading _element_klass from destination array. Reviewed-by: kvn, roland, anoll Contributed-by: Zoltan Majo diff -r 1a2069ede139 -r e7b3d177adda src/share/vm/opto/doCall.cpp --- a/src/share/vm/opto/doCall.cpp Fri Nov 07 09:36:34 2014 -0800 +++ b/src/share/vm/opto/doCall.cpp Mon Nov 10 17:14:59 2014 +0100 @@ -791,7 +791,7 @@ Node* ex_klass_node = NULL; if (has_ex_handler() && !ex_type->klass_is_exact()) { Node* p = basic_plus_adr( ex_node, ex_node, oopDesc::klass_offset_in_bytes()); - ex_klass_node = _gvn.transform( LoadKlassNode::make(_gvn, immutable_memory(), p, TypeInstPtr::KLASS, TypeKlassPtr::OBJECT) ); + ex_klass_node = _gvn.transform(LoadKlassNode::make(_gvn, NULL, immutable_memory(), p, TypeInstPtr::KLASS, TypeKlassPtr::OBJECT)); // Compute the exception klass a little more cleverly. // Obvious solution is to simple do a LoadKlass from the 'ex_node'. @@ -809,7 +809,7 @@ continue; } Node* p = basic_plus_adr(ex_in, ex_in, oopDesc::klass_offset_in_bytes()); - Node* k = _gvn.transform( LoadKlassNode::make(_gvn, immutable_memory(), p, TypeInstPtr::KLASS, TypeKlassPtr::OBJECT) ); + Node* k = _gvn.transform(LoadKlassNode::make(_gvn, NULL, immutable_memory(), p, TypeInstPtr::KLASS, TypeKlassPtr::OBJECT)); ex_klass_node->init_req( i, k ); } _gvn.set_type(ex_klass_node, TypeKlassPtr::OBJECT); diff -r 1a2069ede139 -r e7b3d177adda src/share/vm/opto/graphKit.cpp --- a/src/share/vm/opto/graphKit.cpp Fri Nov 07 09:36:34 2014 -0800 +++ b/src/share/vm/opto/graphKit.cpp Mon Nov 10 17:14:59 2014 +0100 @@ -1150,7 +1150,7 @@ Node* akls = AllocateNode::Ideal_klass(obj, &_gvn); if (akls != NULL) return akls; Node* k_adr = basic_plus_adr(obj, oopDesc::klass_offset_in_bytes()); - return _gvn.transform( LoadKlassNode::make(_gvn, immutable_memory(), k_adr, TypeInstPtr::KLASS) ); + return _gvn.transform(LoadKlassNode::make(_gvn, NULL, immutable_memory(), k_adr, TypeInstPtr::KLASS)); } //-------------------------load_array_length----------------------------------- @@ -2542,7 +2542,7 @@ // cache which is mutable so can't use immutable memory. Other // types load from the super-class display table which is immutable. Node *kmem = might_be_cache ? memory(p2) : immutable_memory(); - Node *nkls = _gvn.transform( LoadKlassNode::make( _gvn, kmem, p2, _gvn.type(p2)->is_ptr(), TypeKlassPtr::OBJECT_OR_NULL ) ); + Node* nkls = _gvn.transform(LoadKlassNode::make(_gvn, NULL, kmem, p2, _gvn.type(p2)->is_ptr(), TypeKlassPtr::OBJECT_OR_NULL)); // Compile speed common case: ARE a subtype and we canNOT fail if( superklass == nkls ) diff -r 1a2069ede139 -r e7b3d177adda src/share/vm/opto/library_call.cpp --- a/src/share/vm/opto/library_call.cpp Fri Nov 07 09:36:34 2014 -0800 +++ b/src/share/vm/opto/library_call.cpp Mon Nov 10 17:14:59 2014 +0100 @@ -3398,7 +3398,7 @@ if (region == NULL) never_see_null = true; Node* p = basic_plus_adr(mirror, offset); const TypeKlassPtr* kls_type = TypeKlassPtr::OBJECT_OR_NULL; - Node* kls = _gvn.transform( LoadKlassNode::make(_gvn, immutable_memory(), p, TypeRawPtr::BOTTOM, kls_type)); + Node* kls = _gvn.transform(LoadKlassNode::make(_gvn, NULL, immutable_memory(), p, TypeRawPtr::BOTTOM, kls_type)); Node* null_ctl = top(); kls = null_check_oop(kls, &null_ctl, never_see_null); if (region != NULL) { @@ -3574,7 +3574,7 @@ phi->add_req(makecon(TypeInstPtr::make(env()->Object_klass()->java_mirror()))); // If we fall through, it's a plain class. Get its _super. p = basic_plus_adr(kls, in_bytes(Klass::super_offset())); - kls = _gvn.transform( LoadKlassNode::make(_gvn, immutable_memory(), p, TypeRawPtr::BOTTOM, TypeKlassPtr::OBJECT_OR_NULL)); + kls = _gvn.transform(LoadKlassNode::make(_gvn, NULL, immutable_memory(), p, TypeRawPtr::BOTTOM, TypeKlassPtr::OBJECT_OR_NULL)); null_ctl = top(); kls = null_check_oop(kls, &null_ctl); if (null_ctl != top()) { @@ -3656,7 +3656,7 @@ args[which_arg] = arg; Node* p = basic_plus_adr(arg, class_klass_offset); - Node* kls = LoadKlassNode::make(_gvn, immutable_memory(), p, adr_type, kls_type); + Node* kls = LoadKlassNode::make(_gvn, NULL, immutable_memory(), p, adr_type, kls_type); klasses[which_arg] = _gvn.transform(kls); } @@ -5172,7 +5172,7 @@ // (At this point we can assume disjoint_bases, since types differ.) int ek_offset = in_bytes(ObjArrayKlass::element_klass_offset()); Node* p1 = basic_plus_adr(dest_klass, ek_offset); - Node* n1 = LoadKlassNode::make(_gvn, immutable_memory(), p1, TypeRawPtr::BOTTOM); + Node* n1 = LoadKlassNode::make(_gvn, NULL, immutable_memory(), p1, TypeRawPtr::BOTTOM); Node* dest_elem_klass = _gvn.transform(n1); Node* cv = generate_checkcast_arraycopy(adr_type, dest_elem_klass, diff -r 1a2069ede139 -r e7b3d177adda src/share/vm/opto/macro.cpp --- a/src/share/vm/opto/macro.cpp Fri Nov 07 09:36:34 2014 -0800 +++ b/src/share/vm/opto/macro.cpp Mon Nov 10 17:14:59 2014 +0100 @@ -2194,7 +2194,7 @@ Node* klass_node = AllocateNode::Ideal_klass(obj, &_igvn); if (klass_node == NULL) { Node* k_adr = basic_plus_adr(obj, oopDesc::klass_offset_in_bytes()); - klass_node = transform_later( LoadKlassNode::make(_igvn, mem, k_adr, _igvn.type(k_adr)->is_ptr()) ); + klass_node = transform_later(LoadKlassNode::make(_igvn, NULL, mem, k_adr, _igvn.type(k_adr)->is_ptr())); #ifdef _LP64 if (UseCompressedClassPointers && klass_node->is_DecodeNKlass()) { assert(klass_node->in(1)->Opcode() == Op_LoadNKlass, "sanity"); diff -r 1a2069ede139 -r e7b3d177adda src/share/vm/opto/memnode.cpp --- a/src/share/vm/opto/memnode.cpp Fri Nov 07 09:36:34 2014 -0800 +++ b/src/share/vm/opto/memnode.cpp Mon Nov 10 17:14:59 2014 +0100 @@ -859,6 +859,10 @@ //============================================================================= +// Should LoadNode::Ideal() attempt to remove control edges? +bool LoadNode::can_remove_control() const { + return true; +} uint LoadNode::size_of() const { return sizeof(*this); } uint LoadNode::cmp( const Node &n ) const { return !Type::cmp( _type, ((LoadNode&)n)._type ); } @@ -1455,7 +1459,7 @@ } //------------------------------Ideal------------------------------------------ -// If the load is from Field memory and the pointer is non-null, we can +// If the load is from Field memory and the pointer is non-null, it might be possible to // zero out the control input. // If the offset is constant and the base is an object allocation, // try to hook me up to the exact initializing store. @@ -1480,6 +1484,7 @@ && phase->C->get_alias_index(phase->type(address)->is_ptr()) != Compile::AliasIdxRaw) { // Check for useless control edge in some common special cases if (in(MemNode::Control) != NULL + && can_remove_control() && phase->type(base)->higher_equal(TypePtr::NOTNULL) && all_controls_dominate(base, phase->C->start())) { // A method-invariant, non-null address (constant or 'this' argument). @@ -2007,9 +2012,8 @@ //============================================================================= //----------------------------LoadKlassNode::make------------------------------ // Polymorphic factory method: -Node *LoadKlassNode::make( PhaseGVN& gvn, Node *mem, Node *adr, const TypePtr* at, const TypeKlassPtr *tk ) { +Node* LoadKlassNode::make(PhaseGVN& gvn, Node* ctl, Node *mem, Node *adr, const TypePtr* at, const TypeKlassPtr *tk) { Compile* C = gvn.C; - Node *ctl = NULL; // sanity check the alias category against the created node type const TypePtr *adr_type = adr->bottom_type()->isa_ptr(); assert(adr_type != NULL, "expecting TypeKlassPtr"); @@ -2029,6 +2033,12 @@ return klass_value_common(phase); } +// In most cases, LoadKlassNode does not have the control input set. If the control +// input is set, it must not be removed (by LoadNode::Ideal()). +bool LoadKlassNode::can_remove_control() const { + return false; +} + const Type *LoadNode::klass_value_common( PhaseTransform *phase ) const { // Either input is TOP ==> the result is TOP const Type *t1 = phase->type( in(MemNode::Memory) ); diff -r 1a2069ede139 -r e7b3d177adda src/share/vm/opto/memnode.hpp --- a/src/share/vm/opto/memnode.hpp Fri Nov 07 09:36:34 2014 -0800 +++ b/src/share/vm/opto/memnode.hpp Mon Nov 10 17:14:59 2014 +0100 @@ -148,6 +148,8 @@ protected: virtual uint cmp(const Node &n) const; virtual uint size_of() const; // Size is bigger + // Should LoadNode::Ideal() attempt to remove control edges? + virtual bool can_remove_control() const; const Type* const _type; // What kind of value is loaded? public: @@ -171,8 +173,10 @@ // we are equivalent to. We look for Load of a Store. virtual Node *Identity( PhaseTransform *phase ); - // If the load is from Field memory and the pointer is non-null, we can + // If the load is from Field memory and the pointer is non-null, it might be possible to // zero out the control input. + // If the offset is constant and the base is an object allocation, + // try to hook me up to the exact initializing store. virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); // Split instance field load through Phi. @@ -413,6 +417,10 @@ //------------------------------LoadKlassNode---------------------------------- // Load a Klass from an object class LoadKlassNode : public LoadPNode { +protected: + // In most cases, LoadKlassNode does not have the control input set. If the control + // input is set, it must not be removed (by LoadNode::Ideal()). + virtual bool can_remove_control() const; public: LoadKlassNode(Node *c, Node *mem, Node *adr, const TypePtr *at, const TypeKlassPtr *tk, MemOrd mo) : LoadPNode(c, mem, adr, at, tk, mo) {} @@ -422,8 +430,8 @@ virtual bool depends_only_on_test() const { return true; } // Polymorphic factory method: - static Node* make( PhaseGVN& gvn, Node *mem, Node *adr, const TypePtr* at, - const TypeKlassPtr *tk = TypeKlassPtr::OBJECT ); + static Node* make(PhaseGVN& gvn, Node* ctl, Node* mem, Node* adr, const TypePtr* at, + const TypeKlassPtr* tk = TypeKlassPtr::OBJECT); }; //------------------------------LoadNKlassNode--------------------------------- diff -r 1a2069ede139 -r e7b3d177adda src/share/vm/opto/parse1.cpp --- a/src/share/vm/opto/parse1.cpp Fri Nov 07 09:36:34 2014 -0800 +++ b/src/share/vm/opto/parse1.cpp Mon Nov 10 17:14:59 2014 +0100 @@ -1958,7 +1958,7 @@ // finalization. In general this will fold up since the concrete // class is often visible so the access flags are constant. Node* klass_addr = basic_plus_adr( receiver, receiver, oopDesc::klass_offset_in_bytes() ); - Node* klass = _gvn.transform( LoadKlassNode::make(_gvn, immutable_memory(), klass_addr, TypeInstPtr::KLASS) ); + Node* klass = _gvn.transform(LoadKlassNode::make(_gvn, NULL, immutable_memory(), klass_addr, TypeInstPtr::KLASS)); Node* access_flags_addr = basic_plus_adr(klass, klass, in_bytes(Klass::access_flags_offset())); Node* access_flags = make_load(NULL, access_flags_addr, TypeInt::INT, T_INT, MemNode::unordered); diff -r 1a2069ede139 -r e7b3d177adda src/share/vm/opto/parseHelper.cpp --- a/src/share/vm/opto/parseHelper.cpp Fri Nov 07 09:36:34 2014 -0800 +++ b/src/share/vm/opto/parseHelper.cpp Mon Nov 10 17:14:59 2014 +0100 @@ -156,22 +156,43 @@ int klass_offset = oopDesc::klass_offset_in_bytes(); Node* p = basic_plus_adr( ary, ary, klass_offset ); // p's type is array-of-OOPS plus klass_offset - Node* array_klass = _gvn.transform( LoadKlassNode::make(_gvn, immutable_memory(), p, TypeInstPtr::KLASS) ); + Node* array_klass = _gvn.transform(LoadKlassNode::make(_gvn, NULL, immutable_memory(), p, TypeInstPtr::KLASS)); // Get the array klass const TypeKlassPtr *tak = _gvn.type(array_klass)->is_klassptr(); - // array_klass's type is generally INexact array-of-oop. Heroically - // cast the array klass to EXACT array and uncommon-trap if the cast - // fails. + // The type of array_klass is usually INexact array-of-oop. Heroically + // cast array_klass to EXACT array and uncommon-trap if the cast fails. + // Make constant out of the inexact array klass, but use it only if the cast + // succeeds. bool always_see_exact_class = false; if (MonomorphicArrayCheck - && !too_many_traps(Deoptimization::Reason_array_check)) { + && !too_many_traps(Deoptimization::Reason_array_check) + && !tak->klass_is_exact() + && tak != TypeKlassPtr::OBJECT) { + // Regarding the fourth condition in the if-statement from above: + // + // If the compiler has determined that the type of array 'ary' (represented + // by 'array_klass') is java/lang/Object, the compiler must not assume that + // the array 'ary' is monomorphic. + // + // If 'ary' were of type java/lang/Object, this arraystore would have to fail, + // because it is not possible to perform a arraystore into an object that is not + // a "proper" array. + // + // Therefore, let's obtain at runtime the type of 'ary' and check if we can still + // successfully perform the store. + // + // The implementation reasons for the condition are the following: + // + // java/lang/Object is the superclass of all arrays, but it is represented by the VM + // as an InstanceKlass. The checks generated by gen_checkcast() (see below) expect + // 'array_klass' to be ObjArrayKlass, which can result in invalid memory accesses. + // + // See issue JDK-8057622 for details. + always_see_exact_class = true; // (If no MDO at all, hope for the best, until a trap actually occurs.) - } - // Is the array klass is exactly its defined type? - if (always_see_exact_class && !tak->klass_is_exact()) { // Make a constant out of the inexact array klass const TypeKlassPtr *extak = tak->cast_to_exactness(true)->is_klassptr(); Node* con = makecon(extak); @@ -202,11 +223,15 @@ // Extract the array element class int element_klass_offset = in_bytes(ObjArrayKlass::element_klass_offset()); Node *p2 = basic_plus_adr(array_klass, array_klass, element_klass_offset); - Node *a_e_klass = _gvn.transform( LoadKlassNode::make(_gvn, immutable_memory(), p2, tak) ); + // We are allowed to use the constant type only if cast succeeded. If always_see_exact_class is true, + // we must set a control edge from the IfTrue node created by the uncommon_trap above to the + // LoadKlassNode. + Node* a_e_klass = _gvn.transform(LoadKlassNode::make(_gvn, always_see_exact_class ? control() : NULL, + immutable_memory(), p2, tak)); // Check (the hard way) and throw if not a subklass. // Result is ignored, we just need the CFG effects. - gen_checkcast( obj, a_e_klass ); + gen_checkcast(obj, a_e_klass); }