OLD | NEW |
1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 7748 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7759 return true; | 7759 return true; |
7760 } | 7760 } |
7761 default: | 7761 default: |
7762 // Not yet supported for inlining. | 7762 // Not yet supported for inlining. |
7763 break; | 7763 break; |
7764 } | 7764 } |
7765 return false; | 7765 return false; |
7766 } | 7766 } |
7767 | 7767 |
7768 | 7768 |
| 7769 bool HOptimizedGraphBuilder::TryInlineApiFunctionCall(Call* expr, |
| 7770 HValue* receiver, |
| 7771 bool drop_extra) { |
| 7772 return TryInlineApiCall( |
| 7773 expr, receiver, Handle<Map>::null(), drop_extra, true); |
| 7774 } |
| 7775 |
| 7776 |
| 7777 bool HOptimizedGraphBuilder::TryInlineApiMethodCall(Call* expr, |
| 7778 HValue* receiver, |
| 7779 Handle<Map> receiver_map) { |
| 7780 return TryInlineApiCall(expr, receiver, receiver_map, false, false); |
| 7781 } |
| 7782 |
| 7783 bool HOptimizedGraphBuilder::TryInlineApiCall(Call* expr, |
| 7784 HValue* receiver, |
| 7785 Handle<Map> receiver_map, |
| 7786 bool drop_extra, |
| 7787 bool is_function_call) { |
| 7788 if (!expr->IsMonomorphic() || expr->check_type() != RECEIVER_MAP_CHECK) { |
| 7789 return false; |
| 7790 } |
| 7791 CallOptimization optimization(expr->target()); |
| 7792 if (!optimization.is_simple_api_call()) return false; |
| 7793 CallOptimization::HolderLookup holder_lookup = |
| 7794 CallOptimization::kHolderNotFound; |
| 7795 Handle<Map> holder_map; |
| 7796 if (is_function_call) { |
| 7797 // Cannot embed a direct reference to the global proxy map |
| 7798 // as it maybe dropped on deserialization. |
| 7799 CHECK(!Serializer::enabled()); |
| 7800 receiver_map = Handle<Map>( |
| 7801 expr->target()->context()->global_object()->global_receiver()->map()); |
| 7802 holder_map = Handle<Map>(); |
| 7803 } else if (!expr->holder().is_null()) { |
| 7804 holder_map = Handle<Map>(expr->holder()->map()); |
| 7805 } else { |
| 7806 holder_map = receiver_map; |
| 7807 } |
| 7808 Handle<Map> holder_lookup_result = optimization.LookupHolderOfExpectedType( |
| 7809 receiver_map, receiver_map, holder_map, &holder_lookup); |
| 7810 if (holder_lookup == CallOptimization::kHolderNotFound) return false; |
| 7811 |
| 7812 if (FLAG_trace_inlining) { |
| 7813 PrintF("Inlining api function "); |
| 7814 expr->target()->ShortPrint(); |
| 7815 PrintF("\n"); |
| 7816 } |
| 7817 |
| 7818 if (is_function_call) { |
| 7819 // Need to ensure the chain between receiver and api_holder is intact |
| 7820 AddCheckMap(receiver, receiver_map); |
| 7821 if (holder_lookup == CallOptimization::kHolderIsPrototypeOfMap) { |
| 7822 Handle<JSObject> api_holder( |
| 7823 JSObject::cast(holder_lookup_result->prototype())); |
| 7824 AddCheckPrototypeMaps(api_holder, receiver_map); |
| 7825 } else { |
| 7826 ASSERT_EQ(holder_lookup, CallOptimization::kHolderIsReceiver); |
| 7827 } |
| 7828 } else { |
| 7829 AddCheckConstantFunction(expr->holder(), receiver, receiver_map); |
| 7830 } |
| 7831 |
| 7832 HValue* holder = NULL; |
| 7833 switch (holder_lookup) { |
| 7834 case CallOptimization::kHolderIsPrototypeOfMap: |
| 7835 { |
| 7836 Handle<JSObject> api_holder( |
| 7837 JSObject::cast(holder_lookup_result->prototype())); |
| 7838 if (isolate()->heap()->InNewSpace(*api_holder)) { |
| 7839 HValue* lookup_value = Add<HConstant>(holder_lookup_result); |
| 7840 holder = AddLoadNamedField( |
| 7841 lookup_value, |
| 7842 HObjectAccess::ForJSObjectOffset(Map::kPrototypeOffset)); |
| 7843 } else { |
| 7844 holder = Add<HConstant>(api_holder); |
| 7845 } |
| 7846 } |
| 7847 break; |
| 7848 case CallOptimization::kHolderIsReceiver: |
| 7849 holder = environment()->ExpressionStackAt(expr->arguments()->length()); |
| 7850 break; |
| 7851 case CallOptimization::kHolderNotFound: |
| 7852 UNREACHABLE(); |
| 7853 break; |
| 7854 } |
| 7855 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info(); |
| 7856 Handle<Object> call_data_obj(api_call_info->data(), isolate()); |
| 7857 bool call_data_is_undefined = call_data_obj->IsUndefined(); |
| 7858 HValue* call_data = Add<HConstant>(call_data_obj); |
| 7859 ApiFunction fun(v8::ToCData<Address>(api_call_info->callback())); |
| 7860 ExternalReference ref = ExternalReference(&fun, |
| 7861 ExternalReference::DIRECT_API_CALL, |
| 7862 isolate()); |
| 7863 HValue* api_function_address = Add<HConstant>(ExternalReference(ref)); |
| 7864 |
| 7865 HValue* op_vals[] = { |
| 7866 // callee |
| 7867 Add<HConstant>(expr->target()), |
| 7868 call_data, |
| 7869 holder, |
| 7870 api_function_address, |
| 7871 context() |
| 7872 }; |
| 7873 |
| 7874 const int argc = expr->arguments()->length(); |
| 7875 // Includes receiver. |
| 7876 PushArgumentsFromEnvironment(argc + 1); |
| 7877 |
| 7878 CallInterfaceDescriptor* descriptor = |
| 7879 isolate()->call_descriptor(Isolate::ApiFunctionCall); |
| 7880 |
| 7881 CallApiFunctionStub stub(true, call_data_is_undefined, argc); |
| 7882 Handle<Code> code = stub.GetCode(isolate()); |
| 7883 HConstant* code_value = Add<HConstant>(code); |
| 7884 |
| 7885 ASSERT((sizeof(op_vals) / kPointerSize) == |
| 7886 descriptor->environment_length()); |
| 7887 |
| 7888 HInstruction* call = New<HCallWithDescriptor>( |
| 7889 code_value, argc + 1, descriptor, |
| 7890 Vector<HValue*>(op_vals, descriptor->environment_length())); |
| 7891 |
| 7892 if (drop_extra) Drop(1); // Drop function. |
| 7893 ast_context()->ReturnInstruction(call, expr->id()); |
| 7894 return true; |
| 7895 } |
| 7896 |
| 7897 |
7769 bool HOptimizedGraphBuilder::TryCallApply(Call* expr) { | 7898 bool HOptimizedGraphBuilder::TryCallApply(Call* expr) { |
7770 Expression* callee = expr->expression(); | 7899 Expression* callee = expr->expression(); |
7771 Property* prop = callee->AsProperty(); | 7900 Property* prop = callee->AsProperty(); |
7772 ASSERT(prop != NULL); | 7901 ASSERT(prop != NULL); |
7773 | 7902 |
7774 if (!expr->IsMonomorphic() || expr->check_type() != RECEIVER_MAP_CHECK) { | 7903 if (!expr->IsMonomorphic() || expr->check_type() != RECEIVER_MAP_CHECK) { |
7775 return false; | 7904 return false; |
7776 } | 7905 } |
7777 Handle<Map> function_map = expr->GetReceiverTypes()->first(); | 7906 Handle<Map> function_map = expr->GetReceiverTypes()->first(); |
7778 if (function_map->instance_type() != JS_FUNCTION_TYPE || | 7907 if (function_map->instance_type() != JS_FUNCTION_TYPE || |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7847 ast_context()->ReturnInstruction(call, expr->id()); | 7976 ast_context()->ReturnInstruction(call, expr->id()); |
7848 return true; | 7977 return true; |
7849 } | 7978 } |
7850 } | 7979 } |
7851 | 7980 |
7852 | 7981 |
7853 HValue* HOptimizedGraphBuilder::ImplicitReceiverFor(HValue* function, | 7982 HValue* HOptimizedGraphBuilder::ImplicitReceiverFor(HValue* function, |
7854 Handle<JSFunction> target) { | 7983 Handle<JSFunction> target) { |
7855 SharedFunctionInfo* shared = target->shared(); | 7984 SharedFunctionInfo* shared = target->shared(); |
7856 if (shared->is_classic_mode() && !shared->native()) { | 7985 if (shared->is_classic_mode() && !shared->native()) { |
7857 HValue* context = Add<HLoadNamedField>( | 7986 // Cannot embed a direct reference to the global proxy |
7858 function, static_cast<HValue*>(NULL), | 7987 // as is it dropped on deserialization. |
7859 HObjectAccess::ForJSObjectOffset(JSFunction::kContextOffset)); | 7988 CHECK(!Serializer::enabled()); |
7860 HValue* global_object = Add<HLoadNamedField>( | 7989 Handle<JSObject> global_receiver( |
7861 context, static_cast<HValue*>(NULL), | 7990 target->context()->global_object()->global_receiver()); |
7862 HObjectAccess::ForContextSlot(Context::GLOBAL_OBJECT_INDEX)); | 7991 return Add<HConstant>(global_receiver); |
7863 return Add<HLoadNamedField>( | |
7864 global_object, static_cast<HValue*>(NULL), | |
7865 HObjectAccess::ForJSObjectOffset( | |
7866 GlobalObject::kGlobalReceiverOffset)); | |
7867 } | 7992 } |
7868 return graph()->GetConstantUndefined(); | 7993 return graph()->GetConstantUndefined(); |
7869 } | 7994 } |
7870 | 7995 |
7871 | 7996 |
7872 void HOptimizedGraphBuilder::VisitCall(Call* expr) { | 7997 void HOptimizedGraphBuilder::VisitCall(Call* expr) { |
7873 ASSERT(!HasStackOverflow()); | 7998 ASSERT(!HasStackOverflow()); |
7874 ASSERT(current_block() != NULL); | 7999 ASSERT(current_block() != NULL); |
7875 ASSERT(current_block()->HasPredecessor()); | 8000 ASSERT(current_block()->HasPredecessor()); |
7876 Expression* callee = expr->expression(); | 8001 Expression* callee = expr->expression(); |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7929 if (monomorphic) { | 8054 if (monomorphic) { |
7930 Handle<Map> map = types->first(); | 8055 Handle<Map> map = types->first(); |
7931 if (TryInlineBuiltinMethodCall(expr, receiver, map, expr->check_type())) { | 8056 if (TryInlineBuiltinMethodCall(expr, receiver, map, expr->check_type())) { |
7932 if (FLAG_trace_inlining) { | 8057 if (FLAG_trace_inlining) { |
7933 PrintF("Inlining builtin "); | 8058 PrintF("Inlining builtin "); |
7934 expr->target()->ShortPrint(); | 8059 expr->target()->ShortPrint(); |
7935 PrintF("\n"); | 8060 PrintF("\n"); |
7936 } | 8061 } |
7937 return; | 8062 return; |
7938 } | 8063 } |
| 8064 if (TryInlineApiMethodCall(expr, receiver, map)) return; |
7939 | 8065 |
7940 if (CallStubCompiler::HasCustomCallGenerator(expr->target()) || | 8066 AddCheckConstantFunction(expr->holder(), receiver, map); |
7941 expr->check_type() != RECEIVER_MAP_CHECK) { | 8067 if (TryInlineCall(expr)) return; |
7942 // When the target has a custom call IC generator, use the IC, | 8068 call = BuildCallConstantFunction(expr->target(), argument_count); |
7943 // because it is likely to generate better code. Also use the IC | 8069 PushArgumentsFromEnvironment(argument_count); |
7944 // when a primitive receiver check is required. | |
7945 call = NewCallNamed(name, argument_count); | |
7946 PushArgumentsFromEnvironment(argument_count); | |
7947 } else { | |
7948 AddCheckConstantFunction(expr->holder(), receiver, map); | |
7949 | |
7950 if (TryInlineCall(expr)) return; | |
7951 call = BuildCallConstantFunction(expr->target(), argument_count); | |
7952 PushArgumentsFromEnvironment(argument_count); | |
7953 } | |
7954 } else if (types != NULL && types->length() > 1) { | 8070 } else if (types != NULL && types->length() > 1) { |
7955 ASSERT(expr->check_type() == RECEIVER_MAP_CHECK); | 8071 ASSERT(expr->check_type() == RECEIVER_MAP_CHECK); |
7956 HandlePolymorphicCallNamed(expr, receiver, types, name); | 8072 HandlePolymorphicCallNamed(expr, receiver, types, name); |
7957 return; | 8073 return; |
7958 | 8074 |
7959 } else { | 8075 } else { |
7960 call = NewCallNamed(name, argument_count); | 8076 call = NewCallNamed(name, argument_count); |
7961 PushArgumentsFromEnvironment(argument_count); | 8077 PushArgumentsFromEnvironment(argument_count); |
7962 } | 8078 } |
7963 } else { | 8079 } else { |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8000 environment()->SetExpressionStackAt(receiver_index, receiver); | 8116 environment()->SetExpressionStackAt(receiver_index, receiver); |
8001 | 8117 |
8002 if (TryInlineBuiltinFunctionCall(expr, false)) { // Nothing to drop. | 8118 if (TryInlineBuiltinFunctionCall(expr, false)) { // Nothing to drop. |
8003 if (FLAG_trace_inlining) { | 8119 if (FLAG_trace_inlining) { |
8004 PrintF("Inlining builtin "); | 8120 PrintF("Inlining builtin "); |
8005 expr->target()->ShortPrint(); | 8121 expr->target()->ShortPrint(); |
8006 PrintF("\n"); | 8122 PrintF("\n"); |
8007 } | 8123 } |
8008 return; | 8124 return; |
8009 } | 8125 } |
| 8126 if (TryInlineApiFunctionCall(expr, receiver, false)) return; |
8010 if (TryInlineCall(expr)) return; | 8127 if (TryInlineCall(expr)) return; |
8011 | 8128 |
8012 if (expr->target().is_identical_to(current_info()->closure())) { | 8129 if (expr->target().is_identical_to(current_info()->closure())) { |
8013 graph()->MarkRecursive(); | 8130 graph()->MarkRecursive(); |
8014 } | 8131 } |
8015 | 8132 |
8016 if (CallStubCompiler::HasCustomCallGenerator(expr->target())) { | 8133 call = BuildCallConstantFunction(expr->target(), argument_count); |
8017 // We're about to install a contextual IC, which expects the global | 8134 PushArgumentsFromEnvironment(argument_count); |
8018 // object as receiver rather than the global proxy. | |
8019 HValue* global_object = Add<HLoadNamedField>( | |
8020 context(), static_cast<HValue*>(NULL), | |
8021 HObjectAccess::ForContextSlot(Context::GLOBAL_OBJECT_INDEX)); | |
8022 const int receiver_index = argument_count - 1; | |
8023 environment()->SetExpressionStackAt(receiver_index, global_object); | |
8024 // When the target has a custom call IC generator, use the IC, | |
8025 // because it is likely to generate better code. | |
8026 call = NewCallNamed(var->name(), argument_count); | |
8027 PushArgumentsFromEnvironment(argument_count); | |
8028 } else { | |
8029 call = BuildCallConstantFunction(expr->target(), argument_count); | |
8030 PushArgumentsFromEnvironment(argument_count); | |
8031 } | |
8032 } else { | 8135 } else { |
8033 HValue* receiver = Add<HLoadNamedField>( | 8136 HValue* receiver = Add<HLoadNamedField>( |
8034 context(), static_cast<HValue*>(NULL), | 8137 context(), static_cast<HValue*>(NULL), |
8035 HObjectAccess::ForContextSlot(Context::GLOBAL_OBJECT_INDEX)); | 8138 HObjectAccess::ForContextSlot(Context::GLOBAL_OBJECT_INDEX)); |
8036 Push(Add<HPushArgument>(receiver)); | 8139 Push(Add<HPushArgument>(receiver)); |
8037 CHECK_ALIVE(VisitArgumentList(expr->arguments())); | 8140 CHECK_ALIVE(VisitArgumentList(expr->arguments())); |
8038 | 8141 |
8039 call = NewCallNamed(var->name(), argument_count); | 8142 call = NewCallNamed(var->name(), argument_count); |
8040 Drop(argument_count); | 8143 Drop(argument_count); |
8041 } | 8144 } |
(...skipping 12 matching lines...) Expand all Loading... |
8054 CHECK_ALIVE(VisitExpressions(expr->arguments())); | 8157 CHECK_ALIVE(VisitExpressions(expr->arguments())); |
8055 | 8158 |
8056 if (TryInlineBuiltinFunctionCall(expr, true)) { // Drop the function. | 8159 if (TryInlineBuiltinFunctionCall(expr, true)) { // Drop the function. |
8057 if (FLAG_trace_inlining) { | 8160 if (FLAG_trace_inlining) { |
8058 PrintF("Inlining builtin "); | 8161 PrintF("Inlining builtin "); |
8059 expr->target()->ShortPrint(); | 8162 expr->target()->ShortPrint(); |
8060 PrintF("\n"); | 8163 PrintF("\n"); |
8061 } | 8164 } |
8062 return; | 8165 return; |
8063 } | 8166 } |
| 8167 if (TryInlineApiFunctionCall(expr, receiver, true)) return; |
8064 | 8168 |
8065 if (TryInlineCall(expr, true)) { // Drop function from environment. | 8169 if (TryInlineCall(expr, true)) { // Drop function from environment. |
8066 return; | 8170 return; |
8067 } else { | 8171 } else { |
8068 call = PreProcessCall(New<HInvokeFunction>(function, expr->target(), | 8172 call = PreProcessCall(New<HInvokeFunction>(function, expr->target(), |
8069 argument_count)); | 8173 argument_count)); |
8070 Drop(1); // The function. | 8174 Drop(1); // The function. |
8071 } | 8175 } |
8072 | 8176 |
8073 } else { | 8177 } else { |
(...skipping 3080 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
11154 if (ShouldProduceTraceOutput()) { | 11258 if (ShouldProduceTraceOutput()) { |
11155 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); | 11259 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); |
11156 } | 11260 } |
11157 | 11261 |
11158 #ifdef DEBUG | 11262 #ifdef DEBUG |
11159 graph_->Verify(false); // No full verify. | 11263 graph_->Verify(false); // No full verify. |
11160 #endif | 11264 #endif |
11161 } | 11265 } |
11162 | 11266 |
11163 } } // namespace v8::internal | 11267 } } // namespace v8::internal |
OLD | NEW |