Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(519)

Side by Side Diff: src/compiler/js-inlining.cc

Issue 481413002: Revert "Add initial support for inlining." (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Created 6 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/compiler/js-inlining.h ('k') | src/compiler/js-typed-lowering.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2014 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "src/compiler/ast-graph-builder.h"
6 #include "src/compiler/common-operator.h"
7 #include "src/compiler/generic-node-inl.h"
8 #include "src/compiler/graph-inl.h"
9 #include "src/compiler/graph-visualizer.h"
10 #include "src/compiler/js-inlining.h"
11 #include "src/compiler/js-operator.h"
12 #include "src/compiler/node-aux-data-inl.h"
13 #include "src/compiler/node-matchers.h"
14 #include "src/compiler/node-properties-inl.h"
15 #include "src/compiler/simplified-operator.h"
16 #include "src/compiler/typer.h"
17 #include "src/parser.h"
18 #include "src/rewriter.h"
19 #include "src/scopes.h"
20
21
22 namespace v8 {
23 namespace internal {
24 namespace compiler {
25
26 class InlinerVisitor : public NullNodeVisitor {
27 public:
28 explicit InlinerVisitor(JSInliner* inliner) : inliner_(inliner) {}
29
30 GenericGraphVisit::Control Post(Node* node) {
31 switch (node->opcode()) {
32 case IrOpcode::kJSCallFunction:
33 inliner_->TryInlineCall(node);
34 break;
35 default:
36 break;
37 }
38 return GenericGraphVisit::CONTINUE;
39 }
40
41 private:
42 JSInliner* inliner_;
43 };
44
45
46 void JSInliner::Inline() {
47 InlinerVisitor visitor(this);
48 jsgraph_->graph()->VisitNodeInputsFromEnd(&visitor);
49 }
50
51
52 static void MoveWithDependencies(Graph* graph, Node* node, Node* old_block,
53 Node* new_block) {
54 if (OperatorProperties::HasControlInput(node->op())) {
55 // Check if we have left the old_block.
56 if (NodeProperties::GetControlInput(node) != old_block) return;
57 // If not, move this node to the new_block.
58 NodeProperties::ReplaceControlInput(node, new_block);
59 }
60 // Independent of whether a node has a control input or not,
61 // it might have a dependency that is pinned to old_block.
62 for (InputIter iter = node->inputs().begin(); iter != node->inputs().end();
63 ++iter) {
64 if (NodeProperties::IsControlEdge(iter.edge())) continue;
65 MoveWithDependencies(graph, *iter, old_block, new_block);
66 }
67 }
68
69
70 static void MoveAllControlNodes(Node* from, Node* to) {
71 for (UseIter iter = from->uses().begin(); iter != from->uses().end();) {
72 if (NodeProperties::IsControlEdge(iter.edge())) {
73 iter.UpdateToAndIncrement(to);
74 } else {
75 ++iter;
76 }
77 }
78 }
79
80
81 // TODO(sigurds) Find a home for this function and reuse it everywhere (esp. in
82 // test cases, where similar code is currently duplicated).
83 static void Parse(Handle<JSFunction> function, CompilationInfoWithZone* info) {
84 CHECK(Parser::Parse(info));
85 StrictMode strict_mode = info->function()->strict_mode();
86 info->SetStrictMode(strict_mode);
87 info->SetOptimizing(BailoutId::None(), Handle<Code>(function->code()));
88 CHECK(Rewriter::Rewrite(info));
89 CHECK(Scope::Analyze(info));
90 CHECK_NE(NULL, info->scope());
91 Handle<ScopeInfo> scope_info = ScopeInfo::Create(info->scope(), info->zone());
92 info->shared_info()->set_scope_info(*scope_info);
93 }
94
95
96 // A facade on a JSFunction's graph to facilitate inlining. It assumes the
97 // that the function graph has only one return statement, and provides
98 // {UnifyReturn} to convert a function graph to that end.
99 // InlineAtCall will create some new nodes using {graph}'s builders (and hence
100 // those nodes will live in {graph}'s zone.
101 class Inlinee {
102 public:
103 explicit Inlinee(JSGraph* graph) : jsgraph_(graph) {}
104
105 Graph* graph() { return jsgraph_->graph(); }
106 JSGraph* jsgraph() { return jsgraph_; }
107
108 // Returns the last regular control node, that is
109 // the last control node before the end node.
110 Node* end_block() { return NodeProperties::GetControlInput(unique_return()); }
111
112 // Return the effect output of the graph,
113 // that is the effect input of the return statement of the inlinee.
114 Node* effect_output() {
115 return NodeProperties::GetEffectInput(unique_return());
116 }
117 // Return the value output of the graph,
118 // that is the value input of the return statement of the inlinee.
119 Node* value_output() {
120 return NodeProperties::GetValueInput(unique_return(), 0);
121 }
122 // Return the unique return statement of the graph.
123 Node* unique_return() {
124 Node* unique_return =
125 NodeProperties::GetControlInput(jsgraph_->graph()->end());
126 DCHECK_EQ(IrOpcode::kReturn, unique_return->opcode());
127 return unique_return;
128 }
129 // Inline this graph at {call}, use {jsgraph} and its zone to create
130 // any new nodes.
131 void InlineAtCall(JSGraph* jsgraph, Node* call);
132 // Ensure that only a single return reaches the end node.
133 void UnifyReturn();
134
135 private:
136 JSGraph* jsgraph_;
137 };
138
139
140 void Inlinee::UnifyReturn() {
141 Graph* graph = jsgraph_->graph();
142
143 Node* final_merge = NodeProperties::GetControlInput(graph->end(), 0);
144 if (final_merge->opcode() == IrOpcode::kReturn) {
145 // nothing to do
146 return;
147 }
148 DCHECK_EQ(IrOpcode::kMerge, final_merge->opcode());
149
150 int predecessors =
151 OperatorProperties::GetControlInputCount(final_merge->op());
152 Operator* op_phi = jsgraph_->common()->Phi(predecessors);
153 Operator* op_ephi = jsgraph_->common()->EffectPhi(predecessors);
154
155 std::vector<Node*> values;
156 std::vector<Node*> effects;
157 // Iterate over all control flow predecessors,
158 // which must be return statements.
159 InputIter iter = final_merge->inputs().begin();
160 while (iter != final_merge->inputs().end()) {
161 Node* input = *iter;
162 switch (input->opcode()) {
163 case IrOpcode::kReturn:
164 values.push_back(NodeProperties::GetValueInput(input, 0));
165 effects.push_back(NodeProperties::GetEffectInput(input));
166 iter.UpdateToAndIncrement(NodeProperties::GetControlInput(input));
167 input->RemoveAllInputs();
168 break;
169 default:
170 UNREACHABLE();
171 ++iter;
172 break;
173 }
174 }
175 values.push_back(final_merge);
176 effects.push_back(final_merge);
177 Node* phi = graph->NewNode(op_phi, values.size(), values.data());
178 Node* ephi = graph->NewNode(op_ephi, effects.size(), effects.data());
179 Node* new_return =
180 graph->NewNode(jsgraph_->common()->Return(), phi, ephi, final_merge);
181 graph->end()->ReplaceInput(0, new_return);
182 }
183
184
185 void Inlinee::InlineAtCall(JSGraph* jsgraph, Node* call) {
186 MachineOperatorBuilder machine(jsgraph->zone());
187
188 Node* control = NodeProperties::GetControlInput(call);
189 // Move all the nodes to the end block.
190 MoveAllControlNodes(control, end_block());
191 // Now move the ones the call depends on back up.
192 // We have to do this back-and-forth to treat the case where the call is
193 // pinned to the start block.
194 MoveWithDependencies(graph(), call, end_block(), control);
195
196 // The inlinee uses the context from the JSFunction object. This will
197 // also be the effect dependency for the inlinee as it produces an effect.
198 // TODO(sigurds) Use simplified load once it is ready.
199 Node* context = jsgraph->graph()->NewNode(
200 machine.Load(kMachAnyTagged), NodeProperties::GetValueInput(call, 0),
201 jsgraph->Int32Constant(JSFunction::kContextOffset - kHeapObjectTag),
202 NodeProperties::GetEffectInput(call));
203
204 // {inlinee_inputs} counts JSFunction, Receiver, arguments, context,
205 // but not effect, control.
206 int inlinee_inputs = graph()->start()->op()->OutputCount();
207 // Context is last argument.
208 int inlinee_context_index = inlinee_inputs - 1;
209 // {inliner_inputs} counts JSFunction, Receiver, arguments, but not
210 // context, effect, control.
211 int inliner_inputs = OperatorProperties::GetValueInputCount(call->op());
212 // Iterate over all uses of the start node.
213 UseIter iter = graph()->start()->uses().begin();
214 while (iter != graph()->start()->uses().end()) {
215 Node* use = *iter;
216 switch (use->opcode()) {
217 case IrOpcode::kParameter: {
218 int index = 1 + static_cast<Operator1<int>*>(use->op())->parameter();
219 if (index < inliner_inputs && index < inlinee_context_index) {
220 // There is an input from the call, and the index is a value
221 // projection but not the context, so rewire the input.
222 NodeProperties::ReplaceWithValue(*iter, call->InputAt(index));
223 } else if (index == inlinee_context_index) {
224 // This is the context projection, rewire it to the context from the
225 // JSFunction object.
226 NodeProperties::ReplaceWithValue(*iter, context);
227 } else if (index < inlinee_context_index) {
228 // Call has fewer arguments than required, fill with undefined.
229 NodeProperties::ReplaceWithValue(*iter, jsgraph->UndefinedConstant());
230 } else {
231 // We got too many arguments, discard for now.
232 // TODO(sigurds): Fix to treat arguments array correctly.
233 }
234 ++iter;
235 break;
236 }
237 default:
238 if (NodeProperties::IsEffectEdge(iter.edge())) {
239 iter.UpdateToAndIncrement(context);
240 } else if (NodeProperties::IsControlEdge(iter.edge())) {
241 iter.UpdateToAndIncrement(control);
242 } else {
243 UNREACHABLE();
244 }
245 break;
246 }
247 }
248
249 // Iterate over all uses of the call node.
250 iter = call->uses().begin();
251 while (iter != call->uses().end()) {
252 if (NodeProperties::IsEffectEdge(iter.edge())) {
253 iter.UpdateToAndIncrement(effect_output());
254 } else if (NodeProperties::IsControlEdge(iter.edge())) {
255 UNREACHABLE();
256 } else {
257 DCHECK(NodeProperties::IsValueEdge(iter.edge()));
258 iter.UpdateToAndIncrement(value_output());
259 }
260 }
261 call->RemoveAllInputs();
262 DCHECK_EQ(0, call->UseCount());
263 // TODO(sigurds) Remove this once we copy.
264 unique_return()->RemoveAllInputs();
265 }
266
267
268 void JSInliner::TryInlineCall(Node* node) {
269 DCHECK_EQ(IrOpcode::kJSCallFunction, node->opcode());
270
271 ValueMatcher<Handle<JSFunction> > match(node->InputAt(0));
272 if (!match.HasValue()) {
273 return;
274 }
275
276 Handle<JSFunction> function = match.Value();
277
278 if (function->shared()->native()) {
279 if (FLAG_trace_turbo_inlining) {
280 SmartArrayPointer<char> name =
281 function->shared()->DebugName()->ToCString();
282 PrintF("Not Inlining %s into %s because inlinee is native\n", name.get(),
283 info_->shared_info()->DebugName()->ToCString().get());
284 }
285 return;
286 }
287
288 CompilationInfoWithZone info(function);
289 Parse(function, &info);
290
291 if (info.scope()->arguments() != NULL) {
292 // For now do not inline functions that use their arguments array.
293 SmartArrayPointer<char> name = function->shared()->DebugName()->ToCString();
294 if (FLAG_trace_turbo_inlining) {
295 PrintF(
296 "Not Inlining %s into %s because inlinee uses arguments "
297 "array\n",
298 name.get(), info_->shared_info()->DebugName()->ToCString().get());
299 }
300 return;
301 }
302
303 if (FLAG_trace_turbo_inlining) {
304 SmartArrayPointer<char> name = function->shared()->DebugName()->ToCString();
305 PrintF("Inlining %s into %s\n", name.get(),
306 info_->shared_info()->DebugName()->ToCString().get());
307 }
308
309 Graph graph(info_->zone());
310 graph.SetNextNodeId(jsgraph_->graph()->NextNodeID());
311
312 Typer typer(info_->zone());
313 CommonOperatorBuilder common(info_->zone());
314 JSGraph jsgraph(&graph, &common, &typer);
315
316 AstGraphBuilder graph_builder(&info, &jsgraph);
317 graph_builder.CreateGraph();
318
319 Inlinee inlinee(&jsgraph);
320 inlinee.UnifyReturn();
321 inlinee.InlineAtCall(jsgraph_, node);
322
323 jsgraph_->graph()->SetNextNodeId(inlinee.graph()->NextNodeID());
324 }
325 }
326 }
327 } // namespace v8::internal::compiler
OLDNEW
« no previous file with comments | « src/compiler/js-inlining.h ('k') | src/compiler/js-typed-lowering.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698