@@ -173,9 +173,6 @@ class StringConcat : public ResourceObj {
173
173
assert (!_control.contains (ctrl), " only push once" );
174
174
_control.push (ctrl);
175
175
}
176
- bool has_control (Node* ctrl) {
177
- return _control.contains (ctrl);
178
- }
179
176
void add_constructor (Node* init) {
180
177
assert (!_constructors.contains (init), " only push once" );
181
178
_constructors.push (init);
@@ -410,66 +407,7 @@ Node_List PhaseStringOpts::collect_toString_calls() {
410
407
return string_calls;
411
408
}
412
409
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
473
411
// of them or the legacy bytecodes of string concatenation prior to JEP-280. eg.
474
412
//
475
413
// String result = new StringBuilder()
@@ -478,17 +416,18 @@ PhaseStringOpts::ProcessAppendResult PhaseStringOpts::process_append_candidate(C
478
416
// .append(123)
479
417
// .toString(); // "foobar123"
480
418
//
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.
484
422
//
423
+ // Since it walks along the receivers of fluent-chain, it will give up if the codeshape is
424
+ // not "fluent" enough. eg.
485
425
// StringBuilder sb = new StringBuilder();
486
426
// sb.append("foo");
487
427
// sb.toString();
488
428
//
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.
492
431
//
493
432
StringConcat* PhaseStringOpts::build_candidate (CallStaticJavaNode* call) {
494
433
ciMethod* m = call->method ();
@@ -527,7 +466,7 @@ StringConcat* PhaseStringOpts::build_candidate(CallStaticJavaNode* call) {
527
466
if (cnode == nullptr ) {
528
467
alloc = recv->isa_Allocate ();
529
468
if (alloc == nullptr ) {
530
- return nullptr ;
469
+ break ;
531
470
}
532
471
// Find the constructor call
533
472
Node* result = alloc->result_cast ();
@@ -539,7 +478,7 @@ StringConcat* PhaseStringOpts::build_candidate(CallStaticJavaNode* call) {
539
478
alloc->jvms ()->dump_spec (tty); tty->cr ();
540
479
}
541
480
#endif
542
- return nullptr ;
481
+ break ;
543
482
}
544
483
Node* constructor = nullptr ;
545
484
for (SimpleDUIterator i (result); i.has_next (); i.next ()) {
@@ -550,10 +489,6 @@ StringConcat* PhaseStringOpts::build_candidate(CallStaticJavaNode* call) {
550
489
use->method ()->name () == ciSymbols::object_initializer_name () &&
551
490
use->method ()->holder () == m->holder ()) {
552
491
// Matched the constructor.
553
- if (constructor != nullptr ) {
554
- // The constructor again. We must only process it once.
555
- continue ;
556
- }
557
492
ciSymbol* sig = use->method ()->signature ()->as_symbol ();
558
493
if (sig == ciSymbols::void_method_signature () ||
559
494
sig == ciSymbols::int_void_signature () ||
@@ -607,16 +542,7 @@ StringConcat* PhaseStringOpts::build_candidate(CallStaticJavaNode* call) {
607
542
}
608
543
#endif
609
544
}
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 ;
620
546
}
621
547
}
622
548
if (constructor == nullptr ) {
@@ -627,7 +553,7 @@ StringConcat* PhaseStringOpts::build_candidate(CallStaticJavaNode* call) {
627
553
alloc->jvms ()->dump_spec (tty); tty->cr ();
628
554
}
629
555
#endif
630
- return nullptr ;
556
+ break ;
631
557
}
632
558
633
559
// Walked all the way back and found the constructor call so see
@@ -642,23 +568,62 @@ StringConcat* PhaseStringOpts::build_candidate(CallStaticJavaNode* call) {
642
568
} else {
643
569
return nullptr ;
644
570
}
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 ()) {
652
582
#ifndef PRODUCT
653
583
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 ();
658
586
}
659
587
#endif
660
- return nullptr ;
588
+ break ;
661
589
}
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 ;
662
627
}
663
628
}
664
629
return nullptr ;
0 commit comments