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/js-inlining.h" | 5 #include "src/compiler/js-inlining.h" |
| 6 | 6 |
| 7 #include "src/ast.h" | 7 #include "src/ast.h" |
| 8 #include "src/ast-numbering.h" | 8 #include "src/ast-numbering.h" |
| 9 #include "src/compiler/all-nodes.h" | 9 #include "src/compiler/all-nodes.h" |
| 10 #include "src/compiler/ast-graph-builder.h" | 10 #include "src/compiler/ast-graph-builder.h" |
| 11 #include "src/compiler/common-operator.h" | 11 #include "src/compiler/common-operator.h" |
| 12 #include "src/compiler/js-context-specialization.h" | |
| 12 #include "src/compiler/js-operator.h" | 13 #include "src/compiler/js-operator.h" |
| 13 #include "src/compiler/node-matchers.h" | 14 #include "src/compiler/node-matchers.h" |
| 14 #include "src/compiler/node-properties.h" | 15 #include "src/compiler/node-properties.h" |
| 15 #include "src/compiler/operator-properties.h" | 16 #include "src/compiler/operator-properties.h" |
| 16 #include "src/full-codegen.h" | 17 #include "src/full-codegen.h" |
| 17 #include "src/parser.h" | 18 #include "src/parser.h" |
| 18 #include "src/rewriter.h" | 19 #include "src/rewriter.h" |
| 19 #include "src/scopes.h" | 20 #include "src/scopes.h" |
| 20 | 21 |
| 21 namespace v8 { | 22 namespace v8 { |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 92 size_t total_parameters() { return start_->op()->ValueOutputCount(); } | 93 size_t total_parameters() { return start_->op()->ValueOutputCount(); } |
| 93 | 94 |
| 94 // Counts only formal parameters. | 95 // Counts only formal parameters. |
| 95 size_t formal_parameters() { | 96 size_t formal_parameters() { |
| 96 DCHECK_GE(total_parameters(), 3u); | 97 DCHECK_GE(total_parameters(), 3u); |
| 97 return total_parameters() - 3; | 98 return total_parameters() - 3; |
| 98 } | 99 } |
| 99 | 100 |
| 100 // Inline this graph at {call}, use {jsgraph} and its zone to create | 101 // Inline this graph at {call}, use {jsgraph} and its zone to create |
| 101 // any new nodes. | 102 // any new nodes. |
| 102 Reduction InlineAtCall(JSGraph* jsgraph, Node* call, Node* context); | 103 Reduction InlineAtCall(JSGraph* jsgraph, Node* call); |
| 103 | 104 |
| 104 // Ensure that only a single return reaches the end node. | 105 // Ensure that only a single return reaches the end node. |
| 105 static void UnifyReturn(JSGraph* jsgraph); | 106 static void UnifyReturn(JSGraph* jsgraph); |
| 106 | 107 |
| 107 private: | 108 private: |
| 108 Node* start_; | 109 Node* start_; |
| 109 Node* end_; | 110 Node* end_; |
| 110 }; | 111 }; |
| 111 | 112 |
| 112 | 113 |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 205 private: | 206 private: |
| 206 Operator const sentinel_op_; | 207 Operator const sentinel_op_; |
| 207 Node* const sentinel_; | 208 Node* const sentinel_; |
| 208 NodeVector copies_; | 209 NodeVector copies_; |
| 209 Graph* const source_graph_; | 210 Graph* const source_graph_; |
| 210 Graph* const target_graph_; | 211 Graph* const target_graph_; |
| 211 Zone* const temp_zone_; | 212 Zone* const temp_zone_; |
| 212 }; | 213 }; |
| 213 | 214 |
| 214 | 215 |
| 215 Reduction Inlinee::InlineAtCall(JSGraph* jsgraph, Node* call, Node* context) { | 216 Reduction Inlinee::InlineAtCall(JSGraph* jsgraph, Node* call) { |
| 216 // The scheduler is smart enough to place our code; we just ensure {control} | 217 // The scheduler is smart enough to place our code; we just ensure {control} |
| 217 // becomes the control input of the start of the inlinee, and {effect} becomes | 218 // becomes the control input of the start of the inlinee, and {effect} becomes |
| 218 // the effect input of the start of the inlinee. | 219 // the effect input of the start of the inlinee. |
| 219 Node* control = NodeProperties::GetControlInput(call); | 220 Node* control = NodeProperties::GetControlInput(call); |
| 220 Node* effect = NodeProperties::GetEffectInput(call); | 221 Node* effect = NodeProperties::GetEffectInput(call); |
| 221 | 222 |
| 222 // Context is last argument. | 223 // Context is last argument. |
| 223 int inlinee_context_index = static_cast<int>(total_parameters()) - 1; | 224 int inlinee_context_index = static_cast<int>(total_parameters()) - 1; |
| 224 // {inliner_inputs} counts JSFunction, Receiver, arguments, but not | 225 // {inliner_inputs} counts JSFunction, Receiver, arguments, but not |
| 225 // context, effect, control. | 226 // context, effect, control. |
| 226 int inliner_inputs = call->op()->ValueInputCount(); | 227 int inliner_inputs = call->op()->ValueInputCount(); |
| 227 // Iterate over all uses of the start node. | 228 // Iterate over all uses of the start node. |
| 228 for (Edge edge : start_->use_edges()) { | 229 for (Edge edge : start_->use_edges()) { |
| 229 Node* use = edge.from(); | 230 Node* use = edge.from(); |
| 230 switch (use->opcode()) { | 231 switch (use->opcode()) { |
| 231 case IrOpcode::kParameter: { | 232 case IrOpcode::kParameter: { |
| 232 int index = 1 + OpParameter<int>(use->op()); | 233 int index = 1 + OpParameter<int>(use->op()); |
| 233 if (index < inliner_inputs && index < inlinee_context_index) { | 234 if (index < inliner_inputs && index < inlinee_context_index) { |
| 234 // There is an input from the call, and the index is a value | 235 // There is an input from the call, and the index is a value |
| 235 // projection but not the context, so rewire the input. | 236 // projection but not the context, so rewire the input. |
| 236 NodeProperties::ReplaceWithValue(use, call->InputAt(index)); | 237 NodeProperties::ReplaceWithValue(use, call->InputAt(index)); |
| 237 } else if (index == inlinee_context_index) { | 238 } else if (index == inlinee_context_index) { |
| 238 // This is the context projection, rewire it to the context from the | 239 // TODO(turbofan): We always context specialize inlinees currently, so |
| 239 // JSFunction object. | 240 // we should never get here. |
| 240 NodeProperties::ReplaceWithValue(use, context); | 241 UNREACHABLE(); |
| 241 } else if (index < inlinee_context_index) { | 242 } else if (index < inlinee_context_index) { |
| 242 // Call has fewer arguments than required, fill with undefined. | 243 // Call has fewer arguments than required, fill with undefined. |
| 243 NodeProperties::ReplaceWithValue(use, jsgraph->UndefinedConstant()); | 244 NodeProperties::ReplaceWithValue(use, jsgraph->UndefinedConstant()); |
| 244 } else { | 245 } else { |
| 245 // We got too many arguments, discard for now. | 246 // We got too many arguments, discard for now. |
| 246 // TODO(sigurds): Fix to treat arguments array correctly. | 247 // TODO(sigurds): Fix to treat arguments array correctly. |
| 247 } | 248 } |
| 248 break; | 249 break; |
| 249 } | 250 } |
| 250 default: | 251 default: |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 334 if (FLAG_trace_turbo_inlining) { | 335 if (FLAG_trace_turbo_inlining) { |
| 335 SmartArrayPointer<char> name = function->shared()->DebugName()->ToCString(); | 336 SmartArrayPointer<char> name = function->shared()->DebugName()->ToCString(); |
| 336 PrintF("Inlining %s into %s\n", name.get(), | 337 PrintF("Inlining %s into %s\n", name.get(), |
| 337 info_->shared_info()->DebugName()->ToCString().get()); | 338 info_->shared_info()->DebugName()->ToCString().get()); |
| 338 } | 339 } |
| 339 | 340 |
| 340 Graph graph(info.zone()); | 341 Graph graph(info.zone()); |
| 341 JSGraph jsgraph(info.isolate(), &graph, jsgraph_->common(), | 342 JSGraph jsgraph(info.isolate(), &graph, jsgraph_->common(), |
| 342 jsgraph_->javascript(), jsgraph_->machine()); | 343 jsgraph_->javascript(), jsgraph_->machine()); |
| 343 | 344 |
| 345 // The inlinee specializes to the context from the JSFunction object. | |
| 346 // TODO(turbofan): We might want to load the context from the JSFunction at | |
| 347 // runtime in case we only know the SharedFunctionInfo once we have dynamic | |
| 348 // type feedback in the compiler. | |
| 344 AstGraphBuilder graph_builder(local_zone_, &info, &jsgraph); | 349 AstGraphBuilder graph_builder(local_zone_, &info, &jsgraph); |
| 345 graph_builder.CreateGraph(false, false); | 350 graph_builder.CreateGraph(true, false); |
|
titzer
2015/03/10 08:16:21
Can we context specialization a flag to the inline
| |
| 351 JSContextSpecializer context_specializer(&jsgraph); | |
| 352 GraphReducer graph_reducer(&graph, local_zone_); | |
| 353 graph_reducer.AddReducer(&context_specializer); | |
| 354 graph_reducer.ReduceGraph(); | |
| 346 Inlinee::UnifyReturn(&jsgraph); | 355 Inlinee::UnifyReturn(&jsgraph); |
| 347 | 356 |
| 348 CopyVisitor visitor(&graph, jsgraph_->graph(), info.zone()); | 357 CopyVisitor visitor(&graph, jsgraph_->graph(), info.zone()); |
| 349 visitor.CopyGraph(); | 358 visitor.CopyGraph(); |
| 350 | 359 |
| 351 Inlinee inlinee(visitor.GetCopy(graph.start()), visitor.GetCopy(graph.end())); | 360 Inlinee inlinee(visitor.GetCopy(graph.start()), visitor.GetCopy(graph.end())); |
| 352 | 361 |
| 353 if (FLAG_turbo_deoptimization) { | 362 if (FLAG_turbo_deoptimization) { |
| 354 Node* outer_frame_state = call.frame_state(); | 363 Node* outer_frame_state = call.frame_state(); |
| 355 // Insert argument adaptor frame if required. | 364 // Insert argument adaptor frame if required. |
| 356 if (call.formal_arguments() != inlinee.formal_parameters()) { | 365 if (call.formal_arguments() != inlinee.formal_parameters()) { |
| 357 outer_frame_state = | 366 outer_frame_state = |
| 358 CreateArgumentsAdaptorFrameState(&call, function, info.zone()); | 367 CreateArgumentsAdaptorFrameState(&call, function, info.zone()); |
| 359 } | 368 } |
| 360 | 369 |
| 361 for (Node* node : visitor.copies()) { | 370 for (Node* node : visitor.copies()) { |
| 362 if (node && node->opcode() == IrOpcode::kFrameState) { | 371 if (node && node->opcode() == IrOpcode::kFrameState) { |
| 363 DCHECK_EQ(1, OperatorProperties::GetFrameStateInputCount(node->op())); | 372 DCHECK_EQ(1, OperatorProperties::GetFrameStateInputCount(node->op())); |
| 364 AddClosureToFrameState(node, function); | 373 AddClosureToFrameState(node, function); |
| 365 NodeProperties::ReplaceFrameStateInput(node, 0, outer_frame_state); | 374 NodeProperties::ReplaceFrameStateInput(node, 0, outer_frame_state); |
| 366 } | 375 } |
| 367 } | 376 } |
| 368 } | 377 } |
| 369 | 378 |
| 370 // The inlinee uses the context from the JSFunction object. | 379 return inlinee.InlineAtCall(jsgraph_, node); |
| 371 // TODO(turbofan): We might want to load the context from the JSFunction at | |
| 372 // runtime in case we only know the SharedFunctionInfo once we have dynamic | |
| 373 // type feedback in the compiler. | |
| 374 Node* context = jsgraph_->HeapConstant(handle(function->context())); | |
| 375 | |
| 376 return inlinee.InlineAtCall(jsgraph_, node, context); | |
| 377 } | 380 } |
| 378 | 381 |
| 379 } // namespace compiler | 382 } // namespace compiler |
| 380 } // namespace internal | 383 } // namespace internal |
| 381 } // namespace v8 | 384 } // namespace v8 |
| OLD | NEW |