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 6557 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6568 int argument_count = 1; | 6568 int argument_count = 1; |
6569 if (!info->IsLoad()) { | 6569 if (!info->IsLoad()) { |
6570 argument_count = 2; | 6570 argument_count = 2; |
6571 Push(value); | 6571 Push(value); |
6572 } | 6572 } |
6573 | 6573 |
6574 if (info->accessor()->IsJSFunction() && | 6574 if (info->accessor()->IsJSFunction() && |
6575 info->NeedsWrappingFor(Handle<JSFunction>::cast(info->accessor()))) { | 6575 info->NeedsWrappingFor(Handle<JSFunction>::cast(info->accessor()))) { |
6576 HValue* function = Add<HConstant>(info->accessor()); | 6576 HValue* function = Add<HConstant>(info->accessor()); |
6577 PushArgumentsFromEnvironment(argument_count); | 6577 PushArgumentsFromEnvironment(argument_count); |
6578 return New<HCallFunction>(function, argument_count, | 6578 return NewCallFunction(function, argument_count, |
6579 ConvertReceiverMode::kNotNullOrUndefined); | 6579 ConvertReceiverMode::kNotNullOrUndefined); |
6580 } else if (FLAG_inline_accessors && can_inline_accessor) { | 6580 } else if (FLAG_inline_accessors && can_inline_accessor) { |
6581 bool success = info->IsLoad() | 6581 bool success = info->IsLoad() |
6582 ? TryInlineGetter(info->accessor(), info->map(), ast_id, return_id) | 6582 ? TryInlineGetter(info->accessor(), info->map(), ast_id, return_id) |
6583 : TryInlineSetter( | 6583 : TryInlineSetter( |
6584 info->accessor(), info->map(), ast_id, return_id, value); | 6584 info->accessor(), info->map(), ast_id, return_id, value); |
6585 if (success || HasStackOverflow()) return NULL; | 6585 if (success || HasStackOverflow()) return NULL; |
6586 } | 6586 } |
6587 | 6587 |
6588 PushArgumentsFromEnvironment(argument_count); | 6588 PushArgumentsFromEnvironment(argument_count); |
6589 if (!info->accessor()->IsJSFunction()) { | 6589 if (!info->accessor()->IsJSFunction()) { |
(...skipping 1392 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7982 | 7982 |
7983 | 7983 |
7984 void HOptimizedGraphBuilder::AddCheckPrototypeMaps(Handle<JSObject> holder, | 7984 void HOptimizedGraphBuilder::AddCheckPrototypeMaps(Handle<JSObject> holder, |
7985 Handle<Map> receiver_map) { | 7985 Handle<Map> receiver_map) { |
7986 if (!holder.is_null()) { | 7986 if (!holder.is_null()) { |
7987 Handle<JSObject> prototype(JSObject::cast(receiver_map->prototype())); | 7987 Handle<JSObject> prototype(JSObject::cast(receiver_map->prototype())); |
7988 BuildCheckPrototypeMaps(prototype, holder); | 7988 BuildCheckPrototypeMaps(prototype, holder); |
7989 } | 7989 } |
7990 } | 7990 } |
7991 | 7991 |
7992 | 7992 HInstruction* HOptimizedGraphBuilder::NewPlainFunctionCall(HValue* function, |
7993 HInstruction* HOptimizedGraphBuilder::NewPlainFunctionCall(HValue* fun, | |
7994 int argument_count) { | 7993 int argument_count) { |
7995 return New<HCallJSFunction>(fun, argument_count); | 7994 return New<HCallJSFunction>(function, argument_count); |
7996 } | 7995 } |
7997 | 7996 |
7998 | |
7999 HInstruction* HOptimizedGraphBuilder::NewArgumentAdaptorCall( | 7997 HInstruction* HOptimizedGraphBuilder::NewArgumentAdaptorCall( |
8000 HValue* fun, HValue* context, | 7998 HValue* function, int argument_count, HValue* expected_param_count) { |
8001 int argument_count, HValue* expected_param_count) { | 7999 HValue* context = Add<HLoadNamedField>( |
| 8000 function, nullptr, HObjectAccess::ForFunctionContextPointer()); |
8002 HValue* new_target = graph()->GetConstantUndefined(); | 8001 HValue* new_target = graph()->GetConstantUndefined(); |
8003 HValue* arity = Add<HConstant>(argument_count - 1); | 8002 HValue* arity = Add<HConstant>(argument_count - 1); |
8004 | 8003 |
8005 HValue* op_vals[] = {context, fun, new_target, arity, expected_param_count}; | 8004 HValue* op_vals[] = {context, function, new_target, arity, |
| 8005 expected_param_count}; |
8006 | 8006 |
8007 Callable callable = CodeFactory::ArgumentAdaptor(isolate()); | 8007 Callable callable = CodeFactory::ArgumentAdaptor(isolate()); |
8008 HConstant* stub = Add<HConstant>(callable.code()); | 8008 HConstant* stub = Add<HConstant>(callable.code()); |
8009 | 8009 |
8010 return New<HCallWithDescriptor>(stub, argument_count, callable.descriptor(), | 8010 return New<HCallWithDescriptor>(stub, argument_count, callable.descriptor(), |
8011 Vector<HValue*>(op_vals, arraysize(op_vals))); | 8011 Vector<HValue*>(op_vals, arraysize(op_vals))); |
8012 } | 8012 } |
8013 | 8013 |
| 8014 HInstruction* HOptimizedGraphBuilder::NewCallFunction( |
| 8015 HValue* function, int argument_count, ConvertReceiverMode convert_mode) { |
| 8016 HValue* arity = Add<HConstant>(argument_count - 1); |
| 8017 |
| 8018 HValue* op_vals[] = {context(), function, arity}; |
| 8019 |
| 8020 Callable callable = CodeFactory::Call(isolate(), convert_mode); |
| 8021 HConstant* stub = Add<HConstant>(callable.code()); |
| 8022 |
| 8023 return New<HCallWithDescriptor>(stub, argument_count, callable.descriptor(), |
| 8024 Vector<HValue*>(op_vals, arraysize(op_vals))); |
| 8025 } |
| 8026 |
| 8027 HInstruction* HOptimizedGraphBuilder::NewCallFunctionViaIC( |
| 8028 HValue* function, int argument_count, ConvertReceiverMode convert_mode, |
| 8029 FeedbackVectorSlot slot) { |
| 8030 int arity = argument_count - 1; |
| 8031 Handle<TypeFeedbackVector> vector(current_feedback_vector(), isolate()); |
| 8032 HValue* index_val = Add<HConstant>(vector->GetIndex(slot)); |
| 8033 HValue* vector_val = Add<HConstant>(vector); |
| 8034 |
| 8035 HValue* op_vals[] = {context(), function, index_val, vector_val}; |
| 8036 |
| 8037 Callable callable = CodeFactory::CallICInOptimizedCode( |
| 8038 isolate(), arity, ConvertReceiverMode::kNullOrUndefined); |
| 8039 HConstant* stub = Add<HConstant>(callable.code()); |
| 8040 |
| 8041 return New<HCallWithDescriptor>(stub, argument_count, callable.descriptor(), |
| 8042 Vector<HValue*>(op_vals, arraysize(op_vals))); |
| 8043 } |
8014 | 8044 |
8015 HInstruction* HOptimizedGraphBuilder::BuildCallConstantFunction( | 8045 HInstruction* HOptimizedGraphBuilder::BuildCallConstantFunction( |
8016 Handle<JSFunction> jsfun, int argument_count) { | 8046 Handle<JSFunction> jsfun, int argument_count) { |
8017 HValue* target = Add<HConstant>(jsfun); | 8047 HValue* target = Add<HConstant>(jsfun); |
8018 // For constant functions, we try to avoid calling the | 8048 // For constant functions, we try to avoid calling the |
8019 // argument adaptor and instead call the function directly | 8049 // argument adaptor and instead call the function directly |
8020 int formal_parameter_count = | 8050 int formal_parameter_count = |
8021 jsfun->shared()->internal_formal_parameter_count(); | 8051 jsfun->shared()->internal_formal_parameter_count(); |
8022 bool dont_adapt_arguments = | 8052 bool dont_adapt_arguments = |
8023 (formal_parameter_count == | 8053 (formal_parameter_count == |
8024 SharedFunctionInfo::kDontAdaptArgumentsSentinel); | 8054 SharedFunctionInfo::kDontAdaptArgumentsSentinel); |
8025 int arity = argument_count - 1; | 8055 int arity = argument_count - 1; |
8026 bool can_invoke_directly = | 8056 bool can_invoke_directly = |
8027 dont_adapt_arguments || formal_parameter_count == arity; | 8057 dont_adapt_arguments || formal_parameter_count == arity; |
8028 if (can_invoke_directly) { | 8058 if (can_invoke_directly) { |
8029 if (jsfun.is_identical_to(current_info()->closure())) { | 8059 if (jsfun.is_identical_to(current_info()->closure())) { |
8030 graph()->MarkRecursive(); | 8060 graph()->MarkRecursive(); |
8031 } | 8061 } |
8032 return NewPlainFunctionCall(target, argument_count); | 8062 return NewPlainFunctionCall(target, argument_count); |
8033 } else { | 8063 } else { |
8034 HValue* param_count_value = Add<HConstant>(formal_parameter_count); | 8064 HValue* param_count_value = Add<HConstant>(formal_parameter_count); |
8035 HValue* context = Add<HLoadNamedField>( | 8065 return NewArgumentAdaptorCall(target, argument_count, param_count_value); |
8036 target, nullptr, HObjectAccess::ForFunctionContextPointer()); | |
8037 return NewArgumentAdaptorCall(target, context, | |
8038 argument_count, param_count_value); | |
8039 } | 8066 } |
8040 UNREACHABLE(); | 8067 UNREACHABLE(); |
8041 return NULL; | 8068 return NULL; |
8042 } | 8069 } |
8043 | 8070 |
8044 | 8071 |
8045 class FunctionSorter { | 8072 class FunctionSorter { |
8046 public: | 8073 public: |
8047 explicit FunctionSorter(int index = 0, int ticks = 0, int size = 0) | 8074 explicit FunctionSorter(int index = 0, int ticks = 0, int size = 0) |
8048 : index_(index), ticks_(ticks), size_(size) {} | 8075 : index_(index), ticks_(ticks), size_(size) {} |
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8173 PrintF("Trying to inline the polymorphic call to %s from %s\n", | 8200 PrintF("Trying to inline the polymorphic call to %s from %s\n", |
8174 name->ToCString().get(), | 8201 name->ToCString().get(), |
8175 caller_name.get()); | 8202 caller_name.get()); |
8176 } | 8203 } |
8177 if (try_inline && TryInlineCall(expr)) { | 8204 if (try_inline && TryInlineCall(expr)) { |
8178 // Trying to inline will signal that we should bailout from the | 8205 // Trying to inline will signal that we should bailout from the |
8179 // entire compilation by setting stack overflow on the visitor. | 8206 // entire compilation by setting stack overflow on the visitor. |
8180 if (HasStackOverflow()) return; | 8207 if (HasStackOverflow()) return; |
8181 } else { | 8208 } else { |
8182 // Since HWrapReceiver currently cannot actually wrap numbers and strings, | 8209 // Since HWrapReceiver currently cannot actually wrap numbers and strings, |
8183 // use the regular CallFunctionStub for method calls to wrap the receiver. | 8210 // use the regular call builtin for method calls to wrap the receiver. |
8184 // TODO(verwaest): Support creation of value wrappers directly in | 8211 // TODO(verwaest): Support creation of value wrappers directly in |
8185 // HWrapReceiver. | 8212 // HWrapReceiver. |
8186 HInstruction* call = | 8213 HInstruction* call = |
8187 needs_wrapping ? NewUncasted<HCallFunction>( | 8214 needs_wrapping |
8188 function, argument_count, | 8215 ? NewCallFunction(function, argument_count, |
8189 ConvertReceiverMode::kNotNullOrUndefined) | 8216 ConvertReceiverMode::kNotNullOrUndefined) |
8190 : BuildCallConstantFunction(target, argument_count); | 8217 : BuildCallConstantFunction(target, argument_count); |
8191 PushArgumentsFromEnvironment(argument_count); | 8218 PushArgumentsFromEnvironment(argument_count); |
8192 AddInstruction(call); | 8219 AddInstruction(call); |
8193 Drop(1); // Drop the function. | 8220 Drop(1); // Drop the function. |
8194 if (!ast_context()->IsEffect()) Push(call); | 8221 if (!ast_context()->IsEffect()) Push(call); |
8195 } | 8222 } |
8196 | 8223 |
8197 if (current_block() != NULL) Goto(join); | 8224 if (current_block() != NULL) Goto(join); |
8198 set_current_block(if_false); | 8225 set_current_block(if_false); |
8199 } | 8226 } |
8200 | 8227 |
8201 // Finish up. Unconditionally deoptimize if we've handled all the maps we | 8228 // Finish up. Unconditionally deoptimize if we've handled all the maps we |
8202 // know about and do not want to handle ones we've never seen. Otherwise | 8229 // know about and do not want to handle ones we've never seen. Otherwise |
8203 // use a generic IC. | 8230 // use a generic IC. |
8204 if (ordered_functions == maps->length() && FLAG_deoptimize_uncommon_cases) { | 8231 if (ordered_functions == maps->length() && FLAG_deoptimize_uncommon_cases) { |
8205 FinishExitWithHardDeoptimization(Deoptimizer::kUnknownMapInPolymorphicCall); | 8232 FinishExitWithHardDeoptimization(Deoptimizer::kUnknownMapInPolymorphicCall); |
8206 } else { | 8233 } else { |
8207 Property* prop = expr->expression()->AsProperty(); | 8234 Property* prop = expr->expression()->AsProperty(); |
8208 HInstruction* function = | 8235 HInstruction* function = |
8209 BuildNamedGeneric(LOAD, prop, prop->PropertyFeedbackSlot(), receiver, | 8236 BuildNamedGeneric(LOAD, prop, prop->PropertyFeedbackSlot(), receiver, |
8210 name, NULL, prop->IsUninitialized()); | 8237 name, NULL, prop->IsUninitialized()); |
8211 AddInstruction(function); | 8238 AddInstruction(function); |
8212 Push(function); | 8239 Push(function); |
8213 AddSimulate(prop->LoadId(), REMOVABLE_SIMULATE); | 8240 AddSimulate(prop->LoadId(), REMOVABLE_SIMULATE); |
8214 | 8241 |
8215 environment()->SetExpressionStackAt(1, function); | 8242 environment()->SetExpressionStackAt(1, function); |
8216 environment()->SetExpressionStackAt(0, receiver); | 8243 environment()->SetExpressionStackAt(0, receiver); |
8217 CHECK_ALIVE(VisitExpressions(expr->arguments())); | 8244 CHECK_ALIVE(VisitExpressions(expr->arguments())); |
8218 | 8245 |
8219 HInstruction* call = New<HCallFunction>( | 8246 HInstruction* call = NewCallFunction( |
8220 function, argument_count, ConvertReceiverMode::kNotNullOrUndefined); | 8247 function, argument_count, ConvertReceiverMode::kNotNullOrUndefined); |
8221 | 8248 |
8222 PushArgumentsFromEnvironment(argument_count); | 8249 PushArgumentsFromEnvironment(argument_count); |
8223 | 8250 |
8224 Drop(1); // Function. | 8251 Drop(1); // Function. |
8225 | 8252 |
8226 if (join != NULL) { | 8253 if (join != NULL) { |
8227 AddInstruction(call); | 8254 AddInstruction(call); |
8228 if (!ast_context()->IsEffect()) Push(call); | 8255 if (!ast_context()->IsEffect()) Push(call); |
8229 Goto(join); | 8256 Goto(join); |
(...skipping 1513 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
9743 known_function->ShortPrint(); | 9770 known_function->ShortPrint(); |
9744 PrintF("\n"); | 9771 PrintF("\n"); |
9745 } | 9772 } |
9746 return; | 9773 return; |
9747 } | 9774 } |
9748 if (TryInlineApiMethodCall(expr, receiver, maps)) return; | 9775 if (TryInlineApiMethodCall(expr, receiver, maps)) return; |
9749 | 9776 |
9750 // Wrap the receiver if necessary. | 9777 // Wrap the receiver if necessary. |
9751 if (NeedsWrapping(maps->first(), known_function)) { | 9778 if (NeedsWrapping(maps->first(), known_function)) { |
9752 // Since HWrapReceiver currently cannot actually wrap numbers and | 9779 // Since HWrapReceiver currently cannot actually wrap numbers and |
9753 // strings, use the regular CallFunctionStub for method calls to wrap | 9780 // strings, use the regular call builtin for method calls to wrap |
9754 // the receiver. | 9781 // the receiver. |
9755 // TODO(verwaest): Support creation of value wrappers directly in | 9782 // TODO(verwaest): Support creation of value wrappers directly in |
9756 // HWrapReceiver. | 9783 // HWrapReceiver. |
9757 call = New<HCallFunction>(function, argument_count, | 9784 call = NewCallFunction(function, argument_count, |
9758 ConvertReceiverMode::kNotNullOrUndefined); | 9785 ConvertReceiverMode::kNotNullOrUndefined); |
9759 } else if (TryInlineCall(expr)) { | 9786 } else if (TryInlineCall(expr)) { |
9760 return; | 9787 return; |
9761 } else { | 9788 } else { |
9762 call = BuildCallConstantFunction(known_function, argument_count); | 9789 call = BuildCallConstantFunction(known_function, argument_count); |
9763 } | 9790 } |
9764 | 9791 |
9765 } else { | 9792 } else { |
9766 ArgumentsAllowedFlag arguments_flag = ARGUMENTS_NOT_ALLOWED; | 9793 ArgumentsAllowedFlag arguments_flag = ARGUMENTS_NOT_ALLOWED; |
9767 if (CanBeFunctionApplyArguments(expr) && expr->is_uninitialized()) { | 9794 if (CanBeFunctionApplyArguments(expr) && expr->is_uninitialized()) { |
9768 // We have to use EAGER deoptimization here because Deoptimizer::SOFT | 9795 // We have to use EAGER deoptimization here because Deoptimizer::SOFT |
9769 // gets ignored by the always-opt flag, which leads to incorrect code. | 9796 // gets ignored by the always-opt flag, which leads to incorrect code. |
9770 Add<HDeoptimize>( | 9797 Add<HDeoptimize>( |
9771 Deoptimizer::kInsufficientTypeFeedbackForCallWithArguments, | 9798 Deoptimizer::kInsufficientTypeFeedbackForCallWithArguments, |
9772 Deoptimizer::EAGER); | 9799 Deoptimizer::EAGER); |
9773 arguments_flag = ARGUMENTS_FAKED; | 9800 arguments_flag = ARGUMENTS_FAKED; |
9774 } | 9801 } |
9775 | 9802 |
9776 // Push the function under the receiver. | 9803 // Push the function under the receiver. |
9777 environment()->SetExpressionStackAt(0, function); | 9804 environment()->SetExpressionStackAt(0, function); |
9778 Push(receiver); | 9805 Push(receiver); |
9779 | 9806 |
9780 CHECK_ALIVE(VisitExpressions(expr->arguments(), arguments_flag)); | 9807 CHECK_ALIVE(VisitExpressions(expr->arguments(), arguments_flag)); |
9781 call = New<HCallFunction>(function, argument_count, | 9808 call = NewCallFunction(function, argument_count, |
9782 ConvertReceiverMode::kNotNullOrUndefined); | 9809 ConvertReceiverMode::kNotNullOrUndefined); |
9783 } | 9810 } |
9784 PushArgumentsFromEnvironment(argument_count); | 9811 PushArgumentsFromEnvironment(argument_count); |
9785 | 9812 |
9786 } else { | 9813 } else { |
9787 VariableProxy* proxy = expr->expression()->AsVariableProxy(); | 9814 VariableProxy* proxy = expr->expression()->AsVariableProxy(); |
9788 if (proxy != NULL && proxy->var()->is_possibly_eval(isolate())) { | 9815 if (proxy != NULL && proxy->var()->is_possibly_eval(isolate())) { |
9789 return Bailout(kPossibleDirectCallToEval); | 9816 return Bailout(kPossibleDirectCallToEval); |
9790 } | 9817 } |
9791 | 9818 |
9792 // The function is on the stack in the unoptimized code during | 9819 // The function is on the stack in the unoptimized code during |
(...skipping 29 matching lines...) Expand all Loading... |
9822 return; | 9849 return; |
9823 } | 9850 } |
9824 if (TryInlineApiFunctionCall(expr, receiver)) return; | 9851 if (TryInlineApiFunctionCall(expr, receiver)) return; |
9825 if (TryHandleArrayCall(expr, function)) return; | 9852 if (TryHandleArrayCall(expr, function)) return; |
9826 if (TryInlineCall(expr)) return; | 9853 if (TryInlineCall(expr)) return; |
9827 | 9854 |
9828 PushArgumentsFromEnvironment(argument_count); | 9855 PushArgumentsFromEnvironment(argument_count); |
9829 call = BuildCallConstantFunction(expr->target(), argument_count); | 9856 call = BuildCallConstantFunction(expr->target(), argument_count); |
9830 } else { | 9857 } else { |
9831 PushArgumentsFromEnvironment(argument_count); | 9858 PushArgumentsFromEnvironment(argument_count); |
9832 HCallFunction* call_function = New<HCallFunction>( | |
9833 function, argument_count, ConvertReceiverMode::kNullOrUndefined); | |
9834 call = call_function; | |
9835 if (expr->is_uninitialized() && | 9859 if (expr->is_uninitialized() && |
9836 expr->IsUsingCallFeedbackICSlot(isolate())) { | 9860 expr->IsUsingCallFeedbackICSlot(isolate())) { |
9837 // We've never seen this call before, so let's have Crankshaft learn | 9861 // We've never seen this call before, so let's have Crankshaft learn |
9838 // through the type vector. | 9862 // through the type vector. |
9839 Handle<TypeFeedbackVector> vector = | 9863 call = NewCallFunctionViaIC(function, argument_count, |
9840 handle(current_feedback_vector(), isolate()); | 9864 ConvertReceiverMode::kNullOrUndefined, |
9841 FeedbackVectorSlot slot = expr->CallFeedbackICSlot(); | 9865 expr->CallFeedbackICSlot()); |
9842 call_function->SetVectorAndSlot(vector, slot); | 9866 } else { |
| 9867 call = NewCallFunction(function, argument_count, |
| 9868 ConvertReceiverMode::kNullOrUndefined); |
9843 } | 9869 } |
9844 } | 9870 } |
9845 } | 9871 } |
9846 | 9872 |
9847 Drop(1); // Drop the function. | 9873 Drop(1); // Drop the function. |
9848 return ast_context()->ReturnInstruction(call, expr->id()); | 9874 return ast_context()->ReturnInstruction(call, expr->id()); |
9849 } | 9875 } |
9850 | 9876 |
9851 | 9877 |
9852 void HOptimizedGraphBuilder::BuildInlinedCallArray( | 9878 void HOptimizedGraphBuilder::BuildInlinedCallArray( |
(...skipping 3618 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
13471 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); | 13497 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); |
13472 } | 13498 } |
13473 | 13499 |
13474 #ifdef DEBUG | 13500 #ifdef DEBUG |
13475 graph_->Verify(false); // No full verify. | 13501 graph_->Verify(false); // No full verify. |
13476 #endif | 13502 #endif |
13477 } | 13503 } |
13478 | 13504 |
13479 } // namespace internal | 13505 } // namespace internal |
13480 } // namespace v8 | 13506 } // namespace v8 |
OLD | NEW |