Chromium Code Reviews| 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..e89062fcf69593d962ff40f27cffd7a9ccce3ce3 100644 |
| --- a/src/compiler/js-builtin-reducer.cc |
| +++ b/src/compiler/js-builtin-reducer.cc |
| @@ -1252,6 +1252,108 @@ Reduction JSBuiltinReducer::ReduceDateGetTime(Node* node) { |
| return NoChange(); |
| } |
| +// ES6 section 19.2.3.2 Function.prototype.bind ( thisArg, ...args ) |
| +Reduction JSBuiltinReducer::ReduceFunctionBind(Node* node) { |
| + 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); |
|
Jarin
2017/06/02 08:07:42
Please describe in a comment what is the layout of
Benedikt Meurer
2017/06/02 11:58:43
Done.
|
| + 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 +2428,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; |