Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(471)

Side by Side Diff: src/compiler/js-call-reducer.cc

Issue 2890023004: [turbofan] Avoid allocating rest parameters for spread calls. (Closed)
Patch Set: Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/code-factory.cc ('k') | src/compiler/js-generic-lowering.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
OLDNEW
« no previous file with comments | « src/code-factory.cc ('k') | src/compiler/js-generic-lowering.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698