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

Side by Side Diff: src/hydrogen.cc

Issue 335683002: Optimize Function.prototype.call (Closed) Base URL: https://github.com/v8/v8.git@master
Patch Set: Call the correct functions Created 6 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/hydrogen.h ('k') | src/objects.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2013 the V8 project authors. All rights reserved. 1 // Copyright 2013 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "src/hydrogen.h" 5 #include "src/hydrogen.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 8
9 #include "src/v8.h" 9 #include "src/v8.h"
10 #include "src/allocation-site-scopes.h" 10 #include "src/allocation-site-scopes.h"
(...skipping 7905 matching lines...) Expand 10 before | Expand all | Expand 10 after
7916 if (TryInlineApiSetter(setter, receiver_map, id)) return true; 7916 if (TryInlineApiSetter(setter, receiver_map, id)) return true;
7917 return TryInline(setter, 7917 return TryInline(setter,
7918 1, 7918 1,
7919 implicit_return_value, 7919 implicit_return_value,
7920 id, assignment_id, 7920 id, assignment_id,
7921 SETTER_CALL_RETURN, 7921 SETTER_CALL_RETURN,
7922 source_position()); 7922 source_position());
7923 } 7923 }
7924 7924
7925 7925
7926 bool HOptimizedGraphBuilder::TryInlineApply(Handle<JSFunction> function, 7926 bool HOptimizedGraphBuilder::TryInlineIndirectCall(Handle<JSFunction> function,
7927 Call* expr, 7927 Call* expr,
7928 int arguments_count) { 7928 int arguments_count) {
7929 return TryInline(function, 7929 return TryInline(function,
7930 arguments_count, 7930 arguments_count,
7931 NULL, 7931 NULL,
7932 expr->id(), 7932 expr->id(),
7933 expr->ReturnId(), 7933 expr->ReturnId(),
7934 NORMAL_RETURN, 7934 NORMAL_RETURN,
7935 ScriptPositionToSourcePosition(expr->position())); 7935 ScriptPositionToSourcePosition(expr->position()));
7936 } 7936 }
7937 7937
7938 7938
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
7970 default: 7970 default:
7971 // Not supported for inlining yet. 7971 // Not supported for inlining yet.
7972 break; 7972 break;
7973 } 7973 }
7974 return false; 7974 return false;
7975 } 7975 }
7976 7976
7977 7977
7978 bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall( 7978 bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall(
7979 Call* expr, 7979 Call* expr,
7980 HValue* receiver, 7980 Handle<JSFunction> function,
7981 Handle<Map> receiver_map) { 7981 Handle<Map> receiver_map,
7982 int args_count_no_receiver) {
7983 if (!function->shared()->HasBuiltinFunctionId()) return false;
7984 BuiltinFunctionId id = function->shared()->builtin_function_id();
7985 int argument_count = args_count_no_receiver + 1; // Plus receiver.
7986
7987 if (receiver_map.is_null()) {
7988 HValue* receiver = environment()->ExpressionStackAt(args_count_no_receiver);
7989 if (receiver->IsConstant() &&
7990 HConstant::cast(receiver)->handle(isolate())->IsHeapObject()) {
7991 receiver_map = handle(Handle<HeapObject>::cast(
7992 HConstant::cast(receiver)->handle(isolate()))->map());
7993 }
7994 }
7982 // Try to inline calls like Math.* as operations in the calling function. 7995 // Try to inline calls like Math.* as operations in the calling function.
7983 if (!expr->target()->shared()->HasBuiltinFunctionId()) return false;
7984 BuiltinFunctionId id = expr->target()->shared()->builtin_function_id();
7985 int argument_count = expr->arguments()->length() + 1; // Plus receiver.
7986 switch (id) { 7996 switch (id) {
7987 case kStringCharCodeAt: 7997 case kStringCharCodeAt:
7988 case kStringCharAt: 7998 case kStringCharAt:
7989 if (argument_count == 2) { 7999 if (argument_count == 2) {
7990 HValue* index = Pop(); 8000 HValue* index = Pop();
7991 HValue* string = Pop(); 8001 HValue* string = Pop();
7992 Drop(1); // Function. 8002 Drop(1); // Function.
7993 HInstruction* char_code = 8003 HInstruction* char_code =
7994 BuildStringCharCodeAt(string, index); 8004 BuildStringCharCodeAt(string, index);
7995 if (id == kStringCharCodeAt) { 8005 if (id == kStringCharCodeAt) {
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after
8083 } 8093 }
8084 break; 8094 break;
8085 case kArrayPop: { 8095 case kArrayPop: {
8086 if (receiver_map.is_null()) return false; 8096 if (receiver_map.is_null()) return false;
8087 if (receiver_map->instance_type() != JS_ARRAY_TYPE) return false; 8097 if (receiver_map->instance_type() != JS_ARRAY_TYPE) return false;
8088 ElementsKind elements_kind = receiver_map->elements_kind(); 8098 ElementsKind elements_kind = receiver_map->elements_kind();
8089 if (!IsFastElementsKind(elements_kind)) return false; 8099 if (!IsFastElementsKind(elements_kind)) return false;
8090 if (receiver_map->is_observed()) return false; 8100 if (receiver_map->is_observed()) return false;
8091 ASSERT(receiver_map->is_extensible()); 8101 ASSERT(receiver_map->is_extensible());
8092 8102
8093 Drop(expr->arguments()->length()); 8103 Drop(args_count_no_receiver);
8094 HValue* result; 8104 HValue* result;
8095 HValue* reduced_length; 8105 HValue* reduced_length;
8096 HValue* receiver = Pop(); 8106 HValue* receiver = Pop();
8097 8107
8098 HValue* checked_object = AddCheckMap(receiver, receiver_map); 8108 HValue* checked_object = AddCheckMap(receiver, receiver_map);
8099 HValue* length = Add<HLoadNamedField>( 8109 HValue* length = Add<HLoadNamedField>(
8100 checked_object, static_cast<HValue*>(NULL), 8110 checked_object, static_cast<HValue*>(NULL),
8101 HObjectAccess::ForArrayLength(elements_kind)); 8111 HObjectAccess::ForArrayLength(elements_kind));
8102 8112
8103 Drop(1); // Function. 8113 Drop(1); // Function.
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
8159 // inlined version can't be used. 8169 // inlined version can't be used.
8160 if (receiver_map->DictionaryElementsInPrototypeChainOnly()) return false; 8170 if (receiver_map->DictionaryElementsInPrototypeChainOnly()) return false;
8161 // If there currently can be no elements accessors on the prototype chain, 8171 // If there currently can be no elements accessors on the prototype chain,
8162 // it doesn't mean that there won't be any later. Install a full prototype 8172 // it doesn't mean that there won't be any later. Install a full prototype
8163 // chain check to trap element accessors being installed on the prototype 8173 // chain check to trap element accessors being installed on the prototype
8164 // chain, which would cause elements to go to dictionary mode and result 8174 // chain, which would cause elements to go to dictionary mode and result
8165 // in a map change. 8175 // in a map change.
8166 Handle<JSObject> prototype(JSObject::cast(receiver_map->prototype())); 8176 Handle<JSObject> prototype(JSObject::cast(receiver_map->prototype()));
8167 BuildCheckPrototypeMaps(prototype, Handle<JSObject>()); 8177 BuildCheckPrototypeMaps(prototype, Handle<JSObject>());
8168 8178
8169 const int argc = expr->arguments()->length(); 8179 const int argc = args_count_no_receiver;
8170 if (argc != 1) return false; 8180 if (argc != 1) return false;
8171 8181
8172 HValue* value_to_push = Pop(); 8182 HValue* value_to_push = Pop();
8173 HValue* array = Pop(); 8183 HValue* array = Pop();
8174 Drop(1); // Drop function. 8184 Drop(1); // Drop function.
8175 8185
8176 HInstruction* new_size = NULL; 8186 HInstruction* new_size = NULL;
8177 HValue* length = NULL; 8187 HValue* length = NULL;
8178 8188
8179 { 8189 {
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
8216 // chain check to trap element accessors being installed on the prototype 8226 // chain check to trap element accessors being installed on the prototype
8217 // chain, which would cause elements to go to dictionary mode and result 8227 // chain, which would cause elements to go to dictionary mode and result
8218 // in a map change. 8228 // in a map change.
8219 BuildCheckPrototypeMaps( 8229 BuildCheckPrototypeMaps(
8220 handle(JSObject::cast(receiver_map->prototype()), isolate()), 8230 handle(JSObject::cast(receiver_map->prototype()), isolate()),
8221 Handle<JSObject>::null()); 8231 Handle<JSObject>::null());
8222 8232
8223 // Threshold for fast inlined Array.shift(). 8233 // Threshold for fast inlined Array.shift().
8224 HConstant* inline_threshold = Add<HConstant>(static_cast<int32_t>(16)); 8234 HConstant* inline_threshold = Add<HConstant>(static_cast<int32_t>(16));
8225 8235
8226 Drop(expr->arguments()->length()); 8236 Drop(args_count_no_receiver);
8227 HValue* receiver = Pop(); 8237 HValue* receiver = Pop();
8228 HValue* function = Pop(); 8238 HValue* function = Pop();
8229 HValue* result; 8239 HValue* result;
8230 8240
8231 { 8241 {
8232 NoObservableSideEffectsScope scope(this); 8242 NoObservableSideEffectsScope scope(this);
8233 8243
8234 HValue* length = Add<HLoadNamedField>( 8244 HValue* length = Add<HLoadNamedField>(
8235 receiver, static_cast<HValue*>(NULL), 8245 receiver, static_cast<HValue*>(NULL),
8236 HObjectAccess::ForArrayLength(kind)); 8246 HObjectAccess::ForArrayLength(kind));
(...skipping 290 matching lines...) Expand 10 before | Expand all | Expand 10 after
8527 HInstruction* call = New<HCallWithDescriptor>( 8537 HInstruction* call = New<HCallWithDescriptor>(
8528 code_value, argc + 1, descriptor, 8538 code_value, argc + 1, descriptor,
8529 Vector<HValue*>(op_vals, descriptor->environment_length())); 8539 Vector<HValue*>(op_vals, descriptor->environment_length()));
8530 8540
8531 if (drop_extra) Drop(1); // Drop function. 8541 if (drop_extra) Drop(1); // Drop function.
8532 ast_context()->ReturnInstruction(call, ast_id); 8542 ast_context()->ReturnInstruction(call, ast_id);
8533 return true; 8543 return true;
8534 } 8544 }
8535 8545
8536 8546
8537 bool HOptimizedGraphBuilder::TryCallApply(Call* expr) { 8547 void HOptimizedGraphBuilder::HandleIndirectCall(Call* expr,
8548 HValue* function,
8549 int arguments_count) {
8550 Handle<JSFunction> known_function;
8551 int args_count_no_receiver = arguments_count - 1;
8552 if (function->IsConstant() &&
8553 HConstant::cast(function)->handle(isolate())->IsJSFunction()) {
8554 known_function = Handle<JSFunction>::cast(
8555 HConstant::cast(function)->handle(isolate()));
8556 if (TryInlineIndirectCall(known_function, expr, args_count_no_receiver)) {
8557 return;
8558 }
8559
8560 Handle<Map> map;
8561 if (TryInlineBuiltinMethodCall(expr, known_function, map,
8562 args_count_no_receiver)) {
8563 if (FLAG_trace_inlining) {
8564 PrintF("Inlining builtin ");
8565 known_function->ShortPrint();
8566 PrintF("\n");
8567 }
8568 return;
8569 }
8570 }
8571
8572 PushArgumentsFromEnvironment(arguments_count);
8573 HInvokeFunction* call = New<HInvokeFunction>(
8574 function, known_function, arguments_count);
8575 Drop(1); // Function
8576 ast_context()->ReturnInstruction(call, expr->id());
8577 }
8578
8579
8580 bool HOptimizedGraphBuilder::TryIndirectCall(Call* expr) {
8538 ASSERT(expr->expression()->IsProperty()); 8581 ASSERT(expr->expression()->IsProperty());
8539 8582
8540 if (!expr->IsMonomorphic()) { 8583 if (!expr->IsMonomorphic()) {
8541 return false; 8584 return false;
8542 } 8585 }
8586
8543 Handle<Map> function_map = expr->GetReceiverTypes()->first(); 8587 Handle<Map> function_map = expr->GetReceiverTypes()->first();
8544 if (function_map->instance_type() != JS_FUNCTION_TYPE || 8588 if (function_map->instance_type() != JS_FUNCTION_TYPE ||
8545 !expr->target()->shared()->HasBuiltinFunctionId() || 8589 !expr->target()->shared()->HasBuiltinFunctionId()) {
8546 expr->target()->shared()->builtin_function_id() != kFunctionApply) {
8547 return false; 8590 return false;
8548 } 8591 }
8549 8592
8550 if (current_info()->scope()->arguments() == NULL) return false; 8593 switch (expr->target()->shared()->builtin_function_id()) {
8594 case kFunctionCall: {
8595 BuildFunctionCall(expr);
8596 return true;
8597 }
8598 case kFunctionApply: {
8599 // For .apply, only the pattern f.apply(receiver, arguments)
8600 // is supported.
8601 if (current_info()->scope()->arguments() == NULL) return false;
8551 8602
8603 ZoneList<Expression*>* args = expr->arguments();
8604 if (args->length() != 2) return false;
8605
8606 VariableProxy* arg_two = args->at(1)->AsVariableProxy();
8607 if (arg_two == NULL || !arg_two->var()->IsStackAllocated()) return false;
8608 HValue* arg_two_value = LookupAndMakeLive(arg_two->var());
8609 if (!arg_two_value->CheckFlag(HValue::kIsArguments)) return false;
8610 BuildFunctionApply(expr);
8611 return true;
8612 }
8613 default: {
8614 return false;
8615 }
8616 }
8617 UNREACHABLE();
8618 }
8619
8620
8621 void HOptimizedGraphBuilder::BuildFunctionApply(Call* expr) {
8552 ZoneList<Expression*>* args = expr->arguments(); 8622 ZoneList<Expression*>* args = expr->arguments();
8553 if (args->length() != 2) return false; 8623 CHECK_ALIVE(VisitForValue(args->at(0)));
8554
8555 VariableProxy* arg_two = args->at(1)->AsVariableProxy();
8556 if (arg_two == NULL || !arg_two->var()->IsStackAllocated()) return false;
8557 HValue* arg_two_value = LookupAndMakeLive(arg_two->var());
8558 if (!arg_two_value->CheckFlag(HValue::kIsArguments)) return false;
8559
8560 // Found pattern f.apply(receiver, arguments).
8561 CHECK_ALIVE_OR_RETURN(VisitForValue(args->at(0)), true);
8562 HValue* receiver = Pop(); // receiver 8624 HValue* receiver = Pop(); // receiver
8563 HValue* function = Pop(); // f 8625 HValue* function = Pop(); // f
8564 Drop(1); // apply 8626 Drop(1); // apply
8565 8627
8566 if (function_state()->outer() == NULL) { 8628 if (function_state()->outer() == NULL) {
8567 HInstruction* elements = Add<HArgumentsElements>(false); 8629 HInstruction* elements = Add<HArgumentsElements>(false);
8568 HInstruction* length = Add<HArgumentsLength>(elements); 8630 HInstruction* length = Add<HArgumentsLength>(elements);
8569 HValue* wrapped_receiver = BuildWrapReceiver(receiver, function); 8631 HValue* wrapped_receiver = BuildWrapReceiver(receiver, function);
8570 HInstruction* result = New<HApplyArguments>(function, 8632 HInstruction* result = New<HApplyArguments>(function,
8571 wrapped_receiver, 8633 wrapped_receiver,
8572 length, 8634 length,
8573 elements); 8635 elements);
8574 ast_context()->ReturnInstruction(result, expr->id()); 8636 ast_context()->ReturnInstruction(result, expr->id());
8575 return true;
8576 } else { 8637 } else {
8577 // We are inside inlined function and we know exactly what is inside 8638 // We are inside inlined function and we know exactly what is inside
8578 // arguments object. But we need to be able to materialize at deopt. 8639 // arguments object. But we need to be able to materialize at deopt.
8579 ASSERT_EQ(environment()->arguments_environment()->parameter_count(), 8640 ASSERT_EQ(environment()->arguments_environment()->parameter_count(),
8580 function_state()->entry()->arguments_object()->arguments_count()); 8641 function_state()->entry()->arguments_object()->arguments_count());
8581 HArgumentsObject* args = function_state()->entry()->arguments_object(); 8642 HArgumentsObject* args = function_state()->entry()->arguments_object();
8582 const ZoneList<HValue*>* arguments_values = args->arguments_values(); 8643 const ZoneList<HValue*>* arguments_values = args->arguments_values();
8583 int arguments_count = arguments_values->length(); 8644 int arguments_count = arguments_values->length();
8584 Push(function); 8645 Push(function);
8585 Push(BuildWrapReceiver(receiver, function)); 8646 Push(BuildWrapReceiver(receiver, function));
8586 for (int i = 1; i < arguments_count; i++) { 8647 for (int i = 1; i < arguments_count; i++) {
8587 Push(arguments_values->at(i)); 8648 Push(arguments_values->at(i));
8588 } 8649 }
8589 8650 HandleIndirectCall(expr, function, arguments_count);
8590 Handle<JSFunction> known_function;
8591 if (function->IsConstant() &&
8592 HConstant::cast(function)->handle(isolate())->IsJSFunction()) {
8593 known_function = Handle<JSFunction>::cast(
8594 HConstant::cast(function)->handle(isolate()));
8595 int args_count = arguments_count - 1; // Excluding receiver.
8596 if (TryInlineApply(known_function, expr, args_count)) return true;
8597 }
8598
8599 PushArgumentsFromEnvironment(arguments_count);
8600 HInvokeFunction* call = New<HInvokeFunction>(
8601 function, known_function, arguments_count);
8602 Drop(1); // Function.
8603 ast_context()->ReturnInstruction(call, expr->id());
8604 return true;
8605 } 8651 }
8606 } 8652 }
8607 8653
8608 8654
8655 // f.call(...)
8656 void HOptimizedGraphBuilder::BuildFunctionCall(Call* expr) {
8657 HValue* function = Pop(); // f
8658 HValue* receiver;
8659 ZoneList<Expression*>* args = expr->arguments();
8660 int args_length = args->length();
8661 Drop(1); // call
8662
8663 if (args_length == 0) {
8664 receiver = graph()->GetConstantUndefined();
8665 args_length = 1;
8666 } else {
8667 CHECK_ALIVE(VisitForValue(args->at(0)));
8668 receiver = Pop();
8669 }
8670 receiver = BuildWrapReceiver(receiver, function);
8671
8672 Push(function);
8673 Push(receiver);
8674 for (int i = 1; i < args_length; i++) {
8675 CHECK_ALIVE(VisitForValue(args->at(i)));
8676 }
8677 HandleIndirectCall(expr, function, args_length);
8678 }
8679
8680
8609 HValue* HOptimizedGraphBuilder::ImplicitReceiverFor(HValue* function, 8681 HValue* HOptimizedGraphBuilder::ImplicitReceiverFor(HValue* function,
8610 Handle<JSFunction> target) { 8682 Handle<JSFunction> target) {
8611 SharedFunctionInfo* shared = target->shared(); 8683 SharedFunctionInfo* shared = target->shared();
8612 if (shared->strict_mode() == SLOPPY && !shared->native()) { 8684 if (shared->strict_mode() == SLOPPY && !shared->native()) {
8613 // Cannot embed a direct reference to the global proxy 8685 // Cannot embed a direct reference to the global proxy
8614 // as is it dropped on deserialization. 8686 // as is it dropped on deserialization.
8615 CHECK(!isolate()->serializer_enabled()); 8687 CHECK(!isolate()->serializer_enabled());
8616 Handle<JSObject> global_receiver( 8688 Handle<JSObject> global_receiver(
8617 target->context()->global_object()->global_receiver()); 8689 target->context()->global_object()->global_receiver());
8618 return Add<HConstant>(global_receiver); 8690 return Add<HConstant>(global_receiver);
(...skipping 241 matching lines...) Expand 10 before | Expand all | Expand 10 after
8860 environment()->SetExpressionStackAt(0, function); 8932 environment()->SetExpressionStackAt(0, function);
8861 8933
8862 Push(receiver); 8934 Push(receiver);
8863 8935
8864 if (function->IsConstant() && 8936 if (function->IsConstant() &&
8865 HConstant::cast(function)->handle(isolate())->IsJSFunction()) { 8937 HConstant::cast(function)->handle(isolate())->IsJSFunction()) {
8866 Handle<JSFunction> known_function = Handle<JSFunction>::cast( 8938 Handle<JSFunction> known_function = Handle<JSFunction>::cast(
8867 HConstant::cast(function)->handle(isolate())); 8939 HConstant::cast(function)->handle(isolate()));
8868 expr->set_target(known_function); 8940 expr->set_target(known_function);
8869 8941
8870 if (TryCallApply(expr)) return; 8942 if (TryIndirectCall(expr)) return;
8871 CHECK_ALIVE(VisitExpressions(expr->arguments())); 8943 CHECK_ALIVE(VisitExpressions(expr->arguments()));
8872 8944
8873 Handle<Map> map = types->length() == 1 ? types->first() : Handle<Map>(); 8945 Handle<Map> map = types->length() == 1 ? types->first() : Handle<Map>();
8874 if (TryInlineBuiltinMethodCall(expr, receiver, map)) { 8946 if (TryInlineBuiltinMethodCall(expr, known_function, map,
8947 expr->arguments()->length())) {
8875 if (FLAG_trace_inlining) { 8948 if (FLAG_trace_inlining) {
8876 PrintF("Inlining builtin "); 8949 PrintF("Inlining builtin ");
8877 known_function->ShortPrint(); 8950 known_function->ShortPrint();
8878 PrintF("\n"); 8951 PrintF("\n");
8879 } 8952 }
8880 return; 8953 return;
8881 } 8954 }
8882 if (TryInlineApiMethodCall(expr, receiver, types)) return; 8955 if (TryInlineApiMethodCall(expr, receiver, types)) return;
8883 8956
8884 // Wrap the receiver if necessary. 8957 // Wrap the receiver if necessary.
(...skipping 3459 matching lines...) Expand 10 before | Expand all | Expand 10 after
12344 if (ShouldProduceTraceOutput()) { 12417 if (ShouldProduceTraceOutput()) {
12345 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); 12418 isolate()->GetHTracer()->TraceHydrogen(name(), graph_);
12346 } 12419 }
12347 12420
12348 #ifdef DEBUG 12421 #ifdef DEBUG
12349 graph_->Verify(false); // No full verify. 12422 graph_->Verify(false); // No full verify.
12350 #endif 12423 #endif
12351 } 12424 }
12352 12425
12353 } } // namespace v8::internal 12426 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/hydrogen.h ('k') | src/objects.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698