< prev index next >

src/share/vm/opto/callnode.cpp

Print this page
rev 8739 : 8004073: Implement C2 Ideal node specific dump() method
Summary: add Node::dump_rel() to dump a node and its related nodes (the notion of "related" depends on the node at hand); add Node::dump_comp() to dump a node in compact representation; add Node::dump_rel_comp() to dump a node and its related nodes in compact representation; add the required machinery; extend some C2 IR nodes with compact and related dumping
Reviewed-by:


  35 #include "opto/machnode.hpp"
  36 #include "opto/matcher.hpp"
  37 #include "opto/parse.hpp"
  38 #include "opto/regalloc.hpp"
  39 #include "opto/regmask.hpp"
  40 #include "opto/rootnode.hpp"
  41 #include "opto/runtime.hpp"
  42 
  43 // Portions of code courtesy of Clifford Click
  44 
  45 // Optimization - Graph Style
  46 
  47 //=============================================================================
  48 uint StartNode::size_of() const { return sizeof(*this); }
  49 uint StartNode::cmp( const Node &n ) const
  50 { return _domain == ((StartNode&)n)._domain; }
  51 const Type *StartNode::bottom_type() const { return _domain; }
  52 const Type *StartNode::Value(PhaseTransform *phase) const { return _domain; }
  53 #ifndef PRODUCT
  54 void StartNode::dump_spec(outputStream *st) const { st->print(" #"); _domain->dump_on(st);}

  55 #endif
  56 
  57 //------------------------------Ideal------------------------------------------
  58 Node *StartNode::Ideal(PhaseGVN *phase, bool can_reshape){
  59   return remove_dead_region(phase, can_reshape) ? this : NULL;
  60 }
  61 
  62 //------------------------------calling_convention-----------------------------
  63 void StartNode::calling_convention( BasicType* sig_bt, VMRegPair *parm_regs, uint argcnt ) const {
  64   Matcher::calling_convention( sig_bt, parm_regs, argcnt, false );
  65 }
  66 
  67 //------------------------------Registers--------------------------------------
  68 const RegMask &StartNode::in_RegMask(uint) const {
  69   return RegMask::Empty;
  70 }
  71 
  72 //------------------------------match------------------------------------------
  73 // Construct projections for incoming parameters, and their RegMask info
  74 Node *StartNode::match( const ProjNode *proj, const Matcher *match ) {


 104   fields[TypeFunc::Parms+0] = TypeRawPtr::BOTTOM;  // address of osr buffer
 105 
 106   return TypeTuple::make(TypeFunc::Parms+1, fields);
 107 }
 108 
 109 //=============================================================================
 110 const char * const ParmNode::names[TypeFunc::Parms+1] = {
 111   "Control", "I_O", "Memory", "FramePtr", "ReturnAdr", "Parms"
 112 };
 113 
 114 #ifndef PRODUCT
 115 void ParmNode::dump_spec(outputStream *st) const {
 116   if( _con < TypeFunc::Parms ) {
 117     st->print("%s", names[_con]);
 118   } else {
 119     st->print("Parm%d: ",_con-TypeFunc::Parms);
 120     // Verbose and WizardMode dump bottom_type for all nodes
 121     if( !Verbose && !WizardMode )   bottom_type()->dump_on(st);
 122   }
 123 }

















 124 #endif
 125 
 126 uint ParmNode::ideal_reg() const {
 127   switch( _con ) {
 128   case TypeFunc::Control  : // fall through
 129   case TypeFunc::I_O      : // fall through
 130   case TypeFunc::Memory   : return 0;
 131   case TypeFunc::FramePtr : // fall through
 132   case TypeFunc::ReturnAdr: return Op_RegP;
 133   default                 : assert( _con > TypeFunc::Parms, "" );
 134     // fall through
 135   case TypeFunc::Parms    : {
 136     // Type of argument being passed
 137     const Type *t = in(0)->as_Start()->_domain->field_at(_con);
 138     return t->ideal_reg();
 139   }
 140   }
 141   ShouldNotReachHere();
 142   return 0;
 143 }


 931 }
 932 
 933 bool CallNode::is_call_to_arraycopystub() const {
 934   if (_name != NULL && strstr(_name, "arraycopy") != 0) {
 935     return true;
 936   }
 937   return false;
 938 }
 939 
 940 //=============================================================================
 941 uint CallJavaNode::size_of() const { return sizeof(*this); }
 942 uint CallJavaNode::cmp( const Node &n ) const {
 943   CallJavaNode &call = (CallJavaNode&)n;
 944   return CallNode::cmp(call) && _method == call._method;
 945 }
 946 #ifndef PRODUCT
 947 void CallJavaNode::dump_spec(outputStream *st) const {
 948   if( _method ) _method->print_short_name(st);
 949   CallNode::dump_spec(st);
 950 }








 951 #endif
 952 
 953 //=============================================================================
 954 uint CallStaticJavaNode::size_of() const { return sizeof(*this); }
 955 uint CallStaticJavaNode::cmp( const Node &n ) const {
 956   CallStaticJavaNode &call = (CallStaticJavaNode&)n;
 957   return CallJavaNode::cmp(call);
 958 }
 959 
 960 //----------------------------uncommon_trap_request----------------------------
 961 // If this is an uncommon trap, return the request code, else zero.
 962 int CallStaticJavaNode::uncommon_trap_request() const {
 963   if (_name != NULL && !strcmp(_name, "uncommon_trap")) {
 964     return extract_uncommon_trap_request(this);
 965   }
 966   return 0;
 967 }
 968 int CallStaticJavaNode::extract_uncommon_trap_request(const Node* call) {
 969 #ifndef PRODUCT
 970   if (!(call->req() > TypeFunc::Parms &&


 978 #endif
 979   return call->in(TypeFunc::Parms)->bottom_type()->is_int()->get_con();
 980 }
 981 
 982 #ifndef PRODUCT
 983 void CallStaticJavaNode::dump_spec(outputStream *st) const {
 984   st->print("# Static ");
 985   if (_name != NULL) {
 986     st->print("%s", _name);
 987     int trap_req = uncommon_trap_request();
 988     if (trap_req != 0) {
 989       char buf[100];
 990       st->print("(%s)",
 991                  Deoptimization::format_trap_request(buf, sizeof(buf),
 992                                                      trap_req));
 993     }
 994     st->print(" ");
 995   }
 996   CallJavaNode::dump_spec(st);
 997 }










 998 #endif
 999 
1000 //=============================================================================
1001 uint CallDynamicJavaNode::size_of() const { return sizeof(*this); }
1002 uint CallDynamicJavaNode::cmp( const Node &n ) const {
1003   CallDynamicJavaNode &call = (CallDynamicJavaNode&)n;
1004   return CallJavaNode::cmp(call);
1005 }
1006 #ifndef PRODUCT
1007 void CallDynamicJavaNode::dump_spec(outputStream *st) const {
1008   st->print("# Dynamic ");
1009   CallJavaNode::dump_spec(st);
1010 }
1011 #endif
1012 
1013 //=============================================================================
1014 uint CallRuntimeNode::size_of() const { return sizeof(*this); }
1015 uint CallRuntimeNode::cmp( const Node &n ) const {
1016   CallRuntimeNode &call = (CallRuntimeNode&)n;
1017   return CallNode::cmp(call) && !strcmp(_name,call._name);


1113       // Useless Safepoint, so remove it
1114       return in(TypeFunc::Control);
1115     }
1116   }
1117 
1118   return this;
1119 }
1120 
1121 //------------------------------Value------------------------------------------
1122 const Type *SafePointNode::Value( PhaseTransform *phase ) const {
1123   if( phase->type(in(0)) == Type::TOP ) return Type::TOP;
1124   if( phase->eqv( in(0), this ) ) return Type::TOP; // Dead infinite loop
1125   return Type::CONTROL;
1126 }
1127 
1128 #ifndef PRODUCT
1129 void SafePointNode::dump_spec(outputStream *st) const {
1130   st->print(" SafePoint ");
1131   _replaced_nodes.dump(st);
1132 }













