Index: src/compiler/effect-control-linearizer.cc |
diff --git a/src/compiler/effect-control-linearizer.cc b/src/compiler/effect-control-linearizer.cc |
index cd697e0a9dcff1e1da61eda227fddf4477880de7..959712f075fc3f34e7c51426f6a0efa7b04ff98b 100644 |
--- a/src/compiler/effect-control-linearizer.cc |
+++ b/src/compiler/effect-control-linearizer.cc |
@@ -706,6 +706,9 @@ bool EffectControlLinearizer::TryWireInStateEffect(Node* node, |
case IrOpcode::kPlainPrimitiveToFloat64: |
state = LowerPlainPrimitiveToFloat64(node, *effect, *control); |
break; |
+ case IrOpcode::kTransitionElementsKind: |
+ state = LowerTransitionElementsKind(node, *effect, *control); |
+ break; |
default: |
return false; |
} |
@@ -2121,6 +2124,65 @@ EffectControlLinearizer::LowerPlainPrimitiveToFloat64(Node* node, Node* effect, |
return ValueEffectControl(value, effect, control); |
} |
+EffectControlLinearizer::ValueEffectControl |
+EffectControlLinearizer::LowerTransitionElementsKind(Node* node, Node* effect, |
+ Node* control) { |
+ ElementsTransition const transition = ElementsTransitionOf(node->op()); |
+ Node* object = node->InputAt(0); |
+ Node* source_map = node->InputAt(1); |
+ Node* target_map = node->InputAt(2); |
+ |
+ // Load the current map of {object}. |
+ Node* object_map = effect = |
+ graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), object, |
+ effect, control); |
+ |
+ // Check if {object_map} is the same as {source_map}. |
+ Node* check = |
+ graph()->NewNode(machine()->WordEqual(), object_map, source_map); |
+ Node* branch = |
+ graph()->NewNode(common()->Branch(BranchHint::kFalse), check, control); |
+ |
+ // Migrate the {object} from {source_map} to {target_map}. |
+ Node* if_true = graph()->NewNode(common()->IfTrue(), branch); |
+ Node* etrue = effect; |
+ { |
+ switch (transition) { |
+ case ElementsTransition::kFastTransition: { |
+ // In-place migration of {object}, just store the {target_map}. |
+ etrue = |
+ graph()->NewNode(simplified()->StoreField(AccessBuilder::ForMap()), |
+ object, target_map, etrue, if_true); |
+ break; |
+ } |
+ case ElementsTransition::kSlowTransition: { |
+ // Instance migration, call out to the runtime for {object}. |
+ Operator::Properties properties = |
+ Operator::kNoDeopt | Operator::kNoThrow; |
+ Runtime::FunctionId id = Runtime::kTransitionElementsKind; |
+ CallDescriptor const* desc = Linkage::GetRuntimeCallDescriptor( |
+ graph()->zone(), id, 2, properties, CallDescriptor::kNoFlags); |
+ etrue = graph()->NewNode( |
+ common()->Call(desc), jsgraph()->CEntryStubConstant(1), object, |
+ target_map, |
+ jsgraph()->ExternalConstant(ExternalReference(id, isolate())), |
+ jsgraph()->Int32Constant(2), jsgraph()->NoContextConstant(), etrue, |
+ if_true); |
+ break; |
+ } |
+ } |
+ } |
+ |
+ // Nothing to do if the {object} doesn't have the {source_map}. |
+ Node* if_false = graph()->NewNode(common()->IfFalse(), branch); |
+ Node* efalse = effect; |
+ |
+ control = graph()->NewNode(common()->Merge(2), if_true, if_false); |
+ effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control); |
+ |
+ return ValueEffectControl(nullptr, effect, control); |
+} |
+ |
Factory* EffectControlLinearizer::factory() const { |
return isolate()->factory(); |
} |