8077504: Unsafe load can loose control dependency and cause crash

Node::depends_only_on_test() should return false for Unsafe loads

Reviewed-by: kvn, adinn
This commit is contained in:
Roland Westrelin 2015-05-21 13:54:07 +02:00
parent 9f6b61b959
commit a3c77df5f1
13 changed files with 228 additions and 67 deletions

View File

@ -1457,18 +1457,18 @@ void GraphKit::set_all_memory_call(Node* call, bool separate_io_proj) {
// 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(ctl, mem, adr, adr_type, t, mo);
ld = LoadLNode::make_atomic(ctl, mem, adr, adr_type, t, mo, control_dependency);
} else if (require_atomic_access && bt == T_DOUBLE) {
ld = LoadDNode::make_atomic(ctl, mem, adr, adr_type, t, mo);
ld = LoadDNode::make_atomic(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()) {

View File

@ -512,21 +512,24 @@ class GraphKit : public Phase {
// 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.

View File

@ -2631,7 +2631,9 @@ bool LibraryCallKit::inline_unsafe_access(bool is_native_ptr, bool is_store, Bas
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:
@ -5488,7 +5490,7 @@ Node * LibraryCallKit::load_field_from_object(Node * fromObj, const char * field
}
// 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.

View File

@ -437,7 +437,13 @@ class Invariance : public StackObj {
}
}
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);

View File

@ -844,7 +844,7 @@ void Matcher::init_spill_mask( Node *ret ) {
MachNode *spillCP = match_tree(new LoadNNode(NULL,mem,fp,atp,TypeInstPtr::BOTTOM,MemNode::unordered));
#endif
MachNode *spillI = match_tree(new LoadINode(NULL,mem,fp,atp,TypeInt::INT,MemNode::unordered));
MachNode *spillL = match_tree(new LoadLNode(NULL,mem,fp,atp,TypeLong::LONG,MemNode::unordered,false));
MachNode *spillL = match_tree(new LoadLNode(NULL,mem,fp,atp,TypeLong::LONG,MemNode::unordered, LoadNode::DependsOnlyOnTest, false));
MachNode *spillF = match_tree(new LoadFNode(NULL,mem,fp,atp,Type::FLOAT,MemNode::unordered));
MachNode *spillD = match_tree(new LoadDNode(NULL,mem,fp,atp,Type::DOUBLE,MemNode::unordered));
MachNode *spillP = match_tree(new LoadPNode(NULL,mem,fp,atp,TypeInstPtr::BOTTOM,MemNode::unordered));

View File

@ -784,6 +784,9 @@ void LoadNode::dump_spec(outputStream *st) const {
// 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
@ -800,7 +803,7 @@ bool LoadNode::is_immutable_value(Node* adr) {
//----------------------------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
@ -816,39 +819,39 @@ Node *LoadNode::make(PhaseGVN& gvn, Node *ctl, Node *mem, Node *adr, const TypeP
rt->isa_oopptr() || is_immutable_value(adr),
"raw memory operations should have control edge");
switch (bt) {
case T_BOOLEAN: return new LoadUBNode(ctl, mem, adr, adr_type, rt->is_int(), mo);
case T_BYTE: return new LoadBNode (ctl, mem, adr, adr_type, rt->is_int(), mo);
case T_INT: return new LoadINode (ctl, mem, adr, adr_type, rt->is_int(), mo);
case T_CHAR: return new LoadUSNode(ctl, mem, adr, adr_type, rt->is_int(), mo);
case T_SHORT: return new LoadSNode (ctl, mem, adr, adr_type, rt->is_int(), mo);
case T_LONG: return new LoadLNode (ctl, mem, adr, adr_type, rt->is_long(), mo);
case T_FLOAT: return new LoadFNode (ctl, mem, adr, adr_type, rt, mo);
case T_DOUBLE: return new LoadDNode (ctl, mem, adr, adr_type, rt, mo);
case T_ADDRESS: return new LoadPNode (ctl, mem, adr, adr_type, rt->is_ptr(), mo);
case T_BOOLEAN: return new LoadUBNode(ctl, mem, adr, adr_type, rt->is_int(), mo, control_dependency);
case T_BYTE: return new LoadBNode (ctl, mem, adr, adr_type, rt->is_int(), mo, control_dependency);
case T_INT: return new LoadINode (ctl, mem, adr, adr_type, rt->is_int(), mo, control_dependency);
case T_CHAR: return new LoadUSNode(ctl, mem, adr, adr_type, rt->is_int(), mo, control_dependency);
case T_SHORT: return new LoadSNode (ctl, mem, adr, adr_type, rt->is_int(), mo, control_dependency);
case T_LONG: return new LoadLNode (ctl, mem, adr, adr_type, rt->is_long(), mo, control_dependency);
case T_FLOAT: return new LoadFNode (ctl, mem, adr, adr_type, rt, mo, control_dependency);
case T_DOUBLE: return new LoadDNode (ctl, mem, adr, adr_type, rt, mo, control_dependency);
case T_ADDRESS: return new 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 LoadNNode(ctl, mem, adr, adr_type, rt->make_narrowoop(), mo));
Node* load = gvn.transform(new LoadNNode(ctl, mem, adr, adr_type, rt->make_narrowoop(), mo, control_dependency));
return new 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 LoadPNode(ctl, mem, adr, adr_type, rt->is_oopptr(), mo);
return new LoadPNode(ctl, mem, adr, adr_type, rt->is_oopptr(), mo, control_dependency);
}
}
ShouldNotReachHere();
return (LoadNode*)NULL;
}
LoadLNode* LoadLNode::make_atomic(Node* ctl, Node* mem, Node* adr, const TypePtr* adr_type, const Type* rt, MemOrd mo) {
LoadLNode* LoadLNode::make_atomic(Node* ctl, Node* mem, Node* adr, const TypePtr* adr_type, const Type* rt, MemOrd mo, ControlDependency control_dependency) {
bool require_atomic = true;
return new LoadLNode(ctl, mem, adr, adr_type, rt->is_long(), mo, require_atomic);
return new LoadLNode(ctl, mem, adr, adr_type, rt->is_long(), mo, control_dependency, require_atomic);
}
LoadDNode* LoadDNode::make_atomic(Node* ctl, Node* mem, Node* adr, const TypePtr* adr_type, const Type* rt, MemOrd mo) {
LoadDNode* LoadDNode::make_atomic(Node* ctl, Node* mem, Node* adr, const TypePtr* adr_type, const Type* rt, MemOrd mo, ControlDependency control_dependency) {
bool require_atomic = true;
return new LoadDNode(ctl, mem, adr, adr_type, rt, mo, require_atomic);
return new LoadDNode(ctl, mem, adr, adr_type, rt, mo, control_dependency, require_atomic);
}

View File

@ -137,7 +137,33 @@ public:
//------------------------------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
@ -154,8 +180,8 @@ protected:
virtual Node* find_previous_arraycopy(PhaseTransform* phase, Node* ld_alloc, Node*& mem, bool can_see_stored_value) const;
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(); }
@ -166,7 +192,8 @@ public:
// 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
@ -234,16 +261,15 @@ protected:
// 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);
@ -256,8 +282,8 @@ public:
// 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);
@ -270,8 +296,8 @@ public:
// 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);
@ -284,8 +310,8 @@ public:
// 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);
@ -298,8 +324,8 @@ public:
// 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; }
@ -331,15 +357,15 @@ class LoadLNode : public LoadNode {
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(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);
@ -352,8 +378,8 @@ public:
// 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;
};
@ -361,8 +387,8 @@ public:
// 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; }
@ -382,15 +408,15 @@ class LoadDNode : public LoadNode {
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(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);
@ -403,8 +429,8 @@ public:
// 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;
};
@ -412,8 +438,8 @@ public:
// 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; }
@ -425,8 +451,8 @@ public:
// 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; }

View File

@ -235,7 +235,7 @@ void Parse::do_get_xxx(Node* obj, ciField* field, bool is_field) {
//
MemNode::MemOrd mo = is_vol ? MemNode::acquire : MemNode::unordered;
bool needs_atomic_access = is_vol || AlwaysAtomicAccesses;
Node* ld = make_load(NULL, adr, type, bt, adr_type, mo, needs_atomic_access);
Node* ld = make_load(NULL, adr, type, bt, adr_type, mo, LoadNode::DependsOnlyOnTest, needs_atomic_access);
// Adjust Java stack
if (type2size[bt] == 1)

View File

@ -1631,7 +1631,7 @@ void SuperWord::output() {
}
Node* adr = low_adr->in(MemNode::Address);
const TypePtr* atyp = n->adr_type();
vn = LoadVectorNode::make(opc, ctl, mem, adr, atyp, vlen, velt_basic_type(n));
vn = LoadVectorNode::make(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
@ -2280,6 +2280,19 @@ Node* SuperWord::executed_last(Node_List* p) {
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.

View File

@ -428,6 +428,7 @@ class SuperWord : public ResourceObj {
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

View File

@ -406,9 +406,11 @@ PackNode* PackNode::binary_tree_pack(int lo, int hi) {
// Return the vector version of a scalar load node.
LoadVectorNode* LoadVectorNode::make(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 LoadVectorNode(ctl, mem, adr, atyp, vt);
return new LoadVectorNode(ctl, mem, adr, atyp, vt, control_dependency);
}
// Return the vector version of a scalar store node.

View File

@ -454,8 +454,8 @@ class XorVNode : public VectorNode {
// 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);
}
@ -471,7 +471,9 @@ class LoadVectorNode : public LoadNode {
virtual int store_Opcode() const { return Op_StoreVector; }
static LoadVectorNode* make(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--------------------------------

View File

@ -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);
}
}