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