comparison src/share/vm/opto/stringopts.cpp @ 6186:751bd303aa45

7179138: Incorrect result with String concatenation optimization Summary: check for and skip diamond shaped NULL check code for the result of toString() Reviewed-by: twisti, roland
author kvn
date Tue, 26 Jun 2012 09:06:16 -0700
parents 8f972594effc
children ed21db7b3fda
comparison
equal deleted inserted replaced
6185:424142833d10 6186:751bd303aa45
110 } 110 }
111 void push(Node* value, int mode) { 111 void push(Node* value, int mode) {
112 _arguments->ins_req(0, value); 112 _arguments->ins_req(0, value);
113 _mode.insert_before(0, mode); 113 _mode.insert_before(0, mode);
114 } 114 }
115
115 void push_string(Node* value) { 116 void push_string(Node* value) {
116 push(value, StringMode); 117 push(value, StringMode);
117 } 118 }
118 void push_string_null_check(Node* value) { 119 void push_string_null_check(Node* value) {
119 push(value, StringNullCheckMode); 120 push(value, StringNullCheckMode);
123 } 124 }
124 void push_char(Node* value) { 125 void push_char(Node* value) {
125 push(value, CharMode); 126 push(value, CharMode);
126 } 127 }
127 128
129 static bool is_SB_toString(Node* call) {
130 if (call->is_CallStaticJava()) {
131 CallStaticJavaNode* csj = call->as_CallStaticJava();
132 ciMethod* m = csj->method();
133 if (m != NULL &&
134 (m->intrinsic_id() == vmIntrinsics::_StringBuilder_toString ||
135 m->intrinsic_id() == vmIntrinsics::_StringBuffer_toString)) {
136 return true;
137 }
138 }
139 return false;
140 }
141
142 static Node* skip_string_null_check(Node* value) {
143 // Look for a diamond shaped Null check of toString() result
144 // (could be code from String.valueOf()):
145 // (Proj == NULL) ? "null":"CastPP(Proj)#NotNULL
146 if (value->is_Phi()) {
147 int true_path = value->as_Phi()->is_diamond_phi();
148 if (true_path != 0) {
149 // phi->region->if_proj->ifnode->bool
150 BoolNode* b = value->in(0)->in(1)->in(0)->in(1)->as_Bool();
151 Node* cmp = b->in(1);
152 Node* v1 = cmp->in(1);
153 Node* v2 = cmp->in(2);
154 // Null check of the return of toString which can simply be skipped.
155 if (b->_test._test == BoolTest::ne &&
156 v2->bottom_type() == TypePtr::NULL_PTR &&
157 value->in(true_path)->Opcode() == Op_CastPP &&
158 value->in(true_path)->in(1) == v1 &&
159 v1->is_Proj() && is_SB_toString(v1->in(0))) {
160 return v1;
161 }
162 }
163 }
164 return value;
165 }
166
128 Node* argument(int i) { 167 Node* argument(int i) {
129 return _arguments->in(i); 168 return _arguments->in(i);
169 }
170 Node* argument_uncast(int i) {
171 Node* arg = argument(i);
172 int amode = mode(i);
173 if (amode == StringConcat::StringMode ||
174 amode == StringConcat::StringNullCheckMode) {
175 arg = skip_string_null_check(arg);
176 }
177 return arg;
130 } 178 }
131 void set_argument(int i, Node* value) { 179 void set_argument(int i, Node* value) {
132 _arguments->set_req(i, value); 180 _arguments->set_req(i, value);
133 } 181 }
134 int num_arguments() { 182 int num_arguments() {
204 } 252 }
205 }; 253 };
206 254
207 255
208 void StringConcat::eliminate_unneeded_control() { 256 void StringConcat::eliminate_unneeded_control() {
209 eliminate_initialize(begin()->initialization());
210 for (uint i = 0; i < _control.size(); i++) { 257 for (uint i = 0; i < _control.size(); i++) {
211 Node* n = _control.at(i); 258 Node* n = _control.at(i);
259 if (n->is_Allocate()) {
260 eliminate_initialize(n->as_Allocate()->initialization());
261 }
212 if (n->is_Call()) { 262 if (n->is_Call()) {
213 if (n != _end) { 263 if (n != _end) {
214 eliminate_call(n->as_Call()); 264 eliminate_call(n->as_Call());
215 } 265 }
216 } else if (n->is_IfTrue()) { 266 } else if (n->is_IfTrue()) {
237 } 287 }
238 } 288 }
239 assert(result->_control.contains(other->_end), "what?"); 289 assert(result->_control.contains(other->_end), "what?");
240 assert(result->_control.contains(_begin), "what?"); 290 assert(result->_control.contains(_begin), "what?");
241 for (int x = 0; x < num_arguments(); x++) { 291 for (int x = 0; x < num_arguments(); x++) {
242 if (argument(x) == arg) { 292 Node* argx = argument_uncast(x);
293 if (argx == arg) {
243 // replace the toString result with the all the arguments that 294 // replace the toString result with the all the arguments that
244 // made up the other StringConcat 295 // made up the other StringConcat
245 for (int y = 0; y < other->num_arguments(); y++) { 296 for (int y = 0; y < other->num_arguments(); y++) {
246 result->append(other->argument(y), other->mode(y)); 297 result->append(other->argument(y), other->mode(y));
247 } 298 }
248 } else { 299 } else {
249 result->append(argument(x), mode(x)); 300 result->append(argx, mode(x));
250 } 301 }
251 } 302 }
252 result->set_allocation(other->_begin); 303 result->set_allocation(other->_begin);
253 result->_multiple = true; 304 result->_multiple = true;
254 return result; 305 return result;
325 } 376 }
326 } 377 }
327 378
328 while (worklist.size() > 0) { 379 while (worklist.size() > 0) {
329 Node* ctrl = worklist.pop(); 380 Node* ctrl = worklist.pop();
330 if (ctrl->is_CallStaticJava()) { 381 if (StringConcat::is_SB_toString(ctrl)) {
331 CallStaticJavaNode* csj = ctrl->as_CallStaticJava(); 382 CallStaticJavaNode* csj = ctrl->as_CallStaticJava();
332 ciMethod* m = csj->method(); 383 string_calls.push(csj);
333 if (m != NULL &&
334 (m->intrinsic_id() == vmIntrinsics::_StringBuffer_toString ||
335 m->intrinsic_id() == vmIntrinsics::_StringBuilder_toString)) {
336 string_calls.push(csj);
337 }
338 } 384 }
339 if (ctrl->in(0) != NULL && !_visited.test_set(ctrl->in(0)->_idx)) { 385 if (ctrl->in(0) != NULL && !_visited.test_set(ctrl->in(0)->_idx)) {
340 worklist.push(ctrl->in(0)); 386 worklist.push(ctrl->in(0));
341 } 387 }
342 if (ctrl->is_Region()) { 388 if (ctrl->is_Region()) {
548 // try to coalesce separate concats 594 // try to coalesce separate concats
549 restart: 595 restart:
550 for (int c = 0; c < concats.length(); c++) { 596 for (int c = 0; c < concats.length(); c++) {
551 StringConcat* sc = concats.at(c); 597 StringConcat* sc = concats.at(c);
552 for (int i = 0; i < sc->num_arguments(); i++) { 598 for (int i = 0; i < sc->num_arguments(); i++) {
553 Node* arg = sc->argument(i); 599 Node* arg = sc->argument_uncast(i);
554 if (arg->is_Proj() && arg->in(0)->is_CallStaticJava()) { 600 if (arg->is_Proj() && StringConcat::is_SB_toString(arg->in(0))) {
555 CallStaticJavaNode* csj = arg->in(0)->as_CallStaticJava(); 601 CallStaticJavaNode* csj = arg->in(0)->as_CallStaticJava();
556 if (csj->method() != NULL && 602 for (int o = 0; o < concats.length(); o++) {
557 (csj->method()->intrinsic_id() == vmIntrinsics::_StringBuilder_toString || 603 if (c == o) continue;
558 csj->method()->intrinsic_id() == vmIntrinsics::_StringBuffer_toString)) { 604 StringConcat* other = concats.at(o);
559 for (int o = 0; o < concats.length(); o++) { 605 if (other->end() == csj) {
560 if (c == o) continue; 606 #ifndef PRODUCT
561 StringConcat* other = concats.at(o); 607 if (PrintOptimizeStringConcat) {
562 if (other->end() == csj) { 608 tty->print_cr("considering stacked concats");
609 }
610 #endif
611
612 StringConcat* merged = sc->merge(other, arg);
613 if (merged->validate_control_flow()) {
563 #ifndef PRODUCT 614 #ifndef PRODUCT
564 if (PrintOptimizeStringConcat) { 615 if (PrintOptimizeStringConcat) {
565 tty->print_cr("considering stacked concats"); 616 tty->print_cr("stacking would succeed");
566 } 617 }
567 #endif 618 #endif
568 619 if (c < o) {
569 StringConcat* merged = sc->merge(other, arg); 620 concats.remove_at(o);
570 if (merged->validate_control_flow()) { 621 concats.at_put(c, merged);
571 #ifndef PRODUCT
572 if (PrintOptimizeStringConcat) {
573 tty->print_cr("stacking would succeed");
574 }
575 #endif
576 if (c < o) {
577 concats.remove_at(o);
578 concats.at_put(c, merged);
579 } else {
580 concats.remove_at(c);
581 concats.at_put(o, merged);
582 }
583 goto restart;
584 } else { 622 } else {
585 #ifndef PRODUCT 623 concats.remove_at(c);
586 if (PrintOptimizeStringConcat) { 624 concats.at_put(o, merged);
587 tty->print_cr("stacking would fail");
588 }
589 #endif
590 } 625 }
626 goto restart;
627 } else {
628 #ifndef PRODUCT
629 if (PrintOptimizeStringConcat) {
630 tty->print_cr("stacking would fail");
631 }
632 #endif
591 } 633 }
592 } 634 }
593 } 635 }
594 } 636 }
595 } 637 }