Index: src/compiler/js-builtin-reducer.cc |
diff --git a/src/compiler/js-builtin-reducer.cc b/src/compiler/js-builtin-reducer.cc |
index 94946a5279e9e6b8cc938239719886f70713871f..bbd5a92a7fd0400a6b82cbf2f747e747405a24cd 100644 |
--- a/src/compiler/js-builtin-reducer.cc |
+++ b/src/compiler/js-builtin-reducer.cc |
@@ -245,6 +245,75 @@ Reduction JSBuiltinReducer::ReduceArrayPop(Node* node) { |
return NoChange(); |
} |
+// ES6 section 22.1.3.18 Array.prototype.push ( ) |
+Reduction JSBuiltinReducer::ReduceArrayPush(Node* node) { |
+ Handle<Map> receiver_map; |
+ // We need exactly target, receiver and value parameters. |
+ if (node->op()->ValueInputCount() != 3) return NoChange(); |
+ Node* receiver = NodeProperties::GetValueInput(node, 1); |
+ Node* effect = NodeProperties::GetEffectInput(node); |
+ Node* control = NodeProperties::GetControlInput(node); |
+ Node* value = NodeProperties::GetValueInput(node, 2); |
+ if (GetMapWitness(node).ToHandle(&receiver_map) && |
+ CanInlineArrayResizeOperation(receiver_map)) { |
+ // Install code dependencies on the {receiver} prototype maps and the |
+ // global array protector cell. |
+ dependencies()->AssumePropertyCell(factory()->array_protector()); |
+ dependencies()->AssumePrototypeMapsStable(receiver_map); |
+ |
+ // TODO(turbofan): Perform type checks on the {value}. We are not guaranteed |
+ // to learn from these checks in case they fail, as the witness (i.e. the |
+ // map check from the LoadIC for a.push) might not be executed in baseline |
+ // code (after we stored the value in the builtin and thereby changed the |
+ // elements kind of a) before be decide to optimize this function again. We |
+ // currently don't have a proper way to deal with this; the proper solution |
+ // here is to learn on deopt, i.e. disable Array.prototype.push inlining |
+ // for this function. |
+ if (IsFastSmiElementsKind(receiver_map->elements_kind())) { |
+ value = effect = graph()->NewNode(simplified()->CheckTaggedSigned(), |
+ value, effect, control); |
+ } else if (IsFastDoubleElementsKind(receiver_map->elements_kind())) { |
+ value = effect = |
+ graph()->NewNode(simplified()->CheckNumber(), value, effect, control); |
+ // Make sure we do not store signaling NaNs into double arrays. |
+ value = graph()->NewNode(simplified()->NumberSilenceNaN(), value); |
+ } |
+ |
+ // Load the "length" property of the {receiver}. |
+ Node* length = effect = graph()->NewNode( |
+ simplified()->LoadField( |
+ AccessBuilder::ForJSArrayLength(receiver_map->elements_kind())), |
+ receiver, effect, control); |
+ |
+ // Load the elements backing store of the {receiver}. |
+ Node* elements = effect = graph()->NewNode( |
+ simplified()->LoadField(AccessBuilder::ForJSObjectElements()), receiver, |
+ effect, control); |
+ |
+ // TODO(turbofan): Check if we need to grow the {elements} backing store. |
+ // This will deopt if we cannot grow the array further, and we currently |
+ // don't necessarily learn from it. See the comment on the value type check |
+ // above. |
+ GrowFastElementsFlags flags = GrowFastElementsFlag::kArrayObject; |
+ if (IsFastDoubleElementsKind(receiver_map->elements_kind())) { |
+ flags |= GrowFastElementsFlag::kDoubleElements; |
+ } |
+ elements = effect = |
+ graph()->NewNode(simplified()->MaybeGrowFastElements(flags), receiver, |
+ elements, length, length, effect, control); |
+ |
+ // Append the value to the {elements}. |
+ effect = graph()->NewNode( |
+ simplified()->StoreElement( |
+ AccessBuilder::ForFixedArrayElement(receiver_map->elements_kind())), |
+ elements, length, value, effect, control); |
+ |
+ ReplaceWithValue(node, value, effect, control); |
+ return Replace(value); |
+ } |
+ return NoChange(); |
+} |
+ |
// ES6 section 20.2.2.1 Math.abs ( x ) |
Reduction JSBuiltinReducer::ReduceMathAbs(Node* node) { |
JSCallReduction r(node); |
@@ -898,6 +967,8 @@ Reduction JSBuiltinReducer::Reduce(Node* node) { |
switch (r.GetBuiltinFunctionId()) { |
case kArrayPop: |
return ReduceArrayPop(node); |
+ case kArrayPush: |
+ return ReduceArrayPush(node); |
case kMathAbs: |
reduction = ReduceMathAbs(node); |
break; |