Index: src/hydrogen.cc |
diff --git a/src/hydrogen.cc b/src/hydrogen.cc |
index c75046ddb0fecf2b3cf66bc47f43b6a7d9deca18..8be2c6717e2e53107a498adf5a263a11a4275377 100644 |
--- a/src/hydrogen.cc |
+++ b/src/hydrogen.cc |
@@ -7923,9 +7923,9 @@ bool HOptimizedGraphBuilder::TryInlineSetter(Handle<JSFunction> setter, |
} |
-bool HOptimizedGraphBuilder::TryInlineIndirectCall(Handle<JSFunction> function, |
- Call* expr, |
- int arguments_count) { |
+bool HOptimizedGraphBuilder::TryInlineApply(Handle<JSFunction> function, |
+ Call* expr, |
+ int arguments_count) { |
return TryInline(function, |
arguments_count, |
NULL, |
@@ -7977,22 +7977,12 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinFunctionCall(Call* expr) { |
bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall( |
Call* expr, |
- Handle<JSFunction> function, |
- Handle<Map> receiver_map, |
- int args_count_no_receiver) { |
- if (!function->shared()->HasBuiltinFunctionId()) return false; |
- BuiltinFunctionId id = function->shared()->builtin_function_id(); |
- int argument_count = args_count_no_receiver + 1; // Plus receiver. |
- |
- if (receiver_map.is_null()) { |
- HValue* receiver = environment()->ExpressionStackAt(args_count_no_receiver); |
- if (receiver->IsConstant() && |
- HConstant::cast(receiver)->handle(isolate())->IsHeapObject()) { |
- receiver_map = handle(Handle<HeapObject>::cast( |
- HConstant::cast(receiver)->handle(isolate()))->map()); |
- } |
- } |
+ HValue* receiver, |
+ Handle<Map> receiver_map) { |
// Try to inline calls like Math.* as operations in the calling function. |
+ if (!expr->target()->shared()->HasBuiltinFunctionId()) return false; |
+ BuiltinFunctionId id = expr->target()->shared()->builtin_function_id(); |
+ int argument_count = expr->arguments()->length() + 1; // Plus receiver. |
switch (id) { |
case kStringCharCodeAt: |
case kStringCharAt: |
@@ -8100,7 +8090,7 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall( |
if (receiver_map->is_observed()) return false; |
ASSERT(receiver_map->is_extensible()); |
- Drop(args_count_no_receiver); |
+ Drop(expr->arguments()->length()); |
HValue* result; |
HValue* reduced_length; |
HValue* receiver = Pop(); |
@@ -8176,7 +8166,7 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall( |
Handle<JSObject> prototype(JSObject::cast(receiver_map->prototype())); |
BuildCheckPrototypeMaps(prototype, Handle<JSObject>()); |
- const int argc = args_count_no_receiver; |
+ const int argc = expr->arguments()->length(); |
if (argc != 1) return false; |
HValue* value_to_push = Pop(); |
@@ -8233,7 +8223,7 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall( |
// Threshold for fast inlined Array.shift(). |
HConstant* inline_threshold = Add<HConstant>(static_cast<int32_t>(16)); |
- Drop(args_count_no_receiver); |
+ Drop(expr->arguments()->length()); |
HValue* receiver = Pop(); |
HValue* function = Pop(); |
HValue* result; |
@@ -8544,83 +8534,31 @@ bool HOptimizedGraphBuilder::TryInlineApiCall(Handle<JSFunction> function, |
} |
-void HOptimizedGraphBuilder::HandleIndirectCall(Call* expr, |
- HValue* function, |
- int arguments_count) { |
- Handle<JSFunction> known_function; |
- int args_count_no_receiver = arguments_count - 1; |
- if (function->IsConstant() && |
- HConstant::cast(function)->handle(isolate())->IsJSFunction()) { |
- known_function = Handle<JSFunction>::cast( |
- HConstant::cast(function)->handle(isolate())); |
- if (TryInlineIndirectCall(known_function, expr, args_count_no_receiver)) { |
- return; |
- } |
- |
- Handle<Map> map; |
- if (TryInlineBuiltinMethodCall(expr, known_function, map, |
- args_count_no_receiver)) { |
- if (FLAG_trace_inlining) { |
- PrintF("Inlining builtin "); |
- known_function->ShortPrint(); |
- PrintF("\n"); |
- } |
- return; |
- } |
- } |
- |
- PushArgumentsFromEnvironment(arguments_count); |
- HInvokeFunction* call = New<HInvokeFunction>( |
- function, known_function, arguments_count); |
- Drop(1); // Function |
- ast_context()->ReturnInstruction(call, expr->id()); |
-} |
- |
- |
-bool HOptimizedGraphBuilder::TryIndirectCall(Call* expr) { |
+bool HOptimizedGraphBuilder::TryCallApply(Call* expr) { |
ASSERT(expr->expression()->IsProperty()); |
if (!expr->IsMonomorphic()) { |
return false; |
} |
- |
Handle<Map> function_map = expr->GetReceiverTypes()->first(); |
if (function_map->instance_type() != JS_FUNCTION_TYPE || |
- !expr->target()->shared()->HasBuiltinFunctionId()) { |
+ !expr->target()->shared()->HasBuiltinFunctionId() || |
+ expr->target()->shared()->builtin_function_id() != kFunctionApply) { |
return false; |
} |
- switch (expr->target()->shared()->builtin_function_id()) { |
- case kFunctionCall: { |
- BuildFunctionCall(expr); |
- return true; |
- } |
- case kFunctionApply: { |
- // For .apply, only the pattern f.apply(receiver, arguments) |
- // is supported. |
- if (current_info()->scope()->arguments() == NULL) return false; |
- |
- ZoneList<Expression*>* args = expr->arguments(); |
- if (args->length() != 2) return false; |
+ if (current_info()->scope()->arguments() == NULL) return false; |
- VariableProxy* arg_two = args->at(1)->AsVariableProxy(); |
- if (arg_two == NULL || !arg_two->var()->IsStackAllocated()) return false; |
- HValue* arg_two_value = LookupAndMakeLive(arg_two->var()); |
- if (!arg_two_value->CheckFlag(HValue::kIsArguments)) return false; |
- BuildFunctionApply(expr); |
- return true; |
- } |
- default: { |
- return false; |
- } |
- } |
- UNREACHABLE(); |
-} |
+ ZoneList<Expression*>* args = expr->arguments(); |
+ if (args->length() != 2) return false; |
+ VariableProxy* arg_two = args->at(1)->AsVariableProxy(); |
+ if (arg_two == NULL || !arg_two->var()->IsStackAllocated()) return false; |
+ HValue* arg_two_value = LookupAndMakeLive(arg_two->var()); |
+ if (!arg_two_value->CheckFlag(HValue::kIsArguments)) return false; |
-void HOptimizedGraphBuilder::BuildFunctionApply(Call* expr) { |
- ZoneList<Expression*>* args = expr->arguments(); |
- CHECK_ALIVE(VisitForValue(args->at(0))); |
+ // Found pattern f.apply(receiver, arguments). |
+ CHECK_ALIVE_OR_RETURN(VisitForValue(args->at(0)), true); |
HValue* receiver = Pop(); // receiver |
HValue* function = Pop(); // f |
Drop(1); // apply |
@@ -8634,6 +8572,7 @@ void HOptimizedGraphBuilder::BuildFunctionApply(Call* expr) { |
length, |
elements); |
ast_context()->ReturnInstruction(result, expr->id()); |
+ return true; |
} else { |
// We are inside inlined function and we know exactly what is inside |
// arguments object. But we need to be able to materialize at deopt. |
@@ -8647,34 +8586,23 @@ void HOptimizedGraphBuilder::BuildFunctionApply(Call* expr) { |
for (int i = 1; i < arguments_count; i++) { |
Push(arguments_values->at(i)); |
} |
- HandleIndirectCall(expr, function, arguments_count); |
- } |
-} |
+ Handle<JSFunction> known_function; |
+ if (function->IsConstant() && |
+ HConstant::cast(function)->handle(isolate())->IsJSFunction()) { |
+ known_function = Handle<JSFunction>::cast( |
+ HConstant::cast(function)->handle(isolate())); |
+ int args_count = arguments_count - 1; // Excluding receiver. |
+ if (TryInlineApply(known_function, expr, args_count)) return true; |
+ } |
-// f.call(...) |
-void HOptimizedGraphBuilder::BuildFunctionCall(Call* expr) { |
- HValue* function = Pop(); // f |
- HValue* receiver; |
- ZoneList<Expression*>* args = expr->arguments(); |
- int args_length = args->length(); |
- Drop(1); // call |
- |
- if (args_length == 0) { |
- receiver = graph()->GetConstantUndefined(); |
- args_length = 1; |
- } else { |
- CHECK_ALIVE(VisitForValue(args->at(0))); |
- receiver = Pop(); |
- } |
- receiver = BuildWrapReceiver(receiver, function); |
- |
- Push(function); |
- Push(receiver); |
- for (int i = 1; i < args_length; i++) { |
- CHECK_ALIVE(VisitForValue(args->at(i))); |
+ PushArgumentsFromEnvironment(arguments_count); |
+ HInvokeFunction* call = New<HInvokeFunction>( |
+ function, known_function, arguments_count); |
+ Drop(1); // Function. |
+ ast_context()->ReturnInstruction(call, expr->id()); |
+ return true; |
} |
- HandleIndirectCall(expr, function, args_length); |
} |
@@ -8939,12 +8867,11 @@ void HOptimizedGraphBuilder::VisitCall(Call* expr) { |
HConstant::cast(function)->handle(isolate())); |
expr->set_target(known_function); |
- if (TryIndirectCall(expr)) return; |
+ if (TryCallApply(expr)) return; |
CHECK_ALIVE(VisitExpressions(expr->arguments())); |
Handle<Map> map = types->length() == 1 ? types->first() : Handle<Map>(); |
- if (TryInlineBuiltinMethodCall(expr, known_function, map, |
- expr->arguments()->length())) { |
+ if (TryInlineBuiltinMethodCall(expr, receiver, map)) { |
if (FLAG_trace_inlining) { |
PrintF("Inlining builtin "); |
known_function->ShortPrint(); |