comparison src/share/vm/opto/stringopts.cpp @ 12889:90abdd727e64

8009303: Tiered: incorrect results in VM tests stringconcat with -Xcomp -XX:+DeoptimizeALot on solaris-amd64 Summary: Do memory flow analysis in string concat optimizier to exclude cases when computation of arguments to StringBuffer::append has side effects Reviewed-by: kvn, twisti
author iveresov
date Wed, 16 Oct 2013 11:13:15 -0700
parents d092d1b31229
children 2113136690bc
comparison
equal deleted inserted replaced
12888:4a2acfb16e97 12889:90abdd727e64
1 /* 1 /*
2 * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved. 2 * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 * 4 *
5 * This code is free software; you can redistribute it and/or modify it 5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as 6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. 7 * published by the Free Software Foundation.
48 // separate StringBuilders 48 // separate StringBuilders
49 49
50 Node* _arguments; // The list of arguments to be concatenated 50 Node* _arguments; // The list of arguments to be concatenated
51 GrowableArray<int> _mode; // into a String along with a mode flag 51 GrowableArray<int> _mode; // into a String along with a mode flag
52 // indicating how to treat the value. 52 // indicating how to treat the value.
53 53 Node_List _constructors; // List of constructors (many in case of stacked concat)
54 Node_List _control; // List of control nodes that will be deleted 54 Node_List _control; // List of control nodes that will be deleted
55 Node_List _uncommon_traps; // Uncommon traps that needs to be rewritten 55 Node_List _uncommon_traps; // Uncommon traps that needs to be rewritten
56 // to restart at the initial JVMState. 56 // to restart at the initial JVMState.
57
57 public: 58 public:
58 // Mode for converting arguments to Strings 59 // Mode for converting arguments to Strings
59 enum { 60 enum {
60 StringMode, 61 StringMode,
61 IntMode, 62 IntMode,
71 _stringopts(stringopts) { 72 _stringopts(stringopts) {
72 _arguments = new (_stringopts->C) Node(1); 73 _arguments = new (_stringopts->C) Node(1);
73 _arguments->del_req(0); 74 _arguments->del_req(0);
74 } 75 }
75 76
77 bool validate_mem_flow();
76 bool validate_control_flow(); 78 bool validate_control_flow();
77 79
78 void merge_add() { 80 void merge_add() {
79 #if 0 81 #if 0
80 // XXX This is place holder code for reusing an existing String 82 // XXX This is place holder code for reusing an existing String
187 } 189 }
188 void add_control(Node* ctrl) { 190 void add_control(Node* ctrl) {
189 assert(!_control.contains(ctrl), "only push once"); 191 assert(!_control.contains(ctrl), "only push once");
190 _control.push(ctrl); 192 _control.push(ctrl);
191 } 193 }
194 void add_constructor(Node* init) {
195 assert(!_constructors.contains(init), "only push once");
196 _constructors.push(init);
197 }
192 CallStaticJavaNode* end() { return _end; } 198 CallStaticJavaNode* end() { return _end; }
193 AllocateNode* begin() { return _begin; } 199 AllocateNode* begin() { return _begin; }
194 Node* string_alloc() { return _string_alloc; } 200 Node* string_alloc() { return _string_alloc; }
195 201
196 void eliminate_unneeded_control(); 202 void eliminate_unneeded_control();
299 } else { 305 } else {
300 result->append(argx, mode(x)); 306 result->append(argx, mode(x));
301 } 307 }
302 } 308 }
303 result->set_allocation(other->_begin); 309 result->set_allocation(other->_begin);
310 for (uint i = 0; i < _constructors.size(); i++) {
311 result->add_constructor(_constructors.at(i));
312 }
313 for (uint i = 0; i < other->_constructors.size(); i++) {
314 result->add_constructor(other->_constructors.at(i));
315 }
304 result->_multiple = true; 316 result->_multiple = true;
305 return result; 317 return result;
306 } 318 }
307 319
308 320
508 // if this call converted into a direct string concatenation. 520 // if this call converted into a direct string concatenation.
509 sc->add_control(call); 521 sc->add_control(call);
510 sc->add_control(constructor); 522 sc->add_control(constructor);
511 sc->add_control(alloc); 523 sc->add_control(alloc);
512 sc->set_allocation(alloc); 524 sc->set_allocation(alloc);
513 if (sc->validate_control_flow()) { 525 sc->add_constructor(constructor);
526 if (sc->validate_control_flow() && sc->validate_mem_flow()) {
514 return sc; 527 return sc;
515 } else { 528 } else {
516 return NULL; 529 return NULL;
517 } 530 }
518 } else if (cnode->method() == NULL) { 531 } else if (cnode->method() == NULL) {
618 tty->print_cr("considering stacked concats"); 631 tty->print_cr("considering stacked concats");
619 } 632 }
620 #endif 633 #endif
621 634
622 StringConcat* merged = sc->merge(other, arg); 635 StringConcat* merged = sc->merge(other, arg);
623 if (merged->validate_control_flow()) { 636 if (merged->validate_control_flow() && merged->validate_mem_flow()) {
624 #ifndef PRODUCT 637 #ifndef PRODUCT
625 if (PrintOptimizeStringConcat) { 638 if (PrintOptimizeStringConcat) {
626 tty->print_cr("stacking would succeed"); 639 tty->print_cr("stacking would succeed");
627 } 640 }
628 #endif 641 #endif
706 } 719 }
707 } 720 }
708 } 721 }
709 722
710 723
724 bool StringConcat::validate_mem_flow() {
725 Compile* C = _stringopts->C;
726
727 for (uint i = 0; i < _control.size(); i++) {
728 #ifndef PRODUCT
729 Node_List path;
730 #endif
731 Node* curr = _control.at(i);
732 if (curr->is_Call() && curr != _begin) { // For all calls except the first allocation
733 // Now here's the main invariant in our case:
734 // For memory between the constructor, and appends, and toString we should only see bottom memory,
735 // produced by the previous call we know about.
736 if (!_constructors.contains(curr)) {
737 NOT_PRODUCT(path.push(curr);)
738 Node* mem = curr->in(TypeFunc::Memory);
739 assert(mem != NULL, "calls should have memory edge");
740 assert(!mem->is_Phi(), "should be handled by control flow validation");
741 NOT_PRODUCT(path.push(mem);)
742 while (mem->is_MergeMem()) {
743 for (uint i = 1; i < mem->req(); i++) {
744 if (i != Compile::AliasIdxBot && mem->in(i) != C->top()) {
745 #ifndef PRODUCT
746 if (PrintOptimizeStringConcat) {
747 tty->print("fusion has incorrect memory flow (side effects) for ");
748 _begin->jvms()->dump_spec(tty); tty->cr();
749 path.dump();
750 }
751 #endif
752 return false;
753 }
754 }
755 // skip through a potential MergeMem chain, linked through Bot
756 mem = mem->in(Compile::AliasIdxBot);
757 NOT_PRODUCT(path.push(mem);)
758 }
759 // now let it fall through, and see if we have a projection
760 if (mem->is_Proj()) {
761 // Should point to a previous known call
762 Node *prev = mem->in(0);
763 NOT_PRODUCT(path.push(prev);)
764 if (!prev->is_Call() || !_control.contains(prev)) {
765 #ifndef PRODUCT
766 if (PrintOptimizeStringConcat) {
767 tty->print("fusion has incorrect memory flow (unknown call) for ");
768 _begin->jvms()->dump_spec(tty); tty->cr();
769 path.dump();
770 }
771 #endif
772 return false;
773 }
774 } else {
775 assert(mem->is_Store() || mem->is_LoadStore(), err_msg_res("unexpected node type: %s", mem->Name()));
776 #ifndef PRODUCT
777 if (PrintOptimizeStringConcat) {
778 tty->print("fusion has incorrect memory flow (unexpected source) for ");
779 _begin->jvms()->dump_spec(tty); tty->cr();
780 path.dump();
781 }
782 #endif
783 return false;
784 }
785 } else {
786 // For memory that feeds into constructors it's more complicated.
787 // However the advantage is that any side effect that happens between the Allocate/Initialize and
788 // the constructor will have to be control-dependent on Initialize.
789 // So we actually don't have to do anything, since it's going to be caught by the control flow
790 // analysis.
791 #ifdef ASSERT
792 // Do a quick verification of the control pattern between the constructor and the initialize node
793 assert(curr->is_Call(), "constructor should be a call");
794 // Go up the control starting from the constructor call
795 Node* ctrl = curr->in(0);
796 IfNode* iff = NULL;
797 RegionNode* copy = NULL;
798
799 while (true) {
800 // skip known check patterns
801 if (ctrl->is_Region()) {
802 if (ctrl->as_Region()->is_copy()) {
803 copy = ctrl->as_Region();
804 ctrl = copy->is_copy();
805 } else { // a cast
806 assert(ctrl->req() == 3 &&
807 ctrl->in(1) != NULL && ctrl->in(1)->is_Proj() &&
808 ctrl->in(2) != NULL && ctrl->in(2)->is_Proj() &&
809 ctrl->in(1)->in(0) == ctrl->in(2)->in(0) &&
810 ctrl->in(1)->in(0) != NULL && ctrl->in(1)->in(0)->is_If(),
811 "must be a simple diamond");
812 Node* true_proj = ctrl->in(1)->is_IfTrue() ? ctrl->in(1) : ctrl->in(2);
813 for (SimpleDUIterator i(true_proj); i.has_next(); i.next()) {
814 Node* use = i.get();
815 assert(use == ctrl || use->is_ConstraintCast(),
816 err_msg_res("unexpected user: %s", use->Name()));
817 }
818
819 iff = ctrl->in(1)->in(0)->as_If();
820 ctrl = iff->in(0);
821 }
822 } else if (ctrl->is_IfTrue()) { // null checks, class checks
823 iff = ctrl->in(0)->as_If();
824 assert(iff->is_If(), "must be if");
825 // Verify that the other arm is an uncommon trap
826 Node* otherproj = iff->proj_out(1 - ctrl->as_Proj()->_con);
827 CallStaticJavaNode* call = otherproj->unique_out()->isa_CallStaticJava();
828 assert(strcmp(call->_name, "uncommon_trap") == 0, "must be uncommond trap");
829 ctrl = iff->in(0);
830 } else {
831 break;
832 }
833 }
834
835 assert(ctrl->is_Proj(), "must be a projection");
836 assert(ctrl->in(0)->is_Initialize(), "should be initialize");
837 for (SimpleDUIterator i(ctrl); i.has_next(); i.next()) {
838 Node* use = i.get();
839 assert(use == copy || use == iff || use == curr || use->is_CheckCastPP() || use->is_Load(),
840 err_msg_res("unexpected user: %s", use->Name()));
841 }
842 #endif // ASSERT
843 }
844 }
845 }
846
847 #ifndef PRODUCT
848 if (PrintOptimizeStringConcat) {
849 tty->print("fusion has correct memory flow for ");
850 _begin->jvms()->dump_spec(tty); tty->cr();
851 tty->cr();
852 }
853 #endif
854 return true;
855 }
856
711 bool StringConcat::validate_control_flow() { 857 bool StringConcat::validate_control_flow() {
712 // We found all the calls and arguments now lets see if it's 858 // We found all the calls and arguments now lets see if it's
713 // safe to transform the graph as we would expect. 859 // safe to transform the graph as we would expect.
714 860
715 // Check to see if this resulted in too many uncommon traps previously 861 // Check to see if this resulted in too many uncommon traps previously
751 } else { 897 } else {
752 ShouldNotReachHere(); 898 ShouldNotReachHere();
753 } 899 }
754 } 900 }
755 901
756 // Skip backwards through the control checking for unexpected contro flow 902 // Skip backwards through the control checking for unexpected control flow
757 Node* ptr = _end; 903 Node* ptr = _end;
758 bool fail = false; 904 bool fail = false;
759 while (ptr != _begin) { 905 while (ptr != _begin) {
760 if (ptr->is_Call() && ctrl_path.member(ptr)) { 906 if (ptr->is_Call() && ctrl_path.member(ptr)) {
761 ptr = ptr->in(0); 907 ptr = ptr->in(0);
934 1080
935 #ifndef PRODUCT 1081 #ifndef PRODUCT
936 if (PrintOptimizeStringConcat && !fail) { 1082 if (PrintOptimizeStringConcat && !fail) {
937 ttyLocker ttyl; 1083 ttyLocker ttyl;
938 tty->cr(); 1084 tty->cr();
939 tty->print("fusion would succeed (%d %d) for ", null_check_count, _uncommon_traps.size()); 1085 tty->print("fusion has correct control flow (%d %d) for ", null_check_count, _uncommon_traps.size());
940 _begin->jvms()->dump_spec(tty); tty->cr(); 1086 _begin->jvms()->dump_spec(tty); tty->cr();
941 for (int i = 0; i < num_arguments(); i++) { 1087 for (int i = 0; i < num_arguments(); i++) {
942 argument(i)->dump(); 1088 argument(i)->dump();
943 } 1089 }
944 _control.dump(); 1090 _control.dump();