OLD | NEW |
---|---|
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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 525 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
536 | 536 |
537 | 537 |
538 HConstant* HGraph::GetConstantHole() { | 538 HConstant* HGraph::GetConstantHole() { |
539 return GetConstant(&constant_hole_, isolate()->heap()->the_hole_value()); | 539 return GetConstant(&constant_hole_, isolate()->heap()->the_hole_value()); |
540 } | 540 } |
541 | 541 |
542 | 542 |
543 HGraphBuilder::HGraphBuilder(CompilationInfo* info, | 543 HGraphBuilder::HGraphBuilder(CompilationInfo* info, |
544 TypeFeedbackOracle* oracle) | 544 TypeFeedbackOracle* oracle) |
545 : function_state_(NULL), | 545 : function_state_(NULL), |
546 initial_function_state_(this, info, oracle, false), | 546 initial_function_state_(this, info, oracle, false, false), |
Vyacheslav Egorov (Chromium)
2012/02/13 15:01:39
I think we should come up with enum at least for i
Michael Starzinger
2012/02/27 14:16:32
Done. Merged drop_extra and is_construct into one
| |
547 ast_context_(NULL), | 547 ast_context_(NULL), |
548 break_scope_(NULL), | 548 break_scope_(NULL), |
549 graph_(NULL), | 549 graph_(NULL), |
550 current_block_(NULL), | 550 current_block_(NULL), |
551 inlined_count_(0), | 551 inlined_count_(0), |
552 zone_(info->isolate()->zone()), | 552 zone_(info->isolate()->zone()), |
553 inline_bailout_(false) { | 553 inline_bailout_(false) { |
554 // This is not initialized in the initializer list because the | 554 // This is not initialized in the initializer list because the |
555 // constructor for the initial state relies on function_state_ == NULL | 555 // constructor for the initial state relies on function_state_ == NULL |
556 // to know it's the initial state. | 556 // to know it's the initial state. |
(...skipping 1462 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2019 } | 2019 } |
2020 } | 2020 } |
2021 } | 2021 } |
2022 | 2022 |
2023 | 2023 |
2024 // Implementation of utility class to encapsulate the translation state for | 2024 // Implementation of utility class to encapsulate the translation state for |
2025 // a (possibly inlined) function. | 2025 // a (possibly inlined) function. |
2026 FunctionState::FunctionState(HGraphBuilder* owner, | 2026 FunctionState::FunctionState(HGraphBuilder* owner, |
2027 CompilationInfo* info, | 2027 CompilationInfo* info, |
2028 TypeFeedbackOracle* oracle, | 2028 TypeFeedbackOracle* oracle, |
2029 bool drop_extra) | 2029 bool drop_extra, |
2030 bool is_construct) | |
2030 : owner_(owner), | 2031 : owner_(owner), |
2031 compilation_info_(info), | 2032 compilation_info_(info), |
2032 oracle_(oracle), | 2033 oracle_(oracle), |
2033 call_context_(NULL), | 2034 call_context_(NULL), |
2034 drop_extra_(drop_extra), | 2035 drop_extra_(drop_extra), |
2036 is_construct_(is_construct), | |
2035 function_return_(NULL), | 2037 function_return_(NULL), |
2036 test_context_(NULL), | 2038 test_context_(NULL), |
2037 outer_(owner->function_state()) { | 2039 outer_(owner->function_state()) { |
2038 if (outer_ != NULL) { | 2040 if (outer_ != NULL) { |
2039 // State for an inline function. | 2041 // State for an inline function. |
2040 if (owner->ast_context()->IsTest()) { | 2042 if (owner->ast_context()->IsTest()) { |
2041 HBasicBlock* if_true = owner->graph()->CreateBasicBlock(); | 2043 HBasicBlock* if_true = owner->graph()->CreateBasicBlock(); |
2042 HBasicBlock* if_false = owner->graph()->CreateBasicBlock(); | 2044 HBasicBlock* if_false = owner->graph()->CreateBasicBlock(); |
2043 if_true->MarkAsInlineReturnTarget(); | 2045 if_true->MarkAsInlineReturnTarget(); |
2044 if_false->MarkAsInlineReturnTarget(); | 2046 if_false->MarkAsInlineReturnTarget(); |
(...skipping 22 matching lines...) Expand all Loading... | |
2067 | 2069 |
2068 // Implementation of utility classes to represent an expression's context in | 2070 // Implementation of utility classes to represent an expression's context in |
2069 // the AST. | 2071 // the AST. |
2070 AstContext::AstContext(HGraphBuilder* owner, Expression::Context kind) | 2072 AstContext::AstContext(HGraphBuilder* owner, Expression::Context kind) |
2071 : owner_(owner), | 2073 : owner_(owner), |
2072 kind_(kind), | 2074 kind_(kind), |
2073 outer_(owner->ast_context()), | 2075 outer_(owner->ast_context()), |
2074 for_typeof_(false) { | 2076 for_typeof_(false) { |
2075 owner->set_ast_context(this); // Push. | 2077 owner->set_ast_context(this); // Push. |
2076 #ifdef DEBUG | 2078 #ifdef DEBUG |
2077 ASSERT(!owner->environment()->is_arguments_adaptor()); | 2079 ASSERT(owner->environment()->frame_type() == JS_FUNCTION); |
2078 original_length_ = owner->environment()->length(); | 2080 original_length_ = owner->environment()->length(); |
2079 #endif | 2081 #endif |
2080 } | 2082 } |
2081 | 2083 |
2082 | 2084 |
2083 AstContext::~AstContext() { | 2085 AstContext::~AstContext() { |
2084 owner_->set_ast_context(outer_); // Pop. | 2086 owner_->set_ast_context(outer_); // Pop. |
2085 } | 2087 } |
2086 | 2088 |
2087 | 2089 |
2088 EffectContext::~EffectContext() { | 2090 EffectContext::~EffectContext() { |
2089 ASSERT(owner()->HasStackOverflow() || | 2091 ASSERT(owner()->HasStackOverflow() || |
2090 owner()->current_block() == NULL || | 2092 owner()->current_block() == NULL || |
2091 (owner()->environment()->length() == original_length_ && | 2093 (owner()->environment()->length() == original_length_ && |
2092 !owner()->environment()->is_arguments_adaptor())); | 2094 owner()->environment()->frame_type() == JS_FUNCTION)); |
2093 } | 2095 } |
2094 | 2096 |
2095 | 2097 |
2096 ValueContext::~ValueContext() { | 2098 ValueContext::~ValueContext() { |
2097 ASSERT(owner()->HasStackOverflow() || | 2099 ASSERT(owner()->HasStackOverflow() || |
2098 owner()->current_block() == NULL || | 2100 owner()->current_block() == NULL || |
2099 (owner()->environment()->length() == original_length_ + 1 && | 2101 (owner()->environment()->length() == original_length_ + 1 && |
2100 !owner()->environment()->is_arguments_adaptor())); | 2102 owner()->environment()->frame_type() == JS_FUNCTION)); |
2101 } | 2103 } |
2102 | 2104 |
2103 | 2105 |
2104 void EffectContext::ReturnValue(HValue* value) { | 2106 void EffectContext::ReturnValue(HValue* value) { |
2105 // The value is simply ignored. | 2107 // The value is simply ignored. |
2106 } | 2108 } |
2107 | 2109 |
2108 | 2110 |
2109 void ValueContext::ReturnValue(HValue* value) { | 2111 void ValueContext::ReturnValue(HValue* value) { |
2110 // The value is tracked in the bailout environment, and communicated | 2112 // The value is tracked in the bailout environment, and communicated |
(...skipping 554 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2665 void HGraphBuilder::VisitReturnStatement(ReturnStatement* stmt) { | 2667 void HGraphBuilder::VisitReturnStatement(ReturnStatement* stmt) { |
2666 ASSERT(!HasStackOverflow()); | 2668 ASSERT(!HasStackOverflow()); |
2667 ASSERT(current_block() != NULL); | 2669 ASSERT(current_block() != NULL); |
2668 ASSERT(current_block()->HasPredecessor()); | 2670 ASSERT(current_block()->HasPredecessor()); |
2669 AstContext* context = call_context(); | 2671 AstContext* context = call_context(); |
2670 if (context == NULL) { | 2672 if (context == NULL) { |
2671 // Not an inlined return, so an actual one. | 2673 // Not an inlined return, so an actual one. |
2672 CHECK_ALIVE(VisitForValue(stmt->expression())); | 2674 CHECK_ALIVE(VisitForValue(stmt->expression())); |
2673 HValue* result = environment()->Pop(); | 2675 HValue* result = environment()->Pop(); |
2674 current_block()->FinishExit(new(zone()) HReturn(result)); | 2676 current_block()->FinishExit(new(zone()) HReturn(result)); |
2675 set_current_block(NULL); | 2677 } else if (function_state()->is_construct()) { |
2678 // Return from an inlined construct call. In a test context the return | |
2679 // value will always evaluate to true, in a value context the return value | |
2680 // needs to be a JSObject. | |
2681 if (context->IsTest()) { | |
2682 TestContext* test = TestContext::cast(context); | |
2683 CHECK_ALIVE(VisitForEffect(stmt->expression())); | |
2684 current_block()->Goto(test->if_true(), function_state()->drop_extra()); | |
2685 } else if (context->IsEffect()) { | |
2686 CHECK_ALIVE(VisitForEffect(stmt->expression())); | |
2687 current_block()->Goto(function_return(), function_state()->drop_extra()); | |
2688 } else { | |
2689 ASSERT(context->IsValue()); | |
2690 CHECK_ALIVE(VisitForValue(stmt->expression())); | |
2691 HValue* return_value = Pop(); | |
2692 HValue* receiver = environment()->Lookup(0); | |
2693 HHasInstanceTypeAndBranch* typecheck = | |
2694 new(zone()) HHasInstanceTypeAndBranch(return_value, | |
2695 FIRST_SPEC_OBJECT_TYPE, | |
2696 LAST_SPEC_OBJECT_TYPE); | |
2697 HBasicBlock* if_spec_object = graph()->CreateBasicBlock(); | |
2698 HBasicBlock* not_spec_object = graph()->CreateBasicBlock(); | |
2699 typecheck->SetSuccessorAt(0, if_spec_object); | |
2700 typecheck->SetSuccessorAt(1, not_spec_object); | |
2701 current_block()->Finish(typecheck); | |
2702 if_spec_object->AddLeaveInlined(return_value, | |
2703 function_return(), | |
2704 function_state()->drop_extra()); | |
2705 not_spec_object->AddLeaveInlined(receiver, | |
2706 function_return(), | |
2707 function_state()->drop_extra()); | |
2708 } | |
2676 } else { | 2709 } else { |
2677 // Return from an inlined function, visit the subexpression in the | 2710 // Return from an inlined function, visit the subexpression in the |
2678 // expression context of the call. | 2711 // expression context of the call. |
2679 if (context->IsTest()) { | 2712 if (context->IsTest()) { |
2680 TestContext* test = TestContext::cast(context); | 2713 TestContext* test = TestContext::cast(context); |
2681 VisitForControl(stmt->expression(), | 2714 VisitForControl(stmt->expression(), |
2682 test->if_true(), | 2715 test->if_true(), |
2683 test->if_false()); | 2716 test->if_false()); |
2684 } else if (context->IsEffect()) { | 2717 } else if (context->IsEffect()) { |
2685 CHECK_ALIVE(VisitForEffect(stmt->expression())); | 2718 CHECK_ALIVE(VisitForEffect(stmt->expression())); |
2686 current_block()->Goto(function_return(), function_state()->drop_extra()); | 2719 current_block()->Goto(function_return(), function_state()->drop_extra()); |
2687 } else { | 2720 } else { |
2688 ASSERT(context->IsValue()); | 2721 ASSERT(context->IsValue()); |
2689 CHECK_ALIVE(VisitForValue(stmt->expression())); | 2722 CHECK_ALIVE(VisitForValue(stmt->expression())); |
2690 HValue* return_value = environment()->Pop(); | 2723 HValue* return_value = Pop(); |
2691 current_block()->AddLeaveInlined(return_value, | 2724 current_block()->AddLeaveInlined(return_value, |
2692 function_return(), | 2725 function_return(), |
2693 function_state()->drop_extra()); | 2726 function_state()->drop_extra()); |
2694 } | 2727 } |
2695 set_current_block(NULL); | |
2696 } | 2728 } |
2729 set_current_block(NULL); | |
2697 } | 2730 } |
2698 | 2731 |
2699 | 2732 |
2700 void HGraphBuilder::VisitWithStatement(WithStatement* stmt) { | 2733 void HGraphBuilder::VisitWithStatement(WithStatement* stmt) { |
2701 ASSERT(!HasStackOverflow()); | 2734 ASSERT(!HasStackOverflow()); |
2702 ASSERT(current_block() != NULL); | 2735 ASSERT(current_block() != NULL); |
2703 ASSERT(current_block()->HasPredecessor()); | 2736 ASSERT(current_block()->HasPredecessor()); |
2704 return Bailout("WithStatement"); | 2737 return Bailout("WithStatement"); |
2705 } | 2738 } |
2706 | 2739 |
(...skipping 1997 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4704 HCompareMap* compare = | 4737 HCompareMap* compare = |
4705 new(zone()) HCompareMap(receiver, map, if_true, if_false); | 4738 new(zone()) HCompareMap(receiver, map, if_true, if_false); |
4706 current_block()->Finish(compare); | 4739 current_block()->Finish(compare); |
4707 | 4740 |
4708 set_current_block(if_true); | 4741 set_current_block(if_true); |
4709 AddCheckConstantFunction(expr, receiver, map, false); | 4742 AddCheckConstantFunction(expr, receiver, map, false); |
4710 if (FLAG_trace_inlining && FLAG_polymorphic_inlining) { | 4743 if (FLAG_trace_inlining && FLAG_polymorphic_inlining) { |
4711 PrintF("Trying to inline the polymorphic call to %s\n", | 4744 PrintF("Trying to inline the polymorphic call to %s\n", |
4712 *name->ToCString()); | 4745 *name->ToCString()); |
4713 } | 4746 } |
4714 if (FLAG_polymorphic_inlining && TryInline(expr)) { | 4747 if (FLAG_polymorphic_inlining && TryInlineCall(expr)) { |
4715 // Trying to inline will signal that we should bailout from the | 4748 // Trying to inline will signal that we should bailout from the |
4716 // entire compilation by setting stack overflow on the visitor. | 4749 // entire compilation by setting stack overflow on the visitor. |
4717 if (HasStackOverflow()) return; | 4750 if (HasStackOverflow()) return; |
4718 } else { | 4751 } else { |
4719 HCallConstantFunction* call = | 4752 HCallConstantFunction* call = |
4720 new(zone()) HCallConstantFunction(expr->target(), argument_count); | 4753 new(zone()) HCallConstantFunction(expr->target(), argument_count); |
4721 call->set_position(expr->position()); | 4754 call->set_position(expr->position()); |
4722 PreProcessCall(call); | 4755 PreProcessCall(call); |
4723 AddInstruction(call); | 4756 AddInstruction(call); |
4724 if (!ast_context()->IsEffect()) Push(call); | 4757 if (!ast_context()->IsEffect()) Push(call); |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4774 if (reason == NULL) { | 4807 if (reason == NULL) { |
4775 PrintF("Inlined %s called from %s.\n", *target_name, *caller_name); | 4808 PrintF("Inlined %s called from %s.\n", *target_name, *caller_name); |
4776 } else { | 4809 } else { |
4777 PrintF("Did not inline %s called from %s (%s).\n", | 4810 PrintF("Did not inline %s called from %s (%s).\n", |
4778 *target_name, *caller_name, reason); | 4811 *target_name, *caller_name, reason); |
4779 } | 4812 } |
4780 } | 4813 } |
4781 } | 4814 } |
4782 | 4815 |
4783 | 4816 |
4784 bool HGraphBuilder::TryInline(Call* expr, bool drop_extra) { | 4817 bool HGraphBuilder::TryInline(CallKind call_kind, |
4818 Handle<JSFunction> target, | |
4819 ZoneList<Expression*>* arguments, | |
4820 HValue* receiver, | |
4821 int ast_id, | |
4822 int return_id, | |
4823 bool drop_extra, | |
Vyacheslav Egorov (Chromium)
2012/02/13 15:01:39
Consider introducing enums
Michael Starzinger
2012/02/27 14:16:32
Done. Merged drop_extra and is_construct into one
| |
4824 bool is_construct) { | |
4785 if (!FLAG_use_inlining) return false; | 4825 if (!FLAG_use_inlining) return false; |
4786 | 4826 |
4787 // The function call we are inlining is a method call if the call | |
4788 // is a property call. | |
4789 CallKind call_kind = (expr->expression()->AsProperty() == NULL) | |
4790 ? CALL_AS_FUNCTION | |
4791 : CALL_AS_METHOD; | |
4792 | |
4793 // Precondition: call is monomorphic and we have found a target with the | 4827 // Precondition: call is monomorphic and we have found a target with the |
4794 // appropriate arity. | 4828 // appropriate arity. |
4795 Handle<JSFunction> caller = info()->closure(); | 4829 Handle<JSFunction> caller = info()->closure(); |
4796 Handle<JSFunction> target = expr->target(); | |
4797 Handle<SharedFunctionInfo> target_shared(target->shared()); | 4830 Handle<SharedFunctionInfo> target_shared(target->shared()); |
4798 | 4831 |
4799 // Do a quick check on source code length to avoid parsing large | 4832 // Do a quick check on source code length to avoid parsing large |
4800 // inlining candidates. | 4833 // inlining candidates. |
4801 if ((FLAG_limit_inlining && target->shared()->SourceSize() > kMaxSourceSize) | 4834 if ((FLAG_limit_inlining && target->shared()->SourceSize() > kMaxSourceSize) |
4802 || target->shared()->SourceSize() > kUnlimitedMaxSourceSize) { | 4835 || target->shared()->SourceSize() > kUnlimitedMaxSourceSize) { |
4803 TraceInline(target, caller, "target text too big"); | 4836 TraceInline(target, caller, "target text too big"); |
4804 return false; | 4837 return false; |
4805 } | 4838 } |
4806 | 4839 |
(...skipping 16 matching lines...) Expand all Loading... | |
4823 | 4856 |
4824 | 4857 |
4825 // Don't inline deeper than kMaxInliningLevels calls. | 4858 // Don't inline deeper than kMaxInliningLevels calls. |
4826 HEnvironment* env = environment(); | 4859 HEnvironment* env = environment(); |
4827 int current_level = 1; | 4860 int current_level = 1; |
4828 while (env->outer() != NULL) { | 4861 while (env->outer() != NULL) { |
4829 if (current_level == Compiler::kMaxInliningLevels) { | 4862 if (current_level == Compiler::kMaxInliningLevels) { |
4830 TraceInline(target, caller, "inline depth limit reached"); | 4863 TraceInline(target, caller, "inline depth limit reached"); |
4831 return false; | 4864 return false; |
4832 } | 4865 } |
4833 if (!env->outer()->is_arguments_adaptor()) { | 4866 if (env->outer()->frame_type() == JS_FUNCTION) { |
4834 current_level++; | 4867 current_level++; |
4835 } | 4868 } |
4836 env = env->outer(); | 4869 env = env->outer(); |
4837 } | 4870 } |
4838 | 4871 |
4839 // Don't inline recursive functions. | 4872 // Don't inline recursive functions. |
4840 for (FunctionState* state = function_state(); | 4873 for (FunctionState* state = function_state(); |
4841 state != NULL; | 4874 state != NULL; |
4842 state = state->outer()) { | 4875 state = state->outer()) { |
4843 if (state->compilation_info()->closure()->shared() == *target_shared) { | 4876 if (state->compilation_info()->closure()->shared() == *target_shared) { |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4934 | 4967 |
4935 // Save the pending call context and type feedback oracle. Set up new ones | 4968 // Save the pending call context and type feedback oracle. Set up new ones |
4936 // for the inlined function. | 4969 // for the inlined function. |
4937 ASSERT(target_shared->has_deoptimization_support()); | 4970 ASSERT(target_shared->has_deoptimization_support()); |
4938 TypeFeedbackOracle target_oracle( | 4971 TypeFeedbackOracle target_oracle( |
4939 Handle<Code>(target_shared->code()), | 4972 Handle<Code>(target_shared->code()), |
4940 Handle<Context>(target->context()->global_context()), | 4973 Handle<Context>(target->context()->global_context()), |
4941 isolate()); | 4974 isolate()); |
4942 // The function state is new-allocated because we need to delete it | 4975 // The function state is new-allocated because we need to delete it |
4943 // in two different places. | 4976 // in two different places. |
4944 FunctionState* target_state = | 4977 FunctionState* target_state = new FunctionState( |
4945 new FunctionState(this, &target_info, &target_oracle, drop_extra); | 4978 this, &target_info, &target_oracle, drop_extra, is_construct); |
4946 | 4979 |
4947 HConstant* undefined = graph()->GetConstantUndefined(); | 4980 HConstant* undefined = graph()->GetConstantUndefined(); |
4948 HEnvironment* inner_env = | 4981 HEnvironment* inner_env = |
4949 environment()->CopyForInlining(target, | 4982 environment()->CopyForInlining(target, |
4950 expr->arguments()->length(), | 4983 arguments->length(), |
4951 function, | 4984 function, |
4952 undefined, | 4985 undefined, |
4953 call_kind); | 4986 call_kind, |
4987 is_construct); | |
4954 #ifdef V8_TARGET_ARCH_IA32 | 4988 #ifdef V8_TARGET_ARCH_IA32 |
4955 // IA32 only, overwrite the caller's context in the deoptimization | 4989 // IA32 only, overwrite the caller's context in the deoptimization |
4956 // environment with the correct one. | 4990 // environment with the correct one. |
4957 // | 4991 // |
4958 // TODO(kmillikin): implement the same inlining on other platforms so we | 4992 // TODO(kmillikin): implement the same inlining on other platforms so we |
4959 // can remove the unsightly ifdefs in this function. | 4993 // can remove the unsightly ifdefs in this function. |
4960 HConstant* context = new HConstant(Handle<Context>(target->context()), | 4994 HConstant* context = new HConstant(Handle<Context>(target->context()), |
4961 Representation::Tagged()); | 4995 Representation::Tagged()); |
4962 AddInstruction(context); | 4996 AddInstruction(context); |
4963 inner_env->BindContext(context); | 4997 inner_env->BindContext(context); |
4964 #endif | 4998 #endif |
4965 HBasicBlock* body_entry = CreateBasicBlock(inner_env); | 4999 HBasicBlock* body_entry = CreateBasicBlock(inner_env); |
4966 current_block()->Goto(body_entry); | 5000 current_block()->Goto(body_entry); |
4967 body_entry->SetJoinId(expr->ReturnId()); | 5001 body_entry->SetJoinId(return_id); |
4968 set_current_block(body_entry); | 5002 set_current_block(body_entry); |
4969 AddInstruction(new(zone()) HEnterInlined(target, | 5003 AddInstruction(new(zone()) HEnterInlined(target, |
4970 expr->arguments()->length(), | 5004 arguments->length(), |
4971 function, | 5005 function, |
4972 call_kind)); | 5006 call_kind, |
5007 is_construct)); | |
4973 VisitDeclarations(target_info.scope()->declarations()); | 5008 VisitDeclarations(target_info.scope()->declarations()); |
4974 VisitStatements(function->body()); | 5009 VisitStatements(function->body()); |
4975 if (HasStackOverflow()) { | 5010 if (HasStackOverflow()) { |
4976 // Bail out if the inline function did, as we cannot residualize a call | 5011 // Bail out if the inline function did, as we cannot residualize a call |
4977 // instead. | 5012 // instead. |
4978 TraceInline(target, caller, "inline graph construction failed"); | 5013 TraceInline(target, caller, "inline graph construction failed"); |
4979 target_shared->DisableOptimization(*target); | 5014 target_shared->DisableOptimization(*target); |
4980 inline_bailout_ = true; | 5015 inline_bailout_ = true; |
4981 delete target_state; | 5016 delete target_state; |
4982 return true; | 5017 return true; |
4983 } | 5018 } |
4984 | 5019 |
4985 // Update inlined nodes count. | 5020 // Update inlined nodes count. |
4986 inlined_count_ += nodes_added; | 5021 inlined_count_ += nodes_added; |
4987 | 5022 |
4988 TraceInline(target, caller, NULL); | 5023 TraceInline(target, caller, NULL); |
4989 | 5024 |
4990 if (current_block() != NULL) { | 5025 if (current_block() != NULL) { |
4991 // Add a return of undefined if control can fall off the body. In a | 5026 // Add default return value (i.e. undefined for normals calls or the newly |
4992 // test context, undefined is false. | 5027 // allocated receiver for construct calls) if control can fall off the |
5028 // body. In a test context, undefined is false and any JSObject is true. | |
5029 HValue* return_value = is_construct ? receiver : undefined; | |
4993 if (inlined_test_context() == NULL) { | 5030 if (inlined_test_context() == NULL) { |
4994 ASSERT(function_return() != NULL); | 5031 ASSERT(function_return() != NULL); |
4995 ASSERT(call_context()->IsEffect() || call_context()->IsValue()); | 5032 ASSERT(call_context()->IsEffect() || call_context()->IsValue()); |
4996 if (call_context()->IsEffect()) { | 5033 if (call_context()->IsEffect()) { |
4997 current_block()->Goto(function_return(), drop_extra); | 5034 current_block()->Goto(function_return(), drop_extra); |
4998 } else { | 5035 } else { |
4999 current_block()->AddLeaveInlined(undefined, | 5036 current_block()->AddLeaveInlined(return_value, |
5000 function_return(), | 5037 function_return(), |
5001 drop_extra); | 5038 drop_extra); |
5002 } | 5039 } |
5003 } else { | 5040 } else { |
5004 // The graph builder assumes control can reach both branches of a | 5041 // The graph builder assumes control can reach both branches of a |
5005 // test, so we materialize the undefined value and test it rather than | 5042 // test, so we materialize the undefined value and test it rather than |
5006 // simply jumping to the false target. | 5043 // simply jumping to the false target. |
5007 // | 5044 // |
5008 // TODO(3168478): refactor to avoid this. | 5045 // TODO(3168478): refactor to avoid this. |
Vyacheslav Egorov (Chromium)
2012/02/13 15:01:39
It seems this comment&todo is outdated (see r7601)
Michael Starzinger
2012/02/27 14:16:32
Done.
| |
5009 ASSERT(call_context()->IsTest()); | 5046 ASSERT(call_context()->IsTest()); |
5010 HBasicBlock* empty_true = graph()->CreateBasicBlock(); | 5047 HBasicBlock* empty_true = graph()->CreateBasicBlock(); |
5011 HBasicBlock* empty_false = graph()->CreateBasicBlock(); | 5048 HBasicBlock* empty_false = graph()->CreateBasicBlock(); |
5012 HBranch* test = new(zone()) HBranch(undefined, empty_true, empty_false); | 5049 HBranch* test = |
5050 new(zone()) HBranch(return_value, empty_true, empty_false); | |
5013 current_block()->Finish(test); | 5051 current_block()->Finish(test); |
5014 | 5052 |
5015 empty_true->Goto(inlined_test_context()->if_true(), drop_extra); | 5053 empty_true->Goto(inlined_test_context()->if_true(), drop_extra); |
5016 empty_false->Goto(inlined_test_context()->if_false(), drop_extra); | 5054 empty_false->Goto(inlined_test_context()->if_false(), drop_extra); |
5017 } | 5055 } |
5018 } | 5056 } |
5019 | 5057 |
5020 // Fix up the function exits. | 5058 // Fix up the function exits. |
5021 if (inlined_test_context() != NULL) { | 5059 if (inlined_test_context() != NULL) { |
5022 HBasicBlock* if_true = inlined_test_context()->if_true(); | 5060 HBasicBlock* if_true = inlined_test_context()->if_true(); |
5023 HBasicBlock* if_false = inlined_test_context()->if_false(); | 5061 HBasicBlock* if_false = inlined_test_context()->if_false(); |
5024 | 5062 |
5025 // Pop the return test context from the expression context stack. | 5063 // Pop the return test context from the expression context stack. |
5026 ASSERT(ast_context() == inlined_test_context()); | 5064 ASSERT(ast_context() == inlined_test_context()); |
5027 ClearInlinedTestContext(); | 5065 ClearInlinedTestContext(); |
5028 delete target_state; | 5066 delete target_state; |
5029 | 5067 |
5030 // Forward to the real test context. | 5068 // Forward to the real test context. |
5031 if (if_true->HasPredecessor()) { | 5069 if (if_true->HasPredecessor()) { |
5032 if_true->SetJoinId(expr->id()); | 5070 if_true->SetJoinId(ast_id); |
5033 HBasicBlock* true_target = TestContext::cast(ast_context())->if_true(); | 5071 HBasicBlock* true_target = TestContext::cast(ast_context())->if_true(); |
5034 if_true->Goto(true_target, function_state()->drop_extra()); | 5072 if_true->Goto(true_target, function_state()->drop_extra()); |
5035 } | 5073 } |
5036 if (if_false->HasPredecessor()) { | 5074 if (if_false->HasPredecessor()) { |
5037 if_false->SetJoinId(expr->id()); | 5075 if_false->SetJoinId(ast_id); |
5038 HBasicBlock* false_target = TestContext::cast(ast_context())->if_false(); | 5076 HBasicBlock* false_target = TestContext::cast(ast_context())->if_false(); |
5039 if_false->Goto(false_target, function_state()->drop_extra()); | 5077 if_false->Goto(false_target, function_state()->drop_extra()); |
5040 } | 5078 } |
5041 set_current_block(NULL); | 5079 set_current_block(NULL); |
5042 return true; | 5080 return true; |
5043 | 5081 |
5044 } else if (function_return()->HasPredecessor()) { | 5082 } else if (function_return()->HasPredecessor()) { |
5045 function_return()->SetJoinId(expr->id()); | 5083 function_return()->SetJoinId(ast_id); |
5046 set_current_block(function_return()); | 5084 set_current_block(function_return()); |
5047 } else { | 5085 } else { |
5048 set_current_block(NULL); | 5086 set_current_block(NULL); |
5049 } | 5087 } |
5050 delete target_state; | 5088 delete target_state; |
5051 return true; | 5089 return true; |
5052 } | 5090 } |
5053 | 5091 |
5054 | 5092 |
5093 bool HGraphBuilder::TryInlineCall(Call* expr, bool drop_extra) { | |
5094 Handle<JSFunction> target = expr->target(); | |
5095 ZoneList<Expression*>* arguments = expr->arguments(); | |
5096 HValue* receiver = NULL; | |
5097 int return_id = expr->ReturnId(); | |
5098 int ast_id = expr->id(); | |
5099 | |
5100 // The function call we are inlining is a method call if the call | |
5101 // is a property call. | |
5102 CallKind call_kind = (expr->expression()->AsProperty() == NULL) | |
5103 ? CALL_AS_FUNCTION | |
5104 : CALL_AS_METHOD; | |
5105 | |
5106 return TryInline(call_kind, target, arguments, receiver, ast_id, return_id, | |
5107 drop_extra, false); | |
5108 } | |
5109 | |
5110 | |
5111 bool HGraphBuilder::TryInlineConstruct(CallNew* expr, HValue* receiver) { | |
5112 Handle<JSFunction> target = expr->target(); | |
5113 ZoneList<Expression*>* arguments = expr->arguments(); | |
5114 CallKind call_kind = CALL_AS_FUNCTION; | |
5115 int return_id = expr->ReturnId(); | |
5116 int ast_id = expr->id(); | |
5117 | |
5118 return TryInline(call_kind, target, arguments, receiver, ast_id, return_id, | |
5119 false, true); | |
5120 } | |
5121 | |
5122 | |
5055 bool HGraphBuilder::TryInlineBuiltinFunction(Call* expr, | 5123 bool HGraphBuilder::TryInlineBuiltinFunction(Call* expr, |
5056 HValue* receiver, | 5124 HValue* receiver, |
5057 Handle<Map> receiver_map, | 5125 Handle<Map> receiver_map, |
5058 CheckType check_type) { | 5126 CheckType check_type) { |
5059 ASSERT(check_type != RECEIVER_MAP_CHECK || !receiver_map.is_null()); | 5127 ASSERT(check_type != RECEIVER_MAP_CHECK || !receiver_map.is_null()); |
5060 // Try to inline calls like Math.* as operations in the calling function. | 5128 // Try to inline calls like Math.* as operations in the calling function. |
5061 if (!expr->target()->shared()->HasBuiltinFunctionId()) return false; | 5129 if (!expr->target()->shared()->HasBuiltinFunctionId()) return false; |
5062 BuiltinFunctionId id = expr->target()->shared()->builtin_function_id(); | 5130 BuiltinFunctionId id = expr->target()->shared()->builtin_function_id(); |
5063 int argument_count = expr->arguments()->length() + 1; // Plus receiver. | 5131 int argument_count = expr->arguments()->length() + 1; // Plus receiver. |
5064 switch (id) { | 5132 switch (id) { |
(...skipping 263 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
5328 expr->check_type() != RECEIVER_MAP_CHECK) { | 5396 expr->check_type() != RECEIVER_MAP_CHECK) { |
5329 // When the target has a custom call IC generator, use the IC, | 5397 // When the target has a custom call IC generator, use the IC, |
5330 // because it is likely to generate better code. Also use the IC | 5398 // because it is likely to generate better code. Also use the IC |
5331 // when a primitive receiver check is required. | 5399 // when a primitive receiver check is required. |
5332 HValue* context = environment()->LookupContext(); | 5400 HValue* context = environment()->LookupContext(); |
5333 call = PreProcessCall( | 5401 call = PreProcessCall( |
5334 new(zone()) HCallNamed(context, name, argument_count)); | 5402 new(zone()) HCallNamed(context, name, argument_count)); |
5335 } else { | 5403 } else { |
5336 AddCheckConstantFunction(expr, receiver, receiver_map, true); | 5404 AddCheckConstantFunction(expr, receiver, receiver_map, true); |
5337 | 5405 |
5338 if (TryInline(expr)) return; | 5406 if (TryInlineCall(expr)) return; |
5339 call = PreProcessCall( | 5407 call = PreProcessCall( |
5340 new(zone()) HCallConstantFunction(expr->target(), | 5408 new(zone()) HCallConstantFunction(expr->target(), |
5341 argument_count)); | 5409 argument_count)); |
5342 } | 5410 } |
5343 } else if (types != NULL && types->length() > 1) { | 5411 } else if (types != NULL && types->length() > 1) { |
5344 ASSERT(expr->check_type() == RECEIVER_MAP_CHECK); | 5412 ASSERT(expr->check_type() == RECEIVER_MAP_CHECK); |
5345 HandlePolymorphicCallNamed(expr, receiver, types, name); | 5413 HandlePolymorphicCallNamed(expr, receiver, types, name); |
5346 return; | 5414 return; |
5347 | 5415 |
5348 } else { | 5416 } else { |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
5384 // Replace the global object with the global receiver. | 5452 // Replace the global object with the global receiver. |
5385 HGlobalReceiver* global_receiver = | 5453 HGlobalReceiver* global_receiver = |
5386 new(zone()) HGlobalReceiver(global_object); | 5454 new(zone()) HGlobalReceiver(global_object); |
5387 // Index of the receiver from the top of the expression stack. | 5455 // Index of the receiver from the top of the expression stack. |
5388 const int receiver_index = argument_count - 1; | 5456 const int receiver_index = argument_count - 1; |
5389 AddInstruction(global_receiver); | 5457 AddInstruction(global_receiver); |
5390 ASSERT(environment()->ExpressionStackAt(receiver_index)-> | 5458 ASSERT(environment()->ExpressionStackAt(receiver_index)-> |
5391 IsGlobalObject()); | 5459 IsGlobalObject()); |
5392 environment()->SetExpressionStackAt(receiver_index, global_receiver); | 5460 environment()->SetExpressionStackAt(receiver_index, global_receiver); |
5393 | 5461 |
5394 if (TryInline(expr)) return; | 5462 if (TryInlineCall(expr)) return; |
5395 call = PreProcessCall(new(zone()) HCallKnownGlobal(expr->target(), | 5463 call = PreProcessCall(new(zone()) HCallKnownGlobal(expr->target(), |
5396 argument_count)); | 5464 argument_count)); |
5397 } else { | 5465 } else { |
5398 HValue* context = environment()->LookupContext(); | 5466 HValue* context = environment()->LookupContext(); |
5399 HGlobalObject* receiver = new(zone()) HGlobalObject(context); | 5467 HGlobalObject* receiver = new(zone()) HGlobalObject(context); |
5400 AddInstruction(receiver); | 5468 AddInstruction(receiver); |
5401 PushAndAdd(new(zone()) HPushArgument(receiver)); | 5469 PushAndAdd(new(zone()) HPushArgument(receiver)); |
5402 CHECK_ALIVE(VisitArgumentList(expr->arguments())); | 5470 CHECK_ALIVE(VisitArgumentList(expr->arguments())); |
5403 | 5471 |
5404 call = new(zone()) HCallGlobal(context, var->name(), argument_count); | 5472 call = new(zone()) HCallGlobal(context, var->name(), argument_count); |
5405 Drop(argument_count); | 5473 Drop(argument_count); |
5406 } | 5474 } |
5407 | 5475 |
5408 } else if (expr->IsMonomorphic()) { | 5476 } else if (expr->IsMonomorphic()) { |
5409 // The function is on the stack in the unoptimized code during | 5477 // The function is on the stack in the unoptimized code during |
5410 // evaluation of the arguments. | 5478 // evaluation of the arguments. |
5411 CHECK_ALIVE(VisitForValue(expr->expression())); | 5479 CHECK_ALIVE(VisitForValue(expr->expression())); |
5412 HValue* function = Top(); | 5480 HValue* function = Top(); |
5413 HValue* context = environment()->LookupContext(); | 5481 HValue* context = environment()->LookupContext(); |
5414 HGlobalObject* global = new(zone()) HGlobalObject(context); | 5482 HGlobalObject* global = new(zone()) HGlobalObject(context); |
5415 HGlobalReceiver* receiver = new(zone()) HGlobalReceiver(global); | 5483 HGlobalReceiver* receiver = new(zone()) HGlobalReceiver(global); |
5416 AddInstruction(global); | 5484 AddInstruction(global); |
5417 PushAndAdd(receiver); | 5485 PushAndAdd(receiver); |
5418 CHECK_ALIVE(VisitExpressions(expr->arguments())); | 5486 CHECK_ALIVE(VisitExpressions(expr->arguments())); |
5419 AddInstruction(new(zone()) HCheckFunction(function, expr->target())); | 5487 AddInstruction(new(zone()) HCheckFunction(function, expr->target())); |
5420 if (TryInline(expr, true)) { // Drop function from environment. | 5488 if (TryInlineCall(expr, true)) { // Drop function from environment. |
5421 return; | 5489 return; |
5422 } else { | 5490 } else { |
5423 call = PreProcessCall(new(zone()) HInvokeFunction(context, | 5491 call = PreProcessCall(new(zone()) HInvokeFunction(context, |
5424 function, | 5492 function, |
5425 argument_count)); | 5493 argument_count)); |
5426 Drop(1); // The function. | 5494 Drop(1); // The function. |
5427 } | 5495 } |
5428 | 5496 |
5429 } else { | 5497 } else { |
5430 CHECK_ALIVE(VisitForValue(expr->expression())); | 5498 CHECK_ALIVE(VisitForValue(expr->expression())); |
5431 HValue* function = Top(); | 5499 HValue* function = Top(); |
5432 HValue* context = environment()->LookupContext(); | 5500 HValue* context = environment()->LookupContext(); |
5433 HGlobalObject* global_object = new(zone()) HGlobalObject(context); | 5501 HGlobalObject* global_object = new(zone()) HGlobalObject(context); |
5434 HGlobalReceiver* receiver = new(zone()) HGlobalReceiver(global_object); | 5502 HGlobalReceiver* receiver = new(zone()) HGlobalReceiver(global_object); |
5435 AddInstruction(global_object); | 5503 AddInstruction(global_object); |
5436 AddInstruction(receiver); | 5504 AddInstruction(receiver); |
5437 PushAndAdd(new(zone()) HPushArgument(receiver)); | 5505 PushAndAdd(new(zone()) HPushArgument(receiver)); |
5438 CHECK_ALIVE(VisitArgumentList(expr->arguments())); | 5506 CHECK_ALIVE(VisitArgumentList(expr->arguments())); |
5439 | 5507 |
5440 call = new(zone()) HCallFunction(context, function, argument_count); | 5508 call = new(zone()) HCallFunction(context, function, argument_count); |
5441 Drop(argument_count + 1); | 5509 Drop(argument_count + 1); |
5442 } | 5510 } |
5443 } | 5511 } |
5444 | 5512 |
5445 call->set_position(expr->position()); | 5513 call->set_position(expr->position()); |
5446 return ast_context()->ReturnInstruction(call, expr->id()); | 5514 return ast_context()->ReturnInstruction(call, expr->id()); |
5447 } | 5515 } |
5448 | 5516 |
5449 | 5517 |
5518 // Checks whether allocation using the given constructor can be inlined. | |
5519 static bool IsAllocationInlineable(Handle<JSFunction> constructor) { | |
5520 return constructor->has_initial_map() && | |
5521 constructor->initial_map()->instance_type() == JS_OBJECT_TYPE; | |
5522 } | |
5523 | |
5524 | |
5450 void HGraphBuilder::VisitCallNew(CallNew* expr) { | 5525 void HGraphBuilder::VisitCallNew(CallNew* expr) { |
5451 ASSERT(!HasStackOverflow()); | 5526 ASSERT(!HasStackOverflow()); |
5452 ASSERT(current_block() != NULL); | 5527 ASSERT(current_block() != NULL); |
5453 ASSERT(current_block()->HasPredecessor()); | 5528 ASSERT(current_block()->HasPredecessor()); |
5454 // The constructor function is also used as the receiver argument to the | 5529 expr->RecordTypeFeedback(oracle()); |
5455 // JS construct call builtin. | 5530 int argument_count = expr->arguments()->length() + 1; // Plus constructor. |
5456 HValue* constructor = NULL; | |
5457 CHECK_ALIVE(constructor = VisitArgument(expr->expression())); | |
5458 CHECK_ALIVE(VisitArgumentList(expr->arguments())); | |
5459 | |
5460 HValue* context = environment()->LookupContext(); | 5531 HValue* context = environment()->LookupContext(); |
5461 | 5532 |
5462 // The constructor is both an operand to the instruction and an argument | 5533 if (FLAG_inline_construct && |
5463 // to the construct call. | 5534 expr->IsMonomorphic() && |
5464 int arg_count = expr->arguments()->length() + 1; // Plus constructor. | 5535 IsAllocationInlineable(expr->target())) { |
5465 HCallNew* call = new(zone()) HCallNew(context, constructor, arg_count); | 5536 // The constructor function is on the stack in the unoptimized code |
5466 call->set_position(expr->position()); | 5537 // during evaluation of the arguments. |
5467 Drop(arg_count); | 5538 CHECK_ALIVE(VisitForValue(expr->expression())); |
5468 return ast_context()->ReturnInstruction(call, expr->id()); | 5539 HValue* function = Top(); |
5540 CHECK_ALIVE(VisitExpressions(expr->arguments())); | |
5541 Handle<JSFunction> constructor = expr->target(); | |
5542 AddInstruction(new(zone()) HCheckFunction(function, constructor)); | |
5543 | |
5544 // Replace the constructor function with a newly allocated receiver. | |
5545 HInstruction* receiver = new(zone()) HAllocateObject(context, | |
5546 function, | |
5547 constructor); | |
5548 // Index of the receiver from the top of the expression stack. | |
5549 const int receiver_index = argument_count - 1; | |
5550 AddInstruction(receiver); | |
5551 ASSERT(environment()->ExpressionStackAt(receiver_index) == function); | |
5552 environment()->SetExpressionStackAt(receiver_index, receiver); | |
5553 | |
5554 if (TryInlineConstruct(expr, receiver)) return; | |
5555 HInstruction* call = PreProcessCall( | |
Vyacheslav Egorov (Chromium)
2012/02/13 15:01:39
Is lazy bailout handled correctly on this call-sit
Michael Starzinger
2012/02/27 14:16:32
Done. I temporarily disabled partial inlining as s
| |
5556 new(zone()) HInvokeFunction(context, function, argument_count)); | |
5557 PushAndAdd(call); | |
5558 AddSimulate(expr->id()); | |
5559 | |
5560 // Check whether return value of constructor is a JSObject. | |
5561 HValue* return_value = Pop(); | |
5562 HHasInstanceTypeAndBranch* typecheck = | |
Vyacheslav Egorov (Chromium)
2012/02/13 15:01:39
Branch construction code seems to be duplicated wi
Michael Starzinger
2012/02/27 14:16:32
Comment no longer applies after addressing previou
| |
5563 new(zone()) HHasInstanceTypeAndBranch(return_value, | |
5564 FIRST_SPEC_OBJECT_TYPE, | |
5565 LAST_SPEC_OBJECT_TYPE); | |
5566 HBasicBlock* if_spec_object = graph()->CreateBasicBlock(); | |
5567 HBasicBlock* not_spec_object = graph()->CreateBasicBlock(); | |
5568 typecheck->SetSuccessorAt(0, if_spec_object); | |
5569 typecheck->SetSuccessorAt(1, not_spec_object); | |
5570 current_block()->Finish(typecheck); | |
5571 if_spec_object->last_environment()->Push(return_value); | |
5572 not_spec_object->last_environment()->Push(receiver); | |
5573 set_current_block(CreateJoin(if_spec_object, not_spec_object, expr->id())); | |
5574 return ast_context()->ReturnValue(Pop()); | |
5575 } else { | |
5576 // The constructor function is both an operand to the instruction and an | |
5577 // argument to the construct call. | |
5578 HValue* constructor = NULL; | |
5579 CHECK_ALIVE(constructor = VisitArgument(expr->expression())); | |
5580 CHECK_ALIVE(VisitArgumentList(expr->arguments())); | |
5581 HInstruction* call = | |
5582 new(zone()) HCallNew(context, constructor, argument_count); | |
5583 Drop(argument_count); | |
5584 call->set_position(expr->position()); | |
5585 return ast_context()->ReturnInstruction(call, expr->id()); | |
5586 } | |
5469 } | 5587 } |
5470 | 5588 |
5471 | 5589 |
5472 // Support for generating inlined runtime functions. | 5590 // Support for generating inlined runtime functions. |
5473 | 5591 |
5474 // Lookup table for generators for runtime calls that are generated inline. | 5592 // Lookup table for generators for runtime calls that are generated inline. |
5475 // Elements of the table are member pointers to functions of HGraphBuilder. | 5593 // Elements of the table are member pointers to functions of HGraphBuilder. |
5476 #define INLINE_FUNCTION_GENERATOR_ADDRESS(Name, argc, ressize) \ | 5594 #define INLINE_FUNCTION_GENERATOR_ADDRESS(Name, argc, ressize) \ |
5477 &HGraphBuilder::Generate##Name, | 5595 &HGraphBuilder::Generate##Name, |
5478 | 5596 |
(...skipping 1024 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
6503 CallRuntime* call) { | 6621 CallRuntime* call) { |
6504 return Bailout( | 6622 return Bailout( |
6505 "inlined runtime function: IsStringWrapperSafeForDefaultValueOf"); | 6623 "inlined runtime function: IsStringWrapperSafeForDefaultValueOf"); |
6506 } | 6624 } |
6507 | 6625 |
6508 | 6626 |
6509 // Support for construct call checks. | 6627 // Support for construct call checks. |
6510 void HGraphBuilder::GenerateIsConstructCall(CallRuntime* call) { | 6628 void HGraphBuilder::GenerateIsConstructCall(CallRuntime* call) { |
6511 ASSERT(call->arguments()->length() == 0); | 6629 ASSERT(call->arguments()->length() == 0); |
6512 if (function_state()->outer() != NULL) { | 6630 if (function_state()->outer() != NULL) { |
6513 // We are generating graph for inlined function. Currently | 6631 // We are generating graph for inlined function. |
6514 // constructor inlining is not supported and we can just return | 6632 HValue* value = function_state()->is_construct() |
6515 // false from %_IsConstructCall(). | 6633 ? graph()->GetConstantTrue() |
6516 return ast_context()->ReturnValue(graph()->GetConstantFalse()); | 6634 : graph()->GetConstantFalse(); |
6635 return ast_context()->ReturnValue(value); | |
6517 } else { | 6636 } else { |
6518 return ast_context()->ReturnControl(new(zone()) HIsConstructCallAndBranch, | 6637 return ast_context()->ReturnControl(new(zone()) HIsConstructCallAndBranch, |
6519 call->id()); | 6638 call->id()); |
6520 } | 6639 } |
6521 } | 6640 } |
6522 | 6641 |
6523 | 6642 |
6524 // Support for arguments.length and arguments[?]. | 6643 // Support for arguments.length and arguments[?]. |
6525 void HGraphBuilder::GenerateArgumentsLength(CallRuntime* call) { | 6644 void HGraphBuilder::GenerateArgumentsLength(CallRuntime* call) { |
6526 // Our implementation of arguments (based on this stack frame or an | 6645 // Our implementation of arguments (based on this stack frame or an |
(...skipping 367 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
6894 #undef CHECK_BAILOUT | 7013 #undef CHECK_BAILOUT |
6895 #undef CHECK_ALIVE | 7014 #undef CHECK_ALIVE |
6896 | 7015 |
6897 | 7016 |
6898 HEnvironment::HEnvironment(HEnvironment* outer, | 7017 HEnvironment::HEnvironment(HEnvironment* outer, |
6899 Scope* scope, | 7018 Scope* scope, |
6900 Handle<JSFunction> closure) | 7019 Handle<JSFunction> closure) |
6901 : closure_(closure), | 7020 : closure_(closure), |
6902 values_(0), | 7021 values_(0), |
6903 assigned_variables_(4), | 7022 assigned_variables_(4), |
7023 frame_type_(JS_FUNCTION), | |
6904 parameter_count_(0), | 7024 parameter_count_(0), |
6905 specials_count_(1), | 7025 specials_count_(1), |
6906 local_count_(0), | 7026 local_count_(0), |
6907 outer_(outer), | 7027 outer_(outer), |
6908 pop_count_(0), | 7028 pop_count_(0), |
6909 push_count_(0), | 7029 push_count_(0), |
6910 ast_id_(AstNode::kNoNumber), | 7030 ast_id_(AstNode::kNoNumber) { |
6911 arguments_adaptor_(false) { | |
6912 Initialize(scope->num_parameters() + 1, scope->num_stack_slots(), 0); | 7031 Initialize(scope->num_parameters() + 1, scope->num_stack_slots(), 0); |
6913 } | 7032 } |
6914 | 7033 |
6915 | 7034 |
6916 HEnvironment::HEnvironment(const HEnvironment* other) | 7035 HEnvironment::HEnvironment(const HEnvironment* other) |
6917 : values_(0), | 7036 : values_(0), |
6918 assigned_variables_(0), | 7037 assigned_variables_(0), |
7038 frame_type_(JS_FUNCTION), | |
6919 parameter_count_(0), | 7039 parameter_count_(0), |
6920 specials_count_(1), | 7040 specials_count_(1), |
6921 local_count_(0), | 7041 local_count_(0), |
6922 outer_(NULL), | 7042 outer_(NULL), |
6923 pop_count_(0), | 7043 pop_count_(0), |
6924 push_count_(0), | 7044 push_count_(0), |
6925 ast_id_(other->ast_id()), | 7045 ast_id_(other->ast_id()) { |
6926 arguments_adaptor_(false) { | |
6927 Initialize(other); | 7046 Initialize(other); |
6928 } | 7047 } |
6929 | 7048 |
6930 | 7049 |
6931 HEnvironment::HEnvironment(HEnvironment* outer, | 7050 HEnvironment::HEnvironment(HEnvironment* outer, |
6932 Handle<JSFunction> closure, | 7051 Handle<JSFunction> closure, |
6933 int arguments) | 7052 int arguments) |
6934 : closure_(closure), | 7053 : closure_(closure), |
6935 values_(arguments), | 7054 values_(arguments), |
6936 assigned_variables_(0), | 7055 assigned_variables_(0), |
7056 frame_type_(ARGUMENTS_ADAPTOR), | |
6937 parameter_count_(arguments), | 7057 parameter_count_(arguments), |
6938 local_count_(0), | 7058 local_count_(0), |
6939 outer_(outer), | 7059 outer_(outer), |
6940 pop_count_(0), | 7060 pop_count_(0), |
6941 push_count_(0), | 7061 push_count_(0), |
6942 ast_id_(AstNode::kNoNumber), | 7062 ast_id_(AstNode::kNoNumber) { |
6943 arguments_adaptor_(true) { | |
6944 } | 7063 } |
6945 | 7064 |
6946 | 7065 |
7066 HEnvironment::HEnvironment(HEnvironment* outer, | |
7067 Handle<JSFunction> closure) | |
7068 : closure_(closure), | |
7069 values_(0), | |
7070 assigned_variables_(0), | |
7071 frame_type_(JS_CONSTRUCT), | |
7072 parameter_count_(0), | |
7073 local_count_(0), | |
7074 outer_(outer), | |
7075 pop_count_(0), | |
7076 push_count_(0), | |
7077 ast_id_(AstNode::kNoNumber) { | |
7078 } | |
7079 | |
7080 | |
6947 void HEnvironment::Initialize(int parameter_count, | 7081 void HEnvironment::Initialize(int parameter_count, |
6948 int local_count, | 7082 int local_count, |
6949 int stack_height) { | 7083 int stack_height) { |
6950 parameter_count_ = parameter_count; | 7084 parameter_count_ = parameter_count; |
6951 local_count_ = local_count; | 7085 local_count_ = local_count; |
6952 | 7086 |
6953 // Avoid reallocating the temporaries' backing store on the first Push. | 7087 // Avoid reallocating the temporaries' backing store on the first Push. |
6954 int total = parameter_count + specials_count_ + local_count + stack_height; | 7088 int total = parameter_count + specials_count_ + local_count + stack_height; |
6955 values_.Initialize(total + 4); | 7089 values_.Initialize(total + 4); |
6956 for (int i = 0; i < total; ++i) values_.Add(NULL); | 7090 for (int i = 0; i < total; ++i) values_.Add(NULL); |
6957 } | 7091 } |
6958 | 7092 |
6959 | 7093 |
6960 void HEnvironment::Initialize(const HEnvironment* other) { | 7094 void HEnvironment::Initialize(const HEnvironment* other) { |
6961 closure_ = other->closure(); | 7095 closure_ = other->closure(); |
6962 values_.AddAll(other->values_); | 7096 values_.AddAll(other->values_); |
6963 assigned_variables_.AddAll(other->assigned_variables_); | 7097 assigned_variables_.AddAll(other->assigned_variables_); |
7098 frame_type_ = other->frame_type_; | |
6964 parameter_count_ = other->parameter_count_; | 7099 parameter_count_ = other->parameter_count_; |
6965 local_count_ = other->local_count_; | 7100 local_count_ = other->local_count_; |
6966 if (other->outer_ != NULL) outer_ = other->outer_->Copy(); // Deep copy. | 7101 if (other->outer_ != NULL) outer_ = other->outer_->Copy(); // Deep copy. |
6967 pop_count_ = other->pop_count_; | 7102 pop_count_ = other->pop_count_; |
6968 push_count_ = other->push_count_; | 7103 push_count_ = other->push_count_; |
6969 ast_id_ = other->ast_id_; | 7104 ast_id_ = other->ast_id_; |
6970 arguments_adaptor_ = other->arguments_adaptor_; | |
6971 } | 7105 } |
6972 | 7106 |
6973 | 7107 |
6974 void HEnvironment::AddIncomingEdge(HBasicBlock* block, HEnvironment* other) { | 7108 void HEnvironment::AddIncomingEdge(HBasicBlock* block, HEnvironment* other) { |
6975 ASSERT(!block->IsLoopHeader()); | 7109 ASSERT(!block->IsLoopHeader()); |
6976 ASSERT(values_.length() == other->values_.length()); | 7110 ASSERT(values_.length() == other->values_.length()); |
6977 | 7111 |
6978 int length = values_.length(); | 7112 int length = values_.length(); |
6979 for (int i = 0; i < length; ++i) { | 7113 for (int i = 0; i < length; ++i) { |
6980 HValue* value = values_[i]; | 7114 HValue* value = values_[i]; |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
7067 new_env->ClearHistory(); | 7201 new_env->ClearHistory(); |
7068 return new_env; | 7202 return new_env; |
7069 } | 7203 } |
7070 | 7204 |
7071 | 7205 |
7072 HEnvironment* HEnvironment::CopyForInlining( | 7206 HEnvironment* HEnvironment::CopyForInlining( |
7073 Handle<JSFunction> target, | 7207 Handle<JSFunction> target, |
7074 int arguments, | 7208 int arguments, |
7075 FunctionLiteral* function, | 7209 FunctionLiteral* function, |
7076 HConstant* undefined, | 7210 HConstant* undefined, |
7077 CallKind call_kind) const { | 7211 CallKind call_kind, |
7078 ASSERT(!is_arguments_adaptor()); | 7212 bool is_construct) const { |
7213 ASSERT(frame_type() == JS_FUNCTION); | |
7079 | 7214 |
7080 Zone* zone = closure()->GetIsolate()->zone(); | 7215 Zone* zone = closure()->GetIsolate()->zone(); |
7081 | 7216 |
7082 // Outer environment is a copy of this one without the arguments. | 7217 // Outer environment is a copy of this one without the arguments. |
7083 int arity = function->scope()->num_parameters(); | 7218 int arity = function->scope()->num_parameters(); |
7084 | 7219 |
7085 HEnvironment* outer = Copy(); | 7220 HEnvironment* outer = Copy(); |
7086 outer->Drop(arguments + 1); // Including receiver. | 7221 outer->Drop(arguments + 1); // Including receiver. |
7087 outer->ClearHistory(); | 7222 outer->ClearHistory(); |
7088 | 7223 |
7224 if (is_construct) { | |
7225 // Create artificial constructor stub environment. The receiver should | |
7226 // actually be the constructor function, but we pass the newly allocated | |
7227 // object instead, DoComputeConstructStubFrame() relies on that. | |
7228 outer = new(zone) HEnvironment(outer, target); | |
7229 for (int i = 0; i <= arguments; ++i) { // Include receiver. | |
7230 outer->Push(ExpressionStackAt(arguments - i)); | |
7231 } | |
7232 outer->ClearHistory(); | |
7233 } | |
7234 | |
7089 if (arity != arguments) { | 7235 if (arity != arguments) { |
7090 // Create artificial arguments adaptation environment. | 7236 // Create artificial arguments adaptation environment. |
7091 outer = new(zone) HEnvironment(outer, target, arguments + 1); | 7237 outer = new(zone) HEnvironment(outer, target, arguments + 1); |
Vyacheslav Egorov (Chromium)
2012/02/13 15:01:39
I think HEnvironent constructor for the "artificia
Michael Starzinger
2012/02/27 14:16:32
Done.
| |
7092 for (int i = 0; i <= arguments; ++i) { // Include receiver. | 7238 for (int i = 0; i <= arguments; ++i) { // Include receiver. |
7093 outer->Push(ExpressionStackAt(arguments - i)); | 7239 outer->Push(ExpressionStackAt(arguments - i)); |
7094 } | 7240 } |
7095 outer->ClearHistory(); | 7241 outer->ClearHistory(); |
7096 } | 7242 } |
7097 | 7243 |
7098 HEnvironment* inner = | 7244 HEnvironment* inner = |
7099 new(zone) HEnvironment(outer, function->scope(), target); | 7245 new(zone) HEnvironment(outer, function->scope(), target); |
7100 // Get the argument values from the original environment. | 7246 // Get the argument values from the original environment. |
7101 for (int i = 0; i <= arity; ++i) { // Include receiver. | 7247 for (int i = 0; i <= arity; ++i) { // Include receiver. |
(...skipping 351 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
7453 } | 7599 } |
7454 } | 7600 } |
7455 | 7601 |
7456 #ifdef DEBUG | 7602 #ifdef DEBUG |
7457 if (graph_ != NULL) graph_->Verify(false); // No full verify. | 7603 if (graph_ != NULL) graph_->Verify(false); // No full verify. |
7458 if (allocator_ != NULL) allocator_->Verify(); | 7604 if (allocator_ != NULL) allocator_->Verify(); |
7459 #endif | 7605 #endif |
7460 } | 7606 } |
7461 | 7607 |
7462 } } // namespace v8::internal | 7608 } } // namespace v8::internal |
OLD | NEW |