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

Unified Diff: src/compiler/js-builtin-reducer.cc

Issue 2916063002: [turbofan] Optimize Function.prototype.bind for the common case. (Closed)
Patch Set: Address feedback. Created 3 years, 7 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/compiler/js-builtin-reducer.h ('k') | src/compiler/typer.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/compiler/js-builtin-reducer.cc
diff --git a/src/compiler/js-builtin-reducer.cc b/src/compiler/js-builtin-reducer.cc
index 3d4e53378170e99a0942830650a167fb1d919d0a..ba30f4e3767b055c9e7ae8ec1e22f508c060620a 100644
--- a/src/compiler/js-builtin-reducer.cc
+++ b/src/compiler/js-builtin-reducer.cc
@@ -1252,6 +1252,114 @@ Reduction JSBuiltinReducer::ReduceDateGetTime(Node* node) {
return NoChange();
}
+// ES6 section 19.2.3.2 Function.prototype.bind ( thisArg, ...args )
+Reduction JSBuiltinReducer::ReduceFunctionBind(Node* node) {
+ // Value inputs to the {node} are as follows:
+ //
+ // - target, which is Function.prototype.bind JSFunction
+ // - receiver, which is the [[BoundTargetFunction]]
+ // - bound_this (optional), which is the [[BoundThis]]
+ // - and all the remaining value inouts are [[BoundArguments]]
+ Node* receiver = NodeProperties::GetValueInput(node, 1);
+ Type* receiver_type = NodeProperties::GetType(receiver);
+ Node* bound_this = (node->op()->ValueInputCount() < 3)
+ ? jsgraph()->UndefinedConstant()
+ : NodeProperties::GetValueInput(node, 2);
+ Node* effect = NodeProperties::GetEffectInput(node);
+ Node* control = NodeProperties::GetControlInput(node);
+ if (receiver_type->IsHeapConstant() &&
+ receiver_type->AsHeapConstant()->Value()->IsJSFunction()) {
+ Handle<JSFunction> target_function =
+ Handle<JSFunction>::cast(receiver_type->AsHeapConstant()->Value());
+
+ // Check that the "length" property on the {target_function} is the
+ // default JSFunction accessor.
+ LookupIterator length_lookup(target_function, factory()->length_string(),
+ target_function, LookupIterator::OWN);
+ if (length_lookup.state() != LookupIterator::ACCESSOR ||
+ !length_lookup.GetAccessors()->IsAccessorInfo()) {
+ return NoChange();
+ }
+
+ // Check that the "name" property on the {target_function} is the
+ // default JSFunction accessor.
+ LookupIterator name_lookup(target_function, factory()->name_string(),
+ target_function, LookupIterator::OWN);
+ if (name_lookup.state() != LookupIterator::ACCESSOR ||
+ !name_lookup.GetAccessors()->IsAccessorInfo()) {
+ return NoChange();
+ }
+
+ // Determine the prototype of the {target_function}.
+ Handle<Object> prototype(target_function->map()->prototype(), isolate());
+
+ // Setup the map for the JSBoundFunction instance.
+ Handle<Map> map = target_function->IsConstructor()
+ ? isolate()->bound_function_with_constructor_map()
+ : isolate()->bound_function_without_constructor_map();
+ if (map->prototype() != *prototype) {
+ map = Map::TransitionToPrototype(map, prototype, REGULAR_PROTOTYPE);
+ }
+ DCHECK_EQ(target_function->IsConstructor(), map->is_constructor());
+
+ // Create the [[BoundArguments]] for the result.
+ Node* bound_arguments = jsgraph()->EmptyFixedArrayConstant();
+ if (node->op()->ValueInputCount() > 3) {
+ int const length = node->op()->ValueInputCount() - 3;
+ effect = graph()->NewNode(
+ common()->BeginRegion(RegionObservability::kNotObservable), effect);
+ bound_arguments = effect = graph()->NewNode(
+ simplified()->Allocate(Type::OtherInternal(), NOT_TENURED),
+ jsgraph()->Constant(FixedArray::SizeFor(length)), effect, control);
+ effect = graph()->NewNode(
+ simplified()->StoreField(AccessBuilder::ForMap()), bound_arguments,
+ jsgraph()->FixedArrayMapConstant(), effect, control);
+ effect = graph()->NewNode(
+ simplified()->StoreField(AccessBuilder::ForFixedArrayLength()),
+ bound_arguments, jsgraph()->Constant(length), effect, control);
+ for (int i = 0; i < length; ++i) {
+ effect = graph()->NewNode(
+ simplified()->StoreField(AccessBuilder::ForFixedArraySlot(i)),
+ bound_arguments, NodeProperties::GetValueInput(node, 3 + i), effect,
+ control);
+ }
+ bound_arguments = effect =
+ graph()->NewNode(common()->FinishRegion(), bound_arguments, effect);
+ }
+
+ // Create the JSBoundFunction result.
+ effect = graph()->NewNode(
+ common()->BeginRegion(RegionObservability::kNotObservable), effect);
+ Node* value = effect = graph()->NewNode(
+ simplified()->Allocate(Type::BoundFunction(), NOT_TENURED),
+ jsgraph()->Constant(JSBoundFunction::kSize), effect, control);
+ effect = graph()->NewNode(simplified()->StoreField(AccessBuilder::ForMap()),
+ value, jsgraph()->Constant(map), effect, control);
+ effect = graph()->NewNode(
+ simplified()->StoreField(AccessBuilder::ForJSObjectProperties()), value,
+ jsgraph()->EmptyFixedArrayConstant(), effect, control);
+ effect = graph()->NewNode(
+ simplified()->StoreField(AccessBuilder::ForJSObjectElements()), value,
+ jsgraph()->EmptyFixedArrayConstant(), effect, control);
+ effect = graph()->NewNode(
+ simplified()->StoreField(
+ AccessBuilder::ForJSBoundFunctionBoundTargetFunction()),
+ value, receiver, effect, control);
+ effect = graph()->NewNode(
+ simplified()->StoreField(AccessBuilder::ForJSBoundFunctionBoundThis()),
+ value, bound_this, effect, control);
+ effect =
+ graph()->NewNode(simplified()->StoreField(
+ AccessBuilder::ForJSBoundFunctionBoundArguments()),
+ value, bound_arguments, effect, control);
+ value = effect = graph()->NewNode(common()->FinishRegion(), value, effect);
+
+ ReplaceWithValue(node, value, effect, control);
+ return Replace(value);
+ }
+ return NoChange();
+}
+
// ES6 section 18.2.2 isFinite ( number )
Reduction JSBuiltinReducer::ReduceGlobalIsFinite(Node* node) {
JSCallReduction r(node);
@@ -2326,6 +2434,8 @@ Reduction JSBuiltinReducer::Reduce(Node* node) {
return ReduceDateNow(node);
case kDateGetTime:
return ReduceDateGetTime(node);
+ case kFunctionBind:
+ return ReduceFunctionBind(node);
case kGlobalIsFinite:
reduction = ReduceGlobalIsFinite(node);
break;
« no previous file with comments | « src/compiler/js-builtin-reducer.h ('k') | src/compiler/typer.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698