Chromium Code Reviews| 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 | 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 Loading... | |
| 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 Loading... | |
| 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 |
| OLD | NEW |