OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |