Index: src/hydrogen.cc |
diff --git a/src/hydrogen.cc b/src/hydrogen.cc |
index 339e0d3a8aba3297551cefdabb6e799b63201e1a..3d6284d0de2ad2e6a19c01054d09137466dc48c1 100644 |
--- a/src/hydrogen.cc |
+++ b/src/hydrogen.cc |
@@ -7927,9 +7927,9 @@ bool HOptimizedGraphBuilder::TryInlineSetter(Handle<JSFunction> setter, |
} |
-bool HOptimizedGraphBuilder::TryInlineApply(Handle<JSFunction> function, |
- Call* expr, |
- int arguments_count) { |
+bool HOptimizedGraphBuilder::TryInlineIndirectCall(Handle<JSFunction> function, |
+ Call* expr, |
+ int arguments_count) { |
return TryInline(function, |
arguments_count, |
NULL, |
@@ -7981,19 +7981,30 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinFunctionCall(Call* expr) { |
bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall( |
Call* expr, |
- HValue* receiver, |
- Handle<Map> receiver_map) { |
+ Handle<JSFunction> function, |
+ Handle<Map> receiver_map, |
+ int args_count_no_receiver, |
+ int drop_extra) { |
+ 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()); |
+ } |
+ } |
// 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: |
if (argument_count == 2) { |
HValue* index = Pop(); |
HValue* string = Pop(); |
- Drop(1); // Function. |
+ Drop(1 + drop_extra); // Function + extra. |
HInstruction* char_code = |
BuildStringCharCodeAt(string, index); |
if (id == kStringCharCodeAt) { |
@@ -8009,7 +8020,7 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall( |
case kStringFromCharCode: |
if (argument_count == 2) { |
HValue* argument = Pop(); |
- Drop(2); // Receiver and function. |
+ Drop(2 + drop_extra); // Receiver and function + extra. |
HInstruction* result = NewUncasted<HStringCharFromCode>(argument); |
ast_context()->ReturnInstruction(result, expr->id()); |
return true; |
@@ -8026,7 +8037,7 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall( |
case kMathClz32: |
if (argument_count == 2) { |
HValue* argument = Pop(); |
- Drop(2); // Receiver and function. |
+ Drop(2 + drop_extra); // Receiver and function + extra. |
HInstruction* op = NewUncasted<HUnaryMathOperation>(argument, id); |
ast_context()->ReturnInstruction(op, expr->id()); |
return true; |
@@ -8036,7 +8047,7 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall( |
if (argument_count == 3) { |
HValue* right = Pop(); |
HValue* left = Pop(); |
- Drop(2); // Receiver and function. |
+ Drop(2 + drop_extra); // Receiver and function + extra. |
HInstruction* result = NULL; |
// Use sqrt() if exponent is 0.5 or -0.5. |
if (right->IsConstant() && HConstant::cast(right)->HasDoubleValue()) { |
@@ -8068,7 +8079,7 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall( |
if (argument_count == 3) { |
HValue* right = Pop(); |
HValue* left = Pop(); |
- Drop(2); // Receiver and function. |
+ Drop(2 + drop_extra); // Receiver and function + extra. |
HMathMinMax::Operation op = (id == kMathMin) ? HMathMinMax::kMathMin |
: HMathMinMax::kMathMax; |
HInstruction* result = NewUncasted<HMathMinMax>(left, right, op); |
@@ -8080,7 +8091,7 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall( |
if (argument_count == 3) { |
HValue* right = Pop(); |
HValue* left = Pop(); |
- Drop(2); // Receiver and function. |
+ Drop(2 + drop_extra); // Receiver and function + extra. |
HInstruction* result = HMul::NewImul(zone(), context(), left, right); |
ast_context()->ReturnInstruction(result, expr->id()); |
return true; |
@@ -8094,7 +8105,7 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall( |
if (receiver_map->is_observed()) return false; |
ASSERT(receiver_map->is_extensible()); |
- Drop(expr->arguments()->length()); |
+ Drop(args_count_no_receiver); |
HValue* result; |
HValue* reduced_length; |
HValue* receiver = Pop(); |
@@ -8104,7 +8115,7 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall( |
checked_object, static_cast<HValue*>(NULL), |
HObjectAccess::ForArrayLength(elements_kind)); |
- Drop(1); // Function. |
+ Drop(1 + drop_extra); // Function + extra. |
{ NoObservableSideEffectsScope scope(this); |
IfBuilder length_checker(this); |
@@ -8170,12 +8181,12 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall( |
Handle<JSObject> prototype(JSObject::cast(receiver_map->prototype())); |
BuildCheckPrototypeMaps(prototype, Handle<JSObject>()); |
- const int argc = expr->arguments()->length(); |
+ const int argc = args_count_no_receiver; |
if (argc != 1) return false; |
HValue* value_to_push = Pop(); |
HValue* array = Pop(); |
- Drop(1); // Drop function. |
+ Drop(1 + drop_extra); // Drop function + extra. |
HInstruction* new_size = NULL; |
HValue* length = NULL; |
@@ -8227,9 +8238,10 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall( |
// Threshold for fast inlined Array.shift(). |
HConstant* inline_threshold = Add<HConstant>(static_cast<int32_t>(16)); |
- Drop(expr->arguments()->length()); |
+ Drop(args_count_no_receiver); |
HValue* receiver = Pop(); |
HValue* function = Pop(); |
+ Drop(drop_extra); // Drop extras after function. |
HValue* result; |
{ |
@@ -8341,7 +8353,7 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall( |
HValue* search_element = Pop(); |
HValue* receiver = Pop(); |
- Drop(1); // Drop function. |
+ Drop(1 + drop_extra); // Drop function + extra. |
ArrayIndexOfMode mode = (id == kArrayIndexOf) |
? kFirstIndexOf : kLastIndexOf; |
@@ -8538,35 +8550,90 @@ bool HOptimizedGraphBuilder::TryInlineApiCall(Handle<JSFunction> function, |
} |
-bool HOptimizedGraphBuilder::TryCallApply(Call* expr) { |
+void HOptimizedGraphBuilder::HandleIndirectCall(Call* expr, |
+ HValue* function, |
+ int arguments_count, |
+ int drop_extra) { |
+ 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)) { |
+ Drop(drop_extra); |
+ return; |
+ } |
+ |
+ Handle<Map> map; |
+ if (TryInlineBuiltinMethodCall(expr, known_function, map, |
+ args_count_no_receiver, drop_extra)) { |
+ 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 + drop_extra); // Function + extra. |
+ ast_context()->ReturnInstruction(call, expr->id()); |
+} |
+ |
+ |
+bool HOptimizedGraphBuilder::TryIndirectCall(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()->builtin_function_id() != kFunctionApply) { |
+ !expr->target()->shared()->HasBuiltinFunctionId()) { |
return false; |
} |
- if (current_info()->scope()->arguments() == NULL) 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; |
+ 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; |
+ 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(); |
+} |
- // Found pattern f.apply(receiver, arguments). |
- CHECK_ALIVE_OR_RETURN(VisitForValue(args->at(0)), true); |
+ |
+void HOptimizedGraphBuilder::BuildFunctionApply(Call* expr) { |
+ ZoneList<Expression*>* args = expr->arguments(); |
+ CHECK_ALIVE(VisitForValue(args->at(0))); |
HValue* receiver = Pop(); // receiver |
HValue* function = Pop(); // f |
Drop(1); // apply |
+ Handle<Map> function_map = expr->GetReceiverTypes()->first(); |
HValue* checked_function = AddCheckMap(function, function_map); |
if (function_state()->outer() == NULL) { |
@@ -8578,7 +8645,6 @@ bool HOptimizedGraphBuilder::TryCallApply(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. |
@@ -8592,23 +8658,36 @@ bool HOptimizedGraphBuilder::TryCallApply(Call* expr) { |
for (int i = 1; i < arguments_count; i++) { |
Push(arguments_values->at(i)); |
} |
+ HandleIndirectCall(expr, function, arguments_count, 0); |
+ } |
+} |
- 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; |
- } |
- PushArgumentsFromEnvironment(arguments_count); |
- HInvokeFunction* call = New<HInvokeFunction>( |
- function, known_function, arguments_count); |
- Drop(1); // Function. |
- ast_context()->ReturnInstruction(call, expr->id()); |
- return true; |
+// f.call(...) |
+void HOptimizedGraphBuilder::BuildFunctionCall(Call* expr) { |
+ HValue* function = Top(); // f |
+ Handle<Map> function_map = expr->GetReceiverTypes()->first(); |
+ HValue* checked_function = AddCheckMap(function, function_map); |
+ |
+ int drop_extra = 0; |
+ ZoneList<Expression*>* args = expr->arguments(); |
+ int args_length = args->length(); |
+ if (args_length == 0) { |
+ Drop(2); // function and call |
+ Push(function); |
+ Push(BuildWrapReceiver( |
+ graph()->GetConstantUndefined(), checked_function)); |
+ args_length = 1; |
+ } else { |
+ CHECK_ALIVE(VisitForValue(args->at(0))); |
+ Push(BuildWrapReceiver(Pop(), checked_function)); |
+ for (int i = 1; i < args_length; i++) { |
+ CHECK_ALIVE(VisitForValue(args->at(i))); |
+ } |
+ drop_extra = 1; // drop call later |
} |
+ |
+ HandleIndirectCall(expr, function, args_length, drop_extra); |
} |
@@ -8873,11 +8952,12 @@ void HOptimizedGraphBuilder::VisitCall(Call* expr) { |
HConstant::cast(function)->handle(isolate())); |
expr->set_target(known_function); |
- if (TryCallApply(expr)) return; |
+ if (TryIndirectCall(expr)) return; |
CHECK_ALIVE(VisitExpressions(expr->arguments())); |
Handle<Map> map = types->length() == 1 ? types->first() : Handle<Map>(); |
- if (TryInlineBuiltinMethodCall(expr, receiver, map)) { |
+ if (TryInlineBuiltinMethodCall(expr, known_function, map, |
+ expr->arguments()->length())) { |
if (FLAG_trace_inlining) { |
PrintF("Inlining builtin "); |
known_function->ShortPrint(); |