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 7934 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7945 return true; | 7945 return true; |
7946 } | 7946 } |
7947 default: | 7947 default: |
7948 // Not yet supported for inlining. | 7948 // Not yet supported for inlining. |
7949 break; | 7949 break; |
7950 } | 7950 } |
7951 return false; | 7951 return false; |
7952 } | 7952 } |
7953 | 7953 |
7954 | 7954 |
| 7955 bool HOptimizedGraphBuilder::TryInlineApiFunctionCall(Call* expr, |
| 7956 HValue* receiver, |
| 7957 bool drop_extra) { |
| 7958 return TryInlineApiCall( |
| 7959 expr, receiver, Handle<Map>::null(), drop_extra, true); |
| 7960 } |
| 7961 |
| 7962 |
| 7963 bool HOptimizedGraphBuilder::TryInlineApiMethodCall(Call* expr, |
| 7964 HValue* receiver, |
| 7965 Handle<Map> receiver_map) { |
| 7966 return TryInlineApiCall(expr, receiver, receiver_map, false, false); |
| 7967 } |
| 7968 |
| 7969 bool HOptimizedGraphBuilder::TryInlineApiCall(Call* expr, |
| 7970 HValue* receiver, |
| 7971 Handle<Map> receiver_map, |
| 7972 bool drop_extra, |
| 7973 bool is_function_call) { |
| 7974 if (!expr->IsMonomorphic() || expr->check_type() != RECEIVER_MAP_CHECK) { |
| 7975 return false; |
| 7976 } |
| 7977 CallOptimization optimization(expr->target()); |
| 7978 if (!optimization.is_simple_api_call()) return false; |
| 7979 Handle<Map> holder_map; |
| 7980 if (is_function_call) { |
| 7981 // Cannot embed a direct reference to the global proxy map |
| 7982 // as it maybe dropped on deserialization. |
| 7983 CHECK(!Serializer::enabled()); |
| 7984 receiver_map = Handle<Map>( |
| 7985 expr->target()->context()->global_object()->global_receiver()->map()); |
| 7986 } |
| 7987 CallOptimization::HolderLookup holder_lookup = |
| 7988 CallOptimization::kHolderNotFound; |
| 7989 Handle<JSObject> api_holder = optimization.LookupHolderOfExpectedType( |
| 7990 receiver_map, &holder_lookup); |
| 7991 if (holder_lookup == CallOptimization::kHolderNotFound) return false; |
| 7992 |
| 7993 if (FLAG_trace_inlining) { |
| 7994 PrintF("Inlining api function "); |
| 7995 expr->target()->ShortPrint(); |
| 7996 PrintF("\n"); |
| 7997 } |
| 7998 |
| 7999 // Need to ensure the chain between receiver and api_holder is intact |
| 8000 AddCheckMap(receiver, receiver_map); |
| 8001 if (holder_lookup == CallOptimization::kHolderFound) { |
| 8002 AddCheckPrototypeMaps(api_holder, receiver_map); |
| 8003 } else { |
| 8004 ASSERT_EQ(holder_lookup, CallOptimization::kHolderIsReceiver); |
| 8005 } |
| 8006 |
| 8007 // TODO(verwaest): remove. |
| 8008 if (!is_function_call) { |
| 8009 AddCheckConstantFunction(expr->holder(), receiver, receiver_map); |
| 8010 } |
| 8011 |
| 8012 HValue* holder = NULL; |
| 8013 switch (holder_lookup) { |
| 8014 case CallOptimization::kHolderFound: |
| 8015 holder = Add<HConstant>(api_holder); |
| 8016 break; |
| 8017 case CallOptimization::kHolderIsReceiver: |
| 8018 holder = environment()->ExpressionStackAt(expr->arguments()->length()); |
| 8019 break; |
| 8020 case CallOptimization::kHolderNotFound: |
| 8021 UNREACHABLE(); |
| 8022 break; |
| 8023 } |
| 8024 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info(); |
| 8025 Handle<Object> call_data_obj(api_call_info->data(), isolate()); |
| 8026 bool call_data_is_undefined = call_data_obj->IsUndefined(); |
| 8027 HValue* call_data = Add<HConstant>(call_data_obj); |
| 8028 ApiFunction fun(v8::ToCData<Address>(api_call_info->callback())); |
| 8029 ExternalReference ref = ExternalReference(&fun, |
| 8030 ExternalReference::DIRECT_API_CALL, |
| 8031 isolate()); |
| 8032 HValue* api_function_address = Add<HConstant>(ExternalReference(ref)); |
| 8033 |
| 8034 HValue* op_vals[] = { |
| 8035 // callee |
| 8036 Add<HConstant>(expr->target()), |
| 8037 call_data, |
| 8038 holder, |
| 8039 api_function_address, |
| 8040 context() |
| 8041 }; |
| 8042 |
| 8043 const int argc = expr->arguments()->length(); |
| 8044 // Includes receiver. |
| 8045 PushArgumentsFromEnvironment(argc + 1); |
| 8046 |
| 8047 CallInterfaceDescriptor* descriptor = |
| 8048 isolate()->call_descriptor(Isolate::ApiFunctionCall); |
| 8049 |
| 8050 CallApiFunctionStub stub(true, call_data_is_undefined, argc); |
| 8051 Handle<Code> code = stub.GetCode(isolate()); |
| 8052 HConstant* code_value = Add<HConstant>(code); |
| 8053 |
| 8054 ASSERT((sizeof(op_vals) / kPointerSize) == |
| 8055 descriptor->environment_length()); |
| 8056 |
| 8057 HInstruction* call = New<HCallWithDescriptor>( |
| 8058 code_value, argc + 1, descriptor, |
| 8059 Vector<HValue*>(op_vals, descriptor->environment_length())); |
| 8060 |
| 8061 if (drop_extra) Drop(1); // Drop function. |
| 8062 ast_context()->ReturnInstruction(call, expr->id()); |
| 8063 return true; |
| 8064 } |
| 8065 |
| 8066 |
7955 bool HOptimizedGraphBuilder::TryCallApply(Call* expr) { | 8067 bool HOptimizedGraphBuilder::TryCallApply(Call* expr) { |
7956 Expression* callee = expr->expression(); | 8068 Expression* callee = expr->expression(); |
7957 Property* prop = callee->AsProperty(); | 8069 Property* prop = callee->AsProperty(); |
7958 ASSERT(prop != NULL); | 8070 ASSERT(prop != NULL); |
7959 | 8071 |
7960 if (!expr->IsMonomorphic() || expr->check_type() != RECEIVER_MAP_CHECK) { | 8072 if (!expr->IsMonomorphic() || expr->check_type() != RECEIVER_MAP_CHECK) { |
7961 return false; | 8073 return false; |
7962 } | 8074 } |
7963 Handle<Map> function_map = expr->GetReceiverTypes()->first(); | 8075 Handle<Map> function_map = expr->GetReceiverTypes()->first(); |
7964 if (function_map->instance_type() != JS_FUNCTION_TYPE || | 8076 if (function_map->instance_type() != JS_FUNCTION_TYPE || |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8033 ast_context()->ReturnInstruction(call, expr->id()); | 8145 ast_context()->ReturnInstruction(call, expr->id()); |
8034 return true; | 8146 return true; |
8035 } | 8147 } |
8036 } | 8148 } |
8037 | 8149 |
8038 | 8150 |
8039 HValue* HOptimizedGraphBuilder::ImplicitReceiverFor(HValue* function, | 8151 HValue* HOptimizedGraphBuilder::ImplicitReceiverFor(HValue* function, |
8040 Handle<JSFunction> target) { | 8152 Handle<JSFunction> target) { |
8041 SharedFunctionInfo* shared = target->shared(); | 8153 SharedFunctionInfo* shared = target->shared(); |
8042 if (shared->is_classic_mode() && !shared->native()) { | 8154 if (shared->is_classic_mode() && !shared->native()) { |
8043 HValue* context = Add<HLoadNamedField>( | 8155 // Cannot embed a direct reference to the global proxy |
8044 function, static_cast<HValue*>(NULL), | 8156 // as is it dropped on deserialization. |
8045 HObjectAccess::ForJSObjectOffset(JSFunction::kContextOffset)); | 8157 CHECK(!Serializer::enabled()); |
8046 HValue* global_object = Add<HLoadNamedField>( | 8158 Handle<JSObject> global_receiver( |
8047 context, static_cast<HValue*>(NULL), | 8159 target->context()->global_object()->global_receiver()); |
8048 HObjectAccess::ForContextSlot(Context::GLOBAL_OBJECT_INDEX)); | 8160 return Add<HConstant>(global_receiver); |
8049 return Add<HLoadNamedField>( | |
8050 global_object, static_cast<HValue*>(NULL), | |
8051 HObjectAccess::ForJSObjectOffset( | |
8052 GlobalObject::kGlobalReceiverOffset)); | |
8053 } | 8161 } |
8054 return graph()->GetConstantUndefined(); | 8162 return graph()->GetConstantUndefined(); |
8055 } | 8163 } |
8056 | 8164 |
8057 | 8165 |
8058 void HOptimizedGraphBuilder::VisitCall(Call* expr) { | 8166 void HOptimizedGraphBuilder::VisitCall(Call* expr) { |
8059 ASSERT(!HasStackOverflow()); | 8167 ASSERT(!HasStackOverflow()); |
8060 ASSERT(current_block() != NULL); | 8168 ASSERT(current_block() != NULL); |
8061 ASSERT(current_block()->HasPredecessor()); | 8169 ASSERT(current_block()->HasPredecessor()); |
8062 Expression* callee = expr->expression(); | 8170 Expression* callee = expr->expression(); |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8115 if (monomorphic) { | 8223 if (monomorphic) { |
8116 Handle<Map> map = types->first(); | 8224 Handle<Map> map = types->first(); |
8117 if (TryInlineBuiltinMethodCall(expr, receiver, map, expr->check_type())) { | 8225 if (TryInlineBuiltinMethodCall(expr, receiver, map, expr->check_type())) { |
8118 if (FLAG_trace_inlining) { | 8226 if (FLAG_trace_inlining) { |
8119 PrintF("Inlining builtin "); | 8227 PrintF("Inlining builtin "); |
8120 expr->target()->ShortPrint(); | 8228 expr->target()->ShortPrint(); |
8121 PrintF("\n"); | 8229 PrintF("\n"); |
8122 } | 8230 } |
8123 return; | 8231 return; |
8124 } | 8232 } |
| 8233 if (TryInlineApiMethodCall(expr, receiver, map)) return; |
8125 | 8234 |
8126 if (CallStubCompiler::HasCustomCallGenerator(expr->target()) || | 8235 if (expr->check_type() != RECEIVER_MAP_CHECK) { |
8127 expr->check_type() != RECEIVER_MAP_CHECK) { | |
8128 // When the target has a custom call IC generator, use the IC, | |
8129 // because it is likely to generate better code. Also use the IC | |
8130 // when a primitive receiver check is required. | |
8131 call = NewCallNamed(name, argument_count); | 8236 call = NewCallNamed(name, argument_count); |
8132 PushArgumentsFromEnvironment(argument_count); | 8237 PushArgumentsFromEnvironment(argument_count); |
8133 } else { | 8238 } else { |
8134 AddCheckConstantFunction(expr->holder(), receiver, map); | 8239 AddCheckConstantFunction(expr->holder(), receiver, map); |
8135 | 8240 |
8136 if (TryInlineCall(expr)) return; | 8241 if (TryInlineCall(expr)) return; |
8137 call = BuildCallConstantFunction(expr->target(), argument_count); | 8242 call = BuildCallConstantFunction(expr->target(), argument_count); |
8138 PushArgumentsFromEnvironment(argument_count); | 8243 PushArgumentsFromEnvironment(argument_count); |
8139 } | 8244 } |
8140 } else if (types != NULL && types->length() > 1) { | 8245 } else if (types != NULL && types->length() > 1) { |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8186 environment()->SetExpressionStackAt(receiver_index, receiver); | 8291 environment()->SetExpressionStackAt(receiver_index, receiver); |
8187 | 8292 |
8188 if (TryInlineBuiltinFunctionCall(expr, false)) { // Nothing to drop. | 8293 if (TryInlineBuiltinFunctionCall(expr, false)) { // Nothing to drop. |
8189 if (FLAG_trace_inlining) { | 8294 if (FLAG_trace_inlining) { |
8190 PrintF("Inlining builtin "); | 8295 PrintF("Inlining builtin "); |
8191 expr->target()->ShortPrint(); | 8296 expr->target()->ShortPrint(); |
8192 PrintF("\n"); | 8297 PrintF("\n"); |
8193 } | 8298 } |
8194 return; | 8299 return; |
8195 } | 8300 } |
| 8301 if (TryInlineApiFunctionCall(expr, receiver, false)) return; |
8196 if (TryInlineCall(expr)) return; | 8302 if (TryInlineCall(expr)) return; |
8197 | 8303 |
8198 if (expr->target().is_identical_to(current_info()->closure())) { | 8304 if (expr->target().is_identical_to(current_info()->closure())) { |
8199 graph()->MarkRecursive(); | 8305 graph()->MarkRecursive(); |
8200 } | 8306 } |
8201 | 8307 |
8202 if (CallStubCompiler::HasCustomCallGenerator(expr->target())) { | 8308 call = BuildCallConstantFunction(expr->target(), argument_count); |
8203 // We're about to install a contextual IC, which expects the global | 8309 PushArgumentsFromEnvironment(argument_count); |
8204 // object as receiver rather than the global proxy. | |
8205 HValue* global_object = Add<HLoadNamedField>( | |
8206 context(), static_cast<HValue*>(NULL), | |
8207 HObjectAccess::ForContextSlot(Context::GLOBAL_OBJECT_INDEX)); | |
8208 const int receiver_index = argument_count - 1; | |
8209 environment()->SetExpressionStackAt(receiver_index, global_object); | |
8210 // When the target has a custom call IC generator, use the IC, | |
8211 // because it is likely to generate better code. | |
8212 call = NewCallNamed(var->name(), argument_count); | |
8213 PushArgumentsFromEnvironment(argument_count); | |
8214 } else { | |
8215 call = BuildCallConstantFunction(expr->target(), argument_count); | |
8216 PushArgumentsFromEnvironment(argument_count); | |
8217 } | |
8218 } else { | 8310 } else { |
8219 HValue* receiver = Add<HLoadNamedField>( | 8311 HValue* receiver = Add<HLoadNamedField>( |
8220 context(), static_cast<HValue*>(NULL), | 8312 context(), static_cast<HValue*>(NULL), |
8221 HObjectAccess::ForContextSlot(Context::GLOBAL_OBJECT_INDEX)); | 8313 HObjectAccess::ForContextSlot(Context::GLOBAL_OBJECT_INDEX)); |
8222 Push(Add<HPushArgument>(receiver)); | 8314 Push(Add<HPushArgument>(receiver)); |
8223 CHECK_ALIVE(VisitArgumentList(expr->arguments())); | 8315 CHECK_ALIVE(VisitArgumentList(expr->arguments())); |
8224 | 8316 |
8225 call = NewCallNamed(var->name(), argument_count); | 8317 call = NewCallNamed(var->name(), argument_count); |
8226 Drop(argument_count); | 8318 Drop(argument_count); |
8227 } | 8319 } |
(...skipping 12 matching lines...) Expand all Loading... |
8240 CHECK_ALIVE(VisitExpressions(expr->arguments())); | 8332 CHECK_ALIVE(VisitExpressions(expr->arguments())); |
8241 | 8333 |
8242 if (TryInlineBuiltinFunctionCall(expr, true)) { // Drop the function. | 8334 if (TryInlineBuiltinFunctionCall(expr, true)) { // Drop the function. |
8243 if (FLAG_trace_inlining) { | 8335 if (FLAG_trace_inlining) { |
8244 PrintF("Inlining builtin "); | 8336 PrintF("Inlining builtin "); |
8245 expr->target()->ShortPrint(); | 8337 expr->target()->ShortPrint(); |
8246 PrintF("\n"); | 8338 PrintF("\n"); |
8247 } | 8339 } |
8248 return; | 8340 return; |
8249 } | 8341 } |
| 8342 if (TryInlineApiFunctionCall(expr, receiver, true)) return; |
8250 | 8343 |
8251 if (TryInlineCall(expr, true)) { // Drop function from environment. | 8344 if (TryInlineCall(expr, true)) { // Drop function from environment. |
8252 return; | 8345 return; |
8253 } else { | 8346 } else { |
8254 call = PreProcessCall(New<HInvokeFunction>(function, expr->target(), | 8347 call = PreProcessCall(New<HInvokeFunction>(function, expr->target(), |
8255 argument_count)); | 8348 argument_count)); |
8256 Drop(1); // The function. | 8349 Drop(1); // The function. |
8257 } | 8350 } |
8258 | 8351 |
8259 } else { | 8352 } else { |
(...skipping 3102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
11362 if (ShouldProduceTraceOutput()) { | 11455 if (ShouldProduceTraceOutput()) { |
11363 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); | 11456 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); |
11364 } | 11457 } |
11365 | 11458 |
11366 #ifdef DEBUG | 11459 #ifdef DEBUG |
11367 graph_->Verify(false); // No full verify. | 11460 graph_->Verify(false); // No full verify. |
11368 #endif | 11461 #endif |
11369 } | 11462 } |
11370 | 11463 |
11371 } } // namespace v8::internal | 11464 } } // namespace v8::internal |
OLD | NEW |