1133 #endif
1134 
1135 const RegMask &SafePointNode::in_RegMask(uint idx) const {
1136   if( idx < TypeFunc::Parms ) return RegMask::Empty;
1137   // Values outside the domain represent debug info
1138   return *(Compile::current()->matcher()->idealreg2debugmask[in(idx)->ideal_reg()]);
1139 }
1140 const RegMask &SafePointNode::out_RegMask() const {
1141   return RegMask::Empty;
1142 }
1143 
1144 
1145 void SafePointNode::grow_stack(JVMState* jvms, uint grow_by) {
1146   assert((int)grow_by > 0, "sanity");
1147   int monoff = jvms->monoff();
1148   int scloff = jvms->scloff();
1149   int endoff = jvms->endoff();
1150   assert(endoff == (int)req(), "no other states or debug info after me");
1151   Node* top = Compile::current()->top();
1152   for (uint i = 0; i < grow_by; i++) {


1659   return true;
1660 
1661 }
1662 
1663 #ifndef PRODUCT
1664 //
1665 // Create a counter which counts the number of times this lock is acquired
1666 //
1667 void AbstractLockNode::create_lock_counter(JVMState* state) {
1668   _counter = OptoRuntime::new_named_counter(state, NamedCounter::LockCounter);
1669 }
1670 
1671 void AbstractLockNode::set_eliminated_lock_counter() {
1672   if (_counter) {
1673     // Update the counter to indicate that this lock was eliminated.
1674     // The counter update code will stay around even though the
1675     // optimizer will eliminate the lock operation itself.
1676     _counter->set_tag(NamedCounter::EliminatedLockCounter);
1677   }
1678 }





















1679 #endif
1680 
1681 //=============================================================================
1682 Node *LockNode::Ideal(PhaseGVN *phase, bool can_reshape) {
1683 
1684   // perform any generic optimizations first (returns 'this' or NULL)
1685   Node *result = SafePointNode::Ideal(phase, can_reshape);
1686   if (result != NULL)  return result;
1687   // Don't bother trying to transform a dead node
1688   if (in(0) && in(0)->is_top())  return NULL;
1689 
1690   // Now see if we can optimize away this lock.  We don't actually
1691   // remove the locking here, we simply set the _eliminate flag which
1692   // prevents macro expansion from expanding the lock.  Since we don't
1693   // modify the graph, the value returned from this function is the
1694   // one computed above.
1695   if (can_reshape && EliminateLocks && !is_non_esc_obj()) {
1696     //
1697     // If we are locking an unescaped object, the lock/unlock is unnecessary
1698     //




  35 #include "opto/machnode.hpp"
  36 #include "opto/matcher.hpp"
  37 #include "opto/parse.hpp"
  38 #include "opto/regalloc.hpp"
  39 #include "opto/regmask.hpp"
  40 #include "opto/rootnode.hpp"
  41 #include "opto/runtime.hpp"
  42 
  43 // Portions of code courtesy of Clifford Click
  44 
  45 // Optimization - Graph Style
  46 
  47 //=============================================================================
  48 uint StartNode::size_of() const { return sizeof(*this); }
  49 uint StartNode::cmp( const Node &n ) const
  50 { return _domain == ((StartNode&)n)._domain; }
  51 const Type *StartNode::bottom_type() const { return _domain; }
  52 const Type *StartNode::Value(PhaseTransform *phase) const { return _domain; }
  53 #ifndef PRODUCT
  54 void StartNode::dump_spec(outputStream *st) const { st->print(" #"); _domain->dump_on(st);}
  55 void StartNode::dump_comp_spec(outputStream *st) const { /* empty */ }
  56 #endif
  57 
  58 //------------------------------Ideal------------------------------------------
  59 Node *StartNode::Ideal(PhaseGVN *phase, bool can_reshape){
  60   return remove_dead_region(phase, can_reshape) ? this : NULL;
  61 }
  62 
  63 //------------------------------calling_convention-----------------------------
  64 void StartNode::calling_convention( BasicType* sig_bt, VMRegPair *parm_regs, uint argcnt ) const {
  65   Matcher::calling_convention( sig_bt, parm_regs, argcnt, false );
  66 }
  67 
  68 //------------------------------Registers--------------------------------------
  69 const RegMask &StartNode::in_RegMask(uint) const {
  70   return RegMask::Empty;
  71 }
  72 
  73 //------------------------------match------------------------------------------
  74 // Construct projections for incoming parameters, and their RegMask info
  75 Node *StartNode::match( const ProjNode *proj, const Matcher *match ) {


 105   fields[TypeFunc::Parms+0] = TypeRawPtr::BOTTOM;  // address of osr buffer
 106 
 107   return TypeTuple::make(TypeFunc::Parms+1, fields);
 108 }
 109 
 110 //=============================================================================
 111 const char * const ParmNode::names[TypeFunc::Parms+1] = {
 112   "Control", "I_O", "Memory", "FramePtr", "ReturnAdr", "Parms"
 113 };
 114 
 115 #ifndef PRODUCT
 116 void ParmNode::dump_spec(outputStream *st) const {
 117   if( _con < TypeFunc::Parms ) {
 118     st->print("%s", names[_con]);
 119   } else {
 120     st->print("Parm%d: ",_con-TypeFunc::Parms);
 121     // Verbose and WizardMode dump bottom_type for all nodes
 122     if( !Verbose && !WizardMode )   bottom_type()->dump_on(st);
 123   }
 124 }
 125 
 126 void ParmNode::dump_comp_spec(outputStream *st) const {
 127   if (_con < TypeFunc::Parms) {
 128     st->print("%s", names[_con]);
 129   } else {
 130     st->print("%d:", _con-TypeFunc::Parms);
 131     // unconditionally dump bottom_type
 132     bottom_type()->dump_on(st);
 133   }
 134 }
 135 
 136 // For a ParmNode, all immediate inputs and outputs are considered relevant
 137 // both in compact and standard representation.
 138 void ParmNode::rel(GrowableArray<Node*> *in_rel, GrowableArray<Node*> *out_rel, bool compact) const {
 139   this->collect_nodes(in_rel, 1, false, false);
 140   this->collect_nodes(out_rel, -1, false, false);
 141 }
 142 #endif
 143 
 144 uint ParmNode::ideal_reg() const {
 145   switch( _con ) {
 146   case TypeFunc::Control  : // fall through
 147   case TypeFunc::I_O      : // fall through
 148   case TypeFunc::Memory   : return 0;
 149   case TypeFunc::FramePtr : // fall through
 150   case TypeFunc::ReturnAdr: return Op_RegP;
 151   default                 : assert( _con > TypeFunc::Parms, "" );
 152     // fall through
 153   case TypeFunc::Parms    : {
 154     // Type of argument being passed
 155     const Type *t = in(0)->as_Start()->_domain->field_at(_con);
 156     return t->ideal_reg();
 157   }
 158   }
 159   ShouldNotReachHere();
 160   return 0;
 161 }


 949 }
 950 
 951 bool CallNode::is_call_to_arraycopystub() const {
 952   if (_name != NULL && strstr(_name, "arraycopy") != 0) {
 953     return true;
 954   }
 955   return false;
 956 }
 957 
 958 //=============================================================================
 959 uint CallJavaNode::size_of() const { return sizeof(*this); }
 960 uint CallJavaNode::cmp( const Node &n ) const {
 961   CallJavaNode &call = (CallJavaNode&)n;
 962   return CallNode::cmp(call) && _method == call._method;
 963 }
 964 #ifndef PRODUCT
 965 void CallJavaNode::dump_spec(outputStream *st) const {
 966   if( _method ) _method->print_short_name(st);
 967   CallNode::dump_spec(st);
 968 }
 969 
 970 void CallJavaNode::dump_comp_spec(outputStream* st) const {
 971   if (_method) {
 972     _method->print_short_name(st);
 973   } else {
 974     st->print("<?>");
 975   }
 976 }
 977 #endif
 978 
 979 //=============================================================================
 980 uint CallStaticJavaNode::size_of() const { return sizeof(*this); }
 981 uint CallStaticJavaNode::cmp( const Node &n ) const {
 982   CallStaticJavaNode &call = (CallStaticJavaNode&)n;
 983   return CallJavaNode::cmp(call);
 984 }
 985 
 986 //----------------------------uncommon_trap_request----------------------------
 987 // If this is an uncommon trap, return the request code, else zero.
 988 int CallStaticJavaNode::uncommon_trap_request() const {
 989   if (_name != NULL && !strcmp(_name, "uncommon_trap")) {
 990     return extract_uncommon_trap_request(this);
 991   }
 992   return 0;
 993 }
 994 int CallStaticJavaNode::extract_uncommon_trap_request(const Node* call) {
 995 #ifndef PRODUCT
 996   if (!(call->req() > TypeFunc::Parms &&


1004 #endif
1005   return call->in(TypeFunc::Parms)->bottom_type()->is_int()->get_con();
1006 }
1007 
1008 #ifndef PRODUCT
1009 void CallStaticJavaNode::dump_spec(outputStream *st) const {
1010   st->print("# Static ");
1011   if (_name != NULL) {
1012     st->print("%s", _name);
1013     int trap_req = uncommon_trap_request();
1014     if (trap_req != 0) {
1015       char buf[100];
1016       st->print("(%s)",
1017                  Deoptimization::format_trap_request(buf, sizeof(buf),
1018                                                      trap_req));
1019     }
1020     st->print(" ");
1021   }
1022   CallJavaNode::dump_spec(st);
1023 }
1024 
1025 void CallStaticJavaNode::dump_comp_spec(outputStream* st) const {
1026   if (_method) {
1027     _method->print_short_name(st);
1028   } else if (_name) {
1029     st->print("%s", _name);
1030   } else {
1031     st->print("<?>");
1032   }
1033 }
1034 #endif
1035 
1036 //=============================================================================
1037 uint CallDynamicJavaNode::size_of() const { return sizeof(*this); }
1038 uint CallDynamicJavaNode::cmp( const Node &n ) const {
1039   CallDynamicJavaNode &call = (CallDynamicJavaNode&)n;
1040   return CallJavaNode::cmp(call);
1041 }
1042 #ifndef PRODUCT
1043 void CallDynamicJavaNode::dump_spec(outputStream *st) const {
1044   st->print("# Dynamic ");
1045   CallJavaNode::dump_spec(st);
1046 }
1047 #endif
1048 
1049 //=============================================================================
1050 uint CallRuntimeNode::size_of() const { return sizeof(*this); }
1051 uint CallRuntimeNode::cmp( const Node &n ) const {
1052   CallRuntimeNode &call = (CallRuntimeNode&)n;
1053   return CallNode::cmp(call) && !strcmp(_name,call._name);


1149       // Useless Safepoint, so remove it
1150       return in(TypeFunc::Control);
1151     }
1152   }
1153 
1154   return this;
1155 }
1156 
1157 //------------------------------Value------------------------------------------
1158 const Type *SafePointNode::Value( PhaseTransform *phase ) const {
1159   if( phase->type(in(0)) == Type::TOP ) return Type::TOP;
1160   if( phase->eqv( in(0), this ) ) return Type::TOP; // Dead infinite loop
1161   return Type::CONTROL;
1162 }
1163 
1164 #ifndef PRODUCT
1165 void SafePointNode::dump_spec(outputStream *st) const {
1166   st->print(" SafePoint ");
1167   _replaced_nodes.dump(st);
1168 }
1169 
1170 // The related nodes of a SafepointNode are all data inputs, excluding the
1171 // control boundary, as well as all outputs till level 2 (to include projection
1172 // nodes and targets). In compact mode, just include inputs till level 1 and
1173 // outputs as before.
1174 void SafePointNode::rel(GrowableArray<Node*> *in_rel, GrowableArray<Node*> *out_rel, bool compact) const {
1175   if (compact) {
1176     this->collect_nodes(in_rel, 1, false, false);
1177   } else {
1178     this->collect_nodes_in_all_data(in_rel, false);
1179   }
1180   this->collect_nodes(out_rel, -2, false, false);
1181 }
1182 #endif
1183 
1184 const RegMask &SafePointNode::in_RegMask(uint idx) const {
1185   if( idx < TypeFunc::Parms ) return RegMask::Empty;
1186   // Values outside the domain represent debug info
1187   return *(Compile::current()->matcher()->idealreg2debugmask[in(idx)->ideal_reg()]);
1188 }
1189 const RegMask &SafePointNode::out_RegMask() const {
1190   return RegMask::Empty;
1191 }
1192 
1193 
1194 void SafePointNode::grow_stack(JVMState* jvms, uint grow_by) {
1195   assert((int)grow_by > 0, "sanity");
1196   int monoff = jvms->monoff();
1197   int scloff = jvms->scloff();
1198   int endoff = jvms->endoff();
1199   assert(endoff == (int)req(), "no other states or debug info after me");
1200   Node* top = Compile::current()->top();
1201   for (uint i = 0; i < grow_by; i++) {


1708   return true;
1709 
1710 }
1711 
1712 #ifndef PRODUCT
1713 //
1714 // Create a counter which counts the number of times this lock is acquired
1715 //
1716 void AbstractLockNode::create_lock_counter(JVMState* state) {
1717   _counter = OptoRuntime::new_named_counter(state, NamedCounter::LockCounter);
1718 }
1719 
1720 void AbstractLockNode::set_eliminated_lock_counter() {
1721   if (_counter) {
1722     // Update the counter to indicate that this lock was eliminated.
1723     // The counter update code will stay around even though the
1724     // optimizer will eliminate the lock operation itself.
1725     _counter->set_tag(NamedCounter::EliminatedLockCounter);
1726   }
1727 }
1728 
1729 const char* AbstractLockNode::_kind_names[] = {"Regular", "NonEscObj", "Coarsened", "Nested"};
1730 
1731 void AbstractLockNode::dump_spec(outputStream* st) const {
1732   st->print("%s ", _kind_names[_kind]);
1733   CallNode::dump_spec(st);
1734 }
1735 
1736 void AbstractLockNode::dump_comp_spec(outputStream* st) const {
1737   st->print("%s", _kind_names[_kind]);
1738 }
1739 
1740 // The related set of lock nodes includes the control boundary.
1741 void AbstractLockNode::rel(GrowableArray<Node*> *in_rel, GrowableArray<Node*> *out_rel, bool compact) const {
1742   if (compact) {
1743       this->collect_nodes(in_rel, 1, false, false);
1744     } else {
1745       this->collect_nodes_in_all_data(in_rel, true);
1746     }
1747     this->collect_nodes(out_rel, -2, false, false);
1748 }
1749 #endif
1750 
1751 //=============================================================================
1752 Node *LockNode::Ideal(PhaseGVN *phase, bool can_reshape) {
1753 
1754   // perform any generic optimizations first (returns 'this' or NULL)
1755   Node *result = SafePointNode::Ideal(phase, can_reshape);
1756   if (result != NULL)  return result;
1757   // Don't bother trying to transform a dead node
1758   if (in(0) && in(0)->is_top())  return NULL;
1759 
1760   // Now see if we can optimize away this lock.  We don't actually
1761   // remove the locking here, we simply set the _eliminate flag which
1762   // prevents macro expansion from expanding the lock.  Since we don't
1763   // modify the graph, the value returned from this function is the
1764   // one computed above.
1765   if (can_reshape && EliminateLocks && !is_non_esc_obj()) {
1766     //
1767     // If we are locking an unescaped object, the lock/unlock is unnecessary
1768     //


< prev index next >