Index: src/hydrogen.cc |
diff --git a/src/hydrogen.cc b/src/hydrogen.cc |
index 78a703b5652d8282edc0fc7a77e6e791cc9f2541..98191ce650daab15f282f0ab7a496e084c606d34 100644 |
--- a/src/hydrogen.cc |
+++ b/src/hydrogen.cc |
@@ -7952,6 +7952,118 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall( |
} |
+bool HOptimizedGraphBuilder::TryInlineApiFunctionCall(Call* expr, |
+ HValue* receiver, |
+ bool drop_extra) { |
+ return TryInlineApiCall( |
+ expr, receiver, Handle<Map>::null(), drop_extra, true); |
+} |
+ |
+ |
+bool HOptimizedGraphBuilder::TryInlineApiMethodCall(Call* expr, |
+ HValue* receiver, |
+ Handle<Map> receiver_map) { |
+ return TryInlineApiCall(expr, receiver, receiver_map, false, false); |
+} |
+ |
+bool HOptimizedGraphBuilder::TryInlineApiCall(Call* expr, |
+ HValue* receiver, |
+ Handle<Map> receiver_map, |
+ bool drop_extra, |
+ bool is_function_call) { |
+ if (!expr->IsMonomorphic() || expr->check_type() != RECEIVER_MAP_CHECK) { |
+ return false; |
+ } |
+ CallOptimization optimization(expr->target()); |
+ if (!optimization.is_simple_api_call()) return false; |
+ Handle<Map> holder_map; |
+ if (is_function_call) { |
+ // Cannot embed a direct reference to the global proxy map |
+ // as it maybe dropped on deserialization. |
+ CHECK(!Serializer::enabled()); |
+ receiver_map = Handle<Map>( |
+ expr->target()->context()->global_object()->global_receiver()->map()); |
+ } |
+ CallOptimization::HolderLookup holder_lookup = |
+ CallOptimization::kHolderNotFound; |
+ Handle<JSObject> api_holder = optimization.LookupHolderOfExpectedType( |
+ receiver_map, &holder_lookup); |
+ if (holder_lookup == CallOptimization::kHolderNotFound) return false; |
+ |
+ if (FLAG_trace_inlining) { |
+ PrintF("Inlining api function "); |
+ expr->target()->ShortPrint(); |
+ PrintF("\n"); |
+ } |
+ |
+ // Need to ensure the chain between receiver and api_holder is intact |
+ AddCheckMap(receiver, receiver_map); |
+ if (holder_lookup == CallOptimization::kHolderFound) { |
+ AddCheckPrototypeMaps(api_holder, receiver_map); |
+ } else { |
+ ASSERT_EQ(holder_lookup, CallOptimization::kHolderIsReceiver); |
+ } |
+ |
+ // TODO(verwaest): remove. |
+ if (!is_function_call) { |
+ AddCheckConstantFunction(expr->holder(), receiver, receiver_map); |
+ } |
+ |
+ HValue* holder = NULL; |
+ switch (holder_lookup) { |
+ case CallOptimization::kHolderFound: |
+ holder = Add<HConstant>(api_holder); |
+ break; |
+ case CallOptimization::kHolderIsReceiver: |
+ holder = environment()->ExpressionStackAt(expr->arguments()->length()); |
+ break; |
+ case CallOptimization::kHolderNotFound: |
+ UNREACHABLE(); |
+ break; |
+ } |
+ Handle<CallHandlerInfo> api_call_info = optimization.api_call_info(); |
+ Handle<Object> call_data_obj(api_call_info->data(), isolate()); |
+ bool call_data_is_undefined = call_data_obj->IsUndefined(); |
+ HValue* call_data = Add<HConstant>(call_data_obj); |
+ ApiFunction fun(v8::ToCData<Address>(api_call_info->callback())); |
+ ExternalReference ref = ExternalReference(&fun, |
+ ExternalReference::DIRECT_API_CALL, |
+ isolate()); |
+ HValue* api_function_address = Add<HConstant>(ExternalReference(ref)); |
+ |
+ HValue* op_vals[] = { |
+ // callee |
+ Add<HConstant>(expr->target()), |
+ call_data, |
+ holder, |
+ api_function_address, |
+ context() |
+ }; |
+ |
+ const int argc = expr->arguments()->length(); |
+ // Includes receiver. |
+ PushArgumentsFromEnvironment(argc + 1); |
+ |
+ CallInterfaceDescriptor* descriptor = |
+ isolate()->call_descriptor(Isolate::ApiFunctionCall); |
+ |
+ CallApiFunctionStub stub(true, call_data_is_undefined, argc); |
+ Handle<Code> code = stub.GetCode(isolate()); |
+ HConstant* code_value = Add<HConstant>(code); |
+ |
+ ASSERT((sizeof(op_vals) / kPointerSize) == |
+ descriptor->environment_length()); |
+ |
+ HInstruction* call = New<HCallWithDescriptor>( |
+ code_value, argc + 1, descriptor, |
+ Vector<HValue*>(op_vals, descriptor->environment_length())); |
+ |
+ if (drop_extra) Drop(1); // Drop function. |
+ ast_context()->ReturnInstruction(call, expr->id()); |
+ return true; |
+} |
+ |
+ |
bool HOptimizedGraphBuilder::TryCallApply(Call* expr) { |
Expression* callee = expr->expression(); |
Property* prop = callee->AsProperty(); |
@@ -8040,16 +8152,12 @@ HValue* HOptimizedGraphBuilder::ImplicitReceiverFor(HValue* function, |
Handle<JSFunction> target) { |
SharedFunctionInfo* shared = target->shared(); |
if (shared->is_classic_mode() && !shared->native()) { |
- HValue* context = Add<HLoadNamedField>( |
- function, static_cast<HValue*>(NULL), |
- HObjectAccess::ForJSObjectOffset(JSFunction::kContextOffset)); |
- HValue* global_object = Add<HLoadNamedField>( |
- context, static_cast<HValue*>(NULL), |
- HObjectAccess::ForContextSlot(Context::GLOBAL_OBJECT_INDEX)); |
- return Add<HLoadNamedField>( |
- global_object, static_cast<HValue*>(NULL), |
- HObjectAccess::ForJSObjectOffset( |
- GlobalObject::kGlobalReceiverOffset)); |
+ // Cannot embed a direct reference to the global proxy |
+ // as is it dropped on deserialization. |
+ CHECK(!Serializer::enabled()); |
+ Handle<JSObject> global_receiver( |
+ target->context()->global_object()->global_receiver()); |
+ return Add<HConstant>(global_receiver); |
} |
return graph()->GetConstantUndefined(); |
} |
@@ -8122,12 +8230,9 @@ void HOptimizedGraphBuilder::VisitCall(Call* expr) { |
} |
return; |
} |
+ if (TryInlineApiMethodCall(expr, receiver, map)) return; |
- if (CallStubCompiler::HasCustomCallGenerator(expr->target()) || |
- expr->check_type() != RECEIVER_MAP_CHECK) { |
- // When the target has a custom call IC generator, use the IC, |
- // because it is likely to generate better code. Also use the IC |
- // when a primitive receiver check is required. |
+ if (expr->check_type() != RECEIVER_MAP_CHECK) { |
call = NewCallNamed(name, argument_count); |
PushArgumentsFromEnvironment(argument_count); |
} else { |
@@ -8193,28 +8298,15 @@ void HOptimizedGraphBuilder::VisitCall(Call* expr) { |
} |
return; |
} |
+ if (TryInlineApiFunctionCall(expr, receiver, false)) return; |
if (TryInlineCall(expr)) return; |
if (expr->target().is_identical_to(current_info()->closure())) { |
graph()->MarkRecursive(); |
} |
- if (CallStubCompiler::HasCustomCallGenerator(expr->target())) { |
- // We're about to install a contextual IC, which expects the global |
- // object as receiver rather than the global proxy. |
- HValue* global_object = Add<HLoadNamedField>( |
- context(), static_cast<HValue*>(NULL), |
- HObjectAccess::ForContextSlot(Context::GLOBAL_OBJECT_INDEX)); |
- const int receiver_index = argument_count - 1; |
- environment()->SetExpressionStackAt(receiver_index, global_object); |
- // When the target has a custom call IC generator, use the IC, |
- // because it is likely to generate better code. |
- call = NewCallNamed(var->name(), argument_count); |
- PushArgumentsFromEnvironment(argument_count); |
- } else { |
- call = BuildCallConstantFunction(expr->target(), argument_count); |
- PushArgumentsFromEnvironment(argument_count); |
- } |
+ call = BuildCallConstantFunction(expr->target(), argument_count); |
+ PushArgumentsFromEnvironment(argument_count); |
} else { |
HValue* receiver = Add<HLoadNamedField>( |
context(), static_cast<HValue*>(NULL), |
@@ -8247,6 +8339,7 @@ void HOptimizedGraphBuilder::VisitCall(Call* expr) { |
} |
return; |
} |
+ if (TryInlineApiFunctionCall(expr, receiver, true)) return; |
if (TryInlineCall(expr, true)) { // Drop function from environment. |
return; |