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 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
159 ASSERT(!IsFinished()); | 159 ASSERT(!IsFinished()); |
160 AddInstruction(end); | 160 AddInstruction(end); |
161 end_ = end; | 161 end_ = end; |
162 for (HSuccessorIterator it(end); !it.Done(); it.Advance()) { | 162 for (HSuccessorIterator it(end); !it.Done(); it.Advance()) { |
163 it.Current()->RegisterPredecessor(this); | 163 it.Current()->RegisterPredecessor(this); |
164 } | 164 } |
165 } | 165 } |
166 | 166 |
167 | 167 |
168 void HBasicBlock::Goto(HBasicBlock* block, FunctionState* state) { | 168 void HBasicBlock::Goto(HBasicBlock* block, FunctionState* state) { |
169 bool drop_extra = state != NULL && state->drop_extra(); | 169 bool drop_extra = state != NULL && |
170 state->inlining_kind() == DROP_EXTRA_ON_RETURN; | |
170 bool arguments_pushed = state != NULL && state->arguments_pushed(); | 171 bool arguments_pushed = state != NULL && state->arguments_pushed(); |
171 | 172 |
172 if (block->IsInlineReturnTarget()) { | 173 if (block->IsInlineReturnTarget()) { |
173 AddInstruction(new(zone()) HLeaveInlined(arguments_pushed)); | 174 AddInstruction(new(zone()) HLeaveInlined(arguments_pushed)); |
174 last_environment_ = last_environment()->DiscardInlined(drop_extra); | 175 last_environment_ = last_environment()->DiscardInlined(drop_extra); |
175 } | 176 } |
176 | 177 |
177 AddSimulate(BailoutId::None()); | 178 AddSimulate(BailoutId::None()); |
178 HGoto* instr = new(zone()) HGoto(block); | 179 HGoto* instr = new(zone()) HGoto(block); |
179 Finish(instr); | 180 Finish(instr); |
180 } | 181 } |
181 | 182 |
182 | 183 |
183 void HBasicBlock::AddLeaveInlined(HValue* return_value, | 184 void HBasicBlock::AddLeaveInlined(HValue* return_value, |
184 HBasicBlock* target, | |
185 FunctionState* state) { | 185 FunctionState* state) { |
186 bool drop_extra = state != NULL && state->drop_extra(); | 186 HBasicBlock* target = state->function_return(); |
187 bool arguments_pushed = state != NULL && state->arguments_pushed(); | 187 bool drop_extra = state->inlining_kind() == DROP_EXTRA_ON_RETURN; |
188 bool arguments_pushed = state->arguments_pushed(); | |
188 | 189 |
189 ASSERT(target->IsInlineReturnTarget()); | 190 ASSERT(target->IsInlineReturnTarget()); |
190 ASSERT(return_value != NULL); | 191 ASSERT(return_value != NULL); |
191 AddInstruction(new(zone()) HLeaveInlined(arguments_pushed)); | 192 AddInstruction(new(zone()) HLeaveInlined(arguments_pushed)); |
192 last_environment_ = last_environment()->DiscardInlined(drop_extra); | 193 last_environment_ = last_environment()->DiscardInlined(drop_extra); |
193 last_environment()->Push(return_value); | 194 last_environment()->Push(return_value); |
194 AddSimulate(BailoutId::None()); | 195 AddSimulate(BailoutId::None()); |
195 HGoto* instr = new(zone()) HGoto(target); | 196 HGoto* instr = new(zone()) HGoto(target); |
196 Finish(instr); | 197 Finish(instr); |
197 } | 198 } |
(...skipping 2546 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2744 } | 2745 } |
2745 } | 2746 } |
2746 } | 2747 } |
2747 | 2748 |
2748 | 2749 |
2749 // Implementation of utility class to encapsulate the translation state for | 2750 // Implementation of utility class to encapsulate the translation state for |
2750 // a (possibly inlined) function. | 2751 // a (possibly inlined) function. |
2751 FunctionState::FunctionState(HGraphBuilder* owner, | 2752 FunctionState::FunctionState(HGraphBuilder* owner, |
2752 CompilationInfo* info, | 2753 CompilationInfo* info, |
2753 TypeFeedbackOracle* oracle, | 2754 TypeFeedbackOracle* oracle, |
2754 ReturnHandlingFlag return_handling) | 2755 InliningKind inlining_kind) |
2755 : owner_(owner), | 2756 : owner_(owner), |
2756 compilation_info_(info), | 2757 compilation_info_(info), |
2757 oracle_(oracle), | 2758 oracle_(oracle), |
2758 call_context_(NULL), | 2759 call_context_(NULL), |
2759 return_handling_(return_handling), | 2760 inlining_kind_(inlining_kind), |
2760 function_return_(NULL), | 2761 function_return_(NULL), |
2761 test_context_(NULL), | 2762 test_context_(NULL), |
2762 entry_(NULL), | 2763 entry_(NULL), |
2763 arguments_elements_(NULL), | 2764 arguments_elements_(NULL), |
2764 outer_(owner->function_state()) { | 2765 outer_(owner->function_state()) { |
2765 if (outer_ != NULL) { | 2766 if (outer_ != NULL) { |
2766 // State for an inline function. | 2767 // State for an inline function. |
2767 if (owner->ast_context()->IsTest()) { | 2768 if (owner->ast_context()->IsTest()) { |
2768 HBasicBlock* if_true = owner->graph()->CreateBasicBlock(); | 2769 HBasicBlock* if_true = owner->graph()->CreateBasicBlock(); |
2769 HBasicBlock* if_false = owner->graph()->CreateBasicBlock(); | 2770 HBasicBlock* if_false = owner->graph()->CreateBasicBlock(); |
(...skipping 1054 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3824 Drop(drop_extra); | 3825 Drop(drop_extra); |
3825 current_block()->Goto(break_block); | 3826 current_block()->Goto(break_block); |
3826 set_current_block(NULL); | 3827 set_current_block(NULL); |
3827 } | 3828 } |
3828 | 3829 |
3829 | 3830 |
3830 void HGraphBuilder::VisitReturnStatement(ReturnStatement* stmt) { | 3831 void HGraphBuilder::VisitReturnStatement(ReturnStatement* stmt) { |
3831 ASSERT(!HasStackOverflow()); | 3832 ASSERT(!HasStackOverflow()); |
3832 ASSERT(current_block() != NULL); | 3833 ASSERT(current_block() != NULL); |
3833 ASSERT(current_block()->HasPredecessor()); | 3834 ASSERT(current_block()->HasPredecessor()); |
3835 FunctionState* state = function_state(); | |
3834 AstContext* context = call_context(); | 3836 AstContext* context = call_context(); |
3835 if (context == NULL) { | 3837 if (context == NULL) { |
3836 // Not an inlined return, so an actual one. | 3838 // Not an inlined return, so an actual one. |
3837 CHECK_ALIVE(VisitForValue(stmt->expression())); | 3839 CHECK_ALIVE(VisitForValue(stmt->expression())); |
3838 HValue* result = environment()->Pop(); | 3840 HValue* result = environment()->Pop(); |
3839 current_block()->FinishExit(new(zone()) HReturn(result)); | 3841 current_block()->FinishExit(new(zone()) HReturn(result)); |
3840 } else if (function_state()->is_construct()) { | 3842 } else if (state->inlining_kind() == CONSTRUCT_CALL_RETURN) { |
3841 // Return from an inlined construct call. In a test context the return | 3843 // Return from an inlined construct call. In a test context the return value |
3842 // value will always evaluate to true, in a value context the return value | 3844 // will always evaluate to true, in a value context the return value needs |
3843 // needs to be a JSObject. | 3845 // to be a JSObject. |
3844 if (context->IsTest()) { | 3846 if (context->IsTest()) { |
3845 TestContext* test = TestContext::cast(context); | 3847 TestContext* test = TestContext::cast(context); |
3846 CHECK_ALIVE(VisitForEffect(stmt->expression())); | 3848 CHECK_ALIVE(VisitForEffect(stmt->expression())); |
3847 current_block()->Goto(test->if_true(), function_state()); | 3849 current_block()->Goto(test->if_true(), state); |
3848 } else if (context->IsEffect()) { | 3850 } else if (context->IsEffect()) { |
3849 CHECK_ALIVE(VisitForEffect(stmt->expression())); | 3851 CHECK_ALIVE(VisitForEffect(stmt->expression())); |
3850 current_block()->Goto(function_return(), function_state()); | 3852 current_block()->Goto(function_return(), state); |
3851 } else { | 3853 } else { |
3852 ASSERT(context->IsValue()); | 3854 ASSERT(context->IsValue()); |
3853 CHECK_ALIVE(VisitForValue(stmt->expression())); | 3855 CHECK_ALIVE(VisitForValue(stmt->expression())); |
3854 HValue* return_value = Pop(); | 3856 HValue* return_value = Pop(); |
3855 HValue* receiver = environment()->Lookup(0); | 3857 HValue* receiver = environment()->arguments_environment()->Lookup(0); |
3856 HHasInstanceTypeAndBranch* typecheck = | 3858 HHasInstanceTypeAndBranch* typecheck = |
3857 new(zone()) HHasInstanceTypeAndBranch(return_value, | 3859 new(zone()) HHasInstanceTypeAndBranch(return_value, |
3858 FIRST_SPEC_OBJECT_TYPE, | 3860 FIRST_SPEC_OBJECT_TYPE, |
3859 LAST_SPEC_OBJECT_TYPE); | 3861 LAST_SPEC_OBJECT_TYPE); |
3860 HBasicBlock* if_spec_object = graph()->CreateBasicBlock(); | 3862 HBasicBlock* if_spec_object = graph()->CreateBasicBlock(); |
3861 HBasicBlock* not_spec_object = graph()->CreateBasicBlock(); | 3863 HBasicBlock* not_spec_object = graph()->CreateBasicBlock(); |
3862 typecheck->SetSuccessorAt(0, if_spec_object); | 3864 typecheck->SetSuccessorAt(0, if_spec_object); |
3863 typecheck->SetSuccessorAt(1, not_spec_object); | 3865 typecheck->SetSuccessorAt(1, not_spec_object); |
3864 current_block()->Finish(typecheck); | 3866 current_block()->Finish(typecheck); |
3865 if_spec_object->AddLeaveInlined(return_value, | 3867 if_spec_object->AddLeaveInlined(return_value, state); |
3866 function_return(), | 3868 not_spec_object->AddLeaveInlined(receiver, state); |
3867 function_state()); | 3869 } |
3868 not_spec_object->AddLeaveInlined(receiver, | 3870 } else if (state->inlining_kind() == SETTER_CALL_RETURN) { |
3869 function_return(), | 3871 // Return from an inlined setter call. The returned value is never used, the |
3870 function_state()); | 3872 // value of an assignment is always the value of the RHS of the assignment. |
3873 CHECK_ALIVE(VisitForEffect(stmt->expression())); | |
3874 if (context->IsTest()) { | |
3875 HValue* rhs = environment()->arguments_environment()->Lookup(1); | |
3876 context->ReturnValue(rhs); | |
3877 } else if (context->IsEffect()) { | |
3878 current_block()->Goto(function_return(), state); | |
3879 } else { | |
3880 ASSERT(context->IsValue()); | |
3881 HValue* rhs = environment()->arguments_environment()->Lookup(1); | |
3882 current_block()->AddLeaveInlined(rhs, state); | |
3871 } | 3883 } |
3872 } else { | 3884 } else { |
3873 // Return from an inlined function, visit the subexpression in the | 3885 // Return from a normal inlined function. Visit the subexpression in the |
3874 // expression context of the call. | 3886 // expression context of the call. |
3875 if (context->IsTest()) { | 3887 if (context->IsTest()) { |
3876 TestContext* test = TestContext::cast(context); | 3888 TestContext* test = TestContext::cast(context); |
3877 VisitForControl(stmt->expression(), | 3889 VisitForControl(stmt->expression(), test->if_true(), test->if_false()); |
3878 test->if_true(), | |
3879 test->if_false()); | |
3880 } else if (context->IsEffect()) { | 3890 } else if (context->IsEffect()) { |
3881 CHECK_ALIVE(VisitForEffect(stmt->expression())); | 3891 CHECK_ALIVE(VisitForEffect(stmt->expression())); |
3882 current_block()->Goto(function_return(), function_state()); | 3892 current_block()->Goto(function_return(), state); |
3883 } else { | 3893 } else { |
3884 ASSERT(context->IsValue()); | 3894 ASSERT(context->IsValue()); |
3885 CHECK_ALIVE(VisitForValue(stmt->expression())); | 3895 CHECK_ALIVE(VisitForValue(stmt->expression())); |
3886 HValue* return_value = Pop(); | 3896 current_block()->AddLeaveInlined(Pop(), state); |
3887 current_block()->AddLeaveInlined(return_value, | |
3888 function_return(), | |
3889 function_state()); | |
3890 } | 3897 } |
3891 } | 3898 } |
3892 set_current_block(NULL); | 3899 set_current_block(NULL); |
3893 } | 3900 } |
3894 | 3901 |
3895 | 3902 |
3896 void HGraphBuilder::VisitWithStatement(WithStatement* stmt) { | 3903 void HGraphBuilder::VisitWithStatement(WithStatement* stmt) { |
3897 ASSERT(!HasStackOverflow()); | 3904 ASSERT(!HasStackOverflow()); |
3898 ASSERT(current_block() != NULL); | 3905 ASSERT(current_block() != NULL); |
3899 ASSERT(current_block()->HasPredecessor()); | 3906 ASSERT(current_block()->HasPredecessor()); |
(...skipping 1326 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
5226 bool monomorphic = expr->IsMonomorphic(); | 5233 bool monomorphic = expr->IsMonomorphic(); |
5227 Handle<Map> map; | 5234 Handle<Map> map; |
5228 if (monomorphic) { | 5235 if (monomorphic) { |
5229 map = types->first(); | 5236 map = types->first(); |
5230 if (map->is_dictionary_map()) monomorphic = false; | 5237 if (map->is_dictionary_map()) monomorphic = false; |
5231 } | 5238 } |
5232 if (monomorphic) { | 5239 if (monomorphic) { |
5233 Handle<AccessorPair> accessors; | 5240 Handle<AccessorPair> accessors; |
5234 Handle<JSObject> holder; | 5241 Handle<JSObject> holder; |
5235 if (LookupAccessorPair(map, name, &accessors, &holder)) { | 5242 if (LookupAccessorPair(map, name, &accessors, &holder)) { |
5243 Handle<JSFunction> setter(JSFunction::cast(accessors->setter())); | |
5244 AddCheckConstantFunction(holder, object, map, true); | |
5245 if (FLAG_inline_accessors && TryInlineSetter(setter, expr, value)) { | |
5246 return; | |
5247 } | |
5236 Drop(2); | 5248 Drop(2); |
Michael Starzinger
2012/08/10 08:52:15
It seems dropping the arguments after doing HChcec
| |
5237 instr = BuildCallSetter(object, value, map, accessors, holder); | 5249 AddInstruction(new(zone()) HPushArgument(object)); |
5250 AddInstruction(new(zone()) HPushArgument(value)); | |
5251 instr = new(zone()) HCallConstantFunction(setter, 2); | |
5238 } else { | 5252 } else { |
5239 Drop(2); | 5253 Drop(2); |
5240 CHECK_ALIVE(instr = BuildStoreNamedMonomorphic(object, | 5254 CHECK_ALIVE(instr = BuildStoreNamedMonomorphic(object, |
5241 name, | 5255 name, |
5242 value, | 5256 value, |
5243 map)); | 5257 map)); |
5244 } | 5258 } |
5245 | 5259 |
5246 } else if (types != NULL && types->length() > 1) { | 5260 } else if (types != NULL && types->length() > 1) { |
5247 Drop(2); | 5261 Drop(2); |
(...skipping 1378 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
6626 } | 6640 } |
6627 | 6641 |
6628 int nodes_added = target_shared->ast_node_count(); | 6642 int nodes_added = target_shared->ast_node_count(); |
6629 return nodes_added; | 6643 return nodes_added; |
6630 } | 6644 } |
6631 | 6645 |
6632 | 6646 |
6633 bool HGraphBuilder::TryInline(CallKind call_kind, | 6647 bool HGraphBuilder::TryInline(CallKind call_kind, |
6634 Handle<JSFunction> target, | 6648 Handle<JSFunction> target, |
6635 int arguments_count, | 6649 int arguments_count, |
6636 HValue* receiver, | 6650 HValue* implicit_return_value, |
6637 BailoutId ast_id, | 6651 BailoutId ast_id, |
6638 BailoutId return_id, | 6652 BailoutId return_id, |
6639 ReturnHandlingFlag return_handling) { | 6653 InliningKind inlining_kind) { |
6640 int nodes_added = InliningAstSize(target); | 6654 int nodes_added = InliningAstSize(target); |
6641 if (nodes_added == kNotInlinable) return false; | 6655 if (nodes_added == kNotInlinable) return false; |
6642 | 6656 |
6643 Handle<JSFunction> caller = info()->closure(); | 6657 Handle<JSFunction> caller = info()->closure(); |
6644 | 6658 |
6645 if (nodes_added > Min(FLAG_max_inlined_nodes, kUnlimitedMaxInlinedNodes)) { | 6659 if (nodes_added > Min(FLAG_max_inlined_nodes, kUnlimitedMaxInlinedNodes)) { |
6646 TraceInline(target, caller, "target AST is too large [early]"); | 6660 TraceInline(target, caller, "target AST is too large [early]"); |
6647 return false; | 6661 return false; |
6648 } | 6662 } |
6649 | 6663 |
(...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
6782 // for the inlined function. | 6796 // for the inlined function. |
6783 ASSERT(target_shared->has_deoptimization_support()); | 6797 ASSERT(target_shared->has_deoptimization_support()); |
6784 TypeFeedbackOracle target_oracle( | 6798 TypeFeedbackOracle target_oracle( |
6785 Handle<Code>(target_shared->code()), | 6799 Handle<Code>(target_shared->code()), |
6786 Handle<Context>(target->context()->global_context()), | 6800 Handle<Context>(target->context()->global_context()), |
6787 isolate(), | 6801 isolate(), |
6788 zone()); | 6802 zone()); |
6789 // The function state is new-allocated because we need to delete it | 6803 // The function state is new-allocated because we need to delete it |
6790 // in two different places. | 6804 // in two different places. |
6791 FunctionState* target_state = new FunctionState( | 6805 FunctionState* target_state = new FunctionState( |
6792 this, &target_info, &target_oracle, return_handling); | 6806 this, &target_info, &target_oracle, inlining_kind); |
6793 | 6807 |
6794 HConstant* undefined = graph()->GetConstantUndefined(); | 6808 HConstant* undefined = graph()->GetConstantUndefined(); |
6795 HEnvironment* inner_env = | 6809 HEnvironment* inner_env = |
6796 environment()->CopyForInlining(target, | 6810 environment()->CopyForInlining(target, |
6797 arguments_count, | 6811 arguments_count, |
6798 function, | 6812 function, |
6799 undefined, | 6813 undefined, |
6800 call_kind, | 6814 call_kind, |
6801 function_state()->is_construct()); | 6815 function_state()->inlining_kind()); |
6802 #ifdef V8_TARGET_ARCH_IA32 | 6816 #ifdef V8_TARGET_ARCH_IA32 |
6803 // IA32 only, overwrite the caller's context in the deoptimization | 6817 // IA32 only, overwrite the caller's context in the deoptimization |
6804 // environment with the correct one. | 6818 // environment with the correct one. |
6805 // | 6819 // |
6806 // TODO(kmillikin): implement the same inlining on other platforms so we | 6820 // TODO(kmillikin): implement the same inlining on other platforms so we |
6807 // can remove the unsightly ifdefs in this function. | 6821 // can remove the unsightly ifdefs in this function. |
6808 HConstant* context = | 6822 HConstant* context = |
6809 new(zone()) HConstant(Handle<Context>(target->context()), | 6823 new(zone()) HConstant(Handle<Context>(target->context()), |
6810 Representation::Tagged()); | 6824 Representation::Tagged()); |
6811 AddInstruction(context); | 6825 AddInstruction(context); |
(...skipping 14 matching lines...) Expand all Loading... | |
6826 for (int i = 0; i < arguments_count; i++) { | 6840 for (int i = 0; i < arguments_count; i++) { |
6827 arguments_values->Add(arguments_env->Lookup(i), zone()); | 6841 arguments_values->Add(arguments_env->Lookup(i), zone()); |
6828 } | 6842 } |
6829 } | 6843 } |
6830 | 6844 |
6831 HEnterInlined* enter_inlined = | 6845 HEnterInlined* enter_inlined = |
6832 new(zone()) HEnterInlined(target, | 6846 new(zone()) HEnterInlined(target, |
6833 arguments_count, | 6847 arguments_count, |
6834 function, | 6848 function, |
6835 call_kind, | 6849 call_kind, |
6836 function_state()->is_construct(), | 6850 function_state()->inlining_kind(), |
6837 function->scope()->arguments(), | 6851 function->scope()->arguments(), |
6838 arguments_values); | 6852 arguments_values); |
6839 function_state()->set_entry(enter_inlined); | 6853 function_state()->set_entry(enter_inlined); |
6840 AddInstruction(enter_inlined); | 6854 AddInstruction(enter_inlined); |
6841 | 6855 |
6842 // If the function uses arguments object create and bind one. | 6856 // If the function uses arguments object create and bind one. |
6843 if (function->scope()->arguments() != NULL) { | 6857 if (function->scope()->arguments() != NULL) { |
6844 ASSERT(function->scope()->arguments()->IsStackAllocated()); | 6858 ASSERT(function->scope()->arguments()->IsStackAllocated()); |
6845 inner_env->Bind(function->scope()->arguments(), | 6859 inner_env->Bind(function->scope()->arguments(), |
6846 graph()->GetArgumentsObject()); | 6860 graph()->GetArgumentsObject()); |
(...skipping 11 matching lines...) Expand all Loading... | |
6858 delete target_state; | 6872 delete target_state; |
6859 return true; | 6873 return true; |
6860 } | 6874 } |
6861 | 6875 |
6862 // Update inlined nodes count. | 6876 // Update inlined nodes count. |
6863 inlined_count_ += nodes_added; | 6877 inlined_count_ += nodes_added; |
6864 | 6878 |
6865 TraceInline(target, caller, NULL); | 6879 TraceInline(target, caller, NULL); |
6866 | 6880 |
6867 if (current_block() != NULL) { | 6881 if (current_block() != NULL) { |
6868 // Add default return value (i.e. undefined for normals calls or the newly | 6882 FunctionState* state = function_state(); |
6869 // allocated receiver for construct calls) if control can fall off the | 6883 if (state->inlining_kind() == CONSTRUCT_CALL_RETURN) { |
6870 // body. In a test context, undefined is false and any JSObject is true. | 6884 // Falling off the end of an inlined construct call. In a test context the |
6871 if (call_context()->IsValue()) { | 6885 // return value will always evaluate to true, in a value context the |
6872 ASSERT(function_return() != NULL); | 6886 // return value is the newly allocated receiver. |
6873 HValue* return_value = function_state()->is_construct() | 6887 if (call_context()->IsTest()) { |
6874 ? receiver | 6888 current_block()->Goto(inlined_test_context()->if_true(), state); |
6875 : undefined; | 6889 } else if (call_context()->IsEffect()) { |
6876 current_block()->AddLeaveInlined(return_value, | 6890 current_block()->Goto(function_return(), state); |
6877 function_return(), | 6891 } else { |
6878 function_state()); | 6892 ASSERT(call_context()->IsValue()); |
6879 } else if (call_context()->IsEffect()) { | 6893 current_block()->AddLeaveInlined(implicit_return_value, state); |
6880 ASSERT(function_return() != NULL); | 6894 } |
6881 current_block()->Goto(function_return(), function_state()); | 6895 } else if (state->inlining_kind() == SETTER_CALL_RETURN) { |
6896 // Falling off the end of an inlined setter call. The returned value is | |
6897 // never used, the value of an assignment is always the value of the RHS | |
6898 // of the assignment. | |
6899 if (call_context()->IsTest()) { | |
6900 inlined_test_context()->ReturnValue(implicit_return_value); | |
6901 } else if (call_context()->IsEffect()) { | |
6902 current_block()->Goto(function_return(), state); | |
6903 } else { | |
6904 ASSERT(call_context()->IsValue()); | |
6905 current_block()->AddLeaveInlined(implicit_return_value, state); | |
6906 } | |
6882 } else { | 6907 } else { |
6883 ASSERT(call_context()->IsTest()); | 6908 // Falling off the end of a normal inlined function. This basically means |
6884 ASSERT(inlined_test_context() != NULL); | 6909 // returning undefined. |
6885 HBasicBlock* target = function_state()->is_construct() | 6910 if (call_context()->IsTest()) { |
6886 ? inlined_test_context()->if_true() | 6911 current_block()->Goto(inlined_test_context()->if_false(), state); |
6887 : inlined_test_context()->if_false(); | 6912 } else if (call_context()->IsEffect()) { |
6888 current_block()->Goto(target, function_state()); | 6913 current_block()->Goto(function_return(), state); |
6914 } else { | |
6915 ASSERT(call_context()->IsValue()); | |
6916 current_block()->AddLeaveInlined(undefined, state); | |
6917 } | |
6889 } | 6918 } |
6890 } | 6919 } |
6891 | 6920 |
6892 // Fix up the function exits. | 6921 // Fix up the function exits. |
6893 if (inlined_test_context() != NULL) { | 6922 if (inlined_test_context() != NULL) { |
6894 HBasicBlock* if_true = inlined_test_context()->if_true(); | 6923 HBasicBlock* if_true = inlined_test_context()->if_true(); |
6895 HBasicBlock* if_false = inlined_test_context()->if_false(); | 6924 HBasicBlock* if_false = inlined_test_context()->if_false(); |
6896 | 6925 |
6897 // Pop the return test context from the expression context stack. | 6926 // Pop the return test context from the expression context stack. |
6898 ASSERT(ast_context() == inlined_test_context()); | 6927 ASSERT(ast_context() == inlined_test_context()); |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
6934 return TryInline(call_kind, | 6963 return TryInline(call_kind, |
6935 expr->target(), | 6964 expr->target(), |
6936 expr->arguments()->length(), | 6965 expr->arguments()->length(), |
6937 NULL, | 6966 NULL, |
6938 expr->id(), | 6967 expr->id(), |
6939 expr->ReturnId(), | 6968 expr->ReturnId(), |
6940 drop_extra ? DROP_EXTRA_ON_RETURN : NORMAL_RETURN); | 6969 drop_extra ? DROP_EXTRA_ON_RETURN : NORMAL_RETURN); |
6941 } | 6970 } |
6942 | 6971 |
6943 | 6972 |
6944 bool HGraphBuilder::TryInlineConstruct(CallNew* expr, HValue* receiver) { | 6973 bool HGraphBuilder::TryInlineConstruct(CallNew* expr, |
6974 HValue* implicit_return_value) { | |
6945 return TryInline(CALL_AS_FUNCTION, | 6975 return TryInline(CALL_AS_FUNCTION, |
6946 expr->target(), | 6976 expr->target(), |
6947 expr->arguments()->length(), | 6977 expr->arguments()->length(), |
6948 receiver, | 6978 implicit_return_value, |
6949 expr->id(), | 6979 expr->id(), |
6950 expr->ReturnId(), | 6980 expr->ReturnId(), |
6951 CONSTRUCT_CALL_RETURN); | 6981 CONSTRUCT_CALL_RETURN); |
6952 } | 6982 } |
6953 | 6983 |
6954 | 6984 |
6955 bool HGraphBuilder::TryInlineGetter(Handle<JSFunction> getter, | 6985 bool HGraphBuilder::TryInlineGetter(Handle<JSFunction> getter, |
6956 Property* prop) { | 6986 Property* prop) { |
6957 return TryInline(CALL_AS_METHOD, | 6987 return TryInline(CALL_AS_METHOD, |
6958 getter, | 6988 getter, |
6959 0, | 6989 0, |
6960 NULL, | 6990 NULL, |
6961 prop->id(), | 6991 prop->id(), |
6962 prop->LoadId(), | 6992 prop->LoadId(), |
6963 NORMAL_RETURN); | 6993 NORMAL_RETURN); |
6964 } | 6994 } |
6965 | 6995 |
6966 | 6996 |
6997 bool HGraphBuilder::TryInlineSetter(Handle<JSFunction> setter, | |
6998 Assignment* assignment, | |
6999 HValue* implicit_return_value) { | |
7000 return TryInline(CALL_AS_METHOD, | |
7001 setter, | |
7002 1, | |
7003 implicit_return_value, | |
7004 assignment->id(), | |
7005 assignment->AssignmentId(), | |
7006 SETTER_CALL_RETURN); | |
7007 } | |
7008 | |
7009 | |
6967 bool HGraphBuilder::TryInlineBuiltinFunctionCall(Call* expr, bool drop_extra) { | 7010 bool HGraphBuilder::TryInlineBuiltinFunctionCall(Call* expr, bool drop_extra) { |
6968 if (!expr->target()->shared()->HasBuiltinFunctionId()) return false; | 7011 if (!expr->target()->shared()->HasBuiltinFunctionId()) return false; |
6969 BuiltinFunctionId id = expr->target()->shared()->builtin_function_id(); | 7012 BuiltinFunctionId id = expr->target()->shared()->builtin_function_id(); |
6970 switch (id) { | 7013 switch (id) { |
6971 case kMathRound: | 7014 case kMathRound: |
6972 case kMathAbs: | 7015 case kMathAbs: |
6973 case kMathSqrt: | 7016 case kMathSqrt: |
6974 case kMathLog: | 7017 case kMathLog: |
6975 case kMathSin: | 7018 case kMathSin: |
6976 case kMathCos: | 7019 case kMathCos: |
(...skipping 1663 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
8640 return Bailout( | 8683 return Bailout( |
8641 "inlined runtime function: IsStringWrapperSafeForDefaultValueOf"); | 8684 "inlined runtime function: IsStringWrapperSafeForDefaultValueOf"); |
8642 } | 8685 } |
8643 | 8686 |
8644 | 8687 |
8645 // Support for construct call checks. | 8688 // Support for construct call checks. |
8646 void HGraphBuilder::GenerateIsConstructCall(CallRuntime* call) { | 8689 void HGraphBuilder::GenerateIsConstructCall(CallRuntime* call) { |
8647 ASSERT(call->arguments()->length() == 0); | 8690 ASSERT(call->arguments()->length() == 0); |
8648 if (function_state()->outer() != NULL) { | 8691 if (function_state()->outer() != NULL) { |
8649 // We are generating graph for inlined function. | 8692 // We are generating graph for inlined function. |
8650 HValue* value = function_state()->is_construct() | 8693 HValue* value = function_state()->inlining_kind() == CONSTRUCT_CALL_RETURN |
8651 ? graph()->GetConstantTrue() | 8694 ? graph()->GetConstantTrue() |
8652 : graph()->GetConstantFalse(); | 8695 : graph()->GetConstantFalse(); |
8653 return ast_context()->ReturnValue(value); | 8696 return ast_context()->ReturnValue(value); |
8654 } else { | 8697 } else { |
8655 return ast_context()->ReturnControl(new(zone()) HIsConstructCallAndBranch, | 8698 return ast_context()->ReturnControl(new(zone()) HIsConstructCallAndBranch, |
8656 call->id()); | 8699 call->id()); |
8657 } | 8700 } |
8658 } | 8701 } |
8659 | 8702 |
8660 | 8703 |
(...skipping 569 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
9230 return new_env; | 9273 return new_env; |
9231 } | 9274 } |
9232 | 9275 |
9233 | 9276 |
9234 HEnvironment* HEnvironment::CopyForInlining( | 9277 HEnvironment* HEnvironment::CopyForInlining( |
9235 Handle<JSFunction> target, | 9278 Handle<JSFunction> target, |
9236 int arguments, | 9279 int arguments, |
9237 FunctionLiteral* function, | 9280 FunctionLiteral* function, |
9238 HConstant* undefined, | 9281 HConstant* undefined, |
9239 CallKind call_kind, | 9282 CallKind call_kind, |
9240 bool is_construct) const { | 9283 InliningKind inlining_kind) const { |
9241 ASSERT(frame_type() == JS_FUNCTION); | 9284 ASSERT(frame_type() == JS_FUNCTION); |
9242 | 9285 |
9243 // Outer environment is a copy of this one without the arguments. | 9286 // Outer environment is a copy of this one without the arguments. |
9244 int arity = function->scope()->num_parameters(); | 9287 int arity = function->scope()->num_parameters(); |
9245 | 9288 |
9246 HEnvironment* outer = Copy(); | 9289 HEnvironment* outer = Copy(); |
9247 outer->Drop(arguments + 1); // Including receiver. | 9290 outer->Drop(arguments + 1); // Including receiver. |
9248 outer->ClearHistory(); | 9291 outer->ClearHistory(); |
9249 | 9292 |
9250 if (is_construct) { | 9293 if (inlining_kind == CONSTRUCT_CALL_RETURN) { |
9251 // Create artificial constructor stub environment. The receiver should | 9294 // Create artificial constructor stub environment. The receiver should |
9252 // actually be the constructor function, but we pass the newly allocated | 9295 // actually be the constructor function, but we pass the newly allocated |
9253 // object instead, DoComputeConstructStubFrame() relies on that. | 9296 // object instead, DoComputeConstructStubFrame() relies on that. |
9254 outer = CreateStubEnvironment(outer, target, JS_CONSTRUCT, arguments); | 9297 outer = CreateStubEnvironment(outer, target, JS_CONSTRUCT, arguments); |
9298 } else if (inlining_kind == SETTER_CALL_RETURN) { | |
9299 outer = CreateStubEnvironment(outer, target, JS_SETTER, arguments); | |
Michael Starzinger
2012/08/10 08:52:15
Can we add a comment specifying which stub is simu
| |
9255 } | 9300 } |
9256 | 9301 |
9257 if (arity != arguments) { | 9302 if (arity != arguments) { |
9258 // Create artificial arguments adaptation environment. | 9303 // Create artificial arguments adaptation environment. |
9259 outer = CreateStubEnvironment(outer, target, ARGUMENTS_ADAPTOR, arguments); | 9304 outer = CreateStubEnvironment(outer, target, ARGUMENTS_ADAPTOR, arguments); |
9260 } | 9305 } |
9261 | 9306 |
9262 HEnvironment* inner = | 9307 HEnvironment* inner = |
9263 new(zone()) HEnvironment(outer, function->scope(), target, zone()); | 9308 new(zone()) HEnvironment(outer, function->scope(), target, zone()); |
9264 // Get the argument values from the original environment. | 9309 // Get the argument values from the original environment. |
9265 for (int i = 0; i <= arity; ++i) { // Include receiver. | 9310 for (int i = 0; i <= arity; ++i) { // Include receiver. |
9266 HValue* push = (i <= arguments) ? | 9311 HValue* push = (i <= arguments) ? |
9267 ExpressionStackAt(arguments - i) : undefined; | 9312 ExpressionStackAt(arguments - i) : undefined; |
9268 inner->SetValueAt(i, push); | 9313 inner->SetValueAt(i, push); |
9269 } | 9314 } |
9270 // If the function we are inlining is a strict mode function or a | 9315 // If the function we are inlining is a strict mode function or a |
9271 // builtin function, pass undefined as the receiver for function | 9316 // builtin function, pass undefined as the receiver for function |
9272 // calls (instead of the global receiver). | 9317 // calls (instead of the global receiver). |
9273 if ((target->shared()->native() || !function->is_classic_mode()) && | 9318 if ((target->shared()->native() || !function->is_classic_mode()) && |
9274 call_kind == CALL_AS_FUNCTION && !is_construct) { | 9319 call_kind == CALL_AS_FUNCTION && inlining_kind != CONSTRUCT_CALL_RETURN) { |
9275 inner->SetValueAt(0, undefined); | 9320 inner->SetValueAt(0, undefined); |
9276 } | 9321 } |
9277 inner->SetValueAt(arity + 1, LookupContext()); | 9322 inner->SetValueAt(arity + 1, LookupContext()); |
9278 for (int i = arity + 2; i < inner->length(); ++i) { | 9323 for (int i = arity + 2; i < inner->length(); ++i) { |
9279 inner->SetValueAt(i, undefined); | 9324 inner->SetValueAt(i, undefined); |
9280 } | 9325 } |
9281 | 9326 |
9282 inner->set_ast_id(BailoutId::FunctionEntry()); | 9327 inner->set_ast_id(BailoutId::FunctionEntry()); |
9283 return inner; | 9328 return inner; |
9284 } | 9329 } |
(...skipping 341 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
9626 } | 9671 } |
9627 } | 9672 } |
9628 | 9673 |
9629 #ifdef DEBUG | 9674 #ifdef DEBUG |
9630 if (graph_ != NULL) graph_->Verify(false); // No full verify. | 9675 if (graph_ != NULL) graph_->Verify(false); // No full verify. |
9631 if (allocator_ != NULL) allocator_->Verify(); | 9676 if (allocator_ != NULL) allocator_->Verify(); |
9632 #endif | 9677 #endif |
9633 } | 9678 } |
9634 | 9679 |
9635 } } // namespace v8::internal | 9680 } } // namespace v8::internal |
OLD | NEW |