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