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