Mercurial > hg > truffle
annotate src/share/vm/opto/stringopts.cpp @ 1721:413ad0331a0c
6977924: Changes for 6975078 produce build error with certain gcc versions
Summary: The changes introduced for 6975078 assign badHeapOopVal to the _allocation field in the ResourceObj class. In 32 bit linux builds with certain versions of gcc this assignment will be flagged as an error while compiling allocation.cpp. In 32 bit builds the constant value badHeapOopVal (which is cast to an intptr_t) is negative. The _allocation field is typed as an unsigned intptr_t and gcc catches this as an error.
Reviewed-by: jcoomes, ysr, phh
author | johnc |
---|---|
date | Wed, 18 Aug 2010 10:59:06 -0700 |
parents | c18cbe5936b8 |
children | 3e8fbc61cee8 |
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 && | |
78 use->method()->holder() == C->env()->String_klass() && | |
79 use->method()->name() == ciSymbol::object_initializer_name() && | |
80 use->in(TypeFunc::Parms + 1) == endprojs.resproj) { | |
81 // Found useless new String(sb.toString()) so reuse the newly allocated String | |
82 // when creating the result instead of allocating a new one. | |
83 sc->set_string_alloc(use->in(TypeFunc::Parms)); | |
84 sc->set_end(use); | |
85 } | |
86 } | |
87 } | |
88 #endif | |
89 } | |
90 | |
91 StringConcat* merge(StringConcat* other, Node* arg); | |
92 | |
93 void set_allocation(AllocateNode* alloc) { | |
94 _begin = alloc; | |
95 } | |
96 | |
97 void append(Node* value, int mode) { | |
98 _arguments->add_req(value); | |
99 _mode.append(mode); | |
100 } | |
101 void push(Node* value, int mode) { | |
102 _arguments->ins_req(0, value); | |
103 _mode.insert_before(0, mode); | |
104 } | |
105 void push_string(Node* value) { | |
106 push(value, StringMode); | |
107 } | |
108 void push_int(Node* value) { | |
109 push(value, IntMode); | |
110 } | |
111 void push_char(Node* value) { | |
112 push(value, CharMode); | |
113 } | |
114 | |
115 Node* argument(int i) { | |
116 return _arguments->in(i); | |
117 } | |
118 void set_argument(int i, Node* value) { | |
119 _arguments->set_req(i, value); | |
120 } | |
121 int num_arguments() { | |
122 return _mode.length(); | |
123 } | |
124 int mode(int i) { | |
125 return _mode.at(i); | |
126 } | |
127 void add_control(Node* ctrl) { | |
128 assert(!_control.contains(ctrl), "only push once"); | |
129 _control.push(ctrl); | |
130 } | |
131 CallStaticJavaNode* end() { return _end; } | |
132 AllocateNode* begin() { return _begin; } | |
133 Node* string_alloc() { return _string_alloc; } | |
134 | |
135 void eliminate_unneeded_control(); | |
136 void eliminate_initialize(InitializeNode* init); | |
137 void eliminate_call(CallNode* call); | |
138 | |
139 void maybe_log_transform() { | |
140 CompileLog* log = _stringopts->C->log(); | |
141 if (log != NULL) { | |
142 log->head("replace_string_concat arguments='%d' string_alloc='%d' multiple='%d'", | |
143 num_arguments(), | |
144 _string_alloc != NULL, | |
145 _multiple); | |
146 JVMState* p = _begin->jvms(); | |
147 while (p != NULL) { | |
148 log->elem("jvms bci='%d' method='%d'", p->bci(), log->identify(p->method())); | |
149 p = p->caller(); | |
150 } | |
151 log->tail("replace_string_concat"); | |
152 } | |
153 } | |
154 | |
155 void convert_uncommon_traps(GraphKit& kit, const JVMState* jvms) { | |
156 for (uint u = 0; u < _uncommon_traps.size(); u++) { | |
157 Node* uct = _uncommon_traps.at(u); | |
158 | |
159 // Build a new call using the jvms state of the allocate | |
160 address call_addr = SharedRuntime::uncommon_trap_blob()->instructions_begin(); | |
161 const TypeFunc* call_type = OptoRuntime::uncommon_trap_Type(); | |
162 int size = call_type->domain()->cnt(); | |
163 const TypePtr* no_memory_effects = NULL; | |
164 Compile* C = _stringopts->C; | |
165 CallStaticJavaNode* call = new (C, size) CallStaticJavaNode(call_type, call_addr, "uncommon_trap", | |
166 jvms->bci(), no_memory_effects); | |
167 for (int e = 0; e < TypeFunc::Parms; e++) { | |
168 call->init_req(e, uct->in(e)); | |
169 } | |
170 // Set the trap request to record intrinsic failure if this trap | |
171 // is taken too many times. Ideally we would handle then traps by | |
172 // doing the original bookkeeping in the MDO so that if it caused | |
173 // the code to be thrown out we could still recompile and use the | |
174 // optimization. Failing the uncommon traps doesn't really mean | |
175 // that the optimization is a bad idea but there's no other way to | |
176 // do the MDO updates currently. | |
177 int trap_request = Deoptimization::make_trap_request(Deoptimization::Reason_intrinsic, | |
178 Deoptimization::Action_make_not_entrant); | |
179 call->init_req(TypeFunc::Parms, __ intcon(trap_request)); | |
180 kit.add_safepoint_edges(call); | |
181 | |
182 _stringopts->gvn()->transform(call); | |
183 C->gvn_replace_by(uct, call); | |
184 uct->disconnect_inputs(NULL); | |
185 } | |
186 } | |
187 | |
188 void cleanup() { | |
189 // disconnect the hook node | |
190 _arguments->disconnect_inputs(NULL); | |
191 } | |
192 }; | |
193 | |
194 | |
195 void StringConcat::eliminate_unneeded_control() { | |
196 eliminate_initialize(begin()->initialization()); | |
197 for (uint i = 0; i < _control.size(); i++) { | |
198 Node* n = _control.at(i); | |
199 if (n->is_Call()) { | |
200 if (n != _end) { | |
201 eliminate_call(n->as_Call()); | |
202 } | |
203 } else if (n->is_IfTrue()) { | |
204 Compile* C = _stringopts->C; | |
205 C->gvn_replace_by(n, n->in(0)->in(0)); | |
206 C->gvn_replace_by(n->in(0), C->top()); | |
207 } | |
208 } | |
209 } | |
210 | |
211 | |
212 StringConcat* StringConcat::merge(StringConcat* other, Node* arg) { | |
213 StringConcat* result = new StringConcat(_stringopts, _end); | |
214 for (uint x = 0; x < _control.size(); x++) { | |
215 Node* n = _control.at(x); | |
216 if (n->is_Call()) { | |
217 result->_control.push(n); | |
218 } | |
219 } | |
220 for (uint x = 0; x < other->_control.size(); x++) { | |
221 Node* n = other->_control.at(x); | |
222 if (n->is_Call()) { | |
223 result->_control.push(n); | |
224 } | |
225 } | |
226 assert(result->_control.contains(other->_end), "what?"); | |
227 assert(result->_control.contains(_begin), "what?"); | |
228 for (int x = 0; x < num_arguments(); x++) { | |
229 if (argument(x) == arg) { | |
230 // replace the toString result with the all the arguments that | |
231 // made up the other StringConcat | |
232 for (int y = 0; y < other->num_arguments(); y++) { | |
233 result->append(other->argument(y), other->mode(y)); | |
234 } | |
235 } else { | |
236 result->append(argument(x), mode(x)); | |
237 } | |
238 } | |
239 result->set_allocation(other->_begin); | |
240 result->_multiple = true; | |
241 return result; | |
242 } | |
243 | |
244 | |
245 void StringConcat::eliminate_call(CallNode* call) { | |
246 Compile* C = _stringopts->C; | |
247 CallProjections projs; | |
248 call->extract_projections(&projs, false); | |
249 if (projs.fallthrough_catchproj != NULL) { | |
250 C->gvn_replace_by(projs.fallthrough_catchproj, call->in(TypeFunc::Control)); | |
251 } | |
252 if (projs.fallthrough_memproj != NULL) { | |
253 C->gvn_replace_by(projs.fallthrough_memproj, call->in(TypeFunc::Memory)); | |
254 } | |
255 if (projs.catchall_memproj != NULL) { | |
256 C->gvn_replace_by(projs.catchall_memproj, C->top()); | |
257 } | |
258 if (projs.fallthrough_ioproj != NULL) { | |
259 C->gvn_replace_by(projs.fallthrough_ioproj, call->in(TypeFunc::I_O)); | |
260 } | |
261 if (projs.catchall_ioproj != NULL) { | |
262 C->gvn_replace_by(projs.catchall_ioproj, C->top()); | |
263 } | |
264 if (projs.catchall_catchproj != NULL) { | |
265 // EA can't cope with the partially collapsed graph this | |
266 // creates so put it on the worklist to be collapsed later. | |
267 for (SimpleDUIterator i(projs.catchall_catchproj); i.has_next(); i.next()) { | |
268 Node *use = i.get(); | |
269 int opc = use->Opcode(); | |
270 if (opc == Op_CreateEx || opc == Op_Region) { | |
271 _stringopts->record_dead_node(use); | |
272 } | |
273 } | |
274 C->gvn_replace_by(projs.catchall_catchproj, C->top()); | |
275 } | |
276 if (projs.resproj != NULL) { | |
277 C->gvn_replace_by(projs.resproj, C->top()); | |
278 } | |
279 C->gvn_replace_by(call, C->top()); | |
280 } | |
281 | |
282 void StringConcat::eliminate_initialize(InitializeNode* init) { | |
283 Compile* C = _stringopts->C; | |
284 | |
285 // Eliminate Initialize node. | |
286 assert(init->outcnt() <= 2, "only a control and memory projection expected"); | |
287 assert(init->req() <= InitializeNode::RawStores, "no pending inits"); | |
288 Node *ctrl_proj = init->proj_out(TypeFunc::Control); | |
289 if (ctrl_proj != NULL) { | |
290 C->gvn_replace_by(ctrl_proj, init->in(TypeFunc::Control)); | |
291 } | |
292 Node *mem_proj = init->proj_out(TypeFunc::Memory); | |
293 if (mem_proj != NULL) { | |
294 Node *mem = init->in(TypeFunc::Memory); | |
295 C->gvn_replace_by(mem_proj, mem); | |
296 } | |
297 C->gvn_replace_by(init, C->top()); | |
298 init->disconnect_inputs(NULL); | |
299 } | |
300 | |
301 Node_List PhaseStringOpts::collect_toString_calls() { | |
302 Node_List string_calls; | |
303 Node_List worklist; | |
304 | |
305 _visited.Clear(); | |
306 | |
307 // Prime the worklist | |
308 for (uint i = 1; i < C->root()->len(); i++) { | |
309 Node* n = C->root()->in(i); | |
310 if (n != NULL && !_visited.test_set(n->_idx)) { | |
311 worklist.push(n); | |
312 } | |
313 } | |
314 | |
315 while (worklist.size() > 0) { | |
316 Node* ctrl = worklist.pop(); | |
317 if (ctrl->is_CallStaticJava()) { | |
318 CallStaticJavaNode* csj = ctrl->as_CallStaticJava(); | |
319 ciMethod* m = csj->method(); | |
320 if (m != NULL && | |
321 (m->intrinsic_id() == vmIntrinsics::_StringBuffer_toString || | |
322 m->intrinsic_id() == vmIntrinsics::_StringBuilder_toString)) { | |
323 string_calls.push(csj); | |
324 } | |
325 } | |
326 if (ctrl->in(0) != NULL && !_visited.test_set(ctrl->in(0)->_idx)) { | |
327 worklist.push(ctrl->in(0)); | |
328 } | |
329 if (ctrl->is_Region()) { | |
330 for (uint i = 1; i < ctrl->len(); i++) { | |
331 if (ctrl->in(i) != NULL && !_visited.test_set(ctrl->in(i)->_idx)) { | |
332 worklist.push(ctrl->in(i)); | |
333 } | |
334 } | |
335 } | |
336 } | |
337 return string_calls; | |
338 } | |
339 | |
340 | |
341 StringConcat* PhaseStringOpts::build_candidate(CallStaticJavaNode* call) { | |
342 ciMethod* m = call->method(); | |
343 ciSymbol* string_sig; | |
344 ciSymbol* int_sig; | |
345 ciSymbol* char_sig; | |
346 if (m->holder() == C->env()->StringBuilder_klass()) { | |
347 string_sig = ciSymbol::String_StringBuilder_signature(); | |
348 int_sig = ciSymbol::int_StringBuilder_signature(); | |
349 char_sig = ciSymbol::char_StringBuilder_signature(); | |
350 } else if (m->holder() == C->env()->StringBuffer_klass()) { | |
351 string_sig = ciSymbol::String_StringBuffer_signature(); | |
352 int_sig = ciSymbol::int_StringBuffer_signature(); | |
353 char_sig = ciSymbol::char_StringBuffer_signature(); | |
354 } else { | |
355 return NULL; | |
356 } | |
357 #ifndef PRODUCT | |
358 if (PrintOptimizeStringConcat) { | |
359 tty->print("considering toString call in "); | |
360 call->jvms()->dump_spec(tty); tty->cr(); | |
361 } | |
362 #endif | |
363 | |
364 StringConcat* sc = new StringConcat(this, call); | |
365 | |
366 AllocateNode* alloc = NULL; | |
367 InitializeNode* init = NULL; | |
368 | |
369 // possible opportunity for StringBuilder fusion | |
370 CallStaticJavaNode* cnode = call; | |
371 while (cnode) { | |
372 Node* recv = cnode->in(TypeFunc::Parms)->uncast(); | |
373 if (recv->is_Proj()) { | |
374 recv = recv->in(0); | |
375 } | |
376 cnode = recv->isa_CallStaticJava(); | |
377 if (cnode == NULL) { | |
378 alloc = recv->isa_Allocate(); | |
379 if (alloc == NULL) { | |
380 break; | |
381 } | |
382 // Find the constructor call | |
383 Node* result = alloc->result_cast(); | |
384 if (result == NULL || !result->is_CheckCastPP()) { | |
385 // strange looking allocation | |
386 #ifndef PRODUCT | |
387 if (PrintOptimizeStringConcat) { | |
388 tty->print("giving up because allocation looks strange "); | |
389 alloc->jvms()->dump_spec(tty); tty->cr(); | |
390 } | |
391 #endif | |
392 break; | |
393 } | |
394 Node* constructor = NULL; | |
395 for (SimpleDUIterator i(result); i.has_next(); i.next()) { | |
396 CallStaticJavaNode *use = i.get()->isa_CallStaticJava(); | |
397 if (use != NULL && use->method() != NULL && | |
398 use->method()->name() == ciSymbol::object_initializer_name() && | |
399 use->method()->holder() == m->holder()) { | |
400 // Matched the constructor. | |
401 ciSymbol* sig = use->method()->signature()->as_symbol(); | |
402 if (sig == ciSymbol::void_method_signature() || | |
403 sig == ciSymbol::int_void_signature() || | |
404 sig == ciSymbol::string_void_signature()) { | |
405 if (sig == ciSymbol::string_void_signature()) { | |
406 // StringBuilder(String) so pick this up as the first argument | |
407 assert(use->in(TypeFunc::Parms + 1) != NULL, "what?"); | |
408 sc->push_string(use->in(TypeFunc::Parms + 1)); | |
409 } | |
410 // The int variant takes an initial size for the backing | |
411 // array so just treat it like the void version. | |
412 constructor = use; | |
413 } else { | |
414 #ifndef PRODUCT | |
415 if (PrintOptimizeStringConcat) { | |
416 tty->print("unexpected constructor signature: %s", sig->as_utf8()); | |
417 } | |
418 #endif | |
419 } | |
420 break; | |
421 } | |
422 } | |
423 if (constructor == NULL) { | |
424 // couldn't find constructor | |
425 #ifndef PRODUCT | |
426 if (PrintOptimizeStringConcat) { | |
427 tty->print("giving up because couldn't find constructor "); | |
428 alloc->jvms()->dump_spec(tty); | |
429 } | |
430 #endif | |
431 break; | |
432 } | |
433 | |
434 // Walked all the way back and found the constructor call so see | |
435 // if this call converted into a direct string concatenation. | |
436 sc->add_control(call); | |
437 sc->add_control(constructor); | |
438 sc->add_control(alloc); | |
439 sc->set_allocation(alloc); | |
440 if (sc->validate_control_flow()) { | |
441 return sc; | |
442 } else { | |
443 return NULL; | |
444 } | |
445 } else if (cnode->method() == NULL) { | |
446 break; | |
447 } else if (cnode->method()->holder() == m->holder() && | |
448 cnode->method()->name() == ciSymbol::append_name() && | |
449 (cnode->method()->signature()->as_symbol() == string_sig || | |
450 cnode->method()->signature()->as_symbol() == char_sig || | |
451 cnode->method()->signature()->as_symbol() == int_sig)) { | |
452 sc->add_control(cnode); | |
453 Node* arg = cnode->in(TypeFunc::Parms + 1); | |
454 if (cnode->method()->signature()->as_symbol() == int_sig) { | |
455 sc->push_int(arg); | |
456 } else if (cnode->method()->signature()->as_symbol() == char_sig) { | |
457 sc->push_char(arg); | |
458 } else { | |
459 if (arg->is_Proj() && arg->in(0)->is_CallStaticJava()) { | |
460 CallStaticJavaNode* csj = arg->in(0)->as_CallStaticJava(); | |
461 if (csj->method() != NULL && | |
462 csj->method()->holder() == C->env()->Integer_klass() && | |
463 csj->method()->name() == ciSymbol::toString_name()) { | |
464 sc->add_control(csj); | |
465 sc->push_int(csj->in(TypeFunc::Parms)); | |
466 continue; | |
467 } | |
468 } | |
469 sc->push_string(arg); | |
470 } | |
471 continue; | |
472 } else { | |
473 // some unhandled signature | |
474 #ifndef PRODUCT | |
475 if (PrintOptimizeStringConcat) { | |
476 tty->print("giving up because encountered unexpected signature "); | |
477 cnode->tf()->dump(); tty->cr(); | |
478 cnode->in(TypeFunc::Parms + 1)->dump(); | |
479 } | |
480 #endif | |
481 break; | |
482 } | |
483 } | |
484 return NULL; | |
485 } | |
486 | |
487 | |
488 PhaseStringOpts::PhaseStringOpts(PhaseGVN* gvn, Unique_Node_List*): | |
489 Phase(StringOpts), | |
490 _gvn(gvn), | |
491 _visited(Thread::current()->resource_area()) { | |
492 | |
493 assert(OptimizeStringConcat, "shouldn't be here"); | |
494 | |
495 size_table_field = C->env()->Integer_klass()->get_field_by_name(ciSymbol::make("sizeTable"), | |
496 ciSymbol::make("[I"), true); | |
497 if (size_table_field == NULL) { | |
498 // Something wrong so give up. | |
499 assert(false, "why can't we find Integer.sizeTable?"); | |
500 return; | |
501 } | |
502 | |
503 // Collect the types needed to talk about the various slices of memory | |
504 const TypeInstPtr* string_type = TypeInstPtr::make(TypePtr::NotNull, C->env()->String_klass(), | |
505 false, NULL, 0); | |
506 | |
507 const TypePtr* value_field_type = string_type->add_offset(java_lang_String::value_offset_in_bytes()); | |
508 const TypePtr* offset_field_type = string_type->add_offset(java_lang_String::offset_offset_in_bytes()); | |
509 const TypePtr* count_field_type = string_type->add_offset(java_lang_String::count_offset_in_bytes()); | |
510 | |
511 value_field_idx = C->get_alias_index(value_field_type); | |
512 count_field_idx = C->get_alias_index(count_field_type); | |
513 offset_field_idx = C->get_alias_index(offset_field_type); | |
514 char_adr_idx = C->get_alias_index(TypeAryPtr::CHARS); | |
515 | |
516 // For each locally allocated StringBuffer see if the usages can be | |
517 // collapsed into a single String construction. | |
518 | |
519 // Run through the list of allocation looking for SB.toString to see | |
520 // if it's possible to fuse the usage of the SB into a single String | |
521 // construction. | |
522 GrowableArray<StringConcat*> concats; | |
523 Node_List toStrings = collect_toString_calls(); | |
524 while (toStrings.size() > 0) { | |
525 StringConcat* sc = build_candidate(toStrings.pop()->as_CallStaticJava()); | |
526 if (sc != NULL) { | |
527 concats.push(sc); | |
528 } | |
529 } | |
530 | |
531 // try to coalesce separate concats | |
532 restart: | |
533 for (int c = 0; c < concats.length(); c++) { | |
534 StringConcat* sc = concats.at(c); | |
535 for (int i = 0; i < sc->num_arguments(); i++) { | |
536 Node* arg = sc->argument(i); | |
537 if (arg->is_Proj() && arg->in(0)->is_CallStaticJava()) { | |
538 CallStaticJavaNode* csj = arg->in(0)->as_CallStaticJava(); | |
539 if (csj->method() != NULL && | |
540 (csj->method()->holder() == C->env()->StringBuffer_klass() || | |
541 csj->method()->holder() == C->env()->StringBuilder_klass()) && | |
542 csj->method()->name() == ciSymbol::toString_name()) { | |
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 } |