1.1 --- a/src/share/vm/opto/stringopts.cpp Fri Oct 11 12:06:14 2013 +0200 1.2 +++ b/src/share/vm/opto/stringopts.cpp Wed Oct 16 11:13:15 2013 -0700 1.3 @@ -1,5 +1,5 @@ 1.4 /* 1.5 - * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved. 1.6 + * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. 1.7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 1.8 * 1.9 * This code is free software; you can redistribute it and/or modify it 1.10 @@ -50,10 +50,11 @@ 1.11 Node* _arguments; // The list of arguments to be concatenated 1.12 GrowableArray<int> _mode; // into a String along with a mode flag 1.13 // indicating how to treat the value. 1.14 - 1.15 + Node_List _constructors; // List of constructors (many in case of stacked concat) 1.16 Node_List _control; // List of control nodes that will be deleted 1.17 Node_List _uncommon_traps; // Uncommon traps that needs to be rewritten 1.18 // to restart at the initial JVMState. 1.19 + 1.20 public: 1.21 // Mode for converting arguments to Strings 1.22 enum { 1.23 @@ -73,6 +74,7 @@ 1.24 _arguments->del_req(0); 1.25 } 1.26 1.27 + bool validate_mem_flow(); 1.28 bool validate_control_flow(); 1.29 1.30 void merge_add() { 1.31 @@ -189,6 +191,10 @@ 1.32 assert(!_control.contains(ctrl), "only push once"); 1.33 _control.push(ctrl); 1.34 } 1.35 + void add_constructor(Node* init) { 1.36 + assert(!_constructors.contains(init), "only push once"); 1.37 + _constructors.push(init); 1.38 + } 1.39 CallStaticJavaNode* end() { return _end; } 1.40 AllocateNode* begin() { return _begin; } 1.41 Node* string_alloc() { return _string_alloc; } 1.42 @@ -301,6 +307,12 @@ 1.43 } 1.44 } 1.45 result->set_allocation(other->_begin); 1.46 + for (uint i = 0; i < _constructors.size(); i++) { 1.47 + result->add_constructor(_constructors.at(i)); 1.48 + } 1.49 + for (uint i = 0; i < other->_constructors.size(); i++) { 1.50 + result->add_constructor(other->_constructors.at(i)); 1.51 + } 1.52 result->_multiple = true; 1.53 return result; 1.54 } 1.55 @@ -510,7 +522,8 @@ 1.56 sc->add_control(constructor); 1.57 sc->add_control(alloc); 1.58 sc->set_allocation(alloc); 1.59 - if (sc->validate_control_flow()) { 1.60 + sc->add_constructor(constructor); 1.61 + if (sc->validate_control_flow() && sc->validate_mem_flow()) { 1.62 return sc; 1.63 } else { 1.64 return NULL; 1.65 @@ -620,7 +633,7 @@ 1.66 #endif 1.67 1.68 StringConcat* merged = sc->merge(other, arg); 1.69 - if (merged->validate_control_flow()) { 1.70 + if (merged->validate_control_flow() && merged->validate_mem_flow()) { 1.71 #ifndef PRODUCT 1.72 if (PrintOptimizeStringConcat) { 1.73 tty->print_cr("stacking would succeed"); 1.74 @@ -708,6 +721,139 @@ 1.75 } 1.76 1.77 1.78 +bool StringConcat::validate_mem_flow() { 1.79 + Compile* C = _stringopts->C; 1.80 + 1.81 + for (uint i = 0; i < _control.size(); i++) { 1.82 +#ifndef PRODUCT 1.83 + Node_List path; 1.84 +#endif 1.85 + Node* curr = _control.at(i); 1.86 + if (curr->is_Call() && curr != _begin) { // For all calls except the first allocation 1.87 + // Now here's the main invariant in our case: 1.88 + // For memory between the constructor, and appends, and toString we should only see bottom memory, 1.89 + // produced by the previous call we know about. 1.90 + if (!_constructors.contains(curr)) { 1.91 + NOT_PRODUCT(path.push(curr);) 1.92 + Node* mem = curr->in(TypeFunc::Memory); 1.93 + assert(mem != NULL, "calls should have memory edge"); 1.94 + assert(!mem->is_Phi(), "should be handled by control flow validation"); 1.95 + NOT_PRODUCT(path.push(mem);) 1.96 + while (mem->is_MergeMem()) { 1.97 + for (uint i = 1; i < mem->req(); i++) { 1.98 + if (i != Compile::AliasIdxBot && mem->in(i) != C->top()) { 1.99 +#ifndef PRODUCT 1.100 + if (PrintOptimizeStringConcat) { 1.101 + tty->print("fusion has incorrect memory flow (side effects) for "); 1.102 + _begin->jvms()->dump_spec(tty); tty->cr(); 1.103 + path.dump(); 1.104 + } 1.105 +#endif 1.106 + return false; 1.107 + } 1.108 + } 1.109 + // skip through a potential MergeMem chain, linked through Bot 1.110 + mem = mem->in(Compile::AliasIdxBot); 1.111 + NOT_PRODUCT(path.push(mem);) 1.112 + } 1.113 + // now let it fall through, and see if we have a projection 1.114 + if (mem->is_Proj()) { 1.115 + // Should point to a previous known call 1.116 + Node *prev = mem->in(0); 1.117 + NOT_PRODUCT(path.push(prev);) 1.118 + if (!prev->is_Call() || !_control.contains(prev)) { 1.119 +#ifndef PRODUCT 1.120 + if (PrintOptimizeStringConcat) { 1.121 + tty->print("fusion has incorrect memory flow (unknown call) for "); 1.122 + _begin->jvms()->dump_spec(tty); tty->cr(); 1.123 + path.dump(); 1.124 + } 1.125 +#endif 1.126 + return false; 1.127 + } 1.128 + } else { 1.129 + assert(mem->is_Store() || mem->is_LoadStore(), err_msg_res("unexpected node type: %s", mem->Name())); 1.130 +#ifndef PRODUCT 1.131 + if (PrintOptimizeStringConcat) { 1.132 + tty->print("fusion has incorrect memory flow (unexpected source) for "); 1.133 + _begin->jvms()->dump_spec(tty); tty->cr(); 1.134 + path.dump(); 1.135 + } 1.136 +#endif 1.137 + return false; 1.138 + } 1.139 + } else { 1.140 + // For memory that feeds into constructors it's more complicated. 1.141 + // However the advantage is that any side effect that happens between the Allocate/Initialize and 1.142 + // the constructor will have to be control-dependent on Initialize. 1.143 + // So we actually don't have to do anything, since it's going to be caught by the control flow 1.144 + // analysis. 1.145 +#ifdef ASSERT 1.146 + // Do a quick verification of the control pattern between the constructor and the initialize node 1.147 + assert(curr->is_Call(), "constructor should be a call"); 1.148 + // Go up the control starting from the constructor call 1.149 + Node* ctrl = curr->in(0); 1.150 + IfNode* iff = NULL; 1.151 + RegionNode* copy = NULL; 1.152 + 1.153 + while (true) { 1.154 + // skip known check patterns 1.155 + if (ctrl->is_Region()) { 1.156 + if (ctrl->as_Region()->is_copy()) { 1.157 + copy = ctrl->as_Region(); 1.158 + ctrl = copy->is_copy(); 1.159 + } else { // a cast 1.160 + assert(ctrl->req() == 3 && 1.161 + ctrl->in(1) != NULL && ctrl->in(1)->is_Proj() && 1.162 + ctrl->in(2) != NULL && ctrl->in(2)->is_Proj() && 1.163 + ctrl->in(1)->in(0) == ctrl->in(2)->in(0) && 1.164 + ctrl->in(1)->in(0) != NULL && ctrl->in(1)->in(0)->is_If(), 1.165 + "must be a simple diamond"); 1.166 + Node* true_proj = ctrl->in(1)->is_IfTrue() ? ctrl->in(1) : ctrl->in(2); 1.167 + for (SimpleDUIterator i(true_proj); i.has_next(); i.next()) { 1.168 + Node* use = i.get(); 1.169 + assert(use == ctrl || use->is_ConstraintCast(), 1.170 + err_msg_res("unexpected user: %s", use->Name())); 1.171 + } 1.172 + 1.173 + iff = ctrl->in(1)->in(0)->as_If(); 1.174 + ctrl = iff->in(0); 1.175 + } 1.176 + } else if (ctrl->is_IfTrue()) { // null checks, class checks 1.177 + iff = ctrl->in(0)->as_If(); 1.178 + assert(iff->is_If(), "must be if"); 1.179 + // Verify that the other arm is an uncommon trap 1.180 + Node* otherproj = iff->proj_out(1 - ctrl->as_Proj()->_con); 1.181 + CallStaticJavaNode* call = otherproj->unique_out()->isa_CallStaticJava(); 1.182 + assert(strcmp(call->_name, "uncommon_trap") == 0, "must be uncommond trap"); 1.183 + ctrl = iff->in(0); 1.184 + } else { 1.185 + break; 1.186 + } 1.187 + } 1.188 + 1.189 + assert(ctrl->is_Proj(), "must be a projection"); 1.190 + assert(ctrl->in(0)->is_Initialize(), "should be initialize"); 1.191 + for (SimpleDUIterator i(ctrl); i.has_next(); i.next()) { 1.192 + Node* use = i.get(); 1.193 + assert(use == copy || use == iff || use == curr || use->is_CheckCastPP() || use->is_Load(), 1.194 + err_msg_res("unexpected user: %s", use->Name())); 1.195 + } 1.196 +#endif // ASSERT 1.197 + } 1.198 + } 1.199 + } 1.200 + 1.201 +#ifndef PRODUCT 1.202 + if (PrintOptimizeStringConcat) { 1.203 + tty->print("fusion has correct memory flow for "); 1.204 + _begin->jvms()->dump_spec(tty); tty->cr(); 1.205 + tty->cr(); 1.206 + } 1.207 +#endif 1.208 + return true; 1.209 +} 1.210 + 1.211 bool StringConcat::validate_control_flow() { 1.212 // We found all the calls and arguments now lets see if it's 1.213 // safe to transform the graph as we would expect. 1.214 @@ -753,7 +899,7 @@ 1.215 } 1.216 } 1.217 1.218 - // Skip backwards through the control checking for unexpected contro flow 1.219 + // Skip backwards through the control checking for unexpected control flow 1.220 Node* ptr = _end; 1.221 bool fail = false; 1.222 while (ptr != _begin) { 1.223 @@ -936,7 +1082,7 @@ 1.224 if (PrintOptimizeStringConcat && !fail) { 1.225 ttyLocker ttyl; 1.226 tty->cr(); 1.227 - tty->print("fusion would succeed (%d %d) for ", null_check_count, _uncommon_traps.size()); 1.228 + tty->print("fusion has correct control flow (%d %d) for ", null_check_count, _uncommon_traps.size()); 1.229 _begin->jvms()->dump_spec(tty); tty->cr(); 1.230 for (int i = 0; i < num_arguments(); i++) { 1.231 argument(i)->dump();