Commit aa0ddf7d authored by sigurds's avatar sigurds Committed by Commit bot

[turbofan] Initial support for escape analysis.

This is the first part of escape analysis for turbofan.
At the moment, there is no deopt support, and support
for loops is partial (only binary Phis are handled).

The CL includes 4 unittests.

There are also 8 new mjsunit tests, some of which are
skiped as they require features not yet implemented.

BUG=v8:4586
LOG=n

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

Cr-Commit-Position: refs/heads/master@{#32498}
parent 9bee6750
...@@ -760,6 +760,10 @@ source_set("v8_base") { ...@@ -760,6 +760,10 @@ source_set("v8_base") {
"src/compiler/dead-code-elimination.cc", "src/compiler/dead-code-elimination.cc",
"src/compiler/dead-code-elimination.h", "src/compiler/dead-code-elimination.h",
"src/compiler/diamond.h", "src/compiler/diamond.h",
"src/compiler/escape-analysis.cc",
"src/compiler/escape-analysis.h",
"src/compiler/escape-analysis-reducer.cc",
"src/compiler/escape-analysis-reducer.h",
"src/compiler/frame.cc", "src/compiler/frame.cc",
"src/compiler/frame.h", "src/compiler/frame.h",
"src/compiler/frame-elider.cc", "src/compiler/frame-elider.cc",
......
// 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/compiler/js-operator.h"
namespace v8 {
namespace internal {
namespace compiler {
EscapeAnalysisReducer::EscapeAnalysisReducer(
Editor* editor, JSGraph* jsgraph, EscapeStatusAnalysis* escape_status,
EscapeObjectAnalysis* escape_analysis, Zone* zone)
: AdvancedReducer(editor),
jsgraph_(jsgraph),
escape_status_(escape_status),
escape_analysis_(escape_analysis),
zone_(zone) {}
Reduction EscapeAnalysisReducer::Reduce(Node* node) {
switch (node->opcode()) {
case IrOpcode::kLoadField:
return ReduceLoadField(node);
case IrOpcode::kStoreField:
return ReduceStoreField(node);
case IrOpcode::kAllocate:
return ReduceAllocate(node);
case IrOpcode::kFinishRegion:
return ReduceFinishRegion(node);
case IrOpcode::kReferenceEqual:
return ReduceReferenceEqual(node);
case IrOpcode::kStateValues:
case IrOpcode::kFrameState:
return ReplaceWithDeoptDummy(node);
default:
break;
}
return NoChange();
}
Reduction EscapeAnalysisReducer::ReduceLoadField(Node* node) {
DCHECK_EQ(node->opcode(), IrOpcode::kLoadField);
if (Node* rep = escape_analysis()->GetReplacement(node, node->id())) {
if (FLAG_trace_turbo_escape) {
PrintF("Replaced #%d with #%d\n", node->id(), rep->id());
}
ReplaceWithValue(node, rep);
return Changed(rep);
}
return NoChange();
}
Reduction EscapeAnalysisReducer::ReduceStoreField(Node* node) {
DCHECK_EQ(node->opcode(), IrOpcode::kStoreField);
if (escape_status()->IsVirtual(NodeProperties::GetValueInput(node, 0))) {
if (FLAG_trace_turbo_escape) {
PrintF("Removed store field #%d from effect chain\n", node->id());
}
RelaxEffectsAndControls(node);
return Changed(node);
}
return NoChange();
}
Reduction EscapeAnalysisReducer::ReduceAllocate(Node* node) {
DCHECK_EQ(node->opcode(), IrOpcode::kAllocate);
if (escape_status()->IsVirtual(node)) {
RelaxEffectsAndControls(node);
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_status()->IsVirtual(left)) {
if (escape_status()->IsVirtual(right)) {
if (Node* rep = escape_analysis()->GetReplacement(node, left->id())) {
left = rep;
}
if (Node* rep = escape_analysis()->GetReplacement(node, right->id())) {
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);
}
}
// Right-hand side is either not virtual, or a different node.
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_status()->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();
}
// 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();
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_status()->IsVirtual(input)) {
NodeProperties::ReplaceValueInput(node, jsgraph()->UndefinedConstant(),
i);
if (FLAG_trace_turbo_escape) {
PrintF("Replaced state value (#%d) input with dummy\n", node->id());
}
r = Changed(node);
}
}
}
return r;
}
} // namespace compiler
} // namespace internal
} // namespace v8
// 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.
#ifndef V8_COMPILER_ESCAPE_ANALYSIS_REDUCER_H_
#define V8_COMPILER_ESCAPE_ANALYSIS_REDUCER_H_
#include "src/compiler/escape-analysis.h"
#include "src/compiler/graph-reducer.h"
namespace v8 {
namespace internal {
namespace compiler {
// Forward declarations.
class JSGraph;
class EscapeAnalysisReducer final : public AdvancedReducer {
public:
EscapeAnalysisReducer(Editor* editor, JSGraph* jsgraph,
EscapeStatusAnalysis* escape_status,
EscapeObjectAnalysis* escape_analysis, Zone* zone);
Reduction Reduce(Node* node) final;
private:
Reduction ReduceLoadField(Node* node);
Reduction ReduceStoreField(Node* node);
Reduction ReduceAllocate(Node* node);
Reduction ReduceFinishRegion(Node* node);
Reduction ReduceReferenceEqual(Node* node);
Reduction ReplaceWithDeoptDummy(Node* node);
JSGraph* jsgraph() const { return jsgraph_; }
EscapeObjectAnalysis* escape_analysis() const { return escape_analysis_; }
EscapeStatusAnalysis* escape_status() const { return escape_status_; }
Zone* zone() const { return zone_; }
JSGraph* const jsgraph_;
EscapeStatusAnalysis* escape_status_;
EscapeObjectAnalysis* escape_analysis_;
Zone* const zone_;
DISALLOW_COPY_AND_ASSIGN(EscapeAnalysisReducer);
};
} // namespace compiler
} // namespace internal
} // namespace v8
#endif // V8_COMPILER_ESCAPE_ANALYSIS_REDUCER_H_
This diff is collapsed.
// 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.
#ifndef V8_COMPILER_ESCAPE_ANALYSIS_H_
#define V8_COMPILER_ESCAPE_ANALYSIS_H_
#include "src/base/flags.h"
#include "src/compiler/graph.h"
namespace v8 {
namespace internal {
namespace compiler {
// Forward declarations.
class CommonOperatorBuilder;
class EscapeObjectAnalysis;
class VirtualState;
// EscapeStatusAnalysis determines for each allocation whether it escapes.
class EscapeStatusAnalysis {
public:
EscapeStatusAnalysis(EscapeObjectAnalysis* object_analysis, Graph* graph,
Zone* zone);
~EscapeStatusAnalysis();
enum EscapeStatusFlag {
kUnknown = 0u,
kVirtual = 1u << 0,
kEscaped = 1u << 1,
};
typedef base::Flags<EscapeStatusFlag> EscapeStatusFlags;
void Run();
bool HasEntry(Node* node);
bool IsVirtual(Node* node);
bool IsEscaped(Node* node);
void DebugPrint();
private:
void Process(Node* node);
void ProcessAllocate(Node* node);
void ProcessFinishRegion(Node* node);
void ProcessStoreField(Node* node);
bool CheckUsesForEscape(Node* node) { return CheckUsesForEscape(node, node); }
bool CheckUsesForEscape(Node* node, Node* rep);
void RevisitUses(Node* node);
void RevisitInputs(Node* node);
bool SetEscaped(Node* node);
Graph* graph() const { return graph_; }
Zone* zone() const { return zone_; }
EscapeObjectAnalysis* object_analysis_;
Graph* const graph_;
Zone* const zone_;
ZoneVector<EscapeStatusFlags> info_;
ZoneDeque<Node*> queue_;
DISALLOW_COPY_AND_ASSIGN(EscapeStatusAnalysis);
};
DEFINE_OPERATORS_FOR_FLAGS(EscapeStatusAnalysis::EscapeStatusFlags)
// EscapeObjectAnalysis simulates stores to determine values of loads if
// an object is virtual and eliminated.
class EscapeObjectAnalysis {
public:
EscapeObjectAnalysis(Graph* graph, CommonOperatorBuilder* common, Zone* zone);
~EscapeObjectAnalysis();
void Run();
Node* GetReplacement(Node* at, NodeId id);
private:
bool Process(Node* node);
void ProcessLoadField(Node* node);
void ProcessStoreField(Node* node);
void ProcessAllocation(Node* node);
void ProcessFinishRegion(Node* node);
void ProcessCall(Node* node);
void ProcessStart(Node* node);
bool ProcessEffectPhi(Node* node);
void ForwardVirtualState(Node* node);
bool IsEffectBranchPoint(Node* node);
bool IsDanglingEffectNode(Node* node);
int OffsetFromAccess(Node* node);
void DebugPrint();
Graph* graph() const { return graph_; }
CommonOperatorBuilder* common() const { return common_; }
Zone* zone() const { return zone_; }
Graph* const graph_;
CommonOperatorBuilder* const common_;
Zone* const zone_;
ZoneVector<VirtualState*> virtual_states_;
DISALLOW_COPY_AND_ASSIGN(EscapeObjectAnalysis);
};
} // namespace compiler
} // namespace internal
} // namespace v8
#endif // V8_COMPILER_ESCAPE_ANALYSIS_H_
...@@ -19,6 +19,8 @@ ...@@ -19,6 +19,8 @@
#include "src/compiler/common-operator-reducer.h" #include "src/compiler/common-operator-reducer.h"
#include "src/compiler/control-flow-optimizer.h" #include "src/compiler/control-flow-optimizer.h"
#include "src/compiler/dead-code-elimination.h" #include "src/compiler/dead-code-elimination.h"
#include "src/compiler/escape-analysis.h"
#include "src/compiler/escape-analysis-reducer.h"
#include "src/compiler/frame-elider.h" #include "src/compiler/frame-elider.h"
#include "src/compiler/graph-replay.h" #include "src/compiler/graph-replay.h"
#include "src/compiler/graph-trimmer.h" #include "src/compiler/graph-trimmer.h"
...@@ -646,6 +648,26 @@ struct BranchEliminationPhase { ...@@ -646,6 +648,26 @@ struct BranchEliminationPhase {
}; };
struct EscapeAnalysisPhase {
static const char* phase_name() { return "escape analysis"; }
void Run(PipelineData* data, Zone* temp_zone) {
EscapeObjectAnalysis escape_analysis(data->graph(),
data->jsgraph()->common(), temp_zone);
escape_analysis.Run();
EscapeStatusAnalysis escape_status(&escape_analysis, data->graph(),
temp_zone);
escape_status.Run();
JSGraphReducer graph_reducer(data->jsgraph(), temp_zone);
EscapeAnalysisReducer escape_reducer(&graph_reducer, data->jsgraph(),
&escape_status, &escape_analysis,
temp_zone);
AddReducer(data, &graph_reducer, &escape_reducer);
graph_reducer.ReduceGraph();
}
};
struct SimplifiedLoweringPhase { struct SimplifiedLoweringPhase {
static const char* phase_name() { return "simplified lowering"; } static const char* phase_name() { return "simplified lowering"; }
...@@ -1148,6 +1170,11 @@ Handle<Code> Pipeline::GenerateCode() { ...@@ -1148,6 +1170,11 @@ Handle<Code> Pipeline::GenerateCode() {
RunPrintAndVerify("Loop peeled"); RunPrintAndVerify("Loop peeled");
} }
if (FLAG_turbo_escape) {
Run<EscapeAnalysisPhase>();
RunPrintAndVerify("Escape Analysed");
}
// Lower simplified operators and insert changes. // Lower simplified operators and insert changes.
Run<SimplifiedLoweringPhase>(); Run<SimplifiedLoweringPhase>();
RunPrintAndVerify("Lowered simplified"); RunPrintAndVerify("Lowered simplified");
......
...@@ -463,6 +463,8 @@ DEFINE_BOOL(turbo_cf_optimization, true, "optimize control flow in TurboFan") ...@@ -463,6 +463,8 @@ DEFINE_BOOL(turbo_cf_optimization, true, "optimize control flow in TurboFan")
DEFINE_BOOL(turbo_frame_elision, true, "elide frames in TurboFan") DEFINE_BOOL(turbo_frame_elision, true, "elide frames in TurboFan")
DEFINE_BOOL(turbo_cache_shared_code, true, "cache context-independent code") DEFINE_BOOL(turbo_cache_shared_code, true, "cache context-independent code")
DEFINE_BOOL(turbo_preserve_shared_code, false, "keep context-independent code") DEFINE_BOOL(turbo_preserve_shared_code, false, "keep context-independent code")
DEFINE_BOOL(turbo_escape, false, "enable escape analysis")
DEFINE_BOOL(trace_turbo_escape, false, "enable tracing in escape analysis")
#if defined(V8_WASM) #if defined(V8_WASM)
// Flags for native WebAssembly. // Flags for native WebAssembly.
......
// 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(a) {
"use strict";
return arguments.length;
}
function g() {
return f(1,2,3);
}
assertEquals(3, g());
assertEquals(3, g());
%OptimizeFunctionOnNextCall(g);
assertEquals(3, 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(a) {
"use strict";
if (arguments === a)
return 1;
return arguments.length;
}
function g(a) {
return f(a,1,2,3);
}
assertEquals(4, g());
assertEquals(4, g());
%OptimizeFunctionOnNextCall(g);
assertEquals(4, 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(a) {
"use strict";
return arguments.length;
}
function g() {
"use strict";
return arguments[f(1,2)];
}
assertEquals(6, g(4,5,6));
assertEquals(6, g(4,5,6));
%OptimizeFunctionOnNextCall(g);
assertEquals(6, g(4,5,6));
// 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(a) {
"use strict";
return arguments.length;
}
function h() {
"use strict";
return arguments;
}
function g() {
return "" + f(1,2,3) + " " + h(4,5,6);
}
assertEquals("3 [object Arguments]", g());
assertEquals("3 [object Arguments]", g());
%OptimizeFunctionOnNextCall(g);
assertEquals("3 [object Arguments]", 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(h) {
"use strict";
h(arguments);
return arguments.length;
}
function g(h) {
return f(h,1,2,3);
}
function h(x) {
assertEquals("[object Arguments]", ""+x)
}
assertEquals(4, g(h));
assertEquals(4, g(h));
%OptimizeFunctionOnNextCall(g);
assertEquals(4, g(h));
// 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(a) {
"use strict";
return arguments;
}
function g() {
"use strict";
var x = f(1,2,3);
while (x.length < 4) {
x = f(4,5,6,7,8);
}
return x.length;
}
assertEquals(5, g());
assertEquals(5, g());
%OptimizeFunctionOnNextCall(g);
assertEquals(5, 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(a) {
"use strict";
return arguments;
}
function g(a) {
"use strict";
var x = f(1,2,3);
if (a) {
x[1] = 5;
} else {
x[1] = 7;
}
return x[1];
}
assertEquals(7, g());
assertEquals(7, g());
%OptimizeFunctionOnNextCall(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(a) {
this.x=a;
this.y=1;
}
function g() {
"use strict";
var o = new f(2);
while (o.y < 4) {
o.x = 5;
o.y = 5;
}
return o.x;
}
assertEquals(5, g());
assertEquals(5, g());
%OptimizeFunctionOnNextCall(g);
assertEquals(5, g());
...@@ -167,6 +167,18 @@ ...@@ -167,6 +167,18 @@
# TODO(titzer): too slow in --turbo mode due to O(n^2) graph verification. # TODO(titzer): too slow in --turbo mode due to O(n^2) graph verification.
'regress/regress-1122': [PASS, NO_VARIANTS], 'regress/regress-1122': [PASS, NO_VARIANTS],
# TODO(sigurds): Tests that may fail because of missing deopt support.
'compiler/escape-analysis-1': [PASS, NO_VARIANTS],
'compiler/escape-analysis-2': [PASS, NO_VARIANTS],
'compiler/escape-analysis-3': [PASS, NO_VARIANTS],
'compiler/escape-analysis-4': [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],
# TODO(sigurds): Tests that fail because of incomplete use handling (i.e. select).
'compiler/escape-analysis-8': [PASS, NO_VARIANTS],
# Assumptions about optimization need investigation in TurboFan. # Assumptions about optimization need investigation in TurboFan.
'regress-sync-optimized-lists': [PASS, NO_VARIANTS], 'regress-sync-optimized-lists': [PASS, NO_VARIANTS],
......
// 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/bit-vector.h"
#include "src/compiler/escape-analysis.h"
#include "src/compiler/escape-analysis-reducer.h"
#include "src/compiler/graph-visualizer.h"
#include "src/compiler/js-graph.h"
#include "src/compiler/node-properties.h"
#include "src/compiler/simplified-operator.h"
#include "src/types-inl.h"
#include "src/zone-containers.h"
#include "test/unittests/compiler/graph-unittest.h"
namespace v8 {
namespace internal {
namespace compiler {
class EscapeAnalysisTest : public GraphTest {
public:
EscapeAnalysisTest()
: simplified_(zone()),
jsgraph_(isolate(), graph(), common(), nullptr, nullptr, nullptr),
escape_objects_(graph(), common(), zone()),
escape_status_(&escape_objects_, graph(), zone()),
effect_(graph()->start()),
control_(graph()->start()) {}
~EscapeAnalysisTest() {}
EscapeStatusAnalysis* escape_status() { return &escape_status_; }
EscapeObjectAnalysis* escape_objects() { return &escape_objects_; }
protected:
void Analysis() {
escape_objects_.Run();
escape_status_.Run();
}
void Transformation() {
GraphReducer graph_reducer(zone(), graph());
EscapeAnalysisReducer escape_reducer(
&graph_reducer, &jsgraph_, &escape_status_, &escape_objects_, zone());
graph_reducer.AddReducer(&escape_reducer);
graph_reducer.ReduceGraph();
}
// ---------------------------------Node Creation Helper----------------------
Node* BeginRegion(Node* effect = nullptr) {
if (!effect) {
effect = effect_;
}
return effect_ = graph()->NewNode(common()->BeginRegion(), effect);
}
Node* FinishRegion(Node* value, Node* effect = nullptr) {
if (!effect) {
effect = effect_;
}
return effect_ = graph()->NewNode(common()->FinishRegion(), value, effect);
}
Node* Allocate(Node* size, Node* effect = nullptr, Node* control = nullptr) {
if (!effect) {
effect = effect_;
}
if (!control) {
control = control_;
}
return effect_ = graph()->NewNode(simplified()->Allocate(), size, effect,
control);
}
Node* Constant(int num) {
return graph()->NewNode(common()->NumberConstant(num));
}
Node* Store(const FieldAccess& access, Node* allocation, Node* value,
Node* effect = nullptr, Node* control = nullptr) {
if (!effect) {
effect = effect_;
}
if (!control) {
control = control_;
}
return effect_ = graph()->NewNode(simplified()->StoreField(access),
allocation, value, effect, control);
}
Node* Load(const FieldAccess& access, Node* from, Node* effect = nullptr,
Node* control = nullptr) {
if (!effect) {
effect = effect_;
}
if (!control) {
control = control_;
}
return graph()->NewNode(simplified()->LoadField(access), from, effect,
control);
}
Node* Return(Node* value, Node* effect = nullptr, Node* control = nullptr) {
if (!effect) {
effect = effect_;
}
if (!control) {
control = control_;
}
return control_ =
graph()->NewNode(common()->Return(), value, effect, control);
}
void EndGraph() {
for (Edge edge : graph()->end()->input_edges()) {
if (NodeProperties::IsControlEdge(edge)) {
edge.UpdateTo(control_);
}
}
}
Node* Branch() {
return control_ =
graph()->NewNode(common()->Branch(), Constant(0), control_);
}
Node* IfTrue() {
return control_ = graph()->NewNode(common()->IfTrue(), control_);
}
Node* IfFalse() { return graph()->NewNode(common()->IfFalse(), control_); }
Node* Merge2(Node* control1, Node* control2) {
return control_ = graph()->NewNode(common()->Merge(2), control1, control2);
}
FieldAccess AccessAtIndex(int offset) {
FieldAccess access = {kTaggedBase, offset, MaybeHandle<Name>(), Type::Any(),
kMachAnyTagged};
return access;
}
// ---------------------------------Assertion Helper--------------------------
void ExpectReplacement(Node* node, Node* rep) {
EXPECT_EQ(rep, escape_objects()->GetReplacement(node, node->id()));
}
void ExpectReplacementPhi(Node* node, Node* left, Node* right) {
Node* rep = escape_objects()->GetReplacement(node, node->id());
ASSERT_NE(nullptr, rep);
ASSERT_EQ(IrOpcode::kPhi, rep->opcode());
EXPECT_EQ(left, NodeProperties::GetValueInput(rep, 0));
EXPECT_EQ(right, NodeProperties::GetValueInput(rep, 1));
}
void ExpectVirtual(Node* node) {
EXPECT_TRUE(node->opcode() == IrOpcode::kAllocate ||
node->opcode() == IrOpcode::kFinishRegion);
EXPECT_TRUE(escape_status()->IsVirtual(node));
}
void ExpectEscaped(Node* node) {
EXPECT_TRUE(node->opcode() == IrOpcode::kAllocate ||
node->opcode() == IrOpcode::kFinishRegion);
EXPECT_TRUE(escape_status()->IsEscaped(node));
}
SimplifiedOperatorBuilder* simplified() { return &simplified_; }
Node* effect() { return effect_; }
private:
SimplifiedOperatorBuilder simplified_;
JSGraph jsgraph_;
EscapeObjectAnalysis escape_objects_;
EscapeStatusAnalysis escape_status_;
Node* effect_;
Node* control_;
};
// -----------------------------------------------------------------------------
// Test cases.
TEST_F(EscapeAnalysisTest, StraightNonEscape) {
Node* object1 = Constant(1);
BeginRegion();
Node* allocation = Allocate(Constant(kPointerSize));
Store(AccessAtIndex(0), allocation, object1);
Node* finish = FinishRegion(allocation);
Node* load = Load(AccessAtIndex(0), finish);
Node* result = Return(load);
EndGraph();
Analysis();
ExpectVirtual(allocation);
ExpectReplacement(load, object1);
Transformation();
ASSERT_EQ(object1, NodeProperties::GetValueInput(result, 0));
}
TEST_F(EscapeAnalysisTest, StraightEscape) {
Node* object1 = Constant(1);
BeginRegion();
Node* allocation = Allocate(Constant(kPointerSize));
Store(AccessAtIndex(0), allocation, object1);
Node* finish = FinishRegion(allocation);
Node* load = Load(AccessAtIndex(0), finish);
Node* result = Return(allocation);
EndGraph();
Analysis();
ExpectEscaped(allocation);
ExpectReplacement(load, object1);
Transformation();
ASSERT_EQ(allocation, NodeProperties::GetValueInput(result, 0));
}
TEST_F(EscapeAnalysisTest, StoreLoadEscape) {
Node* object1 = Constant(1);
BeginRegion();
Node* allocation1 = Allocate(Constant(kPointerSize));
Store(AccessAtIndex(0), allocation1, object1);
Node* finish1 = FinishRegion(allocation1);
BeginRegion();
Node* allocation2 = Allocate(Constant(kPointerSize));
Store(AccessAtIndex(0), allocation2, finish1);
Node* finish2 = FinishRegion(allocation2);
Node* load = Load(AccessAtIndex(0), finish2);
Node* result = Return(load);
EndGraph();
Analysis();
ExpectEscaped(allocation1);
ExpectVirtual(allocation2);
ExpectReplacement(load, finish1);
Transformation();
ASSERT_EQ(finish1, NodeProperties::GetValueInput(result, 0));
}
TEST_F(EscapeAnalysisTest, BranchNonEscape) {
Node* object1 = Constant(1);
Node* object2 = Constant(2);
BeginRegion();
Node* allocation = Allocate(Constant(kPointerSize));
Store(AccessAtIndex(0), allocation, object1);
Node* finish = FinishRegion(allocation);
Branch();
Node* ifFalse = IfFalse();
Node* ifTrue = IfTrue();
Node* effect1 = Store(AccessAtIndex(0), allocation, object1, finish, ifFalse);
Node* effect2 = Store(AccessAtIndex(0), allocation, object2, finish, ifTrue);
Node* merge = Merge2(ifFalse, ifTrue);
Node* phi = graph()->NewNode(common()->EffectPhi(2), effect1, effect2, merge);
Node* load = Load(AccessAtIndex(0), finish, phi, merge);
Node* result = Return(load, phi);
EndGraph();
Analysis();
ExpectVirtual(allocation);
ExpectReplacementPhi(load, object1, object2);
Node* replacement_phi = escape_objects()->GetReplacement(load, load->id());
Transformation();
ASSERT_EQ(replacement_phi, NodeProperties::GetValueInput(result, 0));
}
TEST_F(EscapeAnalysisTest, DanglingLoadOrder) {
Node* object1 = Constant(1);
Node* object2 = Constant(2);
Node* allocation = Allocate(Constant(kPointerSize));
Node* store1 = Store(AccessAtIndex(0), allocation, object1);
Node* load1 = Load(AccessAtIndex(0), allocation);
Store(AccessAtIndex(0), allocation, object2);
Node* load2 = Load(AccessAtIndex(0), allocation, store1);
Node* result = Return(load2);
EndGraph();
Analysis();
ExpectVirtual(allocation);
ExpectReplacement(load1, object1);
ExpectReplacement(load2, object1);
Transformation();
ASSERT_EQ(object1, NodeProperties::GetValueInput(result, 0));
}
} // namespace compiler
} // namespace internal
} // namespace v8
...@@ -54,6 +54,7 @@ ...@@ -54,6 +54,7 @@
'compiler/control-flow-optimizer-unittest.cc', 'compiler/control-flow-optimizer-unittest.cc',
'compiler/dead-code-elimination-unittest.cc', 'compiler/dead-code-elimination-unittest.cc',
'compiler/diamond-unittest.cc', 'compiler/diamond-unittest.cc',
'compiler/escape-analysis-unittest.cc',
'compiler/graph-reducer-unittest.cc', 'compiler/graph-reducer-unittest.cc',
'compiler/graph-reducer-unittest.h', 'compiler/graph-reducer-unittest.h',
'compiler/graph-trimmer-unittest.cc', 'compiler/graph-trimmer-unittest.cc',
......
...@@ -498,6 +498,10 @@ ...@@ -498,6 +498,10 @@
'../../src/compiler/dead-code-elimination.cc', '../../src/compiler/dead-code-elimination.cc',
'../../src/compiler/dead-code-elimination.h', '../../src/compiler/dead-code-elimination.h',
'../../src/compiler/diamond.h', '../../src/compiler/diamond.h',
'../../src/compiler/escape-analysis.cc',
'../../src/compiler/escape-analysis.h',
"../../src/compiler/escape-analysis-reducer.cc",
"../../src/compiler/escape-analysis-reducer.h",
'../../src/compiler/frame.cc', '../../src/compiler/frame.cc',
'../../src/compiler/frame.h', '../../src/compiler/frame.h',
'../../src/compiler/frame-elider.cc', '../../src/compiler/frame-elider.cc',
......
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