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

Side by Side Diff: src/hydrogen.cc

Issue 6635012: Refactor inlined functions to avoid using subgraphs. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Created 9 years, 9 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
« no previous file with comments | « src/hydrogen.h ('k') | src/preparser.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2011 the V8 project authors. All rights reserved. 1 // Copyright 2011 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
(...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after
143 if (end->FirstSuccessor() != NULL) { 143 if (end->FirstSuccessor() != NULL) {
144 end->FirstSuccessor()->RegisterPredecessor(this); 144 end->FirstSuccessor()->RegisterPredecessor(this);
145 if (end->SecondSuccessor() != NULL) { 145 if (end->SecondSuccessor() != NULL) {
146 end->SecondSuccessor()->RegisterPredecessor(this); 146 end->SecondSuccessor()->RegisterPredecessor(this);
147 } 147 }
148 } 148 }
149 } 149 }
150 150
151 151
152 void HBasicBlock::Goto(HBasicBlock* block, bool include_stack_check) { 152 void HBasicBlock::Goto(HBasicBlock* block, bool include_stack_check) {
153 if (block->IsInlineReturnTarget()) {
154 AddInstruction(new HLeaveInlined);
155 last_environment_ = last_environment()->outer();
156 }
153 AddSimulate(AstNode::kNoNumber); 157 AddSimulate(AstNode::kNoNumber);
154 HGoto* instr = new HGoto(block); 158 HGoto* instr = new HGoto(block);
155 instr->set_include_stack_check(include_stack_check); 159 instr->set_include_stack_check(include_stack_check);
156 Finish(instr); 160 Finish(instr);
157 } 161 }
158 162
159 163
164 void HBasicBlock::AddLeaveInlined(HValue* return_value, HBasicBlock* target) {
165 ASSERT(target->IsInlineReturnTarget());
166 ASSERT(return_value != NULL);
167 AddInstruction(new HLeaveInlined);
168 last_environment_ = last_environment()->outer();
169 last_environment()->Push(return_value);
170 AddSimulate(AstNode::kNoNumber);
171 HGoto* instr = new HGoto(target);
172 Finish(instr);
173 }
174
175
160 void HBasicBlock::SetInitialEnvironment(HEnvironment* env) { 176 void HBasicBlock::SetInitialEnvironment(HEnvironment* env) {
161 ASSERT(!HasEnvironment()); 177 ASSERT(!HasEnvironment());
162 ASSERT(first() == NULL); 178 ASSERT(first() == NULL);
163 UpdateEnvironment(env); 179 UpdateEnvironment(env);
164 } 180 }
165 181
166 182
167 void HBasicBlock::SetJoinId(int id) { 183 void HBasicBlock::SetJoinId(int id) {
168 int length = predecessors_.length(); 184 int length = predecessors_.length();
169 ASSERT(length > 0); 185 ASSERT(length > 0);
(...skipping 1802 matching lines...) Expand 10 before | Expand all | Expand 10 after
1972 // We expect the graph to be in edge-split form: there is no edge that 1988 // We expect the graph to be in edge-split form: there is no edge that
1973 // connects a branch node to a join node. We conservatively ensure that 1989 // connects a branch node to a join node. We conservatively ensure that
1974 // property by always adding an empty block on the outgoing edges of this 1990 // property by always adding an empty block on the outgoing edges of this
1975 // branch. 1991 // branch.
1976 HGraphBuilder* builder = owner(); 1992 HGraphBuilder* builder = owner();
1977 HBasicBlock* empty_true = builder->graph()->CreateBasicBlock(); 1993 HBasicBlock* empty_true = builder->graph()->CreateBasicBlock();
1978 HBasicBlock* empty_false = builder->graph()->CreateBasicBlock(); 1994 HBasicBlock* empty_false = builder->graph()->CreateBasicBlock();
1979 HTest* test = new HTest(value, empty_true, empty_false); 1995 HTest* test = new HTest(value, empty_true, empty_false);
1980 builder->current_block()->Finish(test); 1996 builder->current_block()->Finish(test);
1981 1997
1982 HValue* const no_return_value = NULL; 1998 empty_true->Goto(if_true(), false);
1983 HBasicBlock* true_target = if_true(); 1999 empty_false->Goto(if_false(), false);
1984 if (true_target->IsInlineReturnTarget()) {
1985 empty_true->AddLeaveInlined(no_return_value, true_target);
1986 } else {
1987 empty_true->Goto(true_target);
1988 }
1989
1990 HBasicBlock* false_target = if_false();
1991 if (false_target->IsInlineReturnTarget()) {
1992 empty_false->AddLeaveInlined(no_return_value, false_target);
1993 } else {
1994 empty_false->Goto(false_target);
1995 }
1996 builder->set_current_block(NULL); 2000 builder->set_current_block(NULL);
1997 } 2001 }
1998 2002
1999 2003
2000 // HGraphBuilder infrastructure for bailing out and checking bailouts. 2004 // HGraphBuilder infrastructure for bailing out and checking bailouts.
2001 #define BAILOUT(reason) \ 2005 #define BAILOUT(reason) \
2002 do { \ 2006 do { \
2003 Bailout(reason); \ 2007 Bailout(reason); \
2004 return; \ 2008 return; \
2005 } while (false) 2009 } while (false)
(...skipping 295 matching lines...) Expand 10 before | Expand all | Expand 10 after
2301 } 2305 }
2302 2306
2303 2307
2304 HBasicBlock* HGraphBuilder::CreateBasicBlock(HEnvironment* env) { 2308 HBasicBlock* HGraphBuilder::CreateBasicBlock(HEnvironment* env) {
2305 HBasicBlock* b = graph()->CreateBasicBlock(); 2309 HBasicBlock* b = graph()->CreateBasicBlock();
2306 b->SetInitialEnvironment(env); 2310 b->SetInitialEnvironment(env);
2307 return b; 2311 return b;
2308 } 2312 }
2309 2313
2310 2314
2311 HSubgraph* HGraphBuilder::CreateInlinedSubgraph(HEnvironment* outer,
2312 Handle<JSFunction> target,
2313 FunctionLiteral* function) {
2314 HConstant* undefined = graph()->GetConstantUndefined();
2315 HEnvironment* inner =
2316 outer->CopyForInlining(target, function, true, undefined);
2317 HSubgraph* subgraph = new HSubgraph(graph());
2318 subgraph->Initialize(CreateBasicBlock(inner));
2319 return subgraph;
2320 }
2321
2322
2323 HSubgraph* HGraphBuilder::CreateEmptySubgraph() { 2315 HSubgraph* HGraphBuilder::CreateEmptySubgraph() {
2324 HSubgraph* subgraph = new HSubgraph(graph()); 2316 HSubgraph* subgraph = new HSubgraph(graph());
2325 subgraph->Initialize(graph()->CreateBasicBlock()); 2317 subgraph->Initialize(graph()->CreateBasicBlock());
2326 return subgraph; 2318 return subgraph;
2327 } 2319 }
2328 2320
2329 2321
2330 HSubgraph* HGraphBuilder::CreateBranchSubgraph(HEnvironment* env) {
2331 HSubgraph* subgraph = new HSubgraph(graph());
2332 HEnvironment* new_env = env->Copy();
2333 subgraph->Initialize(CreateBasicBlock(new_env));
2334 return subgraph;
2335 }
2336
2337
2338 HBasicBlock* HGraphBuilder::CreateLoopHeaderBlock() { 2322 HBasicBlock* HGraphBuilder::CreateLoopHeaderBlock() {
2339 HBasicBlock* header = graph()->CreateBasicBlock(); 2323 HBasicBlock* header = graph()->CreateBasicBlock();
2340 HEnvironment* entry_env = environment()->CopyAsLoopHeader(header); 2324 HEnvironment* entry_env = environment()->CopyAsLoopHeader(header);
2341 header->SetInitialEnvironment(entry_env); 2325 header->SetInitialEnvironment(entry_env);
2342 header->AttachLoopInformation(); 2326 header->AttachLoopInformation();
2343 return header; 2327 return header;
2344 } 2328 }
2345 2329
2346 2330
2347 void HGraphBuilder::VisitBlock(Block* stmt) { 2331 void HGraphBuilder::VisitBlock(Block* stmt) {
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after
2451 current_block()->FinishExit(new HReturn(result)); 2435 current_block()->FinishExit(new HReturn(result));
2452 set_current_block(NULL); 2436 set_current_block(NULL);
2453 } else { 2437 } else {
2454 // Return from an inlined function, visit the subexpression in the 2438 // Return from an inlined function, visit the subexpression in the
2455 // expression context of the call. 2439 // expression context of the call.
2456 if (context->IsTest()) { 2440 if (context->IsTest()) {
2457 TestContext* test = TestContext::cast(context); 2441 TestContext* test = TestContext::cast(context);
2458 VisitForControl(stmt->expression(), 2442 VisitForControl(stmt->expression(),
2459 test->if_true(), 2443 test->if_true(),
2460 test->if_false()); 2444 test->if_false());
2445 } else if (context->IsEffect()) {
2446 VISIT_FOR_EFFECT(stmt->expression());
2447 current_block()->Goto(function_return(), false);
2461 } else { 2448 } else {
2462 HValue* return_value = NULL; 2449 ASSERT(context->IsValue());
2463 if (context->IsEffect()) { 2450 VISIT_FOR_VALUE(stmt->expression());
2464 VISIT_FOR_EFFECT(stmt->expression()); 2451 HValue* return_value = environment()->Pop();
2465 return_value = graph()->GetConstantUndefined(); 2452 current_block()->AddLeaveInlined(return_value, function_return());
2466 } else {
2467 ASSERT(context->IsValue());
2468 VISIT_FOR_VALUE(stmt->expression());
2469 return_value = environment()->Pop();
2470 }
2471 current_block()->AddLeaveInlined(return_value,
2472 function_return());
2473 set_current_block(NULL);
2474 } 2453 }
2454 set_current_block(NULL);
2475 } 2455 }
2476 } 2456 }
2477 2457
2478 2458
2479 void HGraphBuilder::VisitWithEnterStatement(WithEnterStatement* stmt) { 2459 void HGraphBuilder::VisitWithEnterStatement(WithEnterStatement* stmt) {
2480 BAILOUT("WithEnterStatement"); 2460 BAILOUT("WithEnterStatement");
2481 } 2461 }
2482 2462
2483 2463
2484 void HGraphBuilder::VisitWithExitStatement(WithExitStatement* stmt) { 2464 void HGraphBuilder::VisitWithExitStatement(WithExitStatement* stmt) {
(...skipping 557 matching lines...) Expand 10 before | Expand all | Expand 10 after
3042 } 3022 }
3043 ast_context()->ReturnValue(Pop()); 3023 ast_context()->ReturnValue(Pop());
3044 } 3024 }
3045 3025
3046 3026
3047 void HGraphBuilder::VisitCatchExtensionObject(CatchExtensionObject* expr) { 3027 void HGraphBuilder::VisitCatchExtensionObject(CatchExtensionObject* expr) {
3048 BAILOUT("CatchExtensionObject"); 3028 BAILOUT("CatchExtensionObject");
3049 } 3029 }
3050 3030
3051 3031
3052 HBasicBlock* HGraphBuilder::BuildTypeSwitch(HValue* receiver,
3053 ZoneMapList* maps,
3054 ZoneList<HSubgraph*>* body_graphs,
3055 HSubgraph* default_graph,
3056 int join_id) {
3057 ASSERT(maps->length() == body_graphs->length());
3058 HBasicBlock* join_block = graph()->CreateBasicBlock();
3059 AddInstruction(new HCheckNonSmi(receiver));
3060
3061 for (int i = 0; i < maps->length(); ++i) {
3062 // Build the branches, connect all the target subgraphs to the join
3063 // block. Use the default as a target of the last branch.
3064 HSubgraph* if_true = body_graphs->at(i);
3065 HSubgraph* if_false = (i == maps->length() - 1)
3066 ? default_graph
3067 : CreateBranchSubgraph(environment());
3068 HCompareMap* compare =
3069 new HCompareMap(receiver,
3070 maps->at(i),
3071 if_true->entry_block(),
3072 if_false->entry_block());
3073 current_block()->Finish(compare);
3074
3075 if (if_true->exit_block() != NULL) {
3076 // In an effect context the value of the type switch is not needed.
3077 // There is no need to merge it at the join block only to discard it.
3078 if (ast_context()->IsEffect()) {
3079 if_true->exit_block()->last_environment()->Drop(1);
3080 }
3081 if_true->exit_block()->Goto(join_block);
3082 }
3083
3084 set_current_block(if_false->exit_block());
3085 }
3086
3087 // Connect the default if necessary.
3088 if (current_block() != NULL) {
3089 if (ast_context()->IsEffect()) {
3090 environment()->Drop(1);
3091 }
3092 current_block()->Goto(join_block);
3093 }
3094
3095 if (join_block->predecessors()->is_empty()) return NULL;
3096 join_block->SetJoinId(join_id);
3097 return join_block;
3098 }
3099
3100
3101 // Sets the lookup result and returns true if the store can be inlined. 3032 // Sets the lookup result and returns true if the store can be inlined.
3102 static bool ComputeStoredField(Handle<Map> type, 3033 static bool ComputeStoredField(Handle<Map> type,
3103 Handle<String> name, 3034 Handle<String> name,
3104 LookupResult* lookup) { 3035 LookupResult* lookup) {
3105 type->LookupInDescriptors(NULL, *name, lookup); 3036 type->LookupInDescriptors(NULL, *name, lookup);
3106 if (!lookup->IsPropertyOrTransition()) return false; 3037 if (!lookup->IsPropertyOrTransition()) return false;
3107 if (lookup->type() == FIELD) return true; 3038 if (lookup->type() == FIELD) return true;
3108 return (lookup->type() == MAP_TRANSITION) && 3039 return (lookup->type() == MAP_TRANSITION) &&
3109 (type->unused_property_fields() > 0); 3040 (type->unused_property_fields() > 0);
3110 } 3041 }
(...skipping 767 matching lines...) Expand 10 before | Expand all | Expand 10 after
3878 Handle<JSObject>(JSObject::cast(receiver_map->prototype())), 3809 Handle<JSObject>(JSObject::cast(receiver_map->prototype())),
3879 expr->holder())); 3810 expr->holder()));
3880 } 3811 }
3881 } 3812 }
3882 3813
3883 3814
3884 void HGraphBuilder::HandlePolymorphicCallNamed(Call* expr, 3815 void HGraphBuilder::HandlePolymorphicCallNamed(Call* expr,
3885 HValue* receiver, 3816 HValue* receiver,
3886 ZoneMapList* types, 3817 ZoneMapList* types,
3887 Handle<String> name) { 3818 Handle<String> name) {
3888 int argument_count = expr->arguments()->length() + 1; // Plus receiver.
3889 int number_of_types = Min(types->length(), kMaxCallPolymorphism);
3890 ZoneMapList maps(number_of_types);
3891 ZoneList<HSubgraph*> subgraphs(number_of_types);
3892 bool needs_generic = (types->length() > kMaxCallPolymorphism);
3893
3894 // Build subgraphs for each of the specific maps.
3895 //
3896 // TODO(ager): We should recognize when the prototype chains for different 3819 // TODO(ager): We should recognize when the prototype chains for different
3897 // maps are identical. In that case we can avoid repeatedly generating the 3820 // maps are identical. In that case we can avoid repeatedly generating the
3898 // same prototype map checks. 3821 // same prototype map checks.
3899 for (int i = 0; i < number_of_types; ++i) { 3822 int argument_count = expr->arguments()->length() + 1; // Includes receiver.
3823 int count = 0;
3824 HBasicBlock* join = NULL;
3825 for (int i = 0; i < types->length() && count < kMaxCallPolymorphism; ++i) {
3900 Handle<Map> map = types->at(i); 3826 Handle<Map> map = types->at(i);
3901 if (expr->ComputeTarget(map, name)) { 3827 if (expr->ComputeTarget(map, name)) {
3902 HSubgraph* subgraph = CreateBranchSubgraph(environment()); 3828 if (count == 0) {
3903 SubgraphScope scope(this, subgraph); 3829 AddInstruction(new HCheckNonSmi(receiver)); // Only needed once.
3830 join = graph()->CreateBasicBlock();
3831 }
3832 ++count;
3833 HBasicBlock* if_true = graph()->CreateBasicBlock();
3834 HBasicBlock* if_false = graph()->CreateBasicBlock();
3835 HCompareMap* compare = new HCompareMap(receiver, map, if_true, if_false);
3836 current_block()->Finish(compare);
3837
3838 set_current_block(if_true);
3904 AddCheckConstantFunction(expr, receiver, map, false); 3839 AddCheckConstantFunction(expr, receiver, map, false);
3905 if (FLAG_trace_inlining && FLAG_polymorphic_inlining) { 3840 if (FLAG_trace_inlining && FLAG_polymorphic_inlining) {
3906 PrintF("Trying to inline the polymorphic call to %s\n", 3841 PrintF("Trying to inline the polymorphic call to %s\n",
3907 *name->ToCString()); 3842 *name->ToCString());
3908 } 3843 }
3909 if (!FLAG_polymorphic_inlining || !TryInline(expr)) { 3844 if (!FLAG_polymorphic_inlining || !TryInline(expr)) {
3910 // Check for bailout, as trying to inline might fail due to bailout 3845 // Check for bailout, as trying to inline might fail due to bailout
3911 // during hydrogen processing. 3846 // during hydrogen processing.
3912 CHECK_BAILOUT; 3847 CHECK_BAILOUT;
3913 HCallConstantFunction* call = 3848 HCallConstantFunction* call =
3914 new HCallConstantFunction(expr->target(), argument_count); 3849 new HCallConstantFunction(expr->target(), argument_count);
3915 call->set_position(expr->position()); 3850 call->set_position(expr->position());
3916 PreProcessCall(call); 3851 PreProcessCall(call);
3917 PushAndAdd(call); 3852 AddInstruction(call);
3853 if (!ast_context()->IsEffect()) Push(call);
3918 } 3854 }
3919 maps.Add(map); 3855
3920 subgraphs.Add(subgraph); 3856 if (current_block() != NULL) current_block()->Goto(join);
3921 } else { 3857 set_current_block(if_false);
3922 needs_generic = true;
3923 } 3858 }
3924 } 3859 }
3925 3860
3926 // If we couldn't compute the target for any of the maps just perform an 3861 // Finish up. Unconditionally deoptimize if we've handled all the maps we
3927 // IC call. 3862 // know about and do not want to handle ones we've never seen. Otherwise
3928 if (maps.length() == 0) { 3863 // use a generic IC.
3864 if (count == types->length() && FLAG_deoptimize_uncommon_cases) {
3865 current_block()->FinishExit(new HDeoptimize);
3866 } else {
3929 HContext* context = new HContext; 3867 HContext* context = new HContext;
3930 AddInstruction(context); 3868 AddInstruction(context);
3931 HCallNamed* call = new HCallNamed(context, name, argument_count); 3869 HCallNamed* call = new HCallNamed(context, name, argument_count);
3932 call->set_position(expr->position()); 3870 call->set_position(expr->position());
3933 PreProcessCall(call); 3871 PreProcessCall(call);
3934 ast_context()->ReturnInstruction(call, expr->id()); 3872
3935 } else { 3873 if (join != NULL) {
3936 // Build subgraph for generic call through IC. 3874 AddInstruction(call);
3937 HSubgraph* default_graph = CreateBranchSubgraph(environment()); 3875 if (!ast_context()->IsEffect()) Push(call);
3938 { SubgraphScope scope(this, default_graph); 3876 current_block()->Goto(join);
3939 if (!needs_generic && FLAG_deoptimize_uncommon_cases) { 3877 } else {
3940 default_graph->exit_block()->FinishExit(new HDeoptimize()); 3878 ast_context()->ReturnInstruction(call, expr->id());
3941 default_graph->set_exit_block(NULL); 3879 return;
3942 } else {
3943 HContext* context = new HContext;
3944 AddInstruction(context);
3945 HCallNamed* call = new HCallNamed(context, name, argument_count);
3946 call->set_position(expr->position());
3947 PreProcessCall(call);
3948 PushAndAdd(call);
3949 }
3950 } 3880 }
3881 }
3951 3882
3952 HBasicBlock* new_exit_block = 3883 // We assume that control flow is always live after an expression. So
3953 BuildTypeSwitch(receiver, &maps, &subgraphs, default_graph, expr->id()); 3884 // even without predecessors to the join block, we set it as the exit
3954 set_current_block(new_exit_block); 3885 // block and continue by adding instructions there.
3955 // In an effect context, we did not materialized the value in the 3886 ASSERT(join != NULL);
3956 // predecessor environments so there's no need to handle it here. 3887 set_current_block(join);
3957 if (new_exit_block != NULL && !ast_context()->IsEffect()) { 3888 if (join->HasPredecessor()) {
3958 ast_context()->ReturnValue(Pop()); 3889 join->SetJoinId(expr->id());
3959 } 3890 if (!ast_context()->IsEffect()) ast_context()->ReturnValue(Pop());
3960 } 3891 }
3961 } 3892 }
3962 3893
3963 3894
3964 void HGraphBuilder::TraceInline(Handle<JSFunction> target, const char* reason) { 3895 void HGraphBuilder::TraceInline(Handle<JSFunction> target, const char* reason) {
3965 if (FLAG_trace_inlining) { 3896 if (FLAG_trace_inlining) {
3966 SmartPointer<char> callee = target->shared()->DebugName()->ToCString(); 3897 SmartPointer<char> callee = target->shared()->DebugName()->ToCString();
3967 SmartPointer<char> caller = 3898 SmartPointer<char> caller =
3968 info()->function()->debug_name()->ToCString(); 3899 info()->function()->debug_name()->ToCString();
3969 if (reason == NULL) { 3900 if (reason == NULL) {
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after
4096 4027
4097 // ---------------------------------------------------------------- 4028 // ----------------------------------------------------------------
4098 // Save the pending call context and type feedback oracle. Set up new ones 4029 // Save the pending call context and type feedback oracle. Set up new ones
4099 // for the inlined function. 4030 // for the inlined function.
4100 ASSERT(target_shared->has_deoptimization_support()); 4031 ASSERT(target_shared->has_deoptimization_support());
4101 TypeFeedbackOracle target_oracle( 4032 TypeFeedbackOracle target_oracle(
4102 Handle<Code>(target_shared->code()), 4033 Handle<Code>(target_shared->code()),
4103 Handle<Context>(target->context()->global_context())); 4034 Handle<Context>(target->context()->global_context()));
4104 FunctionState target_state(this, &target_info, &target_oracle); 4035 FunctionState target_state(this, &target_info, &target_oracle);
4105 4036
4106 HSubgraph* body = CreateInlinedSubgraph(env, target, function); 4037 HConstant* undefined = graph()->GetConstantUndefined();
4107 body->exit_block()->AddInstruction(new HEnterInlined(target, function)); 4038 HEnvironment* inner_env =
4108 AddToSubgraph(body, function->body()); 4039 environment()->CopyForInlining(target, function, true, undefined);
4040 HBasicBlock* body_entry = CreateBasicBlock(inner_env);
4041 current_block()->Goto(body_entry);
4042
4043 body_entry->SetJoinId(expr->ReturnId());
4044 set_current_block(body_entry);
4045 AddInstruction(new HEnterInlined(target, function));
4046 VisitStatements(function->body());
4109 if (HasStackOverflow()) { 4047 if (HasStackOverflow()) {
4110 // Bail out if the inline function did, as we cannot residualize a call 4048 // Bail out if the inline function did, as we cannot residualize a call
4111 // instead. 4049 // instead.
4112 TraceInline(target, "inline graph construction failed"); 4050 TraceInline(target, "inline graph construction failed");
4113 return false; 4051 return false;
4114 } 4052 }
4115 4053
4116 // Update inlined nodes count. 4054 // Update inlined nodes count.
4117 inlined_count_ += nodes_added; 4055 inlined_count_ += nodes_added;
4118 4056
4119 TraceInline(target, NULL); 4057 TraceInline(target, NULL);
4120 4058
4121 if (body->exit_block() != NULL) { 4059 if (current_block() != NULL) {
4122 // Add a return of undefined if control can fall off the body. In a 4060 // Add a return of undefined if control can fall off the body. In a
4123 // test context, undefined is false. 4061 // test context, undefined is false.
4124 HValue* return_value = graph()->GetConstantUndefined();
4125 if (inlined_test_context() == NULL) { 4062 if (inlined_test_context() == NULL) {
4126 ASSERT(function_return() != NULL); 4063 ASSERT(function_return() != NULL);
4127 body->exit_block()->AddLeaveInlined(return_value, function_return()); 4064 ASSERT(call_context()->IsEffect() || call_context()->IsValue());
4065 if (call_context()->IsEffect()) {
4066 current_block()->Goto(function_return(), false);
4067 } else {
4068 current_block()->AddLeaveInlined(undefined, function_return());
4069 }
4128 } else { 4070 } else {
4129 // The graph builder assumes control can reach both branches of a 4071 // The graph builder assumes control can reach both branches of a
4130 // test, so we materialize the undefined value and test it rather than 4072 // test, so we materialize the undefined value and test it rather than
4131 // simply jumping to the false target. 4073 // simply jumping to the false target.
4132 // 4074 //
4133 // TODO(3168478): refactor to avoid this. 4075 // TODO(3168478): refactor to avoid this.
4134 HBasicBlock* empty_true = graph()->CreateBasicBlock(); 4076 HBasicBlock* empty_true = graph()->CreateBasicBlock();
4135 HBasicBlock* empty_false = graph()->CreateBasicBlock(); 4077 HBasicBlock* empty_false = graph()->CreateBasicBlock();
4136 HTest* test = new HTest(return_value, empty_true, empty_false); 4078 HTest* test = new HTest(undefined, empty_true, empty_false);
4137 body->exit_block()->Finish(test); 4079 current_block()->Finish(test);
4138 4080
4139 HValue* const no_return_value = NULL; 4081 empty_true->Goto(inlined_test_context()->if_true(), false);
4140 empty_true->AddLeaveInlined(no_return_value, 4082 empty_false->Goto(inlined_test_context()->if_false(), false);
4141 inlined_test_context()->if_true());
4142 empty_false->AddLeaveInlined(no_return_value,
4143 inlined_test_context()->if_false());
4144 } 4083 }
4145 body->set_exit_block(NULL);
4146 } 4084 }
4147 4085
4148 // Record the environment at the inlined function call.
4149 AddSimulate(expr->ReturnId());
4150
4151 // Jump to the function entry (without re-recording the environment).
4152 current_block()->Finish(new HGoto(body->entry_block()));
4153
4154 // Fix up the function exits. 4086 // Fix up the function exits.
4155 if (inlined_test_context() != NULL) { 4087 if (inlined_test_context() != NULL) {
4156 HBasicBlock* if_true = inlined_test_context()->if_true(); 4088 HBasicBlock* if_true = inlined_test_context()->if_true();
4157 HBasicBlock* if_false = inlined_test_context()->if_false(); 4089 HBasicBlock* if_false = inlined_test_context()->if_false();
4158 if_true->SetJoinId(expr->id()); 4090 if_true->SetJoinId(expr->id());
4159 if_false->SetJoinId(expr->id()); 4091 if_false->SetJoinId(expr->id());
4160 ASSERT(ast_context() == inlined_test_context()); 4092 ASSERT(ast_context() == inlined_test_context());
4161 // Pop the return test context from the expression context stack. 4093 // Pop the return test context from the expression context stack.
4162 ClearInlinedTestContext(); 4094 ClearInlinedTestContext();
4163 4095
4164 // Forward to the real test context. 4096 // Forward to the real test context.
4165 HValue* const no_return_value = NULL;
4166 HBasicBlock* true_target = TestContext::cast(ast_context())->if_true(); 4097 HBasicBlock* true_target = TestContext::cast(ast_context())->if_true();
4167 if (true_target->IsInlineReturnTarget()) {
4168 if_true->AddLeaveInlined(no_return_value, true_target);
4169 } else {
4170 if_true->Goto(true_target);
4171 }
4172
4173 HBasicBlock* false_target = TestContext::cast(ast_context())->if_false(); 4098 HBasicBlock* false_target = TestContext::cast(ast_context())->if_false();
4174 if (false_target->IsInlineReturnTarget()) { 4099 if_true->Goto(true_target, false);
4175 if_false->AddLeaveInlined(no_return_value, false_target); 4100 if_false->Goto(false_target, false);
4176 } else {
4177 if_false->Goto(false_target);
4178 }
4179 4101
4180 // TODO(kmillikin): Come up with a better way to handle this. It is too 4102 // TODO(kmillikin): Come up with a better way to handle this. It is too
4181 // subtle. NULL here indicates that the enclosing context has no control 4103 // subtle. NULL here indicates that the enclosing context has no control
4182 // flow to handle. 4104 // flow to handle.
4183 set_current_block(NULL); 4105 set_current_block(NULL);
4184 4106
4185 } else { 4107 } else {
4186 function_return()->SetJoinId(expr->id()); 4108 function_return()->SetJoinId(expr->id());
4187 set_current_block(function_return()); 4109 set_current_block(function_return());
4188 } 4110 }
4189 4111
4190 return true; 4112 return true;
4191 } 4113 }
4192 4114
4193 4115
4194 void HBasicBlock::AddLeaveInlined(HValue* return_value, HBasicBlock* target) {
4195 ASSERT(target->IsInlineReturnTarget());
4196 AddInstruction(new HLeaveInlined);
4197 HEnvironment* outer = last_environment()->outer();
4198 if (return_value != NULL) outer->Push(return_value);
4199 UpdateEnvironment(outer);
4200 Goto(target);
4201 }
4202
4203
4204 bool HGraphBuilder::TryInlineBuiltinFunction(Call* expr, 4116 bool HGraphBuilder::TryInlineBuiltinFunction(Call* expr,
4205 HValue* receiver, 4117 HValue* receiver,
4206 Handle<Map> receiver_map, 4118 Handle<Map> receiver_map,
4207 CheckType check_type) { 4119 CheckType check_type) {
4208 ASSERT(check_type != RECEIVER_MAP_CHECK || !receiver_map.is_null()); 4120 ASSERT(check_type != RECEIVER_MAP_CHECK || !receiver_map.is_null());
4209 // Try to inline calls like Math.* as operations in the calling function. 4121 // Try to inline calls like Math.* as operations in the calling function.
4210 if (!expr->target()->shared()->HasBuiltinFunctionId()) return false; 4122 if (!expr->target()->shared()->HasBuiltinFunctionId()) return false;
4211 BuiltinFunctionId id = expr->target()->shared()->builtin_function_id(); 4123 BuiltinFunctionId id = expr->target()->shared()->builtin_function_id();
4212 int argument_count = expr->arguments()->length() + 1; // Plus receiver. 4124 int argument_count = expr->arguments()->length() + 1; // Plus receiver.
4213 switch (id) { 4125 switch (id) {
(...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after
4400 // When the target has a custom call IC generator, use the IC, 4312 // When the target has a custom call IC generator, use the IC,
4401 // because it is likely to generate better code. Also use the 4313 // because it is likely to generate better code. Also use the
4402 // IC when a primitive receiver check is required. 4314 // IC when a primitive receiver check is required.
4403 HContext* context = new HContext; 4315 HContext* context = new HContext;
4404 AddInstruction(context); 4316 AddInstruction(context);
4405 call = PreProcessCall(new HCallNamed(context, name, argument_count)); 4317 call = PreProcessCall(new HCallNamed(context, name, argument_count));
4406 } else { 4318 } else {
4407 AddCheckConstantFunction(expr, receiver, receiver_map, true); 4319 AddCheckConstantFunction(expr, receiver, receiver_map, true);
4408 4320
4409 if (TryInline(expr)) { 4321 if (TryInline(expr)) {
4410 if (current_block() != NULL) {
4411 HValue* return_value = Pop();
4412 // If we inlined a function in a test context then we need to emit
4413 // a simulate here to shadow the ones at the end of the
4414 // predecessor blocks. Those environments contain the return
4415 // value on top and do not correspond to any actual state of the
4416 // unoptimized code.
4417 if (ast_context()->IsEffect()) AddSimulate(expr->id());
4418 ast_context()->ReturnValue(return_value);
4419 }
4420 return; 4322 return;
4421 } else { 4323 } else {
4422 // Check for bailout, as the TryInline call in the if condition above 4324 // Check for bailout, as the TryInline call in the if condition above
4423 // might return false due to bailout during hydrogen processing. 4325 // might return false due to bailout during hydrogen processing.
4424 CHECK_BAILOUT; 4326 CHECK_BAILOUT;
4425 call = PreProcessCall(new HCallConstantFunction(expr->target(), 4327 call = PreProcessCall(new HCallConstantFunction(expr->target(),
4426 argument_count)); 4328 argument_count));
4427 } 4329 }
4428 } 4330 }
4429 } else if (types != NULL && types->length() > 1) { 4331 } else if (types != NULL && types->length() > 1) {
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
4473 // Replace the global object with the global receiver. 4375 // Replace the global object with the global receiver.
4474 HGlobalReceiver* global_receiver = new HGlobalReceiver(global_object); 4376 HGlobalReceiver* global_receiver = new HGlobalReceiver(global_object);
4475 // Index of the receiver from the top of the expression stack. 4377 // Index of the receiver from the top of the expression stack.
4476 const int receiver_index = argument_count - 1; 4378 const int receiver_index = argument_count - 1;
4477 AddInstruction(global_receiver); 4379 AddInstruction(global_receiver);
4478 ASSERT(environment()->ExpressionStackAt(receiver_index)-> 4380 ASSERT(environment()->ExpressionStackAt(receiver_index)->
4479 IsGlobalObject()); 4381 IsGlobalObject());
4480 environment()->SetExpressionStackAt(receiver_index, global_receiver); 4382 environment()->SetExpressionStackAt(receiver_index, global_receiver);
4481 4383
4482 if (TryInline(expr)) { 4384 if (TryInline(expr)) {
4483 if (current_block() != NULL) {
4484 HValue* return_value = Pop();
4485 // If we inlined a function in a test context then we need to
4486 // emit a simulate here to shadow the ones at the end of the
4487 // predecessor blocks. Those environments contain the return
4488 // value on top and do not correspond to any actual state of the
4489 // unoptimized code.
4490 if (ast_context()->IsEffect()) AddSimulate(expr->id());
4491 ast_context()->ReturnValue(return_value);
4492 }
4493 return; 4385 return;
4494 } 4386 }
4495 // Check for bailout, as trying to inline might fail due to bailout 4387 // Check for bailout, as trying to inline might fail due to bailout
4496 // during hydrogen processing. 4388 // during hydrogen processing.
4497 CHECK_BAILOUT; 4389 CHECK_BAILOUT;
4498 4390
4499 call = PreProcessCall(new HCallKnownGlobal(expr->target(), 4391 call = PreProcessCall(new HCallKnownGlobal(expr->target(),
4500 argument_count)); 4392 argument_count));
4501 } else { 4393 } else {
4502 HContext* context = new HContext; 4394 HContext* context = new HContext;
(...skipping 1544 matching lines...) Expand 10 before | Expand all | Expand 10 after
6047 } 5939 }
6048 } 5940 }
6049 5941
6050 #ifdef DEBUG 5942 #ifdef DEBUG
6051 if (graph_ != NULL) graph_->Verify(); 5943 if (graph_ != NULL) graph_->Verify();
6052 if (allocator_ != NULL) allocator_->Verify(); 5944 if (allocator_ != NULL) allocator_->Verify();
6053 #endif 5945 #endif
6054 } 5946 }
6055 5947
6056 } } // namespace v8::internal 5948 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/hydrogen.h ('k') | src/preparser.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698