| 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;
|
|
|