Mercurial > hg > graal-jvmci-8
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 } |