OLD | NEW |
1 // Copyright 2015 the V8 project authors. All rights reserved. | 1 // Copyright 2015 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-call-reducer.h" | 5 #include "src/compiler/js-call-reducer.h" |
6 | 6 |
7 #include "src/code-factory.h" | 7 #include "src/code-factory.h" |
8 #include "src/code-stubs.h" | 8 #include "src/code-stubs.h" |
9 #include "src/compilation-dependencies.h" | 9 #include "src/compilation-dependencies.h" |
10 #include "src/compiler/js-graph.h" | 10 #include "src/compiler/js-graph.h" |
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
117 } else if (arity == 3) { | 117 } else if (arity == 3) { |
118 // The argArray was not provided, just remove the {target}. | 118 // The argArray was not provided, just remove the {target}. |
119 node->RemoveInput(0); | 119 node->RemoveInput(0); |
120 --arity; | 120 --arity; |
121 } else if (arity == 4) { | 121 } else if (arity == 4) { |
122 // Check if argArray is an arguments object, and {node} is the only value | 122 // Check if argArray is an arguments object, and {node} is the only value |
123 // user of argArray (except for value uses in frame states). | 123 // user of argArray (except for value uses in frame states). |
124 Node* arg_array = NodeProperties::GetValueInput(node, 3); | 124 Node* arg_array = NodeProperties::GetValueInput(node, 3); |
125 if (arg_array->opcode() != IrOpcode::kJSCreateArguments) return NoChange(); | 125 if (arg_array->opcode() != IrOpcode::kJSCreateArguments) return NoChange(); |
126 for (Edge edge : arg_array->use_edges()) { | 126 for (Edge edge : arg_array->use_edges()) { |
127 Node* user = edge.from(); | 127 Node* const user = edge.from(); |
| 128 if (user == node) continue; |
128 // Ignore uses as frame state's locals or parameters. | 129 // Ignore uses as frame state's locals or parameters. |
129 if (user->opcode() == IrOpcode::kStateValues) continue; | 130 if (user->opcode() == IrOpcode::kStateValues) continue; |
130 // Ignore uses as frame state's accumulator. | 131 // Ignore uses as frame state's accumulator. |
131 if (user->opcode() == IrOpcode::kFrameState && | 132 if (user->opcode() == IrOpcode::kFrameState && |
132 user->InputAt(2) == arg_array) { | 133 user->InputAt(2) == arg_array) { |
133 continue; | 134 continue; |
134 } | 135 } |
135 if (!NodeProperties::IsValueEdge(edge)) continue; | 136 if (!NodeProperties::IsValueEdge(edge)) continue; |
136 if (edge.from() == node) continue; | |
137 return NoChange(); | 137 return NoChange(); |
138 } | 138 } |
139 // Check if the arguments can be handled in the fast case (i.e. we don't | 139 // Check if the arguments can be handled in the fast case (i.e. we don't |
140 // have aliased sloppy arguments), and compute the {start_index} for | 140 // have aliased sloppy arguments), and compute the {start_index} for |
141 // rest parameters. | 141 // rest parameters. |
142 CreateArgumentsType const type = CreateArgumentsTypeOf(arg_array->op()); | 142 CreateArgumentsType const type = CreateArgumentsTypeOf(arg_array->op()); |
143 Node* frame_state = NodeProperties::GetFrameStateInput(arg_array); | 143 Node* frame_state = NodeProperties::GetFrameStateInput(arg_array); |
144 FrameStateInfo state_info = OpParameter<FrameStateInfo>(frame_state); | 144 FrameStateInfo state_info = OpParameter<FrameStateInfo>(frame_state); |
145 int start_index = 0; | 145 int start_index = 0; |
146 // Determine the formal parameter count; | 146 // Determine the formal parameter count; |
(...skipping 19 matching lines...) Expand all Loading... |
166 } | 166 } |
167 // Check if are applying to inlined arguments or to the arguments of | 167 // Check if are applying to inlined arguments or to the arguments of |
168 // the outermost function. | 168 // the outermost function. |
169 Node* outer_state = frame_state->InputAt(kFrameStateOuterStateInput); | 169 Node* outer_state = frame_state->InputAt(kFrameStateOuterStateInput); |
170 if (outer_state->opcode() != IrOpcode::kFrameState) { | 170 if (outer_state->opcode() != IrOpcode::kFrameState) { |
171 // Reduce {node} to a JSCallForwardVarargs operation, which just | 171 // Reduce {node} to a JSCallForwardVarargs operation, which just |
172 // re-pushes the incoming arguments and calls the {target}. | 172 // re-pushes the incoming arguments and calls the {target}. |
173 node->RemoveInput(0); // Function.prototype.apply | 173 node->RemoveInput(0); // Function.prototype.apply |
174 node->RemoveInput(2); // arguments | 174 node->RemoveInput(2); // arguments |
175 NodeProperties::ChangeOp(node, javascript()->CallForwardVarargs( | 175 NodeProperties::ChangeOp(node, javascript()->CallForwardVarargs( |
176 start_index, p.tail_call_mode())); | 176 2, start_index, p.tail_call_mode())); |
177 return Changed(node); | 177 return Changed(node); |
178 } | 178 } |
179 // Get to the actual frame state from which to extract the arguments; | 179 // Get to the actual frame state from which to extract the arguments; |
180 // we can only optimize this in case the {node} was already inlined into | 180 // we can only optimize this in case the {node} was already inlined into |
181 // some other function (and same for the {arg_array}). | 181 // some other function (and same for the {arg_array}). |
182 FrameStateInfo outer_info = OpParameter<FrameStateInfo>(outer_state); | 182 FrameStateInfo outer_info = OpParameter<FrameStateInfo>(outer_state); |
183 if (outer_info.type() == FrameStateType::kArgumentsAdaptor) { | 183 if (outer_info.type() == FrameStateType::kArgumentsAdaptor) { |
184 // Need to take the parameters from the arguments adaptor. | 184 // Need to take the parameters from the arguments adaptor. |
185 frame_state = outer_state; | 185 frame_state = outer_state; |
186 } | 186 } |
(...skipping 260 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
447 if (!isolate()->initial_array_iterator_prototype_map()->is_stable()) { | 447 if (!isolate()->initial_array_iterator_prototype_map()->is_stable()) { |
448 return NoChange(); | 448 return NoChange(); |
449 } | 449 } |
450 | 450 |
451 Node* spread = NodeProperties::GetValueInput(node, arity); | 451 Node* spread = NodeProperties::GetValueInput(node, arity); |
452 | 452 |
453 // Check if spread is an arguments object, and {node} is the only value user | 453 // Check if spread is an arguments object, and {node} is the only value user |
454 // of spread (except for value uses in frame states). | 454 // of spread (except for value uses in frame states). |
455 if (spread->opcode() != IrOpcode::kJSCreateArguments) return NoChange(); | 455 if (spread->opcode() != IrOpcode::kJSCreateArguments) return NoChange(); |
456 for (Edge edge : spread->use_edges()) { | 456 for (Edge edge : spread->use_edges()) { |
457 if (edge.from()->opcode() == IrOpcode::kStateValues) continue; | 457 Node* const user = edge.from(); |
| 458 if (user == node) continue; |
| 459 // Ignore uses as frame state's locals or parameters. |
| 460 if (user->opcode() == IrOpcode::kStateValues) continue; |
| 461 // Ignore uses as frame state's accumulator. |
| 462 if (user->opcode() == IrOpcode::kFrameState && user->InputAt(2) == spread) { |
| 463 continue; |
| 464 } |
458 if (!NodeProperties::IsValueEdge(edge)) continue; | 465 if (!NodeProperties::IsValueEdge(edge)) continue; |
459 if (edge.from() == node) continue; | |
460 return NoChange(); | 466 return NoChange(); |
461 } | 467 } |
462 | 468 |
463 // Get to the actual frame state from which to extract the arguments; | 469 // Get to the actual frame state from which to extract the arguments; |
464 // we can only optimize this in case the {node} was already inlined into | 470 // we can only optimize this in case the {node} was already inlined into |
465 // some other function (and same for the {spread}). | 471 // some other function (and same for the {spread}). |
466 CreateArgumentsType type = CreateArgumentsTypeOf(spread->op()); | 472 CreateArgumentsType const type = CreateArgumentsTypeOf(spread->op()); |
467 Node* frame_state = NodeProperties::GetFrameStateInput(spread); | 473 Node* frame_state = NodeProperties::GetFrameStateInput(spread); |
| 474 FrameStateInfo state_info = OpParameter<FrameStateInfo>(frame_state); |
| 475 int start_index = 0; |
| 476 // Determine the formal parameter count; |
| 477 Handle<SharedFunctionInfo> shared; |
| 478 if (!state_info.shared_info().ToHandle(&shared)) return NoChange(); |
| 479 int formal_parameter_count = shared->internal_formal_parameter_count(); |
| 480 if (type == CreateArgumentsType::kMappedArguments) { |
| 481 // Mapped arguments (sloppy mode) that are aliased can only be handled |
| 482 // here if there's no side-effect between the {node} and the {arg_array}. |
| 483 // TODO(turbofan): Further relax this constraint. |
| 484 if (formal_parameter_count != 0) { |
| 485 Node* effect = NodeProperties::GetEffectInput(node); |
| 486 while (effect != spread) { |
| 487 if (effect->op()->EffectInputCount() != 1 || |
| 488 !(effect->op()->properties() & Operator::kNoWrite)) { |
| 489 return NoChange(); |
| 490 } |
| 491 effect = NodeProperties::GetEffectInput(effect); |
| 492 } |
| 493 } |
| 494 } else if (type == CreateArgumentsType::kRestParameter) { |
| 495 start_index = formal_parameter_count; |
| 496 |
| 497 // Only check the array iterator protector when we have a rest object. |
| 498 if (!isolate()->IsArrayIteratorLookupChainIntact()) return NoChange(); |
| 499 } |
| 500 |
| 501 // Install appropriate code dependencies. |
| 502 dependencies()->AssumeMapStable( |
| 503 isolate()->initial_array_iterator_prototype_map()); |
| 504 if (type == CreateArgumentsType::kRestParameter) { |
| 505 dependencies()->AssumePropertyCell(factory()->array_iterator_protector()); |
| 506 } |
| 507 // Remove the spread input from the {node}. |
| 508 node->RemoveInput(arity--); |
| 509 // Check if are spreading to inlined arguments or to the arguments of |
| 510 // the outermost function. |
468 Node* outer_state = frame_state->InputAt(kFrameStateOuterStateInput); | 511 Node* outer_state = frame_state->InputAt(kFrameStateOuterStateInput); |
469 if (outer_state->opcode() != IrOpcode::kFrameState) return NoChange(); | 512 if (outer_state->opcode() != IrOpcode::kFrameState) { |
| 513 Operator const* op = |
| 514 (node->opcode() == IrOpcode::kJSCallWithSpread) |
| 515 ? javascript()->CallForwardVarargs(arity + 1, start_index, |
| 516 TailCallMode::kDisallow) |
| 517 : javascript()->ConstructForwardVarargs(arity + 2, start_index); |
| 518 NodeProperties::ChangeOp(node, op); |
| 519 return Changed(node); |
| 520 } |
| 521 // Get to the actual frame state from which to extract the arguments; |
| 522 // we can only optimize this in case the {node} was already inlined into |
| 523 // some other function (and same for the {arg_array}). |
470 FrameStateInfo outer_info = OpParameter<FrameStateInfo>(outer_state); | 524 FrameStateInfo outer_info = OpParameter<FrameStateInfo>(outer_state); |
471 if (outer_info.type() == FrameStateType::kArgumentsAdaptor) { | 525 if (outer_info.type() == FrameStateType::kArgumentsAdaptor) { |
472 // Need to take the parameters from the arguments adaptor. | 526 // Need to take the parameters from the arguments adaptor. |
473 frame_state = outer_state; | 527 frame_state = outer_state; |
474 } | 528 } |
475 FrameStateInfo state_info = OpParameter<FrameStateInfo>(frame_state); | |
476 int start_index = 0; | |
477 if (type == CreateArgumentsType::kMappedArguments) { | |
478 // Mapped arguments (sloppy mode) cannot be handled if they are aliased. | |
479 Handle<SharedFunctionInfo> shared; | |
480 if (!state_info.shared_info().ToHandle(&shared)) return NoChange(); | |
481 if (shared->internal_formal_parameter_count() != 0) return NoChange(); | |
482 } else if (type == CreateArgumentsType::kRestParameter) { | |
483 Handle<SharedFunctionInfo> shared; | |
484 if (!state_info.shared_info().ToHandle(&shared)) return NoChange(); | |
485 start_index = shared->internal_formal_parameter_count(); | |
486 | |
487 // Only check the array iterator protector when we have a rest object. | |
488 if (!isolate()->IsArrayIteratorLookupChainIntact()) return NoChange(); | |
489 // Add a code dependency on the array iterator protector. | |
490 dependencies()->AssumePropertyCell(factory()->array_iterator_protector()); | |
491 } | |
492 | |
493 dependencies()->AssumeMapStable( | |
494 isolate()->initial_array_iterator_prototype_map()); | |
495 | |
496 node->RemoveInput(arity--); | |
497 | |
498 // Add the actual parameters to the {node}, skipping the receiver. | 529 // Add the actual parameters to the {node}, skipping the receiver. |
499 Node* const parameters = frame_state->InputAt(kFrameStateParametersInput); | 530 Node* const parameters = frame_state->InputAt(kFrameStateParametersInput); |
500 for (int i = start_index + 1; i < state_info.parameter_count(); ++i) { | 531 for (int i = start_index + 1; i < parameters->InputCount(); ++i) { |
501 node->InsertInput(graph()->zone(), static_cast<int>(++arity), | 532 node->InsertInput(graph()->zone(), static_cast<int>(++arity), |
502 parameters->InputAt(i)); | 533 parameters->InputAt(i)); |
503 } | 534 } |
504 | 535 |
505 // TODO(turbofan): Collect call counts on spread call/construct and thread it | 536 // TODO(turbofan): Collect call counts on spread call/construct and thread it |
506 // through here. | 537 // through here. |
507 if (node->opcode() == IrOpcode::kJSCallWithSpread) { | 538 if (node->opcode() == IrOpcode::kJSCallWithSpread) { |
508 NodeProperties::ChangeOp(node, javascript()->Call(arity + 1)); | 539 NodeProperties::ChangeOp(node, javascript()->Call(arity + 1)); |
509 Reduction const r = ReduceJSCall(node); | 540 Reduction const r = ReduceJSCall(node); |
510 return r.Changed() ? r : Changed(node); | 541 return r.Changed() ? r : Changed(node); |
(...skipping 350 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
861 return jsgraph()->javascript(); | 892 return jsgraph()->javascript(); |
862 } | 893 } |
863 | 894 |
864 SimplifiedOperatorBuilder* JSCallReducer::simplified() const { | 895 SimplifiedOperatorBuilder* JSCallReducer::simplified() const { |
865 return jsgraph()->simplified(); | 896 return jsgraph()->simplified(); |
866 } | 897 } |
867 | 898 |
868 } // namespace compiler | 899 } // namespace compiler |
869 } // namespace internal | 900 } // namespace internal |
870 } // namespace v8 | 901 } // namespace v8 |
OLD | NEW |