changeset 9447:3882524b04a9

Reduce memory dependencies of barriers for provingly independent barrier types, or when not needed, e.g. for read barriers on store-values.
author rkennke
date Tue, 18 Aug 2015 18:36:41 +0200
parents 553da5b66da3
children e45726f53c00
files src/share/vm/opto/graphKit.cpp src/share/vm/opto/graphKit.hpp src/share/vm/opto/library_call.cpp src/share/vm/opto/parse2.cpp src/share/vm/opto/parse3.cpp src/share/vm/opto/shenandoahSupport.cpp src/share/vm/opto/shenandoahSupport.hpp
diffstat 7 files changed, 136 insertions(+), 15 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/vm/opto/graphKit.cpp	Tue Aug 18 18:34:37 2015 +0200
+++ b/src/share/vm/opto/graphKit.cpp	Tue Aug 18 18:36:41 2015 +0200
@@ -4389,7 +4389,7 @@
   // TODO: See comment in load_String_offset().
   // TODO: Use incoming ctrl.
   str = shenandoah_write_barrier(str);
-  value = shenandoah_read_barrier(value);
+  value = shenandoah_read_barrier_nomem(value);
 
   store_oop_to_object(UseShenandoahGC ? control() : ctrl, str,  basic_plus_adr(str, value_offset), value_field_type,
       value, TypeAryPtr::CHARS, T_OBJECT, MemNode::unordered);
@@ -4416,7 +4416,15 @@
   return _gvn.transform(new CastPPNode(ary, ary_type->cast_to_stable(true)));
 }
 
-Node* GraphKit::shenandoah_read_barrier(Node* obj, bool use_ctrl) {
+Node* GraphKit::shenandoah_read_barrier(Node* obj) {
+  return shenandoah_read_barrier_impl(obj, false, true);
+}
+
+Node* GraphKit::shenandoah_read_barrier_nomem(Node* obj) {
+  return shenandoah_read_barrier_impl(obj, false, false);
+}
+
+Node* GraphKit::shenandoah_read_barrier_impl(Node* obj, bool use_ctrl, bool use_mem) {
 
   if (UseShenandoahGC && ShenandoahReadBarrier) {
     const Type* obj_type = obj->bottom_type();
@@ -4454,8 +4462,10 @@
     } else {
       // We know it is not null. Simple barrier is sufficient.
       Node* ctrl = use_ctrl ? control() : NULL;
-      ShenandoahReadBarrierNode* rb = new ShenandoahReadBarrierNode(ctrl, memory(adr_type), obj);
+      Node* mem = use_mem ? memory(adr_type) : immutable_memory();
+      ShenandoahReadBarrierNode* rb = new ShenandoahReadBarrierNode(ctrl, mem, obj);
       Node* n = _gvn.transform(rb);
+      record_for_igvn(n);
       return n;
     }
 
@@ -4507,11 +4517,10 @@
     } else {
       // We know it is not null. Simple barrier is sufficient.
       ShenandoahWriteBarrierNode* wb = new ShenandoahWriteBarrierNode(NULL, memory(adr_type), obj);
+      Node* proj = _gvn.transform(new ShenandoahWBMemProjNode(wb));
+      set_memory(proj, adr_type);
       Node* n = _gvn.transform(wb);
-      if (n == wb) { // New barrier needs memory projection.
-	Node* proj = _gvn.transform(new ShenandoahWBMemProjNode(n));
-	set_memory(proj, adr_type);
-      }
+      record_for_igvn(n);
       return n;
     }
 
@@ -4571,8 +4580,8 @@
 
     // Unequal path: retry after read barriers.
     set_control(iffalse);
-    a = shenandoah_read_barrier(a, true);
-    b = shenandoah_read_barrier(b, true);
+    a = shenandoah_read_barrier_impl(a, true, true);
+    b = shenandoah_read_barrier_impl(b, true, true);
 
     region->init_req(_not_equal, control());
     phiA->init_req(_not_equal, a);
--- a/src/share/vm/opto/graphKit.hpp	Tue Aug 18 18:34:37 2015 +0200
+++ b/src/share/vm/opto/graphKit.hpp	Tue Aug 18 18:36:41 2015 +0200
@@ -895,9 +895,12 @@
   // Produce new array node of stable type
   Node* cast_array_to_stable(Node* ary, const TypeAryPtr* ary_type);
 
-  Node* shenandoah_read_barrier(Node* obj, bool use_ctrl = false);
+  Node* shenandoah_read_barrier(Node* obj);
+  Node* shenandoah_read_barrier_nomem(Node* obj);
   Node* shenandoah_write_barrier(Node* obj);
   void shenandoah_acmp_barrier(Node*& a, Node*& b);
+private:
+  Node* shenandoah_read_barrier_impl(Node* obj, bool use_ctrl, bool use_mem);
 };
 
 // Helper class to support building of control flow branches. Upon
