< prev index next >

src/hotspot/share/opto/escape.cpp

Print this page
rev 52560 : 8213615: GC/C2 abstraction for escape analysis

@@ -23,10 +23,11 @@
  */
 
 #include "precompiled.hpp"
 #include "ci/bcEscapeAnalyzer.hpp"
 #include "compiler/compileLog.hpp"
+#include "gc/shared/barrierSet.hpp"
 #include "gc/shared/c2/barrierSetC2.hpp"
 #include "libadt/vectset.hpp"
 #include "memory/allocation.hpp"
 #include "memory/resourceArea.hpp"
 #include "opto/c2compiler.hpp"

@@ -37,16 +38,10 @@
 #include "opto/escape.hpp"
 #include "opto/phaseX.hpp"
 #include "opto/movenode.hpp"
 #include "opto/rootnode.hpp"
 #include "utilities/macros.hpp"
-#if INCLUDE_G1GC
-#include "gc/g1/g1ThreadLocalData.hpp"
-#endif // INCLUDE_G1GC
-#if INCLUDE_ZGC
-#include "gc/z/c2/zBarrierSetC2.hpp"
-#endif
 
 ConnectionGraph::ConnectionGraph(Compile * C, PhaseIterGVN *igvn) :
   _nodes(C->comp_arena(), C->unique(), C->unique(), NULL),
   _in_worklist(C->comp_arena()),
   _next_pidx(0),

@@ -386,10 +381,14 @@
   // point to phantom_obj.
   if (n_ptn == phantom_obj || n_ptn == null_obj)
     return; // Skip predefined nodes.
 
   int opcode = n->Opcode();
