| 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 |