< prev index next >

src/share/vm/opto/graphKit.cpp

Print this page

        

@@ -39,10 +39,11 @@
 #include "opto/machnode.hpp"
 #include "opto/opaquenode.hpp"
 #include "opto/parse.hpp"
 #include "opto/rootnode.hpp"
 #include "opto/runtime.hpp"
+#include "opto/shenandoahSupport.hpp"
 #include "runtime/deoptimization.hpp"
 #include "runtime/sharedRuntime.hpp"
 
 //----------------------------GraphKit-----------------------------------------
 // Main utility constructor.

@@ -813,11 +814,11 @@
 #endif //ASSERT
 
 // Helper function for enforcing certain bytecodes to reexecute if
 // deoptimization happens
 static bool should_reexecute_implied_by_bytecode(JVMState *jvms, bool is_anewarray) {
-  ciMethod* cur_method = jvms->method();
+  ciMethod* cur_method = jvms->has_method() ? jvms->method() : NULL;
   int       cur_bci   = jvms->bci();
   if (cur_method != NULL && cur_bci != InvocationEntryBci) {
     Bytecodes::Code code = cur_method->java_code_at_bci(cur_bci);
     return Interpreter::bytecode_should_reexecute(code) ||
            is_anewarray && code == Bytecodes::_multianewarray;

@@ -1151,20 +1152,27 @@
 //-------------------------load_object_klass-----------------------------------
 Node* GraphKit::load_object_klass(Node* obj) {
   // Special-case a fresh allocation to avoid building nodes:
   Node* akls = AllocateNode::Ideal_klass(obj, &_gvn);
   if (akls != NULL)  return akls;
+  if (ShenandoahVerifyReadsToFromSpace) {
+    obj = shenandoah_read_barrier(obj);
+  }
   Node* k_adr = basic_plus_adr(obj, oopDesc::klass_offset_in_bytes());
   return _gvn.transform(LoadKlassNode::make(_gvn, NULL, immutable_memory(), k_adr, TypeInstPtr::KLASS));
 }
 
 //-------------------------load_array_length-----------------------------------
 Node* GraphKit::load_array_length(Node* array) {
   // Special-case a fresh allocation to avoid building nodes:
   AllocateArrayNode* alloc = AllocateArrayNode::Ideal_array_allocation(array, &_gvn);
   Node *alen;
   if (alloc == NULL) {
+    if (ShenandoahVerifyReadsToFromSpace) {
+      array = shenandoah_read_barrier(array);
+    }
+
     Node *r_adr = basic_plus_adr(array, arrayOopDesc::length_offset_in_bytes());
     alen = _gvn.transform( new LoadRangeNode(0, immutable_memory(), r_adr, TypeInt::POS));
   } else {
     alen = alloc->Ideal_length();
     Node* ccast = alloc->make_ideal_length(_gvn.type(array)->is_oopptr(), &_gvn);

@@ -1517,10 +1525,11 @@
 
   BarrierSet* bs = Universe::heap()->barrier_set();
   set_control(ctl);
   switch (bs->kind()) {
     case BarrierSet::G1SATBCTLogging:
+    case BarrierSet::ShenandoahBarrierSet:
       g1_write_barrier_pre(do_load, obj, adr, adr_idx, val, val_type, pre_val, bt);
       break;
 
     case BarrierSet::CardTableForRS:
     case BarrierSet::CardTableExtension:

@@ -1535,10 +1544,11 @@
 
 bool GraphKit::can_move_pre_barrier() const {
   BarrierSet* bs = Universe::heap()->barrier_set();
   switch (bs->kind()) {
     case BarrierSet::G1SATBCTLogging:
+    case BarrierSet::ShenandoahBarrierSet:
       return true; // Can move it if no safepoint
 
     case BarrierSet::CardTableForRS:
     case BarrierSet::CardTableExtension:
     case BarrierSet::ModRef:

@@ -1569,10 +1579,11 @@
     case BarrierSet::CardTableExtension:
       write_barrier_post(store, obj, adr, adr_idx, val, use_precise);
       break;
 
     case BarrierSet::ModRef:
+    case BarrierSet::ShenandoahBarrierSet:
       break;
 
     default      :
       ShouldNotReachHere();
 

@@ -1676,10 +1687,13 @@
 void GraphKit::set_arguments_for_java_call(CallJavaNode* call) {
   // Add the call arguments:
   uint nargs = call->method()->arg_size();
   for (uint i = 0; i < nargs; i++) {
     Node* arg = argument(i);
+    if (ShenandoahVerifyReadsToFromSpace && call->is_CallDynamicJava() && i == 0) {
+      arg = shenandoah_read_barrier(arg);
+    }
     call->init_req(i + TypeFunc::Parms, arg);
   }
 }
 
 //---------------------------set_edges_for_java_call---------------------------

@@ -2917,10 +2931,14 @@
         not_null_obj = cast_obj;
       }
     }
   }
 
+  if (ShenandoahVerifyReadsToFromSpace) {
+    not_null_obj = shenandoah_read_barrier(not_null_obj);
+  }
+
   // Load the object's klass
   Node* obj_klass = load_object_klass(not_null_obj);
 
   // Generate the subtype check
   Node* not_subtype_ctrl = gen_subtype_check(obj_klass, superklass);

@@ -2998,10 +3016,14 @@
 
   // Null check; get casted pointer; set region slot 3
   Node* null_ctl = top();
   Node* not_null_obj = null_check_oop(obj, &null_ctl, never_see_null, safe_for_replace, speculative_not_null);
 
+  if (ShenandoahVerifyReadsToFromSpace) {
+    not_null_obj = shenandoah_read_barrier(not_null_obj);
+  }
+
   // If not_null_obj is dead, only null-path is taken
   if (stopped()) {              // Doing instance-of on a NULL?
     set_control(null_ctl);
     return null();
   }

@@ -3147,10 +3169,12 @@
   if (stopped())                // Dead monitor?
     return NULL;
 
   assert(dead_locals_are_killed(), "should kill locals before sync. point");
 
+  obj = shenandoah_write_barrier(obj);
+
   // Box the stack location
   Node* box = _gvn.transform(new BoxLockNode(next_monitor()));
   Node* mem = reset_memory();
 
   FastLockNode * flock = _gvn.transform(new FastLockNode(0, obj, box) )->as_FastLock();

@@ -3620,10 +3644,14 @@
 // Given an oop pointer or raw pointer, see if it feeds from an AllocateNode.
 AllocateNode* AllocateNode::Ideal_allocation(Node* ptr, PhaseTransform* phase) {
   if (ptr == NULL) {     // reduce dumb test in callers
     return NULL;
   }
+
+  // Attempt to see through Shenandoah barriers.
+  ptr = ShenandoahBarrierNode::skip_through_barrier(ptr);
+
   if (ptr->is_CheckCastPP()) { // strip only one raw-to-oop cast
     ptr = ptr->in(1);
     if (ptr == NULL) return NULL;
   }
   // Return NULL for allocations with several casts:

@@ -4272,10 +4300,13 @@
     int offset_offset = java_lang_String::offset_offset_in_bytes();
     const TypeInstPtr* string_type = TypeInstPtr::make(TypePtr::NotNull, C->env()->String_klass(),
                                                        false, NULL, 0);
     const TypePtr* offset_field_type = string_type->add_offset(offset_offset);
     int offset_field_idx = C->get_alias_index(offset_field_type);
+
+    str = shenandoah_read_barrier(str);
+
     return make_load(ctrl,
                      basic_plus_adr(str, str, offset_offset),
                      TypeInt::INT, T_INT, offset_field_idx, MemNode::unordered);
   } else {
     return intcon(0);

@@ -4287,10 +4318,13 @@
     int count_offset = java_lang_String::count_offset_in_bytes();
     const TypeInstPtr* string_type = TypeInstPtr::make(TypePtr::NotNull, C->env()->String_klass(),
                                                        false, NULL, 0);
     const TypePtr* count_field_type = string_type->add_offset(count_offset);
     int count_field_idx = C->get_alias_index(count_field_type);
+
+    str = shenandoah_read_barrier(str);
+
     return make_load(ctrl,
                      basic_plus_adr(str, str, count_offset),
                      TypeInt::INT, T_INT, count_field_idx, MemNode::unordered);
   } else {
     return load_array_length(load_String_value(ctrl, str));

@@ -4304,10 +4338,13 @@
   const TypePtr* value_field_type = string_type->add_offset(value_offset);
   const TypeAryPtr*  value_type = TypeAryPtr::make(TypePtr::NotNull,
                                                    TypeAry::make(TypeInt::CHAR,TypeInt::POS),
                                                    ciTypeArrayKlass::make(T_CHAR), true, 0);
   int value_field_idx = C->get_alias_index(value_field_type);
+
+  str = shenandoah_read_barrier(str);
+
   Node* load = make_load(ctrl, basic_plus_adr(str, str, value_offset),
                          value_type, T_OBJECT, value_field_idx, MemNode::unordered);
   // String.value field is known to be @Stable.
   if (UseImplicitStableValues) {
     load = cast_array_to_stable(load, value_type);

@@ -4319,34 +4356,238 @@
   int offset_offset = java_lang_String::offset_offset_in_bytes();
   const TypeInstPtr* string_type = TypeInstPtr::make(TypePtr::NotNull, C->env()->String_klass(),
                                                      false, NULL, 0);
   const TypePtr* offset_field_type = string_type->add_offset(offset_offset);
   int offset_field_idx = C->get_alias_index(offset_field_type);
-  store_to_memory(ctrl, basic_plus_adr(str, offset_offset),
+
+  // TODO: Use incoming ctrl.
+  str = shenandoah_write_barrier(str);
+
+  store_to_memory(UseShenandoahGC ? control() : ctrl, basic_plus_adr(str, offset_offset),
                   value, T_INT, offset_field_idx, MemNode::unordered);
 }
 
 void GraphKit::store_String_value(Node* ctrl, Node* str, Node* value) {
   int value_offset = java_lang_String::value_offset_in_bytes();
   const TypeInstPtr* string_type = TypeInstPtr::make(TypePtr::NotNull, C->env()->String_klass(),
                                                      false, NULL, 0);
   const TypePtr* value_field_type = string_type->add_offset(value_offset);
 
-  store_oop_to_object(ctrl, str,  basic_plus_adr(str, value_offset), value_field_type,
+  // TODO: Use incoming ctrl.
+  str = shenandoah_write_barrier(str);
+  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);
 }
 
 void GraphKit::store_String_length(Node* ctrl, Node* str, Node* value) {
   int count_offset = java_lang_String::count_offset_in_bytes();
   const TypeInstPtr* string_type = TypeInstPtr::make(TypePtr::NotNull, C->env()->String_klass(),
                                                      false, NULL, 0);
   const TypePtr* count_field_type = string_type->add_offset(count_offset);
   int count_field_idx = C->get_alias_index(count_field_type);
-  store_to_memory(ctrl, basic_plus_adr(str, count_offset),
+
+  // TODO: Use incoming ctrl.
+  str = shenandoah_write_barrier(str);
+
+  store_to_memory(UseShenandoahGC ? control() : ctrl, basic_plus_adr(str, count_offset),
                   value, T_INT, count_field_idx, MemNode::unordered);
 }
 
 Node* GraphKit::cast_array_to_stable(Node* ary, const TypeAryPtr* ary_type) {
   // Reify the property as a CastPP node in Ideal graph to comply with monotonicity
   // assumption of CCP analysis.
   return _gvn.transform(new CastPPNode(ary, ary_type->cast_to_stable(true)));
 }
+
+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();
+    if (obj_type->higher_equal(TypePtr::NULL_PTR)) {
+      // tty->print_cr("killed barrier for NULL object");
+      return obj;
+    }
+    const TypePtr* adr_type = obj_type->is_ptr()->add_offset(-8);
+    Node* mem = use_mem ? memory(adr_type) : immutable_memory();
+
+    if (! ShenandoahBarrierNode::needs_barrier(&_gvn, NULL, obj, mem)) {
+      // We know it is null, no barrier needed.
+      return obj;
+    }
+
+
+    if (obj_type->meet(TypePtr::NULL_PTR) == obj_type->remove_speculative()) {
+
+      // We don't know if it's null or not. Need null-check.
+      enum { _not_null_path = 1, _null_path, PATH_LIMIT };
+      RegionNode* region = new RegionNode(PATH_LIMIT);
+      Node*       phi    = new PhiNode(region, obj_type);
+      Node* null_ctrl = top();
+      Node* not_null_obj = null_check_oop(obj, &null_ctrl);
+
+      region->init_req(_null_path, null_ctrl);
+      phi   ->init_req(_null_path, obj);
+
+      Node* ctrl = use_ctrl ? control() : NULL;
+      ShenandoahReadBarrierNode* rb = new ShenandoahReadBarrierNode(ctrl, mem, not_null_obj);
+      Node* n = _gvn.transform(rb);
+
+      region->init_req(_not_null_path, control());
+      phi   ->init_req(_not_null_path, n);
+
+      set_control(_gvn.transform(region));
+      record_for_igvn(region);
+      return _gvn.transform(phi);
+
+    } else {
+      // We know it is not null. Simple barrier is sufficient.
+      Node* ctrl = use_ctrl ? control() : NULL;
+      ShenandoahReadBarrierNode* rb = new ShenandoahReadBarrierNode(ctrl, mem, obj);
+      Node* n = _gvn.transform(rb);
+      record_for_igvn(n);
+      return n;
+    }
+
+  } else {
+    return obj;
+  }
+}
+
+Node* GraphKit::shenandoah_write_barrier(Node* obj) {
+
+  if (UseShenandoahGC && ShenandoahWriteBarrier) {
+
+    if (! ShenandoahBarrierNode::needs_barrier(&_gvn, NULL, obj, NULL)) {
+      return obj;
+    }
+    const Type* obj_type = obj->bottom_type();
+    const TypePtr* adr_type = obj_type->is_ptr()->add_offset(-8);
+    // tty->print_cr("memory at:");
+    // adr_type->dump();
+    // tty->print_cr("\n");
+    // memory(adr_type)->dump();
+    if (obj_type->meet(TypePtr::NULL_PTR) == obj_type->remove_speculative()) {
+      // We don't know if it's null or not. Need null-check.
+      enum { _not_null_path = 1, _null_path, PATH_LIMIT };
+      RegionNode* region = new RegionNode(PATH_LIMIT);
+      Node*       phi    = new PhiNode(region, obj_type);
+      Node*    memphi    = PhiNode::make(region, memory(adr_type), Type::MEMORY, C->alias_type(adr_type)->adr_type());
+
+      Node* prev_mem = memory(adr_type);
+      Node* null_ctrl = top();
+      Node* not_null_obj = null_check_oop(obj, &null_ctrl);
+
+      region->init_req(_null_path, null_ctrl);
+      phi   ->init_req(_null_path, null());
+      memphi->init_req(_null_path, prev_mem);
+
+      ShenandoahWriteBarrierNode* wb = new ShenandoahWriteBarrierNode(NULL, memory(adr_type), not_null_obj);
+      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);
+      }
+
+      region->init_req(_not_null_path, control());
+      phi   ->init_req(_not_null_path, n);
+      memphi->init_req(_not_null_path, memory(adr_type));
+
+      set_control(_gvn.transform(region));
+      record_for_igvn(region);
+      set_memory(_gvn.transform(memphi), adr_type);
+
+      Node* res_val = _gvn.transform(phi);
+      // replace_in_map(obj, res_val);
+      return res_val;
+    } else {
+      // We know it is not null. Simple barrier is sufficient.
+      ShenandoahWriteBarrierNode* wb = new ShenandoahWriteBarrierNode(NULL, memory(adr_type), obj);
+      Node* n = _gvn.transform(wb);
+      if (n == wb) {
+        Node* proj = _gvn.transform(new ShenandoahWBMemProjNode(wb));
+        set_memory(proj, adr_type);
+      }
+      // replace_in_map(obj, n);
+      record_for_igvn(n);
+      return n;
+    }
+
+  } else {
+    return obj;
+  }
+}
+
+void GraphKit::shenandoah_acmp_barrier(Node*& a, Node*& b) {
+  if (UseShenandoahGC) {
+    const Type* a_type = a->bottom_type();
+    const Type* b_type = b->bottom_type();
+    if (a_type->higher_equal(TypePtr::NULL_PTR) || b_type->higher_equal(TypePtr::NULL_PTR)) {
+      // We know one arg is gonna be null. No need for barriers.
+      // tty->print_cr("eliminate acmp barrier on null");
+      return;
+    }
+    /*
+    if ((!a_type->isa_oopptr()) || (!b_type->isa_oopptr())) {
+      a_type->dump();
+      b_type->dump();
+    }
+    */
+    if (a_type->is_oopptr()->const_oop() != NULL && b_type->is_oopptr()->const_oop() != NULL ) {
+      // We know one arg is inlined constant. No need for barriers.
+      // tty->print_cr("eliminate acmp barrier on constant");
+      return;
+    }
+    if (a->Opcode() == Op_ShenandoahWriteBarrier && b->Opcode() == Op_ShenandoahWriteBarrier) {
+      // We know one arg is already write-barrier'd. No need for barriers.
+      // tty->print_cr("eliminate acmp barrier on write barrier");
+      return;
+    }
+    if (AllocateNode::Ideal_allocation(a, &_gvn) != NULL || AllocateNode::Ideal_allocation(b, &_gvn) != NULL) {
+      // We know one arg is already in to-space. No need for barriers.
+      // tty->print_cr("eliminate acmp barrier on new obj");
+      return;
+    }
+
+    enum { _equal = 1, _not_equal, PATH_LIMIT };
+    RegionNode* region = new RegionNode(PATH_LIMIT);
+    PhiNode* phiA = PhiNode::make(region, a);
+    PhiNode* phiB = PhiNode::make(region, b);
+
+    Node* cmp = _gvn.transform(new CmpPNode(b, a));
+    Node* tst = _gvn.transform(new BoolNode(cmp, BoolTest::eq));
+
+    // TODO: Use profiling data.
+    IfNode* iff = create_and_map_if(control(), tst, PROB_FAIR, COUNT_UNKNOWN);
+    Node* iftrue = _gvn.transform(new IfTrueNode(iff));
+    Node* iffalse = _gvn.transform(new IfFalseNode(iff));
+
+    // Equal path: Use original values.
+    region->init_req(_equal, iftrue);
+    phiA->init_req(_equal, a);
+    phiB->init_req(_equal, b);
+
+    // Unequal path: retry after read barriers.
+    set_control(iffalse);
+    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);
+    phiB->init_req(_not_equal, b);
+
+    set_control(_gvn.transform(region));
+    record_for_igvn(region);
+
+    a = _gvn.transform(phiA);
+    b = _gvn.transform(phiB);
+  }
+}
< prev index next >