Mercurial > hg > truffle
annotate src/share/vm/opto/stringopts.cpp @ 1994:6cd6d394f280
7001033: assert(gch->gc_cause() == GCCause::_scavenge_alot || !gch->incremental_collection_failed())
7002546: regression on SpecJbb2005 on 7b118 comparing to 7b117 on small heaps
Summary: Relaxed assertion checking related to incremental_collection_failed flag to allow for ExplicitGCInvokesConcurrent behaviour where we do not want a failing scavenge to bail to a stop-world collection. Parameterized incremental_collection_will_fail() so we can selectively use, or not use, as appropriate, the statistical prediction at specific use sites. This essentially reverts the scavenge bail-out logic to what it was prior to some recent changes that had inadvertently started using the statistical prediction which can be noisy in the presence of bursty loads. Added some associated verbose non-product debugging messages.
Reviewed-by: johnc, tonyp
author | ysr |
---|---|
date | Tue, 07 Dec 2010 21:55:53 -0800 |
parents | f95d63e2154a |
children | 2ddb2fab82cb |
rev | line source |
---|---|
1080 | 1 /* |
1552
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
1250
diff
changeset
|
2 * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. |
1080 | 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 * | |
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 | |
7 * published by the Free Software Foundation. | |
8 * | |
9 * This code is distributed in the hope that it will be useful, but WITHOUT | |
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
12 * version 2 for more details (a copy is included in the LICENSE file that | |
13 * accompanied this code). | |
14 * | |
15 * You should have received a copy of the GNU General Public License version | |
16 * 2 along with this work; if not, write to the Free Software Foundation, | |
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
18 * | |
1552
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
1250
diff
changeset
|
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
1250
diff
changeset
|
20 * or visit www.oracle.com if you need additional information or have any |
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
1250
diff
changeset
|
21 * questions. |
1080 | 22 * |
23 */ | |
24 | |
1972 | 25 #include "precompiled.hpp" |
26 #include "compiler/compileLog.hpp" | |
27 #include "opto/addnode.hpp" | |
28 #include "opto/callGenerator.hpp" | |
29 #include "opto/callnode.hpp" | |
30 #include "opto/divnode.hpp" | |
31 #include "opto/graphKit.hpp" | |
32 #include "opto/idealKit.hpp" | |
33 #include "opto/rootnode.hpp" | |
34 #include "opto/runtime.hpp" | |
35 #include "opto/stringopts.hpp" | |
36 #include "opto/subnode.hpp" | |
1080 | 37 |
38 #define __ kit. | |
39 | |
40 class StringConcat : public ResourceObj { | |
41 private: | |
42 PhaseStringOpts* _stringopts; | |
43 Node* _string_alloc; | |
44 AllocateNode* _begin; // The allocation the begins the pattern | |
45 CallStaticJavaNode* _end; // The final call of the pattern. Will either be | |
46 // SB.toString or or String.<init>(SB.toString) | |
47 bool _multiple; // indicates this is a fusion of two or more | |
48 // separate StringBuilders | |
49 | |
50 Node* _arguments; // The list of arguments to be concatenated | |
51 GrowableArray<int> _mode; // into a String along with a mode flag | |
52 // indicating how to treat the value. | |
53 | |
54 Node_List _control; // List of control nodes that will be deleted | |
55 Node_List _uncommon_traps; // Uncommon traps that needs to be rewritten | |
56 // to restart at the initial JVMState. | |
57 public: | |
58 // Mode for converting arguments to Strings | |
59 enum { | |
60 StringMode, | |
61 IntMode, | |
62 CharMode | |
63 }; | |
64 | |
65 StringConcat(PhaseStringOpts* stringopts, CallStaticJavaNode* end): | |
66 _end(end), | |
67 _begin(NULL), | |
68 _multiple(false), | |
69 _string_alloc(NULL), | |
70 _stringopts(stringopts) { | |
71 _arguments = new (_stringopts->C, 1) Node(1); | |
72 _arguments->del_req(0); | |
73 } | |
74 | |
75 bool validate_control_flow(); | |
76 | |
77 void merge_add() { | |
78 #if 0 | |
79 // XXX This is place holder code for reusing an existing String | |
80 // allocation but the logic for checking the state safety is | |
81 // probably inadequate at the moment. | |
82 CallProjections endprojs; | |
83 sc->end()->extract_projections(&endprojs, false); | |
84 if (endprojs.resproj != NULL) { | |
85 for (SimpleDUIterator i(endprojs.resproj); i.has_next(); i.next()) { | |
86 CallStaticJavaNode *use = i.get()->isa_CallStaticJava(); | |
87 if (use != NULL && use->method() != NULL && | |
1817
c40600e85311
6986028: assert(_base == Int) failed: Not an Int in CmpINode::sub
never
parents:
1748
diff
changeset
|
88 use->method()->intrinsic_id() == vmIntrinsics::_String_String && |
1080 | 89 use->in(TypeFunc::Parms + 1) == endprojs.resproj) { |
90 // Found useless new String(sb.toString()) so reuse the newly allocated String | |
91 // when creating the result instead of allocating a new one. | |
92 sc->set_string_alloc(use->in(TypeFunc::Parms)); | |
93 sc->set_end(use); | |
94 } | |
95 } | |
96 } | |
97 #endif | |
98 } | |
99 | |
100 StringConcat* merge(StringConcat* other, Node* arg); | |
101 | |
102 void set_allocation(AllocateNode* alloc) { | |
103 _begin = alloc; | |
104 } | |
105 | |
106 void append(Node* value, int mode) { | |
107 _arguments->add_req(value); | |
108 _mode.append(mode); | |
109 } | |
110 void push(Node* value, int mode) { | |
111 _arguments->ins_req(0, value); | |
112 _mode.insert_before(0, mode); | |
113 } | |
114 void push_string(Node* value) { | |
115 push(value, StringMode); | |
116 } | |
117 void push_int(Node* value) { | |
118 push(value, IntMode); | |
119 } | |
120 void push_char(Node* value) { | |
121 push(value, CharMode); | |
122 } | |
123 | |
124 Node* argument(int i) { | |
125 return _arguments->in(i); | |
126 } | |
127 void set_argument(int i, Node* value) { | |
128 _arguments->set_req(i, value); | |
129 } | |
130 int num_arguments() { | |
131 return _mode.length(); | |
132 } | |
133 int mode(int i) { | |
134 return _mode.at(i); | |
135 } | |
136 void add_control(Node* ctrl) { | |
137 assert(!_control.contains(ctrl), "only push once"); | |
138 _control.push(ctrl); | |
139 } | |
140 CallStaticJavaNode* end() { return _end; } | |
141 AllocateNode* begin() { return _begin; } | |
142 Node* string_alloc() { return _string_alloc; } | |
143 | |
144 void eliminate_unneeded_control(); | |
145 void eliminate_initialize(InitializeNode* init); | |
146 void eliminate_call(CallNode* call); | |
147 | |
148 void maybe_log_transform() { | |
149 CompileLog* log = _stringopts->C->log(); | |
150 if (log != NULL) { | |
151 log->head("replace_string_concat arguments='%d' string_alloc='%d' multiple='%d'", | |
152 num_arguments(), | |
153 _string_alloc != NULL, | |
154 _multiple); | |
155 JVMState* p = _begin->jvms(); | |
156 while (p != NULL) { | |
157 log->elem("jvms bci='%d' method='%d'", p->bci(), log->identify(p->method())); | |
158 p = p->caller(); | |
159 } | |
160 log->tail("replace_string_concat"); | |
161 } | |
162 } | |
163 | |
164 void convert_uncommon_traps(GraphKit& kit, const JVMState* jvms) { | |
165 for (uint u = 0; u < _uncommon_traps.size(); u++) { | |
166 Node* uct = _uncommon_traps.at(u); | |
167 | |
168 // Build a new call using the jvms state of the allocate | |
1748 | 169 address call_addr = SharedRuntime::uncommon_trap_blob()->entry_point(); |
1080 | 170 const TypeFunc* call_type = OptoRuntime::uncommon_trap_Type(); |
171 int size = call_type->domain()->cnt(); | |
172 const TypePtr* no_memory_effects = NULL; | |
173 Compile* C = _stringopts->C; | |
174 CallStaticJavaNode* call = new (C, size) CallStaticJavaNode(call_type, call_addr, "uncommon_trap", | |
175 jvms->bci(), no_memory_effects); | |
176 for (int e = 0; e < TypeFunc::Parms; e++) { | |
177 call->init_req(e, uct->in(e)); | |
178 } | |
179 // Set the trap request to record intrinsic failure if this trap | |
180 // is taken too many times. Ideally we would handle then traps by | |
181 // doing the original bookkeeping in the MDO so that if it caused | |
182 // the code to be thrown out we could still recompile and use the | |
183 // optimization. Failing the uncommon traps doesn't really mean | |
184 // that the optimization is a bad idea but there's no other way to | |
185 // do the MDO updates currently. | |
186 int trap_request = Deoptimization::make_trap_request(Deoptimization::Reason_intrinsic, | |
187 Deoptimization::Action_make_not_entrant); | |
188 call->init_req(TypeFunc::Parms, __ intcon(trap_request)); | |
189 kit.add_safepoint_edges(call); | |
190 | |
191 _stringopts->gvn()->transform(call); | |
192 C->gvn_replace_by(uct, call); | |
193 uct->disconnect_inputs(NULL); | |
194 } | |
195 } | |
196 | |
197 void cleanup() { | |
198 // disconnect the hook node | |
199 _arguments->disconnect_inputs(NULL); | |
200 } | |
201 }; | |
202 | |
203 | |
204 void StringConcat::eliminate_unneeded_control() { | |
205 eliminate_initialize(begin()->initialization()); | |
206 for (uint i = 0; i < _control.size(); i++) { | |
207 Node* n = _control.at(i); | |
208 if (n->is_Call()) { | |
209 if (n != _end) { | |
210 eliminate_call(n->as_Call()); | |
211 } | |
212 } else if (n->is_IfTrue()) { | |
213 Compile* C = _stringopts->C; | |
214 C->gvn_replace_by(n, n->in(0)->in(0)); | |
215 C->gvn_replace_by(n->in(0), C->top()); | |
216 } | |
217 } | |
218 } | |
219 | |
220 | |
221 StringConcat* StringConcat::merge(StringConcat* other, Node* arg) { | |
222 StringConcat* result = new StringConcat(_stringopts, _end); | |
223 for (uint x = 0; x < _control.size(); x++) { | |
224 Node* n = _control.at(x); | |
225 if (n->is_Call()) { | |
226 result->_control.push(n); | |
227 } | |
228 } | |
229 for (uint x = 0; x < other->_control.size(); x++) { | |
230 Node* n = other->_control.at(x); | |
231 if (n->is_Call()) { | |
232 result->_control.push(n); | |
233 } | |
234 } | |
235 assert(result->_control.contains(other->_end), "what?"); | |
236 assert(result->_control.contains(_begin), "what?"); | |
237 for (int x = 0; x < num_arguments(); x++) { | |
238 if (argument(x) == arg) { | |
239 // replace the toString result with the all the arguments that | |
240 // made up the other StringConcat | |
241 for (int y = 0; y < other->num_arguments(); y++) { | |
242 result->append(other->argument(y), other->mode(y)); | |
243 } | |
244 } else { | |
245 result->append(argument(x), mode(x)); | |
246 } | |
247 } | |
248 result->set_allocation(other->_begin); | |
249 result->_multiple = true; | |
250 return result; | |
251 } | |
252 | |
253 | |
254 void StringConcat::eliminate_call(CallNode* call) { | |
255 Compile* C = _stringopts->C; | |
256 CallProjections projs; | |
257 call->extract_projections(&projs, false); | |
258 if (projs.fallthrough_catchproj != NULL) { | |
259 C->gvn_replace_by(projs.fallthrough_catchproj, call->in(TypeFunc::Control)); | |
260 } | |
261 if (projs.fallthrough_memproj != NULL) { | |
262 C->gvn_replace_by(projs.fallthrough_memproj, call->in(TypeFunc::Memory)); | |
263 } | |
264 if (projs.catchall_memproj != NULL) { | |
265 C->gvn_replace_by(projs.catchall_memproj, C->top()); | |
266 } | |
267 if (projs.fallthrough_ioproj != NULL) { | |
268 C->gvn_replace_by(projs.fallthrough_ioproj, call->in(TypeFunc::I_O)); | |
269 } | |
270 if (projs.catchall_ioproj != NULL) { | |
271 C->gvn_replace_by(projs.catchall_ioproj, C->top()); | |
272 } | |
273 if (projs.catchall_catchproj != NULL) { | |
274 // EA can't cope with the partially collapsed graph this | |
275 // creates so put it on the worklist to be collapsed later. | |
276 for (SimpleDUIterator i(projs.catchall_catchproj); i.has_next(); i.next()) { | |
277 Node *use = i.get(); | |
278 int opc = use->Opcode(); | |
279 if (opc == Op_CreateEx || opc == Op_Region) { | |
280 _stringopts->record_dead_node(use); | |
281 } | |
282 } | |
283 C->gvn_replace_by(projs.catchall_catchproj, C->top()); | |
284 } | |
285 if (projs.resproj != NULL) { | |
286 C->gvn_replace_by(projs.resproj, C->top()); | |
287 } | |
288 C->gvn_replace_by(call, C->top()); | |
289 } | |
290 | |
291 void StringConcat::eliminate_initialize(InitializeNode* init) { | |
292 Compile* C = _stringopts->C; | |
293 | |
294 // Eliminate Initialize node. | |
295 assert(init->outcnt() <= 2, "only a control and memory projection expected"); | |
296 assert(init->req() <= InitializeNode::RawStores, "no pending inits"); | |
297 Node *ctrl_proj = init->proj_out(TypeFunc::Control); | |
298 if (ctrl_proj != NULL) { | |
299 C->gvn_replace_by(ctrl_proj, init->in(TypeFunc::Control)); | |
300 } | |
301 Node *mem_proj = init->proj_out(TypeFunc::Memory); | |
302 if (mem_proj != NULL) { | |
303 Node *mem = init->in(TypeFunc::Memory); | |
304 C->gvn_replace_by(mem_proj, mem); | |
305 } | |
306 C->gvn_replace_by(init, C->top()); | |
307 init->disconnect_inputs(NULL); | |
308 } | |
309 | |
310 Node_List PhaseStringOpts::collect_toString_calls() { | |
311 Node_List string_calls; | |
312 Node_List worklist; | |
313 | |
314 _visited.Clear(); | |
315 | |
316 // Prime the worklist | |
317 for (uint i = 1; i < C->root()->len(); i++) { | |
318 Node* n = C->root()->in(i); | |
319 if (n != NULL && !_visited.test_set(n->_idx)) { | |
320 worklist.push(n); | |
321 } | |
322 } | |
323 | |
324 while (worklist.size() > 0) { | |
325 Node* ctrl = worklist.pop(); | |
326 if (ctrl->is_CallStaticJava()) { | |
327 CallStaticJavaNode* csj = ctrl->as_CallStaticJava(); | |
328 ciMethod* m = csj->method(); | |
329 if (m != NULL && | |
330 (m->intrinsic_id() == vmIntrinsics::_StringBuffer_toString || | |
331 m->intrinsic_id() == vmIntrinsics::_StringBuilder_toString)) { | |
332 string_calls.push(csj); | |
333 } | |
334 } | |
335 if (ctrl->in(0) != NULL && !_visited.test_set(ctrl->in(0)->_idx)) { | |
336 worklist.push(ctrl->in(0)); | |
337 } | |
338 if (ctrl->is_Region()) { | |
339 for (uint i = 1; i < ctrl->len(); i++) { | |
340 if (ctrl->in(i) != NULL && !_visited.test_set(ctrl->in(i)->_idx)) { | |
341 worklist.push(ctrl->in(i)); | |
342 } | |
343 } | |
344 } | |
345 } | |
346 return string_calls; | |
347 } | |
348 | |
349 | |
350 StringConcat* PhaseStringOpts::build_candidate(CallStaticJavaNode* call) { | |
351 ciMethod* m = call->method(); | |
352 ciSymbol* string_sig; | |
353 ciSymbol* int_sig; | |
354 ciSymbol* char_sig; | |
355 if (m->holder() == C->env()->StringBuilder_klass()) { | |
356 string_sig = ciSymbol::String_StringBuilder_signature(); | |
357 int_sig = ciSymbol::int_StringBuilder_signature(); | |
358 char_sig = ciSymbol::char_StringBuilder_signature(); | |
359 } else if (m->holder() == C->env()->StringBuffer_klass()) { | |
360 string_sig = ciSymbol::String_StringBuffer_signature(); | |
361 int_sig = ciSymbol::int_StringBuffer_signature(); | |
362 char_sig = ciSymbol::char_StringBuffer_signature(); | |
363 } else { | |
364 return NULL; | |
365 } | |
366 #ifndef PRODUCT | |
367 if (PrintOptimizeStringConcat) { | |
368 tty->print("considering toString call in "); | |
369 call->jvms()->dump_spec(tty); tty->cr(); | |
370 } | |
371 #endif | |
372 | |
373 StringConcat* sc = new StringConcat(this, call); | |
374 | |
375 AllocateNode* alloc = NULL; | |
376 InitializeNode* init = NULL; | |
377 | |
378 // possible opportunity for StringBuilder fusion | |
379 CallStaticJavaNode* cnode = call; | |
380 while (cnode) { | |
381 Node* recv = cnode->in(TypeFunc::Parms)->uncast(); | |
382 if (recv->is_Proj()) { | |
383 recv = recv->in(0); | |
384 } | |
385 cnode = recv->isa_CallStaticJava(); | |
386 if (cnode == NULL) { | |
387 alloc = recv->isa_Allocate(); | |
388 if (alloc == NULL) { | |
389 break; | |
390 } | |
391 // Find the constructor call | |
392 Node* result = alloc->result_cast(); | |
393 if (result == NULL || !result->is_CheckCastPP()) { | |
394 // strange looking allocation | |
395 #ifndef PRODUCT | |
396 if (PrintOptimizeStringConcat) { | |
397 tty->print("giving up because allocation looks strange "); | |
398 alloc->jvms()->dump_spec(tty); tty->cr(); | |
399 } | |
400 #endif | |
401 break; | |
402 } | |
403 Node* constructor = NULL; | |
404 for (SimpleDUIterator i(result); i.has_next(); i.next()) { | |
405 CallStaticJavaNode *use = i.get()->isa_CallStaticJava(); | |
1817
c40600e85311
6986028: assert(_base == Int) failed: Not an Int in CmpINode::sub
never
parents:
1748
diff
changeset
|
406 if (use != NULL && |
c40600e85311
6986028: assert(_base == Int) failed: Not an Int in CmpINode::sub
never
parents:
1748
diff
changeset
|
407 use->method() != NULL && |
c40600e85311
6986028: assert(_base == Int) failed: Not an Int in CmpINode::sub
never
parents:
1748
diff
changeset
|
408 !use->method()->is_static() && |
1080 | 409 use->method()->name() == ciSymbol::object_initializer_name() && |
410 use->method()->holder() == m->holder()) { | |
411 // Matched the constructor. | |
412 ciSymbol* sig = use->method()->signature()->as_symbol(); | |
413 if (sig == ciSymbol::void_method_signature() || | |
414 sig == ciSymbol::int_void_signature() || | |
415 sig == ciSymbol::string_void_signature()) { | |
416 if (sig == ciSymbol::string_void_signature()) { | |
417 // StringBuilder(String) so pick this up as the first argument | |
418 assert(use->in(TypeFunc::Parms + 1) != NULL, "what?"); | |
419 sc->push_string(use->in(TypeFunc::Parms + 1)); | |
420 } | |
421 // The int variant takes an initial size for the backing | |
422 // array so just treat it like the void version. | |
423 constructor = use; | |
424 } else { | |
425 #ifndef PRODUCT | |
426 if (PrintOptimizeStringConcat) { | |
427 tty->print("unexpected constructor signature: %s", sig->as_utf8()); | |
428 } | |
429 #endif | |
430 } | |
431 break; | |
432 } | |
433 } | |
434 if (constructor == NULL) { | |
435 // couldn't find constructor | |
436 #ifndef PRODUCT | |
437 if (PrintOptimizeStringConcat) { | |
438 tty->print("giving up because couldn't find constructor "); | |
439 alloc->jvms()->dump_spec(tty); | |
440 } | |
441 #endif | |
442 break; | |
443 } | |
444 | |
445 // Walked all the way back and found the constructor call so see | |
446 // if this call converted into a direct string concatenation. | |
447 sc->add_control(call); | |
448 sc->add_control(constructor); | |
449 sc->add_control(alloc); | |
450 sc->set_allocation(alloc); | |
451 if (sc->validate_control_flow()) { | |
452 return sc; | |
453 } else { | |
454 return NULL; | |
455 } | |
456 } else if (cnode->method() == NULL) { | |
457 break; | |
1817
c40600e85311
6986028: assert(_base == Int) failed: Not an Int in CmpINode::sub
never
parents:
1748
diff
changeset
|
458 } else if (!cnode->method()->is_static() && |
c40600e85311
6986028: assert(_base == Int) failed: Not an Int in CmpINode::sub
never
parents:
1748
diff
changeset
|
459 cnode->method()->holder() == m->holder() && |
1080 | 460 cnode->method()->name() == ciSymbol::append_name() && |
461 (cnode->method()->signature()->as_symbol() == string_sig || | |
462 cnode->method()->signature()->as_symbol() == char_sig || | |
463 cnode->method()->signature()->as_symbol() == int_sig)) { | |
464 sc->add_control(cnode); | |
465 Node* arg = cnode->in(TypeFunc::Parms + 1); | |
466 if (cnode->method()->signature()->as_symbol() == int_sig) { | |
467 sc->push_int(arg); | |
468 } else if (cnode->method()->signature()->as_symbol() == char_sig) { | |
469 sc->push_char(arg); | |
470 } else { | |
471 if (arg->is_Proj() && arg->in(0)->is_CallStaticJava()) { | |
472 CallStaticJavaNode* csj = arg->in(0)->as_CallStaticJava(); | |
473 if (csj->method() != NULL && | |
1817
c40600e85311
6986028: assert(_base == Int) failed: Not an Int in CmpINode::sub
never
parents:
1748
diff
changeset
|
474 csj->method()->intrinsic_id() == vmIntrinsics::_Integer_toString) { |
1080 | 475 sc->add_control(csj); |
476 sc->push_int(csj->in(TypeFunc::Parms)); | |
477 continue; | |
478 } | |
479 } | |
480 sc->push_string(arg); | |
481 } | |
482 continue; | |
483 } else { | |
484 // some unhandled signature | |
485 #ifndef PRODUCT | |
486 if (PrintOptimizeStringConcat) { | |
487 tty->print("giving up because encountered unexpected signature "); | |
488 cnode->tf()->dump(); tty->cr(); | |
489 cnode->in(TypeFunc::Parms + 1)->dump(); | |
490 } | |
491 #endif | |
492 break; | |
493 } | |
494 } | |
495 return NULL; | |
496 } | |
497 | |
498 | |
499 PhaseStringOpts::PhaseStringOpts(PhaseGVN* gvn, Unique_Node_List*): | |
500 Phase(StringOpts), | |
501 _gvn(gvn), | |
502 _visited(Thread::current()->resource_area()) { | |
503 | |
504 assert(OptimizeStringConcat, "shouldn't be here"); | |
505 | |
506 size_table_field = C->env()->Integer_klass()->get_field_by_name(ciSymbol::make("sizeTable"), | |
507 ciSymbol::make("[I"), true); | |
508 if (size_table_field == NULL) { | |
509 // Something wrong so give up. | |
510 assert(false, "why can't we find Integer.sizeTable?"); | |
511 return; | |
512 } | |
513 | |
514 // Collect the types needed to talk about the various slices of memory | |
515 const TypeInstPtr* string_type = TypeInstPtr::make(TypePtr::NotNull, C->env()->String_klass(), | |
516 false, NULL, 0); | |
517 | |
518 const TypePtr* value_field_type = string_type->add_offset(java_lang_String::value_offset_in_bytes()); | |
519 const TypePtr* offset_field_type = string_type->add_offset(java_lang_String::offset_offset_in_bytes()); | |
520 const TypePtr* count_field_type = string_type->add_offset(java_lang_String::count_offset_in_bytes()); | |
521 | |
522 value_field_idx = C->get_alias_index(value_field_type); | |
523 count_field_idx = C->get_alias_index(count_field_type); | |
524 offset_field_idx = C->get_alias_index(offset_field_type); | |
525 char_adr_idx = C->get_alias_index(TypeAryPtr::CHARS); | |
526 | |
527 // For each locally allocated StringBuffer see if the usages can be | |
528 // collapsed into a single String construction. | |
529 | |
530 // Run through the list of allocation looking for SB.toString to see | |
531 // if it's possible to fuse the usage of the SB into a single String | |
532 // construction. | |
533 GrowableArray<StringConcat*> concats; | |
534 Node_List toStrings = collect_toString_calls(); | |
535 while (toStrings.size() > 0) { | |
536 StringConcat* sc = build_candidate(toStrings.pop()->as_CallStaticJava()); | |
537 if (sc != NULL) { | |
538 concats.push(sc); | |
539 } | |
540 } | |
541 | |
542 // try to coalesce separate concats | |
543 restart: | |
544 for (int c = 0; c < concats.length(); c++) { | |
545 StringConcat* sc = concats.at(c); | |
546 for (int i = 0; i < sc->num_arguments(); i++) { | |
547 Node* arg = sc->argument(i); | |
548 if (arg->is_Proj() && arg->in(0)->is_CallStaticJava()) { | |
549 CallStaticJavaNode* csj = arg->in(0)->as_CallStaticJava(); | |
550 if (csj->method() != NULL && | |
1817
c40600e85311
6986028: assert(_base == Int) failed: Not an Int in CmpINode::sub
never
parents:
1748
diff
changeset
|
551 (csj->method()->intrinsic_id() == vmIntrinsics::_StringBuilder_toString || |
c40600e85311
6986028: assert(_base == Int) failed: Not an Int in CmpINode::sub
never
parents:
1748
diff
changeset
|
552 csj->method()->intrinsic_id() == vmIntrinsics::_StringBuffer_toString)) { |
1080 | 553 for (int o = 0; o < concats.length(); o++) { |
554 if (c == o) continue; | |
555 StringConcat* other = concats.at(o); | |
556 if (other->end() == csj) { | |
557 #ifndef PRODUCT | |
558 if (PrintOptimizeStringConcat) { | |
559 tty->print_cr("considering stacked concats"); | |
560 } | |
561 #endif | |
562 | |
563 StringConcat* merged = sc->merge(other, arg); | |
564 if (merged->validate_control_flow()) { | |
565 #ifndef PRODUCT | |
566 if (PrintOptimizeStringConcat) { | |
567 tty->print_cr("stacking would succeed"); | |
568 } | |
569 #endif | |
570 if (c < o) { | |
571 concats.remove_at(o); | |
572 concats.at_put(c, merged); | |
573 } else { | |
574 concats.remove_at(c); | |
575 concats.at_put(o, merged); | |
576 } | |
577 goto restart; | |
578 } else { | |
579 #ifndef PRODUCT | |
580 if (PrintOptimizeStringConcat) { | |
581 tty->print_cr("stacking would fail"); | |
582 } | |
583 #endif | |
584 } | |
585 } | |
586 } | |
587 } | |
588 } | |
589 } | |
590 } | |
591 | |
592 | |
593 for (int c = 0; c < concats.length(); c++) { | |
594 StringConcat* sc = concats.at(c); | |
595 replace_string_concat(sc); | |
596 } | |
597 | |
598 remove_dead_nodes(); | |
599 } | |
600 | |
601 void PhaseStringOpts::record_dead_node(Node* dead) { | |
602 dead_worklist.push(dead); | |
603 } | |
604 | |
605 void PhaseStringOpts::remove_dead_nodes() { | |
606 // Delete any dead nodes to make things clean enough that escape | |
607 // analysis doesn't get unhappy. | |
608 while (dead_worklist.size() > 0) { | |
609 Node* use = dead_worklist.pop(); | |
610 int opc = use->Opcode(); | |
611 switch (opc) { | |
612 case Op_Region: { | |
613 uint i = 1; | |
614 for (i = 1; i < use->req(); i++) { | |
615 if (use->in(i) != C->top()) { | |
616 break; | |
617 } | |
618 } | |
619 if (i >= use->req()) { | |
620 for (SimpleDUIterator i(use); i.has_next(); i.next()) { | |
621 Node* m = i.get(); | |
622 if (m->is_Phi()) { | |
623 dead_worklist.push(m); | |
624 } | |
625 } | |
626 C->gvn_replace_by(use, C->top()); | |
627 } | |
628 break; | |
629 } | |
630 case Op_AddP: | |
631 case Op_CreateEx: { | |
632 // Recurisvely clean up references to CreateEx so EA doesn't | |
633 // get unhappy about the partially collapsed graph. | |
634 for (SimpleDUIterator i(use); i.has_next(); i.next()) { | |
635 Node* m = i.get(); | |
636 if (m->is_AddP()) { | |
637 dead_worklist.push(m); | |
638 } | |
639 } | |
640 C->gvn_replace_by(use, C->top()); | |
641 break; | |
642 } | |
643 case Op_Phi: | |
644 if (use->in(0) == C->top()) { | |
645 C->gvn_replace_by(use, C->top()); | |
646 } | |
647 break; | |
648 } | |
649 } | |
650 } | |
651 | |
652 | |
653 bool StringConcat::validate_control_flow() { | |
654 // We found all the calls and arguments now lets see if it's | |
655 // safe to transform the graph as we would expect. | |
656 | |
657 // Check to see if this resulted in too many uncommon traps previously | |
658 if (Compile::current()->too_many_traps(_begin->jvms()->method(), _begin->jvms()->bci(), | |
659 Deoptimization::Reason_intrinsic)) { | |
660 return false; | |
661 } | |
662 | |
663 // Walk backwards over the control flow from toString to the | |
664 // allocation and make sure all the control flow is ok. This | |
665 // means it's either going to be eliminated once the calls are | |
666 // removed or it can safely be transformed into an uncommon | |
667 // trap. | |
668 | |
669 int null_check_count = 0; | |
670 Unique_Node_List ctrl_path; | |
671 | |
672 assert(_control.contains(_begin), "missing"); | |
673 assert(_control.contains(_end), "missing"); | |
674 | |
675 // Collect the nodes that we know about and will eliminate into ctrl_path | |
676 for (uint i = 0; i < _control.size(); i++) { | |
677 // Push the call and it's control projection | |
678 Node* n = _control.at(i); | |
679 if (n->is_Allocate()) { | |
680 AllocateNode* an = n->as_Allocate(); | |
681 InitializeNode* init = an->initialization(); | |
682 ctrl_path.push(init); | |
683 ctrl_path.push(init->as_Multi()->proj_out(0)); | |
684 } | |
685 if (n->is_Call()) { | |
686 CallNode* cn = n->as_Call(); | |
687 ctrl_path.push(cn); | |
688 ctrl_path.push(cn->proj_out(0)); | |
689 ctrl_path.push(cn->proj_out(0)->unique_out()); | |
690 ctrl_path.push(cn->proj_out(0)->unique_out()->as_Catch()->proj_out(0)); | |
691 } else { | |
692 ShouldNotReachHere(); | |
693 } | |
694 } | |
695 | |
696 // Skip backwards through the control checking for unexpected contro flow | |
697 Node* ptr = _end; | |
698 bool fail = false; | |
699 while (ptr != _begin) { | |
700 if (ptr->is_Call() && ctrl_path.member(ptr)) { | |
701 ptr = ptr->in(0); | |
702 } else if (ptr->is_CatchProj() && ctrl_path.member(ptr)) { | |
703 ptr = ptr->in(0)->in(0)->in(0); | |
704 assert(ctrl_path.member(ptr), "should be a known piece of control"); | |
705 } else if (ptr->is_IfTrue()) { | |
706 IfNode* iff = ptr->in(0)->as_If(); | |
707 BoolNode* b = iff->in(1)->isa_Bool(); | |
708 Node* cmp = b->in(1); | |
709 Node* v1 = cmp->in(1); | |
710 Node* v2 = cmp->in(2); | |
711 Node* otherproj = iff->proj_out(1 - ptr->as_Proj()->_con); | |
712 | |
713 // Null check of the return of append which can simply be eliminated | |
714 if (b->_test._test == BoolTest::ne && | |
715 v2->bottom_type() == TypePtr::NULL_PTR && | |
716 v1->is_Proj() && ctrl_path.member(v1->in(0))) { | |
717 // NULL check of the return value of the append | |
718 null_check_count++; | |
719 if (otherproj->outcnt() == 1) { | |
720 CallStaticJavaNode* call = otherproj->unique_out()->isa_CallStaticJava(); | |
721 if (call != NULL && call->_name != NULL && strcmp(call->_name, "uncommon_trap") == 0) { | |
722 ctrl_path.push(call); | |
723 } | |
724 } | |
725 _control.push(ptr); | |
726 ptr = ptr->in(0)->in(0); | |
727 continue; | |
728 } | |
729 | |
730 // A test which leads to an uncommon trap which should be safe. | |
731 // Later this trap will be converted into a trap that restarts | |
732 // at the beginning. | |
733 if (otherproj->outcnt() == 1) { | |
734 CallStaticJavaNode* call = otherproj->unique_out()->isa_CallStaticJava(); | |
735 if (call != NULL && call->_name != NULL && strcmp(call->_name, "uncommon_trap") == 0) { | |
736 // control flow leads to uct so should be ok | |
737 _uncommon_traps.push(call); | |
738 ctrl_path.push(call); | |
739 ptr = ptr->in(0)->in(0); | |
740 continue; | |
741 } | |
742 } | |
743 | |
744 #ifndef PRODUCT | |
745 // Some unexpected control flow we don't know how to handle. | |
746 if (PrintOptimizeStringConcat) { | |
747 tty->print_cr("failing with unknown test"); | |
748 b->dump(); | |
749 cmp->dump(); | |
750 v1->dump(); | |
751 v2->dump(); | |
752 tty->cr(); | |
753 } | |
754 #endif | |
755 break; | |
756 } else if (ptr->is_Proj() && ptr->in(0)->is_Initialize()) { | |
757 ptr = ptr->in(0)->in(0); | |
758 } else if (ptr->is_Region()) { | |
759 Node* copy = ptr->as_Region()->is_copy(); | |
760 if (copy != NULL) { | |
761 ptr = copy; | |
762 continue; | |
763 } | |
764 if (ptr->req() == 3 && | |
765 ptr->in(1) != NULL && ptr->in(1)->is_Proj() && | |
766 ptr->in(2) != NULL && ptr->in(2)->is_Proj() && | |
767 ptr->in(1)->in(0) == ptr->in(2)->in(0) && | |
768 ptr->in(1)->in(0) != NULL && ptr->in(1)->in(0)->is_If()) { | |
769 // Simple diamond. | |
770 // XXX should check for possibly merging stores. simple data merges are ok. | |
771 ptr = ptr->in(1)->in(0)->in(0); | |
772 continue; | |
773 } | |
774 #ifndef PRODUCT | |
775 if (PrintOptimizeStringConcat) { | |
776 tty->print_cr("fusion would fail for region"); | |
777 _begin->dump(); | |
778 ptr->dump(2); | |
779 } | |
780 #endif | |
781 fail = true; | |
782 break; | |
783 } else { | |
784 // other unknown control | |
785 if (!fail) { | |
786 #ifndef PRODUCT | |
787 if (PrintOptimizeStringConcat) { | |
788 tty->print_cr("fusion would fail for"); | |
789 _begin->dump(); | |
790 } | |
791 #endif | |
792 fail = true; | |
793 } | |
794 #ifndef PRODUCT | |
795 if (PrintOptimizeStringConcat) { | |
796 ptr->dump(); | |
797 } | |
798 #endif | |
799 ptr = ptr->in(0); | |
800 } | |
801 } | |
802 #ifndef PRODUCT | |
803 if (PrintOptimizeStringConcat && fail) { | |
804 tty->cr(); | |
805 } | |
806 #endif | |
807 if (fail) return !fail; | |
808 | |
809 // Validate that all these results produced are contained within | |
810 // this cluster of objects. First collect all the results produced | |
811 // by calls in the region. | |
812 _stringopts->_visited.Clear(); | |
813 Node_List worklist; | |
814 Node* final_result = _end->proj_out(TypeFunc::Parms); | |
815 for (uint i = 0; i < _control.size(); i++) { | |
816 CallNode* cnode = _control.at(i)->isa_Call(); | |
817 if (cnode != NULL) { | |
818 _stringopts->_visited.test_set(cnode->_idx); | |
819 } | |
820 Node* result = cnode != NULL ? cnode->proj_out(TypeFunc::Parms) : NULL; | |
821 if (result != NULL && result != final_result) { | |
822 worklist.push(result); | |
823 } | |
824 } | |
825 | |
826 Node* last_result = NULL; | |
827 while (worklist.size() > 0) { | |
828 Node* result = worklist.pop(); | |
829 if (_stringopts->_visited.test_set(result->_idx)) | |
830 continue; | |
831 for (SimpleDUIterator i(result); i.has_next(); i.next()) { | |
832 Node *use = i.get(); | |
833 if (ctrl_path.member(use)) { | |
834 // already checked this | |
835 continue; | |
836 } | |
837 int opc = use->Opcode(); | |
838 if (opc == Op_CmpP || opc == Op_Node) { | |
839 ctrl_path.push(use); | |
840 continue; | |
841 } | |
842 if (opc == Op_CastPP || opc == Op_CheckCastPP) { | |
843 for (SimpleDUIterator j(use); j.has_next(); j.next()) { | |
844 worklist.push(j.get()); | |
845 } | |
846 worklist.push(use->in(1)); | |
847 ctrl_path.push(use); | |
848 continue; | |
849 } | |
850 #ifndef PRODUCT | |
851 if (PrintOptimizeStringConcat) { | |
852 if (result != last_result) { | |
853 last_result = result; | |
854 tty->print_cr("extra uses for result:"); | |
855 last_result->dump(); | |
856 } | |
857 use->dump(); | |
858 } | |
859 #endif | |
860 fail = true; | |
861 break; | |
862 } | |
863 } | |
864 | |
865 #ifndef PRODUCT | |
866 if (PrintOptimizeStringConcat && !fail) { | |
867 ttyLocker ttyl; | |
868 tty->cr(); | |
869 tty->print("fusion would succeed (%d %d) for ", null_check_count, _uncommon_traps.size()); | |
870 _begin->jvms()->dump_spec(tty); tty->cr(); | |
871 for (int i = 0; i < num_arguments(); i++) { | |
872 argument(i)->dump(); | |
873 } | |
874 _control.dump(); | |
875 tty->cr(); | |
876 } | |
877 #endif | |
878 | |
879 return !fail; | |
880 } | |
881 | |
882 Node* PhaseStringOpts::fetch_static_field(GraphKit& kit, ciField* field) { | |
883 const TypeKlassPtr* klass_type = TypeKlassPtr::make(field->holder()); | |
884 Node* klass_node = __ makecon(klass_type); | |
885 BasicType bt = field->layout_type(); | |
886 ciType* field_klass = field->type(); | |
887 | |
888 const Type *type; | |
889 if( bt == T_OBJECT ) { | |
890 if (!field->type()->is_loaded()) { | |
891 type = TypeInstPtr::BOTTOM; | |
892 } else if (field->is_constant()) { | |
893 // This can happen if the constant oop is non-perm. | |
894 ciObject* con = field->constant_value().as_object(); | |
895 // Do not "join" in the previous type; it doesn't add value, | |
896 // and may yield a vacuous result if the field is of interface type. | |
897 type = TypeOopPtr::make_from_constant(con)->isa_oopptr(); | |
898 assert(type != NULL, "field singleton type must be consistent"); | |
899 } else { | |
900 type = TypeOopPtr::make_from_klass(field_klass->as_klass()); | |
901 } | |
902 } else { | |
903 type = Type::get_const_basic_type(bt); | |
904 } | |
905 | |
906 return kit.make_load(NULL, kit.basic_plus_adr(klass_node, field->offset_in_bytes()), | |
907 type, T_OBJECT, | |
908 C->get_alias_index(klass_type->add_offset(field->offset_in_bytes()))); | |
909 } | |
910 | |
911 Node* PhaseStringOpts::int_stringSize(GraphKit& kit, Node* arg) { | |
912 RegionNode *final_merge = new (C, 3) RegionNode(3); | |
913 kit.gvn().set_type(final_merge, Type::CONTROL); | |
914 Node* final_size = new (C, 3) PhiNode(final_merge, TypeInt::INT); | |
915 kit.gvn().set_type(final_size, TypeInt::INT); | |
916 | |
917 IfNode* iff = kit.create_and_map_if(kit.control(), | |
918 __ Bool(__ CmpI(arg, __ intcon(0x80000000)), BoolTest::ne), | |
919 PROB_FAIR, COUNT_UNKNOWN); | |
920 Node* is_min = __ IfFalse(iff); | |
921 final_merge->init_req(1, is_min); | |
922 final_size->init_req(1, __ intcon(11)); | |
923 | |
924 kit.set_control(__ IfTrue(iff)); | |
925 if (kit.stopped()) { | |
926 final_merge->init_req(2, C->top()); | |
927 final_size->init_req(2, C->top()); | |
928 } else { | |
929 | |
930 // int size = (i < 0) ? stringSize(-i) + 1 : stringSize(i); | |
931 RegionNode *r = new (C, 3) RegionNode(3); | |
932 kit.gvn().set_type(r, Type::CONTROL); | |
933 Node *phi = new (C, 3) PhiNode(r, TypeInt::INT); | |
934 kit.gvn().set_type(phi, TypeInt::INT); | |
935 Node *size = new (C, 3) PhiNode(r, TypeInt::INT); | |
936 kit.gvn().set_type(size, TypeInt::INT); | |
937 Node* chk = __ CmpI(arg, __ intcon(0)); | |
938 Node* p = __ Bool(chk, BoolTest::lt); | |
939 IfNode* iff = kit.create_and_map_if(kit.control(), p, PROB_FAIR, COUNT_UNKNOWN); | |
940 Node* lessthan = __ IfTrue(iff); | |
941 Node* greaterequal = __ IfFalse(iff); | |
942 r->init_req(1, lessthan); | |
943 phi->init_req(1, __ SubI(__ intcon(0), arg)); | |
944 size->init_req(1, __ intcon(1)); | |
945 r->init_req(2, greaterequal); | |
946 phi->init_req(2, arg); | |
947 size->init_req(2, __ intcon(0)); | |
948 kit.set_control(r); | |
949 C->record_for_igvn(r); | |
950 C->record_for_igvn(phi); | |
951 C->record_for_igvn(size); | |
952 | |
953 // for (int i=0; ; i++) | |
954 // if (x <= sizeTable[i]) | |
955 // return i+1; | |
956 RegionNode *loop = new (C, 3) RegionNode(3); | |
957 loop->init_req(1, kit.control()); | |
958 kit.gvn().set_type(loop, Type::CONTROL); | |
959 | |
960 Node *index = new (C, 3) PhiNode(loop, TypeInt::INT); | |
961 index->init_req(1, __ intcon(0)); | |
962 kit.gvn().set_type(index, TypeInt::INT); | |
963 kit.set_control(loop); | |
964 Node* sizeTable = fetch_static_field(kit, size_table_field); | |
965 | |
966 Node* value = kit.load_array_element(NULL, sizeTable, index, TypeAryPtr::INTS); | |
967 C->record_for_igvn(value); | |
968 Node* limit = __ CmpI(phi, value); | |
969 Node* limitb = __ Bool(limit, BoolTest::le); | |
970 IfNode* iff2 = kit.create_and_map_if(kit.control(), limitb, PROB_MIN, COUNT_UNKNOWN); | |
971 Node* lessEqual = __ IfTrue(iff2); | |
972 Node* greater = __ IfFalse(iff2); | |
973 | |
974 loop->init_req(2, greater); | |
975 index->init_req(2, __ AddI(index, __ intcon(1))); | |
976 | |
977 kit.set_control(lessEqual); | |
978 C->record_for_igvn(loop); | |
979 C->record_for_igvn(index); | |
980 | |
981 final_merge->init_req(2, kit.control()); | |
982 final_size->init_req(2, __ AddI(__ AddI(index, size), __ intcon(1))); | |
983 } | |
984 | |
985 kit.set_control(final_merge); | |
986 C->record_for_igvn(final_merge); | |
987 C->record_for_igvn(final_size); | |
988 | |
989 return final_size; | |
990 } | |
991 | |
992 void PhaseStringOpts::int_getChars(GraphKit& kit, Node* arg, Node* char_array, Node* start, Node* end) { | |
993 RegionNode *final_merge = new (C, 4) RegionNode(4); | |
994 kit.gvn().set_type(final_merge, Type::CONTROL); | |
995 Node *final_mem = PhiNode::make(final_merge, kit.memory(char_adr_idx), Type::MEMORY, TypeAryPtr::CHARS); | |
996 kit.gvn().set_type(final_mem, Type::MEMORY); | |
997 | |
998 // need to handle Integer.MIN_VALUE specially because negating doesn't make it positive | |
999 { | |
1000 // i == MIN_VALUE | |
1001 IfNode* iff = kit.create_and_map_if(kit.control(), | |
1002 __ Bool(__ CmpI(arg, __ intcon(0x80000000)), BoolTest::ne), | |
1003 PROB_FAIR, COUNT_UNKNOWN); | |
1004 | |
1005 Node* old_mem = kit.memory(char_adr_idx); | |
1006 | |
1007 kit.set_control(__ IfFalse(iff)); | |
1008 if (kit.stopped()) { | |
1009 // Statically not equal to MIN_VALUE so this path is dead | |
1010 final_merge->init_req(3, kit.control()); | |
1011 } else { | |
1012 copy_string(kit, __ makecon(TypeInstPtr::make(C->env()->the_min_jint_string())), | |
1013 char_array, start); | |
1014 final_merge->init_req(3, kit.control()); | |
1015 final_mem->init_req(3, kit.memory(char_adr_idx)); | |
1016 } | |
1017 | |
1018 kit.set_control(__ IfTrue(iff)); | |
1019 kit.set_memory(old_mem, char_adr_idx); | |
1020 } | |
1021 | |
1022 | |
1023 // Simplified version of Integer.getChars | |
1024 | |
1025 // int q, r; | |
1026 // int charPos = index; | |
1027 Node* charPos = end; | |
1028 | |
1029 // char sign = 0; | |
1030 | |
1031 Node* i = arg; | |
1032 Node* sign = __ intcon(0); | |
1033 | |
1034 // if (i < 0) { | |
1035 // sign = '-'; | |
1036 // i = -i; | |
1037 // } | |
1038 { | |
1039 IfNode* iff = kit.create_and_map_if(kit.control(), | |
1040 __ Bool(__ CmpI(arg, __ intcon(0)), BoolTest::lt), | |
1041 PROB_FAIR, COUNT_UNKNOWN); | |
1042 | |
1043 RegionNode *merge = new (C, 3) RegionNode(3); | |
1044 kit.gvn().set_type(merge, Type::CONTROL); | |
1045 i = new (C, 3) PhiNode(merge, TypeInt::INT); | |
1046 kit.gvn().set_type(i, TypeInt::INT); | |
1047 sign = new (C, 3) PhiNode(merge, TypeInt::INT); | |
1048 kit.gvn().set_type(sign, TypeInt::INT); | |
1049 | |
1050 merge->init_req(1, __ IfTrue(iff)); | |
1051 i->init_req(1, __ SubI(__ intcon(0), arg)); | |
1052 sign->init_req(1, __ intcon('-')); | |
1053 merge->init_req(2, __ IfFalse(iff)); | |
1054 i->init_req(2, arg); | |
1055 sign->init_req(2, __ intcon(0)); | |
1056 | |
1057 kit.set_control(merge); | |
1058 | |
1059 C->record_for_igvn(merge); | |
1060 C->record_for_igvn(i); | |
1061 C->record_for_igvn(sign); | |
1062 } | |
1063 | |
1064 // for (;;) { | |
1065 // q = i / 10; | |
1066 // r = i - ((q << 3) + (q << 1)); // r = i-(q*10) ... | |
1067 // buf [--charPos] = digits [r]; | |
1068 // i = q; | |
1069 // if (i == 0) break; | |
1070 // } | |
1071 | |
1072 { | |
1073 RegionNode *head = new (C, 3) RegionNode(3); | |
1074 head->init_req(1, kit.control()); | |
1075 kit.gvn().set_type(head, Type::CONTROL); | |
1076 Node *i_phi = new (C, 3) PhiNode(head, TypeInt::INT); | |
1077 i_phi->init_req(1, i); | |
1078 kit.gvn().set_type(i_phi, TypeInt::INT); | |
1079 charPos = PhiNode::make(head, charPos); | |
1080 kit.gvn().set_type(charPos, TypeInt::INT); | |
1081 Node *mem = PhiNode::make(head, kit.memory(char_adr_idx), Type::MEMORY, TypeAryPtr::CHARS); | |
1082 kit.gvn().set_type(mem, Type::MEMORY); | |
1083 kit.set_control(head); | |
1084 kit.set_memory(mem, char_adr_idx); | |
1085 | |
1250 | 1086 Node* q = __ DivI(NULL, i_phi, __ intcon(10)); |
1080 | 1087 Node* r = __ SubI(i_phi, __ AddI(__ LShiftI(q, __ intcon(3)), |
1088 __ LShiftI(q, __ intcon(1)))); | |
1089 Node* m1 = __ SubI(charPos, __ intcon(1)); | |
1090 Node* ch = __ AddI(r, __ intcon('0')); | |
1091 | |
1092 Node* st = __ store_to_memory(kit.control(), kit.array_element_address(char_array, m1, T_CHAR), | |
1093 ch, T_CHAR, char_adr_idx); | |
1094 | |
1095 | |
1096 IfNode* iff = kit.create_and_map_if(head, __ Bool(__ CmpI(q, __ intcon(0)), BoolTest::ne), | |
1097 PROB_FAIR, COUNT_UNKNOWN); | |
1098 Node* ne = __ IfTrue(iff); | |
1099 Node* eq = __ IfFalse(iff); | |
1100 | |
1101 head->init_req(2, ne); | |
1102 mem->init_req(2, st); | |
1103 i_phi->init_req(2, q); | |
1104 charPos->init_req(2, m1); | |
1105 | |
1106 charPos = m1; | |
1107 | |
1108 kit.set_control(eq); | |
1109 kit.set_memory(st, char_adr_idx); | |
1110 | |
1111 C->record_for_igvn(head); | |
1112 C->record_for_igvn(mem); | |
1113 C->record_for_igvn(i_phi); | |
1114 C->record_for_igvn(charPos); | |
1115 } | |
1116 | |
1117 { | |
1118 // if (sign != 0) { | |
1119 // buf [--charPos] = sign; | |
1120 // } | |
1121 IfNode* iff = kit.create_and_map_if(kit.control(), | |
1122 __ Bool(__ CmpI(sign, __ intcon(0)), BoolTest::ne), | |
1123 PROB_FAIR, COUNT_UNKNOWN); | |
1124 | |
1125 final_merge->init_req(2, __ IfFalse(iff)); | |
1126 final_mem->init_req(2, kit.memory(char_adr_idx)); | |
1127 | |
1128 kit.set_control(__ IfTrue(iff)); | |
1129 if (kit.stopped()) { | |
1130 final_merge->init_req(1, C->top()); | |
1131 final_mem->init_req(1, C->top()); | |
1132 } else { | |
1133 Node* m1 = __ SubI(charPos, __ intcon(1)); | |
1134 Node* st = __ store_to_memory(kit.control(), kit.array_element_address(char_array, m1, T_CHAR), | |
1135 sign, T_CHAR, char_adr_idx); | |
1136 | |
1137 final_merge->init_req(1, kit.control()); | |
1138 final_mem->init_req(1, st); | |
1139 } | |
1140 | |
1141 kit.set_control(final_merge); | |
1142 kit.set_memory(final_mem, char_adr_idx); | |
1143 | |
1144 C->record_for_igvn(final_merge); | |
1145 C->record_for_igvn(final_mem); | |
1146 } | |
1147 } | |
1148 | |
1149 | |
1150 Node* PhaseStringOpts::copy_string(GraphKit& kit, Node* str, Node* char_array, Node* start) { | |
1151 Node* string = str; | |
1152 Node* offset = kit.make_load(NULL, | |
1153 kit.basic_plus_adr(string, string, java_lang_String::offset_offset_in_bytes()), | |
1154 TypeInt::INT, T_INT, offset_field_idx); | |
1155 Node* count = kit.make_load(NULL, | |
1156 kit.basic_plus_adr(string, string, java_lang_String::count_offset_in_bytes()), | |
1157 TypeInt::INT, T_INT, count_field_idx); | |
1158 const TypeAryPtr* value_type = TypeAryPtr::make(TypePtr::NotNull, | |
1159 TypeAry::make(TypeInt::CHAR,TypeInt::POS), | |
1160 ciTypeArrayKlass::make(T_CHAR), true, 0); | |
1161 Node* value = kit.make_load(NULL, | |
1162 kit.basic_plus_adr(string, string, java_lang_String::value_offset_in_bytes()), | |
1163 value_type, T_OBJECT, value_field_idx); | |
1164 | |
1165 // copy the contents | |
1166 if (offset->is_Con() && count->is_Con() && value->is_Con() && count->get_int() < unroll_string_copy_length) { | |
1167 // For small constant strings just emit individual stores. | |
1168 // A length of 6 seems like a good space/speed tradeof. | |
1169 int c = count->get_int(); | |
1170 int o = offset->get_int(); | |
1171 const TypeOopPtr* t = kit.gvn().type(value)->isa_oopptr(); | |
1172 ciTypeArray* value_array = t->const_oop()->as_type_array(); | |
1173 for (int e = 0; e < c; e++) { | |
1174 __ store_to_memory(kit.control(), kit.array_element_address(char_array, start, T_CHAR), | |
1175 __ intcon(value_array->char_at(o + e)), T_CHAR, char_adr_idx); | |
1176 start = __ AddI(start, __ intcon(1)); | |
1177 } | |
1178 } else { | |
1179 Node* src_ptr = kit.array_element_address(value, offset, T_CHAR); | |
1180 Node* dst_ptr = kit.array_element_address(char_array, start, T_CHAR); | |
1181 Node* c = count; | |
1182 Node* extra = NULL; | |
1183 #ifdef _LP64 | |
1184 c = __ ConvI2L(c); | |
1185 extra = C->top(); | |
1186 #endif | |
1187 Node* call = kit.make_runtime_call(GraphKit::RC_LEAF|GraphKit::RC_NO_FP, | |
1188 OptoRuntime::fast_arraycopy_Type(), | |
1189 CAST_FROM_FN_PTR(address, StubRoutines::jshort_disjoint_arraycopy()), | |
1190 "jshort_disjoint_arraycopy", TypeAryPtr::CHARS, | |
1191 src_ptr, dst_ptr, c, extra); | |
1192 start = __ AddI(start, count); | |
1193 } | |
1194 return start; | |
1195 } | |
1196 | |
1197 | |
1198 void PhaseStringOpts::replace_string_concat(StringConcat* sc) { | |
1199 // Log a little info about the transformation | |
1200 sc->maybe_log_transform(); | |
1201 | |
1202 // pull the JVMState of the allocation into a SafePointNode to serve as | |
1203 // as a shim for the insertion of the new code. | |
1204 JVMState* jvms = sc->begin()->jvms()->clone_shallow(C); | |
1205 uint size = sc->begin()->req(); | |
1206 SafePointNode* map = new (C, size) SafePointNode(size, jvms); | |
1207 | |
1208 // copy the control and memory state from the final call into our | |
1209 // new starting state. This allows any preceeding tests to feed | |
1210 // into the new section of code. | |
1211 for (uint i1 = 0; i1 < TypeFunc::Parms; i1++) { | |
1212 map->init_req(i1, sc->end()->in(i1)); | |
1213 } | |
1214 // blow away old allocation arguments | |
1215 for (uint i1 = TypeFunc::Parms; i1 < jvms->debug_start(); i1++) { | |
1216 map->init_req(i1, C->top()); | |
1217 } | |
1218 // Copy the rest of the inputs for the JVMState | |
1219 for (uint i1 = jvms->debug_start(); i1 < sc->begin()->req(); i1++) { | |
1220 map->init_req(i1, sc->begin()->in(i1)); | |
1221 } | |
1222 // Make sure the memory state is a MergeMem for parsing. | |
1223 if (!map->in(TypeFunc::Memory)->is_MergeMem()) { | |
1224 map->set_req(TypeFunc::Memory, MergeMemNode::make(C, map->in(TypeFunc::Memory))); | |
1225 } | |
1226 | |
1227 jvms->set_map(map); | |
1228 map->ensure_stack(jvms, jvms->method()->max_stack()); | |
1229 | |
1230 | |
1231 // disconnect all the old StringBuilder calls from the graph | |
1232 sc->eliminate_unneeded_control(); | |
1233 | |
1234 // At this point all the old work has been completely removed from | |
1235 // the graph and the saved JVMState exists at the point where the | |
1236 // final toString call used to be. | |
1237 GraphKit kit(jvms); | |
1238 | |
1239 // There may be uncommon traps which are still using the | |
1240 // intermediate states and these need to be rewritten to point at | |
1241 // the JVMState at the beginning of the transformation. | |
1242 sc->convert_uncommon_traps(kit, jvms); | |
1243 | |
1244 // Now insert the logic to compute the size of the string followed | |
1245 // by all the logic to construct array and resulting string. | |
1246 | |
1247 Node* null_string = __ makecon(TypeInstPtr::make(C->env()->the_null_string())); | |
1248 | |
1249 // Create a region for the overflow checks to merge into. | |
1250 int args = MAX2(sc->num_arguments(), 1); | |
1251 RegionNode* overflow = new (C, args) RegionNode(args); | |
1252 kit.gvn().set_type(overflow, Type::CONTROL); | |
1253 | |
1254 // Create a hook node to hold onto the individual sizes since they | |
1255 // are need for the copying phase. | |
1256 Node* string_sizes = new (C, args) Node(args); | |
1257 | |
1258 Node* length = __ intcon(0); | |
1259 for (int argi = 0; argi < sc->num_arguments(); argi++) { | |
1260 Node* arg = sc->argument(argi); | |
1261 switch (sc->mode(argi)) { | |
1262 case StringConcat::IntMode: { | |
1263 Node* string_size = int_stringSize(kit, arg); | |
1264 | |
1265 // accumulate total | |
1266 length = __ AddI(length, string_size); | |
1267 | |
1268 // Cache this value for the use by int_toString | |
1269 string_sizes->init_req(argi, string_size); | |
1270 break; | |
1271 } | |
1272 case StringConcat::StringMode: { | |
1273 const Type* type = kit.gvn().type(arg); | |
1274 if (type == TypePtr::NULL_PTR) { | |
1275 // replace the argument with the null checked version | |
1276 arg = null_string; | |
1277 sc->set_argument(argi, arg); | |
1278 } else if (!type->higher_equal(TypeInstPtr::NOTNULL)) { | |
1279 // s = s != null ? s : "null"; | |
1280 // length = length + (s.count - s.offset); | |
1281 RegionNode *r = new (C, 3) RegionNode(3); | |
1282 kit.gvn().set_type(r, Type::CONTROL); | |
1250 | 1283 Node *phi = new (C, 3) PhiNode(r, type); |
1080 | 1284 kit.gvn().set_type(phi, phi->bottom_type()); |
1285 Node* p = __ Bool(__ CmpP(arg, kit.null()), BoolTest::ne); | |
1286 IfNode* iff = kit.create_and_map_if(kit.control(), p, PROB_MIN, COUNT_UNKNOWN); | |
1287 Node* notnull = __ IfTrue(iff); | |
1288 Node* isnull = __ IfFalse(iff); | |
1250 | 1289 kit.set_control(notnull); // set control for the cast_not_null |
1080 | 1290 r->init_req(1, notnull); |
1250 | 1291 phi->init_req(1, kit.cast_not_null(arg, false)); |
1080 | 1292 r->init_req(2, isnull); |
1293 phi->init_req(2, null_string); | |
1294 kit.set_control(r); | |
1295 C->record_for_igvn(r); | |
1296 C->record_for_igvn(phi); | |
1297 // replace the argument with the null checked version | |
1298 arg = phi; | |
1299 sc->set_argument(argi, arg); | |
1300 } | |
1301 // Node* offset = kit.make_load(NULL, kit.basic_plus_adr(arg, arg, offset_offset), | |
1302 // TypeInt::INT, T_INT, offset_field_idx); | |
1303 Node* count = kit.make_load(NULL, kit.basic_plus_adr(arg, arg, java_lang_String::count_offset_in_bytes()), | |
1304 TypeInt::INT, T_INT, count_field_idx); | |
1305 length = __ AddI(length, count); | |
1306 string_sizes->init_req(argi, NULL); | |
1307 break; | |
1308 } | |
1309 case StringConcat::CharMode: { | |
1310 // one character only | |
1311 length = __ AddI(length, __ intcon(1)); | |
1312 break; | |
1313 } | |
1314 default: | |
1315 ShouldNotReachHere(); | |
1316 } | |
1317 if (argi > 0) { | |
1318 // Check that the sum hasn't overflowed | |
1319 IfNode* iff = kit.create_and_map_if(kit.control(), | |
1320 __ Bool(__ CmpI(length, __ intcon(0)), BoolTest::lt), | |
1321 PROB_MIN, COUNT_UNKNOWN); | |
1322 kit.set_control(__ IfFalse(iff)); | |
1323 overflow->set_req(argi, __ IfTrue(iff)); | |
1324 } | |
1325 } | |
1326 | |
1327 { | |
1328 // Hook | |
1329 PreserveJVMState pjvms(&kit); | |
1330 kit.set_control(overflow); | |
1331 kit.uncommon_trap(Deoptimization::Reason_intrinsic, | |
1332 Deoptimization::Action_make_not_entrant); | |
1333 } | |
1334 | |
1335 // length now contains the number of characters needed for the | |
1336 // char[] so create a new AllocateArray for the char[] | |
1337 Node* char_array = NULL; | |
1338 { | |
1339 PreserveReexecuteState preexecs(&kit); | |
1340 // The original jvms is for an allocation of either a String or | |
1341 // StringBuffer so no stack adjustment is necessary for proper | |
1342 // reexecution. If we deoptimize in the slow path the bytecode | |
1343 // will be reexecuted and the char[] allocation will be thrown away. | |
1344 kit.jvms()->set_should_reexecute(true); | |
1345 char_array = kit.new_array(__ makecon(TypeKlassPtr::make(ciTypeArrayKlass::make(T_CHAR))), | |
1346 length, 1); | |
1347 } | |
1348 | |
1349 // Mark the allocation so that zeroing is skipped since the code | |
1350 // below will overwrite the entire array | |
1351 AllocateArrayNode* char_alloc = AllocateArrayNode::Ideal_array_allocation(char_array, _gvn); | |
1352 char_alloc->maybe_set_complete(_gvn); | |
1353 | |
1354 // Now copy the string representations into the final char[] | |
1355 Node* start = __ intcon(0); | |
1356 for (int argi = 0; argi < sc->num_arguments(); argi++) { | |
1357 Node* arg = sc->argument(argi); | |
1358 switch (sc->mode(argi)) { | |
1359 case StringConcat::IntMode: { | |
1360 Node* end = __ AddI(start, string_sizes->in(argi)); | |
1361 // getChars words backwards so pass the ending point as well as the start | |
1362 int_getChars(kit, arg, char_array, start, end); | |
1363 start = end; | |
1364 break; | |
1365 } | |
1366 case StringConcat::StringMode: { | |
1367 start = copy_string(kit, arg, char_array, start); | |
1368 break; | |
1369 } | |
1370 case StringConcat::CharMode: { | |
1371 __ store_to_memory(kit.control(), kit.array_element_address(char_array, start, T_CHAR), | |
1372 arg, T_CHAR, char_adr_idx); | |
1373 start = __ AddI(start, __ intcon(1)); | |
1374 break; | |
1375 } | |
1376 default: | |
1377 ShouldNotReachHere(); | |
1378 } | |
1379 } | |
1380 | |
1381 // If we're not reusing an existing String allocation then allocate one here. | |
1382 Node* result = sc->string_alloc(); | |
1383 if (result == NULL) { | |
1384 PreserveReexecuteState preexecs(&kit); | |
1385 // The original jvms is for an allocation of either a String or | |
1386 // StringBuffer so no stack adjustment is necessary for proper | |
1387 // reexecution. | |
1388 kit.jvms()->set_should_reexecute(true); | |
1389 result = kit.new_instance(__ makecon(TypeKlassPtr::make(C->env()->String_klass()))); | |
1390 } | |
1391 | |
1392 // Intialize the string | |
1393 kit.store_to_memory(kit.control(), kit.basic_plus_adr(result, java_lang_String::offset_offset_in_bytes()), | |
1394 __ intcon(0), T_INT, offset_field_idx); | |
1395 kit.store_to_memory(kit.control(), kit.basic_plus_adr(result, java_lang_String::count_offset_in_bytes()), | |
1396 length, T_INT, count_field_idx); | |
1397 kit.store_to_memory(kit.control(), kit.basic_plus_adr(result, java_lang_String::value_offset_in_bytes()), | |
1398 char_array, T_OBJECT, value_field_idx); | |
1399 | |
1400 // hook up the outgoing control and result | |
1401 kit.replace_call(sc->end(), result); | |
1402 | |
1403 // Unhook any hook nodes | |
1404 string_sizes->disconnect_inputs(NULL); | |
1405 sc->cleanup(); | |
1406 } |