Index: src/compiler/effect-control-linearizer.cc |
diff --git a/src/compiler/effect-control-linearizer.cc b/src/compiler/effect-control-linearizer.cc |
index b87c15ac327601721a99ccb4acc1bd3126c8d9a4..1e36187b0d321be20eeb607b075756afc2e97004 100644 |
--- a/src/compiler/effect-control-linearizer.cc |
+++ b/src/compiler/effect-control-linearizer.cc |
@@ -726,6 +726,9 @@ bool EffectControlLinearizer::TryWireInStateEffect(Node* node, |
case IrOpcode::kEnsureWritableFastElements: |
state = LowerEnsureWritableFastElements(node, *effect, *control); |
break; |
+ case IrOpcode::kMaybeGrowFastElements: |
+ state = LowerMaybeGrowFastElements(node, frame_state, *effect, *control); |
+ break; |
case IrOpcode::kTransitionElementsKind: |
state = LowerTransitionElementsKind(node, *effect, *control); |
break; |
@@ -2632,19 +2635,14 @@ EffectControlLinearizer::LowerEnsureWritableFastElements(Node* node, |
{ |
// We need to create a copy of the {elements} for {object}. |
Operator::Properties properties = Operator::kEliminatable; |
- Callable callable = CodeFactory::CopyFixedArray(isolate()); |
+ Callable callable = CodeFactory::CopyFastSmiOrObjectElements(isolate()); |
CallDescriptor::Flags flags = CallDescriptor::kNoFlags; |
CallDescriptor const* const desc = Linkage::GetStubCallDescriptor( |
isolate(), graph()->zone(), callable.descriptor(), 0, flags, |
properties); |
vfalse = efalse = graph()->NewNode( |
- common()->Call(desc), jsgraph()->HeapConstant(callable.code()), |
- elements, jsgraph()->NoContextConstant(), efalse); |
- |
- // Store the new {elements} into {object}. |
- efalse = graph()->NewNode( |
- simplified()->StoreField(AccessBuilder::ForJSObjectElements()), object, |
- vfalse, efalse, if_false); |
+ common()->Call(desc), jsgraph()->HeapConstant(callable.code()), object, |
+ jsgraph()->NoContextConstant(), efalse); |
} |
control = graph()->NewNode(common()->Merge(2), if_true, if_false); |
@@ -2656,6 +2654,115 @@ EffectControlLinearizer::LowerEnsureWritableFastElements(Node* node, |
} |
EffectControlLinearizer::ValueEffectControl |
+EffectControlLinearizer::LowerMaybeGrowFastElements(Node* node, |
+ Node* frame_state, |
+ Node* effect, |
+ Node* control) { |
+ GrowFastElementsFlags flags = GrowFastElementsFlagsOf(node->op()); |
+ Node* object = node->InputAt(0); |
+ Node* elements = node->InputAt(1); |
+ Node* index = node->InputAt(2); |
+ Node* length = node->InputAt(3); |
+ |
+ Node* check0 = graph()->NewNode((flags & GrowFastElementsFlag::kHoleyElements) |
+ ? machine()->Uint32LessThanOrEqual() |
+ : machine()->Word32Equal(), |
+ length, index); |
+ Node* branch0 = graph()->NewNode(common()->Branch(), check0, control); |
+ |
+ Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0); |
+ Node* etrue0 = effect; |
+ Node* vtrue0 = elements; |
+ { |
+ // Load the length of the {elements} backing store. |
+ Node* elements_length = etrue0 = graph()->NewNode( |
+ simplified()->LoadField(AccessBuilder::ForFixedArrayLength()), elements, |
+ etrue0, if_true0); |
+ elements_length = ChangeSmiToInt32(elements_length); |
+ |
+ // Check if we need to grow the {elements} backing store. |
+ Node* check1 = |
+ graph()->NewNode(machine()->Uint32LessThan(), index, elements_length); |
+ Node* branch1 = |
+ graph()->NewNode(common()->Branch(BranchHint::kTrue), check1, if_true0); |
+ |
+ Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1); |
+ Node* etrue1 = etrue0; |
+ Node* vtrue1 = vtrue0; |
+ |
+ Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1); |
+ Node* efalse1 = etrue0; |
+ Node* vfalse1 = vtrue0; |
+ { |
+ // We need to grow the {elements} for {object}. |
+ Operator::Properties properties = Operator::kEliminatable; |
+ Callable callable = |
+ (flags & GrowFastElementsFlag::kDoubleElements) |
+ ? CodeFactory::GrowFastDoubleElements(isolate()) |
+ : CodeFactory::GrowFastSmiOrObjectElements(isolate()); |
+ CallDescriptor::Flags flags = CallDescriptor::kNoFlags; |
+ CallDescriptor const* const desc = Linkage::GetStubCallDescriptor( |
+ isolate(), graph()->zone(), callable.descriptor(), 0, flags, |
+ properties); |
+ vfalse1 = efalse1 = graph()->NewNode( |
+ common()->Call(desc), jsgraph()->HeapConstant(callable.code()), |
+ object, ChangeInt32ToSmi(index), jsgraph()->NoContextConstant(), |
+ efalse1); |
+ |
+ // Ensure that we were able to grow the {elements}. |
+ // TODO(turbofan): We use kSmi as reason here similar to Crankshaft, |
+ // but maybe we should just introduce a reason that makes sense. |
+ efalse1 = if_false1 = graph()->NewNode( |
+ common()->DeoptimizeIf(DeoptimizeReason::kSmi), ObjectIsSmi(vfalse1), |
+ frame_state, efalse1, if_false1); |
+ } |
+ |
+ if_true0 = graph()->NewNode(common()->Merge(2), if_true1, if_false1); |
+ etrue0 = |
+ graph()->NewNode(common()->EffectPhi(2), etrue1, efalse1, if_true0); |
+ vtrue0 = graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), |
+ vtrue1, vfalse1, if_true0); |
+ |
+ // For JSArray {object}s we also need to update the "length". |
+ if (flags & GrowFastElementsFlag::kArrayObject) { |
+ // Compute the new {length}. |
+ Node* object_length = ChangeInt32ToSmi(graph()->NewNode( |
+ machine()->Int32Add(), index, jsgraph()->Int32Constant(1))); |
+ |
+ // Update the "length" property of the {object}. |
+ etrue0 = |
+ graph()->NewNode(simplified()->StoreField( |
+ AccessBuilder::ForJSArrayLength(FAST_ELEMENTS)), |
+ object, object_length, etrue0, if_true0); |
+ } |
+ } |
+ |
+ Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0); |
+ Node* efalse0 = effect; |
+ Node* vfalse0 = elements; |
+ { |
+ // In case of non-holey {elements}, we need to verify that the {index} is |
+ // in-bounds, otherwise for holey {elements}, the check above already |
+ // guards the index (and the operator forces {index} to be unsigned). |
+ if (!(flags & GrowFastElementsFlag::kHoleyElements)) { |
+ Node* check1 = |
+ graph()->NewNode(machine()->Uint32LessThan(), index, length); |
+ efalse0 = if_false0 = graph()->NewNode( |
+ common()->DeoptimizeUnless(DeoptimizeReason::kOutOfBounds), check1, |
+ frame_state, efalse0, if_false0); |
+ } |
+ } |
+ |
+ control = graph()->NewNode(common()->Merge(2), if_true0, if_false0); |
+ effect = graph()->NewNode(common()->EffectPhi(2), etrue0, efalse0, control); |
+ Node* value = |
+ graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), vtrue0, |
+ vfalse0, control); |
+ |
+ return ValueEffectControl(value, effect, control); |
+} |
+ |
+EffectControlLinearizer::ValueEffectControl |
EffectControlLinearizer::LowerTransitionElementsKind(Node* node, Node* effect, |
Node* control) { |
ElementsTransition const transition = ElementsTransitionOf(node->op()); |