+  bool gc_handled = BarrierSet::barrier_set()->barrier_set_c2()->escape_add_to_con_graph(this, igvn, delayed_worklist, n, opcode);
+  if (gc_handled) {
+    return; // Ignore node if already handled by GC.
+  }
   switch (opcode) {
     case Op_AddP: {
       Node* base = get_addp_base(n);
       PointsToNode* ptn_base = ptnode_adr(base->_idx);
       // Field nodes are created for all field types. They are used in

@@ -451,14 +450,10 @@
       // Unknown class is loaded
       map_ideal_node(n, phantom_obj);
       break;
     }
     case Op_LoadP:
-#if INCLUDE_ZGC
-    case Op_LoadBarrierSlowReg:
-    case Op_LoadBarrierWeakSlowReg:
-#endif
     case Op_LoadN:
     case Op_LoadPLocked: {
       add_objload_to_connection_graph(n, delayed_worklist);
       break;
     }

@@ -489,17 +484,10 @@
       if (n->as_Proj()->_con == TypeFunc::Parms && n->in(0)->is_Call() &&
           n->in(0)->as_Call()->returns_pointer()) {
         add_local_var_and_edge(n, PointsToNode::NoEscape,
                                n->in(0), delayed_worklist);
       }
-#if INCLUDE_ZGC
-      else if (UseZGC) {
-        if (n->as_Proj()->_con == LoadBarrierNode::Oop && n->in(0)->is_LoadBarrier()) {
-          add_local_var_and_edge(n, PointsToNode::NoEscape, n->in(0)->in(LoadBarrierNode::Oop), delayed_worklist);
-        }
-      }
-#endif
       break;
     }
     case Op_Rethrow: // Exception object escapes
     case Op_Return: {
       if (n->req() > TypeFunc::Parms &&

@@ -523,66 +511,11 @@
     case Op_StorePConditional:
     case Op_WeakCompareAndSwapP:
     case Op_WeakCompareAndSwapN:
     case Op_CompareAndSwapP:
     case Op_CompareAndSwapN: {
-      Node* adr = n->in(MemNode::Address);
-      const Type *adr_type = igvn->type(adr);
-      adr_type = adr_type->make_ptr();
-      if (adr_type == NULL) {
-        break; // skip dead nodes
-      }
-      if (   adr_type->isa_oopptr()
-          || (   (opcode == Op_StoreP || opcode == Op_StoreN || opcode == Op_StoreNKlass)
-              && adr_type == TypeRawPtr::NOTNULL
-              && adr->in(AddPNode::Address)->is_Proj()
-              && adr->in(AddPNode::Address)->in(0)->is_Allocate())) {
-        delayed_worklist->push(n); // Process it later.
-#ifdef ASSERT
-        assert(adr->is_AddP(), "expecting an AddP");
-        if (adr_type == TypeRawPtr::NOTNULL) {
-          // Verify a raw address for a store captured by Initialize node.
-          int offs = (int)igvn->find_intptr_t_con(adr->in(AddPNode::Offset), Type::OffsetBot);
-          assert(offs != Type::OffsetBot, "offset must be a constant");
-        }
-#endif
-      } else {
-        // Ignore copy the displaced header to the BoxNode (OSR compilation).
-        if (adr->is_BoxLock())
-          break;
-        // Stored value escapes in unsafe access.
-        if ((opcode == Op_StoreP) && adr_type->isa_rawptr()) {
-          // Pointer stores in G1 barriers looks like unsafe access.
-          // Ignore such stores to be able scalar replace non-escaping
-          // allocations.
-#if INCLUDE_G1GC
-          if (UseG1GC && adr->is_AddP()) {
-            Node* base = get_addp_base(adr);
-            if (base->Opcode() == Op_LoadP &&
-                base->in(MemNode::Address)->is_AddP()) {
-              adr = base->in(MemNode::Address);
-              Node* tls = get_addp_base(adr);
-              if (tls->Opcode() == Op_ThreadLocal) {
-                int offs = (int)igvn->find_intptr_t_con(adr->in(AddPNode::Offset), Type::OffsetBot);
-                if (offs == in_bytes(G1ThreadLocalData::satb_mark_queue_buffer_offset())) {
-                  break; // G1 pre barrier previous oop value store.
-                }
-                if (offs == in_bytes(G1ThreadLocalData::dirty_card_queue_buffer_offset())) {
-                  break; // G1 post barrier card address store.
-                }
-              }
-            }
-          }
-#endif
-          delayed_worklist->push(n); // Process unsafe access later.
-          break;
-        }
-#ifdef ASSERT
-        n->dump(1);
-        assert(false, "not unsafe or G1 barrier raw StoreP");
-#endif
-      }
+      add_to_congraph_unsafe_access(n, opcode, delayed_worklist);
       break;
     }
     case Op_AryEq:
     case Op_HasNegatives:
     case Op_StrComp:

@@ -631,10 +564,14 @@
   }
   assert(n->is_Store() || n->is_LoadStore() ||
          (n_ptn != NULL) && (n_ptn->ideal_node() != NULL),
          "node should be registered already");
   int opcode = n->Opcode();
+  bool gc_handled = BarrierSet::barrier_set()->barrier_set_c2()->escape_add_final_edges(this, _igvn, n, opcode);
+  if (gc_handled) {
+    return; // Ignore node if already handled by GC.
+  }
   switch (opcode) {
     case Op_AddP: {
       Node* base = get_addp_base(n);
       PointsToNode* ptn_base = ptnode_adr(base->_idx);
       assert(ptn_base != NULL, "field's base should be registered");

@@ -664,14 +601,10 @@
         add_edge(n_ptn, ptn);
       }
       break;
     }
     case Op_LoadP:
-#if INCLUDE_ZGC
-    case Op_LoadBarrierSlowReg:
-    case Op_LoadBarrierWeakSlowReg:
-#endif
     case Op_LoadN:
     case Op_LoadPLocked: {
       // Using isa_ptr() instead of isa_oopptr() for LoadP and Phi because
       // ThreadLocal has RawPtr type.
       const Type* t = _igvn->type(n);

@@ -707,18 +640,10 @@
       if (n->as_Proj()->_con == TypeFunc::Parms && n->in(0)->is_Call() &&
           n->in(0)->as_Call()->returns_pointer()) {
         add_local_var_and_edge(n, PointsToNode::NoEscape, n->in(0), NULL);
         break;
       }
-#if INCLUDE_ZGC
-      else if (UseZGC) {
-        if (n->as_Proj()->_con == LoadBarrierNode::Oop && n->in(0)->is_LoadBarrier()) {
-          add_local_var_and_edge(n, PointsToNode::NoEscape, n->in(0)->in(LoadBarrierNode::Oop), NULL);
-          break;
-        }
-      }
-#endif
       ELSE_FAIL("Op_Proj");
     }
     case Op_Rethrow: // Exception object escapes
     case Op_Return: {
       if (n->req() > TypeFunc::Parms &&

@@ -741,50 +666,15 @@
     case Op_WeakCompareAndSwapP:
     case Op_WeakCompareAndSwapN:
     case Op_GetAndSetP:
     case Op_GetAndSetN: {
       Node* adr = n->in(MemNode::Address);
-      const Type *adr_type = _igvn->type(adr);
-      adr_type = adr_type->make_ptr();
-#ifdef ASSERT
-      if (adr_type == NULL) {
-        n->dump(1);
-        assert(adr_type != NULL, "dead node should not be on list");
-        break;
-      }
-#endif
       if (opcode == Op_GetAndSetP || opcode == Op_GetAndSetN ||
           opcode == Op_CompareAndExchangeN || opcode == Op_CompareAndExchangeP) {
         add_local_var_and_edge(n, PointsToNode::NoEscape, adr, NULL);
       }
-      if (   adr_type->isa_oopptr()
-          || (   (opcode == Op_StoreP || opcode == Op_StoreN || opcode == Op_StoreNKlass)
-              && adr_type == TypeRawPtr::NOTNULL
-              && adr->in(AddPNode::Address)->is_Proj()
-              && adr->in(AddPNode::Address)->in(0)->is_Allocate())) {
-        // Point Address to Value
-        PointsToNode* adr_ptn = ptnode_adr(adr->_idx);
-        assert(adr_ptn != NULL &&
-               adr_ptn->as_Field()->is_oop(), "node should be registered");
-        Node *val = n->in(MemNode::ValueIn);
-        PointsToNode* ptn = ptnode_adr(val->_idx);
-        assert(ptn != NULL, "node should be registered");
-        add_edge(adr_ptn, ptn);
-        break;
-      } else if ((opcode == Op_StoreP) && adr_type->isa_rawptr()) {
-        // Stored value escapes in unsafe access.
-        Node *val = n->in(MemNode::ValueIn);
-        PointsToNode* ptn = ptnode_adr(val->_idx);
-        assert(ptn != NULL, "node should be registered");
-        set_escape_state(ptn, PointsToNode::GlobalEscape);
-        // Add edge to object for unsafe access with offset.
-        PointsToNode* adr_ptn = ptnode_adr(adr->_idx);
-        assert(adr_ptn != NULL, "node should be registered");
-        if (adr_ptn->is_Field()) {
-          assert(adr_ptn->as_Field()->is_oop(), "should be oop field");
-          add_edge(adr_ptn, ptn);
-        }
+      if (add_final_edges_unsafe_access(n, opcode)) {
         break;
       }
       ELSE_FAIL("Op_StoreP");
     }
     case Op_AryEq:

@@ -825,10 +715,97 @@
     }
   }
   return;
 }
 
+void ConnectionGraph::add_to_congraph_unsafe_access(Node* n, uint opcode, Unique_Node_List* delayed_worklist) {
+  Node* adr = n->in(MemNode::Address);
+  const Type* adr_type = _igvn->type(adr);
+  adr_type = adr_type->make_ptr();
+  if (adr_type == NULL) {
+    return; // skip dead nodes
+  }
+  if (adr_type->isa_oopptr()
+      || ((opcode == Op_StoreP || opcode == Op_StoreN || opcode == Op_StoreNKlass)
+          && adr_type == TypeRawPtr::NOTNULL
+          && adr->in(AddPNode::Address)->is_Proj()
+          && adr->in(AddPNode::Address)->in(0)->is_Allocate())) {
+    delayed_worklist->push(n); // Process it later.
+#ifdef ASSERT
+    assert (adr->is_AddP(), "expecting an AddP");
+    if (adr_type == TypeRawPtr::NOTNULL) {
+      // Verify a raw address for a store captured by Initialize node.
+      int offs = (int) _igvn->find_intptr_t_con(adr->in(AddPNode::Offset), Type::OffsetBot);
+      assert(offs != Type::OffsetBot, "offset must be a constant");
+    }
+#endif
+  } else {
+    // Ignore copy the displaced header to the BoxNode (OSR compilation).
+    if (adr->is_BoxLock()) {
+      return;
+    }
+    // Stored value escapes in unsafe access.
+    if ((opcode == Op_StoreP) && adr_type->isa_rawptr()) {
+      delayed_worklist->push(n); // Process unsafe access later.
+      return;
+    }
+#ifdef ASSERT
+    n->dump(1);
+    assert(false, "not unsafe");
+#endif
+  }
+}
+
+bool ConnectionGraph::add_final_edges_unsafe_access(Node* n, uint opcode) {
+  Node* adr = n->in(MemNode::Address);
+  const Type *adr_type = _igvn->type(adr);
+  adr_type = adr_type->make_ptr();
+#ifdef ASSERT
+  if (adr_type == NULL) {
+    n->dump(1);
+    assert(adr_type != NULL, "dead node should not be on list");
+    return true;
+  }
+#endif
+
+  if (opcode == Op_GetAndSetP || opcode == Op_GetAndSetN ||
+      opcode == Op_CompareAndExchangeN || opcode == Op_CompareAndExchangeP) {
+    add_local_var_and_edge(n, PointsToNode::NoEscape, adr, NULL);
+  }
+
+  if (adr_type->isa_oopptr()
+      || ((opcode == Op_StoreP || opcode == Op_StoreN || opcode == Op_StoreNKlass)
+           && adr_type == TypeRawPtr::NOTNULL
+           && adr->in(AddPNode::Address)->is_Proj()
+           && adr->in(AddPNode::Address)->in(0)->is_Allocate())) {
+    // Point Address to Value
+    PointsToNode* adr_ptn = ptnode_adr(adr->_idx);
+    assert(adr_ptn != NULL &&
+           adr_ptn->as_Field()->is_oop(), "node should be registered");
+    Node* val = n->in(MemNode::ValueIn);
+    PointsToNode* ptn = ptnode_adr(val->_idx);
+    assert(ptn != NULL, "node should be registered");
+    add_edge(adr_ptn, ptn);
+    return true;
+  } else if ((opcode == Op_StoreP) && adr_type->isa_rawptr()) {
+    // Stored value escapes in unsafe access.
+    Node* val = n->in(MemNode::ValueIn);
+    PointsToNode* ptn = ptnode_adr(val->_idx);
+    assert(ptn != NULL, "node should be registered");
+    set_escape_state(ptn, PointsToNode::GlobalEscape);
+    // Add edge to object for unsafe access with offset.
+    PointsToNode* adr_ptn = ptnode_adr(adr->_idx);
+    assert(adr_ptn != NULL, "node should be registered");
+    if (adr_ptn->is_Field()) {
+      assert(adr_ptn->as_Field()->is_oop(), "should be oop field");
+      add_edge(adr_ptn, ptn);
+    }
+    return true;
+  }
+  return false;
+}
+
 void ConnectionGraph::add_call_node(CallNode* call) {
   assert(call->returns_pointer(), "only for call which returns pointer");
   uint call_idx = call->_idx;
   if (call->is_Allocate()) {
     Node* k = call->in(AllocateNode::KlassNode);

@@ -2098,11 +2075,12 @@
         bt = field->layout_type();
       } else {
         // Check for unsafe oop field access
         if (n->has_out_with(Op_StoreP, Op_LoadP, Op_StoreN, Op_LoadN) ||
             n->has_out_with(Op_GetAndSetP, Op_GetAndSetN, Op_CompareAndExchangeP, Op_CompareAndExchangeN) ||
-            n->has_out_with(Op_CompareAndSwapP, Op_CompareAndSwapN, Op_WeakCompareAndSwapP, Op_WeakCompareAndSwapN)) {
+            n->has_out_with(Op_CompareAndSwapP, Op_CompareAndSwapN, Op_WeakCompareAndSwapP, Op_WeakCompareAndSwapN) ||
+            BarrierSet::barrier_set()->barrier_set_c2()->escape_has_out_with_unsafe_object(n)) {
           bt = T_OBJECT;
           (*unsafe) = true;
         }
       }
     } else if (adr_type->isa_aryptr()) {

@@ -2116,11 +2094,12 @@
       }
     } else if (adr_type->isa_rawptr() || adr_type->isa_klassptr()) {
       // Allocation initialization, ThreadLocal field access, unsafe access
       if (n->has_out_with(Op_StoreP, Op_LoadP, Op_StoreN, Op_LoadN) ||
           n->has_out_with(Op_GetAndSetP, Op_GetAndSetN, Op_CompareAndExchangeP, Op_CompareAndExchangeN) ||
-          n->has_out_with(Op_CompareAndSwapP, Op_CompareAndSwapN, Op_WeakCompareAndSwapP, Op_WeakCompareAndSwapN)) {
+          n->has_out_with(Op_CompareAndSwapP, Op_CompareAndSwapN, Op_WeakCompareAndSwapP, Op_WeakCompareAndSwapN) ||
+          BarrierSet::barrier_set()->barrier_set_c2()->escape_has_out_with_unsafe_object(n)) {
         bt = T_OBJECT;
       }
     }
   }
   return (bt == T_OBJECT || bt == T_NARROWOOP || bt == T_ARRAY);

