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 3474 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3485 return array_object; | 3485 return array_object; |
3486 } | 3486 } |
3487 | 3487 |
3488 | 3488 |
3489 HValue* HGraphBuilder::AddLoadJSBuiltin(int context_index) { | 3489 HValue* HGraphBuilder::AddLoadJSBuiltin(int context_index) { |
3490 HValue* native_context = BuildGetNativeContext(); | 3490 HValue* native_context = BuildGetNativeContext(); |
3491 HObjectAccess function_access = HObjectAccess::ForContextSlot(context_index); | 3491 HObjectAccess function_access = HObjectAccess::ForContextSlot(context_index); |
3492 return Add<HLoadNamedField>(native_context, nullptr, function_access); | 3492 return Add<HLoadNamedField>(native_context, nullptr, function_access); |
3493 } | 3493 } |
3494 | 3494 |
3495 | |
3496 HOptimizedGraphBuilder::HOptimizedGraphBuilder(CompilationInfo* info) | 3495 HOptimizedGraphBuilder::HOptimizedGraphBuilder(CompilationInfo* info) |
3497 : HGraphBuilder(info, CallInterfaceDescriptor()), | 3496 : HGraphBuilder(info, CallInterfaceDescriptor()), |
3498 function_state_(NULL), | 3497 function_state_(NULL), |
3499 initial_function_state_(this, info, NORMAL_RETURN, 0), | 3498 initial_function_state_(this, info, NORMAL_RETURN, 0, |
| 3499 TailCallMode::kAllow), |
3500 ast_context_(NULL), | 3500 ast_context_(NULL), |
3501 break_scope_(NULL), | 3501 break_scope_(NULL), |
3502 inlined_count_(0), | 3502 inlined_count_(0), |
3503 globals_(10, info->zone()), | 3503 globals_(10, info->zone()), |
3504 osr_(new (info->zone()) HOsrBuilder(this)) { | 3504 osr_(new (info->zone()) HOsrBuilder(this)) { |
3505 // This is not initialized in the initializer list because the | 3505 // This is not initialized in the initializer list because the |
3506 // constructor for the initial state relies on function_state_ == NULL | 3506 // constructor for the initial state relies on function_state_ == NULL |
3507 // to know it's the initial state. | 3507 // to know it's the initial state. |
3508 function_state_ = &initial_function_state_; | 3508 function_state_ = &initial_function_state_; |
3509 InitializeAstVisitor(info->isolate()); | 3509 InitializeAstVisitor(info->isolate()); |
(...skipping 515 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4025 phi_list_->Add(phi, zone()); | 4025 phi_list_->Add(phi, zone()); |
4026 } | 4026 } |
4027 } | 4027 } |
4028 } | 4028 } |
4029 | 4029 |
4030 | 4030 |
4031 // Implementation of utility class to encapsulate the translation state for | 4031 // Implementation of utility class to encapsulate the translation state for |
4032 // a (possibly inlined) function. | 4032 // a (possibly inlined) function. |
4033 FunctionState::FunctionState(HOptimizedGraphBuilder* owner, | 4033 FunctionState::FunctionState(HOptimizedGraphBuilder* owner, |
4034 CompilationInfo* info, InliningKind inlining_kind, | 4034 CompilationInfo* info, InliningKind inlining_kind, |
4035 int inlining_id) | 4035 int inlining_id, TailCallMode tail_call_mode) |
4036 : owner_(owner), | 4036 : owner_(owner), |
4037 compilation_info_(info), | 4037 compilation_info_(info), |
4038 call_context_(NULL), | 4038 call_context_(NULL), |
4039 inlining_kind_(inlining_kind), | 4039 inlining_kind_(inlining_kind), |
| 4040 tail_call_mode_(tail_call_mode), |
4040 function_return_(NULL), | 4041 function_return_(NULL), |
4041 test_context_(NULL), | 4042 test_context_(NULL), |
4042 entry_(NULL), | 4043 entry_(NULL), |
4043 arguments_object_(NULL), | 4044 arguments_object_(NULL), |
4044 arguments_elements_(NULL), | 4045 arguments_elements_(NULL), |
4045 inlining_id_(inlining_id), | 4046 inlining_id_(inlining_id), |
4046 outer_source_position_(SourcePosition::Unknown()), | 4047 outer_source_position_(SourcePosition::Unknown()), |
4047 outer_(owner->function_state()) { | 4048 outer_(owner->function_state()) { |
4048 if (outer_ != NULL) { | 4049 if (outer_ != NULL) { |
4049 // State for an inline function. | 4050 // State for an inline function. |
(...skipping 2516 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6566 if (!info->IsLoad()) { | 6567 if (!info->IsLoad()) { |
6567 argument_count = 2; | 6568 argument_count = 2; |
6568 Push(value); | 6569 Push(value); |
6569 } | 6570 } |
6570 | 6571 |
6571 if (info->accessor()->IsJSFunction() && | 6572 if (info->accessor()->IsJSFunction() && |
6572 info->NeedsWrappingFor(Handle<JSFunction>::cast(info->accessor()))) { | 6573 info->NeedsWrappingFor(Handle<JSFunction>::cast(info->accessor()))) { |
6573 HValue* function = Add<HConstant>(info->accessor()); | 6574 HValue* function = Add<HConstant>(info->accessor()); |
6574 PushArgumentsFromEnvironment(argument_count); | 6575 PushArgumentsFromEnvironment(argument_count); |
6575 return NewCallFunction(function, argument_count, | 6576 return NewCallFunction(function, argument_count, |
6576 ConvertReceiverMode::kNotNullOrUndefined); | 6577 ConvertReceiverMode::kNotNullOrUndefined, |
| 6578 TailCallMode::kDisallow); |
6577 } else if (FLAG_inline_accessors && can_inline_accessor) { | 6579 } else if (FLAG_inline_accessors && can_inline_accessor) { |
6578 bool success = info->IsLoad() | 6580 bool success = info->IsLoad() |
6579 ? TryInlineGetter(info->accessor(), info->map(), ast_id, return_id) | 6581 ? TryInlineGetter(info->accessor(), info->map(), ast_id, return_id) |
6580 : TryInlineSetter( | 6582 : TryInlineSetter( |
6581 info->accessor(), info->map(), ast_id, return_id, value); | 6583 info->accessor(), info->map(), ast_id, return_id, value); |
6582 if (success || HasStackOverflow()) return NULL; | 6584 if (success || HasStackOverflow()) return NULL; |
6583 } | 6585 } |
6584 | 6586 |
6585 PushArgumentsFromEnvironment(argument_count); | 6587 PushArgumentsFromEnvironment(argument_count); |
6586 if (!info->accessor()->IsJSFunction()) { | 6588 if (!info->accessor()->IsJSFunction()) { |
6587 Bailout(kInliningBailedOut); | 6589 Bailout(kInliningBailedOut); |
6588 return nullptr; | 6590 return nullptr; |
6589 } | 6591 } |
6590 return NewCallConstantFunction(Handle<JSFunction>::cast(info->accessor()), | 6592 return NewCallConstantFunction(Handle<JSFunction>::cast(info->accessor()), |
6591 argument_count); | 6593 argument_count, TailCallMode::kDisallow); |
6592 } | 6594 } |
6593 | 6595 |
6594 DCHECK(info->IsDataConstant()); | 6596 DCHECK(info->IsDataConstant()); |
6595 if (info->IsLoad()) { | 6597 if (info->IsLoad()) { |
6596 return New<HConstant>(info->constant()); | 6598 return New<HConstant>(info->constant()); |
6597 } else { | 6599 } else { |
6598 return New<HCheckValue>(value, Handle<JSFunction>::cast(info->constant())); | 6600 return New<HCheckValue>(value, Handle<JSFunction>::cast(info->constant())); |
6599 } | 6601 } |
6600 } | 6602 } |
6601 | 6603 |
(...skipping 1378 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7980 | 7982 |
7981 void HOptimizedGraphBuilder::AddCheckPrototypeMaps(Handle<JSObject> holder, | 7983 void HOptimizedGraphBuilder::AddCheckPrototypeMaps(Handle<JSObject> holder, |
7982 Handle<Map> receiver_map) { | 7984 Handle<Map> receiver_map) { |
7983 if (!holder.is_null()) { | 7985 if (!holder.is_null()) { |
7984 Handle<JSObject> prototype(JSObject::cast(receiver_map->prototype())); | 7986 Handle<JSObject> prototype(JSObject::cast(receiver_map->prototype())); |
7985 BuildCheckPrototypeMaps(prototype, holder); | 7987 BuildCheckPrototypeMaps(prototype, holder); |
7986 } | 7988 } |
7987 } | 7989 } |
7988 | 7990 |
7989 HInstruction* HOptimizedGraphBuilder::NewCallFunction( | 7991 HInstruction* HOptimizedGraphBuilder::NewCallFunction( |
7990 HValue* function, int argument_count, ConvertReceiverMode convert_mode) { | 7992 HValue* function, int argument_count, ConvertReceiverMode convert_mode, |
| 7993 TailCallMode tail_call_mode) { |
7991 HValue* arity = Add<HConstant>(argument_count - 1); | 7994 HValue* arity = Add<HConstant>(argument_count - 1); |
7992 | 7995 |
7993 HValue* op_vals[] = {context(), function, arity}; | 7996 HValue* op_vals[] = {context(), function, arity}; |
7994 | 7997 |
| 7998 // TODO(ishell): use tail_call_mode here. |
7995 Callable callable = CodeFactory::Call(isolate(), convert_mode); | 7999 Callable callable = CodeFactory::Call(isolate(), convert_mode); |
7996 HConstant* stub = Add<HConstant>(callable.code()); | 8000 HConstant* stub = Add<HConstant>(callable.code()); |
7997 | 8001 |
7998 return New<HCallWithDescriptor>(stub, argument_count, callable.descriptor(), | 8002 return New<HCallWithDescriptor>(stub, argument_count, callable.descriptor(), |
7999 Vector<HValue*>(op_vals, arraysize(op_vals))); | 8003 Vector<HValue*>(op_vals, arraysize(op_vals))); |
8000 } | 8004 } |
8001 | 8005 |
8002 HInstruction* HOptimizedGraphBuilder::NewCallFunctionViaIC( | 8006 HInstruction* HOptimizedGraphBuilder::NewCallFunctionViaIC( |
8003 HValue* function, int argument_count, ConvertReceiverMode convert_mode, | 8007 HValue* function, int argument_count, ConvertReceiverMode convert_mode, |
8004 FeedbackVectorSlot slot) { | 8008 TailCallMode tail_call_mode, FeedbackVectorSlot slot) { |
8005 int arity = argument_count - 1; | 8009 int arity = argument_count - 1; |
8006 Handle<TypeFeedbackVector> vector(current_feedback_vector(), isolate()); | 8010 Handle<TypeFeedbackVector> vector(current_feedback_vector(), isolate()); |
8007 HValue* index_val = Add<HConstant>(vector->GetIndex(slot)); | 8011 HValue* index_val = Add<HConstant>(vector->GetIndex(slot)); |
8008 HValue* vector_val = Add<HConstant>(vector); | 8012 HValue* vector_val = Add<HConstant>(vector); |
8009 | 8013 |
8010 HValue* op_vals[] = {context(), function, index_val, vector_val}; | 8014 HValue* op_vals[] = {context(), function, index_val, vector_val}; |
8011 | 8015 |
| 8016 // TODO(ishell): use tail_call_mode here. |
8012 Callable callable = CodeFactory::CallICInOptimizedCode( | 8017 Callable callable = CodeFactory::CallICInOptimizedCode( |
8013 isolate(), arity, ConvertReceiverMode::kNullOrUndefined); | 8018 isolate(), arity, ConvertReceiverMode::kNullOrUndefined); |
8014 HConstant* stub = Add<HConstant>(callable.code()); | 8019 HConstant* stub = Add<HConstant>(callable.code()); |
8015 | 8020 |
8016 return New<HCallWithDescriptor>(stub, argument_count, callable.descriptor(), | 8021 return New<HCallWithDescriptor>(stub, argument_count, callable.descriptor(), |
8017 Vector<HValue*>(op_vals, arraysize(op_vals))); | 8022 Vector<HValue*>(op_vals, arraysize(op_vals))); |
8018 } | 8023 } |
8019 | 8024 |
8020 HInstruction* HOptimizedGraphBuilder::NewCallConstantFunction( | 8025 HInstruction* HOptimizedGraphBuilder::NewCallConstantFunction( |
8021 Handle<JSFunction> function, int argument_count) { | 8026 Handle<JSFunction> function, int argument_count, |
| 8027 TailCallMode tail_call_mode) { |
| 8028 // TODO(ishell): use tail_call_mode here. |
8022 HValue* target = Add<HConstant>(function); | 8029 HValue* target = Add<HConstant>(function); |
8023 return New<HInvokeFunction>(target, function, argument_count); | 8030 return New<HInvokeFunction>(target, function, argument_count); |
8024 } | 8031 } |
8025 | 8032 |
8026 | 8033 |
8027 class FunctionSorter { | 8034 class FunctionSorter { |
8028 public: | 8035 public: |
8029 explicit FunctionSorter(int index = 0, int ticks = 0, int size = 0) | 8036 explicit FunctionSorter(int index = 0, int ticks = 0, int size = 0) |
8030 : index_(index), ticks_(ticks), size_(size) {} | 8037 : index_(index), ticks_(ticks), size_(size) {} |
8031 | 8038 |
(...skipping 19 matching lines...) Expand all Loading... |
8051 HValue* receiver, | 8058 HValue* receiver, |
8052 SmallMapList* maps, | 8059 SmallMapList* maps, |
8053 Handle<String> name) { | 8060 Handle<String> name) { |
8054 int argument_count = expr->arguments()->length() + 1; // Includes receiver. | 8061 int argument_count = expr->arguments()->length() + 1; // Includes receiver. |
8055 FunctionSorter order[kMaxCallPolymorphism]; | 8062 FunctionSorter order[kMaxCallPolymorphism]; |
8056 | 8063 |
8057 bool handle_smi = false; | 8064 bool handle_smi = false; |
8058 bool handled_string = false; | 8065 bool handled_string = false; |
8059 int ordered_functions = 0; | 8066 int ordered_functions = 0; |
8060 | 8067 |
| 8068 TailCallMode syntactic_tail_call_mode = expr->tail_call_mode(); |
| 8069 TailCallMode tail_call_mode = |
| 8070 function_state()->ComputeTailCallMode(syntactic_tail_call_mode); |
| 8071 |
8061 int i; | 8072 int i; |
8062 for (i = 0; i < maps->length() && ordered_functions < kMaxCallPolymorphism; | 8073 for (i = 0; i < maps->length() && ordered_functions < kMaxCallPolymorphism; |
8063 ++i) { | 8074 ++i) { |
8064 PropertyAccessInfo info(this, LOAD, maps->at(i), name); | 8075 PropertyAccessInfo info(this, LOAD, maps->at(i), name); |
8065 if (info.CanAccessMonomorphic() && info.IsDataConstant() && | 8076 if (info.CanAccessMonomorphic() && info.IsDataConstant() && |
8066 info.constant()->IsJSFunction()) { | 8077 info.constant()->IsJSFunction()) { |
8067 if (info.IsStringType()) { | 8078 if (info.IsStringType()) { |
8068 if (handled_string) continue; | 8079 if (handled_string) continue; |
8069 handled_string = true; | 8080 handled_string = true; |
8070 } | 8081 } |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8161 // entire compilation by setting stack overflow on the visitor. | 8172 // entire compilation by setting stack overflow on the visitor. |
8162 if (HasStackOverflow()) return; | 8173 if (HasStackOverflow()) return; |
8163 } else { | 8174 } else { |
8164 // Since HWrapReceiver currently cannot actually wrap numbers and strings, | 8175 // Since HWrapReceiver currently cannot actually wrap numbers and strings, |
8165 // use the regular call builtin for method calls to wrap the receiver. | 8176 // use the regular call builtin for method calls to wrap the receiver. |
8166 // TODO(verwaest): Support creation of value wrappers directly in | 8177 // TODO(verwaest): Support creation of value wrappers directly in |
8167 // HWrapReceiver. | 8178 // HWrapReceiver. |
8168 HInstruction* call = | 8179 HInstruction* call = |
8169 needs_wrapping | 8180 needs_wrapping |
8170 ? NewCallFunction(function, argument_count, | 8181 ? NewCallFunction(function, argument_count, |
8171 ConvertReceiverMode::kNotNullOrUndefined) | 8182 ConvertReceiverMode::kNotNullOrUndefined, |
8172 : NewCallConstantFunction(target, argument_count); | 8183 tail_call_mode) |
| 8184 : NewCallConstantFunction(target, argument_count, tail_call_mode); |
8173 PushArgumentsFromEnvironment(argument_count); | 8185 PushArgumentsFromEnvironment(argument_count); |
8174 AddInstruction(call); | 8186 AddInstruction(call); |
8175 Drop(1); // Drop the function. | 8187 Drop(1); // Drop the function. |
8176 if (!ast_context()->IsEffect()) Push(call); | 8188 if (!ast_context()->IsEffect()) Push(call); |
8177 } | 8189 } |
8178 | 8190 |
8179 if (current_block() != NULL) Goto(join); | 8191 if (current_block() != NULL) Goto(join); |
8180 set_current_block(if_false); | 8192 set_current_block(if_false); |
8181 } | 8193 } |
8182 | 8194 |
8183 // Finish up. Unconditionally deoptimize if we've handled all the maps we | 8195 // Finish up. Unconditionally deoptimize if we've handled all the maps we |
8184 // know about and do not want to handle ones we've never seen. Otherwise | 8196 // know about and do not want to handle ones we've never seen. Otherwise |
8185 // use a generic IC. | 8197 // use a generic IC. |
8186 if (ordered_functions == maps->length() && FLAG_deoptimize_uncommon_cases) { | 8198 if (ordered_functions == maps->length() && FLAG_deoptimize_uncommon_cases) { |
8187 FinishExitWithHardDeoptimization(Deoptimizer::kUnknownMapInPolymorphicCall); | 8199 FinishExitWithHardDeoptimization(Deoptimizer::kUnknownMapInPolymorphicCall); |
8188 } else { | 8200 } else { |
8189 Property* prop = expr->expression()->AsProperty(); | 8201 Property* prop = expr->expression()->AsProperty(); |
8190 HInstruction* function = | 8202 HInstruction* function = |
8191 BuildNamedGeneric(LOAD, prop, prop->PropertyFeedbackSlot(), receiver, | 8203 BuildNamedGeneric(LOAD, prop, prop->PropertyFeedbackSlot(), receiver, |
8192 name, NULL, prop->IsUninitialized()); | 8204 name, NULL, prop->IsUninitialized()); |
8193 AddInstruction(function); | 8205 AddInstruction(function); |
8194 Push(function); | 8206 Push(function); |
8195 AddSimulate(prop->LoadId(), REMOVABLE_SIMULATE); | 8207 AddSimulate(prop->LoadId(), REMOVABLE_SIMULATE); |
8196 | 8208 |
8197 environment()->SetExpressionStackAt(1, function); | 8209 environment()->SetExpressionStackAt(1, function); |
8198 environment()->SetExpressionStackAt(0, receiver); | 8210 environment()->SetExpressionStackAt(0, receiver); |
8199 CHECK_ALIVE(VisitExpressions(expr->arguments())); | 8211 CHECK_ALIVE(VisitExpressions(expr->arguments())); |
8200 | 8212 |
8201 HInstruction* call = NewCallFunction( | 8213 HInstruction* call = NewCallFunction( |
8202 function, argument_count, ConvertReceiverMode::kNotNullOrUndefined); | 8214 function, argument_count, ConvertReceiverMode::kNotNullOrUndefined, |
| 8215 tail_call_mode); |
8203 | 8216 |
8204 PushArgumentsFromEnvironment(argument_count); | 8217 PushArgumentsFromEnvironment(argument_count); |
8205 | 8218 |
8206 Drop(1); // Function. | 8219 Drop(1); // Function. |
8207 | 8220 |
8208 if (join != NULL) { | 8221 if (join != NULL) { |
8209 AddInstruction(call); | 8222 AddInstruction(call); |
8210 if (!ast_context()->IsEffect()) Push(call); | 8223 if (!ast_context()->IsEffect()) Push(call); |
8211 Goto(join); | 8224 Goto(join); |
8212 } else { | 8225 } else { |
8213 return ast_context()->ReturnInstruction(call, expr->id()); | 8226 return ast_context()->ReturnInstruction(call, expr->id()); |
8214 } | 8227 } |
8215 } | 8228 } |
8216 | 8229 |
8217 // We assume that control flow is always live after an expression. So | 8230 // We assume that control flow is always live after an expression. So |
8218 // even without predecessors to the join block, we set it as the exit | 8231 // even without predecessors to the join block, we set it as the exit |
8219 // block and continue by adding instructions there. | 8232 // block and continue by adding instructions there. |
8220 DCHECK(join != NULL); | 8233 DCHECK(join != NULL); |
8221 if (join->HasPredecessor()) { | 8234 if (join->HasPredecessor()) { |
8222 set_current_block(join); | 8235 set_current_block(join); |
8223 join->SetJoinId(expr->id()); | 8236 join->SetJoinId(expr->id()); |
8224 if (!ast_context()->IsEffect()) return ast_context()->ReturnValue(Pop()); | 8237 if (!ast_context()->IsEffect()) return ast_context()->ReturnValue(Pop()); |
8225 } else { | 8238 } else { |
8226 set_current_block(NULL); | 8239 set_current_block(NULL); |
8227 } | 8240 } |
8228 } | 8241 } |
8229 | 8242 |
8230 | |
8231 void HOptimizedGraphBuilder::TraceInline(Handle<JSFunction> target, | 8243 void HOptimizedGraphBuilder::TraceInline(Handle<JSFunction> target, |
8232 Handle<JSFunction> caller, | 8244 Handle<JSFunction> caller, |
8233 const char* reason) { | 8245 const char* reason, |
| 8246 TailCallMode tail_call_mode) { |
8234 if (FLAG_trace_inlining) { | 8247 if (FLAG_trace_inlining) { |
8235 base::SmartArrayPointer<char> target_name = | 8248 base::SmartArrayPointer<char> target_name = |
8236 target->shared()->DebugName()->ToCString(); | 8249 target->shared()->DebugName()->ToCString(); |
8237 base::SmartArrayPointer<char> caller_name = | 8250 base::SmartArrayPointer<char> caller_name = |
8238 caller->shared()->DebugName()->ToCString(); | 8251 caller->shared()->DebugName()->ToCString(); |
8239 if (reason == NULL) { | 8252 if (reason == NULL) { |
8240 PrintF("Inlined %s called from %s.\n", target_name.get(), | 8253 const char* call_mode = |
| 8254 tail_call_mode == TailCallMode::kAllow ? "tail called" : "called"; |
| 8255 PrintF("Inlined %s %s from %s.\n", target_name.get(), call_mode, |
8241 caller_name.get()); | 8256 caller_name.get()); |
8242 } else { | 8257 } else { |
8243 PrintF("Did not inline %s called from %s (%s).\n", | 8258 PrintF("Did not inline %s called from %s (%s).\n", |
8244 target_name.get(), caller_name.get(), reason); | 8259 target_name.get(), caller_name.get(), reason); |
8245 } | 8260 } |
8246 } | 8261 } |
8247 } | 8262 } |
8248 | 8263 |
8249 | 8264 |
8250 static const int kNotInlinable = 1000000000; | 8265 static const int kNotInlinable = 1000000000; |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8287 } | 8302 } |
8288 if (noopt_reason != kNoReason && noopt_reason != kHydrogenFilter) { | 8303 if (noopt_reason != kNoReason && noopt_reason != kHydrogenFilter) { |
8289 TraceInline(target, caller, "target contains unsupported syntax [early]"); | 8304 TraceInline(target, caller, "target contains unsupported syntax [early]"); |
8290 return kNotInlinable; | 8305 return kNotInlinable; |
8291 } | 8306 } |
8292 | 8307 |
8293 int nodes_added = target_shared->ast_node_count(); | 8308 int nodes_added = target_shared->ast_node_count(); |
8294 return nodes_added; | 8309 return nodes_added; |
8295 } | 8310 } |
8296 | 8311 |
8297 | |
8298 bool HOptimizedGraphBuilder::TryInline(Handle<JSFunction> target, | 8312 bool HOptimizedGraphBuilder::TryInline(Handle<JSFunction> target, |
8299 int arguments_count, | 8313 int arguments_count, |
8300 HValue* implicit_return_value, | 8314 HValue* implicit_return_value, |
8301 BailoutId ast_id, BailoutId return_id, | 8315 BailoutId ast_id, BailoutId return_id, |
8302 InliningKind inlining_kind) { | 8316 InliningKind inlining_kind, |
| 8317 TailCallMode syntactic_tail_call_mode) { |
8303 if (target->context()->native_context() != | 8318 if (target->context()->native_context() != |
8304 top_info()->closure()->context()->native_context()) { | 8319 top_info()->closure()->context()->native_context()) { |
8305 return false; | 8320 return false; |
8306 } | 8321 } |
8307 int nodes_added = InliningAstSize(target); | 8322 int nodes_added = InliningAstSize(target); |
8308 if (nodes_added == kNotInlinable) return false; | 8323 if (nodes_added == kNotInlinable) return false; |
8309 | 8324 |
8310 Handle<JSFunction> caller = current_info()->closure(); | 8325 Handle<JSFunction> caller = current_info()->closure(); |
| 8326 if (syntactic_tail_call_mode == TailCallMode::kAllow) { |
| 8327 TraceInline(target, caller, "call is at tail position"); |
| 8328 return false; |
| 8329 } |
8311 | 8330 |
8312 if (nodes_added > Min(FLAG_max_inlined_nodes, kUnlimitedMaxInlinedNodes)) { | 8331 if (nodes_added > Min(FLAG_max_inlined_nodes, kUnlimitedMaxInlinedNodes)) { |
8313 TraceInline(target, caller, "target AST is too large [early]"); | 8332 TraceInline(target, caller, "target AST is too large [early]"); |
8314 return false; | 8333 return false; |
8315 } | 8334 } |
8316 | 8335 |
8317 // Don't inline deeper than the maximum number of inlining levels. | 8336 // Don't inline deeper than the maximum number of inlining levels. |
8318 HEnvironment* env = environment(); | 8337 HEnvironment* env = environment(); |
8319 int current_level = 1; | 8338 int current_level = 1; |
8320 while (env->outer() != NULL) { | 8339 while (env->outer() != NULL) { |
(...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8462 | 8481 |
8463 int inlining_id = 0; | 8482 int inlining_id = 0; |
8464 if (top_info()->is_tracking_positions()) { | 8483 if (top_info()->is_tracking_positions()) { |
8465 inlining_id = top_info()->TraceInlinedFunction( | 8484 inlining_id = top_info()->TraceInlinedFunction( |
8466 target_shared, source_position(), function_state()->inlining_id()); | 8485 target_shared, source_position(), function_state()->inlining_id()); |
8467 } | 8486 } |
8468 | 8487 |
8469 // Save the pending call context. Set up new one for the inlined function. | 8488 // Save the pending call context. Set up new one for the inlined function. |
8470 // The function state is new-allocated because we need to delete it | 8489 // The function state is new-allocated because we need to delete it |
8471 // in two different places. | 8490 // in two different places. |
8472 FunctionState* target_state = | 8491 FunctionState* target_state = new FunctionState( |
8473 new FunctionState(this, &target_info, inlining_kind, inlining_id); | 8492 this, &target_info, inlining_kind, inlining_id, |
| 8493 function_state()->ComputeTailCallMode(syntactic_tail_call_mode)); |
8474 | 8494 |
8475 HConstant* undefined = graph()->GetConstantUndefined(); | 8495 HConstant* undefined = graph()->GetConstantUndefined(); |
8476 | 8496 |
8477 HEnvironment* inner_env = | 8497 HEnvironment* inner_env = |
8478 environment()->CopyForInlining(target, | 8498 environment()->CopyForInlining(target, |
8479 arguments_count, | 8499 arguments_count, |
8480 function, | 8500 function, |
8481 undefined, | 8501 undefined, |
8482 function_state()->inlining_kind()); | 8502 function_state()->inlining_kind()); |
8483 | 8503 |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8533 | 8553 |
8534 // Update inlined nodes count. | 8554 // Update inlined nodes count. |
8535 inlined_count_ += nodes_added; | 8555 inlined_count_ += nodes_added; |
8536 | 8556 |
8537 Handle<Code> unoptimized_code(target_shared->code()); | 8557 Handle<Code> unoptimized_code(target_shared->code()); |
8538 DCHECK(unoptimized_code->kind() == Code::FUNCTION); | 8558 DCHECK(unoptimized_code->kind() == Code::FUNCTION); |
8539 Handle<TypeFeedbackInfo> type_info( | 8559 Handle<TypeFeedbackInfo> type_info( |
8540 TypeFeedbackInfo::cast(unoptimized_code->type_feedback_info())); | 8560 TypeFeedbackInfo::cast(unoptimized_code->type_feedback_info())); |
8541 graph()->update_type_change_checksum(type_info->own_type_change_checksum()); | 8561 graph()->update_type_change_checksum(type_info->own_type_change_checksum()); |
8542 | 8562 |
8543 TraceInline(target, caller, NULL); | 8563 TraceInline(target, caller, NULL, syntactic_tail_call_mode); |
8544 | 8564 |
8545 if (current_block() != NULL) { | 8565 if (current_block() != NULL) { |
8546 FunctionState* state = function_state(); | 8566 FunctionState* state = function_state(); |
8547 if (state->inlining_kind() == CONSTRUCT_CALL_RETURN) { | 8567 if (state->inlining_kind() == CONSTRUCT_CALL_RETURN) { |
8548 // Falling off the end of an inlined construct call. In a test context the | 8568 // Falling off the end of an inlined construct call. In a test context the |
8549 // return value will always evaluate to true, in a value context the | 8569 // return value will always evaluate to true, in a value context the |
8550 // return value is the newly allocated receiver. | 8570 // return value is the newly allocated receiver. |
8551 if (call_context()->IsTest()) { | 8571 if (call_context()->IsTest()) { |
8552 Goto(inlined_test_context()->if_true(), state); | 8572 Goto(inlined_test_context()->if_true(), state); |
8553 } else if (call_context()->IsEffect()) { | 8573 } else if (call_context()->IsEffect()) { |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8617 } else { | 8637 } else { |
8618 set_current_block(NULL); | 8638 set_current_block(NULL); |
8619 } | 8639 } |
8620 delete target_state; | 8640 delete target_state; |
8621 return true; | 8641 return true; |
8622 } | 8642 } |
8623 | 8643 |
8624 | 8644 |
8625 bool HOptimizedGraphBuilder::TryInlineCall(Call* expr) { | 8645 bool HOptimizedGraphBuilder::TryInlineCall(Call* expr) { |
8626 return TryInline(expr->target(), expr->arguments()->length(), NULL, | 8646 return TryInline(expr->target(), expr->arguments()->length(), NULL, |
8627 expr->id(), expr->ReturnId(), NORMAL_RETURN); | 8647 expr->id(), expr->ReturnId(), NORMAL_RETURN, |
| 8648 expr->tail_call_mode()); |
8628 } | 8649 } |
8629 | 8650 |
8630 | 8651 |
8631 bool HOptimizedGraphBuilder::TryInlineConstruct(CallNew* expr, | 8652 bool HOptimizedGraphBuilder::TryInlineConstruct(CallNew* expr, |
8632 HValue* implicit_return_value) { | 8653 HValue* implicit_return_value) { |
8633 return TryInline(expr->target(), expr->arguments()->length(), | 8654 return TryInline(expr->target(), expr->arguments()->length(), |
8634 implicit_return_value, expr->id(), expr->ReturnId(), | 8655 implicit_return_value, expr->id(), expr->ReturnId(), |
8635 CONSTRUCT_CALL_RETURN); | 8656 CONSTRUCT_CALL_RETURN, TailCallMode::kDisallow); |
8636 } | 8657 } |
8637 | 8658 |
8638 bool HOptimizedGraphBuilder::TryInlineGetter(Handle<Object> getter, | 8659 bool HOptimizedGraphBuilder::TryInlineGetter(Handle<Object> getter, |
8639 Handle<Map> receiver_map, | 8660 Handle<Map> receiver_map, |
8640 BailoutId ast_id, | 8661 BailoutId ast_id, |
8641 BailoutId return_id) { | 8662 BailoutId return_id) { |
8642 if (TryInlineApiGetter(getter, receiver_map, ast_id)) return true; | 8663 if (TryInlineApiGetter(getter, receiver_map, ast_id)) return true; |
8643 return getter->IsJSFunction() && | 8664 return getter->IsJSFunction() && |
8644 TryInline(Handle<JSFunction>::cast(getter), 0, NULL, ast_id, return_id, | 8665 TryInline(Handle<JSFunction>::cast(getter), 0, NULL, ast_id, return_id, |
8645 GETTER_CALL_RETURN); | 8666 GETTER_CALL_RETURN, TailCallMode::kDisallow); |
8646 } | 8667 } |
8647 | 8668 |
8648 bool HOptimizedGraphBuilder::TryInlineSetter(Handle<Object> setter, | 8669 bool HOptimizedGraphBuilder::TryInlineSetter(Handle<Object> setter, |
8649 Handle<Map> receiver_map, | 8670 Handle<Map> receiver_map, |
8650 BailoutId id, | 8671 BailoutId id, |
8651 BailoutId assignment_id, | 8672 BailoutId assignment_id, |
8652 HValue* implicit_return_value) { | 8673 HValue* implicit_return_value) { |
8653 if (TryInlineApiSetter(setter, receiver_map, id)) return true; | 8674 if (TryInlineApiSetter(setter, receiver_map, id)) return true; |
8654 return setter->IsJSFunction() && | 8675 return setter->IsJSFunction() && |
8655 TryInline(Handle<JSFunction>::cast(setter), 1, implicit_return_value, | 8676 TryInline(Handle<JSFunction>::cast(setter), 1, implicit_return_value, |
8656 id, assignment_id, SETTER_CALL_RETURN); | 8677 id, assignment_id, SETTER_CALL_RETURN, |
| 8678 TailCallMode::kDisallow); |
8657 } | 8679 } |
8658 | 8680 |
8659 | 8681 |
8660 bool HOptimizedGraphBuilder::TryInlineIndirectCall(Handle<JSFunction> function, | 8682 bool HOptimizedGraphBuilder::TryInlineIndirectCall(Handle<JSFunction> function, |
8661 Call* expr, | 8683 Call* expr, |
8662 int arguments_count) { | 8684 int arguments_count) { |
8663 return TryInline(function, arguments_count, NULL, expr->id(), | 8685 return TryInline(function, arguments_count, NULL, expr->id(), |
8664 expr->ReturnId(), NORMAL_RETURN); | 8686 expr->ReturnId(), NORMAL_RETURN, expr->tail_call_mode()); |
8665 } | 8687 } |
8666 | 8688 |
8667 | 8689 |
8668 bool HOptimizedGraphBuilder::TryInlineBuiltinFunctionCall(Call* expr) { | 8690 bool HOptimizedGraphBuilder::TryInlineBuiltinFunctionCall(Call* expr) { |
8669 if (!expr->target()->shared()->HasBuiltinFunctionId()) return false; | 8691 if (!expr->target()->shared()->HasBuiltinFunctionId()) return false; |
8670 BuiltinFunctionId id = expr->target()->shared()->builtin_function_id(); | 8692 BuiltinFunctionId id = expr->target()->shared()->builtin_function_id(); |
| 8693 // We intentionally ignore expr->tail_call_mode() here because builtins |
| 8694 // we inline here do not observe if they were tail called or not. |
8671 switch (id) { | 8695 switch (id) { |
8672 case kMathExp: | 8696 case kMathExp: |
8673 if (!FLAG_fast_math) break; | 8697 if (!FLAG_fast_math) break; |
8674 // Fall through if FLAG_fast_math. | 8698 // Fall through if FLAG_fast_math. |
8675 case kMathRound: | 8699 case kMathRound: |
8676 case kMathFround: | 8700 case kMathFround: |
8677 case kMathFloor: | 8701 case kMathFloor: |
8678 case kMathAbs: | 8702 case kMathAbs: |
8679 case kMathSqrt: | 8703 case kMathSqrt: |
8680 case kMathLog: | 8704 case kMathLog: |
(...skipping 395 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
9076 INITIALIZING_STORE); | 9100 INITIALIZING_STORE); |
9077 | 9101 |
9078 // Remember new length. | 9102 // Remember new length. |
9079 Add<HStoreNamedField>( | 9103 Add<HStoreNamedField>( |
9080 receiver, HObjectAccess::ForArrayLength(kind), | 9104 receiver, HObjectAccess::ForArrayLength(kind), |
9081 new_length, STORE_TO_INITIALIZED_ENTRY); | 9105 new_length, STORE_TO_INITIALIZED_ENTRY); |
9082 } | 9106 } |
9083 if_inline.Else(); | 9107 if_inline.Else(); |
9084 { | 9108 { |
9085 Add<HPushArguments>(receiver); | 9109 Add<HPushArguments>(receiver); |
9086 result = AddInstruction(NewCallConstantFunction(function, 1)); | 9110 result = AddInstruction( |
| 9111 NewCallConstantFunction(function, 1, TailCallMode::kDisallow)); |
9087 if (!ast_context()->IsEffect()) Push(result); | 9112 if (!ast_context()->IsEffect()) Push(result); |
9088 } | 9113 } |
9089 if_inline.End(); | 9114 if_inline.End(); |
9090 } | 9115 } |
9091 if_lengthiszero.End(); | 9116 if_lengthiszero.End(); |
9092 } | 9117 } |
9093 result = ast_context()->IsEffect() ? graph()->GetConstant0() : Top(); | 9118 result = ast_context()->IsEffect() ? graph()->GetConstant0() : Top(); |
9094 Add<HSimulate>(expr->id(), REMOVABLE_SIMULATE); | 9119 Add<HSimulate>(expr->id(), REMOVABLE_SIMULATE); |
9095 if (!ast_context()->IsEffect()) Drop(1); | 9120 if (!ast_context()->IsEffect()) Drop(1); |
9096 ast_context()->ReturnValue(result); | 9121 ast_context()->ReturnValue(result); |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
9140 } | 9165 } |
9141 return false; | 9166 return false; |
9142 } | 9167 } |
9143 | 9168 |
9144 | 9169 |
9145 bool HOptimizedGraphBuilder::TryInlineApiFunctionCall(Call* expr, | 9170 bool HOptimizedGraphBuilder::TryInlineApiFunctionCall(Call* expr, |
9146 HValue* receiver) { | 9171 HValue* receiver) { |
9147 Handle<JSFunction> function = expr->target(); | 9172 Handle<JSFunction> function = expr->target(); |
9148 int argc = expr->arguments()->length(); | 9173 int argc = expr->arguments()->length(); |
9149 SmallMapList receiver_maps; | 9174 SmallMapList receiver_maps; |
9150 return TryInlineApiCall(function, | 9175 return TryInlineApiCall(function, receiver, &receiver_maps, argc, expr->id(), |
9151 receiver, | 9176 kCallApiFunction, expr->tail_call_mode()); |
9152 &receiver_maps, | |
9153 argc, | |
9154 expr->id(), | |
9155 kCallApiFunction); | |
9156 } | 9177 } |
9157 | 9178 |
9158 | 9179 |
9159 bool HOptimizedGraphBuilder::TryInlineApiMethodCall( | 9180 bool HOptimizedGraphBuilder::TryInlineApiMethodCall( |
9160 Call* expr, | 9181 Call* expr, |
9161 HValue* receiver, | 9182 HValue* receiver, |
9162 SmallMapList* receiver_maps) { | 9183 SmallMapList* receiver_maps) { |
9163 Handle<JSFunction> function = expr->target(); | 9184 Handle<JSFunction> function = expr->target(); |
9164 int argc = expr->arguments()->length(); | 9185 int argc = expr->arguments()->length(); |
9165 return TryInlineApiCall(function, | 9186 return TryInlineApiCall(function, receiver, receiver_maps, argc, expr->id(), |
9166 receiver, | 9187 kCallApiMethod, expr->tail_call_mode()); |
9167 receiver_maps, | |
9168 argc, | |
9169 expr->id(), | |
9170 kCallApiMethod); | |
9171 } | 9188 } |
9172 | 9189 |
9173 bool HOptimizedGraphBuilder::TryInlineApiGetter(Handle<Object> function, | 9190 bool HOptimizedGraphBuilder::TryInlineApiGetter(Handle<Object> function, |
9174 Handle<Map> receiver_map, | 9191 Handle<Map> receiver_map, |
9175 BailoutId ast_id) { | 9192 BailoutId ast_id) { |
9176 SmallMapList receiver_maps(1, zone()); | 9193 SmallMapList receiver_maps(1, zone()); |
9177 receiver_maps.Add(receiver_map, zone()); | 9194 receiver_maps.Add(receiver_map, zone()); |
9178 return TryInlineApiCall(function, | 9195 return TryInlineApiCall(function, |
9179 NULL, // Receiver is on expression stack. | 9196 NULL, // Receiver is on expression stack. |
9180 &receiver_maps, | 9197 &receiver_maps, 0, ast_id, kCallApiGetter, |
9181 0, | 9198 TailCallMode::kDisallow); |
9182 ast_id, | |
9183 kCallApiGetter); | |
9184 } | 9199 } |
9185 | 9200 |
9186 bool HOptimizedGraphBuilder::TryInlineApiSetter(Handle<Object> function, | 9201 bool HOptimizedGraphBuilder::TryInlineApiSetter(Handle<Object> function, |
9187 Handle<Map> receiver_map, | 9202 Handle<Map> receiver_map, |
9188 BailoutId ast_id) { | 9203 BailoutId ast_id) { |
9189 SmallMapList receiver_maps(1, zone()); | 9204 SmallMapList receiver_maps(1, zone()); |
9190 receiver_maps.Add(receiver_map, zone()); | 9205 receiver_maps.Add(receiver_map, zone()); |
9191 return TryInlineApiCall(function, | 9206 return TryInlineApiCall(function, |
9192 NULL, // Receiver is on expression stack. | 9207 NULL, // Receiver is on expression stack. |
9193 &receiver_maps, | 9208 &receiver_maps, 1, ast_id, kCallApiSetter, |
9194 1, | 9209 TailCallMode::kDisallow); |
9195 ast_id, | |
9196 kCallApiSetter); | |
9197 } | 9210 } |
9198 | 9211 |
9199 bool HOptimizedGraphBuilder::TryInlineApiCall(Handle<Object> function, | 9212 bool HOptimizedGraphBuilder::TryInlineApiCall( |
9200 HValue* receiver, | 9213 Handle<Object> function, HValue* receiver, SmallMapList* receiver_maps, |
9201 SmallMapList* receiver_maps, | 9214 int argc, BailoutId ast_id, ApiCallType call_type, |
9202 int argc, BailoutId ast_id, | 9215 TailCallMode syntactic_tail_call_mode) { |
9203 ApiCallType call_type) { | |
9204 if (function->IsJSFunction() && | 9216 if (function->IsJSFunction() && |
9205 Handle<JSFunction>::cast(function)->context()->native_context() != | 9217 Handle<JSFunction>::cast(function)->context()->native_context() != |
9206 top_info()->closure()->context()->native_context()) { | 9218 top_info()->closure()->context()->native_context()) { |
9207 return false; | 9219 return false; |
9208 } | 9220 } |
| 9221 if (syntactic_tail_call_mode == TailCallMode::kAllow) { |
| 9222 return false; |
| 9223 } |
9209 CallOptimization optimization(function); | 9224 CallOptimization optimization(function); |
9210 if (!optimization.is_simple_api_call()) return false; | 9225 if (!optimization.is_simple_api_call()) return false; |
9211 Handle<Map> holder_map; | 9226 Handle<Map> holder_map; |
9212 for (int i = 0; i < receiver_maps->length(); ++i) { | 9227 for (int i = 0; i < receiver_maps->length(); ++i) { |
9213 auto map = receiver_maps->at(i); | 9228 auto map = receiver_maps->at(i); |
9214 // Don't inline calls to receivers requiring accesschecks. | 9229 // Don't inline calls to receivers requiring accesschecks. |
9215 if (map->is_access_check_needed()) return false; | 9230 if (map->is_access_check_needed()) return false; |
9216 } | 9231 } |
9217 if (call_type == kCallApiFunction) { | 9232 if (call_type == kCallApiFunction) { |
9218 // Cannot embed a direct reference to the global proxy map | 9233 // Cannot embed a direct reference to the global proxy map |
(...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
9352 PrintF("\n"); | 9367 PrintF("\n"); |
9353 } | 9368 } |
9354 return; | 9369 return; |
9355 } | 9370 } |
9356 | 9371 |
9357 if (TryInlineIndirectCall(known_function, expr, args_count_no_receiver)) { | 9372 if (TryInlineIndirectCall(known_function, expr, args_count_no_receiver)) { |
9358 return; | 9373 return; |
9359 } | 9374 } |
9360 } | 9375 } |
9361 | 9376 |
| 9377 TailCallMode syntactic_tail_call_mode = expr->tail_call_mode(); |
| 9378 TailCallMode tail_call_mode = |
| 9379 function_state()->ComputeTailCallMode(syntactic_tail_call_mode); |
| 9380 USE(tail_call_mode); |
| 9381 |
| 9382 // TODO(ishell): use tail_call_mode here. |
9362 PushArgumentsFromEnvironment(arguments_count); | 9383 PushArgumentsFromEnvironment(arguments_count); |
9363 HInvokeFunction* call = | 9384 HInvokeFunction* call = |
9364 New<HInvokeFunction>(function, known_function, arguments_count); | 9385 New<HInvokeFunction>(function, known_function, arguments_count); |
9365 Drop(1); // Function | 9386 Drop(1); // Function |
9366 ast_context()->ReturnInstruction(call, expr->id()); | 9387 ast_context()->ReturnInstruction(call, expr->id()); |
9367 } | 9388 } |
9368 | 9389 |
9369 | 9390 |
9370 bool HOptimizedGraphBuilder::TryIndirectCall(Call* expr) { | 9391 bool HOptimizedGraphBuilder::TryIndirectCall(Call* expr) { |
9371 DCHECK(expr->expression()->IsProperty()); | 9392 DCHECK(expr->expression()->IsProperty()); |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
9406 ZoneList<Expression*>* args = expr->arguments(); | 9427 ZoneList<Expression*>* args = expr->arguments(); |
9407 CHECK_ALIVE(VisitForValue(args->at(0))); | 9428 CHECK_ALIVE(VisitForValue(args->at(0))); |
9408 HValue* receiver = Pop(); // receiver | 9429 HValue* receiver = Pop(); // receiver |
9409 HValue* function = Pop(); // f | 9430 HValue* function = Pop(); // f |
9410 Drop(1); // apply | 9431 Drop(1); // apply |
9411 | 9432 |
9412 Handle<Map> function_map = expr->GetReceiverTypes()->first(); | 9433 Handle<Map> function_map = expr->GetReceiverTypes()->first(); |
9413 HValue* checked_function = AddCheckMap(function, function_map); | 9434 HValue* checked_function = AddCheckMap(function, function_map); |
9414 | 9435 |
9415 if (function_state()->outer() == NULL) { | 9436 if (function_state()->outer() == NULL) { |
| 9437 TailCallMode syntactic_tail_call_mode = expr->tail_call_mode(); |
| 9438 TailCallMode tail_call_mode = |
| 9439 function_state()->ComputeTailCallMode(syntactic_tail_call_mode); |
| 9440 USE(tail_call_mode); |
| 9441 |
| 9442 // TODO(ishell): use tail_call_mode here. |
9416 HInstruction* elements = Add<HArgumentsElements>(false); | 9443 HInstruction* elements = Add<HArgumentsElements>(false); |
9417 HInstruction* length = Add<HArgumentsLength>(elements); | 9444 HInstruction* length = Add<HArgumentsLength>(elements); |
9418 HValue* wrapped_receiver = BuildWrapReceiver(receiver, checked_function); | 9445 HValue* wrapped_receiver = BuildWrapReceiver(receiver, checked_function); |
9419 HInstruction* result = New<HApplyArguments>(function, | 9446 HInstruction* result = New<HApplyArguments>(function, |
9420 wrapped_receiver, | 9447 wrapped_receiver, |
9421 length, | 9448 length, |
9422 elements); | 9449 elements); |
9423 ast_context()->ReturnInstruction(result, expr->id()); | 9450 ast_context()->ReturnInstruction(result, expr->id()); |
9424 } else { | 9451 } else { |
9425 // We are inside inlined function and we know exactly what is inside | 9452 // We are inside inlined function and we know exactly what is inside |
(...skipping 265 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
9691 return Bailout(kTailCall); | 9718 return Bailout(kTailCall); |
9692 } | 9719 } |
9693 DCHECK(!HasStackOverflow()); | 9720 DCHECK(!HasStackOverflow()); |
9694 DCHECK(current_block() != NULL); | 9721 DCHECK(current_block() != NULL); |
9695 DCHECK(current_block()->HasPredecessor()); | 9722 DCHECK(current_block()->HasPredecessor()); |
9696 if (!top_info()->is_tracking_positions()) SetSourcePosition(expr->position()); | 9723 if (!top_info()->is_tracking_positions()) SetSourcePosition(expr->position()); |
9697 Expression* callee = expr->expression(); | 9724 Expression* callee = expr->expression(); |
9698 int argument_count = expr->arguments()->length() + 1; // Plus receiver. | 9725 int argument_count = expr->arguments()->length() + 1; // Plus receiver. |
9699 HInstruction* call = NULL; | 9726 HInstruction* call = NULL; |
9700 | 9727 |
| 9728 TailCallMode syntactic_tail_call_mode = expr->tail_call_mode(); |
| 9729 TailCallMode tail_call_mode = |
| 9730 function_state()->ComputeTailCallMode(syntactic_tail_call_mode); |
| 9731 |
9701 Property* prop = callee->AsProperty(); | 9732 Property* prop = callee->AsProperty(); |
9702 if (prop != NULL) { | 9733 if (prop != NULL) { |
9703 CHECK_ALIVE(VisitForValue(prop->obj())); | 9734 CHECK_ALIVE(VisitForValue(prop->obj())); |
9704 HValue* receiver = Top(); | 9735 HValue* receiver = Top(); |
9705 | 9736 |
9706 SmallMapList* maps; | 9737 SmallMapList* maps; |
9707 ComputeReceiverTypes(expr, receiver, &maps, this); | 9738 ComputeReceiverTypes(expr, receiver, &maps, this); |
9708 | 9739 |
9709 if (prop->key()->IsPropertyName() && maps->length() > 0) { | 9740 if (prop->key()->IsPropertyName() && maps->length() > 0) { |
9710 Handle<String> name = prop->key()->AsLiteral()->AsPropertyName(); | 9741 Handle<String> name = prop->key()->AsLiteral()->AsPropertyName(); |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
9749 if (TryInlineApiMethodCall(expr, receiver, maps)) return; | 9780 if (TryInlineApiMethodCall(expr, receiver, maps)) return; |
9750 | 9781 |
9751 // Wrap the receiver if necessary. | 9782 // Wrap the receiver if necessary. |
9752 if (NeedsWrapping(maps->first(), known_function)) { | 9783 if (NeedsWrapping(maps->first(), known_function)) { |
9753 // Since HWrapReceiver currently cannot actually wrap numbers and | 9784 // Since HWrapReceiver currently cannot actually wrap numbers and |
9754 // strings, use the regular call builtin for method calls to wrap | 9785 // strings, use the regular call builtin for method calls to wrap |
9755 // the receiver. | 9786 // the receiver. |
9756 // TODO(verwaest): Support creation of value wrappers directly in | 9787 // TODO(verwaest): Support creation of value wrappers directly in |
9757 // HWrapReceiver. | 9788 // HWrapReceiver. |
9758 call = NewCallFunction(function, argument_count, | 9789 call = NewCallFunction(function, argument_count, |
9759 ConvertReceiverMode::kNotNullOrUndefined); | 9790 ConvertReceiverMode::kNotNullOrUndefined, |
| 9791 tail_call_mode); |
9760 } else if (TryInlineCall(expr)) { | 9792 } else if (TryInlineCall(expr)) { |
9761 return; | 9793 return; |
9762 } else { | 9794 } else { |
9763 call = NewCallConstantFunction(known_function, argument_count); | 9795 call = NewCallConstantFunction(known_function, argument_count, |
| 9796 tail_call_mode); |
9764 } | 9797 } |
9765 | 9798 |
9766 } else { | 9799 } else { |
9767 ArgumentsAllowedFlag arguments_flag = ARGUMENTS_NOT_ALLOWED; | 9800 ArgumentsAllowedFlag arguments_flag = ARGUMENTS_NOT_ALLOWED; |
9768 if (CanBeFunctionApplyArguments(expr) && expr->is_uninitialized()) { | 9801 if (CanBeFunctionApplyArguments(expr) && expr->is_uninitialized()) { |
9769 // We have to use EAGER deoptimization here because Deoptimizer::SOFT | 9802 // We have to use EAGER deoptimization here because Deoptimizer::SOFT |
9770 // gets ignored by the always-opt flag, which leads to incorrect code. | 9803 // gets ignored by the always-opt flag, which leads to incorrect code. |
9771 Add<HDeoptimize>( | 9804 Add<HDeoptimize>( |
9772 Deoptimizer::kInsufficientTypeFeedbackForCallWithArguments, | 9805 Deoptimizer::kInsufficientTypeFeedbackForCallWithArguments, |
9773 Deoptimizer::EAGER); | 9806 Deoptimizer::EAGER); |
9774 arguments_flag = ARGUMENTS_FAKED; | 9807 arguments_flag = ARGUMENTS_FAKED; |
9775 } | 9808 } |
9776 | 9809 |
9777 // Push the function under the receiver. | 9810 // Push the function under the receiver. |
9778 environment()->SetExpressionStackAt(0, function); | 9811 environment()->SetExpressionStackAt(0, function); |
9779 Push(receiver); | 9812 Push(receiver); |
9780 | 9813 |
9781 CHECK_ALIVE(VisitExpressions(expr->arguments(), arguments_flag)); | 9814 CHECK_ALIVE(VisitExpressions(expr->arguments(), arguments_flag)); |
9782 call = NewCallFunction(function, argument_count, | 9815 call = NewCallFunction(function, argument_count, |
9783 ConvertReceiverMode::kNotNullOrUndefined); | 9816 ConvertReceiverMode::kNotNullOrUndefined, |
| 9817 tail_call_mode); |
9784 } | 9818 } |
9785 PushArgumentsFromEnvironment(argument_count); | 9819 PushArgumentsFromEnvironment(argument_count); |
9786 | 9820 |
9787 } else { | 9821 } else { |
9788 VariableProxy* proxy = expr->expression()->AsVariableProxy(); | 9822 VariableProxy* proxy = expr->expression()->AsVariableProxy(); |
9789 if (proxy != NULL && proxy->var()->is_possibly_eval(isolate())) { | 9823 if (proxy != NULL && proxy->var()->is_possibly_eval(isolate())) { |
9790 return Bailout(kPossibleDirectCallToEval); | 9824 return Bailout(kPossibleDirectCallToEval); |
9791 } | 9825 } |
9792 | 9826 |
9793 // The function is on the stack in the unoptimized code during | 9827 // The function is on the stack in the unoptimized code during |
(...skipping 26 matching lines...) Expand all Loading... |
9820 expr->target()->ShortPrint(); | 9854 expr->target()->ShortPrint(); |
9821 PrintF("\n"); | 9855 PrintF("\n"); |
9822 } | 9856 } |
9823 return; | 9857 return; |
9824 } | 9858 } |
9825 if (TryInlineApiFunctionCall(expr, receiver)) return; | 9859 if (TryInlineApiFunctionCall(expr, receiver)) return; |
9826 if (TryHandleArrayCall(expr, function)) return; | 9860 if (TryHandleArrayCall(expr, function)) return; |
9827 if (TryInlineCall(expr)) return; | 9861 if (TryInlineCall(expr)) return; |
9828 | 9862 |
9829 PushArgumentsFromEnvironment(argument_count); | 9863 PushArgumentsFromEnvironment(argument_count); |
9830 call = NewCallConstantFunction(expr->target(), argument_count); | 9864 call = NewCallConstantFunction(expr->target(), argument_count, |
| 9865 tail_call_mode); |
9831 } else { | 9866 } else { |
9832 PushArgumentsFromEnvironment(argument_count); | 9867 PushArgumentsFromEnvironment(argument_count); |
9833 if (expr->is_uninitialized() && | 9868 if (expr->is_uninitialized() && |
9834 expr->IsUsingCallFeedbackICSlot(isolate())) { | 9869 expr->IsUsingCallFeedbackICSlot(isolate())) { |
9835 // We've never seen this call before, so let's have Crankshaft learn | 9870 // We've never seen this call before, so let's have Crankshaft learn |
9836 // through the type vector. | 9871 // through the type vector. |
9837 call = NewCallFunctionViaIC(function, argument_count, | 9872 call = NewCallFunctionViaIC(function, argument_count, |
9838 ConvertReceiverMode::kNullOrUndefined, | 9873 ConvertReceiverMode::kNullOrUndefined, |
9839 expr->CallFeedbackICSlot()); | 9874 tail_call_mode, expr->CallFeedbackICSlot()); |
9840 } else { | 9875 } else { |
9841 call = NewCallFunction(function, argument_count, | 9876 call = NewCallFunction(function, argument_count, |
9842 ConvertReceiverMode::kNullOrUndefined); | 9877 ConvertReceiverMode::kNullOrUndefined, |
| 9878 tail_call_mode); |
9843 } | 9879 } |
9844 } | 9880 } |
9845 } | 9881 } |
9846 | 9882 |
9847 Drop(1); // Drop the function. | 9883 Drop(1); // Drop the function. |
9848 return ast_context()->ReturnInstruction(call, expr->id()); | 9884 return ast_context()->ReturnInstruction(call, expr->id()); |
9849 } | 9885 } |
9850 | 9886 |
9851 | 9887 |
9852 void HOptimizedGraphBuilder::BuildInlinedCallArray( | 9888 void HOptimizedGraphBuilder::BuildInlinedCallArray( |
(...skipping 3617 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
13470 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); | 13506 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); |
13471 } | 13507 } |
13472 | 13508 |
13473 #ifdef DEBUG | 13509 #ifdef DEBUG |
13474 graph_->Verify(false); // No full verify. | 13510 graph_->Verify(false); // No full verify. |
13475 #endif | 13511 #endif |
13476 } | 13512 } |
13477 | 13513 |
13478 } // namespace internal | 13514 } // namespace internal |
13479 } // namespace v8 | 13515 } // namespace v8 |
OLD | NEW |