| OLD | NEW |
| 1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 4628 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4639 CallKind call_kind = (expr->expression()->AsProperty() == NULL) | 4639 CallKind call_kind = (expr->expression()->AsProperty() == NULL) |
| 4640 ? CALL_AS_FUNCTION | 4640 ? CALL_AS_FUNCTION |
| 4641 : CALL_AS_METHOD; | 4641 : CALL_AS_METHOD; |
| 4642 | 4642 |
| 4643 // Precondition: call is monomorphic and we have found a target with the | 4643 // Precondition: call is monomorphic and we have found a target with the |
| 4644 // appropriate arity. | 4644 // appropriate arity. |
| 4645 Handle<JSFunction> caller = info()->closure(); | 4645 Handle<JSFunction> caller = info()->closure(); |
| 4646 Handle<JSFunction> target = expr->target(); | 4646 Handle<JSFunction> target = expr->target(); |
| 4647 Handle<SharedFunctionInfo> target_shared(target->shared()); | 4647 Handle<SharedFunctionInfo> target_shared(target->shared()); |
| 4648 | 4648 |
| 4649 // Do a quick check on source code length to avoid parsing large | 4649 if (!target_shared->is_inlineable()) { |
| 4650 // inlining candidates. | 4650 TraceInline(target, caller, "target has non-trivial declarations" |
| 4651 if (FLAG_limit_inlining && target->shared()->SourceSize() > kMaxSourceSize) { | 4651 " or statements."); |
| 4652 TraceInline(target, caller, "target text too big"); | |
| 4653 return false; | 4652 return false; |
| 4654 } | 4653 } |
| 4655 | 4654 |
| 4655 int ast_node_count = target_shared->ast_node_count(); |
| 4656 |
| 4657 if (FLAG_limit_inlining) { |
| 4658 if (ast_node_count > kMaxInlinedSize) { |
| 4659 // Never inline big functions. |
| 4660 TraceInline(target, caller, "target AST is too large"); |
| 4661 return false; |
| 4662 } |
| 4663 |
| 4664 if (target->shared()->SourceSize() > kMaxSourceSize) { |
| 4665 // Never inline big functions. |
| 4666 TraceInline(target, caller, "target text too big"); |
| 4667 return false; |
| 4668 } |
| 4669 |
| 4670 if (inlined_count_ > kMaxInlinedNodesHard) { |
| 4671 // Do not inline after the hard limit is reached. |
| 4672 TraceInline(target, caller, "cumulative AST node limit reached"); |
| 4673 return false; |
| 4674 } |
| 4675 |
| 4676 if (inlined_count_ > kMaxInlinedNodesSoft) { |
| 4677 // Inline only small primitive functions after the soft limit is reached. |
| 4678 // See comments of AstNode::IsInlineable for definition of "primitive". |
| 4679 if (ast_node_count > kMaxInlinedPrimitiveSize || |
| 4680 !target_shared->is_primitive()) { |
| 4681 TraceInline(target, caller, "cumulative AST node limit reached (soft)"); |
| 4682 return false; |
| 4683 } |
| 4684 } |
| 4685 } |
| 4686 |
| 4656 // Target must be inlineable. | 4687 // Target must be inlineable. |
| 4657 if (!target->IsInlineable()) { | 4688 if (!target->IsInlineable()) { |
| 4658 TraceInline(target, caller, "target not inlineable"); | 4689 TraceInline(target, caller, "target not inlineable"); |
| 4659 return false; | 4690 return false; |
| 4660 } | 4691 } |
| 4661 | 4692 |
| 4662 #if !defined(V8_TARGET_ARCH_IA32) | 4693 #if !defined(V8_TARGET_ARCH_IA32) |
| 4663 // Target must be able to use caller's context. | 4694 // Target must be able to use caller's context. |
| 4664 CompilationInfo* outer_info = info(); | 4695 CompilationInfo* outer_info = info(); |
| 4665 if (target->context() != outer_info->closure()->context() || | 4696 if (target->context() != outer_info->closure()->context() || |
| (...skipping 20 matching lines...) Expand all Loading... |
| 4686 // Don't inline recursive functions. | 4717 // Don't inline recursive functions. |
| 4687 for (FunctionState* state = function_state(); | 4718 for (FunctionState* state = function_state(); |
| 4688 state != NULL; | 4719 state != NULL; |
| 4689 state = state->outer()) { | 4720 state = state->outer()) { |
| 4690 if (state->compilation_info()->closure()->shared() == *target_shared) { | 4721 if (state->compilation_info()->closure()->shared() == *target_shared) { |
| 4691 TraceInline(target, caller, "target is recursive"); | 4722 TraceInline(target, caller, "target is recursive"); |
| 4692 return false; | 4723 return false; |
| 4693 } | 4724 } |
| 4694 } | 4725 } |
| 4695 | 4726 |
| 4696 // We don't want to add more than a certain number of nodes from inlining. | |
| 4697 if (FLAG_limit_inlining && inlined_count_ > kMaxInlinedNodes) { | |
| 4698 TraceInline(target, caller, "cumulative AST node limit reached"); | |
| 4699 return false; | |
| 4700 } | |
| 4701 | |
| 4702 int count_before = AstNode::Count(); | |
| 4703 | |
| 4704 // Parse and allocate variables. | 4727 // Parse and allocate variables. |
| 4705 CompilationInfo target_info(target); | 4728 CompilationInfo target_info(target); |
| 4706 if (!ParserApi::Parse(&target_info) || | 4729 if (!ParserApi::Parse(&target_info) || |
| 4707 !Scope::Analyze(&target_info)) { | 4730 !Scope::Analyze(&target_info)) { |
| 4708 if (target_info.isolate()->has_pending_exception()) { | 4731 if (target_info.isolate()->has_pending_exception()) { |
| 4709 // Parse or scope error, never optimize this function. | 4732 // Parse or scope error, never optimize this function. |
| 4710 SetStackOverflow(); | 4733 SetStackOverflow(); |
| 4711 target_shared->DisableOptimization(*target); | 4734 target_shared->DisableOptimization(*target); |
| 4712 } | 4735 } |
| 4713 TraceInline(target, caller, "parse failure"); | 4736 TraceInline(target, caller, "parse failure"); |
| 4714 return false; | 4737 return false; |
| 4715 } | 4738 } |
| 4716 | 4739 |
| 4717 if (target_info.scope()->num_heap_slots() > 0) { | 4740 if (target_info.scope()->num_heap_slots() > 0) { |
| 4718 TraceInline(target, caller, "target has context-allocated variables"); | 4741 TraceInline(target, caller, "target has context-allocated variables"); |
| 4719 return false; | 4742 return false; |
| 4720 } | 4743 } |
| 4744 |
| 4721 FunctionLiteral* function = target_info.function(); | 4745 FunctionLiteral* function = target_info.function(); |
| 4722 | 4746 |
| 4723 // Count the number of AST nodes added by inlining this call. | |
| 4724 int nodes_added = AstNode::Count() - count_before; | |
| 4725 if (FLAG_limit_inlining && nodes_added > kMaxInlinedSize) { | |
| 4726 TraceInline(target, caller, "target AST is too large"); | |
| 4727 return false; | |
| 4728 } | |
| 4729 | |
| 4730 // Don't inline functions that uses the arguments object or that | 4747 // Don't inline functions that uses the arguments object or that |
| 4731 // have a mismatching number of parameters. | 4748 // have a mismatching number of parameters. |
| 4732 int arity = expr->arguments()->length(); | 4749 int arity = expr->arguments()->length(); |
| 4733 if (function->scope()->arguments() != NULL || | 4750 if (function->scope()->arguments() != NULL || |
| 4734 arity != target_shared->formal_parameter_count()) { | 4751 arity != target_shared->formal_parameter_count()) { |
| 4735 TraceInline(target, caller, "target requires special argument handling"); | 4752 TraceInline(target, caller, "target requires special argument handling"); |
| 4736 return false; | 4753 return false; |
| 4737 } | 4754 } |
| 4738 | 4755 |
| 4739 // All declarations must be inlineable. | |
| 4740 ZoneList<Declaration*>* decls = target_info.scope()->declarations(); | |
| 4741 int decl_count = decls->length(); | |
| 4742 for (int i = 0; i < decl_count; ++i) { | |
| 4743 if (!decls->at(i)->IsInlineable()) { | |
| 4744 TraceInline(target, caller, "target has non-trivial declaration"); | |
| 4745 return false; | |
| 4746 } | |
| 4747 } | |
| 4748 // All statements in the body must be inlineable. | |
| 4749 for (int i = 0, count = function->body()->length(); i < count; ++i) { | |
| 4750 if (!function->body()->at(i)->IsInlineable()) { | |
| 4751 TraceInline(target, caller, "target contains unsupported syntax"); | |
| 4752 return false; | |
| 4753 } | |
| 4754 } | |
| 4755 | |
| 4756 // Generate the deoptimization data for the unoptimized version of | 4756 // Generate the deoptimization data for the unoptimized version of |
| 4757 // the target function if we don't already have it. | 4757 // the target function if we don't already have it. |
| 4758 if (!target_shared->has_deoptimization_support()) { | 4758 if (!target_shared->has_deoptimization_support()) { |
| 4759 // Note that we compile here using the same AST that we will use for | 4759 // Note that we compile here using the same AST that we will use for |
| 4760 // generating the optimized inline code. | 4760 // generating the optimized inline code. |
| 4761 target_info.EnableDeoptimizationSupport(); | 4761 target_info.EnableDeoptimizationSupport(); |
| 4762 if (!FullCodeGenerator::MakeCode(&target_info)) { | 4762 if (!FullCodeGenerator::MakeCode(&target_info)) { |
| 4763 TraceInline(target, caller, "could not generate deoptimization info"); | 4763 TraceInline(target, caller, "could not generate deoptimization info"); |
| 4764 return false; | 4764 return false; |
| 4765 } | 4765 } |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4822 // Bail out if the inline function did, as we cannot residualize a call | 4822 // Bail out if the inline function did, as we cannot residualize a call |
| 4823 // instead. | 4823 // instead. |
| 4824 TraceInline(target, caller, "inline graph construction failed"); | 4824 TraceInline(target, caller, "inline graph construction failed"); |
| 4825 target_shared->DisableOptimization(*target); | 4825 target_shared->DisableOptimization(*target); |
| 4826 inline_bailout_ = true; | 4826 inline_bailout_ = true; |
| 4827 delete target_state; | 4827 delete target_state; |
| 4828 return true; | 4828 return true; |
| 4829 } | 4829 } |
| 4830 | 4830 |
| 4831 // Update inlined nodes count. | 4831 // Update inlined nodes count. |
| 4832 inlined_count_ += nodes_added; | 4832 inlined_count_ += ast_node_count; |
| 4833 | 4833 |
| 4834 TraceInline(target, caller, NULL); | 4834 TraceInline(target, caller, NULL); |
| 4835 | 4835 |
| 4836 if (current_block() != NULL) { | 4836 if (current_block() != NULL) { |
| 4837 // Add a return of undefined if control can fall off the body. In a | 4837 // Add a return of undefined if control can fall off the body. In a |
| 4838 // test context, undefined is false. | 4838 // test context, undefined is false. |
| 4839 if (inlined_test_context() == NULL) { | 4839 if (inlined_test_context() == NULL) { |
| 4840 ASSERT(function_return() != NULL); | 4840 ASSERT(function_return() != NULL); |
| 4841 ASSERT(call_context()->IsEffect() || call_context()->IsValue()); | 4841 ASSERT(call_context()->IsEffect() || call_context()->IsValue()); |
| 4842 if (call_context()->IsEffect()) { | 4842 if (call_context()->IsEffect()) { |
| (...skipping 2309 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7152 } | 7152 } |
| 7153 } | 7153 } |
| 7154 | 7154 |
| 7155 #ifdef DEBUG | 7155 #ifdef DEBUG |
| 7156 if (graph_ != NULL) graph_->Verify(false); // No full verify. | 7156 if (graph_ != NULL) graph_->Verify(false); // No full verify. |
| 7157 if (allocator_ != NULL) allocator_->Verify(); | 7157 if (allocator_ != NULL) allocator_->Verify(); |
| 7158 #endif | 7158 #endif |
| 7159 } | 7159 } |
| 7160 | 7160 |
| 7161 } } // namespace v8::internal | 7161 } } // namespace v8::internal |
| OLD | NEW |