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 }