Commit e57a99ce authored by Benedikt Meurer's avatar Benedikt Meurer Committed by Commit Bot

[ic] Teach CallIC about JSBoundFunction.

This addresses the odd performance cliff, where the CallIC tracks known
JSFunction targets, but goes MEGAMORPHIC when it sees a JSBoundFunction
target. With this fix in place the micro-benchmark on the bug goes from

  arrowCall: 82 ms.
  boundCall: 234 ms.

to

  arrowCall: 81 ms.
  boundCall: 80 ms.

so Function#bind doesn't cause any additional overhead anymore.

Bug: v8:5267, v8:6962
Change-Id: Iaceaf89fd3e99e2afe2ae45e96a6813a3ef8b1d2
Reviewed-on: https://chromium-review.googlesource.com/727879
Commit-Queue: Benedikt Meurer <bmeurer@chromium.org>
Reviewed-by: 's avatarJaroslav Sevcik <jarin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#48722}
parent 4c5c5bc0
...@@ -1985,7 +1985,7 @@ Reduction JSCallReducer::ReduceJSCall(Node* node) { ...@@ -1985,7 +1985,7 @@ Reduction JSCallReducer::ReduceJSCall(Node* node) {
if (!ShouldUseCallICFeedback(target)) return NoChange(); if (!ShouldUseCallICFeedback(target)) return NoChange();
Handle<WeakCell> cell = Handle<WeakCell>::cast(feedback); Handle<WeakCell> cell = Handle<WeakCell>::cast(feedback);
if (cell->value()->IsJSFunction()) { if (cell->value()->IsCallable()) {
Node* target_function = Node* target_function =
jsgraph()->Constant(handle(cell->value(), isolate())); jsgraph()->Constant(handle(cell->value(), isolate()));
......
...@@ -641,15 +641,42 @@ void InterpreterAssembler::CollectCallFeedback(Node* target, Node* context, ...@@ -641,15 +641,42 @@ void InterpreterAssembler::CollectCallFeedback(Node* target, Node* context,
// context. // context.
Comment("check if function in same native context"); Comment("check if function in same native context");
GotoIf(TaggedIsSmi(target), &mark_megamorphic); GotoIf(TaggedIsSmi(target), &mark_megamorphic);
// TODO(bmeurer): Add support for arbitrary callables here, and // Check if the {target} is a JSFunction or JSBoundFunction
// check via GetFunctionRealm (see src/objects.cc). // in the current native context.
GotoIfNot(IsJSFunction(target), &mark_megamorphic); VARIABLE(var_target, MachineRepresentation::kTagged, target);
Node* target_context = Label loop(this, &var_target), done_loop(this);
LoadObjectField(target, JSFunction::kContextOffset); Goto(&loop);
Node* target_native_context = LoadNativeContext(target_context); BIND(&loop);
GotoIfNot(WordEqual(LoadNativeContext(context), target_native_context), {
&mark_megamorphic); Label if_boundfunction(this), if_function(this);
Node* target = var_target.value();
CSA_ASSERT(this, TaggedIsNotSmi(target));
Node* target_instance_type = LoadInstanceType(target);
GotoIf(InstanceTypeEqual(target_instance_type, JS_BOUND_FUNCTION_TYPE),
&if_boundfunction);
Branch(InstanceTypeEqual(target_instance_type, JS_FUNCTION_TYPE),
&if_function, &mark_megamorphic);
BIND(&if_function);
{
// Check that the JSFunction {target} is in the current native
// context.
Node* target_context =
LoadObjectField(target, JSFunction::kContextOffset);
Node* target_native_context = LoadNativeContext(target_context);
Branch(WordEqual(LoadNativeContext(context), target_native_context),
&done_loop, &mark_megamorphic);
}
BIND(&if_boundfunction);
{
// Continue with the [[BoundTargetFunction]] of {target}.
var_target.Bind(LoadObjectField(
target, JSBoundFunction::kBoundTargetFunctionOffset));
Goto(&loop);
}
}
BIND(&done_loop);
CreateWeakCellInFeedbackVector(feedback_vector, SmiTag(slot_id), target); CreateWeakCellInFeedbackVector(feedback_vector, SmiTag(slot_id), target);
// Reset profiler ticks. // Reset profiler ticks.
StoreObjectFieldNoWriteBarrier(feedback_vector, StoreObjectFieldNoWriteBarrier(feedback_vector,
......
...@@ -99,3 +99,15 @@ ...@@ -99,3 +99,15 @@
assertEquals([1, 2, 3], foo([0, 1, 2])); assertEquals([1, 2, 3], foo([0, 1, 2]));
assertEquals([2, 3, 4], foo([1, 2, 3])); assertEquals([2, 3, 4], foo([1, 2, 3]));
})(); })();
(function() {
const add = (x, y) => x + y;
const inc = add.bind(null, 1);
function foo(inc) { return inc(1); }
assertEquals(2, foo(inc));
assertEquals(2, foo(inc));
%OptimizeFunctionOnNextCall(foo);
assertEquals(2, foo(inc));
})();
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment