294 } |
294 } |
295 |
295 |
296 // Allow inlining decisions to be delayed |
296 // Allow inlining decisions to be delayed |
297 class LateInlineCallGenerator : public DirectCallGenerator { |
297 class LateInlineCallGenerator : public DirectCallGenerator { |
298 private: |
298 private: |
299 // unique id for log compilation |
299 jlong _unique_id; // unique id for log compilation |
300 jlong _unique_id; |
300 bool _is_pure_call; // a hint that the call doesn't have important side effects to care about |
301 |
301 |
302 protected: |
302 protected: |
303 CallGenerator* _inline_cg; |
303 CallGenerator* _inline_cg; |
304 virtual bool do_late_inline_check(JVMState* jvms) { return true; } |
304 virtual bool do_late_inline_check(JVMState* jvms) { return true; } |
305 |
305 |
306 public: |
306 public: |
307 LateInlineCallGenerator(ciMethod* method, CallGenerator* inline_cg) : |
307 LateInlineCallGenerator(ciMethod* method, CallGenerator* inline_cg, bool is_pure_call = false) : |
308 DirectCallGenerator(method, true), _unique_id(0), _inline_cg(inline_cg) {} |
308 DirectCallGenerator(method, true), _unique_id(0), _is_pure_call(is_pure_call), _inline_cg(inline_cg) {} |
309 |
309 |
310 virtual bool is_late_inline() const { return true; } |
310 virtual bool is_late_inline() const { return true; } |
311 |
311 |
312 // Convert the CallStaticJava into an inline |
312 // Convert the CallStaticJava into an inline |
313 virtual void do_late_inline(); |
313 virtual void do_late_inline(); |
387 // Remove inlined methods from Compiler's lists. |
387 // Remove inlined methods from Compiler's lists. |
388 if (call->is_macro()) { |
388 if (call->is_macro()) { |
389 C->remove_macro_node(call); |
389 C->remove_macro_node(call); |
390 } |
390 } |
391 |
391 |
392 // Make a clone of the JVMState that appropriate to use for driving a parse |
392 bool result_not_used = (callprojs.resproj == NULL || callprojs.resproj->outcnt() == 0); |
393 JVMState* old_jvms = call->jvms(); |
393 if (_is_pure_call && result_not_used) { |
394 JVMState* jvms = old_jvms->clone_shallow(C); |
394 // The call is marked as pure (no important side effects), but result isn't used. |
395 uint size = call->req(); |
395 // It's safe to remove the call. |
396 SafePointNode* map = new SafePointNode(size, jvms); |
396 GraphKit kit(call->jvms()); |
397 for (uint i1 = 0; i1 < size; i1++) { |
397 kit.replace_call(call, C->top(), true); |
398 map->init_req(i1, call->in(i1)); |
398 } else { |
399 } |
399 // Make a clone of the JVMState that appropriate to use for driving a parse |
400 |
400 JVMState* old_jvms = call->jvms(); |
401 // Make sure the state is a MergeMem for parsing. |
401 JVMState* jvms = old_jvms->clone_shallow(C); |
402 if (!map->in(TypeFunc::Memory)->is_MergeMem()) { |
402 uint size = call->req(); |
403 Node* mem = MergeMemNode::make(map->in(TypeFunc::Memory)); |
403 SafePointNode* map = new SafePointNode(size, jvms); |
404 C->initial_gvn()->set_type_bottom(mem); |
404 for (uint i1 = 0; i1 < size; i1++) { |
405 map->set_req(TypeFunc::Memory, mem); |
405 map->init_req(i1, call->in(i1)); |
406 } |
406 } |
407 |
407 |
408 uint nargs = method()->arg_size(); |
408 // Make sure the state is a MergeMem for parsing. |
409 // blow away old call arguments |
409 if (!map->in(TypeFunc::Memory)->is_MergeMem()) { |
410 Node* top = C->top(); |
410 Node* mem = MergeMemNode::make(map->in(TypeFunc::Memory)); |
411 for (uint i1 = 0; i1 < nargs; i1++) { |
411 C->initial_gvn()->set_type_bottom(mem); |
412 map->set_req(TypeFunc::Parms + i1, top); |
412 map->set_req(TypeFunc::Memory, mem); |
413 } |
413 } |
414 jvms->set_map(map); |
414 |
415 |
415 uint nargs = method()->arg_size(); |
416 // Make enough space in the expression stack to transfer |
416 // blow away old call arguments |
417 // the incoming arguments and return value. |
417 Node* top = C->top(); |
418 map->ensure_stack(jvms, jvms->method()->max_stack()); |
418 for (uint i1 = 0; i1 < nargs; i1++) { |
419 for (uint i1 = 0; i1 < nargs; i1++) { |
419 map->set_req(TypeFunc::Parms + i1, top); |
420 map->set_argument(jvms, i1, call->in(TypeFunc::Parms + i1)); |
420 } |
421 } |
421 jvms->set_map(map); |
422 |
422 |
423 C->print_inlining_assert_ready(); |
423 // Make enough space in the expression stack to transfer |
424 |
424 // the incoming arguments and return value. |
425 C->print_inlining_move_to(this); |
425 map->ensure_stack(jvms, jvms->method()->max_stack()); |
426 |
426 for (uint i1 = 0; i1 < nargs; i1++) { |
427 C->log_late_inline(this); |
427 map->set_argument(jvms, i1, call->in(TypeFunc::Parms + i1)); |
428 |
428 } |
429 // This check is done here because for_method_handle_inline() method |
429 |
430 // needs jvms for inlined state. |
430 C->print_inlining_assert_ready(); |
431 if (!do_late_inline_check(jvms)) { |
431 |
432 map->disconnect_inputs(NULL, C); |
432 C->print_inlining_move_to(this); |
433 return; |
433 |
434 } |
434 C->log_late_inline(this); |
435 |
435 |
436 // Setup default node notes to be picked up by the inlining |
436 // This check is done here because for_method_handle_inline() method |
437 Node_Notes* old_nn = C->node_notes_at(call->_idx); |
437 // needs jvms for inlined state. |
438 if (old_nn != NULL) { |
438 if (!do_late_inline_check(jvms)) { |
439 Node_Notes* entry_nn = old_nn->clone(C); |
439 map->disconnect_inputs(NULL, C); |
440 entry_nn->set_jvms(jvms); |
440 return; |
441 C->set_default_node_notes(entry_nn); |
441 } |
442 } |
442 |
443 |
443 // Setup default node notes to be picked up by the inlining |
444 // Now perform the inlining using the synthesized JVMState |
444 Node_Notes* old_nn = C->node_notes_at(call->_idx); |
445 JVMState* new_jvms = _inline_cg->generate(jvms); |
445 if (old_nn != NULL) { |
446 if (new_jvms == NULL) return; // no change |
446 Node_Notes* entry_nn = old_nn->clone(C); |
447 if (C->failing()) return; |
447 entry_nn->set_jvms(jvms); |
448 |
448 C->set_default_node_notes(entry_nn); |
449 // Capture any exceptional control flow |
449 } |
450 GraphKit kit(new_jvms); |
450 |
451 |
451 // Now perform the inlining using the synthesized JVMState |
452 // Find the result object |
452 JVMState* new_jvms = _inline_cg->generate(jvms); |
453 Node* result = C->top(); |
453 if (new_jvms == NULL) return; // no change |
454 int result_size = method()->return_type()->size(); |
454 if (C->failing()) return; |
455 if (result_size != 0 && !kit.stopped()) { |
455 |
456 result = (result_size == 1) ? kit.pop() : kit.pop_pair(); |
456 // Capture any exceptional control flow |
457 } |
457 GraphKit kit(new_jvms); |
458 |
458 |
459 C->set_has_loops(C->has_loops() || _inline_cg->method()->has_loops()); |
459 // Find the result object |
460 C->env()->notice_inlined_method(_inline_cg->method()); |
460 Node* result = C->top(); |
461 C->set_inlining_progress(true); |
461 int result_size = method()->return_type()->size(); |
462 C->set_do_cleanup(kit.stopped()); // path is dead; needs cleanup |
462 if (result_size != 0 && !kit.stopped()) { |
463 kit.replace_call(call, result, true); |
463 result = (result_size == 1) ? kit.pop() : kit.pop_pair(); |
|
464 } |
|
465 |
|
466 C->set_has_loops(C->has_loops() || _inline_cg->method()->has_loops()); |
|
467 C->env()->notice_inlined_method(_inline_cg->method()); |
|
468 C->set_inlining_progress(true); |
|
469 C->set_do_cleanup(kit.stopped()); // path is dead; needs cleanup |
|
470 kit.replace_call(call, result, true); |
|
471 } |
464 } |
472 } |
465 |
473 |
466 |
474 |
467 CallGenerator* CallGenerator::for_late_inline(ciMethod* method, CallGenerator* inline_cg) { |
475 CallGenerator* CallGenerator::for_late_inline(ciMethod* method, CallGenerator* inline_cg) { |
468 return new LateInlineCallGenerator(method, inline_cg); |
476 return new LateInlineCallGenerator(method, inline_cg); |