Mercurial > hg > truffle
comparison src/share/vm/opto/callGenerator.cpp @ 1080:7c57aead6d3e
6892658: C2 should optimize some stringbuilder patterns
Reviewed-by: kvn, twisti
author | never |
---|---|
date | Thu, 12 Nov 2009 09:24:21 -0800 |
parents | 9ee9cf798b59 |
children | 97125851f396 |
comparison
equal
deleted
inserted
replaced
1078:8e7adf982378 | 1080:7c57aead6d3e |
---|---|
96 } | 96 } |
97 | 97 |
98 //---------------------------DirectCallGenerator------------------------------ | 98 //---------------------------DirectCallGenerator------------------------------ |
99 // Internal class which handles all out-of-line calls w/o receiver type checks. | 99 // Internal class which handles all out-of-line calls w/o receiver type checks. |
100 class DirectCallGenerator : public CallGenerator { | 100 class DirectCallGenerator : public CallGenerator { |
101 public: | 101 private: |
102 DirectCallGenerator(ciMethod* method) | 102 CallStaticJavaNode* _call_node; |
103 : CallGenerator(method) | 103 // Force separate memory and I/O projections for the exceptional |
104 // paths to facilitate late inlinig. | |
105 bool _separate_io_proj; | |
106 | |
107 public: | |
108 DirectCallGenerator(ciMethod* method, bool separate_io_proj) | |
109 : CallGenerator(method), | |
110 _separate_io_proj(separate_io_proj) | |
104 { | 111 { |
105 } | 112 } |
106 virtual JVMState* generate(JVMState* jvms); | 113 virtual JVMState* generate(JVMState* jvms); |
114 | |
115 CallStaticJavaNode* call_node() const { return _call_node; } | |
107 }; | 116 }; |
108 | 117 |
109 JVMState* DirectCallGenerator::generate(JVMState* jvms) { | 118 JVMState* DirectCallGenerator::generate(JVMState* jvms) { |
110 GraphKit kit(jvms); | 119 GraphKit kit(jvms); |
111 bool is_static = method()->is_static(); | 120 bool is_static = method()->is_static(); |
127 } | 136 } |
128 // Mark the call node as virtual, sort of: | 137 // Mark the call node as virtual, sort of: |
129 call->set_optimized_virtual(true); | 138 call->set_optimized_virtual(true); |
130 } | 139 } |
131 kit.set_arguments_for_java_call(call); | 140 kit.set_arguments_for_java_call(call); |
132 kit.set_edges_for_java_call(call); | 141 kit.set_edges_for_java_call(call, false, _separate_io_proj); |
133 Node* ret = kit.set_results_for_java_call(call); | 142 Node* ret = kit.set_results_for_java_call(call, _separate_io_proj); |
134 kit.push_node(method()->return_type()->basic_type(), ret); | 143 kit.push_node(method()->return_type()->basic_type(), ret); |
144 _call_node = call; // Save the call node in case we need it later | |
135 return kit.transfer_exceptions_into_jvms(); | 145 return kit.transfer_exceptions_into_jvms(); |
136 } | 146 } |
137 | 147 |
138 class VirtualCallGenerator : public CallGenerator { | 148 class VirtualCallGenerator : public CallGenerator { |
139 private: | 149 private: |
236 float past_uses = m->interpreter_invocation_count(); | 246 float past_uses = m->interpreter_invocation_count(); |
237 float expected_uses = past_uses; | 247 float expected_uses = past_uses; |
238 return new ParseGenerator(m, expected_uses, true); | 248 return new ParseGenerator(m, expected_uses, true); |
239 } | 249 } |
240 | 250 |
241 CallGenerator* CallGenerator::for_direct_call(ciMethod* m) { | 251 CallGenerator* CallGenerator::for_direct_call(ciMethod* m, bool separate_io_proj) { |
242 assert(!m->is_abstract(), "for_direct_call mismatch"); | 252 assert(!m->is_abstract(), "for_direct_call mismatch"); |
243 return new DirectCallGenerator(m); | 253 return new DirectCallGenerator(m, separate_io_proj); |
244 } | 254 } |
245 | 255 |
246 CallGenerator* CallGenerator::for_virtual_call(ciMethod* m, int vtable_index) { | 256 CallGenerator* CallGenerator::for_virtual_call(ciMethod* m, int vtable_index) { |
247 assert(!m->is_static(), "for_virtual_call mismatch"); | 257 assert(!m->is_static(), "for_virtual_call mismatch"); |
248 return new VirtualCallGenerator(m, vtable_index); | 258 return new VirtualCallGenerator(m, vtable_index); |
259 } | |
260 | |
261 // Allow inlining decisions to be delayed | |
262 class LateInlineCallGenerator : public DirectCallGenerator { | |
263 CallGenerator* _inline_cg; | |
264 | |
265 public: | |
266 LateInlineCallGenerator(ciMethod* method, CallGenerator* inline_cg) : | |
267 DirectCallGenerator(method, true), _inline_cg(inline_cg) {} | |
268 | |
269 virtual bool is_late_inline() const { return true; } | |
270 | |
271 // Convert the CallStaticJava into an inline | |
272 virtual void do_late_inline(); | |
273 | |
274 JVMState* generate(JVMState* jvms) { | |
275 // Record that this call site should be revisited once the main | |
276 // parse is finished. | |
277 Compile::current()->add_late_inline(this); | |
278 | |
279 // Emit the CallStaticJava and request separate projections so | |
280 // that the late inlining logic can distinguish between fall | |
281 // through and exceptional uses of the memory and io projections | |
282 // as is done for allocations and macro expansion. | |
283 return DirectCallGenerator::generate(jvms); | |
284 } | |
285 | |
286 }; | |
287 | |
288 | |
289 void LateInlineCallGenerator::do_late_inline() { | |
290 // Can't inline it | |
291 if (call_node() == NULL || call_node()->outcnt() == 0 || | |
292 call_node()->in(0) == NULL || call_node()->in(0)->is_top()) | |
293 return; | |
294 | |
295 CallStaticJavaNode* call = call_node(); | |
296 | |
297 // Make a clone of the JVMState that appropriate to use for driving a parse | |
298 Compile* C = Compile::current(); | |
299 JVMState* jvms = call->jvms()->clone_shallow(C); | |
300 uint size = call->req(); | |
301 SafePointNode* map = new (C, size) SafePointNode(size, jvms); | |
302 for (uint i1 = 0; i1 < size; i1++) { | |
303 map->init_req(i1, call->in(i1)); | |
304 } | |
305 | |
306 // Make sure the state is a MergeMem for parsing. | |
307 if (!map->in(TypeFunc::Memory)->is_MergeMem()) { | |
308 map->set_req(TypeFunc::Memory, MergeMemNode::make(C, map->in(TypeFunc::Memory))); | |
309 } | |
310 | |
311 // Make enough space for the expression stack and transfer the incoming arguments | |
312 int nargs = method()->arg_size(); | |
313 jvms->set_map(map); | |
314 map->ensure_stack(jvms, jvms->method()->max_stack()); | |
315 if (nargs > 0) { | |
316 for (int i1 = 0; i1 < nargs; i1++) { | |
317 map->set_req(i1 + jvms->argoff(), call->in(TypeFunc::Parms + i1)); | |
318 } | |
319 } | |
320 | |
321 CompileLog* log = C->log(); | |
322 if (log != NULL) { | |
323 log->head("late_inline method='%d'", log->identify(method())); | |
324 JVMState* p = jvms; | |
325 while (p != NULL) { | |
326 log->elem("jvms bci='%d' method='%d'", p->bci(), log->identify(p->method())); | |
327 p = p->caller(); | |
328 } | |
329 log->tail("late_inline"); | |
330 } | |
331 | |
332 // Setup default node notes to be picked up by the inlining | |
333 Node_Notes* old_nn = C->default_node_notes(); | |
334 if (old_nn != NULL) { | |
335 Node_Notes* entry_nn = old_nn->clone(C); | |
336 entry_nn->set_jvms(jvms); | |
337 C->set_default_node_notes(entry_nn); | |
338 } | |
339 | |
340 // Now perform the inling using the synthesized JVMState | |
341 JVMState* new_jvms = _inline_cg->generate(jvms); | |
342 if (new_jvms == NULL) return; // no change | |
343 if (C->failing()) return; | |
344 | |
345 // Capture any exceptional control flow | |
346 GraphKit kit(new_jvms); | |
347 | |
348 // Find the result object | |
349 Node* result = C->top(); | |
350 int result_size = method()->return_type()->size(); | |
351 if (result_size != 0 && !kit.stopped()) { | |
352 result = (result_size == 1) ? kit.pop() : kit.pop_pair(); | |
353 } | |
354 | |
355 kit.replace_call(call, result); | |
356 } | |
357 | |
358 | |
359 CallGenerator* CallGenerator::for_late_inline(ciMethod* method, CallGenerator* inline_cg) { | |
360 return new LateInlineCallGenerator(method, inline_cg); | |
249 } | 361 } |
250 | 362 |
251 | 363 |
252 //---------------------------WarmCallGenerator-------------------------------- | 364 //---------------------------WarmCallGenerator-------------------------------- |
253 // Internal class which handles initial deferral of inlining decisions. | 365 // Internal class which handles initial deferral of inlining decisions. |
313 } | 425 } |
314 return jvms; | 426 return jvms; |
315 } | 427 } |
316 | 428 |
317 void WarmCallInfo::make_hot() { | 429 void WarmCallInfo::make_hot() { |
318 Compile* C = Compile::current(); | 430 Unimplemented(); |
319 // Replace the callnode with something better. | |
320 CallJavaNode* call = this->call()->as_CallJava(); | |
321 ciMethod* method = call->method(); | |
322 int nargs = method->arg_size(); | |
323 JVMState* jvms = call->jvms()->clone_shallow(C); | |
324 uint size = TypeFunc::Parms + MAX2(2, nargs); | |
325 SafePointNode* map = new (C, size) SafePointNode(size, jvms); | |
326 for (uint i1 = 0; i1 < (uint)(TypeFunc::Parms + nargs); i1++) { | |
327 map->init_req(i1, call->in(i1)); | |
328 } | |
329 jvms->set_map(map); | |
330 jvms->set_offsets(map->req()); | |
331 jvms->set_locoff(TypeFunc::Parms); | |
332 jvms->set_stkoff(TypeFunc::Parms); | |
333 GraphKit kit(jvms); | |
334 | |
335 JVMState* new_jvms = _hot_cg->generate(kit.jvms()); | |
336 if (new_jvms == NULL) return; // no change | |
337 if (C->failing()) return; | |
338 | |
339 kit.set_jvms(new_jvms); | |
340 Node* res = C->top(); | |
341 int res_size = method->return_type()->size(); | |
342 if (res_size != 0) { | |
343 kit.inc_sp(-res_size); | |
344 res = kit.argument(0); | |
345 } | |
346 GraphKit ekit(kit.combine_and_pop_all_exception_states()->jvms()); | |
347 | |
348 // Replace the call: | |
349 for (DUIterator i = call->outs(); call->has_out(i); i++) { | |
350 Node* n = call->out(i); | |
351 Node* nn = NULL; // replacement | |
352 if (n->is_Proj()) { | |
353 ProjNode* nproj = n->as_Proj(); | |
354 assert(nproj->_con < (uint)(TypeFunc::Parms + (res_size ? 1 : 0)), "sane proj"); | |
355 if (nproj->_con == TypeFunc::Parms) { | |
356 nn = res; | |
357 } else { | |
358 nn = kit.map()->in(nproj->_con); | |
359 } | |
360 if (nproj->_con == TypeFunc::I_O) { | |
361 for (DUIterator j = nproj->outs(); nproj->has_out(j); j++) { | |
362 Node* e = nproj->out(j); | |
363 if (e->Opcode() == Op_CreateEx) { | |
364 e->replace_by(ekit.argument(0)); | |
365 } else if (e->Opcode() == Op_Catch) { | |
366 for (DUIterator k = e->outs(); e->has_out(k); k++) { | |
367 CatchProjNode* p = e->out(j)->as_CatchProj(); | |
368 if (p->is_handler_proj()) { | |
369 p->replace_by(ekit.control()); | |
370 } else { | |
371 p->replace_by(kit.control()); | |
372 } | |
373 } | |
374 } | |
375 } | |
376 } | |
377 } | |
378 NOT_PRODUCT(if (!nn) n->dump(2)); | |
379 assert(nn != NULL, "don't know what to do with this user"); | |
380 n->replace_by(nn); | |
381 } | |
382 } | 431 } |
383 | 432 |
384 void WarmCallInfo::make_cold() { | 433 void WarmCallInfo::make_cold() { |
385 // No action: Just dequeue. | 434 // No action: Just dequeue. |
386 } | 435 } |