summaryrefslogtreecommitdiff
path: root/deps/v8/src/compiler/js-inlining.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/compiler/js-inlining.cc')
-rw-r--r--deps/v8/src/compiler/js-inlining.cc277
1 files changed, 123 insertions, 154 deletions
diff --git a/deps/v8/src/compiler/js-inlining.cc b/deps/v8/src/compiler/js-inlining.cc
index e3254bd077..635daa4d76 100644
--- a/deps/v8/src/compiler/js-inlining.cc
+++ b/deps/v8/src/compiler/js-inlining.cc
@@ -4,20 +4,22 @@
#include "src/compiler/js-inlining.h"
-#include "src/ast/ast.h"
#include "src/ast/ast-numbering.h"
+#include "src/ast/ast.h"
#include "src/ast/scopes.h"
#include "src/compiler.h"
-#include "src/compiler/all-nodes.h"
#include "src/compiler/ast-graph-builder.h"
+#include "src/compiler/ast-loop-assignment-analyzer.h"
#include "src/compiler/common-operator.h"
#include "src/compiler/graph-reducer.h"
#include "src/compiler/js-operator.h"
#include "src/compiler/node-matchers.h"
#include "src/compiler/node-properties.h"
#include "src/compiler/operator-properties.h"
+#include "src/compiler/simplified-operator.h"
+#include "src/compiler/type-hint-analyzer.h"
#include "src/isolate-inl.h"
-#include "src/parsing/parser.h"
+#include "src/parsing/parse-info.h"
#include "src/parsing/rewriter.h"
namespace v8 {
@@ -54,13 +56,9 @@ class JSCallAccessor {
return call_->InputAt(formal_arguments() + 1);
}
- Node* frame_state_before() {
- return NodeProperties::GetFrameStateInput(call_, 1);
- }
-
- Node* frame_state_after() {
- // Both, {JSCallFunction} and {JSCallConstruct}, have frame state after.
- return NodeProperties::GetFrameStateInput(call_, 0);
+ Node* frame_state() {
+ // Both, {JSCallFunction} and {JSCallConstruct}, have frame state.
+ return NodeProperties::GetFrameStateInput(call_);
}
int formal_arguments() {
@@ -75,63 +73,6 @@ class JSCallAccessor {
};
-class CopyVisitor {
- public:
- CopyVisitor(Graph* source_graph, Graph* target_graph, Zone* temp_zone)
- : sentinel_op_(IrOpcode::kDead, Operator::kNoProperties, "Sentinel", 0, 0,
- 0, 0, 0, 0),
- sentinel_(target_graph->NewNode(&sentinel_op_)),
- copies_(source_graph->NodeCount(), sentinel_, temp_zone),
- source_graph_(source_graph),
- target_graph_(target_graph),
- temp_zone_(temp_zone) {}
-
- Node* GetCopy(Node* orig) { return copies_[orig->id()]; }
-
- void CopyGraph() {
- NodeVector inputs(temp_zone_);
- // TODO(bmeurer): AllNodes should be turned into something like
- // Graph::CollectNodesReachableFromEnd() and the gray set stuff should be
- // removed since it's only needed by the visualizer.
- AllNodes all(temp_zone_, source_graph_);
- // Copy all nodes reachable from end.
- for (Node* orig : all.live) {
- Node* copy = GetCopy(orig);
- if (copy != sentinel_) {
- // Mapping already exists.
- continue;
- }
- // Copy the node.
- inputs.clear();
- for (Node* input : orig->inputs()) inputs.push_back(copies_[input->id()]);
- copy = target_graph_->NewNode(orig->op(), orig->InputCount(),
- inputs.empty() ? nullptr : &inputs[0]);
- copies_[orig->id()] = copy;
- }
- // For missing inputs.
- for (Node* orig : all.live) {
- Node* copy = copies_[orig->id()];
- for (int i = 0; i < copy->InputCount(); ++i) {
- Node* input = copy->InputAt(i);
- if (input == sentinel_) {
- copy->ReplaceInput(i, GetCopy(orig->InputAt(i)));
- }
- }
- }
- }
-
- const NodeVector& copies() const { return copies_; }
-
- private:
- Operator const sentinel_op_;
- Node* const sentinel_;
- NodeVector copies_;
- Graph* const source_graph_;
- Graph* const target_graph_;
- Zone* const temp_zone_;
-};
-
-
Reduction JSInliner::InlineCall(Node* call, Node* new_target, Node* context,
Node* frame_state, Node* start, Node* end) {
// The scheduler is smart enough to place our code; we just ensure {control}
@@ -166,13 +107,13 @@ Reduction JSInliner::InlineCall(Node* call, Node* new_target, Node* context,
Replace(use, new_target);
} else if (index == inlinee_arity_index) {
// The projection is requesting the number of arguments.
- Replace(use, jsgraph_->Int32Constant(inliner_inputs - 2));
+ Replace(use, jsgraph()->Int32Constant(inliner_inputs - 2));
} else if (index == inlinee_context_index) {
// The projection is requesting the inlinee function context.
Replace(use, context);
} else {
// Call has fewer arguments than required, fill with undefined.
- Replace(use, jsgraph_->UndefinedConstant());
+ Replace(use, jsgraph()->UndefinedConstant());
}
break;
}
@@ -203,9 +144,8 @@ Reduction JSInliner::InlineCall(Node* call, Node* new_target, Node* context,
case IrOpcode::kDeoptimize:
case IrOpcode::kTerminate:
case IrOpcode::kThrow:
- NodeProperties::MergeControlToEnd(jsgraph_->graph(), jsgraph_->common(),
- input);
- Revisit(jsgraph_->graph()->end());
+ NodeProperties::MergeControlToEnd(graph(), common(), input);
+ Revisit(graph()->end());
break;
default:
UNREACHABLE();
@@ -219,20 +159,20 @@ Reduction JSInliner::InlineCall(Node* call, Node* new_target, Node* context,
// uses with said value or kill value uses if no value can be returned.
if (values.size() > 0) {
int const input_count = static_cast<int>(controls.size());
- Node* control_output = jsgraph_->graph()->NewNode(
- jsgraph_->common()->Merge(input_count), input_count, &controls.front());
+ Node* control_output = graph()->NewNode(common()->Merge(input_count),
+ input_count, &controls.front());
values.push_back(control_output);
effects.push_back(control_output);
- Node* value_output = jsgraph_->graph()->NewNode(
- jsgraph_->common()->Phi(MachineRepresentation::kTagged, input_count),
+ Node* value_output = graph()->NewNode(
+ common()->Phi(MachineRepresentation::kTagged, input_count),
static_cast<int>(values.size()), &values.front());
- Node* effect_output = jsgraph_->graph()->NewNode(
- jsgraph_->common()->EffectPhi(input_count),
- static_cast<int>(effects.size()), &effects.front());
+ Node* effect_output =
+ graph()->NewNode(common()->EffectPhi(input_count),
+ static_cast<int>(effects.size()), &effects.front());
ReplaceWithValue(call, value_output, effect_output, control_output);
return Changed(value_output);
} else {
- ReplaceWithValue(call, call, call, jsgraph_->Dead());
+ ReplaceWithValue(call, call, call, jsgraph()->Dead());
return Changed(call);
}
}
@@ -243,24 +183,24 @@ Node* JSInliner::CreateArtificialFrameState(Node* node, Node* outer_frame_state,
FrameStateType frame_state_type,
Handle<SharedFunctionInfo> shared) {
const FrameStateFunctionInfo* state_info =
- jsgraph_->common()->CreateFrameStateFunctionInfo(
- frame_state_type, parameter_count + 1, 0, shared);
+ common()->CreateFrameStateFunctionInfo(frame_state_type,
+ parameter_count + 1, 0, shared);
- const Operator* op = jsgraph_->common()->FrameState(
+ const Operator* op = common()->FrameState(
BailoutId(-1), OutputFrameStateCombine::Ignore(), state_info);
- const Operator* op0 = jsgraph_->common()->StateValues(0);
- Node* node0 = jsgraph_->graph()->NewNode(op0);
+ const Operator* op0 = common()->StateValues(0);
+ Node* node0 = graph()->NewNode(op0);
NodeVector params(local_zone_);
for (int parameter = 0; parameter < parameter_count + 1; ++parameter) {
params.push_back(node->InputAt(1 + parameter));
}
const Operator* op_param =
- jsgraph_->common()->StateValues(static_cast<int>(params.size()));
- Node* params_node = jsgraph_->graph()->NewNode(
+ common()->StateValues(static_cast<int>(params.size()));
+ Node* params_node = graph()->NewNode(
op_param, static_cast<int>(params.size()), &params.front());
- return jsgraph_->graph()->NewNode(op, params_node, node0, node0,
- jsgraph_->UndefinedConstant(),
- node->InputAt(0), outer_frame_state);
+ return graph()->NewNode(op, params_node, node0, node0,
+ jsgraph()->UndefinedConstant(), node->InputAt(0),
+ outer_frame_state);
}
Node* JSInliner::CreateTailCallerFrameState(Node* node, Node* frame_state) {
@@ -272,25 +212,25 @@ Node* JSInliner::CreateTailCallerFrameState(Node* node, Node* frame_state) {
// If we are inlining a tail call drop caller's frame state and an
// arguments adaptor if it exists.
- frame_state = NodeProperties::GetFrameStateInput(frame_state, 0);
+ frame_state = NodeProperties::GetFrameStateInput(frame_state);
if (frame_state->opcode() == IrOpcode::kFrameState) {
FrameStateInfo const& frame_info = OpParameter<FrameStateInfo>(frame_state);
if (frame_info.type() == FrameStateType::kArgumentsAdaptor) {
- frame_state = NodeProperties::GetFrameStateInput(frame_state, 0);
+ frame_state = NodeProperties::GetFrameStateInput(frame_state);
}
}
const FrameStateFunctionInfo* state_info =
- jsgraph_->common()->CreateFrameStateFunctionInfo(
+ common()->CreateFrameStateFunctionInfo(
FrameStateType::kTailCallerFunction, 0, 0, shared);
- const Operator* op = jsgraph_->common()->FrameState(
+ const Operator* op = common()->FrameState(
BailoutId(-1), OutputFrameStateCombine::Ignore(), state_info);
- const Operator* op0 = jsgraph_->common()->StateValues(0);
- Node* node0 = jsgraph_->graph()->NewNode(op0);
- return jsgraph_->graph()->NewNode(op, node0, node0, node0,
- jsgraph_->UndefinedConstant(), function,
- frame_state);
+ const Operator* op0 = common()->StateValues(0);
+ Node* node0 = graph()->NewNode(op0);
+ return graph()->NewNode(op, node0, node0, node0,
+ jsgraph()->UndefinedConstant(), function,
+ frame_state);
}
namespace {
@@ -390,7 +330,7 @@ Reduction JSInliner::ReduceJSCall(Node* node, Handle<JSFunction> function) {
// TODO(turbofan): TranslatedState::GetAdaptedArguments() currently relies on
// not inlining recursive functions. We might want to relax that at some
// point.
- for (Node* frame_state = call.frame_state_after();
+ for (Node* frame_state = call.frame_state();
frame_state->opcode() == IrOpcode::kFrameState;
frame_state = frame_state->InputAt(kFrameStateOuterStateInput)) {
FrameStateInfo const& frame_info = OpParameter<FrameStateInfo>(frame_state);
@@ -414,8 +354,9 @@ Reduction JSInliner::ReduceJSCall(Node* node, Handle<JSFunction> function) {
Zone zone(info_->isolate()->allocator());
ParseInfo parse_info(&zone, function);
- CompilationInfo info(&parse_info);
+ CompilationInfo info(&parse_info, function);
if (info_->is_deoptimization_enabled()) info.MarkAsDeoptimizationEnabled();
+ if (info_->is_type_feedback_enabled()) info.MarkAsTypeFeedbackEnabled();
if (!Compiler::ParseAndAnalyze(info.parse_info())) {
TRACE("Not inlining %s into %s because parsing failed\n",
@@ -433,6 +374,7 @@ Reduction JSInliner::ReduceJSCall(Node* node, Handle<JSFunction> function) {
info_->shared_info()->DebugName()->ToCString().get());
return NoChange();
}
+
// Remember that we inlined this function. This needs to be called right
// after we ensure deoptimization support so that the code flusher
// does not remove the code with the deoptimization support.
@@ -446,59 +388,73 @@ Reduction JSInliner::ReduceJSCall(Node* node, Handle<JSFunction> function) {
shared_info->DebugName()->ToCString().get(),
info_->shared_info()->DebugName()->ToCString().get());
- // TODO(mstarzinger): We could use the temporary zone for the graph because
- // nodes are copied. This however leads to Zone-Types being allocated in the
- // wrong zone and makes the engine explode at high speeds. Explosion bad!
- Graph graph(jsgraph_->zone());
- JSGraph jsgraph(info.isolate(), &graph, jsgraph_->common(),
- jsgraph_->javascript(), jsgraph_->simplified(),
- jsgraph_->machine());
- AstGraphBuilder graph_builder(local_zone_, &info, &jsgraph);
- graph_builder.CreateGraph(false);
-
- CopyVisitor visitor(&graph, jsgraph_->graph(), &zone);
- visitor.CopyGraph();
-
- Node* start = visitor.GetCopy(graph.start());
- Node* end = visitor.GetCopy(graph.end());
- Node* frame_state = call.frame_state_after();
- Node* new_target = jsgraph_->UndefinedConstant();
-
- // Insert nodes around the call that model the behavior required for a
- // constructor dispatch (allocate implicit receiver and check return value).
- // This models the behavior usually accomplished by our {JSConstructStub}.
- // Note that the context has to be the callers context (input to call node).
- Node* receiver = jsgraph_->UndefinedConstant(); // Implicit receiver.
- if (node->opcode() == IrOpcode::kJSCallConstruct &&
- NeedsImplicitReceiver(shared_info)) {
- Node* effect = NodeProperties::GetEffectInput(node);
- Node* context = NodeProperties::GetContextInput(node);
- Node* create = jsgraph_->graph()->NewNode(
- jsgraph_->javascript()->Create(), call.target(), call.new_target(),
- context, call.frame_state_before(), effect);
- NodeProperties::ReplaceEffectInput(node, create);
- // Insert a check of the return value to determine whether the return value
- // or the implicit receiver should be selected as a result of the call.
- Node* check = jsgraph_->graph()->NewNode(
- jsgraph_->javascript()->CallRuntime(Runtime::kInlineIsJSReceiver, 1),
- node, context, node, start);
- Node* select = jsgraph_->graph()->NewNode(
- jsgraph_->common()->Select(MachineRepresentation::kTagged), check, node,
- create);
- NodeProperties::ReplaceUses(node, select, check, node, node);
- NodeProperties::ReplaceValueInput(select, node, 1);
- NodeProperties::ReplaceValueInput(check, node, 0);
- NodeProperties::ReplaceEffectInput(check, node);
- receiver = create; // The implicit receiver.
+ // If function was lazily compiled, it's literals array may not yet be set up.
+ JSFunction::EnsureLiterals(function);
+
+ // Create the subgraph for the inlinee.
+ Node* start;
+ Node* end;
+ {
+ // Run the loop assignment analyzer on the inlinee.
+ AstLoopAssignmentAnalyzer loop_assignment_analyzer(&zone, &info);
+ LoopAssignmentAnalysis* loop_assignment =
+ loop_assignment_analyzer.Analyze();
+
+ // Run the type hint analyzer on the inlinee.
+ TypeHintAnalyzer type_hint_analyzer(&zone);
+ TypeHintAnalysis* type_hint_analysis =
+ type_hint_analyzer.Analyze(handle(shared_info->code(), info.isolate()));
+
+ // Run the AstGraphBuilder to create the subgraph.
+ Graph::SubgraphScope scope(graph());
+ AstGraphBuilder graph_builder(&zone, &info, jsgraph(), loop_assignment,
+ type_hint_analysis);
+ graph_builder.CreateGraph(false);
+
+ // Extract the inlinee start/end nodes.
+ start = graph()->start();
+ end = graph()->end();
}
- // Swizzle the inputs of the {JSCallConstruct} node to look like inputs to a
- // normal {JSCallFunction} node so that the rest of the inlining machinery
- // behaves as if we were dealing with a regular function invocation.
+ Node* frame_state = call.frame_state();
+ Node* new_target = jsgraph()->UndefinedConstant();
+
+ // Inline {JSCallConstruct} requires some additional magic.
if (node->opcode() == IrOpcode::kJSCallConstruct) {
+ // Insert nodes around the call that model the behavior required for a
+ // constructor dispatch (allocate implicit receiver and check return value).
+ // This models the behavior usually accomplished by our {JSConstructStub}.
+ // Note that the context has to be the callers context (input to call node).
+ Node* receiver = jsgraph()->UndefinedConstant(); // Implicit receiver.
+ if (NeedsImplicitReceiver(shared_info)) {
+ Node* frame_state_before = NodeProperties::FindFrameStateBefore(node);
+ Node* effect = NodeProperties::GetEffectInput(node);
+ Node* context = NodeProperties::GetContextInput(node);
+ Node* create = graph()->NewNode(javascript()->Create(), call.target(),
+ call.new_target(), context,
+ frame_state_before, effect);
+ NodeProperties::ReplaceEffectInput(node, create);
+ // Insert a check of the return value to determine whether the return
+ // value or the implicit receiver should be selected as a result of the
+ // call.
+ Node* check = graph()->NewNode(simplified()->ObjectIsReceiver(), node);
+ Node* select =
+ graph()->NewNode(common()->Select(MachineRepresentation::kTagged),
+ check, node, create);
+ NodeProperties::ReplaceUses(node, select, node, node, node);
+ // Fix-up inputs that have been mangled by the {ReplaceUses} call above.
+ NodeProperties::ReplaceValueInput(select, node, 1); // Fix-up input.
+ NodeProperties::ReplaceValueInput(check, node, 0); // Fix-up input.
+ receiver = create; // The implicit receiver.
+ }
+
+ // Swizzle the inputs of the {JSCallConstruct} node to look like inputs to a
+ // normal {JSCallFunction} node so that the rest of the inlining machinery
+ // behaves as if we were dealing with a regular function invocation.
new_target = call.new_target(); // Retrieve new target value input.
node->RemoveInput(call.formal_arguments() + 1); // Drop new target.
- node->InsertInput(jsgraph_->graph()->zone(), 1, receiver);
+ node->InsertInput(graph()->zone(), 1, receiver);
+
// Insert a construct stub frame into the chain of frame states. This will
// reconstruct the proper frame when deoptimizing within the constructor.
frame_state = CreateArtificialFrameState(
@@ -510,7 +466,7 @@ Reduction JSInliner::ReduceJSCall(Node* node, Handle<JSFunction> function) {
// TODO(turbofan): We might want to load the context from the JSFunction at
// runtime in case we only know the SharedFunctionInfo once we have dynamic
// type feedback in the compiler.
- Node* context = jsgraph_->Constant(handle(function->context()));
+ Node* context = jsgraph()->Constant(handle(function->context()));
// Insert a JSConvertReceiver node for sloppy callees. Note that the context
// passed into this node has to be the callees context (loaded above). Note
@@ -519,12 +475,13 @@ Reduction JSInliner::ReduceJSCall(Node* node, Handle<JSFunction> function) {
// in that frame state tho, as the conversion of the receiver can be repeated
// any number of times, it's not observable.
if (node->opcode() == IrOpcode::kJSCallFunction &&
- is_sloppy(info.language_mode()) && !shared_info->native()) {
+ is_sloppy(parse_info.language_mode()) && !shared_info->native()) {
const CallFunctionParameters& p = CallFunctionParametersOf(node->op());
+ Node* frame_state_before = NodeProperties::FindFrameStateBefore(node);
Node* effect = NodeProperties::GetEffectInput(node);
- Node* convert = jsgraph_->graph()->NewNode(
- jsgraph_->javascript()->ConvertReceiver(p.convert_mode()),
- call.receiver(), context, call.frame_state_before(), effect, start);
+ Node* convert = graph()->NewNode(
+ javascript()->ConvertReceiver(p.convert_mode()), call.receiver(),
+ context, frame_state_before, effect, start);
NodeProperties::ReplaceValueInput(node, convert, 1);
NodeProperties::ReplaceEffectInput(node, convert);
}
@@ -558,6 +515,18 @@ Reduction JSInliner::ReduceJSCall(Node* node, Handle<JSFunction> function) {
return InlineCall(node, new_target, context, frame_state, start, end);
}
+Graph* JSInliner::graph() const { return jsgraph()->graph(); }
+
+JSOperatorBuilder* JSInliner::javascript() const {
+ return jsgraph()->javascript();
+}
+
+CommonOperatorBuilder* JSInliner::common() const { return jsgraph()->common(); }
+
+SimplifiedOperatorBuilder* JSInliner::simplified() const {
+ return jsgraph()->simplified();
+}
+
} // namespace compiler
} // namespace internal
} // namespace v8