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