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

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

Issue 553873002: Add copy support in inliner. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Rebase + cosmetics. Created 6 years, 3 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-graph.h ('k') | src/compiler/machine-operator-reducer-unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2014 the V8 project authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "src/compiler/ast-graph-builder.h" 5 #include "src/compiler/ast-graph-builder.h"
6 #include "src/compiler/common-operator.h" 6 #include "src/compiler/common-operator.h"
7 #include "src/compiler/generic-node-inl.h" 7 #include "src/compiler/generic-node-inl.h"
8 #include "src/compiler/graph-inl.h" 8 #include "src/compiler/graph-inl.h"
9 #include "src/compiler/graph-visualizer.h" 9 #include "src/compiler/graph-visualizer.h"
10 #include "src/compiler/js-inlining.h" 10 #include "src/compiler/js-inlining.h"
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
60 CHECK(Scope::Analyze(info)); 60 CHECK(Scope::Analyze(info));
61 CHECK_NE(NULL, info->scope()); 61 CHECK_NE(NULL, info->scope());
62 Handle<ScopeInfo> scope_info = ScopeInfo::Create(info->scope(), info->zone()); 62 Handle<ScopeInfo> scope_info = ScopeInfo::Create(info->scope(), info->zone());
63 info->shared_info()->set_scope_info(*scope_info); 63 info->shared_info()->set_scope_info(*scope_info);
64 } 64 }
65 65
66 66
67 // A facade on a JSFunction's graph to facilitate inlining. It assumes the 67 // A facade on a JSFunction's graph to facilitate inlining. It assumes the
68 // that the function graph has only one return statement, and provides 68 // that the function graph has only one return statement, and provides
69 // {UnifyReturn} to convert a function graph to that end. 69 // {UnifyReturn} to convert a function graph to that end.
70 // InlineAtCall will create some new nodes using {graph}'s builders (and hence 70 // InlineAtCall will create some new nodes using {graph}'s builders (and hence
Michael Starzinger 2014/09/09 11:52:15 nit: The last sentence of the comment is slightly
sigurds 2014/09/15 10:29:09 Done.
71 // those nodes will live in {graph}'s zone. 71 // those nodes will live in {graph}'s zone.
72 class Inlinee { 72 class Inlinee {
73 public: 73 public:
74 explicit Inlinee(JSGraph* graph) : jsgraph_(graph) {} 74 Inlinee(Node* start, Node* end) : start_(start), end_(end) {}
75
76 Graph* graph() { return jsgraph_->graph(); }
77 JSGraph* jsgraph() { return jsgraph_; }
78 75
79 // Returns the last regular control node, that is 76 // Returns the last regular control node, that is
80 // the last control node before the end node. 77 // the last control node before the end node.
81 Node* end_block() { return NodeProperties::GetControlInput(unique_return()); } 78 Node* end_block() { return NodeProperties::GetControlInput(unique_return()); }
82 79
83 // Return the effect output of the graph, 80 // Return the effect output of the graph,
84 // that is the effect input of the return statement of the inlinee. 81 // that is the effect input of the return statement of the inlinee.
85 Node* effect_output() { 82 Node* effect_output() {
86 return NodeProperties::GetEffectInput(unique_return()); 83 return NodeProperties::GetEffectInput(unique_return());
87 } 84 }
88 // Return the value output of the graph, 85 // Return the value output of the graph,
89 // that is the value input of the return statement of the inlinee. 86 // that is the value input of the return statement of the inlinee.
90 Node* value_output() { 87 Node* value_output() {
91 return NodeProperties::GetValueInput(unique_return(), 0); 88 return NodeProperties::GetValueInput(unique_return(), 0);
92 } 89 }
93 // Return the unique return statement of the graph. 90 // Return the unique return statement of the graph.
94 Node* unique_return() { 91 Node* unique_return() {
95 Node* unique_return = 92 Node* unique_return = NodeProperties::GetControlInput(end_);
96 NodeProperties::GetControlInput(jsgraph_->graph()->end());
97 DCHECK_EQ(IrOpcode::kReturn, unique_return->opcode()); 93 DCHECK_EQ(IrOpcode::kReturn, unique_return->opcode());
98 return unique_return; 94 return unique_return;
99 } 95 }
100 // Inline this graph at {call}, use {jsgraph} and its zone to create 96 // Inline this graph at {call}, use {jsgraph} and its zone to create
101 // any new nodes. 97 // any new nodes.
102 void InlineAtCall(JSGraph* jsgraph, Node* call); 98 void InlineAtCall(JSGraph* jsgraph, Node* call);
99
103 // Ensure that only a single return reaches the end node. 100 // Ensure that only a single return reaches the end node.
104 void UnifyReturn(); 101 static void UnifyReturn(JSGraph* jsgraph);
105 102
106 private: 103 private:
107 JSGraph* jsgraph_; 104 Node* start_;
105 Node* end_;
108 }; 106 };
109 107
110 108
111 void Inlinee::UnifyReturn() { 109 void Inlinee::UnifyReturn(JSGraph* jsgraph) {
112 Graph* graph = jsgraph_->graph(); 110 Graph* graph = jsgraph->graph();
113 111
114 Node* final_merge = NodeProperties::GetControlInput(graph->end(), 0); 112 Node* final_merge = NodeProperties::GetControlInput(graph->end(), 0);
115 if (final_merge->opcode() == IrOpcode::kReturn) { 113 if (final_merge->opcode() == IrOpcode::kReturn) {
116 // nothing to do 114 // nothing to do
117 return; 115 return;
118 } 116 }
119 DCHECK_EQ(IrOpcode::kMerge, final_merge->opcode()); 117 DCHECK_EQ(IrOpcode::kMerge, final_merge->opcode());
120 118
121 int predecessors = 119 int predecessors =
122 OperatorProperties::GetControlInputCount(final_merge->op()); 120 OperatorProperties::GetControlInputCount(final_merge->op());
123 Operator* op_phi = jsgraph_->common()->Phi(kMachAnyTagged, predecessors); 121 Operator* op_phi = jsgraph->common()->Phi(kMachAnyTagged, predecessors);
124 Operator* op_ephi = jsgraph_->common()->EffectPhi(predecessors); 122 Operator* op_ephi = jsgraph->common()->EffectPhi(predecessors);
125 123
126 NodeVector values(jsgraph_->zone()); 124 NodeVector values(jsgraph->zone());
127 NodeVector effects(jsgraph_->zone()); 125 NodeVector effects(jsgraph->zone());
128 // Iterate over all control flow predecessors, 126 // Iterate over all control flow predecessors,
129 // which must be return statements. 127 // which must be return statements.
130 InputIter iter = final_merge->inputs().begin(); 128 InputIter iter = final_merge->inputs().begin();
131 while (iter != final_merge->inputs().end()) { 129 while (iter != final_merge->inputs().end()) {
132 Node* input = *iter; 130 Node* input = *iter;
133 switch (input->opcode()) { 131 switch (input->opcode()) {
134 case IrOpcode::kReturn: 132 case IrOpcode::kReturn:
135 values.push_back(NodeProperties::GetValueInput(input, 0)); 133 values.push_back(NodeProperties::GetValueInput(input, 0));
136 effects.push_back(NodeProperties::GetEffectInput(input)); 134 effects.push_back(NodeProperties::GetEffectInput(input));
137 iter.UpdateToAndIncrement(NodeProperties::GetControlInput(input)); 135 iter.UpdateToAndIncrement(NodeProperties::GetControlInput(input));
138 input->RemoveAllInputs(); 136 input->RemoveAllInputs();
139 break; 137 break;
140 default: 138 default:
141 UNREACHABLE(); 139 UNREACHABLE();
142 ++iter; 140 ++iter;
143 break; 141 break;
144 } 142 }
145 } 143 }
146 values.push_back(final_merge); 144 values.push_back(final_merge);
147 effects.push_back(final_merge); 145 effects.push_back(final_merge);
148 Node* phi = 146 Node* phi =
149 graph->NewNode(op_phi, static_cast<int>(values.size()), &values.front()); 147 graph->NewNode(op_phi, static_cast<int>(values.size()), &values.front());
150 Node* ephi = graph->NewNode(op_ephi, static_cast<int>(effects.size()), 148 Node* ephi = graph->NewNode(op_ephi, static_cast<int>(effects.size()),
151 &effects.front()); 149 &effects.front());
152 Node* new_return = 150 Node* new_return =
153 graph->NewNode(jsgraph_->common()->Return(), phi, ephi, final_merge); 151 graph->NewNode(jsgraph->common()->Return(), phi, ephi, final_merge);
154 graph->end()->ReplaceInput(0, new_return); 152 graph->end()->ReplaceInput(0, new_return);
155 } 153 }
156 154
157 155
156 class CopyVisitor : public NullNodeVisitor {
157 public:
158 CopyVisitor(Graph* source_graph, JSGraph* target_graph, Zone* temp_zone)
159 : copies_(source_graph->NodeCount(), NULL, temp_zone),
160 sentinels_(source_graph->NodeCount(), NULL, temp_zone),
161 source_graph_(source_graph),
162 target_graph_(target_graph),
163 temp_zone_(temp_zone) {}
164
165 GenericGraphVisit::Control Post(Node* original) {
166 NodeVector inputs(temp_zone_);
167 for (InputIter it = original->inputs().begin();
168 it != original->inputs().end(); ++it) {
169 inputs.push_back(GetCopy(*it));
170 }
171
172 // Reuse the operator in the copy. This assumes that op lives in a zone
173 // that lives longer than graph()'s zone.
174 Node* copy = target_graph_->graph()->NewNode(original->op(), inputs.size(),
175 &inputs.front());
176 copies_[original->id()] = copy;
177 return GenericGraphVisit::CONTINUE;
178 }
179
180 Node* GetCopy(Node* original) {
181 Node* copy = copies_[original->id()];
182 if (copy == NULL) {
183 copy = GetSentinel(original);
184 }
185 return copy;
186 }
187
188 void CopyGraph() {
189 source_graph_->VisitNodeInputsFromEnd(this);
190 ReplaceSentinels();
191 }
192
193 const NodeVector& copies() { return copies_; }
194
195 private:
196 void ReplaceSentinels() {
197 for (int id = 0; id < source_graph_->NodeCount(); ++id) {
198 Node* sentinel = sentinels_[id];
199 if (sentinel == NULL) continue;
200 Node* copy = copies_[id];
201 DCHECK_NE(NULL, copy);
202 sentinel->ReplaceUses(copy);
203 }
204 }
205
206 Node* GetSentinel(Node* original) {
207 Node* sentinel = sentinels_[original->id()];
208 if (sentinel == NULL) {
209 // Create a dummy node we can replace later.
210 sentinel = target_graph_->graph()->NewNode(
211 target_graph_->common()->Int32Constant(0));
212 }
213 return sentinel;
214 }
215
216 NodeVector copies_;
217 NodeVector sentinels_;
218 Graph* source_graph_;
219 JSGraph* target_graph_;
Michael Starzinger 2014/09/09 11:52:15 I think the target_graph_ should be of type "Graph
sigurds 2014/09/15 10:29:09 Done.
220 Zone* temp_zone_;
221 };
222
223
158 void Inlinee::InlineAtCall(JSGraph* jsgraph, Node* call) { 224 void Inlinee::InlineAtCall(JSGraph* jsgraph, Node* call) {
159 MachineOperatorBuilder machine(jsgraph->zone());
160
161 // The scheduler is smart enough to place our code; we just ensure {control} 225 // The scheduler is smart enough to place our code; we just ensure {control}
162 // becomes the control input of the start of the inlinee. 226 // becomes the control input of the start of the inlinee.
163 Node* control = NodeProperties::GetControlInput(call); 227 Node* control = NodeProperties::GetControlInput(call);
164 228
165 // The inlinee uses the context from the JSFunction object. This will 229 // The inlinee uses the context from the JSFunction object. This will
166 // also be the effect dependency for the inlinee as it produces an effect. 230 // also be the effect dependency for the inlinee as it produces an effect.
167 // TODO(sigurds) Use simplified load once it is ready. 231 // TODO(sigurds) Use simplified load once it is ready.
168 Node* context = jsgraph->graph()->NewNode( 232 Node* context = jsgraph->graph()->NewNode(
169 machine.Load(kMachAnyTagged), NodeProperties::GetValueInput(call, 0), 233 jsgraph->machine()->Load(kMachAnyTagged),
234 NodeProperties::GetValueInput(call, 0),
170 jsgraph->Int32Constant(JSFunction::kContextOffset - kHeapObjectTag), 235 jsgraph->Int32Constant(JSFunction::kContextOffset - kHeapObjectTag),
171 NodeProperties::GetEffectInput(call)); 236 NodeProperties::GetEffectInput(call));
172 237
173 // {inlinee_inputs} counts JSFunction, Receiver, arguments, context, 238 // {inlinee_inputs} counts JSFunction, Receiver, arguments, context,
174 // but not effect, control. 239 // but not effect, control.
175 int inlinee_inputs = graph()->start()->op()->OutputCount(); 240 int inlinee_inputs = start_->op()->OutputCount();
176 // Context is last argument. 241 // Context is last argument.
177 int inlinee_context_index = inlinee_inputs - 1; 242 int inlinee_context_index = inlinee_inputs - 1;
178 // {inliner_inputs} counts JSFunction, Receiver, arguments, but not 243 // {inliner_inputs} counts JSFunction, Receiver, arguments, but not
179 // context, effect, control. 244 // context, effect, control.
180 int inliner_inputs = OperatorProperties::GetValueInputCount(call->op()); 245 int inliner_inputs = OperatorProperties::GetValueInputCount(call->op());
181 // Iterate over all uses of the start node. 246 // Iterate over all uses of the start node.
182 UseIter iter = graph()->start()->uses().begin(); 247 UseIter iter = start_->uses().begin();
183 while (iter != graph()->start()->uses().end()) { 248 while (iter != start_->uses().end()) {
184 Node* use = *iter; 249 Node* use = *iter;
185 switch (use->opcode()) { 250 switch (use->opcode()) {
186 case IrOpcode::kParameter: { 251 case IrOpcode::kParameter: {
187 int index = 1 + OpParameter<int>(use->op()); 252 int index = 1 + OpParameter<int>(use->op());
188 if (index < inliner_inputs && index < inlinee_context_index) { 253 if (index < inliner_inputs && index < inlinee_context_index) {
189 // There is an input from the call, and the index is a value 254 // There is an input from the call, and the index is a value
190 // projection but not the context, so rewire the input. 255 // projection but not the context, so rewire the input.
191 NodeProperties::ReplaceWithValue(*iter, call->InputAt(index)); 256 NodeProperties::ReplaceWithValue(*iter, call->InputAt(index));
192 } else if (index == inlinee_context_index) { 257 } else if (index == inlinee_context_index) {
193 // This is the context projection, rewire it to the context from the 258 // This is the context projection, rewire it to the context from the
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
227 iter.UpdateToAndIncrement(value_output()); 292 iter.UpdateToAndIncrement(value_output());
228 } 293 }
229 } 294 }
230 call->RemoveAllInputs(); 295 call->RemoveAllInputs();
231 DCHECK_EQ(0, call->UseCount()); 296 DCHECK_EQ(0, call->UseCount());
232 // TODO(sigurds) Remove this once we copy. 297 // TODO(sigurds) Remove this once we copy.
233 unique_return()->RemoveAllInputs(); 298 unique_return()->RemoveAllInputs();
234 } 299 }
235 300
236 301
237 void JSInliner::TryInlineCall(Node* node) { 302 void JSInliner::TryInlineCall(Node* call) {
238 DCHECK_EQ(IrOpcode::kJSCallFunction, node->opcode()); 303 DCHECK_EQ(IrOpcode::kJSCallFunction, call->opcode());
239 304
240 HeapObjectMatcher<JSFunction> match(node->InputAt(0)); 305 HeapObjectMatcher<JSFunction> match(call->InputAt(0));
241 if (!match.HasValue()) { 306 if (!match.HasValue()) {
242 return; 307 return;
243 } 308 }
244 309
245 Handle<JSFunction> function = match.Value().handle(); 310 Handle<JSFunction> function = match.Value().handle();
246 311
247 if (function->shared()->native()) { 312 if (function->shared()->native()) {
248 if (FLAG_trace_turbo_inlining) { 313 if (FLAG_trace_turbo_inlining) {
249 SmartArrayPointer<char> name = 314 SmartArrayPointer<char> name =
250 function->shared()->DebugName()->ToCString(); 315 function->shared()->DebugName()->ToCString();
(...skipping 17 matching lines...) Expand all
268 } 333 }
269 return; 334 return;
270 } 335 }
271 336
272 if (FLAG_trace_turbo_inlining) { 337 if (FLAG_trace_turbo_inlining) {
273 SmartArrayPointer<char> name = function->shared()->DebugName()->ToCString(); 338 SmartArrayPointer<char> name = function->shared()->DebugName()->ToCString();
274 PrintF("Inlining %s into %s\n", name.get(), 339 PrintF("Inlining %s into %s\n", name.get(),
275 info_->shared_info()->DebugName()->ToCString().get()); 340 info_->shared_info()->DebugName()->ToCString().get());
276 } 341 }
277 342
278 Graph graph(info_->zone()); 343 Graph graph(info.zone());
279 graph.SetNextNodeId(jsgraph_->graph()->NextNodeID()); 344 Typer typer(info.zone());
280 345 JSGraph jsgraph(&graph, jsgraph_->common(), jsgraph_->javascript(), &typer,
281 Typer typer(info_->zone()); 346 jsgraph_->machine());
282 CommonOperatorBuilder common(info_->zone());
283 JSGraph jsgraph(&graph, &common, &typer);
284 347
285 AstGraphBuilder graph_builder(&info, &jsgraph); 348 AstGraphBuilder graph_builder(&info, &jsgraph);
286 graph_builder.CreateGraph(); 349 graph_builder.CreateGraph();
350 Inlinee::UnifyReturn(&jsgraph);
287 351
288 Inlinee inlinee(&jsgraph); 352 CopyVisitor visitor(&graph, jsgraph_, jsgraph_->zone());
289 inlinee.UnifyReturn(); 353 visitor.CopyGraph();
290 inlinee.InlineAtCall(jsgraph_, node);
291 354
292 jsgraph_->graph()->SetNextNodeId(inlinee.graph()->NextNodeID()); 355 Inlinee inlinee(visitor.GetCopy(graph.start()), visitor.GetCopy(graph.end()));
356 inlinee.InlineAtCall(jsgraph_, call);
293 } 357 }
294 } 358 }
295 } 359 }
296 } // namespace v8::internal::compiler 360 } // namespace v8::internal::compiler
OLDNEW
« no previous file with comments | « src/compiler/js-graph.h ('k') | src/compiler/machine-operator-reducer-unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698