Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(337)

Side by Side Diff: src/hydrogen.cc

Issue 10836133: Inline simple setter calls. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Incorporated most review comments of round one. Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
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
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
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
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
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
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698