Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(430)

Unified Diff: src/hydrogen.cc

Issue 350913002: Optimize Function.prototype.call (Closed) Base URL: https://github.com/v8/v8.git@master
Patch Set: Created 6 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/hydrogen.h ('k') | src/objects.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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();
« no previous file with comments | « src/hydrogen.h ('k') | src/objects.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698