| 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 |