Revert "Add initial support for inlining."
This reverts commit r23197. TBR=titzer@chromium.org Review URL: https://codereview.chromium.org/481413002 git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@23198 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
4b943f35cf
commit
b488b2ed29
2
BUILD.gn
2
BUILD.gn
@ -499,8 +499,6 @@ source_set("v8_base") {
|
||||
"src/compiler/js-generic-lowering.h",
|
||||
"src/compiler/js-graph.cc",
|
||||
"src/compiler/js-graph.h",
|
||||
"src/compiler/js-inlining.cc",
|
||||
"src/compiler/js-inlining.h",
|
||||
"src/compiler/js-operator.h",
|
||||
"src/compiler/js-typed-lowering.cc",
|
||||
"src/compiler/js-typed-lowering.h",
|
||||
|
@ -22,7 +22,6 @@ class GenericGraphBase : public ZoneObject {
|
||||
|
||||
NodeId NextNodeID() { return next_node_id_++; }
|
||||
NodeId NodeCount() const { return next_node_id_; }
|
||||
void SetNextNodeId(NodeId next) { next_node_id_ = next; }
|
||||
|
||||
private:
|
||||
Zone* zone_;
|
||||
|
@ -204,12 +204,6 @@ class GenericNode<B, S>::Inputs::iterator {
|
||||
++index_;
|
||||
return *this;
|
||||
}
|
||||
iterator& UpdateToAndIncrement(GenericNode<B, S>* new_to) {
|
||||
typename GenericNode<B, S>::Input* input = GetInput();
|
||||
input->Update(new_to);
|
||||
index_++;
|
||||
return *this;
|
||||
}
|
||||
int index() { return index_; }
|
||||
|
||||
private:
|
||||
|
@ -15,6 +15,26 @@ namespace v8 {
|
||||
namespace internal {
|
||||
namespace compiler {
|
||||
|
||||
// TODO(titzer): factor this out to a common routine with js-typed-lowering.
|
||||
static void ReplaceEffectfulWithValue(Node* node, Node* value) {
|
||||
Node* effect = NULL;
|
||||
if (OperatorProperties::HasEffectInput(node->op())) {
|
||||
effect = NodeProperties::GetEffectInput(node);
|
||||
}
|
||||
|
||||
// Requires distinguishing between value and effect edges.
|
||||
UseIter iter = node->uses().begin();
|
||||
while (iter != node->uses().end()) {
|
||||
if (NodeProperties::IsEffectEdge(iter.edge())) {
|
||||
DCHECK_NE(NULL, effect);
|
||||
iter = iter.UpdateToAndIncrement(effect);
|
||||
} else {
|
||||
iter = iter.UpdateToAndIncrement(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class ContextSpecializationVisitor : public NullNodeVisitor {
|
||||
public:
|
||||
explicit ContextSpecializationVisitor(JSContextSpecializer* spec)
|
||||
@ -25,16 +45,14 @@ class ContextSpecializationVisitor : public NullNodeVisitor {
|
||||
case IrOpcode::kJSLoadContext: {
|
||||
Reduction r = spec_->ReduceJSLoadContext(node);
|
||||
if (r.Changed() && r.replacement() != node) {
|
||||
NodeProperties::ReplaceWithValue(node, r.replacement());
|
||||
node->RemoveAllInputs();
|
||||
ReplaceEffectfulWithValue(node, r.replacement());
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IrOpcode::kJSStoreContext: {
|
||||
Reduction r = spec_->ReduceJSStoreContext(node);
|
||||
if (r.Changed() && r.replacement() != node) {
|
||||
NodeProperties::ReplaceWithValue(node, r.replacement());
|
||||
node->RemoveAllInputs();
|
||||
ReplaceEffectfulWithValue(node, r.replacement());
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -50,8 +68,7 @@ class ContextSpecializationVisitor : public NullNodeVisitor {
|
||||
|
||||
|
||||
void JSContextSpecializer::SpecializeToContext() {
|
||||
NodeProperties::ReplaceWithValue(context_,
|
||||
jsgraph_->Constant(info_->context()));
|
||||
ReplaceEffectfulWithValue(context_, jsgraph_->Constant(info_->context()));
|
||||
|
||||
ContextSpecializationVisitor visitor(this);
|
||||
jsgraph_->graph()->VisitNodeInputsFromEnd(&visitor);
|
||||
|
@ -1,327 +0,0 @@
|
||||
// Copyright 2014 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/ast-graph-builder.h"
|
||||
#include "src/compiler/common-operator.h"
|
||||
#include "src/compiler/generic-node-inl.h"
|
||||
#include "src/compiler/graph-inl.h"
|
||||
#include "src/compiler/graph-visualizer.h"
|
||||
#include "src/compiler/js-inlining.h"
|
||||
#include "src/compiler/js-operator.h"
|
||||
#include "src/compiler/node-aux-data-inl.h"
|
||||
#include "src/compiler/node-matchers.h"
|
||||
#include "src/compiler/node-properties-inl.h"
|
||||
#include "src/compiler/simplified-operator.h"
|
||||
#include "src/compiler/typer.h"
|
||||
#include "src/parser.h"
|
||||
#include "src/rewriter.h"
|
||||
#include "src/scopes.h"
|
||||
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
namespace compiler {
|
||||
|
||||
class InlinerVisitor : public NullNodeVisitor {
|
||||
public:
|
||||
explicit InlinerVisitor(JSInliner* inliner) : inliner_(inliner) {}
|
||||
|
||||
GenericGraphVisit::Control Post(Node* node) {
|
||||
switch (node->opcode()) {
|
||||
case IrOpcode::kJSCallFunction:
|
||||
inliner_->TryInlineCall(node);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return GenericGraphVisit::CONTINUE;
|
||||
}
|
||||
|
||||
private:
|
||||
JSInliner* inliner_;
|
||||
};
|
||||
|
||||
|
||||
void JSInliner::Inline() {
|
||||
InlinerVisitor visitor(this);
|
||||
jsgraph_->graph()->VisitNodeInputsFromEnd(&visitor);
|
||||
}
|
||||
|
||||
|
||||
static void MoveWithDependencies(Graph* graph, Node* node, Node* old_block,
|
||||
Node* new_block) {
|
||||
if (OperatorProperties::HasControlInput(node->op())) {
|
||||
// Check if we have left the old_block.
|
||||
if (NodeProperties::GetControlInput(node) != old_block) return;
|
||||
// If not, move this node to the new_block.
|
||||
NodeProperties::ReplaceControlInput(node, new_block);
|
||||
}
|
||||
// Independent of whether a node has a control input or not,
|
||||
// it might have a dependency that is pinned to old_block.
|
||||
for (InputIter iter = node->inputs().begin(); iter != node->inputs().end();
|
||||
++iter) {
|
||||
if (NodeProperties::IsControlEdge(iter.edge())) continue;
|
||||
MoveWithDependencies(graph, *iter, old_block, new_block);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void MoveAllControlNodes(Node* from, Node* to) {
|
||||
for (UseIter iter = from->uses().begin(); iter != from->uses().end();) {
|
||||
if (NodeProperties::IsControlEdge(iter.edge())) {
|
||||
iter.UpdateToAndIncrement(to);
|
||||
} else {
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// TODO(sigurds) Find a home for this function and reuse it everywhere (esp. in
|
||||
// test cases, where similar code is currently duplicated).
|
||||
static void Parse(Handle<JSFunction> function, CompilationInfoWithZone* info) {
|
||||
CHECK(Parser::Parse(info));
|
||||
StrictMode strict_mode = info->function()->strict_mode();
|
||||
info->SetStrictMode(strict_mode);
|
||||
info->SetOptimizing(BailoutId::None(), Handle<Code>(function->code()));
|
||||
CHECK(Rewriter::Rewrite(info));
|
||||
CHECK(Scope::Analyze(info));
|
||||
CHECK_NE(NULL, info->scope());
|
||||
Handle<ScopeInfo> scope_info = ScopeInfo::Create(info->scope(), info->zone());
|
||||
info->shared_info()->set_scope_info(*scope_info);
|
||||
}
|
||||
|
||||
|
||||
// A facade on a JSFunction's graph to facilitate inlining. It assumes the
|
||||
// that the function graph has only one return statement, and provides
|
||||
// {UnifyReturn} to convert a function graph to that end.
|
||||
// InlineAtCall will create some new nodes using {graph}'s builders (and hence
|
||||
// those nodes will live in {graph}'s zone.
|
||||
class Inlinee {
|
||||
public:
|
||||
explicit Inlinee(JSGraph* graph) : jsgraph_(graph) {}
|
||||
|
||||
Graph* graph() { return jsgraph_->graph(); }
|
||||
JSGraph* jsgraph() { return jsgraph_; }
|
||||
|
||||
// Returns the last regular control node, that is
|
||||
// the last control node before the end node.
|
||||
Node* end_block() { return NodeProperties::GetControlInput(unique_return()); }
|
||||
|
||||
// Return the effect output of the graph,
|
||||
// that is the effect input of the return statement of the inlinee.
|
||||
Node* effect_output() {
|
||||
return NodeProperties::GetEffectInput(unique_return());
|
||||
}
|
||||
// Return the value output of the graph,
|
||||
// that is the value input of the return statement of the inlinee.
|
||||
Node* value_output() {
|
||||
return NodeProperties::GetValueInput(unique_return(), 0);
|
||||
}
|
||||
// Return the unique return statement of the graph.
|
||||
Node* unique_return() {
|
||||
Node* unique_return =
|
||||
NodeProperties::GetControlInput(jsgraph_->graph()->end());
|
||||
DCHECK_EQ(IrOpcode::kReturn, unique_return->opcode());
|
||||
return unique_return;
|
||||
}
|
||||
// Inline this graph at {call}, use {jsgraph} and its zone to create
|
||||
// any new nodes.
|
||||
void InlineAtCall(JSGraph* jsgraph, Node* call);
|
||||
// Ensure that only a single return reaches the end node.
|
||||
void UnifyReturn();
|
||||
|
||||
private:
|
||||
JSGraph* jsgraph_;
|
||||
};
|
||||
|
||||
|
||||
void Inlinee::UnifyReturn() {
|
||||
Graph* graph = jsgraph_->graph();
|
||||
|
||||
Node* final_merge = NodeProperties::GetControlInput(graph->end(), 0);
|
||||
if (final_merge->opcode() == IrOpcode::kReturn) {
|
||||
// nothing to do
|
||||
return;
|
||||
}
|
||||
DCHECK_EQ(IrOpcode::kMerge, final_merge->opcode());
|
||||
|
||||
int predecessors =
|
||||
OperatorProperties::GetControlInputCount(final_merge->op());
|
||||
Operator* op_phi = jsgraph_->common()->Phi(predecessors);
|
||||
Operator* op_ephi = jsgraph_->common()->EffectPhi(predecessors);
|
||||
|
||||
std::vector<Node*> values;
|
||||
std::vector<Node*> effects;
|
||||
// Iterate over all control flow predecessors,
|
||||
// which must be return statements.
|
||||
InputIter iter = final_merge->inputs().begin();
|
||||
while (iter != final_merge->inputs().end()) {
|
||||
Node* input = *iter;
|
||||
switch (input->opcode()) {
|
||||
case IrOpcode::kReturn:
|
||||
values.push_back(NodeProperties::GetValueInput(input, 0));
|
||||
effects.push_back(NodeProperties::GetEffectInput(input));
|
||||
iter.UpdateToAndIncrement(NodeProperties::GetControlInput(input));
|
||||
input->RemoveAllInputs();
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
++iter;
|
||||
break;
|
||||
}
|
||||
}
|
||||
values.push_back(final_merge);
|
||||
effects.push_back(final_merge);
|
||||
Node* phi = graph->NewNode(op_phi, values.size(), values.data());
|
||||
Node* ephi = graph->NewNode(op_ephi, effects.size(), effects.data());
|
||||
Node* new_return =
|
||||
graph->NewNode(jsgraph_->common()->Return(), phi, ephi, final_merge);
|
||||
graph->end()->ReplaceInput(0, new_return);
|
||||
}
|
||||
|
||||
|
||||
void Inlinee::InlineAtCall(JSGraph* jsgraph, Node* call) {
|
||||
MachineOperatorBuilder machine(jsgraph->zone());
|
||||
|
||||
Node* control = NodeProperties::GetControlInput(call);
|
||||
// Move all the nodes to the end block.
|
||||
MoveAllControlNodes(control, end_block());
|
||||
// Now move the ones the call depends on back up.
|
||||
// We have to do this back-and-forth to treat the case where the call is
|
||||
// pinned to the start block.
|
||||
MoveWithDependencies(graph(), call, end_block(), control);
|
||||
|
||||
// The inlinee uses the context from the JSFunction object. This will
|
||||
// also be the effect dependency for the inlinee as it produces an effect.
|
||||
// TODO(sigurds) Use simplified load once it is ready.
|
||||
Node* context = jsgraph->graph()->NewNode(
|
||||
machine.Load(kMachAnyTagged), NodeProperties::GetValueInput(call, 0),
|
||||
jsgraph->Int32Constant(JSFunction::kContextOffset - kHeapObjectTag),
|
||||
NodeProperties::GetEffectInput(call));
|
||||
|
||||
// {inlinee_inputs} counts JSFunction, Receiver, arguments, context,
|
||||
// but not effect, control.
|
||||
int inlinee_inputs = graph()->start()->op()->OutputCount();
|
||||
// Context is last argument.
|
||||
int inlinee_context_index = inlinee_inputs - 1;
|
||||
// {inliner_inputs} counts JSFunction, Receiver, arguments, but not
|
||||
// context, effect, control.
|
||||
int inliner_inputs = OperatorProperties::GetValueInputCount(call->op());
|
||||
// Iterate over all uses of the start node.
|
||||
UseIter iter = graph()->start()->uses().begin();
|
||||
while (iter != graph()->start()->uses().end()) {
|
||||
Node* use = *iter;
|
||||
switch (use->opcode()) {
|
||||
case IrOpcode::kParameter: {
|
||||
int index = 1 + static_cast<Operator1<int>*>(use->op())->parameter();
|
||||
if (index < inliner_inputs && index < inlinee_context_index) {
|
||||
// There is an input from the call, and the index is a value
|
||||
// projection but not the context, so rewire the input.
|
||||
NodeProperties::ReplaceWithValue(*iter, call->InputAt(index));
|
||||
} else if (index == inlinee_context_index) {
|
||||
// This is the context projection, rewire it to the context from the
|
||||
// JSFunction object.
|
||||
NodeProperties::ReplaceWithValue(*iter, context);
|
||||
} else if (index < inlinee_context_index) {
|
||||
// Call has fewer arguments than required, fill with undefined.
|
||||
NodeProperties::ReplaceWithValue(*iter, jsgraph->UndefinedConstant());
|
||||
} else {
|
||||
// We got too many arguments, discard for now.
|
||||
// TODO(sigurds): Fix to treat arguments array correctly.
|
||||
}
|
||||
++iter;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
if (NodeProperties::IsEffectEdge(iter.edge())) {
|
||||
iter.UpdateToAndIncrement(context);
|
||||
} else if (NodeProperties::IsControlEdge(iter.edge())) {
|
||||
iter.UpdateToAndIncrement(control);
|
||||
} else {
|
||||
UNREACHABLE();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Iterate over all uses of the call node.
|
||||
iter = call->uses().begin();
|
||||
while (iter != call->uses().end()) {
|
||||
if (NodeProperties::IsEffectEdge(iter.edge())) {
|
||||
iter.UpdateToAndIncrement(effect_output());
|
||||
} else if (NodeProperties::IsControlEdge(iter.edge())) {
|
||||
UNREACHABLE();
|
||||
} else {
|
||||
DCHECK(NodeProperties::IsValueEdge(iter.edge()));
|
||||
iter.UpdateToAndIncrement(value_output());
|
||||
}
|
||||
}
|
||||
call->RemoveAllInputs();
|
||||
DCHECK_EQ(0, call->UseCount());
|
||||
// TODO(sigurds) Remove this once we copy.
|
||||
unique_return()->RemoveAllInputs();
|
||||
}
|
||||
|
||||
|
||||
void JSInliner::TryInlineCall(Node* node) {
|
||||
DCHECK_EQ(IrOpcode::kJSCallFunction, node->opcode());
|
||||
|
||||
ValueMatcher<Handle<JSFunction> > match(node->InputAt(0));
|
||||
if (!match.HasValue()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Handle<JSFunction> function = match.Value();
|
||||
|
||||
if (function->shared()->native()) {
|
||||
if (FLAG_trace_turbo_inlining) {
|
||||
SmartArrayPointer<char> name =
|
||||
function->shared()->DebugName()->ToCString();
|
||||
PrintF("Not Inlining %s into %s because inlinee is native\n", name.get(),
|
||||
info_->shared_info()->DebugName()->ToCString().get());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
CompilationInfoWithZone info(function);
|
||||
Parse(function, &info);
|
||||
|
||||
if (info.scope()->arguments() != NULL) {
|
||||
// For now do not inline functions that use their arguments array.
|
||||
SmartArrayPointer<char> name = function->shared()->DebugName()->ToCString();
|
||||
if (FLAG_trace_turbo_inlining) {
|
||||
PrintF(
|
||||
"Not Inlining %s into %s because inlinee uses arguments "
|
||||
"array\n",
|
||||
name.get(), info_->shared_info()->DebugName()->ToCString().get());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (FLAG_trace_turbo_inlining) {
|
||||
SmartArrayPointer<char> name = function->shared()->DebugName()->ToCString();
|
||||
PrintF("Inlining %s into %s\n", name.get(),
|
||||
info_->shared_info()->DebugName()->ToCString().get());
|
||||
}
|
||||
|
||||
Graph graph(info_->zone());
|
||||
graph.SetNextNodeId(jsgraph_->graph()->NextNodeID());
|
||||
|
||||
Typer typer(info_->zone());
|
||||
CommonOperatorBuilder common(info_->zone());
|
||||
JSGraph jsgraph(&graph, &common, &typer);
|
||||
|
||||
AstGraphBuilder graph_builder(&info, &jsgraph);
|
||||
graph_builder.CreateGraph();
|
||||
|
||||
Inlinee inlinee(&jsgraph);
|
||||
inlinee.UnifyReturn();
|
||||
inlinee.InlineAtCall(jsgraph_, node);
|
||||
|
||||
jsgraph_->graph()->SetNextNodeId(inlinee.graph()->NextNodeID());
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace v8::internal::compiler
|
@ -1,34 +0,0 @@
|
||||
// Copyright 2014 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_JS_INLINING_H_
|
||||
#define V8_COMPILER_JS_INLINING_H_
|
||||
|
||||
#include "src/compiler/js-graph.h"
|
||||
#include "src/v8.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
namespace compiler {
|
||||
|
||||
class JSInliner {
|
||||
public:
|
||||
JSInliner(CompilationInfo* info, JSGraph* jsgraph)
|
||||
: info_(info), jsgraph_(jsgraph) {}
|
||||
|
||||
void Inline();
|
||||
void TryInlineCall(Node* node);
|
||||
|
||||
private:
|
||||
friend class InlinerVisitor;
|
||||
CompilationInfo* info_;
|
||||
JSGraph* jsgraph_;
|
||||
|
||||
static void UnifyReturn(Graph* graph);
|
||||
};
|
||||
}
|
||||
}
|
||||
} // namespace v8::internal::compiler
|
||||
|
||||
#endif // V8_COMPILER_JS_INLINING_H_
|
@ -17,18 +17,39 @@ namespace compiler {
|
||||
// - relax effects from generic but not-side-effecting operations
|
||||
// - relax effects for ToNumber(mixed)
|
||||
|
||||
// Replace value uses of {node} with {value} and effect uses of {node} with
|
||||
// {effect}. If {effect == NULL}, then use the effect input to {node}.
|
||||
// TODO(titzer): move into a GraphEditor?
|
||||
static void ReplaceUses(Node* node, Node* value, Node* effect) {
|
||||
if (value == effect) {
|
||||
// Effect and value updates are the same; no special iteration needed.
|
||||
if (value != node) node->ReplaceUses(value);
|
||||
return;
|
||||
}
|
||||
|
||||
if (effect == NULL) effect = NodeProperties::GetEffectInput(node);
|
||||
|
||||
// The iteration requires distinguishing between value and effect edges.
|
||||
UseIter iter = node->uses().begin();
|
||||
while (iter != node->uses().end()) {
|
||||
if (NodeProperties::IsEffectEdge(iter.edge())) {
|
||||
iter = iter.UpdateToAndIncrement(effect);
|
||||
} else {
|
||||
iter = iter.UpdateToAndIncrement(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Relax the effects of {node} by immediately replacing effect uses of {node}
|
||||
// with the effect input to {node}.
|
||||
// TODO(turbofan): replace the effect input to {node} with {graph->start()}.
|
||||
// TODO(titzer): move into a GraphEditor?
|
||||
static void RelaxEffects(Node* node) {
|
||||
NodeProperties::ReplaceWithValue(node, node, NULL);
|
||||
}
|
||||
static void RelaxEffects(Node* node) { ReplaceUses(node, node, NULL); }
|
||||
|
||||
|
||||
Reduction JSTypedLowering::ReplaceEagerly(Node* old, Node* node) {
|
||||
NodeProperties::ReplaceWithValue(old, node, node);
|
||||
ReplaceUses(old, node, node);
|
||||
return Reducer::Changed(node);
|
||||
}
|
||||
|
||||
@ -501,7 +522,7 @@ Reduction JSTypedLowering::ReduceJSToBooleanInput(Node* input) {
|
||||
|
||||
static Reduction ReplaceWithReduction(Node* node, Reduction reduction) {
|
||||
if (reduction.Changed()) {
|
||||
NodeProperties::ReplaceWithValue(node, reduction.replacement());
|
||||
ReplaceUses(node, reduction.replacement(), NULL);
|
||||
return reduction;
|
||||
}
|
||||
return Reducer::NoChange();
|
||||
@ -552,13 +573,13 @@ Reduction JSTypedLowering::Reduce(Node* node) {
|
||||
// !x => BooleanNot(x)
|
||||
value =
|
||||
graph()->NewNode(simplified()->BooleanNot(), result.replacement());
|
||||
NodeProperties::ReplaceWithValue(node, value);
|
||||
ReplaceUses(node, value, NULL);
|
||||
return Changed(value);
|
||||
} else {
|
||||
// !x => BooleanNot(JSToBoolean(x))
|
||||
value = graph()->NewNode(simplified()->BooleanNot(), node);
|
||||
node->set_op(javascript()->ToBoolean());
|
||||
NodeProperties::ReplaceWithValue(node, value, node);
|
||||
ReplaceUses(node, value, node);
|
||||
// Note: ReplaceUses() smashes all uses, so smash it back here.
|
||||
value->ReplaceInput(0, node);
|
||||
return ReplaceWith(value);
|
||||
|
@ -148,28 +148,6 @@ inline void NodeProperties::RemoveNonValueInputs(Node* node) {
|
||||
}
|
||||
|
||||
|
||||
// Replace value uses of {node} with {value} and effect uses of {node} with
|
||||
// {effect}. If {effect == NULL}, then use the effect input to {node}.
|
||||
inline void NodeProperties::ReplaceWithValue(Node* node, Node* value,
|
||||
Node* effect) {
|
||||
DCHECK(!OperatorProperties::HasControlOutput(node->op()));
|
||||
if (effect == NULL && OperatorProperties::HasEffectInput(node->op())) {
|
||||
effect = NodeProperties::GetEffectInput(node);
|
||||
}
|
||||
|
||||
// Requires distinguishing between value and effect edges.
|
||||
UseIter iter = node->uses().begin();
|
||||
while (iter != node->uses().end()) {
|
||||
if (NodeProperties::IsEffectEdge(iter.edge())) {
|
||||
DCHECK_NE(NULL, effect);
|
||||
iter = iter.UpdateToAndIncrement(effect);
|
||||
} else {
|
||||
iter = iter.UpdateToAndIncrement(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Type Bounds.
|
||||
|
||||
|
@ -33,8 +33,6 @@ class NodeProperties {
|
||||
static inline void ReplaceEffectInput(Node* node, Node* effect,
|
||||
int index = 0);
|
||||
static inline void RemoveNonValueInputs(Node* node);
|
||||
static inline void ReplaceWithValue(Node* node, Node* value,
|
||||
Node* effect = NULL);
|
||||
|
||||
static inline Bounds GetBounds(Node* node);
|
||||
static inline void SetBounds(Node* node, Bounds bounds);
|
||||
|
@ -13,7 +13,6 @@
|
||||
#include "src/compiler/instruction-selector.h"
|
||||
#include "src/compiler/js-context-specialization.h"
|
||||
#include "src/compiler/js-generic-lowering.h"
|
||||
#include "src/compiler/js-inlining.h"
|
||||
#include "src/compiler/js-typed-lowering.h"
|
||||
#include "src/compiler/phi-reducer.h"
|
||||
#include "src/compiler/register-allocator.h"
|
||||
@ -187,22 +186,14 @@ Handle<Code> Pipeline::GenerateCode() {
|
||||
VerifyAndPrintGraph(&graph, "Initial untyped");
|
||||
|
||||
if (FLAG_context_specialization) {
|
||||
SourcePositionTable::Scope pos(&source_positions,
|
||||
SourcePosition::Unknown());
|
||||
SourcePositionTable::Scope pos_(&source_positions,
|
||||
SourcePosition::Unknown());
|
||||
// Specialize the code to the context as aggressively as possible.
|
||||
JSContextSpecializer spec(info(), &jsgraph, context_node);
|
||||
spec.SpecializeToContext();
|
||||
VerifyAndPrintGraph(&graph, "Context specialized");
|
||||
}
|
||||
|
||||
if (FLAG_turbo_inlining) {
|
||||
SourcePositionTable::Scope pos(&source_positions,
|
||||
SourcePosition::Unknown());
|
||||
JSInliner inliner(info(), &jsgraph);
|
||||
inliner.Inline();
|
||||
VerifyAndPrintGraph(&graph, "Inlined");
|
||||
}
|
||||
|
||||
// Print a replay of the initial graph.
|
||||
if (FLAG_print_turbo_replay) {
|
||||
GraphReplayPrinter::PrintReplay(&graph);
|
||||
|
@ -338,8 +338,6 @@ DEFINE_BOOL(turbo_source_positions, false,
|
||||
DEFINE_BOOL(context_specialization, true,
|
||||
"enable context specialization in TurboFan")
|
||||
DEFINE_BOOL(turbo_deoptimization, false, "enable deoptimization in TurboFan")
|
||||
DEFINE_BOOL(turbo_inlining, false, "enable inlining in TurboFan")
|
||||
DEFINE_BOOL(trace_turbo_inlining, false, "trace TurboFan inlining")
|
||||
|
||||
DEFINE_INT(typed_array_max_size_in_heap, 64,
|
||||
"threshold for in-heap typed array")
|
||||
|
@ -71,7 +71,6 @@
|
||||
'compiler/test-pipeline.cc',
|
||||
'compiler/test-representation-change.cc',
|
||||
'compiler/test-run-deopt.cc',
|
||||
'compiler/test-run-inlining.cc',
|
||||
'compiler/test-run-intrinsics.cc',
|
||||
'compiler/test-run-jsbranches.cc',
|
||||
'compiler/test-run-jscalls.cc',
|
||||
|
@ -1,180 +0,0 @@
|
||||
// Copyright 2014 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/v8.h"
|
||||
|
||||
#include "test/cctest/compiler/function-tester.h"
|
||||
|
||||
using namespace v8::internal;
|
||||
using namespace v8::internal::compiler;
|
||||
|
||||
// TODO(sigurds) At the moment we do not write optimization frames when
|
||||
// inlining, thus the reported stack depth changes depending on inlining.
|
||||
// AssertStackDepth checks the stack depth at a simple way to ensure that
|
||||
// inlining actually occurs.
|
||||
// Once inlining creates optimization frames, all these unit tests need to
|
||||
// check that the optimization frame is there.
|
||||
|
||||
|
||||
static void AssertStackDepth(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
v8::HandleScope scope(args.GetIsolate());
|
||||
v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
|
||||
args.GetIsolate(), 10, v8::StackTrace::kDetailed);
|
||||
CHECK_EQ(args[0]->ToInt32()->Value(), stackTrace->GetFrameCount());
|
||||
}
|
||||
|
||||
|
||||
static void InstallAssertStackDepthHelper(v8::Isolate* isolate) {
|
||||
v8::Local<v8::Context> context = isolate->GetCurrentContext();
|
||||
v8::Local<v8::FunctionTemplate> t =
|
||||
v8::FunctionTemplate::New(isolate, AssertStackDepth);
|
||||
context->Global()->Set(v8_str("AssertStackDepth"), t->GetFunction());
|
||||
}
|
||||
|
||||
|
||||
TEST(SimpleInlining) {
|
||||
i::FLAG_turbo_inlining = true;
|
||||
FunctionTester T(
|
||||
"(function(){"
|
||||
"function foo(s) { AssertStackDepth(1); return s; };"
|
||||
"function bar(s, t) { return foo(s); };"
|
||||
"return bar;})();");
|
||||
|
||||
InstallAssertStackDepthHelper(CcTest::isolate());
|
||||
T.CheckCall(T.Val(1), T.Val(1), T.Val(2));
|
||||
}
|
||||
|
||||
|
||||
TEST(SimpleInliningContext) {
|
||||
i::FLAG_turbo_inlining = true;
|
||||
FunctionTester T(
|
||||
"(function () {"
|
||||
"function foo(s) { AssertStackDepth(1); var x = 12; return s + x; };"
|
||||
"function bar(s, t) { return foo(s); };"
|
||||
"return bar;"
|
||||
"})();");
|
||||
|
||||
InstallAssertStackDepthHelper(CcTest::isolate());
|
||||
T.CheckCall(T.Val(13), T.Val(1), T.Val(2));
|
||||
}
|
||||
|
||||
|
||||
TEST(CaptureContext) {
|
||||
i::FLAG_turbo_inlining = true;
|
||||
FunctionTester T(
|
||||
"var f = (function () {"
|
||||
"var x = 42;"
|
||||
"function bar(s) { return x + s; };"
|
||||
"return (function (s) { return bar(s); });"
|
||||
"})();"
|
||||
"(function (s) { return f(s)})");
|
||||
|
||||
InstallAssertStackDepthHelper(CcTest::isolate());
|
||||
T.CheckCall(T.Val(42 + 12), T.Val(12), T.undefined());
|
||||
}
|
||||
|
||||
|
||||
// TODO(sigurds) For now we do not inline any native functions. If we do at
|
||||
// some point, change this test.
|
||||
TEST(DontInlineEval) {
|
||||
i::FLAG_turbo_inlining = true;
|
||||
FunctionTester T(
|
||||
"var x = 42;"
|
||||
"(function () {"
|
||||
"function bar(s, t) { return eval(\"AssertStackDepth(2); x\") };"
|
||||
"return bar;"
|
||||
"})();");
|
||||
|
||||
InstallAssertStackDepthHelper(CcTest::isolate());
|
||||
T.CheckCall(T.Val(42), T.Val("x"), T.undefined());
|
||||
}
|
||||
|
||||
|
||||
TEST(InlineOmitArguments) {
|
||||
i::FLAG_turbo_inlining = true;
|
||||
FunctionTester T(
|
||||
"(function () {"
|
||||
"var x = 42;"
|
||||
"function bar(s, t, u, v) { AssertStackDepth(1); return x + s; };"
|
||||
"return (function (s,t) { return bar(s); });"
|
||||
"})();");
|
||||
|
||||
InstallAssertStackDepthHelper(CcTest::isolate());
|
||||
T.CheckCall(T.Val(42 + 12), T.Val(12), T.undefined());
|
||||
}
|
||||
|
||||
|
||||
TEST(InlineSurplusArguments) {
|
||||
i::FLAG_turbo_inlining = true;
|
||||
FunctionTester T(
|
||||
"(function () {"
|
||||
"var x = 42;"
|
||||
"function foo(s) { AssertStackDepth(1); return x + s; };"
|
||||
"function bar(s,t) { return foo(s,t,13); };"
|
||||
"return bar;"
|
||||
"})();");
|
||||
|
||||
InstallAssertStackDepthHelper(CcTest::isolate());
|
||||
T.CheckCall(T.Val(42 + 12), T.Val(12), T.undefined());
|
||||
}
|
||||
|
||||
|
||||
TEST(InlineTwice) {
|
||||
i::FLAG_turbo_inlining = true;
|
||||
FunctionTester T(
|
||||
"(function () {"
|
||||
"var x = 42;"
|
||||
"function bar(s) { AssertStackDepth(1); return x + s; };"
|
||||
"return (function (s,t) { return bar(s) + bar(t); });"
|
||||
"})();");
|
||||
|
||||
InstallAssertStackDepthHelper(CcTest::isolate());
|
||||
T.CheckCall(T.Val(2 * 42 + 12 + 4), T.Val(12), T.Val(4));
|
||||
}
|
||||
|
||||
|
||||
TEST(InlineTwiceDependent) {
|
||||
i::FLAG_turbo_inlining = true;
|
||||
FunctionTester T(
|
||||
"(function () {"
|
||||
"var x = 42;"
|
||||
"function foo(s) { AssertStackDepth(1); return x + s; };"
|
||||
"function bar(s,t) { return foo(foo(s)); };"
|
||||
"return bar;"
|
||||
"})();");
|
||||
|
||||
InstallAssertStackDepthHelper(CcTest::isolate());
|
||||
T.CheckCall(T.Val(42 + 42 + 12), T.Val(12), T.Val(4));
|
||||
}
|
||||
|
||||
|
||||
TEST(InlineTwiceDependentDiamond) {
|
||||
i::FLAG_turbo_inlining = true;
|
||||
FunctionTester T(
|
||||
"(function () {"
|
||||
"function foo(s) { if (true) {"
|
||||
" return 12 } else { return 13; } };"
|
||||
"function bar(s,t) { return foo(foo(1)); };"
|
||||
"return bar;"
|
||||
"})();");
|
||||
|
||||
InstallAssertStackDepthHelper(CcTest::isolate());
|
||||
T.CheckCall(T.Val(12), T.undefined(), T.undefined());
|
||||
}
|
||||
|
||||
|
||||
TEST(InlineTwiceDependentDiamondReal) {
|
||||
i::FLAG_turbo_inlining = true;
|
||||
FunctionTester T(
|
||||
"(function () {"
|
||||
"var x = 41;"
|
||||
"function foo(s) { AssertStackDepth(1); if (s % 2 == 0) {"
|
||||
" return x - s } else { return x + s; } };"
|
||||
"function bar(s,t) { return foo(foo(s)); };"
|
||||
"return bar;"
|
||||
"})();");
|
||||
|
||||
InstallAssertStackDepthHelper(CcTest::isolate());
|
||||
T.CheckCall(T.Val(-11), T.Val(11), T.Val(4));
|
||||
}
|
@ -384,8 +384,6 @@
|
||||
'../../src/compiler/js-generic-lowering.h',
|
||||
'../../src/compiler/js-graph.cc',
|
||||
'../../src/compiler/js-graph.h',
|
||||
'../../src/compiler/js-inlining.cc',
|
||||
'../../src/compiler/js-inlining.h',
|
||||
'../../src/compiler/js-operator.h',
|
||||
'../../src/compiler/js-typed-lowering.cc',
|
||||
'../../src/compiler/js-typed-lowering.h',
|
||||
|
Loading…
Reference in New Issue
Block a user