--- old/src/share/vm/opto/loopPredicate.cpp 2015-06-03 18:24:01.822125574 +0200 +++ new/src/share/vm/opto/loopPredicate.cpp 2015-06-03 18:24:01.563563238 +0200 @@ -438,7 +438,13 @@ } } if (all_inputs_invariant) { - _invariant.set(n->_idx); // I am a invariant too + // If n's control is a predicate that was moved out of the + // loop, it was marked invariant but n is only invariant if + // it depends only on that test. Otherwise, unless that test + // is out of the loop, it's not invariant. + if (n->is_CFG() || n->depends_only_on_test() || n->in(0) == NULL || !_phase->is_member(_lpt, n->in(0))) { + _invariant.set(n->_idx); // I am a invariant too + } } } else { // process next input _stack.set_index(idx + 1); --- old/src/share/vm/opto/graphKit.hpp 2015-06-03 18:24:01.846613830 +0200 +++ new/src/share/vm/opto/graphKit.hpp 2015-06-03 18:24:01.615304769 +0200 @@ -516,21 +516,24 @@ // adapted the `do_put_xxx' and `do_get_xxx' procedures for the case // of volatile fields. Node* make_load(Node* ctl, Node* adr, const Type* t, BasicType bt, - MemNode::MemOrd mo, bool require_atomic_access = false) { + MemNode::MemOrd mo, LoadNode::ControlDependency control_dependency = LoadNode::DependsOnlyOnTest, + bool require_atomic_access = false) { // This version computes alias_index from bottom_type return make_load(ctl, adr, t, bt, adr->bottom_type()->is_ptr(), - mo, require_atomic_access); + mo, control_dependency, require_atomic_access); } Node* make_load(Node* ctl, Node* adr, const Type* t, BasicType bt, const TypePtr* adr_type, - MemNode::MemOrd mo, bool require_atomic_access = false) { + MemNode::MemOrd mo, LoadNode::ControlDependency control_dependency = LoadNode::DependsOnlyOnTest, + bool require_atomic_access = false) { // This version computes alias_index from an address type assert(adr_type != NULL, "use other make_load factory"); return make_load(ctl, adr, t, bt, C->get_alias_index(adr_type), - mo, require_atomic_access); + mo, control_dependency, require_atomic_access); } // This is the base version which is given an alias index. Node* make_load(Node* ctl, Node* adr, const Type* t, BasicType bt, int adr_idx, - MemNode::MemOrd mo, bool require_atomic_access = false); + MemNode::MemOrd mo, LoadNode::ControlDependency control_dependency = LoadNode::DependsOnlyOnTest, + bool require_atomic_access = false); // Create & transform a StoreNode and store the effect into the // parser's memory state. --- old/src/share/vm/opto/superword.cpp 2015-06-03 18:24:01.848606917 +0200 +++ new/src/share/vm/opto/superword.cpp 2015-06-03 18:24:01.587831956 +0200 @@ -1431,7 +1431,7 @@ } Node* adr = low_adr->in(MemNode::Address); const TypePtr* atyp = n->adr_type(); - vn = LoadVectorNode::make(C, opc, ctl, mem, adr, atyp, vlen, velt_basic_type(n)); + vn = LoadVectorNode::make(C, opc, ctl, mem, adr, atyp, vlen, velt_basic_type(n), control_dependency(p)); vlen_in_bytes = vn->as_LoadVector()->memory_size(); } else if (n->is_Store()) { // Promote value to be stored to vector @@ -2029,6 +2029,19 @@ return n; } +LoadNode::ControlDependency SuperWord::control_dependency(Node_List* p) { + LoadNode::ControlDependency dep = LoadNode::DependsOnlyOnTest; + for (uint i = 0; i < p->size(); i++) { + Node* n = p->at(i); + assert(n->is_Load(), "only meaningful for loads"); + if (!n->depends_only_on_test()) { + dep = LoadNode::Pinned; + } + } + return dep; +} + + //----------------------------align_initial_loop_index--------------------------- // Adjust pre-loop limit so that in main loop, a load/store reference // to align_to_ref will be a position zero in the vector. --- old/src/share/vm/opto/library_call.cpp 2015-06-03 18:24:01.857110834 +0200 +++ new/src/share/vm/opto/library_call.cpp 2015-06-03 18:24:01.523394096 +0200 @@ -2669,7 +2669,9 @@ if (!is_store) { MemNode::MemOrd mo = is_volatile ? MemNode::acquire : MemNode::unordered; - Node* p = make_load(control(), adr, value_type, type, adr_type, mo, is_volatile); + // To be valid, unsafe loads may depend on other conditions than + // the one that guards them: pin the Load node + Node* p = make_load(control(), adr, value_type, type, adr_type, mo, LoadNode::Pinned, is_volatile); // load value switch (type) { case T_BOOLEAN: @@ -6038,7 +6040,7 @@ } // Build the load. MemNode::MemOrd mo = is_vol ? MemNode::acquire : MemNode::unordered; - Node* loadedField = make_load(NULL, adr, type, bt, adr_type, mo, is_vol); + Node* loadedField = make_load(NULL, adr, type, bt, adr_type, mo, LoadNode::DependsOnlyOnTest, is_vol); // If reference is volatile, prevent following memory ops from // floating up past the volatile read. Also prevents commoning // another volatile read. --- old/src/share/vm/opto/memnode.cpp 2015-06-03 18:24:01.906109866 +0200 +++ new/src/share/vm/opto/memnode.cpp 2015-06-03 18:24:01.643437773 +0200 @@ -878,6 +878,9 @@ // standard dump does this in Verbose and WizardMode st->print(" #"); _type->dump_on(st); } + if (!_depends_only_on_test) { + st->print(" (does not depend only on test)"); + } } #endif @@ -894,7 +897,7 @@ //----------------------------LoadNode::make----------------------------------- // Polymorphic factory method: -Node *LoadNode::make(PhaseGVN& gvn, Node *ctl, Node *mem, Node *adr, const TypePtr* adr_type, const Type *rt, BasicType bt, MemOrd mo) { +Node *LoadNode::make(PhaseGVN& gvn, Node *ctl, Node *mem, Node *adr, const TypePtr* adr_type, const Type *rt, BasicType bt, MemOrd mo, ControlDependency control_dependency) { Compile* C = gvn.C; // sanity check the alias category against the created node type @@ -910,39 +913,39 @@ rt->isa_oopptr() || is_immutable_value(adr), "raw memory operations should have control edge"); switch (bt) { - case T_BOOLEAN: return new (C) LoadUBNode(ctl, mem, adr, adr_type, rt->is_int(), mo); - case T_BYTE: return new (C) LoadBNode (ctl, mem, adr, adr_type, rt->is_int(), mo); - case T_INT: return new (C) LoadINode (ctl, mem, adr, adr_type, rt->is_int(), mo); - case T_CHAR: return new (C) LoadUSNode(ctl, mem, adr, adr_type, rt->is_int(), mo); - case T_SHORT: return new (C) LoadSNode (ctl, mem, adr, adr_type, rt->is_int(), mo); - case T_LONG: return new (C) LoadLNode (ctl, mem, adr, adr_type, rt->is_long(), mo); - case T_FLOAT: return new (C) LoadFNode (ctl, mem, adr, adr_type, rt, mo); - case T_DOUBLE: return new (C) LoadDNode (ctl, mem, adr, adr_type, rt, mo); - case T_ADDRESS: return new (C) LoadPNode (ctl, mem, adr, adr_type, rt->is_ptr(), mo); + case T_BOOLEAN: return new (C) LoadUBNode(ctl, mem, adr, adr_type, rt->is_int(), mo, control_dependency); + case T_BYTE: return new (C) LoadBNode (ctl, mem, adr, adr_type, rt->is_int(), mo, control_dependency); + case T_INT: return new (C) LoadINode (ctl, mem, adr, adr_type, rt->is_int(), mo, control_dependency); + case T_CHAR: return new (C) LoadUSNode(ctl, mem, adr, adr_type, rt->is_int(), mo, control_dependency); + case T_SHORT: return new (C) LoadSNode (ctl, mem, adr, adr_type, rt->is_int(), mo, control_dependency); + case T_LONG: return new (C) LoadLNode (ctl, mem, adr, adr_type, rt->is_long(), mo, control_dependency); + case T_FLOAT: return new (C) LoadFNode (ctl, mem, adr, adr_type, rt, mo, control_dependency); + case T_DOUBLE: return new (C) LoadDNode (ctl, mem, adr, adr_type, rt, mo, control_dependency); + case T_ADDRESS: return new (C) LoadPNode (ctl, mem, adr, adr_type, rt->is_ptr(), mo, control_dependency); case T_OBJECT: #ifdef _LP64 if (adr->bottom_type()->is_ptr_to_narrowoop()) { - Node* load = gvn.transform(new (C) LoadNNode(ctl, mem, adr, adr_type, rt->make_narrowoop(), mo)); + Node* load = gvn.transform(new (C) LoadNNode(ctl, mem, adr, adr_type, rt->make_narrowoop(), mo, control_dependency)); return new (C) DecodeNNode(load, load->bottom_type()->make_ptr()); } else #endif { assert(!adr->bottom_type()->is_ptr_to_narrowoop() && !adr->bottom_type()->is_ptr_to_narrowklass(), "should have got back a narrow oop"); - return new (C) LoadPNode(ctl, mem, adr, adr_type, rt->is_oopptr(), mo); + return new (C) LoadPNode(ctl, mem, adr, adr_type, rt->is_oopptr(), mo, control_dependency); } } ShouldNotReachHere(); return (LoadNode*)NULL; } -LoadLNode* LoadLNode::make_atomic(Compile *C, Node* ctl, Node* mem, Node* adr, const TypePtr* adr_type, const Type* rt, MemOrd mo) { +LoadLNode* LoadLNode::make_atomic(Compile *C, Node* ctl, Node* mem, Node* adr, const TypePtr* adr_type, const Type* rt, MemOrd mo, ControlDependency control_dependency) { bool require_atomic = true; - return new (C) LoadLNode(ctl, mem, adr, adr_type, rt->is_long(), mo, require_atomic); + return new (C) LoadLNode(ctl, mem, adr, adr_type, rt->is_long(), mo, control_dependency, require_atomic); } -LoadDNode* LoadDNode::make_atomic(Compile *C, Node* ctl, Node* mem, Node* adr, const TypePtr* adr_type, const Type* rt, MemOrd mo) { +LoadDNode* LoadDNode::make_atomic(Compile *C, Node* ctl, Node* mem, Node* adr, const TypePtr* adr_type, const Type* rt, MemOrd mo, ControlDependency control_dependency) { bool require_atomic = true; - return new (C) LoadDNode(ctl, mem, adr, adr_type, rt, mo, require_atomic); + return new (C) LoadDNode(ctl, mem, adr, adr_type, rt, mo, control_dependency, require_atomic); } --- old/src/share/vm/opto/vectornode.cpp 2015-06-03 18:24:01.937132834 +0200 +++ new/src/share/vm/opto/vectornode.cpp 2015-06-03 18:24:01.692299696 +0200 @@ -403,9 +403,10 @@ // Return the vector version of a scalar load node. LoadVectorNode* LoadVectorNode::make(Compile* C, int opc, Node* ctl, Node* mem, - Node* adr, const TypePtr* atyp, uint vlen, BasicType bt) { + Node* adr, const TypePtr* atyp, uint vlen, BasicType bt, + ControlDependency control_dependency) { const TypeVect* vt = TypeVect::make(bt, vlen); - return new (C) LoadVectorNode(ctl, mem, adr, atyp, vt); + return new (C) LoadVectorNode(ctl, mem, adr, atyp, vt, control_dependency); } // Return the vector version of a scalar store node. --- old/src/share/vm/opto/memnode.hpp 2015-06-03 18:24:02.008644078 +0200 +++ new/src/share/vm/opto/memnode.hpp 2015-06-03 18:24:01.727226586 +0200 @@ -138,7 +138,33 @@ //------------------------------LoadNode--------------------------------------- // Load value; requires Memory and Address class LoadNode : public MemNode { +public: + // Some loads (from unsafe) should be pinned: they don't depend only + // on the dominating test. The boolean field _depends_only_on_test + // below records whether that node depends only on the dominating + // test. + // Methods used to build LoadNodes pass an argument of type enum + // ControlDependency instead of a boolean because those methods + // typically have multiple boolean parameters with default values: + // passing the wrong boolean to one of these parameters by mistake + // goes easily unnoticed. Using an enum, the compiler can check that + // the type of a value and the type of the parameter match. + enum ControlDependency { + Pinned, + DependsOnlyOnTest + }; private: + // LoadNode::hash() doesn't take the _depends_only_on_test field + // into account: If the graph already has a non-pinned LoadNode and + // we add a pinned LoadNode with the same inputs, it's safe for GVN + // to replace the pinned LoadNode with the non-pinned LoadNode, + // otherwise it wouldn't be safe to have a non pinned LoadNode with + // those inputs in the first place. If the graph already has a + // pinned LoadNode and we add a non pinned LoadNode with the same + // inputs, it's safe (but suboptimal) for GVN to replace the + // non-pinned LoadNode by the pinned LoadNode. + bool _depends_only_on_test; + // On platforms with weak memory ordering (e.g., PPC, Ia64) we distinguish // loads that can be reordered, and such requiring acquire semantics to // adhere to the Java specification. The required behaviour is stored in @@ -153,8 +179,8 @@ const Type* const _type; // What kind of value is loaded? public: - LoadNode(Node *c, Node *mem, Node *adr, const TypePtr* at, const Type *rt, MemOrd mo) - : MemNode(c,mem,adr,at), _type(rt), _mo(mo) { + LoadNode(Node *c, Node *mem, Node *adr, const TypePtr* at, const Type *rt, MemOrd mo, ControlDependency control_dependency) + : MemNode(c,mem,adr,at), _type(rt), _mo(mo), _depends_only_on_test(control_dependency == DependsOnlyOnTest) { init_class_id(Class_Load); } inline bool is_unordered() const { return !is_acquire(); } @@ -165,7 +191,8 @@ // Polymorphic factory method: static Node* make(PhaseGVN& gvn, Node *c, Node *mem, Node *adr, - const TypePtr* at, const Type *rt, BasicType bt, MemOrd mo); + const TypePtr* at, const Type *rt, BasicType bt, + MemOrd mo, ControlDependency control_dependency = DependsOnlyOnTest); virtual uint hash() const; // Check the type @@ -233,16 +260,15 @@ // which produce results (new raw memory state) inside of loops preventing all // manner of other optimizations). Basically, it's ugly but so is the alternative. // See comment in macro.cpp, around line 125 expand_allocate_common(). - virtual bool depends_only_on_test() const { return adr_type() != TypeRawPtr::BOTTOM; } - + virtual bool depends_only_on_test() const { return adr_type() != TypeRawPtr::BOTTOM && _depends_only_on_test; } }; //------------------------------LoadBNode-------------------------------------- // Load a byte (8bits signed) from memory class LoadBNode : public LoadNode { public: - LoadBNode(Node *c, Node *mem, Node *adr, const TypePtr* at, const TypeInt *ti, MemOrd mo) - : LoadNode(c, mem, adr, at, ti, mo) {} + LoadBNode(Node *c, Node *mem, Node *adr, const TypePtr* at, const TypeInt *ti, MemOrd mo, ControlDependency control_dependency = DependsOnlyOnTest) + : LoadNode(c, mem, adr, at, ti, mo, control_dependency) {} virtual int Opcode() const; virtual uint ideal_reg() const { return Op_RegI; } virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); @@ -255,8 +281,8 @@ // Load a unsigned byte (8bits unsigned) from memory class LoadUBNode : public LoadNode { public: - LoadUBNode(Node* c, Node* mem, Node* adr, const TypePtr* at, const TypeInt* ti, MemOrd mo) - : LoadNode(c, mem, adr, at, ti, mo) {} + LoadUBNode(Node* c, Node* mem, Node* adr, const TypePtr* at, const TypeInt* ti, MemOrd mo, ControlDependency control_dependency = DependsOnlyOnTest) + : LoadNode(c, mem, adr, at, ti, mo, control_dependency) {} virtual int Opcode() const; virtual uint ideal_reg() const { return Op_RegI; } virtual Node* Ideal(PhaseGVN *phase, bool can_reshape); @@ -269,8 +295,8 @@ // Load an unsigned short/char (16bits unsigned) from memory class LoadUSNode : public LoadNode { public: - LoadUSNode(Node *c, Node *mem, Node *adr, const TypePtr* at, const TypeInt *ti, MemOrd mo) - : LoadNode(c, mem, adr, at, ti, mo) {} + LoadUSNode(Node *c, Node *mem, Node *adr, const TypePtr* at, const TypeInt *ti, MemOrd mo, ControlDependency control_dependency = DependsOnlyOnTest) + : LoadNode(c, mem, adr, at, ti, mo, control_dependency) {} virtual int Opcode() const; virtual uint ideal_reg() const { return Op_RegI; } virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); @@ -283,8 +309,8 @@ // Load a short (16bits signed) from memory class LoadSNode : public LoadNode { public: - LoadSNode(Node *c, Node *mem, Node *adr, const TypePtr* at, const TypeInt *ti, MemOrd mo) - : LoadNode(c, mem, adr, at, ti, mo) {} + LoadSNode(Node *c, Node *mem, Node *adr, const TypePtr* at, const TypeInt *ti, MemOrd mo, ControlDependency control_dependency = DependsOnlyOnTest) + : LoadNode(c, mem, adr, at, ti, mo, control_dependency) {} virtual int Opcode() const; virtual uint ideal_reg() const { return Op_RegI; } virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); @@ -297,8 +323,8 @@ // Load an integer from memory class LoadINode : public LoadNode { public: - LoadINode(Node *c, Node *mem, Node *adr, const TypePtr* at, const TypeInt *ti, MemOrd mo) - : LoadNode(c, mem, adr, at, ti, mo) {} + LoadINode(Node *c, Node *mem, Node *adr, const TypePtr* at, const TypeInt *ti, MemOrd mo, ControlDependency control_dependency = DependsOnlyOnTest) + : LoadNode(c, mem, adr, at, ti, mo, control_dependency) {} virtual int Opcode() const; virtual uint ideal_reg() const { return Op_RegI; } virtual int store_Opcode() const { return Op_StoreI; } @@ -330,15 +356,15 @@ public: LoadLNode(Node *c, Node *mem, Node *adr, const TypePtr* at, const TypeLong *tl, - MemOrd mo, bool require_atomic_access = false) - : LoadNode(c, mem, adr, at, tl, mo), _require_atomic_access(require_atomic_access) {} + MemOrd mo, ControlDependency control_dependency = DependsOnlyOnTest, bool require_atomic_access = false) + : LoadNode(c, mem, adr, at, tl, mo, control_dependency), _require_atomic_access(require_atomic_access) {} virtual int Opcode() const; virtual uint ideal_reg() const { return Op_RegL; } virtual int store_Opcode() const { return Op_StoreL; } virtual BasicType memory_type() const { return T_LONG; } bool require_atomic_access() const { return _require_atomic_access; } static LoadLNode* make_atomic(Compile *C, Node* ctl, Node* mem, Node* adr, const TypePtr* adr_type, - const Type* rt, MemOrd mo); + const Type* rt, MemOrd mo, ControlDependency control_dependency = DependsOnlyOnTest); #ifndef PRODUCT virtual void dump_spec(outputStream *st) const { LoadNode::dump_spec(st); @@ -351,8 +377,8 @@ // Load a long from unaligned memory class LoadL_unalignedNode : public LoadLNode { public: - LoadL_unalignedNode(Node *c, Node *mem, Node *adr, const TypePtr* at, MemOrd mo) - : LoadLNode(c, mem, adr, at, TypeLong::LONG, mo) {} + LoadL_unalignedNode(Node *c, Node *mem, Node *adr, const TypePtr* at, MemOrd mo, ControlDependency control_dependency = DependsOnlyOnTest) + : LoadLNode(c, mem, adr, at, TypeLong::LONG, mo, control_dependency) {} virtual int Opcode() const; }; @@ -360,8 +386,8 @@ // Load a float (64 bits) from memory class LoadFNode : public LoadNode { public: - LoadFNode(Node *c, Node *mem, Node *adr, const TypePtr* at, const Type *t, MemOrd mo) - : LoadNode(c, mem, adr, at, t, mo) {} + LoadFNode(Node *c, Node *mem, Node *adr, const TypePtr* at, const Type *t, MemOrd mo, ControlDependency control_dependency = DependsOnlyOnTest) + : LoadNode(c, mem, adr, at, t, mo, control_dependency) {} virtual int Opcode() const; virtual uint ideal_reg() const { return Op_RegF; } virtual int store_Opcode() const { return Op_StoreF; } @@ -381,15 +407,15 @@ public: LoadDNode(Node *c, Node *mem, Node *adr, const TypePtr* at, const Type *t, - MemOrd mo, bool require_atomic_access = false) - : LoadNode(c, mem, adr, at, t, mo), _require_atomic_access(require_atomic_access) {} + MemOrd mo, ControlDependency control_dependency = DependsOnlyOnTest, bool require_atomic_access = false) + : LoadNode(c, mem, adr, at, t, mo, control_dependency), _require_atomic_access(require_atomic_access) {} virtual int Opcode() const; virtual uint ideal_reg() const { return Op_RegD; } virtual int store_Opcode() const { return Op_StoreD; } virtual BasicType memory_type() const { return T_DOUBLE; } bool require_atomic_access() const { return _require_atomic_access; } static LoadDNode* make_atomic(Compile *C, Node* ctl, Node* mem, Node* adr, const TypePtr* adr_type, - const Type* rt, MemOrd mo); + const Type* rt, MemOrd mo, ControlDependency control_dependency = DependsOnlyOnTest); #ifndef PRODUCT virtual void dump_spec(outputStream *st) const { LoadNode::dump_spec(st); @@ -402,8 +428,8 @@ // Load a double from unaligned memory class LoadD_unalignedNode : public LoadDNode { public: - LoadD_unalignedNode(Node *c, Node *mem, Node *adr, const TypePtr* at, MemOrd mo) - : LoadDNode(c, mem, adr, at, Type::DOUBLE, mo) {} + LoadD_unalignedNode(Node *c, Node *mem, Node *adr, const TypePtr* at, MemOrd mo, ControlDependency control_dependency = DependsOnlyOnTest) + : LoadDNode(c, mem, adr, at, Type::DOUBLE, mo, control_dependency) {} virtual int Opcode() const; }; @@ -411,8 +437,8 @@ // Load a pointer from memory (either object or array) class LoadPNode : public LoadNode { public: - LoadPNode(Node *c, Node *mem, Node *adr, const TypePtr *at, const TypePtr* t, MemOrd mo) - : LoadNode(c, mem, adr, at, t, mo) {} + LoadPNode(Node *c, Node *mem, Node *adr, const TypePtr *at, const TypePtr* t, MemOrd mo, ControlDependency control_dependency = DependsOnlyOnTest) + : LoadNode(c, mem, adr, at, t, mo, control_dependency) {} virtual int Opcode() const; virtual uint ideal_reg() const { return Op_RegP; } virtual int store_Opcode() const { return Op_StoreP; } @@ -424,8 +450,8 @@ // Load a narrow oop from memory (either object or array) class LoadNNode : public LoadNode { public: - LoadNNode(Node *c, Node *mem, Node *adr, const TypePtr *at, const Type* t, MemOrd mo) - : LoadNode(c, mem, adr, at, t, mo) {} + LoadNNode(Node *c, Node *mem, Node *adr, const TypePtr *at, const Type* t, MemOrd mo, ControlDependency control_dependency = DependsOnlyOnTest) + : LoadNode(c, mem, adr, at, t, mo, control_dependency) {} virtual int Opcode() const; virtual uint ideal_reg() const { return Op_RegN; } virtual int store_Opcode() const { return Op_StoreN; } --- old/src/share/vm/opto/matcher.cpp 2015-06-03 18:24:01.959255512 +0200 +++ new/src/share/vm/opto/matcher.cpp 2015-06-03 18:24:01.709424868 +0200 @@ -840,7 +840,7 @@ MachNode *spillCP = match_tree(new (C) LoadNNode(NULL,mem,fp,atp,TypeInstPtr::BOTTOM,MemNode::unordered)); #endif MachNode *spillI = match_tree(new (C) LoadINode(NULL,mem,fp,atp,TypeInt::INT,MemNode::unordered)); - MachNode *spillL = match_tree(new (C) LoadLNode(NULL,mem,fp,atp,TypeLong::LONG,MemNode::unordered,false)); + MachNode *spillL = match_tree(new (C) LoadLNode(NULL,mem,fp,atp,TypeLong::LONG,MemNode::unordered, LoadNode::DependsOnlyOnTest,false)); MachNode *spillF = match_tree(new (C) LoadFNode(NULL,mem,fp,atp,Type::FLOAT,MemNode::unordered)); MachNode *spillD = match_tree(new (C) LoadDNode(NULL,mem,fp,atp,Type::DOUBLE,MemNode::unordered)); MachNode *spillP = match_tree(new (C) LoadPNode(NULL,mem,fp,atp,TypeInstPtr::BOTTOM,MemNode::unordered)); --- old/src/share/vm/opto/superword.hpp 2015-06-03 18:24:01.924257435 +0200 +++ new/src/share/vm/opto/superword.hpp 2015-06-03 18:24:01.674174352 +0200 @@ -399,6 +399,7 @@ Node* executed_first(Node_List* p); // Return the node executed last in pack p. Node* executed_last(Node_List* p); + static LoadNode::ControlDependency control_dependency(Node_List* p); // Alignment within a vector memory reference int memory_alignment(MemNode* s, int iv_adjust); // (Start, end] half-open range defining which operands are vector --- old/src/share/vm/opto/vectornode.hpp 2015-06-03 18:24:02.026245250 +0200 +++ new/src/share/vm/opto/vectornode.hpp 2015-06-03 18:24:01.777467652 +0200 @@ -355,8 +355,8 @@ // Load Vector from memory class LoadVectorNode : public LoadNode { public: - LoadVectorNode(Node* c, Node* mem, Node* adr, const TypePtr* at, const TypeVect* vt) - : LoadNode(c, mem, adr, at, vt, MemNode::unordered) { + LoadVectorNode(Node* c, Node* mem, Node* adr, const TypePtr* at, const TypeVect* vt, ControlDependency control_dependency = LoadNode::DependsOnlyOnTest) + : LoadNode(c, mem, adr, at, vt, MemNode::unordered, control_dependency) { init_class_id(Class_LoadVector); } @@ -372,7 +372,8 @@ virtual int store_Opcode() const { return Op_StoreVector; } static LoadVectorNode* make(Compile* C, int opc, Node* ctl, Node* mem, - Node* adr, const TypePtr* atyp, uint vlen, BasicType bt); + Node* adr, const TypePtr* atyp, uint vlen, BasicType bt, + ControlDependency control_dependency = LoadNode::DependsOnlyOnTest); }; //------------------------------StoreVectorNode-------------------------------- --- old/src/share/vm/opto/graphKit.cpp 2015-06-03 18:24:02.095852366 +0200 +++ new/src/share/vm/opto/graphKit.cpp 2015-06-03 18:24:01.795710085 +0200 @@ -1452,18 +1452,18 @@ // factory methods in "int adr_idx" Node* GraphKit::make_load(Node* ctl, Node* adr, const Type* t, BasicType bt, int adr_idx, - MemNode::MemOrd mo, bool require_atomic_access) { + MemNode::MemOrd mo, LoadNode::ControlDependency control_dependency, bool require_atomic_access) { assert(adr_idx != Compile::AliasIdxTop, "use other make_load factory" ); const TypePtr* adr_type = NULL; // debug-mode-only argument debug_only(adr_type = C->get_adr_type(adr_idx)); Node* mem = memory(adr_idx); Node* ld; if (require_atomic_access && bt == T_LONG) { - ld = LoadLNode::make_atomic(C, ctl, mem, adr, adr_type, t, mo); + ld = LoadLNode::make_atomic(C, ctl, mem, adr, adr_type, t, mo, control_dependency); } else if (require_atomic_access && bt == T_DOUBLE) { - ld = LoadDNode::make_atomic(C, ctl, mem, adr, adr_type, t, mo); + ld = LoadDNode::make_atomic(C, ctl, mem, adr, adr_type, t, mo, control_dependency); } else { - ld = LoadNode::make(_gvn, ctl, mem, adr, adr_type, t, bt, mo); + ld = LoadNode::make(_gvn, ctl, mem, adr, adr_type, t, bt, mo, control_dependency); } ld = _gvn.transform(ld); if ((bt == T_OBJECT) && C->do_escape_analysis() || C->eliminate_boxing()) { --- old/src/share/vm/opto/parse3.cpp 2015-06-03 18:24:02.044266445 +0200 +++ new/src/share/vm/opto/parse3.cpp 2015-06-03 18:24:01.758665536 +0200 @@ -233,7 +233,7 @@ // Build the load. // MemNode::MemOrd mo = is_vol ? MemNode::acquire : MemNode::unordered; - Node* ld = make_load(NULL, adr, type, bt, adr_type, mo, is_vol); + Node* ld = make_load(NULL, adr, type, bt, adr_type, mo, LoadNode::DependsOnlyOnTest, is_vol); // Adjust Java stack if (type2size[bt] == 1) --- /dev/null 2015-04-28 16:14:11.867039931 +0200 +++ new/test/compiler/unsafe/TestUnsafeLoadControl.java 2015-06-03 18:24:04.804612182 +0200 @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2015, 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 8077504 + * @summary Unsafe load can loose control dependency and cause crash + * @run main/othervm -XX:-BackgroundCompilation -XX:-UseOnStackReplacement TestUnsafeLoadControl + * + */ + +import java.lang.reflect.Field; +import sun.misc.Unsafe; + +public class TestUnsafeLoadControl { + + private static final Unsafe UNSAFE; + + static { + try { + Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe"); + unsafeField.setAccessible(true); + UNSAFE = (Unsafe) unsafeField.get(null); + } catch(Exception e) { + throw new RuntimeException(e); + } + } + + static int val; + static void test1(int[] a, boolean[] flags, boolean flag, long j) { + for (int i = 0; i < 10; i++) { + if (flags[i]) { + if (flag) { + long address = (j << 2) + UNSAFE.ARRAY_INT_BASE_OFFSET; + int v = UNSAFE.getInt(a, address); + val = v; + } + } + } + } + + static int test2(int[] a, boolean[] flags, boolean flag, long j) { + int sum = 0; + for (int i = 0; i < 10; i++) { + if (flags[i]) { + if (flag) { + long address = (j << 2) + UNSAFE.ARRAY_INT_BASE_OFFSET; + int v = UNSAFE.getInt(a, address); + if (v == 0) { + sum++; + } + } + } + } + return sum; + } + + static public void main(String[] args) { + boolean[] flags = new boolean[10]; + for (int i = 0; i < flags.length; i++) { + flags[i] = true; + } + int[] array = new int[10]; + for (int i = 0; i < 20000; i++) { + test1(array, flags, true, 0); + } + for (int i = 0; i < flags.length; i++) { + flags[i] = false; + } + test1(array, flags, true, Long.MAX_VALUE/4); + + for (int i = 0; i < flags.length; i++) { + flags[i] = true; + } + for (int i = 0; i < 20000; i++) { + test2(array, flags, true, 0); + } + for (int i = 0; i < flags.length; i++) { + flags[i] = false; + } + test2(array, flags, true, Long.MAX_VALUE/4); + } +}