Commit 37aa13fe authored by Mike Stanton's avatar Mike Stanton Committed by Commit Bot

[Turbofan] Array.prototype.filter inlining.

Support inlining of Array.prototype.filter in TurboFan.

Bug: v8:1956
Change-Id: Iba4d683aaa86c6104e8a1cf4d0f549a0c516576a
Reviewed-on: https://chromium-review.googlesource.com/657021
Commit-Queue: Michael Stanton <mvstanton@chromium.org>
Reviewed-by: 's avatarMichael Starzinger <mstarzinger@chromium.org>
Cr-Commit-Position: refs/heads/master@{#48040}
parent 7742e534
......@@ -1565,6 +1565,66 @@ TF_BUILTIN(ArrayFilterLoopContinuation, ArrayBuiltinCodeStubAssembler) {
&ArrayBuiltinCodeStubAssembler::NullPostLoopAction);
}
TF_BUILTIN(ArrayFilterLoopEagerDeoptContinuation,
ArrayBuiltinCodeStubAssembler) {
Node* context = Parameter(Descriptor::kContext);
Node* receiver = Parameter(Descriptor::kReceiver);
Node* callbackfn = Parameter(Descriptor::kCallbackFn);
Node* this_arg = Parameter(Descriptor::kThisArg);
Node* array = Parameter(Descriptor::kArray);
Node* initial_k = Parameter(Descriptor::kInitialK);
Node* len = Parameter(Descriptor::kLength);
Node* to = Parameter(Descriptor::kTo);
Callable stub(
Builtins::CallableFor(isolate(), Builtins::kArrayFilterLoopContinuation));
Return(CallStub(stub, context, receiver, callbackfn, this_arg, array,
receiver, initial_k, len, to));
}
TF_BUILTIN(ArrayFilterLoopLazyDeoptContinuation,
ArrayBuiltinCodeStubAssembler) {
Node* context = Parameter(Descriptor::kContext);
Node* receiver = Parameter(Descriptor::kReceiver);
Node* callbackfn = Parameter(Descriptor::kCallbackFn);
Node* this_arg = Parameter(Descriptor::kThisArg);
Node* array = Parameter(Descriptor::kArray);
Node* initial_k = Parameter(Descriptor::kInitialK);
Node* len = Parameter(Descriptor::kLength);
Node* value_k = Parameter(Descriptor::kValueK);
Node* result = Parameter(Descriptor::kResult);
VARIABLE(to, MachineRepresentation::kTagged, Parameter(Descriptor::kTo));
// This custom lazy deopt point is right after the callback. filter() needs
// to pick up at the next step, which is setting the callback result in
// the output array. After incrementing k and to, we can glide into the loop
// continuation builtin.
Label true_continue(this, &to), false_continue(this);
// iii. If selected is true, then...
BranchIfToBooleanIsTrue(result, &true_continue, &false_continue);
BIND(&true_continue);
{
// 1. Perform ? CreateDataPropertyOrThrow(A, ToString(to), kValue).
CallRuntime(Runtime::kCreateDataProperty, context, array, to.value(),
value_k);
// 2. Increase to by 1.
to.Bind(NumberInc(to.value()));
Goto(&false_continue);
}
BIND(&false_continue);
// Increment k.
initial_k = NumberInc(initial_k);
Callable stub(
Builtins::CallableFor(isolate(), Builtins::kArrayFilterLoopContinuation));
Return(CallStub(stub, context, receiver, callbackfn, this_arg, array,
receiver, initial_k, len, to.value()));
}
TF_BUILTIN(ArrayFilter, ArrayBuiltinCodeStubAssembler) {
Node* argc =
ChangeInt32ToIntPtr(Parameter(BuiltinDescriptor::kArgumentsCount));
......
......@@ -287,6 +287,10 @@ namespace internal {
TFS(ArrayFilterLoopContinuation, kReceiver, kCallbackFn, kThisArg, kArray, \
kObject, kInitialK, kLength, kTo) \
TFJ(ArrayFilter, SharedFunctionInfo::kDontAdaptArgumentsSentinel) \
TFJ(ArrayFilterLoopEagerDeoptContinuation, 6, kCallbackFn, kThisArg, kArray, \
kInitialK, kLength, kTo) \
TFJ(ArrayFilterLoopLazyDeoptContinuation, 8, kCallbackFn, kThisArg, kArray, \
kInitialK, kLength, kValueK, kTo, kResult) \
/* ES6 #sec-array.prototype.foreach */ \
TFS(ArrayMapLoopContinuation, kReceiver, kCallbackFn, kThisArg, kArray, \
kObject, kInitialK, kLength, kTo) \
......
......@@ -210,6 +210,16 @@ Callable Builtins::CallableFor(Isolate* isolate, Name name) {
BUILTIN_CODE(isolate, ArrayMapLoopLazyDeoptContinuation);
return Callable(code, BuiltinDescriptor(isolate));
}
case kArrayFilterLoopEagerDeoptContinuation: {
Handle<Code> code =
BUILTIN_CODE(isolate, ArrayFilterLoopEagerDeoptContinuation);
return Callable(code, BuiltinDescriptor(isolate));
}
case kArrayFilterLoopLazyDeoptContinuation: {
Handle<Code> code =
BUILTIN_CODE(isolate, ArrayFilterLoopLazyDeoptContinuation);
return Callable(code, BuiltinDescriptor(isolate));
}
default:
UNREACHABLE();
}
......
This diff is collapsed.
......@@ -71,6 +71,7 @@ class JSCallReducer final : public AdvancedReducer {
Reduction ReduceReflectGetPrototypeOf(Node* node);
Reduction ReduceArrayForEach(Handle<JSFunction> function, Node* node);
Reduction ReduceArrayMap(Handle<JSFunction> function, Node* node);
Reduction ReduceArrayFilter(Handle<JSFunction> function, Node* node);
Reduction ReduceCallOrConstructWithArrayLikeOrSpread(
Node* node, int arity, CallFrequency const& frequency,
VectorSlotPair const& feedback);
......@@ -84,6 +85,33 @@ class JSCallReducer final : public AdvancedReducer {
Reduction ReduceSoftDeoptimize(Node* node, DeoptimizeReason reason);
// Returns the updated {to} node, and updates control and effect along the
// way.
Node* DoFilterPostCallbackWork(ElementsKind kind, Node* context,
Node** control, Node** effect, Node* a,
Node* to, Node* element, Node* callback_value);
// If {fncallback} is not callable, throw via %ThrowCalledNonCallable.
// {control} is altered, and new nodes {check_fail} and {check_throw} are
// returned. {check_fail} is the control branch where IsCallable failed,
// and {check_throw} is the call to %ThrowCalledNonCallable in that
// branch.
void WireInCallbackIsCallableCheck(Node* fncallback, Node* context,
Node* check_frame_state, Node* effect,
Node** control, Node** check_fail,
Node** check_throw);
void RewirePostCallbackExceptionEdges(Node* check_throw, Node* on_exception,
Node* effect, Node** check_fail,
Node** control);
// Creates a map check for {receiver} against {orig_map}. Updates {effect}.
void WireInMapCheck(Node* orig_map, Node* receiver, Node** effect,
Node* control);
// Load receiver[k], first bounding k by receiver array length.
// k is thusly changed, and the effect is changed as well.
Node* SafeLoadElement(Node* receiver, Node* control, Node** effect, Node** k);
Graph* graph() const;
JSGraph* jsgraph() const { return jsgraph_; }
Isolate* isolate() const;
......
This diff is collapsed.
......@@ -35,3 +35,19 @@
%OptimizeFunctionOnNextCall(foo);
assertInstanceof(foo(), TypeError);
})();
(function TestNonCallableFilter() {
function foo() { [].filter(undefined); }
assertThrows(foo, TypeError);
assertThrows(foo, TypeError);
%OptimizeFunctionOnNextCall(foo);
assertThrows(foo, TypeError);
})();
(function TestNonCallableFilterCaught() {
function foo() { try { [].filter(undefined) } catch(e) { return e } }
assertInstanceof(foo(), TypeError);
assertInstanceof(foo(), TypeError);
%OptimizeFunctionOnNextCall(foo);
assertInstanceof(foo(), TypeError);
})();
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