Commit 5b582114 authored by sigurds's avatar sigurds Committed by Commit bot

[turbofan] Improve escape analysis

This patch improves escape analysis and fixes bugs
triggered by clusterfuzz. Impovements include:
* Handling of LoadElement/StoreElement if index is a
  constant
* Handling of JSStoreProperty: invalidate all information,
  as the store could have altered any field.
* Treat phis that use an allocation as escaping
* Improve resolution of replacements

R=mstarzinger@chromium.org
BUG=v8:4586
LOG=n

Review URL: https://codereview.chromium.org/1499143002

Cr-Commit-Position: refs/heads/master@{#32656}
parent 063920e2
...@@ -23,9 +23,11 @@ EscapeAnalysisReducer::EscapeAnalysisReducer(Editor* editor, JSGraph* jsgraph, ...@@ -23,9 +23,11 @@ EscapeAnalysisReducer::EscapeAnalysisReducer(Editor* editor, JSGraph* jsgraph,
Reduction EscapeAnalysisReducer::Reduce(Node* node) { Reduction EscapeAnalysisReducer::Reduce(Node* node) {
switch (node->opcode()) { switch (node->opcode()) {
case IrOpcode::kLoadField: case IrOpcode::kLoadField:
return ReduceLoadField(node); case IrOpcode::kLoadElement:
return ReduceLoad(node);
case IrOpcode::kStoreField: case IrOpcode::kStoreField:
return ReduceStoreField(node); case IrOpcode::kStoreElement:
return ReduceStore(node);
case IrOpcode::kAllocate: case IrOpcode::kAllocate:
return ReduceAllocate(node); return ReduceAllocate(node);
case IrOpcode::kFinishRegion: case IrOpcode::kFinishRegion:
...@@ -42,11 +44,13 @@ Reduction EscapeAnalysisReducer::Reduce(Node* node) { ...@@ -42,11 +44,13 @@ Reduction EscapeAnalysisReducer::Reduce(Node* node) {
} }
Reduction EscapeAnalysisReducer::ReduceLoadField(Node* node) { Reduction EscapeAnalysisReducer::ReduceLoad(Node* node) {
DCHECK_EQ(node->opcode(), IrOpcode::kLoadField); DCHECK(node->opcode() == IrOpcode::kLoadField ||
node->opcode() == IrOpcode::kLoadElement);
if (Node* rep = escape_analysis()->GetReplacement(node, node->id())) { if (Node* rep = escape_analysis()->GetReplacement(node, node->id())) {
if (FLAG_trace_turbo_escape) { if (FLAG_trace_turbo_escape) {
PrintF("Replaced #%d with #%d\n", node->id(), rep->id()); PrintF("Replaced #%d (%s) with #%d (%s)\n", node->id(),
node->op()->mnemonic(), rep->id(), rep->op()->mnemonic());
} }
ReplaceWithValue(node, rep); ReplaceWithValue(node, rep);
return Changed(rep); return Changed(rep);
...@@ -55,11 +59,13 @@ Reduction EscapeAnalysisReducer::ReduceLoadField(Node* node) { ...@@ -55,11 +59,13 @@ Reduction EscapeAnalysisReducer::ReduceLoadField(Node* node) {
} }
Reduction EscapeAnalysisReducer::ReduceStoreField(Node* node) { Reduction EscapeAnalysisReducer::ReduceStore(Node* node) {
DCHECK_EQ(node->opcode(), IrOpcode::kStoreField); DCHECK(node->opcode() == IrOpcode::kStoreField ||
node->opcode() == IrOpcode::kStoreElement);
if (escape_analysis()->IsVirtual(NodeProperties::GetValueInput(node, 0))) { if (escape_analysis()->IsVirtual(NodeProperties::GetValueInput(node, 0))) {
if (FLAG_trace_turbo_escape) { if (FLAG_trace_turbo_escape) {
PrintF("Removed store field #%d from effect chain\n", node->id()); PrintF("Removed #%d (%s) from effect chain\n", node->id(),
node->op()->mnemonic());
} }
RelaxEffectsAndControls(node); RelaxEffectsAndControls(node);
return Changed(node); return Changed(node);
...@@ -90,7 +96,7 @@ Reduction EscapeAnalysisReducer::ReduceFinishRegion(Node* node) { ...@@ -90,7 +96,7 @@ Reduction EscapeAnalysisReducer::ReduceFinishRegion(Node* node) {
if (FLAG_trace_turbo_escape) { if (FLAG_trace_turbo_escape) {
PrintF("Removed region #%d / #%d from effect chain,", effect->id(), PrintF("Removed region #%d / #%d from effect chain,", effect->id(),
node->id()); node->id());
PrintF("%d user(s) of #%d remain(s):", node->UseCount(), node->id()); PrintF(" %d user(s) of #%d remain(s):", node->UseCount(), node->id());
for (Edge edge : node->use_edges()) { for (Edge edge : node->use_edges()) {
PrintF(" #%d", edge.from()->id()); PrintF(" #%d", edge.from()->id());
} }
......
...@@ -24,8 +24,8 @@ class EscapeAnalysisReducer final : public AdvancedReducer { ...@@ -24,8 +24,8 @@ class EscapeAnalysisReducer final : public AdvancedReducer {
Reduction Reduce(Node* node) final; Reduction Reduce(Node* node) final;
private: private:
Reduction ReduceLoadField(Node* node); Reduction ReduceLoad(Node* node);
Reduction ReduceStoreField(Node* node); Reduction ReduceStore(Node* node);
Reduction ReduceAllocate(Node* node); Reduction ReduceAllocate(Node* node);
Reduction ReduceFinishRegion(Node* node); Reduction ReduceFinishRegion(Node* node);
Reduction ReduceReferenceEqual(Node* node); Reduction ReduceReferenceEqual(Node* node);
......
This diff is collapsed.
...@@ -16,6 +16,7 @@ namespace compiler { ...@@ -16,6 +16,7 @@ namespace compiler {
class CommonOperatorBuilder; class CommonOperatorBuilder;
class EscapeAnalysis; class EscapeAnalysis;
class VirtualState; class VirtualState;
class VirtualObject;
// EscapeStatusAnalysis determines for each allocation whether it escapes. // EscapeStatusAnalysis determines for each allocation whether it escapes.
...@@ -46,8 +47,11 @@ class EscapeStatusAnalysis { ...@@ -46,8 +47,11 @@ class EscapeStatusAnalysis {
void ProcessAllocate(Node* node); void ProcessAllocate(Node* node);
void ProcessFinishRegion(Node* node); void ProcessFinishRegion(Node* node);
void ProcessStoreField(Node* node); void ProcessStoreField(Node* node);
bool CheckUsesForEscape(Node* node) { return CheckUsesForEscape(node, node); } void ProcessStoreElement(Node* node);
bool CheckUsesForEscape(Node* node, Node* rep); bool CheckUsesForEscape(Node* node, bool phi_escaping = false) {
return CheckUsesForEscape(node, node, phi_escaping);
}
bool CheckUsesForEscape(Node* node, Node* rep, bool phi_escaping = false);
void RevisitUses(Node* node); void RevisitUses(Node* node);
void RevisitInputs(Node* node); void RevisitInputs(Node* node);
bool SetEscaped(Node* node); bool SetEscaped(Node* node);
...@@ -87,17 +91,28 @@ class EscapeAnalysis { ...@@ -87,17 +91,28 @@ class EscapeAnalysis {
bool Process(Node* node); bool Process(Node* node);
void ProcessLoadField(Node* node); void ProcessLoadField(Node* node);
void ProcessStoreField(Node* node); void ProcessStoreField(Node* node);
void ProcessLoadElement(Node* node);
void ProcessStoreElement(Node* node);
void ProcessAllocationUsers(Node* node);
void ProcessAllocation(Node* node); void ProcessAllocation(Node* node);
void ProcessFinishRegion(Node* node); void ProcessFinishRegion(Node* node);
void ProcessCall(Node* node); void ProcessCall(Node* node);
void ProcessStart(Node* node); void ProcessStart(Node* node);
bool ProcessEffectPhi(Node* node); bool ProcessEffectPhi(Node* node);
void ProcessLoadFromPhi(int offset, Node* from, Node* node,
VirtualState* states);
void ForwardVirtualState(Node* node); void ForwardVirtualState(Node* node);
bool IsEffectBranchPoint(Node* node); bool IsEffectBranchPoint(Node* node);
bool IsDanglingEffectNode(Node* node); bool IsDanglingEffectNode(Node* node);
int OffsetFromAccess(Node* node); int OffsetFromAccess(Node* node);
VirtualObject* GetVirtualObject(Node* at, NodeId id);
void DebugPrint(); void DebugPrint();
void DebugPrintState(VirtualState* state);
void DebugPrintObject(VirtualObject* state, NodeId id);
Graph* graph() const { return graph_; } Graph* graph() const { return graph_; }
CommonOperatorBuilder* common() const { return common_; } CommonOperatorBuilder* common() const { return common_; }
......
...@@ -28,24 +28,25 @@ ...@@ -28,24 +28,25 @@
// Flags: --allow-natives-syntax --turbo-escape // Flags: --allow-natives-syntax --turbo-escape
// //
function f(a) { function f() {
"use strict"; this.x=0;
return arguments;
} }
function g(a) { function g(a) {
"use strict"; "use strict";
var x = f(1,2,3); var o = new f();
if (a) { if (a) {
x[1] = 5; o.x = 5;
} else { } else {
x[1] = 7; o.x = 7;
} }
return x[1]; return o.x;
} }
assertEquals(7, g()); assertEquals(5, g(true));
assertEquals(7, g()); assertEquals(7, g(false));
%OptimizeFunctionOnNextCall(g); %OptimizeFunctionOnNextCall(g);
assertEquals(5, g(true));
assertEquals(7, g(false));
assertEquals(7, g()); assertEquals(7, g());
// Copyright 2015 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Flags: --allow-natives-syntax --turbo-escape
//
function f() {
return arguments;
}
function g(a) {
"use strict";
var o = f(1,2);
if (a) {
o[0] = 5;
} else {
o[0] = 7;
}
return o[0];
}
assertEquals(7, g());
assertEquals(7, g());
%OptimizeFunctionOnNextCall(g);
assertEquals(5, g(true));
assertEquals(7, g(false));
assertEquals(7, g());
...@@ -172,9 +172,9 @@ ...@@ -172,9 +172,9 @@
'compiler/escape-analysis-3': [PASS, NO_VARIANTS], 'compiler/escape-analysis-3': [PASS, NO_VARIANTS],
'compiler/escape-analysis-4': [PASS, NO_VARIANTS], 'compiler/escape-analysis-4': [PASS, NO_VARIANTS],
'compiler/escape-analysis-5': [PASS, NO_VARIANTS], 'compiler/escape-analysis-5': [PASS, NO_VARIANTS],
'compiler/escape-analysis-7': [PASS, NO_VARIANTS],
# TODO(sigurds): Tests that fail because of incomplete phi handling.
'compiler/escape-analysis-6': [PASS, NO_VARIANTS], 'compiler/escape-analysis-6': [PASS, NO_VARIANTS],
'compiler/escape-analysis-7': [PASS, NO_VARIANTS],
'compiler/escape-analysis-9': [PASS, NO_VARIANTS],
# TODO(sigurds): Tests that fail because of incomplete use handling (i.e. select). # TODO(sigurds): Tests that fail because of incomplete use handling (i.e. select).
'compiler/escape-analysis-8': [PASS, NO_VARIANTS], 'compiler/escape-analysis-8': [PASS, NO_VARIANTS],
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment