@@ -173,9 +173,6 @@ class StringConcat : public ResourceObj {
173173 assert (!_control.contains (ctrl), " only push once" );
174174 _control.push (ctrl);
175175 }
176- bool has_control (Node* ctrl) {
177- return _control.contains (ctrl);
178- }
179176 void add_constructor (Node* init) {
180177 assert (!_constructors.contains (init), " only push once" );
181178 _constructors.push (init);
@@ -410,66 +407,7 @@ Node_List PhaseStringOpts::collect_toString_calls() {
410407 return string_calls;
411408}
412409
413- PhaseStringOpts::ProcessAppendResult PhaseStringOpts::process_append_candidate (CallStaticJavaNode* cnode,
414- StringConcat* sc,
415- ciMethod* m,
416- ciSymbol* string_sig,
417- ciSymbol* int_sig,
418- ciSymbol* char_sig) {
419- if (cnode->method () != nullptr && !cnode->method ()->is_static () &&
420- cnode->method ()->holder () == m->holder () &&
421- cnode->method ()->name () == ciSymbols::append_name () &&
422- (cnode->method ()->signature ()->as_symbol () == string_sig ||
423- cnode->method ()->signature ()->as_symbol () == char_sig ||
424- cnode->method ()->signature ()->as_symbol () == int_sig)) {
425- if (sc->has_control (cnode)) {
426- return ProcessAppendResult::AppendWasAdded;
427- }
428- sc->add_control (cnode);
429- Node* arg = cnode->in (TypeFunc::Parms + 1 );
430- if (arg == nullptr || arg->is_top ()) {
431- #ifndef PRODUCT
432- if (PrintOptimizeStringConcat) {
433- tty->print (" giving up because the call is effectively dead" );
434- cnode->jvms ()->dump_spec (tty);
435- tty->cr ();
436- }
437- #endif
438- return ProcessAppendResult::AbortOptimization;
439- }
440-
441- if (cnode->method ()->signature ()->as_symbol () == int_sig) {
442- sc->push_int (arg);
443- } else if (cnode->method ()->signature ()->as_symbol () == char_sig) {
444- sc->push_char (arg);
445- } else if (arg->is_Proj () && arg->in (0 )->is_CallStaticJava ()) {
446- CallStaticJavaNode* csj = arg->in (0 )->as_CallStaticJava ();
447- if (csj->method () != nullptr &&
448- csj->method ()->intrinsic_id () == vmIntrinsics::_Integer_toString &&
449- arg->outcnt () == 1 ) {
450- // _control is the list of StringBuilder calls nodes which
451- // will be replaced by new String code after this optimization.
452- // Integer::toString() call is not part of StringBuilder calls
453- // chain. It could be eliminated only if its result is used
454- // only by this SB calls chain.
455- // Another limitation: it should be used only once because
456- // it is unknown that it is used only by this SB calls chain
457- // until all related SB calls nodes are collected.
458- assert (arg->unique_out () == cnode, " sanity" );
459- sc->add_control (csj);
460- sc->push_int (csj->in (TypeFunc::Parms));
461- } else {
462- sc->push_string (arg);
463- }
464- } else {
465- sc->push_string (arg);
466- }
467- return ProcessAppendResult::AppendWasAdded;
468- }
469- return ProcessAppendResult::CandidateIsNotAppend;
470- }
471-
472- // Recognize fluent-chain and non-fluent uses of StringBuilder/Buffer. They are either explicit usages
410+ // Recognize a fluent-chain of StringBuilder/Buffer. They are either explicit usages
473411// of them or the legacy bytecodes of string concatenation prior to JEP-280. eg.
474412//
475413// String result = new StringBuilder()
@@ -478,17 +416,18 @@ PhaseStringOpts::ProcessAppendResult PhaseStringOpts::process_append_candidate(C
478416// .append(123)
479417// .toString(); // "foobar123"
480418//
481- // Fluent-chains are recognized by walking upwards along the receivers, starting from toString() .
482- // Once the allocation of the StringBuilder has been reached, DU pairs are examined to find the
483- // constructor and non-fluent uses of the StringBuilder such as in this example:
419+ // PS: Only a certain subset of constructor and append methods are acceptable .
420+ // The criterion is that the length of argument is easy to work out in this phrase.
421+ // It will drop complex cases such as Object.
484422//
423+ // Since it walks along the receivers of fluent-chain, it will give up if the codeshape is
424+ // not "fluent" enough. eg.
485425// StringBuilder sb = new StringBuilder();
486426// sb.append("foo");
487427// sb.toString();
488428//
489- // PS: Only a certain subset of constructor and append methods are acceptable.
490- // The criterion is that the length of argument is easy to work out in this phrase.
491- // It will drop complex cases such as Object.
429+ // The receiver of toString method is the result of Allocation Node(CheckCastPP).
430+ // The append method is overlooked. It will fail at validate_control_flow() test.
492431//
493432StringConcat* PhaseStringOpts::build_candidate (CallStaticJavaNode* call) {
494433 ciMethod* m = call->method ();
@@ -527,7 +466,7 @@ StringConcat* PhaseStringOpts::build_candidate(CallStaticJavaNode* call) {
527466 if (cnode == nullptr ) {
528467 alloc = recv->isa_Allocate ();
529468 if (alloc == nullptr ) {
530- return nullptr ;
469+ break ;
531470 }
532471 // Find the constructor call
533472 Node* result = alloc->result_cast ();
@@ -539,7 +478,7 @@ StringConcat* PhaseStringOpts::build_candidate(CallStaticJavaNode* call) {
539478 alloc->jvms ()->dump_spec (tty); tty->cr ();
540479 }
541480#endif
542- return nullptr ;
481+ break ;
543482 }
544483 Node* constructor = nullptr ;
545484 for (SimpleDUIterator i (result); i.has_next (); i.next ()) {
@@ -550,10 +489,6 @@ StringConcat* PhaseStringOpts::build_candidate(CallStaticJavaNode* call) {
550489 use->method ()->name () == ciSymbols::object_initializer_name () &&
551490 use->method ()->holder () == m->holder ()) {
552491 // Matched the constructor.
553- if (constructor != nullptr ) {
554- // The constructor again. We must only process it once.
555- continue ;
556- }
557492 ciSymbol* sig = use->method ()->signature ()->as_symbol ();
558493 if (sig == ciSymbols::void_method_signature () ||
559494 sig == ciSymbols::int_void_signature () ||
@@ -607,16 +542,7 @@ StringConcat* PhaseStringOpts::build_candidate(CallStaticJavaNode* call) {
607542 }
608543#endif
609544 }
610- } else if (use != nullptr ) {
611- if (process_append_candidate (use, sc, m, string_sig, int_sig, char_sig) == ProcessAppendResult::AbortOptimization) {
612- // We must abort if process_append_candidate tells us to...
613- return nullptr ;
614- }
615- // ...but we do not care if we really found an append or not:
616- // - If we found an append, that's perfect. Nothing further to do.
617- // - If this is a call to an unrelated method, validate_mem_flow() (and validate_control_flow())
618- // will later check if this call prevents the optimization. So nothing to do here.
619- // We will continue to look for the constructor (if not found already) and appends.
545+ break ;
620546 }
621547 }
622548 if (constructor == nullptr ) {
@@ -627,7 +553,7 @@ StringConcat* PhaseStringOpts::build_candidate(CallStaticJavaNode* call) {
627553 alloc->jvms ()->dump_spec (tty); tty->cr ();
628554 }
629555#endif
630- return nullptr ;
556+ break ;
631557 }
632558
633559 // Walked all the way back and found the constructor call so see
@@ -642,23 +568,62 @@ StringConcat* PhaseStringOpts::build_candidate(CallStaticJavaNode* call) {
642568 } else {
643569 return nullptr ;
644570 }
645- } else {
646- ProcessAppendResult result = process_append_candidate (cnode, sc, m, string_sig, int_sig, char_sig);
647-
648- if (result == ProcessAppendResult::AbortOptimization) {
649- return nullptr ;
650- } else if (result == ProcessAppendResult::CandidateIsNotAppend) {
651- // some unhandled signature
571+ } else if (cnode->method () == nullptr ) {
572+ break ;
573+ } else if (!cnode->method ()->is_static () &&
574+ cnode->method ()->holder () == m->holder () &&
575+ cnode->method ()->name () == ciSymbols::append_name () &&
576+ (cnode->method ()->signature ()->as_symbol () == string_sig ||
577+ cnode->method ()->signature ()->as_symbol () == char_sig ||
578+ cnode->method ()->signature ()->as_symbol () == int_sig)) {
579+ sc->add_control (cnode);
580+ Node* arg = cnode->in (TypeFunc::Parms + 1 );
581+ if (arg == nullptr || arg->is_top ()) {
652582#ifndef PRODUCT
653583 if (PrintOptimizeStringConcat) {
654- tty->print (" giving up because encountered unexpected signature " );
655- cnode->tf ()->dump ();
656- tty->cr ();
657- cnode->in (TypeFunc::Parms + 1 )->dump ();
584+ tty->print (" giving up because the call is effectively dead" );
585+ cnode->jvms ()->dump_spec (tty); tty->cr ();
658586 }
659587#endif
660- return nullptr ;
588+ break ;
661589 }
590+ if (cnode->method ()->signature ()->as_symbol () == int_sig) {
591+ sc->push_int (arg);
592+ } else if (cnode->method ()->signature ()->as_symbol () == char_sig) {
593+ sc->push_char (arg);
594+ } else {
595+ if (arg->is_Proj () && arg->in (0 )->is_CallStaticJava ()) {
596+ CallStaticJavaNode* csj = arg->in (0 )->as_CallStaticJava ();
597+ if (csj->method () != nullptr &&
598+ csj->method ()->intrinsic_id () == vmIntrinsics::_Integer_toString &&
599+ arg->outcnt () == 1 ) {
600+ // _control is the list of StringBuilder calls nodes which
601+ // will be replaced by new String code after this optimization.
602+ // Integer::toString() call is not part of StringBuilder calls
603+ // chain. It could be eliminated only if its result is used
604+ // only by this SB calls chain.
605+ // Another limitation: it should be used only once because
606+ // it is unknown that it is used only by this SB calls chain
607+ // until all related SB calls nodes are collected.
608+ assert (arg->unique_out () == cnode, " sanity" );
609+ sc->add_control (csj);
610+ sc->push_int (csj->in (TypeFunc::Parms));
611+ continue ;
612+ }
613+ }
614+ sc->push_string (arg);
615+ }
616+ continue ;
617+ } else {
618+ // some unhandled signature
619+ #ifndef PRODUCT
620+ if (PrintOptimizeStringConcat) {
621+ tty->print (" giving up because encountered unexpected signature " );
622+ cnode->tf ()->dump (); tty->cr ();
623+ cnode->in (TypeFunc::Parms + 1 )->dump ();
624+ }
625+ #endif
626+ break ;
662627 }
663628 }
664629 return nullptr ;
0 commit comments