Mercurial > hg > graal-jvmci-8
comparison src/share/vm/opto/phaseX.cpp @ 6244:611e8a669a2c
7147464: Java crashed while executing method with over 8k of dneg operations
Summary: replace recursive method with iterative
Reviewed-by: kvn, twisti
Contributed-by: dean.long@oracle.com
author | dlong |
---|---|
date | Mon, 16 Jul 2012 15:31:18 -0400 |
parents | 670a74b863fc |
children | e626685e9f6c |
comparison
equal
deleted
inserted
replaced
6217:e74da3c2b827 | 6244:611e8a669a2c |
---|---|
755 | 755 |
756 //============================================================================= | 756 //============================================================================= |
757 //------------------------------PhaseIterGVN----------------------------------- | 757 //------------------------------PhaseIterGVN----------------------------------- |
758 // Initialize hash table to fresh and clean for +VerifyOpto | 758 // Initialize hash table to fresh and clean for +VerifyOpto |
759 PhaseIterGVN::PhaseIterGVN( PhaseIterGVN *igvn, const char *dummy ) : PhaseGVN(igvn,dummy), _worklist( ), | 759 PhaseIterGVN::PhaseIterGVN( PhaseIterGVN *igvn, const char *dummy ) : PhaseGVN(igvn,dummy), _worklist( ), |
760 _stack(C->unique() >> 1), | |
760 _delay_transform(false) { | 761 _delay_transform(false) { |
761 } | 762 } |
762 | 763 |
763 //------------------------------PhaseIterGVN----------------------------------- | 764 //------------------------------PhaseIterGVN----------------------------------- |
764 // Initialize with previous PhaseIterGVN info; used by PhaseCCP | 765 // Initialize with previous PhaseIterGVN info; used by PhaseCCP |
765 PhaseIterGVN::PhaseIterGVN( PhaseIterGVN *igvn ) : PhaseGVN(igvn), | 766 PhaseIterGVN::PhaseIterGVN( PhaseIterGVN *igvn ) : PhaseGVN(igvn), |
766 _worklist( igvn->_worklist ), | 767 _worklist( igvn->_worklist ), |
768 _stack( igvn->_stack ), | |
767 _delay_transform(igvn->_delay_transform) | 769 _delay_transform(igvn->_delay_transform) |
768 { | 770 { |
769 } | 771 } |
770 | 772 |
771 //------------------------------PhaseIterGVN----------------------------------- | 773 //------------------------------PhaseIterGVN----------------------------------- |
772 // Initialize with previous PhaseGVN info from Parser | 774 // Initialize with previous PhaseGVN info from Parser |
773 PhaseIterGVN::PhaseIterGVN( PhaseGVN *gvn ) : PhaseGVN(gvn), | 775 PhaseIterGVN::PhaseIterGVN( PhaseGVN *gvn ) : PhaseGVN(gvn), |
774 _worklist(*C->for_igvn()), | 776 _worklist(*C->for_igvn()), |
777 _stack(C->unique() >> 1), | |
775 _delay_transform(false) | 778 _delay_transform(false) |
776 { | 779 { |
777 uint max; | 780 uint max; |
778 | 781 |
779 // Dead nodes in the hash table inherited from GVN were not treated as | 782 // Dead nodes in the hash table inherited from GVN were not treated as |
1136 | 1139 |
1137 //------------------------------remove_globally_dead_node---------------------- | 1140 //------------------------------remove_globally_dead_node---------------------- |
1138 // Kill a globally dead Node. All uses are also globally dead and are | 1141 // Kill a globally dead Node. All uses are also globally dead and are |
1139 // aggressively trimmed. | 1142 // aggressively trimmed. |
1140 void PhaseIterGVN::remove_globally_dead_node( Node *dead ) { | 1143 void PhaseIterGVN::remove_globally_dead_node( Node *dead ) { |
1141 assert(dead != C->root(), "killing root, eh?"); | 1144 enum DeleteProgress { |
1142 if (dead->is_top()) return; | 1145 PROCESS_INPUTS, |
1143 NOT_PRODUCT( set_progress(); ) | 1146 PROCESS_OUTPUTS |
1144 // Remove from iterative worklist | 1147 }; |
1145 _worklist.remove(dead); | 1148 assert(_stack.is_empty(), "not empty"); |
1146 if (!dead->is_Con()) { // Don't kill cons but uses | 1149 _stack.push(dead, PROCESS_INPUTS); |
1147 // Remove from hash table | 1150 |
1148 _table.hash_delete( dead ); | 1151 while (_stack.is_nonempty()) { |
1149 // Smash all inputs to 'dead', isolating him completely | 1152 dead = _stack.node(); |
1150 for( uint i = 0; i < dead->req(); i++ ) { | 1153 uint progress_state = _stack.index(); |
1151 Node *in = dead->in(i); | 1154 assert(dead != C->root(), "killing root, eh?"); |
1152 if( in ) { // Points to something? | 1155 assert(!dead->is_top(), "add check for top when pushing"); |
1153 dead->set_req(i,NULL); // Kill the edge | 1156 NOT_PRODUCT( set_progress(); ) |
1154 if (in->outcnt() == 0 && in != C->top()) {// Made input go dead? | 1157 if (progress_state == PROCESS_INPUTS) { |
1155 remove_dead_node(in); // Recursively remove | 1158 // After following inputs, continue to outputs |
1156 } else if (in->outcnt() == 1 && | 1159 _stack.set_index(PROCESS_OUTPUTS); |
1157 in->has_special_unique_user()) { | 1160 // Remove from iterative worklist |
1158 _worklist.push(in->unique_out()); | 1161 _worklist.remove(dead); |
1159 } else if (in->outcnt() <= 2 && dead->is_Phi()) { | 1162 if (!dead->is_Con()) { // Don't kill cons but uses |
1160 if( in->Opcode() == Op_Region ) | 1163 bool recurse = false; |
1161 _worklist.push(in); | 1164 // Remove from hash table |
1162 else if( in->is_Store() ) { | 1165 _table.hash_delete( dead ); |
1163 DUIterator_Fast imax, i = in->fast_outs(imax); | 1166 // Smash all inputs to 'dead', isolating him completely |
1164 _worklist.push(in->fast_out(i)); | 1167 for( uint i = 0; i < dead->req(); i++ ) { |
1165 i++; | 1168 Node *in = dead->in(i); |
1166 if(in->outcnt() == 2) { | 1169 if( in ) { // Points to something? |
1167 _worklist.push(in->fast_out(i)); | 1170 dead->set_req(i,NULL); // Kill the edge |
1168 i++; | 1171 if (in->outcnt() == 0 && in != C->top()) {// Made input go dead? |
1172 _stack.push(in, PROCESS_INPUTS); // Recursively remove | |
1173 recurse = true; | |
1174 } else if (in->outcnt() == 1 && | |
1175 in->has_special_unique_user()) { | |
1176 _worklist.push(in->unique_out()); | |
1177 } else if (in->outcnt() <= 2 && dead->is_Phi()) { | |
1178 if( in->Opcode() == Op_Region ) | |
1179 _worklist.push(in); | |
1180 else if( in->is_Store() ) { | |
1181 DUIterator_Fast imax, i = in->fast_outs(imax); | |
1182 _worklist.push(in->fast_out(i)); | |
1183 i++; | |
1184 if(in->outcnt() == 2) { | |
1185 _worklist.push(in->fast_out(i)); | |
1186 i++; | |
1187 } | |
1188 assert(!(i < imax), "sanity"); | |
1189 } | |
1169 } | 1190 } |
1170 assert(!(i < imax), "sanity"); | |
1171 } | 1191 } |
1172 } | 1192 } |
1173 } | 1193 |
1174 } | 1194 if (dead->is_macro()) { |
1175 | 1195 C->remove_macro_node(dead); |
1176 if (dead->is_macro()) { | 1196 } |
1177 C->remove_macro_node(dead); | 1197 |
1178 } | 1198 if (recurse) { |
1179 } | 1199 continue; |
1180 // Aggressively kill globally dead uses | 1200 } |
1181 // (Cannot use DUIterator_Last because of the indefinite number | 1201 } |
1182 // of edge deletions per loop trip.) | 1202 } |
1183 while (dead->outcnt() > 0) { | 1203 |
1184 remove_globally_dead_node(dead->raw_out(0)); | 1204 // Aggressively kill globally dead uses |
1205 // (Rather than pushing all the outs at once, we push one at a time, | |
1206 // plus the parent to resume later, because of the indefinite number | |
1207 // of edge deletions per loop trip.) | |
1208 if (dead->outcnt() > 0) { | |
1209 // Recursively remove | |
1210 _stack.push(dead->raw_out(0), PROCESS_INPUTS); | |
1211 } else { | |
1212 _stack.pop(); | |
1213 } | |
1185 } | 1214 } |
1186 } | 1215 } |
1187 | 1216 |
1188 //------------------------------subsume_node----------------------------------- | 1217 //------------------------------subsume_node----------------------------------- |
1189 // Remove users from node 'old' and add them to node 'nn'. | 1218 // Remove users from node 'old' and add them to node 'nn'. |