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