--- a/src/share/vm/opto/library_call.cpp	Tue Aug 18 18:34:37 2015 +0200
+++ b/src/share/vm/opto/library_call.cpp	Tue Aug 18 18:36:41 2015 +0200
@@ -2778,7 +2778,7 @@
     if (type != T_OBJECT ) {
       (void) store_to_memory(control(), adr, val, type, adr_type, mo, is_volatile);
     } else {
-      val = shenandoah_read_barrier(val);
+      val = shenandoah_read_barrier_nomem(val);
       // Possibly an oop being stored to Java heap or native memory
       if (!TypePtr::NULL_PTR->higher_equal(_gvn.type(heap_base_oop))) {
         // oop to Java heap.
@@ -2981,7 +2981,7 @@
     if (_gvn.type(newval) == TypePtr::NULL_PTR)
       newval = _gvn.makecon(TypePtr::NULL_PTR);
 
-    newval = shenandoah_read_barrier(newval);
+    newval = shenandoah_read_barrier_nomem(newval);
 
     // Reference stores need a store barrier.
     if (kind == LS_xchg) {
@@ -3184,7 +3184,7 @@
   const bool require_atomic_access = true;
   Node* store;
   if (type == T_OBJECT) { // reference stores need a store barrier.
-    val = shenandoah_read_barrier(val);
+    val = shenandoah_read_barrier_nomem(val);
     store = store_oop_to_unknown(control(), base, adr, adr_type, val, type, MemNode::release);
   }
   else {
--- a/src/share/vm/opto/parse2.cpp	Tue Aug 18 18:34:37 2015 +0200
+++ b/src/share/vm/opto/parse2.cpp	Tue Aug 18 18:36:41 2015 +0200
@@ -1732,7 +1732,7 @@
     // a is not used except for an assert. The address d already has the
     // write barrier. Adding a barrier on a only results in additional code
     // being generated.
-    c = shenandoah_read_barrier(c);
+    c = shenandoah_read_barrier_nomem(c);
     Node* store = store_oop_to_array(control(), a, d, adr_type, c, elemtype, T_OBJECT,
                                      StoreNode::release_if_reference(T_OBJECT));
     break;
--- a/src/share/vm/opto/parse3.cpp	Tue Aug 18 18:34:37 2015 +0200
+++ b/src/share/vm/opto/parse3.cpp	Tue Aug 18 18:36:41 2015 +0200
@@ -322,7 +322,7 @@
       field_type = TypeOopPtr::make_from_klass(field->type()->as_klass());
     }
 
-    val = shenandoah_read_barrier(val);
+    val = shenandoah_read_barrier_nomem(val);
 
     store = store_oop_to_object(control(), obj, adr, adr_type, val, field_type, bt, mo);
   } else {
--- a/src/share/vm/opto/shenandoahSupport.cpp	Tue Aug 18 18:34:37 2015 +0200
+++ b/src/share/vm/opto/shenandoahSupport.cpp	Tue Aug 18 18:36:41 2015 +0200
@@ -126,6 +126,108 @@
   return true;
 }
 
+bool ShenandoahReadBarrierNode::is_independent(const Type* in_type, const Type* this_type) const {
+  assert(in_type->isa_oopptr(), "expect oop ptr");
+  assert(this_type->isa_oopptr(), "expect oop ptr");
+  /*
+  if ((! in_type->isa_oopptr()) || (! this_type->isa_oopptr())) {
+#ifdef ASSERT
+    tty->print_cr("not oopptr");
+    tty->print("in:   "); in_type->dump(); tty->print_cr(" ");
+    tty->print("this: "); this_type->dump(); tty->print_cr(" ");
+#endif
+    return false;
+  }
+  */
+
+  ciKlass* in_kls = in_type->is_oopptr()->klass();
+  ciKlass* this_kls = this_type->is_oopptr()->klass();
+  if ((!in_kls->is_subclass_of(this_kls)) &&
+      (!this_kls->is_subclass_of(in_kls))) {
+#ifdef ASSERT
+    // tty->print_cr("independent: ");
+    // tty->print("in:   "); in_kls->print(); tty->print_cr(" ");
+    // tty->print("this: "); this_kls->print(); tty->print_cr(" ");
+#endif
+    return true;
+  }
+#ifdef ASSERT
+  // tty->print_cr("possibly dependend?");
+  // tty->print("in:   "); in_type->dump(); tty->print_cr(" ");
+  // tty->print("this: "); this_type->dump(); tty->print_cr(" ");
+#endif
+  return false;
+}
+
+Node* ShenandoahReadBarrierNode::Ideal(PhaseGVN *phase, bool can_reshape) {
+
+  if (! can_reshape) {
+    return NULL;
+  }
+
+  Node* input = in(Memory);
+  if (input->Opcode() == Op_ShenandoahWBMemProj) {
+    input = input->in(0);
+    assert(input->Opcode() == Op_ShenandoahWriteBarrier, "expect write barrier");
+    const Type* in_type = input->bottom_type(); // phase->type(input);
+    const Type* this_type = bottom_type(); //phase->type(this);
+    if (is_independent(in_type, this_type)) {
+      set_req(Memory, input->in(Memory));
+      return this;
+    }
+  }
+  return NULL;
+}
+
+uint ShenandoahWriteBarrierNode::count_rb_users(Node* n, GrowableArray<Node*>* phistack) const {
+  uint count = 0;
+  for (DUIterator_Fast jmax, j = n->fast_outs(jmax); j < jmax; j++) {
+    Node* o = n->fast_out(j);
+    if (o->Opcode() == Op_ShenandoahReadBarrier ||
+	o->Opcode() == Op_ShenandoahWriteBarrier) {
+      // tty->print("counting barrier"); o->dump();
+      count++;
+    } else if (o->isa_Phi()) {
+      if (! phistack->contains(o)) {
+	phistack->push(o);
+	count += count_rb_users(o, phistack);
+	phistack->pop();
+      }
+    } else {
+      // tty->print("not counting: "); o->dump();
+    }
+  }
+  return count;
+}
+
+Node* ShenandoahWriteBarrierNode::Ideal(PhaseGVN *phase, bool can_reshape) {
+
+  if (! can_reshape) return NULL;
+
+  if (in(Memory) == phase->C->immutable_memory()) return NULL;
+
+  Node* mem_proj = find_out_with(Op_ShenandoahWBMemProj);
+  if (mem_proj == NULL) {
+    // tty->print_cr("no mem proj: kill input mem");
+    set_req(Memory, phase->C->immutable_memory());
+    return this;
+  }
+
+  Arena* a = phase->arena();
+  GrowableArray<Node*>* phistack = new (a) GrowableArray<Node*>(a, 4, 0, NULL);
+  uint num_users = count_rb_users(mem_proj, phistack);
+  if (num_users == 0) {
+    // tty->print_cr("no users of mem projection. kill input mem");
+    set_req(Memory, phase->C->immutable_memory());
+    
+    // tty->print_cr("reshaped wb: ");
+    // dump();
+    return this;
+  }
+  // tty->print_cr("leave mem proj alone");
+  return NULL;
+}
+
 Node* ShenandoahBarrierNode::Identity(PhaseTransform* phase) {
 
 #ifdef ASSERT
--- a/src/share/vm/opto/shenandoahSupport.hpp	Tue Aug 18 18:34:37 2015 +0200
+++ b/src/share/vm/opto/shenandoahSupport.hpp	Tue Aug 18 18:36:41 2015 +0200
@@ -68,8 +68,12 @@
     : ShenandoahBarrierNode(ctrl, mem, obj) {
   }
 
+  virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
   virtual Node* Identity(PhaseTransform* phase);
   virtual int Opcode() const;
+private:
+  bool is_independent(const Type* in_type, const Type* this_type) const;
+
 };
 
 class ShenandoahWriteBarrierNode : public ShenandoahBarrierNode {
@@ -80,11 +84,14 @@
   }
 
   virtual int Opcode() const;
+  virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
   
   // virtual void set_req( uint i, Node *n ) {
   //   if (i == MemNode::Memory) { assert(n == Compiler::current()->immutable_memory(), "set only immutable mem on wb"); }
   //   Node::set_req(i, n);
   // }
+private:
+  uint count_rb_users(Node* n, GrowableArray<Node*>* phistack) const;
 };
 
 class ShenandoahWBMemProjNode : public ProjNode {