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