Index: src/compiler/escape-analysis-reducer.cc |
diff --git a/src/compiler/escape-analysis-reducer.cc b/src/compiler/escape-analysis-reducer.cc |
index 9ecd264863bc64b00860543cf72bed41d7fb41e3..cbe808f7eaf7e975098c7fae19f4992f1c1299f9 100644 |
--- a/src/compiler/escape-analysis-reducer.cc |
+++ b/src/compiler/escape-analysis-reducer.cc |
@@ -36,10 +36,13 @@ Reduction EscapeAnalysisReducer::Reduce(Node* node) { |
return ReduceReferenceEqual(node); |
case IrOpcode::kObjectIsSmi: |
return ReduceObjectIsSmi(node); |
- case IrOpcode::kStateValues: |
- case IrOpcode::kFrameState: |
- return ReplaceWithDeoptDummy(node); |
default: |
+ // TODO(sigurds): Change this to GetFrameStateInputCount once |
+ // it is working. For now we use EffectInputCount > 0 to determine |
+ // whether a node might have a frame state input. |
+ if (node->op()->EffectInputCount() > 0) { |
+ return ReduceFrameStateUses(node); |
+ } |
break; |
} |
return NoChange(); |
@@ -117,23 +120,14 @@ Reduction EscapeAnalysisReducer::ReduceReferenceEqual(Node* node) { |
Node* left = NodeProperties::GetValueInput(node, 0); |
Node* right = NodeProperties::GetValueInput(node, 1); |
if (escape_analysis()->IsVirtual(left)) { |
- if (escape_analysis()->IsVirtual(right)) { |
- if (Node* rep = escape_analysis()->GetReplacement(left)) { |
- left = rep; |
- } |
- if (Node* rep = escape_analysis()->GetReplacement(right)) { |
- right = rep; |
- } |
- // TODO(sigurds): What to do if either is a PHI? |
- if (left == right) { |
- ReplaceWithValue(node, jsgraph()->TrueConstant()); |
- if (FLAG_trace_turbo_escape) { |
- PrintF("Replaced ref eq #%d with true\n", node->id()); |
- } |
- return Replace(node); |
+ if (escape_analysis()->IsVirtual(right) && |
+ escape_analysis()->CompareVirtualObjects(left, right)) { |
+ ReplaceWithValue(node, jsgraph()->TrueConstant()); |
+ if (FLAG_trace_turbo_escape) { |
+ PrintF("Replaced ref eq #%d with true\n", node->id()); |
} |
} |
- // Right-hand side is either not virtual, or a different node. |
+ // Right-hand side is not a virtual object, or a different one. |
ReplaceWithValue(node, jsgraph()->FalseConstant()); |
if (FLAG_trace_turbo_escape) { |
PrintF("Replaced ref eq #%d with false\n", node->id()); |
@@ -164,28 +158,132 @@ Reduction EscapeAnalysisReducer::ReduceObjectIsSmi(Node* node) { |
} |
-// TODO(sigurds): This is a temporary solution until escape analysis |
-// supports deoptimization. |
-Reduction EscapeAnalysisReducer::ReplaceWithDeoptDummy(Node* node) { |
- DCHECK(node->opcode() == IrOpcode::kStateValues || |
- node->opcode() == IrOpcode::kFrameState); |
- Reduction r = NoChange(); |
+Reduction EscapeAnalysisReducer::ReduceFrameStateUses(Node* node) { |
+ DCHECK_GE(node->op()->EffectInputCount(), 1); |
+ bool changed = false; |
+ for (int i = 0; i < node->InputCount(); ++i) { |
+ Node* input = node->InputAt(i); |
+ if (input->opcode() == IrOpcode::kFrameState) { |
+ if (Node* ret = ReduceFrameState(input, node, false)) { |
+ node->ReplaceInput(i, ret); |
+ changed = true; |
+ } |
+ } |
+ } |
+ if (changed) { |
+ return Changed(node); |
+ } |
+ return NoChange(); |
+} |
+ |
+ |
+// Returns the clone if it duplicated the node, and null otherwise. |
+Node* EscapeAnalysisReducer::ReduceFrameState(Node* node, Node* effect, |
+ bool multiple_users) { |
+ DCHECK(node->opcode() == IrOpcode::kFrameState); |
+ if (FLAG_trace_turbo_escape) { |
+ PrintF("Reducing FrameState %d\n", node->id()); |
+ } |
+ Node* clone = nullptr; |
for (int i = 0; i < node->op()->ValueInputCount(); ++i) { |
Node* input = NodeProperties::GetValueInput(node, i); |
- if (input->opcode() == IrOpcode::kFinishRegion || |
- input->opcode() == IrOpcode::kAllocate || |
- input->opcode() == IrOpcode::kPhi) { |
- if (escape_analysis()->IsVirtual(input)) { |
- NodeProperties::ReplaceValueInput(node, jsgraph()->UndefinedConstant(), |
- i); |
+ Node* ret = |
+ input->opcode() == IrOpcode::kStateValues |
+ ? ReduceStateValueInputs(input, effect, node->UseCount() > 1) |
+ : ReduceStateValueInput(node, i, effect, node->UseCount() > 1); |
+ if (ret) { |
+ if (node->UseCount() > 1 || multiple_users) { |
+ if (FLAG_trace_turbo_escape) { |
+ PrintF(" Cloning #%d", node->id()); |
+ } |
+ node = clone = jsgraph()->graph()->CloneNode(node); |
+ if (FLAG_trace_turbo_escape) { |
+ PrintF(" to #%d\n", node->id()); |
+ } |
+ multiple_users = false; // Don't clone anymore. |
+ } |
+ NodeProperties::ReplaceValueInput(node, ret, i); |
+ } |
+ } |
+ Node* outer_frame_state = NodeProperties::GetFrameStateInput(node, 0); |
+ if (outer_frame_state->opcode() == IrOpcode::kFrameState) { |
+ if (Node* ret = |
+ ReduceFrameState(outer_frame_state, effect, node->UseCount() > 1)) { |
+ if (node->UseCount() > 1 || multiple_users) { |
+ if (FLAG_trace_turbo_escape) { |
+ PrintF(" Cloning #%d", node->id()); |
+ } |
+ node = clone = jsgraph()->graph()->CloneNode(node); |
+ if (FLAG_trace_turbo_escape) { |
+ PrintF(" to #%d\n", node->id()); |
+ } |
+ multiple_users = false; |
+ } |
+ NodeProperties::ReplaceFrameStateInput(node, 0, ret); |
+ } |
+ } |
+ return clone; |
+} |
+ |
+ |
+// Returns the clone if it duplicated the node, and null otherwise. |
+Node* EscapeAnalysisReducer::ReduceStateValueInputs(Node* node, Node* effect, |
+ bool multiple_users) { |
+ if (FLAG_trace_turbo_escape) { |
+ PrintF("Reducing StateValue #%d\n", node->id()); |
+ } |
+ DCHECK(node->opcode() == IrOpcode::kStateValues); |
+ DCHECK_NOT_NULL(effect); |
+ Node* clone = nullptr; |
+ for (int i = 0; i < node->op()->ValueInputCount(); ++i) { |
+ if (Node* ret = ReduceStateValueInput(node, i, effect, multiple_users)) { |
+ node = ret; |
+ DCHECK_NULL(clone); |
+ clone = ret; |
+ multiple_users = false; |
+ } |
+ } |
+ return clone; |
+} |
+ |
+ |
+// Returns the clone if it duplicated the node, and null otherwise. |
+Node* EscapeAnalysisReducer::ReduceStateValueInput(Node* node, int node_index, |
+ Node* effect, |
+ bool multiple_users) { |
+ Node* input = NodeProperties::GetValueInput(node, node_index); |
+ if (FLAG_trace_turbo_escape) { |
+ PrintF("Reducing State Input #%d (%s)\n", input->id(), |
+ input->op()->mnemonic()); |
+ } |
+ Node* clone = nullptr; |
+ if (input->opcode() == IrOpcode::kFinishRegion || |
+ input->opcode() == IrOpcode::kAllocate) { |
+ if (escape_analysis()->IsVirtual(input)) { |
+ if (Node* object_state = |
+ escape_analysis()->GetOrCreateObjectState(effect, input)) { |
+ if (node->UseCount() > 1 || multiple_users) { |
+ if (FLAG_trace_turbo_escape) { |
+ PrintF("Cloning #%d", node->id()); |
+ } |
+ node = clone = jsgraph()->graph()->CloneNode(node); |
+ if (FLAG_trace_turbo_escape) { |
+ PrintF(" to #%d\n", node->id()); |
+ } |
+ } |
+ NodeProperties::ReplaceValueInput(node, object_state, node_index); |
+ if (FLAG_trace_turbo_escape) { |
+ PrintF("Replaced state #%d input #%d with object state #%d\n", |
+ node->id(), input->id(), object_state->id()); |
+ } |
+ } else { |
if (FLAG_trace_turbo_escape) { |
- PrintF("Replaced state value (#%d) input with dummy\n", node->id()); |
+ PrintF("No object state replacement available.\n"); |
} |
- r = Changed(node); |
} |
} |
} |
- return r; |
+ return clone; |
} |