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

Side by Side Diff: src/crankshaft/hydrogen.cc

Issue 1782743003: [crankshaft] Support inlining of function calls in tail position (in ES6 sense). (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@tco-crank-4
Patch Set: ppc, s390 and x87 ports Created 4 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
« no previous file with comments | « src/crankshaft/hydrogen.h ('k') | src/crankshaft/hydrogen-instructions.h » ('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 2013 the V8 project authors. All rights reserved. 1 // Copyright 2013 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "src/crankshaft/hydrogen.h" 5 #include "src/crankshaft/hydrogen.h"
6 6
7 #include <sstream> 7 #include <sstream>
8 8
9 #include "src/allocation-site-scopes.h" 9 #include "src/allocation-site-scopes.h"
10 #include "src/ast/ast-numbering.h" 10 #include "src/ast/ast-numbering.h"
(...skipping 4093 matching lines...) Expand 10 before | Expand all | Expand 10 after
4104 4104
4105 // Implementation of utility classes to represent an expression's context in 4105 // Implementation of utility classes to represent an expression's context in
4106 // the AST. 4106 // the AST.
4107 AstContext::AstContext(HOptimizedGraphBuilder* owner, Expression::Context kind) 4107 AstContext::AstContext(HOptimizedGraphBuilder* owner, Expression::Context kind)
4108 : owner_(owner), 4108 : owner_(owner),
4109 kind_(kind), 4109 kind_(kind),
4110 outer_(owner->ast_context()), 4110 outer_(owner->ast_context()),
4111 typeof_mode_(NOT_INSIDE_TYPEOF) { 4111 typeof_mode_(NOT_INSIDE_TYPEOF) {
4112 owner->set_ast_context(this); // Push. 4112 owner->set_ast_context(this); // Push.
4113 #ifdef DEBUG 4113 #ifdef DEBUG
4114 DCHECK(owner->environment()->frame_type() == JS_FUNCTION); 4114 DCHECK_EQ(JS_FUNCTION, owner->environment()->frame_type());
4115 original_length_ = owner->environment()->length(); 4115 original_length_ = owner->environment()->length();
4116 #endif 4116 #endif
4117 } 4117 }
4118 4118
4119 4119
4120 AstContext::~AstContext() { 4120 AstContext::~AstContext() {
4121 owner_->set_ast_context(outer_); // Pop. 4121 owner_->set_ast_context(outer_); // Pop.
4122 } 4122 }
4123 4123
4124 4124
4125 EffectContext::~EffectContext() { 4125 EffectContext::~EffectContext() {
4126 DCHECK(owner()->HasStackOverflow() || 4126 DCHECK(owner()->HasStackOverflow() || owner()->current_block() == NULL ||
4127 owner()->current_block() == NULL ||
4128 (owner()->environment()->length() == original_length_ && 4127 (owner()->environment()->length() == original_length_ &&
4129 owner()->environment()->frame_type() == JS_FUNCTION)); 4128 (owner()->environment()->frame_type() == JS_FUNCTION ||
4129 owner()->environment()->frame_type() == TAIL_CALLER_FUNCTION)));
4130 } 4130 }
4131 4131
4132 4132
4133 ValueContext::~ValueContext() { 4133 ValueContext::~ValueContext() {
4134 DCHECK(owner()->HasStackOverflow() || 4134 DCHECK(owner()->HasStackOverflow() || owner()->current_block() == NULL ||
4135 owner()->current_block() == NULL ||
4136 (owner()->environment()->length() == original_length_ + 1 && 4135 (owner()->environment()->length() == original_length_ + 1 &&
4137 owner()->environment()->frame_type() == JS_FUNCTION)); 4136 (owner()->environment()->frame_type() == JS_FUNCTION ||
4137 owner()->environment()->frame_type() == TAIL_CALLER_FUNCTION)));
4138 } 4138 }
4139 4139
4140 4140
4141 void EffectContext::ReturnValue(HValue* value) { 4141 void EffectContext::ReturnValue(HValue* value) {
4142 // The value is simply ignored. 4142 // The value is simply ignored.
4143 } 4143 }
4144 4144
4145 4145
4146 void ValueContext::ReturnValue(HValue* value) { 4146 void ValueContext::ReturnValue(HValue* value) {
4147 // The value is tracked in the bailout environment, and communicated 4147 // The value is tracked in the bailout environment, and communicated
(...skipping 4184 matching lines...) Expand 10 before | Expand all | Expand 10 after
8332 InliningKind inlining_kind, 8332 InliningKind inlining_kind,
8333 TailCallMode syntactic_tail_call_mode) { 8333 TailCallMode syntactic_tail_call_mode) {
8334 if (target->context()->native_context() != 8334 if (target->context()->native_context() !=
8335 top_info()->closure()->context()->native_context()) { 8335 top_info()->closure()->context()->native_context()) {
8336 return false; 8336 return false;
8337 } 8337 }
8338 int nodes_added = InliningAstSize(target); 8338 int nodes_added = InliningAstSize(target);
8339 if (nodes_added == kNotInlinable) return false; 8339 if (nodes_added == kNotInlinable) return false;
8340 8340
8341 Handle<JSFunction> caller = current_info()->closure(); 8341 Handle<JSFunction> caller = current_info()->closure();
8342 if (syntactic_tail_call_mode == TailCallMode::kAllow) {
8343 TraceInline(target, caller, "call is at tail position");
8344 return false;
8345 }
8346
8347 if (nodes_added > Min(FLAG_max_inlined_nodes, kUnlimitedMaxInlinedNodes)) { 8342 if (nodes_added > Min(FLAG_max_inlined_nodes, kUnlimitedMaxInlinedNodes)) {
8348 TraceInline(target, caller, "target AST is too large [early]"); 8343 TraceInline(target, caller, "target AST is too large [early]");
8349 return false; 8344 return false;
8350 } 8345 }
8351 8346
8352 // Don't inline deeper than the maximum number of inlining levels. 8347 // Don't inline deeper than the maximum number of inlining levels.
8353 HEnvironment* env = environment(); 8348 HEnvironment* env = environment();
8354 int current_level = 1; 8349 int current_level = 1;
8355 while (env->outer() != NULL) { 8350 while (env->outer() != NULL) {
8356 if (current_level == FLAG_max_inlining_levels) { 8351 if (current_level == FLAG_max_inlining_levels) {
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after
8503 8498
8504 // Save the pending call context. Set up new one for the inlined function. 8499 // Save the pending call context. Set up new one for the inlined function.
8505 // The function state is new-allocated because we need to delete it 8500 // The function state is new-allocated because we need to delete it
8506 // in two different places. 8501 // in two different places.
8507 FunctionState* target_state = new FunctionState( 8502 FunctionState* target_state = new FunctionState(
8508 this, &target_info, inlining_kind, inlining_id, 8503 this, &target_info, inlining_kind, inlining_id,
8509 function_state()->ComputeTailCallMode(syntactic_tail_call_mode)); 8504 function_state()->ComputeTailCallMode(syntactic_tail_call_mode));
8510 8505
8511 HConstant* undefined = graph()->GetConstantUndefined(); 8506 HConstant* undefined = graph()->GetConstantUndefined();
8512 8507
8513 HEnvironment* inner_env = 8508 HEnvironment* inner_env = environment()->CopyForInlining(
8514 environment()->CopyForInlining(target, 8509 target, arguments_count, function, undefined,
8515 arguments_count, 8510 function_state()->inlining_kind(), syntactic_tail_call_mode);
8516 function,
8517 undefined,
8518 function_state()->inlining_kind());
8519 8511
8520 HConstant* context = Add<HConstant>(Handle<Context>(target->context())); 8512 HConstant* context = Add<HConstant>(Handle<Context>(target->context()));
8521 inner_env->BindContext(context); 8513 inner_env->BindContext(context);
8522 8514
8523 // Create a dematerialized arguments object for the function, also copy the 8515 // Create a dematerialized arguments object for the function, also copy the
8524 // current arguments values to use them for materialization. 8516 // current arguments values to use them for materialization.
8525 HEnvironment* arguments_env = inner_env->arguments_environment(); 8517 HEnvironment* arguments_env = inner_env->arguments_environment();
8526 int parameter_count = arguments_env->parameter_count(); 8518 int parameter_count = arguments_env->parameter_count();
8527 HArgumentsObject* arguments_object = Add<HArgumentsObject>(parameter_count); 8519 HArgumentsObject* arguments_object = Add<HArgumentsObject>(parameter_count);
8528 for (int i = 0; i < parameter_count; i++) { 8520 for (int i = 0; i < parameter_count; i++) {
8529 arguments_object->AddArgument(arguments_env->Lookup(i), zone()); 8521 arguments_object->AddArgument(arguments_env->Lookup(i), zone());
8530 } 8522 }
8531 8523
8532 // If the function uses arguments object then bind bind one. 8524 // If the function uses arguments object then bind bind one.
8533 if (function->scope()->arguments() != NULL) { 8525 if (function->scope()->arguments() != NULL) {
8534 DCHECK(function->scope()->arguments()->IsStackAllocated()); 8526 DCHECK(function->scope()->arguments()->IsStackAllocated());
8535 inner_env->Bind(function->scope()->arguments(), arguments_object); 8527 inner_env->Bind(function->scope()->arguments(), arguments_object);
8536 } 8528 }
8537 8529
8538 // Capture the state before invoking the inlined function for deopt in the 8530 // Capture the state before invoking the inlined function for deopt in the
8539 // inlined function. This simulate has no bailout-id since it's not directly 8531 // inlined function. This simulate has no bailout-id since it's not directly
8540 // reachable for deopt, and is only used to capture the state. If the simulate 8532 // reachable for deopt, and is only used to capture the state. If the simulate
8541 // becomes reachable by merging, the ast id of the simulate merged into it is 8533 // becomes reachable by merging, the ast id of the simulate merged into it is
8542 // adopted. 8534 // adopted.
8543 Add<HSimulate>(BailoutId::None()); 8535 Add<HSimulate>(BailoutId::None());
8544 8536
8545 current_block()->UpdateEnvironment(inner_env); 8537 current_block()->UpdateEnvironment(inner_env);
8546 Scope* saved_scope = scope(); 8538 Scope* saved_scope = scope();
8547 set_scope(target_info.scope()); 8539 set_scope(target_info.scope());
8548 HEnterInlined* enter_inlined = 8540 HEnterInlined* enter_inlined = Add<HEnterInlined>(
8549 Add<HEnterInlined>(return_id, target, context, arguments_count, function, 8541 return_id, target, context, arguments_count, function,
8550 function_state()->inlining_kind(), 8542 function_state()->inlining_kind(), function->scope()->arguments(),
8551 function->scope()->arguments(), arguments_object); 8543 arguments_object, syntactic_tail_call_mode);
8552 if (top_info()->is_tracking_positions()) { 8544 if (top_info()->is_tracking_positions()) {
8553 enter_inlined->set_inlining_id(inlining_id); 8545 enter_inlined->set_inlining_id(inlining_id);
8554 } 8546 }
8555 function_state()->set_entry(enter_inlined); 8547 function_state()->set_entry(enter_inlined);
8556 8548
8557 VisitDeclarations(target_info.scope()->declarations()); 8549 VisitDeclarations(target_info.scope()->declarations());
8558 VisitStatements(function->body()); 8550 VisitStatements(function->body());
8559 set_scope(saved_scope); 8551 set_scope(saved_scope);
8560 if (HasStackOverflow()) { 8552 if (HasStackOverflow()) {
8561 // Bail out if the inline function did, as we cannot residualize a call 8553 // Bail out if the inline function did, as we cannot residualize a call
(...skipping 665 matching lines...) Expand 10 before | Expand all | Expand 10 after
9227 9219
9228 bool HOptimizedGraphBuilder::TryInlineApiCall( 9220 bool HOptimizedGraphBuilder::TryInlineApiCall(
9229 Handle<Object> function, HValue* receiver, SmallMapList* receiver_maps, 9221 Handle<Object> function, HValue* receiver, SmallMapList* receiver_maps,
9230 int argc, BailoutId ast_id, ApiCallType call_type, 9222 int argc, BailoutId ast_id, ApiCallType call_type,
9231 TailCallMode syntactic_tail_call_mode) { 9223 TailCallMode syntactic_tail_call_mode) {
9232 if (function->IsJSFunction() && 9224 if (function->IsJSFunction() &&
9233 Handle<JSFunction>::cast(function)->context()->native_context() != 9225 Handle<JSFunction>::cast(function)->context()->native_context() !=
9234 top_info()->closure()->context()->native_context()) { 9226 top_info()->closure()->context()->native_context()) {
9235 return false; 9227 return false;
9236 } 9228 }
9237 if (syntactic_tail_call_mode == TailCallMode::kAllow) {
9238 return false;
9239 }
9240 if (argc > CallApiCallbackStub::kArgMax) { 9229 if (argc > CallApiCallbackStub::kArgMax) {
9241 return false; 9230 return false;
9242 } 9231 }
9243 9232
9244 CallOptimization optimization(function); 9233 CallOptimization optimization(function);
9245 if (!optimization.is_simple_api_call()) return false; 9234 if (!optimization.is_simple_api_call()) return false;
9246 Handle<Map> holder_map; 9235 Handle<Map> holder_map;
9247 for (int i = 0; i < receiver_maps->length(); ++i) { 9236 for (int i = 0; i < receiver_maps->length(); ++i) {
9248 auto map = receiver_maps->at(i); 9237 auto map = receiver_maps->at(i);
9249 // Don't inline calls to receivers requiring accesschecks. 9238 // Don't inline calls to receivers requiring accesschecks.
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after
9337 9326
9338 HInstruction* call = nullptr; 9327 HInstruction* call = nullptr;
9339 CHECK(argc <= CallApiCallbackStub::kArgMax); 9328 CHECK(argc <= CallApiCallbackStub::kArgMax);
9340 if (!is_function) { 9329 if (!is_function) {
9341 CallApiCallbackStub stub(isolate(), is_store, call_data_undefined, 9330 CallApiCallbackStub stub(isolate(), is_store, call_data_undefined,
9342 !optimization.is_constant_call()); 9331 !optimization.is_constant_call());
9343 Handle<Code> code = stub.GetCode(); 9332 Handle<Code> code = stub.GetCode();
9344 HConstant* code_value = Add<HConstant>(code); 9333 HConstant* code_value = Add<HConstant>(code);
9345 call = New<HCallWithDescriptor>( 9334 call = New<HCallWithDescriptor>(
9346 code_value, argc + 1, stub.GetCallInterfaceDescriptor(), 9335 code_value, argc + 1, stub.GetCallInterfaceDescriptor(),
9347 Vector<HValue*>(op_vals, arraysize(op_vals) - 1)); 9336 Vector<HValue*>(op_vals, arraysize(op_vals) - 1),
9337 syntactic_tail_call_mode);
9348 } else { 9338 } else {
9349 CallApiCallbackStub stub(isolate(), argc, call_data_undefined); 9339 CallApiCallbackStub stub(isolate(), argc, call_data_undefined);
9350 Handle<Code> code = stub.GetCode(); 9340 Handle<Code> code = stub.GetCode();
9351 HConstant* code_value = Add<HConstant>(code); 9341 HConstant* code_value = Add<HConstant>(code);
9352 call = New<HCallWithDescriptor>( 9342 call = New<HCallWithDescriptor>(
9353 code_value, argc + 1, stub.GetCallInterfaceDescriptor(), 9343 code_value, argc + 1, stub.GetCallInterfaceDescriptor(),
9354 Vector<HValue*>(op_vals, arraysize(op_vals) - 1)); 9344 Vector<HValue*>(op_vals, arraysize(op_vals) - 1),
9345 syntactic_tail_call_mode);
9355 Drop(1); // Drop function. 9346 Drop(1); // Drop function.
9356 } 9347 }
9357 9348
9358 ast_context()->ReturnInstruction(call, ast_id); 9349 ast_context()->ReturnInstruction(call, ast_id);
9359 return true; 9350 return true;
9360 } 9351 }
9361 9352
9362 9353
9363 void HOptimizedGraphBuilder::HandleIndirectCall(Call* expr, HValue* function, 9354 void HOptimizedGraphBuilder::HandleIndirectCall(Call* expr, HValue* function,
9364 int arguments_count) { 9355 int arguments_count) {
(...skipping 3750 matching lines...) Expand 10 before | Expand all | Expand 10 after
13115 HEnvironment* new_env = 13106 HEnvironment* new_env =
13116 new(zone()) HEnvironment(outer, target, frame_type, 13107 new(zone()) HEnvironment(outer, target, frame_type,
13117 arguments + 1, zone()); 13108 arguments + 1, zone());
13118 for (int i = 0; i <= arguments; ++i) { // Include receiver. 13109 for (int i = 0; i <= arguments; ++i) { // Include receiver.
13119 new_env->Push(ExpressionStackAt(arguments - i)); 13110 new_env->Push(ExpressionStackAt(arguments - i));
13120 } 13111 }
13121 new_env->ClearHistory(); 13112 new_env->ClearHistory();
13122 return new_env; 13113 return new_env;
13123 } 13114 }
13124 13115
13116 void HEnvironment::MarkAsTailCaller() {
13117 DCHECK_EQ(JS_FUNCTION, frame_type());
13118 frame_type_ = TAIL_CALLER_FUNCTION;
13119 }
13125 13120
13126 HEnvironment* HEnvironment::CopyForInlining( 13121 HEnvironment* HEnvironment::CopyForInlining(
13127 Handle<JSFunction> target, 13122 Handle<JSFunction> target, int arguments, FunctionLiteral* function,
13128 int arguments, 13123 HConstant* undefined, InliningKind inlining_kind,
13129 FunctionLiteral* function, 13124 TailCallMode syntactic_tail_call_mode) const {
13130 HConstant* undefined, 13125 DCHECK_EQ(JS_FUNCTION, frame_type());
13131 InliningKind inlining_kind) const {
13132 DCHECK(frame_type() == JS_FUNCTION);
13133 13126
13134 // Outer environment is a copy of this one without the arguments. 13127 // Outer environment is a copy of this one without the arguments.
13135 int arity = function->scope()->num_parameters(); 13128 int arity = function->scope()->num_parameters();
13136 13129
13137 HEnvironment* outer = Copy(); 13130 HEnvironment* outer = Copy();
13138 outer->Drop(arguments + 1); // Including receiver. 13131 outer->Drop(arguments + 1); // Including receiver.
13139 outer->ClearHistory(); 13132 outer->ClearHistory();
13140 13133
13134 if (syntactic_tail_call_mode == TailCallMode::kAllow) {
13135 DCHECK_EQ(NORMAL_RETURN, inlining_kind);
13136 outer->MarkAsTailCaller();
13137 }
13138
13141 if (inlining_kind == CONSTRUCT_CALL_RETURN) { 13139 if (inlining_kind == CONSTRUCT_CALL_RETURN) {
13142 // Create artificial constructor stub environment. The receiver should 13140 // Create artificial constructor stub environment. The receiver should
13143 // actually be the constructor function, but we pass the newly allocated 13141 // actually be the constructor function, but we pass the newly allocated
13144 // object instead, DoComputeConstructStubFrame() relies on that. 13142 // object instead, DoComputeConstructStubFrame() relies on that.
13145 outer = CreateStubEnvironment(outer, target, JS_CONSTRUCT, arguments); 13143 outer = CreateStubEnvironment(outer, target, JS_CONSTRUCT, arguments);
13146 } else if (inlining_kind == GETTER_CALL_RETURN) { 13144 } else if (inlining_kind == GETTER_CALL_RETURN) {
13147 // We need an additional StackFrame::INTERNAL frame for restoring the 13145 // We need an additional StackFrame::INTERNAL frame for restoring the
13148 // correct context. 13146 // correct context.
13149 outer = CreateStubEnvironment(outer, target, JS_GETTER, arguments); 13147 outer = CreateStubEnvironment(outer, target, JS_GETTER, arguments);
13150 } else if (inlining_kind == SETTER_CALL_RETURN) { 13148 } else if (inlining_kind == SETTER_CALL_RETURN) {
(...skipping 372 matching lines...) Expand 10 before | Expand all | Expand 10 after
13523 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); 13521 isolate()->GetHTracer()->TraceHydrogen(name(), graph_);
13524 } 13522 }
13525 13523
13526 #ifdef DEBUG 13524 #ifdef DEBUG
13527 graph_->Verify(false); // No full verify. 13525 graph_->Verify(false); // No full verify.
13528 #endif 13526 #endif
13529 } 13527 }
13530 13528
13531 } // namespace internal 13529 } // namespace internal
13532 } // namespace v8 13530 } // namespace v8
OLDNEW
« no previous file with comments | « src/crankshaft/hydrogen.h ('k') | src/crankshaft/hydrogen-instructions.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698