< prev index next >

src/hotspot/share/opto/escape.cpp

Print this page




  21  * questions.
  22  *
  23  */
  24 
  25 #include "precompiled.hpp"
  26 #include "ci/bcEscapeAnalyzer.hpp"
  27 #include "compiler/compileLog.hpp"
  28 #include "gc/shared/c2/barrierSetC2.hpp"
  29 #include "libadt/vectset.hpp"
  30 #include "memory/allocation.hpp"
  31 #include "memory/resourceArea.hpp"
  32 #include "opto/c2compiler.hpp"
  33 #include "opto/arraycopynode.hpp"
  34 #include "opto/callnode.hpp"
  35 #include "opto/cfgnode.hpp"
  36 #include "opto/compile.hpp"
  37 #include "opto/escape.hpp"
  38 #include "opto/phaseX.hpp"
  39 #include "opto/movenode.hpp"
  40 #include "opto/rootnode.hpp"

  41 #if INCLUDE_G1GC
  42 #include "gc/g1/g1ThreadLocalData.hpp"
  43 #endif // INCLUDE_G1GC



  44 
  45 ConnectionGraph::ConnectionGraph(Compile * C, PhaseIterGVN *igvn) :
  46   _nodes(C->comp_arena(), C->unique(), C->unique(), NULL),
  47   _in_worklist(C->comp_arena()),
  48   _next_pidx(0),
  49   _collecting(true),
  50   _verify(false),
  51   _compile(C),
  52   _igvn(igvn),
  53   _node_map(C->comp_arena()) {
  54   // Add unknown java object.
  55   add_java_object(C->top(), PointsToNode::GlobalEscape);
  56   phantom_obj = ptnode_adr(C->top()->_idx)->as_JavaObject();
  57   // Add ConP(#NULL) and ConN(#NULL) nodes.
  58   Node* oop_null = igvn->zerocon(T_OBJECT);
  59   assert(oop_null->_idx < nodes_size(), "should be created already");
  60   add_java_object(oop_null, PointsToNode::NoEscape);
  61   null_obj = ptnode_adr(oop_null->_idx)->as_JavaObject();
  62   if (UseCompressedOops) {
  63     Node* noop_null = igvn->zerocon(T_NARROWOOP);


 432       if (t == TypePtr::NULL_PTR || t == TypeNarrowOop::NULL_PTR) {
 433         es = PointsToNode::NoEscape;
 434       } else {
 435         es = PointsToNode::GlobalEscape;
 436       }
 437       add_java_object(n, es);
 438       break;
 439     }
 440     case Op_CreateEx: {
 441       // assume that all exception objects globally escape
 442       map_ideal_node(n, phantom_obj);
 443       break;
 444     }
 445     case Op_LoadKlass:
 446     case Op_LoadNKlass: {
 447       // Unknown class is loaded
 448       map_ideal_node(n, phantom_obj);
 449       break;
 450     }
 451     case Op_LoadP:




 452     case Op_LoadN:
 453     case Op_LoadPLocked: {
 454       add_objload_to_connection_graph(n, delayed_worklist);
 455       break;
 456     }
 457     case Op_Parm: {
 458       map_ideal_node(n, phantom_obj);
 459       break;
 460     }
 461     case Op_PartialSubtypeCheck: {
 462       // Produces Null or notNull and is used in only in CmpP so
 463       // phantom_obj could be used.
 464       map_ideal_node(n, phantom_obj); // Result is unknown
 465       break;
 466     }
 467     case Op_Phi: {
 468       // Using isa_ptr() instead of isa_oopptr() for LoadP and Phi because
 469       // ThreadLocal has RawPtr type.
 470       const Type* t = n->as_Phi()->type();
 471       if (t->make_ptr() != NULL) {
 472         add_local_var(n, PointsToNode::NoEscape);
 473         // Do not add edges during first iteration because some could be
 474         // not defined yet.
 475         delayed_worklist->push(n);
 476       }
 477       break;
 478     }
 479     case Op_Proj: {
 480       // we are only interested in the oop result projection from a call
 481       if (n->as_Proj()->_con == TypeFunc::Parms && n->in(0)->is_Call() &&
 482           n->in(0)->as_Call()->returns_pointer()) {
 483         add_local_var_and_edge(n, PointsToNode::NoEscape,
 484                                n->in(0), delayed_worklist);
 485       }







 486       break;
 487     }
 488     case Op_Rethrow: // Exception object escapes
 489     case Op_Return: {
 490       if (n->req() > TypeFunc::Parms &&
 491           igvn->type(n->in(TypeFunc::Parms))->isa_oopptr()) {
 492         // Treat Return value as LocalVar with GlobalEscape escape state.
 493         add_local_var_and_edge(n, PointsToNode::GlobalEscape,
 494                                n->in(TypeFunc::Parms), delayed_worklist);
 495       }
 496       break;
 497     }
 498     case Op_CompareAndExchangeP:
 499     case Op_CompareAndExchangeN:
 500     case Op_GetAndSetP:
 501     case Op_GetAndSetN: {
 502       add_objload_to_connection_graph(n, delayed_worklist);
 503       // fallthrough
 504     }
 505     case Op_StoreP:


 634     case Op_DecodeNKlass: {
 635       add_local_var_and_edge(n, PointsToNode::NoEscape,
 636                              n->in(1), NULL);
 637       break;
 638     }
 639     case Op_CMoveP: {
 640       for (uint i = CMoveNode::IfFalse; i < n->req(); i++) {
 641         Node* in = n->in(i);
 642         if (in == NULL)
 643           continue;  // ignore NULL
 644         Node* uncast_in = in->uncast();
 645         if (uncast_in->is_top() || uncast_in == n)
 646           continue;  // ignore top or inputs which go back this node
 647         PointsToNode* ptn = ptnode_adr(in->_idx);
 648         assert(ptn != NULL, "node should be registered");
 649         add_edge(n_ptn, ptn);
 650       }
 651       break;
 652     }
 653     case Op_LoadP:




 654     case Op_LoadN:
 655     case Op_LoadPLocked: {
 656       // Using isa_ptr() instead of isa_oopptr() for LoadP and Phi because
 657       // ThreadLocal has RawPtr type.
 658       const Type* t = _igvn->type(n);
 659       if (t->make_ptr() != NULL) {
 660         Node* adr = n->in(MemNode::Address);
 661         add_local_var_and_edge(n, PointsToNode::NoEscape, adr, NULL);
 662         break;
 663       }
 664       ELSE_FAIL("Op_LoadP");
 665     }
 666     case Op_Phi: {
 667       // Using isa_ptr() instead of isa_oopptr() for LoadP and Phi because
 668       // ThreadLocal has RawPtr type.
 669       const Type* t = n->as_Phi()->type();
 670       if (t->make_ptr() != NULL) {
 671         for (uint i = 1; i < n->req(); i++) {
 672           Node* in = n->in(i);
 673           if (in == NULL)
 674             continue;  // ignore NULL
 675           Node* uncast_in = in->uncast();
 676           if (uncast_in->is_top() || uncast_in == n)
 677             continue;  // ignore top or inputs which go back this node
 678           PointsToNode* ptn = ptnode_adr(in->_idx);
 679           assert(ptn != NULL, "node should be registered");
 680           add_edge(n_ptn, ptn);
 681         }
 682         break;
 683       }
 684       ELSE_FAIL("Op_Phi");
 685     }
 686     case Op_Proj: {
 687       // we are only interested in the oop result projection from a call
 688       if (n->as_Proj()->_con == TypeFunc::Parms && n->in(0)->is_Call() &&
 689           n->in(0)->as_Call()->returns_pointer()) {
 690         add_local_var_and_edge(n, PointsToNode::NoEscape, n->in(0), NULL);
 691         break;
 692       }








 693       ELSE_FAIL("Op_Proj");
 694     }
 695     case Op_Rethrow: // Exception object escapes
 696     case Op_Return: {
 697       if (n->req() > TypeFunc::Parms &&
 698           _igvn->type(n->in(TypeFunc::Parms))->isa_oopptr()) {
 699         // Treat Return value as LocalVar with GlobalEscape escape state.
 700         add_local_var_and_edge(n, PointsToNode::GlobalEscape,
 701                                n->in(TypeFunc::Parms), NULL);
 702         break;
 703       }
 704       ELSE_FAIL("Op_Return");
 705     }
 706     case Op_StoreP:
 707     case Op_StoreN:
 708     case Op_StoreNKlass:
 709     case Op_StorePConditional:
 710     case Op_CompareAndExchangeP:
 711     case Op_CompareAndExchangeN:
 712     case Op_CompareAndSwapP:


3146         // (through CheckCastPP nodes) even for debug info.
3147         Node* m = use->in(TypeFunc::Memory);
3148         if (m->is_MergeMem()) {
3149           assert(_mergemem_worklist.contains(m->as_MergeMem()), "EA: missing MergeMem node in the worklist");
3150         }
3151       } else if (use->Opcode() == Op_EncodeISOArray) {
3152         if (use->in(MemNode::Memory) == n || use->in(3) == n) {
3153           // EncodeISOArray overwrites destination array
3154           memnode_worklist.append_if_missing(use);
3155         }
3156       } else {
3157         uint op = use->Opcode();
3158         if ((op == Op_StrCompressedCopy || op == Op_StrInflatedCopy) &&
3159             (use->in(MemNode::Memory) == n)) {
3160           // They overwrite memory edge corresponding to destination array,
3161           memnode_worklist.append_if_missing(use);
3162         } else if (!(op == Op_CmpP || op == Op_Conv2B ||
3163               op == Op_CastP2X || op == Op_StoreCM ||
3164               op == Op_FastLock || op == Op_AryEq || op == Op_StrComp || op == Op_HasNegatives ||
3165               op == Op_StrCompressedCopy || op == Op_StrInflatedCopy ||
3166               op == Op_StrEquals || op == Op_StrIndexOf || op == Op_StrIndexOfChar)) {

3167           n->dump();
3168           use->dump();
3169           assert(false, "EA: missing allocation reference path");
3170         }
3171 #endif
3172       }
3173     }
3174 
3175   }
3176 
3177   // Go over all ArrayCopy nodes and if one of the inputs has a unique
3178   // type, record it in the ArrayCopy node so we know what memory this
3179   // node uses/modified.
3180   for (int next = 0; next < arraycopy_worklist.length(); next++) {
3181     ArrayCopyNode* ac = arraycopy_worklist.at(next);
3182     Node* dest = ac->in(ArrayCopyNode::Dest);
3183     if (dest->is_AddP()) {
3184       dest = get_addp_base(dest);
3185     }
3186     JavaObjectNode* jobj = unique_java_object(dest);




  21  * questions.
  22  *
  23  */
  24 
  25 #include "precompiled.hpp"
  26 #include "ci/bcEscapeAnalyzer.hpp"
  27 #include "compiler/compileLog.hpp"
  28 #include "gc/shared/c2/barrierSetC2.hpp"
  29 #include "libadt/vectset.hpp"
  30 #include "memory/allocation.hpp"
  31 #include "memory/resourceArea.hpp"
  32 #include "opto/c2compiler.hpp"
  33 #include "opto/arraycopynode.hpp"
  34 #include "opto/callnode.hpp"
  35 #include "opto/cfgnode.hpp"
  36 #include "opto/compile.hpp"
  37 #include "opto/escape.hpp"
  38 #include "opto/phaseX.hpp"
  39 #include "opto/movenode.hpp"
  40 #include "opto/rootnode.hpp"
  41 #include "utilities/macros.hpp"
  42 #if INCLUDE_G1GC
  43 #include "gc/g1/g1ThreadLocalData.hpp"
  44 #endif // INCLUDE_G1GC
  45 #if INCLUDE_ZGC
  46 #include "gc/z/c2/zBarrierSetC2.hpp"
  47 #endif
  48 
  49 ConnectionGraph::ConnectionGraph(Compile * C, PhaseIterGVN *igvn) :
  50   _nodes(C->comp_arena(), C->unique(), C->unique(), NULL),
  51   _in_worklist(C->comp_arena()),
  52   _next_pidx(0),
  53   _collecting(true),
  54   _verify(false),
  55   _compile(C),
  56   _igvn(igvn),
  57   _node_map(C->comp_arena()) {
  58   // Add unknown java object.
  59   add_java_object(C->top(), PointsToNode::GlobalEscape);
  60   phantom_obj = ptnode_adr(C->top()->_idx)->as_JavaObject();
  61   // Add ConP(#NULL) and ConN(#NULL) nodes.
  62   Node* oop_null = igvn->zerocon(T_OBJECT);
  63   assert(oop_null->_idx < nodes_size(), "should be created already");
  64   add_java_object(oop_null, PointsToNode::NoEscape);
  65   null_obj = ptnode_adr(oop_null->_idx)->as_JavaObject();
  66   if (UseCompressedOops) {
  67     Node* noop_null = igvn->zerocon(T_NARROWOOP);


 436       if (t == TypePtr::NULL_PTR || t == TypeNarrowOop::NULL_PTR) {
 437         es = PointsToNode::NoEscape;
 438       } else {
 439         es = PointsToNode::GlobalEscape;
 440       }
 441       add_java_object(n, es);
 442       break;
 443     }
 444     case Op_CreateEx: {
 445       // assume that all exception objects globally escape
 446       map_ideal_node(n, phantom_obj);
 447       break;
 448     }
 449     case Op_LoadKlass:
 450     case Op_LoadNKlass: {
 451       // Unknown class is loaded
 452       map_ideal_node(n, phantom_obj);
 453       break;
 454     }
 455     case Op_LoadP:
 456 #if INCLUDE_ZGC
 457     case Op_LoadBarrierSlowReg:
 458     case Op_LoadBarrierWeakSlowReg:
 459 #endif
 460     case Op_LoadN:
 461     case Op_LoadPLocked: {
 462       add_objload_to_connection_graph(n, delayed_worklist);
 463       break;
 464     }
 465     case Op_Parm: {
 466       map_ideal_node(n, phantom_obj);
 467       break;
 468     }
 469     case Op_PartialSubtypeCheck: {
 470       // Produces Null or notNull and is used in only in CmpP so
 471       // phantom_obj could be used.
 472       map_ideal_node(n, phantom_obj); // Result is unknown
 473       break;
 474     }
 475     case Op_Phi: {
 476       // Using isa_ptr() instead of isa_oopptr() for LoadP and Phi because
 477       // ThreadLocal has RawPtr type.
 478       const Type* t = n->as_Phi()->type();
 479       if (t->make_ptr() != NULL) {
 480         add_local_var(n, PointsToNode::NoEscape);
 481         // Do not add edges during first iteration because some could be
 482         // not defined yet.
 483         delayed_worklist->push(n);
 484       }
 485       break;
 486     }
 487     case Op_Proj: {
 488       // we are only interested in the oop result projection from a call
 489       if (n->as_Proj()->_con == TypeFunc::Parms && n->in(0)->is_Call() &&
 490           n->in(0)->as_Call()->returns_pointer()) {
 491         add_local_var_and_edge(n, PointsToNode::NoEscape,
 492                                n->in(0), delayed_worklist);
 493       }
 494 #if INCLUDE_ZGC
 495       else if (UseZGC) {
 496         if (n->as_Proj()->_con == LoadBarrierNode::Oop && n->in(0)->is_LoadBarrier()) {
 497           add_local_var_and_edge(n, PointsToNode::NoEscape, n->in(0)->in(LoadBarrierNode::Oop), delayed_worklist);
 498         }
 499       }
 500 #endif
 501       break;
 502     }
 503     case Op_Rethrow: // Exception object escapes
 504     case Op_Return: {
 505       if (n->req() > TypeFunc::Parms &&
 506           igvn->type(n->in(TypeFunc::Parms))->isa_oopptr()) {
 507         // Treat Return value as LocalVar with GlobalEscape escape state.
 508         add_local_var_and_edge(n, PointsToNode::GlobalEscape,
 509                                n->in(TypeFunc::Parms), delayed_worklist);
 510       }
 511       break;
 512     }
 513     case Op_CompareAndExchangeP:
 514     case Op_CompareAndExchangeN:
 515     case Op_GetAndSetP:
 516     case Op_GetAndSetN: {
 517       add_objload_to_connection_graph(n, delayed_worklist);
 518       // fallthrough
 519     }
 520     case Op_StoreP:


 649     case Op_DecodeNKlass: {
 650       add_local_var_and_edge(n, PointsToNode::NoEscape,
 651                              n->in(1), NULL);
 652       break;
 653     }
 654     case Op_CMoveP: {
 655       for (uint i = CMoveNode::IfFalse; i < n->req(); i++) {
 656         Node* in = n->in(i);
 657         if (in == NULL)
 658           continue;  // ignore NULL
 659         Node* uncast_in = in->uncast();
 660         if (uncast_in->is_top() || uncast_in == n)
 661           continue;  // ignore top or inputs which go back this node
 662         PointsToNode* ptn = ptnode_adr(in->_idx);
 663         assert(ptn != NULL, "node should be registered");
 664         add_edge(n_ptn, ptn);
 665       }
 666       break;
 667     }
 668     case Op_LoadP:
 669 #if INCLUDE_ZGC
 670     case Op_LoadBarrierSlowReg:
 671     case Op_LoadBarrierWeakSlowReg:
 672 #endif
 673     case Op_LoadN:
 674     case Op_LoadPLocked: {
 675       // Using isa_ptr() instead of isa_oopptr() for LoadP and Phi because
 676       // ThreadLocal has RawPtr type.
 677       const Type* t = _igvn->type(n);
 678       if (t->make_ptr() != NULL) {
 679         Node* adr = n->in(MemNode::Address);
 680         add_local_var_and_edge(n, PointsToNode::NoEscape, adr, NULL);
 681         break;
 682       }
 683       ELSE_FAIL("Op_LoadP");
 684     }
 685     case Op_Phi: {
 686       // Using isa_ptr() instead of isa_oopptr() for LoadP and Phi because
 687       // ThreadLocal has RawPtr type.
 688       const Type* t = n->as_Phi()->type();
 689       if (t->make_ptr() != NULL) {
 690         for (uint i = 1; i < n->req(); i++) {
 691           Node* in = n->in(i);
 692           if (in == NULL)
 693             continue;  // ignore NULL
 694           Node* uncast_in = in->uncast();
 695           if (uncast_in->is_top() || uncast_in == n)
 696             continue;  // ignore top or inputs which go back this node
 697           PointsToNode* ptn = ptnode_adr(in->_idx);
 698           assert(ptn != NULL, "node should be registered");
 699           add_edge(n_ptn, ptn);
 700         }
 701         break;
 702       }
 703       ELSE_FAIL("Op_Phi");
 704     }
 705     case Op_Proj: {
 706       // we are only interested in the oop result projection from a call
 707       if (n->as_Proj()->_con == TypeFunc::Parms && n->in(0)->is_Call() &&
 708           n->in(0)->as_Call()->returns_pointer()) {
 709         add_local_var_and_edge(n, PointsToNode::NoEscape, n->in(0), NULL);
 710         break;
 711       }
 712 #if INCLUDE_ZGC
 713       else if (UseZGC) {
 714         if (n->as_Proj()->_con == LoadBarrierNode::Oop && n->in(0)->is_LoadBarrier()) {
 715           add_local_var_and_edge(n, PointsToNode::NoEscape, n->in(0)->in(LoadBarrierNode::Oop), NULL);
 716           break;
 717         }
 718       }
 719 #endif
 720       ELSE_FAIL("Op_Proj");
 721     }
 722     case Op_Rethrow: // Exception object escapes
 723     case Op_Return: {
 724       if (n->req() > TypeFunc::Parms &&
 725           _igvn->type(n->in(TypeFunc::Parms))->isa_oopptr()) {
 726         // Treat Return value as LocalVar with GlobalEscape escape state.
 727         add_local_var_and_edge(n, PointsToNode::GlobalEscape,
 728                                n->in(TypeFunc::Parms), NULL);
 729         break;
 730       }
 731       ELSE_FAIL("Op_Return");
 732     }
 733     case Op_StoreP:
 734     case Op_StoreN:
 735     case Op_StoreNKlass:
 736     case Op_StorePConditional:
 737     case Op_CompareAndExchangeP:
 738     case Op_CompareAndExchangeN:
 739     case Op_CompareAndSwapP:


3173         // (through CheckCastPP nodes) even for debug info.
3174         Node* m = use->in(TypeFunc::Memory);
3175         if (m->is_MergeMem()) {
3176           assert(_mergemem_worklist.contains(m->as_MergeMem()), "EA: missing MergeMem node in the worklist");
3177         }
3178       } else if (use->Opcode() == Op_EncodeISOArray) {
3179         if (use->in(MemNode::Memory) == n || use->in(3) == n) {
3180           // EncodeISOArray overwrites destination array
3181           memnode_worklist.append_if_missing(use);
3182         }
3183       } else {
3184         uint op = use->Opcode();
3185         if ((op == Op_StrCompressedCopy || op == Op_StrInflatedCopy) &&
3186             (use->in(MemNode::Memory) == n)) {
3187           // They overwrite memory edge corresponding to destination array,
3188           memnode_worklist.append_if_missing(use);
3189         } else if (!(op == Op_CmpP || op == Op_Conv2B ||
3190               op == Op_CastP2X || op == Op_StoreCM ||
3191               op == Op_FastLock || op == Op_AryEq || op == Op_StrComp || op == Op_HasNegatives ||
3192               op == Op_StrCompressedCopy || op == Op_StrInflatedCopy ||
3193               op == Op_StrEquals || op == Op_StrIndexOf || op == Op_StrIndexOfChar ||
3194               BarrierSet::barrier_set()->barrier_set_c2()->is_gc_barrier_node(use))) {
3195           n->dump();
3196           use->dump();
3197           assert(false, "EA: missing allocation reference path");
3198         }
3199 #endif
3200       }
3201     }
3202 
3203   }
3204 
3205   // Go over all ArrayCopy nodes and if one of the inputs has a unique
3206   // type, record it in the ArrayCopy node so we know what memory this
3207   // node uses/modified.
3208   for (int next = 0; next < arraycopy_worklist.length(); next++) {
3209     ArrayCopyNode* ac = arraycopy_worklist.at(next);
3210     Node* dest = ac->in(ArrayCopyNode::Dest);
3211     if (dest->is_AddP()) {
3212       dest = get_addp_base(dest);
3213     }
3214     JavaObjectNode* jobj = unique_java_object(dest);


< prev index next >