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