@@ -2357,11 +2336,12 @@
       Node* uncast_base = base->uncast();
       int opcode = uncast_base->Opcode();
       assert(opcode == Op_ConP || opcode == Op_ThreadLocal ||
              opcode == Op_CastX2P || uncast_base->is_DecodeNarrowPtr() ||
              (uncast_base->is_Mem() && (uncast_base->bottom_type()->isa_rawptr() != NULL)) ||
-             (uncast_base->is_Proj() && uncast_base->in(0)->is_Allocate()), "sanity");
+             (uncast_base->is_Proj() && uncast_base->in(0)->is_Allocate()) ||
+             BarrierSet::barrier_set()->barrier_set_c2()->escape_is_barrier_node(uncast_base), "sanity");
     }
   }
   return base;
 }
 

@@ -3090,10 +3070,11 @@
       if (!split_AddP(n, base)) continue; // wrong type from dead path
     } else if (n->is_Phi() ||
                n->is_CheckCastPP() ||
                n->is_EncodeP() ||
                n->is_DecodeN() ||
+               BarrierSet::barrier_set()->barrier_set_c2()->escape_is_barrier_node(n) ||
                (n->is_ConstraintCast() && n->Opcode() == Op_CastPP)) {
       if (visited.test_set(n->_idx)) {
         assert(n->is_Phi(), "loops only through Phi's");
         continue;  // already processed
       }

@@ -3160,10 +3141,11 @@
         alloc_worklist.append_if_missing(use);
       } else if (use->is_Phi() ||
                  use->is_CheckCastPP() ||
                  use->is_EncodeNarrowPtr() ||
                  use->is_DecodeNarrowPtr() ||
+                 BarrierSet::barrier_set()->barrier_set_c2()->escape_is_barrier_node(use) ||
                  (use->is_ConstraintCast() && use->Opcode() == Op_CastPP)) {
         alloc_worklist.append_if_missing(use);
 #ifdef ASSERT
       } else if (use->is_Mem()) {
         assert(use->in(MemNode::Address) != n, "EA: missing allocation reference path");

@@ -3562,5 +3544,10 @@
       tty->cr();
     }
   }
 }
 #endif
+
+void ConnectionGraph::record_for_optimizer(Node *n) {
+  _igvn->_worklist.push(n);
+  _igvn->add_users_to_worklist(n);
+}
< prev index next >