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