summaryrefslogtreecommitdiff
path: root/deps/v8/src/compiler/escape-analysis-reducer.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/compiler/escape-analysis-reducer.cc')
-rw-r--r--deps/v8/src/compiler/escape-analysis-reducer.cc313
1 files changed, 313 insertions, 0 deletions
diff --git a/deps/v8/src/compiler/escape-analysis-reducer.cc b/deps/v8/src/compiler/escape-analysis-reducer.cc
new file mode 100644
index 0000000000..df8b65dab2
--- /dev/null
+++ b/deps/v8/src/compiler/escape-analysis-reducer.cc
@@ -0,0 +1,313 @@
+// Copyright 2015 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/compiler/escape-analysis-reducer.h"
+
+#include "src/compiler/js-graph.h"
+#include "src/counters.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+EscapeAnalysisReducer::EscapeAnalysisReducer(Editor* editor, JSGraph* jsgraph,
+ EscapeAnalysis* escape_analysis,
+ Zone* zone)
+ : AdvancedReducer(editor),
+ jsgraph_(jsgraph),
+ escape_analysis_(escape_analysis),
+ zone_(zone),
+ visited_(static_cast<int>(jsgraph->graph()->NodeCount()), zone) {}
+
+
+Reduction EscapeAnalysisReducer::Reduce(Node* node) {
+ switch (node->opcode()) {
+ case IrOpcode::kLoadField:
+ case IrOpcode::kLoadElement:
+ return ReduceLoad(node);
+ case IrOpcode::kStoreField:
+ case IrOpcode::kStoreElement:
+ return ReduceStore(node);
+ case IrOpcode::kAllocate:
+ return ReduceAllocate(node);
+ case IrOpcode::kFinishRegion:
+ return ReduceFinishRegion(node);
+ case IrOpcode::kReferenceEqual:
+ return ReduceReferenceEqual(node);
+ case IrOpcode::kObjectIsSmi:
+ return ReduceObjectIsSmi(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();
+}
+
+
+Reduction EscapeAnalysisReducer::ReduceLoad(Node* node) {
+ DCHECK(node->opcode() == IrOpcode::kLoadField ||
+ node->opcode() == IrOpcode::kLoadElement);
+ if (visited_.Contains(node->id())) return NoChange();
+ visited_.Add(node->id());
+ if (Node* rep = escape_analysis()->GetReplacement(node)) {
+ visited_.Add(node->id());
+ counters()->turbo_escape_loads_replaced()->Increment();
+ if (FLAG_trace_turbo_escape) {
+ PrintF("Replaced #%d (%s) with #%d (%s)\n", node->id(),
+ node->op()->mnemonic(), rep->id(), rep->op()->mnemonic());
+ }
+ ReplaceWithValue(node, rep);
+ return Changed(rep);
+ }
+ return NoChange();
+}
+
+
+Reduction EscapeAnalysisReducer::ReduceStore(Node* node) {
+ DCHECK(node->opcode() == IrOpcode::kStoreField ||
+ node->opcode() == IrOpcode::kStoreElement);
+ if (visited_.Contains(node->id())) return NoChange();
+ visited_.Add(node->id());
+ if (escape_analysis()->IsVirtual(NodeProperties::GetValueInput(node, 0))) {
+ if (FLAG_trace_turbo_escape) {
+ PrintF("Removed #%d (%s) from effect chain\n", node->id(),
+ node->op()->mnemonic());
+ }
+ RelaxEffectsAndControls(node);
+ return Changed(node);
+ }
+ return NoChange();
+}
+
+
+Reduction EscapeAnalysisReducer::ReduceAllocate(Node* node) {
+ DCHECK_EQ(node->opcode(), IrOpcode::kAllocate);
+ if (visited_.Contains(node->id())) return NoChange();
+ visited_.Add(node->id());
+ if (escape_analysis()->IsVirtual(node)) {
+ RelaxEffectsAndControls(node);
+ counters()->turbo_escape_allocs_replaced()->Increment();
+ if (FLAG_trace_turbo_escape) {
+ PrintF("Removed allocate #%d from effect chain\n", node->id());
+ }
+ return Changed(node);
+ }
+ return NoChange();
+}
+
+
+Reduction EscapeAnalysisReducer::ReduceFinishRegion(Node* node) {
+ DCHECK_EQ(node->opcode(), IrOpcode::kFinishRegion);
+ Node* effect = NodeProperties::GetEffectInput(node, 0);
+ if (effect->opcode() == IrOpcode::kBeginRegion) {
+ RelaxEffectsAndControls(effect);
+ RelaxEffectsAndControls(node);
+ if (FLAG_trace_turbo_escape) {
+ PrintF("Removed region #%d / #%d from effect chain,", effect->id(),
+ node->id());
+ PrintF(" %d user(s) of #%d remain(s):", node->UseCount(), node->id());
+ for (Edge edge : node->use_edges()) {
+ PrintF(" #%d", edge.from()->id());
+ }
+ PrintF("\n");
+ }
+ return Changed(node);
+ }
+ return NoChange();
+}
+
+
+Reduction EscapeAnalysisReducer::ReduceReferenceEqual(Node* node) {
+ DCHECK_EQ(node->opcode(), IrOpcode::kReferenceEqual);
+ Node* left = NodeProperties::GetValueInput(node, 0);
+ Node* right = NodeProperties::GetValueInput(node, 1);
+ if (escape_analysis()->IsVirtual(left)) {
+ 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 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());
+ }
+ return Replace(node);
+ } else if (escape_analysis()->IsVirtual(right)) {
+ // Left-hand side is not a virtual object.
+ ReplaceWithValue(node, jsgraph()->FalseConstant());
+ if (FLAG_trace_turbo_escape) {
+ PrintF("Replaced ref eq #%d with false\n", node->id());
+ }
+ }
+ return NoChange();
+}
+
+
+Reduction EscapeAnalysisReducer::ReduceObjectIsSmi(Node* node) {
+ DCHECK_EQ(node->opcode(), IrOpcode::kObjectIsSmi);
+ Node* input = NodeProperties::GetValueInput(node, 0);
+ if (escape_analysis()->IsVirtual(input)) {
+ ReplaceWithValue(node, jsgraph()->FalseConstant());
+ if (FLAG_trace_turbo_escape) {
+ PrintF("Replaced ObjectIsSmi #%d with false\n", node->id());
+ }
+ return Replace(node);
+ }
+ return NoChange();
+}
+
+
+Reduction EscapeAnalysisReducer::ReduceFrameStateUses(Node* node) {
+ if (visited_.Contains(node->id())) return NoChange();
+ visited_.Add(node->id());
+ 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);
+ 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) {
+ Node* input = NodeProperties::GetValueInput(node, i);
+ Node* ret = nullptr;
+ if (input->opcode() == IrOpcode::kStateValues) {
+ ret = ReduceStateValueInputs(input, effect, multiple_users);
+ } else {
+ ret = ReduceStateValueInput(node, i, effect, multiple_users);
+ }
+ if (ret) {
+ 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("No object state replacement available.\n");
+ }
+ }
+ }
+ }
+ return clone;
+}
+
+
+Counters* EscapeAnalysisReducer::counters() const {
+ return jsgraph_->isolate()->counters();
+}
+
+} // namespace compiler
+} // namespace internal
+} // namespace v8