Index: src/compiler/js-typed-lowering.cc |
diff --git a/src/compiler/js-typed-lowering.cc b/src/compiler/js-typed-lowering.cc |
index 0aebb7fc626b0f9c57dfaa3c2b79f4c967a1f4fb..f5bb09d1b2016927404848c609d8a0683302614a 100644 |
--- a/src/compiler/js-typed-lowering.cc |
+++ b/src/compiler/js-typed-lowering.cc |
@@ -29,8 +29,8 @@ static void RelaxEffects(Node* node) { |
} |
-JSTypedLowering::JSTypedLowering(JSGraph* jsgraph) |
- : jsgraph_(jsgraph), simplified_(jsgraph->zone()) { |
+JSTypedLowering::JSTypedLowering(JSGraph* jsgraph, Zone* zone) |
+ : jsgraph_(jsgraph), simplified_(graph()->zone()), conversions_(zone) { |
Handle<Object> zero = factory()->NewNumber(0.0); |
Handle<Object> one = factory()->NewNumber(1.0); |
zero_range_ = Type::Range(zero, zero, graph()->zone()); |
@@ -195,9 +195,9 @@ class JSBinopReduction FINAL { |
} |
Node* ConvertToNumber(Node* node) { |
- // Avoid introducing too many eager ToNumber() operations. |
- Reduction reduced = lowering_->ReduceJSToNumberInput(node); |
- if (reduced.Changed()) return reduced.replacement(); |
+ if (NodeProperties::GetBounds(node).upper->Is(Type::PlainPrimitive())) { |
+ return lowering_->ConvertToNumber(node); |
+ } |
Node* n = graph()->NewNode(javascript()->ToNumber(), node, context(), |
effect(), control()); |
update_effect(n); |
@@ -497,6 +497,9 @@ Reduction JSTypedLowering::ReduceJSToBooleanInput(Node* input) { |
if (result.Changed()) return result; |
return Changed(input); // JSToBoolean(JSToBoolean(x)) => JSToBoolean(x) |
} |
+ // Check if we have a cached conversion. |
+ Node* conversion = FindConversion<IrOpcode::kJSToBoolean>(input); |
+ if (conversion) return Replace(conversion); |
Type* input_type = NodeProperties::GetBounds(input).upper; |
if (input_type->Is(Type::Boolean())) { |
return Changed(input); // JSToBoolean(x:boolean) => x |
@@ -554,21 +557,13 @@ Reduction JSTypedLowering::ReduceJSToBoolean(Node* node) { |
DCHECK(!NodeProperties::GetBounds(input).upper->Is(Type::Boolean())); |
node->set_op(common()->Phi(kMachAnyTagged, input_count)); |
for (int i = 0; i < input_count; ++i) { |
- Node* value = input->InputAt(i); |
- // Recursively try to reduce the value first. |
- Reduction reduction = ReduceJSToBooleanInput(value); |
- if (reduction.Changed()) { |
- value = reduction.replacement(); |
- } else { |
- // We must be very careful not to introduce cycles when pushing |
- // operations into phis. It is safe for {value}, since it appears |
- // as input to the phi that we are replacing, but it's not safe |
- // to simply reuse the context of the {node}. However, ToBoolean() |
- // does not require a context anyways, so it's safe to discard it |
- // here and pass the dummy context. |
- value = graph()->NewNode(javascript()->ToBoolean(), value, |
- jsgraph()->NoContextConstant()); |
- } |
+ // We must be very careful not to introduce cycles when pushing |
+ // operations into phis. It is safe for {value}, since it appears |
+ // as input to the phi that we are replacing, but it's not safe |
+ // to simply reuse the context of the {node}. However, ToBoolean() |
+ // does not require a context anyways, so it's safe to discard it |
+ // here and pass the dummy context. |
+ Node* const value = ConvertToBoolean(input->InputAt(i)); |
if (i < node->InputCount()) { |
node->ReplaceInput(i, value); |
} else { |
@@ -594,26 +589,24 @@ Reduction JSTypedLowering::ReduceJSToBoolean(Node* node) { |
node->set_op(common()->Select(kMachAnyTagged, input_hint)); |
node->InsertInput(graph()->zone(), 0, input->InputAt(0)); |
for (int i = 1; i < input_count; ++i) { |
- Node* value = input->InputAt(i); |
- // Recursively try to reduce the value first. |
- Reduction reduction = ReduceJSToBooleanInput(value); |
- if (reduction.Changed()) { |
- value = reduction.replacement(); |
- } else { |
- // We must be very careful not to introduce cycles when pushing |
- // operations into selects. It is safe for {value}, since it appears |
- // as input to the select that we are replacing, but it's not safe |
- // to simply reuse the context of the {node}. However, ToBoolean() |
- // does not require a context anyways, so it's safe to discard it |
- // here and pass the dummy context. |
- value = graph()->NewNode(javascript()->ToBoolean(), value, |
- jsgraph()->NoContextConstant()); |
- } |
+ // We must be very careful not to introduce cycles when pushing |
+ // operations into selects. It is safe for {value}, since it appears |
+ // as input to the select that we are replacing, but it's not safe |
+ // to simply reuse the context of the {node}. However, ToBoolean() |
+ // does not require a context anyways, so it's safe to discard it |
+ // here and pass the dummy context. |
+ Node* const value = ConvertToBoolean(input->InputAt(i)); |
node->ReplaceInput(i, value); |
} |
DCHECK_EQ(3, node->InputCount()); |
return Changed(node); |
} |
+ InsertConversion(node); |
+ if (node->InputAt(1) != jsgraph()->NoContextConstant()) { |
+ // JSToBoolean(x,context) => JSToBoolean(x,no-context) |
+ node->ReplaceInput(1, jsgraph()->NoContextConstant()); |
+ return Changed(node); |
+ } |
return NoChange(); |
} |
@@ -625,6 +618,9 @@ Reduction JSTypedLowering::ReduceJSToNumberInput(Node* input) { |
if (result.Changed()) return result; |
return Changed(input); // JSToNumber(JSToNumber(x)) => JSToNumber(x) |
} |
+ // Check if we have a cached conversion. |
+ Node* conversion = FindConversion<IrOpcode::kJSToNumber>(input); |
+ if (conversion) return Replace(conversion); |
Type* input_type = NodeProperties::GetBounds(input).upper; |
if (input_type->Is(Type::Number())) { |
// JSToNumber(x:number) => x |
@@ -671,22 +667,13 @@ Reduction JSTypedLowering::ReduceJSToNumber(Node* node) { |
RelaxEffects(node); |
node->set_op(common()->Phi(kMachAnyTagged, input_count)); |
for (int i = 0; i < input_count; ++i) { |
- Node* value = input->InputAt(i); |
- // Recursively try to reduce the value first. |
- Reduction reduction = ReduceJSToNumberInput(value); |
- if (reduction.Changed()) { |
- value = reduction.replacement(); |
- } else { |
- // We must be very careful not to introduce cycles when pushing |
- // operations into phis. It is safe for {value}, since it appears |
- // as input to the phi that we are replacing, but it's not safe |
- // to simply reuse the context of the {node}. However, ToNumber() |
- // does not require a context anyways, so it's safe to discard it |
- // here and pass the dummy context. |
- value = graph()->NewNode(javascript()->ToNumber(), value, |
- jsgraph()->NoContextConstant(), |
- graph()->start(), graph()->start()); |
- } |
+ // We must be very careful not to introduce cycles when pushing |
+ // operations into phis. It is safe for {value}, since it appears |
+ // as input to the phi that we are replacing, but it's not safe |
+ // to simply reuse the context of the {node}. However, ToNumber() |
+ // does not require a context anyways, so it's safe to discard it |
+ // here and pass the dummy context. |
+ Node* const value = ConvertToNumber(input->InputAt(i)); |
if (i < node->InputCount()) { |
node->ReplaceInput(i, value); |
} else { |
@@ -713,32 +700,29 @@ Reduction JSTypedLowering::ReduceJSToNumber(Node* node) { |
node->set_op(common()->Select(kMachAnyTagged, input_hint)); |
node->ReplaceInput(0, input->InputAt(0)); |
for (int i = 1; i < input_count; ++i) { |
- Node* value = input->InputAt(i); |
- // Recursively try to reduce the value first. |
- Reduction reduction = ReduceJSToNumberInput(value); |
- if (reduction.Changed()) { |
- value = reduction.replacement(); |
- } else { |
- // We must be very careful not to introduce cycles when pushing |
- // operations into selects. It is safe for {value}, since it appears |
- // as input to the select that we are replacing, but it's not safe |
- // to simply reuse the context of the {node}. However, ToNumber() |
- // does not require a context anyways, so it's safe to discard it |
- // here and pass the dummy context. |
- value = graph()->NewNode(javascript()->ToNumber(), value, |
- jsgraph()->NoContextConstant(), |
- graph()->start(), graph()->start()); |
- } |
+ // We must be very careful not to introduce cycles when pushing |
+ // operations into selects. It is safe for {value}, since it appears |
+ // as input to the select that we are replacing, but it's not safe |
+ // to simply reuse the context of the {node}. However, ToNumber() |
+ // does not require a context anyways, so it's safe to discard it |
+ // here and pass the dummy context. |
+ Node* const value = ConvertToNumber(input->InputAt(i)); |
node->ReplaceInput(i, value); |
} |
node->TrimInputCount(input_count); |
return Changed(node); |
} |
+ // Remember this conversion. |
+ InsertConversion(node); |
if (node->InputAt(1) != jsgraph()->NoContextConstant() || |
- node->InputAt(2) != graph()->start()) { |
- // JSToNumber(x:plain-primitive,context) => JSToNumber(x,no-context) |
- node->ReplaceInput(1, jsgraph()->NoContextConstant()); |
+ node->InputAt(2) != graph()->start() || |
+ node->InputAt(3) != graph()->start()) { |
+ // JSToNumber(x:plain-primitive,context,effect,control) |
+ // => JSToNumber(x,no-context,start,start) |
RelaxEffects(node); |
+ node->ReplaceInput(1, jsgraph()->NoContextConstant()); |
+ node->ReplaceInput(2, graph()->start()); |
+ node->ReplaceInput(3, graph()->start()); |
return Changed(node); |
} |
} |
@@ -1022,6 +1006,54 @@ Reduction JSTypedLowering::Reduce(Node* node) { |
} |
+Node* JSTypedLowering::ConvertToBoolean(Node* input) { |
+ // Avoid inserting too many eager ToBoolean() operations. |
+ Reduction const reduction = ReduceJSToBooleanInput(input); |
+ if (reduction.Changed()) return reduction.replacement(); |
+ Node* const conversion = graph()->NewNode(javascript()->ToBoolean(), input, |
+ jsgraph()->NoContextConstant()); |
+ InsertConversion(conversion); |
+ return conversion; |
+} |
+ |
+ |
+Node* JSTypedLowering::ConvertToNumber(Node* input) { |
+ DCHECK(NodeProperties::GetBounds(input).upper->Is(Type::PlainPrimitive())); |
+ // Avoid inserting too many eager ToNumber() operations. |
+ Reduction const reduction = ReduceJSToNumberInput(input); |
+ if (reduction.Changed()) return reduction.replacement(); |
+ Node* const conversion = graph()->NewNode(javascript()->ToNumber(), input, |
+ jsgraph()->NoContextConstant(), |
+ graph()->start(), graph()->start()); |
+ InsertConversion(conversion); |
+ return conversion; |
+} |
+ |
+ |
+template <IrOpcode::Value kOpcode> |
+Node* JSTypedLowering::FindConversion(Node* input) { |
+ size_t const input_id = input->id(); |
+ if (input_id < conversions_.size()) { |
+ Node* const conversion = conversions_[input_id]; |
+ if (conversion && conversion->opcode() == kOpcode) { |
+ return conversion; |
+ } |
+ } |
+ return nullptr; |
+} |
+ |
+ |
+void JSTypedLowering::InsertConversion(Node* conversion) { |
+ DCHECK(conversion->opcode() == IrOpcode::kJSToBoolean || |
+ conversion->opcode() == IrOpcode::kJSToNumber); |
+ size_t const input_id = conversion->InputAt(0)->id(); |
+ if (input_id >= conversions_.size()) { |
+ conversions_.resize(2 * input_id + 1); |
+ } |
+ conversions_[input_id] = conversion; |
+} |
+ |
+ |
Node* JSTypedLowering::Word32Shl(Node* const lhs, int32_t const rhs) { |
if (rhs == 0) return lhs; |
return graph()->NewNode(machine()->Word32Shl(), lhs, |