Merge V8 5.3.332.45. DO NOT MERGE
Test: Manual
FPIIM-449
Change-Id: Id3254828b068abdea3cb10442e0172a8c9a98e03
(cherry picked from commit 13e2dadd00298019ed862f2b2fc5068bba730bcf)
diff --git a/src/compiler/effect-control-linearizer.cc b/src/compiler/effect-control-linearizer.cc
index 716723b..b7f6b12 100644
--- a/src/compiler/effect-control-linearizer.cc
+++ b/src/compiler/effect-control-linearizer.cc
@@ -37,6 +37,7 @@
struct BlockEffectControlData {
Node* current_effect = nullptr; // New effect.
Node* current_control = nullptr; // New control.
+ Node* current_frame_state = nullptr; // New frame state.
};
// Effect phis that need to be updated after the first pass.
@@ -222,10 +223,30 @@
NodeProperties::ReplaceEffectInput(terminate, effect);
}
+ // The frame state at block entry is determined by the frame states leaving
+ // all predecessors. In case there is no frame state dominating this block,
+ // we can rely on a checkpoint being present before the next deoptimization.
+ // TODO(mstarzinger): Eventually we will need to go hunt for a frame state
+ // once deoptimizing nodes roam freely through the schedule.
+ Node* frame_state = nullptr;
+ if (block != schedule()->start()) {
+ // If all the predecessors have the same effect, we can use it
+ // as our current effect.
+ int rpo_number = block->PredecessorAt(0)->rpo_number();
+ frame_state = block_effects[rpo_number].current_frame_state;
+ for (size_t i = 1; i < block->PredecessorCount(); i++) {
+ int rpo_number = block->PredecessorAt(i)->rpo_number();
+ if (block_effects[rpo_number].current_frame_state != frame_state) {
+ frame_state = nullptr;
+ break;
+ }
+ }
+ }
+
// Process the ordinary instructions.
for (; instr < block->NodeCount(); instr++) {
Node* node = block->NodeAt(instr);
- ProcessNode(node, &effect, &control);
+ ProcessNode(node, &frame_state, &effect, &control);
}
switch (block->control()) {
@@ -240,13 +261,14 @@
case BasicBlock::kReturn:
case BasicBlock::kDeoptimize:
case BasicBlock::kThrow:
- ProcessNode(block->control_input(), &effect, &control);
+ ProcessNode(block->control_input(), &frame_state, &effect, &control);
break;
}
// Store the effect for later use.
block_effects[block->rpo_number()].current_effect = effect;
block_effects[block->rpo_number()].current_control = control;
+ block_effects[block->rpo_number()].current_frame_state = frame_state;
}
// Update the incoming edges of the effect phis that could not be processed
@@ -276,29 +298,49 @@
} // namespace
-void EffectControlLinearizer::ProcessNode(Node* node, Node** effect,
- Node** control) {
+void EffectControlLinearizer::ProcessNode(Node* node, Node** frame_state,
+ Node** effect, Node** control) {
// If the node needs to be wired into the effect/control chain, do this
- // here.
- if (TryWireInStateEffect(node, effect, control)) {
+ // here. Pass current frame state for lowering to eager deoptimization.
+ if (TryWireInStateEffect(node, *frame_state, effect, control)) {
return;
}
+ // If the node has a visible effect, then there must be a checkpoint in the
+ // effect chain before we are allowed to place another eager deoptimization
+ // point. We zap the frame state to ensure this invariant is maintained.
+ if (region_observability_ == RegionObservability::kObservable &&
+ !node->op()->HasProperty(Operator::kNoWrite)) {
+ *frame_state = nullptr;
+ }
+
// Remove the end markers of 'atomic' allocation region because the
// region should be wired-in now.
- if (node->opcode() == IrOpcode::kFinishRegion ||
- node->opcode() == IrOpcode::kBeginRegion) {
+ if (node->opcode() == IrOpcode::kFinishRegion) {
+ // Reset the current region observability.
+ region_observability_ = RegionObservability::kObservable;
+ // Update the value uses to the value input of the finish node and
+ // the effect uses to the effect input.
+ return RemoveRegionNode(node);
+ }
+ if (node->opcode() == IrOpcode::kBeginRegion) {
+ // Determine the observability for this region and use that for all
+ // nodes inside the region (i.e. ignore the absence of kNoWrite on
+ // StoreField and other operators).
+ DCHECK_NE(RegionObservability::kNotObservable, region_observability_);
+ region_observability_ = RegionObservabilityOf(node->op());
// Update the value uses to the value input of the finish node and
// the effect uses to the effect input.
return RemoveRegionNode(node);
}
- // Special treatment for CheckPoint nodes.
- // TODO(epertoso): Pickup the current frame state.
- if (node->opcode() == IrOpcode::kCheckPoint) {
+ // Special treatment for checkpoint nodes.
+ if (node->opcode() == IrOpcode::kCheckpoint) {
// Unlink the check point; effect uses will be updated to the incoming
- // effect that is passed.
- node->Kill();
+ // effect that is passed. The frame state is preserved for lowering.
+ DCHECK_EQ(RegionObservability::kObservable, region_observability_);
+ *frame_state = NodeProperties::GetFrameStateInput(node, 0);
+ node->TrimInputCount(0);
return;
}
@@ -347,7 +389,9 @@
}
}
-bool EffectControlLinearizer::TryWireInStateEffect(Node* node, Node** effect,
+bool EffectControlLinearizer::TryWireInStateEffect(Node* node,
+ Node* frame_state,
+ Node** effect,
Node** control) {
ValueEffectControl state(nullptr, nullptr, nullptr);
switch (node->opcode()) {
@@ -384,6 +428,36 @@
case IrOpcode::kChangeTaggedToFloat64:
state = LowerChangeTaggedToFloat64(node, *effect, *control);
break;
+ case IrOpcode::kTruncateTaggedToFloat64:
+ state = LowerTruncateTaggedToFloat64(node, *effect, *control);
+ break;
+ case IrOpcode::kCheckBounds:
+ state = LowerCheckBounds(node, frame_state, *effect, *control);
+ break;
+ case IrOpcode::kCheckTaggedPointer:
+ state = LowerCheckTaggedPointer(node, frame_state, *effect, *control);
+ break;
+ case IrOpcode::kCheckTaggedSigned:
+ state = LowerCheckTaggedSigned(node, frame_state, *effect, *control);
+ break;
+ case IrOpcode::kCheckedInt32Add:
+ state = LowerCheckedInt32Add(node, frame_state, *effect, *control);
+ break;
+ case IrOpcode::kCheckedInt32Sub:
+ state = LowerCheckedInt32Sub(node, frame_state, *effect, *control);
+ break;
+ case IrOpcode::kCheckedUint32ToInt32:
+ state = LowerCheckedUint32ToInt32(node, frame_state, *effect, *control);
+ break;
+ case IrOpcode::kCheckedFloat64ToInt32:
+ state = LowerCheckedFloat64ToInt32(node, frame_state, *effect, *control);
+ break;
+ case IrOpcode::kCheckedTaggedToInt32:
+ state = LowerCheckedTaggedToInt32(node, frame_state, *effect, *control);
+ break;
+ case IrOpcode::kCheckedTaggedToFloat64:
+ state = LowerCheckedTaggedToFloat64(node, frame_state, *effect, *control);
+ break;
case IrOpcode::kTruncateTaggedToWord32:
state = LowerTruncateTaggedToWord32(node, *effect, *control);
break;
@@ -405,10 +479,28 @@
case IrOpcode::kObjectIsUndetectable:
state = LowerObjectIsUndetectable(node, *effect, *control);
break;
+ case IrOpcode::kStringFromCharCode:
+ state = LowerStringFromCharCode(node, *effect, *control);
+ break;
+ case IrOpcode::kCheckFloat64Hole:
+ state = LowerCheckFloat64Hole(node, frame_state, *effect, *control);
+ break;
+ case IrOpcode::kCheckTaggedHole:
+ state = LowerCheckTaggedHole(node, frame_state, *effect, *control);
+ break;
+ case IrOpcode::kPlainPrimitiveToNumber:
+ state = LowerPlainPrimitiveToNumber(node, *effect, *control);
+ break;
+ case IrOpcode::kPlainPrimitiveToWord32:
+ state = LowerPlainPrimitiveToWord32(node, *effect, *control);
+ break;
+ case IrOpcode::kPlainPrimitiveToFloat64:
+ state = LowerPlainPrimitiveToFloat64(node, *effect, *control);
+ break;
default:
return false;
}
- NodeProperties::ReplaceUses(node, state.value);
+ NodeProperties::ReplaceUses(node, state.value, state.effect, state.control);
*effect = state.effect;
*control = state.control;
return true;
@@ -465,10 +557,11 @@
if (machine()->Is64()) {
vsmi = ChangeInt32ToSmi(value32);
} else {
- Node* smi_tag =
- graph()->NewNode(machine()->Int32AddWithOverflow(), value32, value32);
+ Node* smi_tag = graph()->NewNode(machine()->Int32AddWithOverflow(), value32,
+ value32, if_smi);
- Node* check_ovf = graph()->NewNode(common()->Projection(1), smi_tag);
+ Node* check_ovf =
+ graph()->NewNode(common()->Projection(1), smi_tag, if_smi);
Node* branch_ovf = graph()->NewNode(common()->Branch(BranchHint::kFalse),
check_ovf, if_smi);
@@ -476,7 +569,7 @@
if_box = graph()->NewNode(common()->Merge(2), if_ovf, if_box);
if_smi = graph()->NewNode(common()->IfFalse(), branch_ovf);
- vsmi = graph()->NewNode(common()->Projection(0), smi_tag);
+ vsmi = graph()->NewNode(common()->Projection(0), smi_tag, if_smi);
}
// Allocate the box for the {value}.
@@ -528,9 +621,10 @@
return ValueEffectControl(ChangeInt32ToSmi(value), effect, control);
}
- Node* add = graph()->NewNode(machine()->Int32AddWithOverflow(), value, value);
+ Node* add = graph()->NewNode(machine()->Int32AddWithOverflow(), value, value,
+ control);
- Node* ovf = graph()->NewNode(common()->Projection(1), add);
+ Node* ovf = graph()->NewNode(common()->Projection(1), add, control);
Node* branch =
graph()->NewNode(common()->Branch(BranchHint::kFalse), ovf, control);
@@ -539,7 +633,7 @@
AllocateHeapNumberWithValue(ChangeInt32ToFloat64(value), effect, if_true);
Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
- Node* vfalse = graph()->NewNode(common()->Projection(0), add);
+ Node* vfalse = graph()->NewNode(common()->Projection(0), add, if_false);
Node* merge = graph()->NewNode(common()->Merge(2), alloc.control, if_false);
Node* phi = graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
@@ -661,6 +755,12 @@
EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::LowerChangeTaggedToFloat64(Node* node, Node* effect,
Node* control) {
+ return LowerTruncateTaggedToFloat64(node, effect, control);
+}
+
+EffectControlLinearizer::ValueEffectControl
+EffectControlLinearizer::LowerTruncateTaggedToFloat64(Node* node, Node* effect,
+ Node* control) {
Node* value = node->InputAt(0);
Node* check = ObjectIsSmi(value);
@@ -694,6 +794,288 @@
}
EffectControlLinearizer::ValueEffectControl
+EffectControlLinearizer::LowerCheckBounds(Node* node, Node* frame_state,
+ Node* effect, Node* control) {
+ Node* index = node->InputAt(0);
+ Node* limit = node->InputAt(1);
+
+ Node* check = graph()->NewNode(machine()->Uint32LessThan(), index, limit);
+ control = effect = graph()->NewNode(common()->DeoptimizeUnless(), check,
+ frame_state, effect, control);
+
+ // Make sure the lowered node does not appear in any use lists.
+ node->TrimInputCount(0);
+
+ return ValueEffectControl(index, effect, control);
+}
+
+EffectControlLinearizer::ValueEffectControl
+EffectControlLinearizer::LowerCheckTaggedPointer(Node* node, Node* frame_state,
+ Node* effect, Node* control) {
+ Node* value = node->InputAt(0);
+
+ Node* check = ObjectIsSmi(value);
+ control = effect = graph()->NewNode(common()->DeoptimizeIf(), check,
+ frame_state, effect, control);
+
+ // Make sure the lowered node does not appear in any use lists.
+ node->TrimInputCount(0);
+
+ return ValueEffectControl(value, effect, control);
+}
+
+EffectControlLinearizer::ValueEffectControl
+EffectControlLinearizer::LowerCheckTaggedSigned(Node* node, Node* frame_state,
+ Node* effect, Node* control) {
+ Node* value = node->InputAt(0);
+
+ Node* check = ObjectIsSmi(value);
+ control = effect = graph()->NewNode(common()->DeoptimizeUnless(), check,
+ frame_state, effect, control);
+
+ // Make sure the lowered node does not appear in any use lists.
+ node->TrimInputCount(0);
+
+ return ValueEffectControl(value, effect, control);
+}
+
+EffectControlLinearizer::ValueEffectControl
+EffectControlLinearizer::LowerCheckedInt32Add(Node* node, Node* frame_state,
+ Node* effect, Node* control) {
+ Node* lhs = node->InputAt(0);
+ Node* rhs = node->InputAt(1);
+
+ Node* value =
+ graph()->NewNode(machine()->Int32AddWithOverflow(), lhs, rhs, control);
+
+ Node* check = graph()->NewNode(common()->Projection(1), value, control);
+ control = effect = graph()->NewNode(common()->DeoptimizeIf(), check,
+ frame_state, effect, control);
+
+ value = graph()->NewNode(common()->Projection(0), value, control);
+
+ // Make sure the lowered node does not appear in any use lists.
+ node->TrimInputCount(0);
+
+ return ValueEffectControl(value, effect, control);
+}
+
+EffectControlLinearizer::ValueEffectControl
+EffectControlLinearizer::LowerCheckedInt32Sub(Node* node, Node* frame_state,
+ Node* effect, Node* control) {
+ Node* lhs = node->InputAt(0);
+ Node* rhs = node->InputAt(1);
+
+ Node* value =
+ graph()->NewNode(machine()->Int32SubWithOverflow(), lhs, rhs, control);
+
+ Node* check = graph()->NewNode(common()->Projection(1), value, control);
+ control = effect = graph()->NewNode(common()->DeoptimizeIf(), check,
+ frame_state, effect, control);
+
+ value = graph()->NewNode(common()->Projection(0), value, control);
+
+ // Make sure the lowered node does not appear in any use lists.
+ node->TrimInputCount(0);
+
+ return ValueEffectControl(value, effect, control);
+}
+
+EffectControlLinearizer::ValueEffectControl
+EffectControlLinearizer::LowerCheckedUint32ToInt32(Node* node,
+ Node* frame_state,
+ Node* effect,
+ Node* control) {
+ Node* value = node->InputAt(0);
+ Node* max_int = jsgraph()->Int32Constant(std::numeric_limits<int32_t>::max());
+ Node* is_safe =
+ graph()->NewNode(machine()->Uint32LessThanOrEqual(), value, max_int);
+ control = effect = graph()->NewNode(common()->DeoptimizeUnless(), is_safe,
+ frame_state, effect, control);
+
+ // Make sure the lowered node does not appear in any use lists.
+ node->TrimInputCount(0);
+
+ return ValueEffectControl(value, effect, control);
+}
+
+EffectControlLinearizer::ValueEffectControl
+EffectControlLinearizer::BuildCheckedFloat64ToInt32(Node* value,
+ Node* frame_state,
+ Node* effect,
+ Node* control) {
+ Node* value32 = graph()->NewNode(machine()->RoundFloat64ToInt32(), value);
+ Node* check_same = graph()->NewNode(
+ machine()->Float64Equal(), value,
+ graph()->NewNode(machine()->ChangeInt32ToFloat64(), value32));
+ control = effect = graph()->NewNode(common()->DeoptimizeUnless(), check_same,
+ frame_state, effect, control);
+
+ // Check if {value} is -0.
+ Node* check_zero = graph()->NewNode(machine()->Word32Equal(), value32,
+ jsgraph()->Int32Constant(0));
+ Node* branch_zero = graph()->NewNode(common()->Branch(BranchHint::kFalse),
+ check_zero, control);
+
+ Node* if_zero = graph()->NewNode(common()->IfTrue(), branch_zero);
+ Node* if_notzero = graph()->NewNode(common()->IfFalse(), branch_zero);
+
+ // In case of 0, we need to check the high bits for the IEEE -0 pattern.
+ Node* check_negative = graph()->NewNode(
+ machine()->Int32LessThan(),
+ graph()->NewNode(machine()->Float64ExtractHighWord32(), value),
+ jsgraph()->Int32Constant(0));
+
+ Node* deopt_minus_zero = graph()->NewNode(
+ common()->DeoptimizeIf(), check_negative, frame_state, effect, if_zero);
+
+ Node* merge =
+ graph()->NewNode(common()->Merge(2), deopt_minus_zero, if_notzero);
+
+ effect =
+ graph()->NewNode(common()->EffectPhi(2), deopt_minus_zero, effect, merge);
+
+ return ValueEffectControl(value32, effect, merge);
+}
+
+EffectControlLinearizer::ValueEffectControl
+EffectControlLinearizer::LowerCheckedFloat64ToInt32(Node* node,
+ Node* frame_state,
+ Node* effect,
+ Node* control) {
+ Node* value = node->InputAt(0);
+
+ // Make sure the lowered node does not appear in any use lists.
+ node->TrimInputCount(0);
+
+ return BuildCheckedFloat64ToInt32(value, frame_state, effect, control);
+}
+
+EffectControlLinearizer::ValueEffectControl
+EffectControlLinearizer::LowerCheckedTaggedToInt32(Node* node,
+ Node* frame_state,
+ Node* effect,
+ Node* control) {
+ Node* value = node->InputAt(0);
+
+ Node* check = ObjectIsSmi(value);
+ Node* branch =
+ graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
+
+ // In the Smi case, just convert to int32.
+ Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
+ Node* etrue = effect;
+ Node* vtrue = ChangeSmiToInt32(value);
+
+ // In the non-Smi case, check the heap numberness, load the number and convert
+ // to int32.
+ Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
+ Node* efalse = effect;
+ Node* vfalse;
+ {
+ Node* value_map = efalse =
+ graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
+ value, efalse, if_false);
+ Node* check = graph()->NewNode(machine()->WordEqual(), value_map,
+ jsgraph()->HeapNumberMapConstant());
+ if_false = efalse = graph()->NewNode(common()->DeoptimizeUnless(), check,
+ frame_state, efalse, if_false);
+ vfalse = efalse = graph()->NewNode(
+ simplified()->LoadField(AccessBuilder::ForHeapNumberValue()), value,
+ efalse, if_false);
+ ValueEffectControl state =
+ BuildCheckedFloat64ToInt32(vfalse, frame_state, efalse, if_false);
+ if_false = state.control;
+ efalse = state.effect;
+ vfalse = state.value;
+ }
+
+ control = graph()->NewNode(common()->Merge(2), if_true, if_false);
+ effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);
+ value = graph()->NewNode(common()->Phi(MachineRepresentation::kWord32, 2),
+ vtrue, vfalse, control);
+
+ // Make sure the lowered node does not appear in any use lists.
+ node->TrimInputCount(0);
+
+ return ValueEffectControl(value, effect, control);
+}
+
+EffectControlLinearizer::ValueEffectControl
+EffectControlLinearizer::BuildCheckedHeapNumberOrOddballToFloat64(
+ Node* value, Node* frame_state, Node* effect, Node* control) {
+ Node* value_map = effect = graph()->NewNode(
+ simplified()->LoadField(AccessBuilder::ForMap()), value, effect, control);
+ Node* check_number = graph()->NewNode(machine()->WordEqual(), value_map,
+ jsgraph()->HeapNumberMapConstant());
+
+ Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue),
+ check_number, control);
+
+ Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
+ Node* etrue = effect;
+
+ Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
+ // For oddballs also contain the numeric value, let us just check that
+ // we have an oddball here.
+ Node* efalse = effect;
+ Node* instance_type = efalse = graph()->NewNode(
+ simplified()->LoadField(AccessBuilder::ForMapInstanceType()), value_map,
+ efalse, if_false);
+ Node* check_oddball =
+ graph()->NewNode(machine()->Word32Equal(), instance_type,
+ jsgraph()->Int32Constant(ODDBALL_TYPE));
+ if_false = efalse =
+ graph()->NewNode(common()->DeoptimizeUnless(), check_oddball, frame_state,
+ efalse, if_false);
+ STATIC_ASSERT(HeapNumber::kValueOffset == Oddball::kToNumberRawOffset);
+
+ control = graph()->NewNode(common()->Merge(2), if_true, if_false);
+ effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);
+
+ Node* result = effect = graph()->NewNode(
+ simplified()->LoadField(AccessBuilder::ForHeapNumberValue()), value,
+ effect, control);
+ return ValueEffectControl(result, effect, control);
+}
+
+EffectControlLinearizer::ValueEffectControl
+EffectControlLinearizer::LowerCheckedTaggedToFloat64(Node* node,
+ Node* frame_state,
+ Node* effect,
+ Node* control) {
+ Node* value = node->InputAt(0);
+
+ Node* check = ObjectIsSmi(value);
+ Node* branch =
+ graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
+
+ // In the Smi case, just convert to int32 and then float64.
+ Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
+ Node* etrue = effect;
+ Node* vtrue = ChangeSmiToInt32(value);
+ vtrue = graph()->NewNode(machine()->ChangeInt32ToFloat64(), vtrue);
+
+ // Otherwise, check heap numberness and load the number.
+ Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
+ ValueEffectControl number_state = BuildCheckedHeapNumberOrOddballToFloat64(
+ value, frame_state, effect, if_false);
+
+ Node* merge =
+ graph()->NewNode(common()->Merge(2), if_true, number_state.control);
+ Node* effect_phi = graph()->NewNode(common()->EffectPhi(2), etrue,
+ number_state.effect, merge);
+ Node* result =
+ graph()->NewNode(common()->Phi(MachineRepresentation::kFloat64, 2), vtrue,
+ number_state.value, merge);
+
+ // Make sure the lowered node does not appear in any use lists.
+ node->TrimInputCount(0);
+
+ return ValueEffectControl(result, effect_phi, merge);
+}
+
+EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::LowerTruncateTaggedToWord32(Node* node, Node* effect,
Node* control) {
Node* value = node->InputAt(0);
@@ -918,6 +1300,170 @@
}
EffectControlLinearizer::ValueEffectControl
+EffectControlLinearizer::LowerStringFromCharCode(Node* node, Node* effect,
+ Node* control) {
+ Node* value = node->InputAt(0);
+
+ // Compute the character code.
+ Node* code =
+ graph()->NewNode(machine()->Word32And(), value,
+ jsgraph()->Int32Constant(String::kMaxUtf16CodeUnit));
+
+ // Check if the {code} is a one-byte char code.
+ Node* check0 =
+ graph()->NewNode(machine()->Int32LessThanOrEqual(), code,
+ jsgraph()->Int32Constant(String::kMaxOneByteCharCode));
+ Node* branch0 =
+ graph()->NewNode(common()->Branch(BranchHint::kTrue), check0, control);
+
+ Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
+ Node* etrue0 = effect;
+ Node* vtrue0;
+ {
+ // Load the isolate wide single character string cache.
+ Node* cache =
+ jsgraph()->HeapConstant(factory()->single_character_string_cache());
+
+ // Compute the {cache} index for {code}.
+ Node* index =
+ machine()->Is32() ? code : graph()->NewNode(
+ machine()->ChangeUint32ToUint64(), code);
+
+ // Check if we have an entry for the {code} in the single character string
+ // cache already.
+ Node* entry = etrue0 = graph()->NewNode(
+ simplified()->LoadElement(AccessBuilder::ForFixedArrayElement()), cache,
+ index, etrue0, if_true0);
+
+ Node* check1 = graph()->NewNode(machine()->WordEqual(), entry,
+ jsgraph()->UndefinedConstant());
+ Node* branch1 = graph()->NewNode(common()->Branch(BranchHint::kFalse),
+ check1, if_true0);
+
+ Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
+ Node* etrue1 = etrue0;
+ Node* vtrue1;
+ {
+ // Allocate a new SeqOneByteString for {code}.
+ vtrue1 = etrue1 = graph()->NewNode(
+ simplified()->Allocate(NOT_TENURED),
+ jsgraph()->Int32Constant(SeqOneByteString::SizeFor(1)), etrue1,
+ if_true1);
+ etrue1 = graph()->NewNode(
+ simplified()->StoreField(AccessBuilder::ForMap()), vtrue1,
+ jsgraph()->HeapConstant(factory()->one_byte_string_map()), etrue1,
+ if_true1);
+ etrue1 = graph()->NewNode(
+ simplified()->StoreField(AccessBuilder::ForNameHashField()), vtrue1,
+ jsgraph()->IntPtrConstant(Name::kEmptyHashField), etrue1, if_true1);
+ etrue1 = graph()->NewNode(
+ simplified()->StoreField(AccessBuilder::ForStringLength()), vtrue1,
+ jsgraph()->SmiConstant(1), etrue1, if_true1);
+ etrue1 = graph()->NewNode(
+ machine()->Store(StoreRepresentation(MachineRepresentation::kWord8,
+ kNoWriteBarrier)),
+ vtrue1, jsgraph()->IntPtrConstant(SeqOneByteString::kHeaderSize -
+ kHeapObjectTag),
+ code, etrue1, if_true1);
+
+ // Remember it in the {cache}.
+ etrue1 = graph()->NewNode(
+ simplified()->StoreElement(AccessBuilder::ForFixedArrayElement()),
+ cache, index, vtrue1, etrue1, if_true1);
+ }
+
+ // Use the {entry} from the {cache}.
+ Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
+ Node* efalse1 = etrue0;
+ Node* vfalse1 = entry;
+
+ 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);
+ }
+
+ Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
+ Node* efalse0 = effect;
+ Node* vfalse0;
+ {
+ // Allocate a new SeqTwoByteString for {code}.
+ vfalse0 = efalse0 =
+ graph()->NewNode(simplified()->Allocate(NOT_TENURED),
+ jsgraph()->Int32Constant(SeqTwoByteString::SizeFor(1)),
+ efalse0, if_false0);
+ efalse0 = graph()->NewNode(
+ simplified()->StoreField(AccessBuilder::ForMap()), vfalse0,
+ jsgraph()->HeapConstant(factory()->string_map()), efalse0, if_false0);
+ efalse0 = graph()->NewNode(
+ simplified()->StoreField(AccessBuilder::ForNameHashField()), vfalse0,
+ jsgraph()->IntPtrConstant(Name::kEmptyHashField), efalse0, if_false0);
+ efalse0 = graph()->NewNode(
+ simplified()->StoreField(AccessBuilder::ForStringLength()), vfalse0,
+ jsgraph()->SmiConstant(1), efalse0, if_false0);
+ efalse0 = graph()->NewNode(
+ machine()->Store(StoreRepresentation(MachineRepresentation::kWord16,
+ kNoWriteBarrier)),
+ vfalse0, jsgraph()->IntPtrConstant(SeqTwoByteString::kHeaderSize -
+ kHeapObjectTag),
+ code, efalse0, if_false0);
+ }
+
+ control = graph()->NewNode(common()->Merge(2), if_true0, if_false0);
+ effect = graph()->NewNode(common()->EffectPhi(2), etrue0, efalse0, control);
+ value = graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
+ vtrue0, vfalse0, control);
+
+ return ValueEffectControl(value, effect, control);
+}
+
+EffectControlLinearizer::ValueEffectControl
+EffectControlLinearizer::LowerCheckFloat64Hole(Node* node, Node* frame_state,
+ Node* effect, Node* control) {
+ // If we reach this point w/o eliminating the {node} that's marked
+ // with allow-return-hole, we cannot do anything, so just deoptimize
+ // in case of the hole NaN (similar to Crankshaft).
+ Node* value = node->InputAt(0);
+ Node* check = graph()->NewNode(
+ machine()->Word32Equal(),
+ graph()->NewNode(machine()->Float64ExtractHighWord32(), value),
+ jsgraph()->Int32Constant(kHoleNanUpper32));
+ control = effect = graph()->NewNode(common()->DeoptimizeIf(), check,
+ frame_state, effect, control);
+
+ // Make sure the lowered node does not appear in any use lists.
+ node->TrimInputCount(0);
+
+ return ValueEffectControl(value, effect, control);
+}
+
+EffectControlLinearizer::ValueEffectControl
+EffectControlLinearizer::LowerCheckTaggedHole(Node* node, Node* frame_state,
+ Node* effect, Node* control) {
+ CheckTaggedHoleMode mode = CheckTaggedHoleModeOf(node->op());
+ Node* value = node->InputAt(0);
+ Node* check = graph()->NewNode(machine()->WordEqual(), value,
+ jsgraph()->TheHoleConstant());
+ switch (mode) {
+ case CheckTaggedHoleMode::kConvertHoleToUndefined:
+ value = graph()->NewNode(
+ common()->Select(MachineRepresentation::kTagged, BranchHint::kFalse),
+ check, jsgraph()->UndefinedConstant(), value);
+ break;
+ case CheckTaggedHoleMode::kNeverReturnHole:
+ control = effect = graph()->NewNode(common()->DeoptimizeIf(), check,
+ frame_state, effect, control);
+ break;
+ }
+
+ // Make sure the lowered node does not appear in any use lists.
+ node->TrimInputCount(0);
+
+ return ValueEffectControl(value, effect, control);
+}
+
+EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::AllocateHeapNumberWithValue(Node* value, Node* effect,
Node* control) {
Node* result = effect = graph()->NewNode(
@@ -961,7 +1507,6 @@
}
return value;
}
-
Node* EffectControlLinearizer::ObjectIsSmi(Node* value) {
return graph()->NewNode(
machine()->WordEqual(),
@@ -978,6 +1523,148 @@
return jsgraph()->IntPtrConstant(kSmiShiftSize + kSmiTagSize);
}
+EffectControlLinearizer::ValueEffectControl
+EffectControlLinearizer::LowerPlainPrimitiveToNumber(Node* node, Node* effect,
+ Node* control) {
+ Node* value = node->InputAt(0);
+ Node* result = effect =
+ graph()->NewNode(ToNumberOperator(), jsgraph()->ToNumberBuiltinConstant(),
+ value, jsgraph()->NoContextConstant(), effect, control);
+ return ValueEffectControl(result, effect, control);
+}
+
+EffectControlLinearizer::ValueEffectControl
+EffectControlLinearizer::LowerPlainPrimitiveToWord32(Node* node, Node* effect,
+ Node* control) {
+ Node* value = node->InputAt(0);
+
+ Node* check0 = ObjectIsSmi(value);
+ Node* branch0 =
+ graph()->NewNode(common()->Branch(BranchHint::kTrue), check0, control);
+
+ Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
+ Node* etrue0 = effect;
+ Node* vtrue0 = ChangeSmiToInt32(value);
+
+ Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
+ Node* efalse0 = effect;
+ Node* vfalse0;
+ {
+ vfalse0 = efalse0 = graph()->NewNode(
+ ToNumberOperator(), jsgraph()->ToNumberBuiltinConstant(), value,
+ jsgraph()->NoContextConstant(), efalse0, if_false0);
+
+ Node* check1 = ObjectIsSmi(vfalse0);
+ Node* branch1 = graph()->NewNode(common()->Branch(), check1, if_false0);
+
+ Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
+ Node* etrue1 = efalse0;
+ Node* vtrue1 = ChangeSmiToInt32(vfalse0);
+
+ Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
+ Node* efalse1 = efalse0;
+ Node* vfalse1;
+ {
+ vfalse1 = efalse1 = graph()->NewNode(
+ simplified()->LoadField(AccessBuilder::ForHeapNumberValue()), efalse0,
+ efalse1, if_false1);
+ vfalse1 = graph()->NewNode(machine()->TruncateFloat64ToWord32(), vfalse1);
+ }
+
+ if_false0 = graph()->NewNode(common()->Merge(2), if_true1, if_false1);
+ efalse0 =
+ graph()->NewNode(common()->EffectPhi(2), etrue1, efalse1, if_false0);
+ vfalse0 = graph()->NewNode(common()->Phi(MachineRepresentation::kWord32, 2),
+ vtrue1, vfalse1, if_false0);
+ }
+
+ control = graph()->NewNode(common()->Merge(2), if_true0, if_false0);
+ effect = graph()->NewNode(common()->EffectPhi(2), etrue0, efalse0, control);
+ value = graph()->NewNode(common()->Phi(MachineRepresentation::kWord32, 2),
+ vtrue0, vfalse0, control);
+ return ValueEffectControl(value, effect, control);
+}
+
+EffectControlLinearizer::ValueEffectControl
+EffectControlLinearizer::LowerPlainPrimitiveToFloat64(Node* node, Node* effect,
+ Node* control) {
+ Node* value = node->InputAt(0);
+
+ Node* check0 = ObjectIsSmi(value);
+ Node* branch0 =
+ graph()->NewNode(common()->Branch(BranchHint::kTrue), check0, control);
+
+ Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
+ Node* etrue0 = effect;
+ Node* vtrue0;
+ {
+ vtrue0 = ChangeSmiToInt32(value);
+ vtrue0 = graph()->NewNode(machine()->ChangeInt32ToFloat64(), vtrue0);
+ }
+
+ Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
+ Node* efalse0 = effect;
+ Node* vfalse0;
+ {
+ vfalse0 = efalse0 = graph()->NewNode(
+ ToNumberOperator(), jsgraph()->ToNumberBuiltinConstant(), value,
+ jsgraph()->NoContextConstant(), efalse0, if_false0);
+
+ Node* check1 = ObjectIsSmi(vfalse0);
+ Node* branch1 = graph()->NewNode(common()->Branch(), check1, if_false0);
+
+ Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
+ Node* etrue1 = efalse0;
+ Node* vtrue1;
+ {
+ vtrue1 = ChangeSmiToInt32(vfalse0);
+ vtrue1 = graph()->NewNode(machine()->ChangeInt32ToFloat64(), vtrue1);
+ }
+
+ Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
+ Node* efalse1 = efalse0;
+ Node* vfalse1;
+ {
+ vfalse1 = efalse1 = graph()->NewNode(
+ simplified()->LoadField(AccessBuilder::ForHeapNumberValue()), efalse0,
+ efalse1, if_false1);
+ }
+
+ if_false0 = graph()->NewNode(common()->Merge(2), if_true1, if_false1);
+ efalse0 =
+ graph()->NewNode(common()->EffectPhi(2), etrue1, efalse1, if_false0);
+ vfalse0 =
+ graph()->NewNode(common()->Phi(MachineRepresentation::kFloat64, 2),
+ vtrue1, vfalse1, if_false0);
+ }
+
+ control = graph()->NewNode(common()->Merge(2), if_true0, if_false0);
+ effect = graph()->NewNode(common()->EffectPhi(2), etrue0, efalse0, control);
+ value = graph()->NewNode(common()->Phi(MachineRepresentation::kFloat64, 2),
+ vtrue0, vfalse0, control);
+ return ValueEffectControl(value, effect, control);
+}
+
+Factory* EffectControlLinearizer::factory() const {
+ return isolate()->factory();
+}
+
+Isolate* EffectControlLinearizer::isolate() const {
+ return jsgraph()->isolate();
+}
+
+Operator const* EffectControlLinearizer::ToNumberOperator() {
+ if (!to_number_operator_.is_set()) {
+ Callable callable = CodeFactory::ToNumber(isolate());
+ CallDescriptor::Flags flags = CallDescriptor::kNoFlags;
+ CallDescriptor* desc = Linkage::GetStubCallDescriptor(
+ isolate(), graph()->zone(), callable.descriptor(), 0, flags,
+ Operator::kNoThrow);
+ to_number_operator_.set(common()->Call(desc));
+ }
+ return to_number_operator_.get();
+}
+
} // namespace compiler
} // namespace internal
} // namespace v8