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

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

Issue 2950773002: [turbofan] Introduce new JSCallWithArrayLike operator. (Closed)
Patch Set: REBASE Created 3 years, 6 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/compiler/js-call-reducer.h ('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/access-builder.h" 10 #include "src/compiler/access-builder.h"
(...skipping 10 matching lines...) Expand all
21 namespace compiler { 21 namespace compiler {
22 22
23 Reduction JSCallReducer::Reduce(Node* node) { 23 Reduction JSCallReducer::Reduce(Node* node) {
24 switch (node->opcode()) { 24 switch (node->opcode()) {
25 case IrOpcode::kJSConstruct: 25 case IrOpcode::kJSConstruct:
26 return ReduceJSConstruct(node); 26 return ReduceJSConstruct(node);
27 case IrOpcode::kJSConstructWithSpread: 27 case IrOpcode::kJSConstructWithSpread:
28 return ReduceJSConstructWithSpread(node); 28 return ReduceJSConstructWithSpread(node);
29 case IrOpcode::kJSCall: 29 case IrOpcode::kJSCall:
30 return ReduceJSCall(node); 30 return ReduceJSCall(node);
31 case IrOpcode::kJSCallWithArrayLike:
32 return ReduceJSCallWithArrayLike(node);
31 case IrOpcode::kJSCallWithSpread: 33 case IrOpcode::kJSCallWithSpread:
32 return ReduceJSCallWithSpread(node); 34 return ReduceJSCallWithSpread(node);
33 default: 35 default:
34 break; 36 break;
35 } 37 }
36 return NoChange(); 38 return NoChange();
37 } 39 }
38 40
39 41
40 // ES6 section 22.1.1 The Array Constructor 42 // ES6 section 22.1.1 The Array Constructor
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
88 90
89 // Turn the {node} into a {JSToNumber} call. 91 // Turn the {node} into a {JSToNumber} call.
90 DCHECK_LE(2u, p.arity()); 92 DCHECK_LE(2u, p.arity());
91 Node* value = (p.arity() == 2) ? jsgraph()->ZeroConstant() 93 Node* value = (p.arity() == 2) ? jsgraph()->ZeroConstant()
92 : NodeProperties::GetValueInput(node, 2); 94 : NodeProperties::GetValueInput(node, 2);
93 NodeProperties::ReplaceValueInputs(node, value); 95 NodeProperties::ReplaceValueInputs(node, value);
94 NodeProperties::ChangeOp(node, javascript()->ToNumber()); 96 NodeProperties::ChangeOp(node, javascript()->ToNumber());
95 return Changed(node); 97 return Changed(node);
96 } 98 }
97 99
100 namespace {
101
102 bool CanBeNullOrUndefined(Node* node) {
103 switch (node->opcode()) {
104 case IrOpcode::kJSCreate:
105 case IrOpcode::kJSCreateArguments:
106 case IrOpcode::kJSCreateArray:
107 case IrOpcode::kJSCreateClosure:
108 case IrOpcode::kJSCreateIterResultObject:
109 case IrOpcode::kJSCreateKeyValueArray:
110 case IrOpcode::kJSCreateLiteralArray:
111 case IrOpcode::kJSCreateLiteralObject:
112 case IrOpcode::kJSCreateLiteralRegExp:
113 case IrOpcode::kJSConstruct:
114 case IrOpcode::kJSConstructForwardVarargs:
115 case IrOpcode::kJSConstructWithSpread:
116 case IrOpcode::kJSConvertReceiver:
117 case IrOpcode::kJSToBoolean:
118 case IrOpcode::kJSToInteger:
119 case IrOpcode::kJSToLength:
120 case IrOpcode::kJSToName:
121 case IrOpcode::kJSToNumber:
122 case IrOpcode::kJSToObject:
123 case IrOpcode::kJSToString:
124 case IrOpcode::kJSToPrimitiveToString:
125 return false;
126 case IrOpcode::kHeapConstant: {
127 Handle<HeapObject> value = HeapObjectMatcher(node).Value();
128 Isolate* const isolate = value->GetIsolate();
129 return value->IsNull(isolate) || value->IsUndefined(isolate);
130 }
131 default:
132 return true;
133 }
134 }
135
136 } // namespace
98 137
99 // ES6 section 19.2.3.1 Function.prototype.apply ( thisArg, argArray ) 138 // ES6 section 19.2.3.1 Function.prototype.apply ( thisArg, argArray )
100 Reduction JSCallReducer::ReduceFunctionPrototypeApply(Node* node) { 139 Reduction JSCallReducer::ReduceFunctionPrototypeApply(Node* node) {
101 DCHECK_EQ(IrOpcode::kJSCall, node->opcode()); 140 DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
102 Node* target = NodeProperties::GetValueInput(node, 0);
103 CallParameters const& p = CallParametersOf(node->op()); 141 CallParameters const& p = CallParametersOf(node->op());
104 // Tail calls to Function.prototype.apply are not properly supported 142 // Tail calls to Function.prototype.apply are not properly supported
105 // down the pipeline, so we disable this optimization completely for 143 // down the pipeline, so we disable this optimization completely for
106 // tail calls (for now). 144 // tail calls (for now).
107 if (p.tail_call_mode() == TailCallMode::kAllow) return NoChange(); 145 if (p.tail_call_mode() == TailCallMode::kAllow) return NoChange();
108 Handle<JSFunction> apply =
109 Handle<JSFunction>::cast(HeapObjectMatcher(target).Value());
110 size_t arity = p.arity(); 146 size_t arity = p.arity();
111 DCHECK_LE(2u, arity); 147 DCHECK_LE(2u, arity);
112 ConvertReceiverMode convert_mode = ConvertReceiverMode::kAny; 148 ConvertReceiverMode convert_mode = ConvertReceiverMode::kAny;
113 if (arity == 2) { 149 if (arity == 2) {
114 // Neither thisArg nor argArray was provided. 150 // Neither thisArg nor argArray was provided.
115 convert_mode = ConvertReceiverMode::kNullOrUndefined; 151 convert_mode = ConvertReceiverMode::kNullOrUndefined;
116 node->ReplaceInput(0, node->InputAt(1)); 152 node->ReplaceInput(0, node->InputAt(1));
117 node->ReplaceInput(1, jsgraph()->UndefinedConstant()); 153 node->ReplaceInput(1, jsgraph()->UndefinedConstant());
118 } else if (arity == 3) { 154 } else if (arity == 3) {
119 // The argArray was not provided, just remove the {target}. 155 // The argArray was not provided, just remove the {target}.
120 node->RemoveInput(0); 156 node->RemoveInput(0);
121 --arity; 157 --arity;
122 } else if (arity == 4) { 158 } else {
123 // Check if argArray is an arguments object, and {node} is the only value 159 Node* target = NodeProperties::GetValueInput(node, 1);
124 // user of argArray (except for value uses in frame states). 160 Node* this_argument = NodeProperties::GetValueInput(node, 2);
125 Node* arg_array = NodeProperties::GetValueInput(node, 3); 161 Node* arguments_list = NodeProperties::GetValueInput(node, 3);
126 if (arg_array->opcode() != IrOpcode::kJSCreateArguments) return NoChange(); 162 Node* context = NodeProperties::GetContextInput(node);
127 for (Edge edge : arg_array->use_edges()) { 163 Node* frame_state = NodeProperties::GetFrameStateInput(node);
128 Node* const user = edge.from(); 164 Node* effect = NodeProperties::GetEffectInput(node);
129 if (user == node) continue; 165 Node* control = NodeProperties::GetControlInput(node);
130 // Ignore uses as frame state's locals or parameters. 166
131 if (user->opcode() == IrOpcode::kStateValues) continue; 167 // If {arguments_list} cannot be null or undefined, we don't need
132 // Ignore uses as frame state's accumulator. 168 // to expand this {node} to control-flow.
133 if (user->opcode() == IrOpcode::kFrameState && 169 if (!CanBeNullOrUndefined(arguments_list)) {
134 user->InputAt(2) == arg_array) { 170 // Massage the value inputs appropriately.
135 continue; 171 node->ReplaceInput(0, target);
172 node->ReplaceInput(1, this_argument);
173 node->ReplaceInput(2, arguments_list);
174 while (arity-- > 3) node->RemoveInput(3);
175
176 // Morph the {node} to a {JSCallWithArrayLike}.
177 NodeProperties::ChangeOp(node,
178 javascript()->CallWithArrayLike(p.frequency()));
179 Reduction const reduction = ReduceJSCallWithArrayLike(node);
180 return reduction.Changed() ? reduction : Changed(node);
181 } else {
182 // Check whether {arguments_list} is null.
183 Node* check_null =
184 graph()->NewNode(simplified()->ReferenceEqual(), arguments_list,
185 jsgraph()->NullConstant());
186 control = graph()->NewNode(common()->Branch(BranchHint::kFalse),
187 check_null, control);
188 Node* if_null = graph()->NewNode(common()->IfTrue(), control);
189 control = graph()->NewNode(common()->IfFalse(), control);
190
191 // Check whether {arguments_list} is undefined.
192 Node* check_undefined =
193 graph()->NewNode(simplified()->ReferenceEqual(), arguments_list,
194 jsgraph()->UndefinedConstant());
195 control = graph()->NewNode(common()->Branch(BranchHint::kFalse),
196 check_undefined, control);
197 Node* if_undefined = graph()->NewNode(common()->IfTrue(), control);
198 control = graph()->NewNode(common()->IfFalse(), control);
199
200 // Lower to {JSCallWithArrayLike} if {arguments_list} is neither null
201 // nor undefined.
202 Node* effect0 = effect;
203 Node* control0 = control;
204 Node* value0 = effect0 = control0 = graph()->NewNode(
205 javascript()->CallWithArrayLike(p.frequency()), target, this_argument,
206 arguments_list, context, frame_state, effect0, control0);
207
208 // Lower to {JSCall} if {arguments_list} is either null or undefined.
209 Node* effect1 = effect;
210 Node* control1 =
211 graph()->NewNode(common()->Merge(2), if_null, if_undefined);
212 Node* value1 = effect1 = control1 =
213 graph()->NewNode(javascript()->Call(2), target, this_argument,
214 context, frame_state, effect1, control1);
215
216 // Rewire potential exception edges.
217 Node* if_exception = nullptr;
218 if (NodeProperties::IsExceptionalCall(node, &if_exception)) {
219 // Create appropriate {IfException} and {IfSuccess} nodes.
220 Node* if_exception0 =
221 graph()->NewNode(common()->IfException(), control0, effect0);
222 control0 = graph()->NewNode(common()->IfSuccess(), control0);
223 Node* if_exception1 =
224 graph()->NewNode(common()->IfException(), control1, effect1);
225 control1 = graph()->NewNode(common()->IfSuccess(), control1);
226
227 // Join the exception edges.
228 Node* merge =
229 graph()->NewNode(common()->Merge(2), if_exception0, if_exception1);
230 Node* ephi = graph()->NewNode(common()->EffectPhi(2), if_exception0,
231 if_exception1, merge);
232 Node* phi =
233 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
234 if_exception0, if_exception1, merge);
235 ReplaceWithValue(if_exception, phi, ephi, merge);
136 } 236 }
137 if (!NodeProperties::IsValueEdge(edge)) continue; 237
138 return NoChange(); 238 // Join control paths.
239 control = graph()->NewNode(common()->Merge(2), control0, control1);
240 effect =
241 graph()->NewNode(common()->EffectPhi(2), effect0, effect1, control);
242 Node* value =
243 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
244 value0, value1, control);
245 ReplaceWithValue(node, value, effect, control);
246 return Replace(value);
139 } 247 }
140 // Check if the arguments can be handled in the fast case (i.e. we don't
141 // have aliased sloppy arguments), and compute the {start_index} for
142 // rest parameters.
143 CreateArgumentsType const type = CreateArgumentsTypeOf(arg_array->op());
144 Node* frame_state = NodeProperties::GetFrameStateInput(arg_array);
145 FrameStateInfo state_info = OpParameter<FrameStateInfo>(frame_state);
146 int start_index = 0;
147 // Determine the formal parameter count;
148 Handle<SharedFunctionInfo> shared;
149 if (!state_info.shared_info().ToHandle(&shared)) return NoChange();
150 int formal_parameter_count = shared->internal_formal_parameter_count();
151 if (type == CreateArgumentsType::kMappedArguments) {
152 // Mapped arguments (sloppy mode) that are aliased can only be handled
153 // here if there's no side-effect between the {node} and the {arg_array}.
154 // TODO(turbofan): Further relax this constraint.
155 if (formal_parameter_count != 0) {
156 Node* effect = NodeProperties::GetEffectInput(node);
157 while (effect != arg_array) {
158 if (effect->op()->EffectInputCount() != 1 ||
159 !(effect->op()->properties() & Operator::kNoWrite)) {
160 return NoChange();
161 }
162 effect = NodeProperties::GetEffectInput(effect);
163 }
164 }
165 } else if (type == CreateArgumentsType::kRestParameter) {
166 start_index = formal_parameter_count;
167 }
168 // Check if are applying to inlined arguments or to the arguments of
169 // the outermost function.
170 Node* outer_state = frame_state->InputAt(kFrameStateOuterStateInput);
171 if (outer_state->opcode() != IrOpcode::kFrameState) {
172 // Reduce {node} to a JSCallForwardVarargs operation, which just
173 // re-pushes the incoming arguments and calls the {target}.
174 node->RemoveInput(0); // Function.prototype.apply
175 node->RemoveInput(2); // arguments
176 NodeProperties::ChangeOp(node, javascript()->CallForwardVarargs(
177 2, start_index, p.tail_call_mode()));
178 return Changed(node);
179 }
180 // Get to the actual frame state from which to extract the arguments;
181 // we can only optimize this in case the {node} was already inlined into
182 // some other function (and same for the {arg_array}).
183 FrameStateInfo outer_info = OpParameter<FrameStateInfo>(outer_state);
184 if (outer_info.type() == FrameStateType::kArgumentsAdaptor) {
185 // Need to take the parameters from the arguments adaptor.
186 frame_state = outer_state;
187 }
188 // Remove the argArray input from the {node}.
189 node->RemoveInput(static_cast<int>(--arity));
190 // Add the actual parameters to the {node}, skipping the receiver,
191 // starting from {start_index}.
192 Node* const parameters = frame_state->InputAt(kFrameStateParametersInput);
193 for (int i = start_index + 1; i < parameters->InputCount(); ++i) {
194 node->InsertInput(graph()->zone(), static_cast<int>(arity),
195 parameters->InputAt(i));
196 ++arity;
197 }
198 // Drop the {target} from the {node}.
199 node->RemoveInput(0);
200 --arity;
201 } else {
202 return NoChange();
203 } 248 }
204 // Change {node} to the new {JSCall} operator. 249 // Change {node} to the new {JSCall} operator.
205 NodeProperties::ChangeOp( 250 NodeProperties::ChangeOp(
206 node, 251 node,
207 javascript()->Call(arity, p.frequency(), VectorSlotPair(), convert_mode, 252 javascript()->Call(arity, p.frequency(), VectorSlotPair(), convert_mode,
208 p.tail_call_mode())); 253 p.tail_call_mode()));
209 // Change context of {node} to the Function.prototype.apply context,
210 // to ensure any exception is thrown in the correct context.
211 NodeProperties::ReplaceContextInput(
212 node, jsgraph()->HeapConstant(handle(apply->context(), isolate())));
213 // Try to further reduce the JSCall {node}. 254 // Try to further reduce the JSCall {node}.
214 Reduction const reduction = ReduceJSCall(node); 255 Reduction const reduction = ReduceJSCall(node);
215 return reduction.Changed() ? reduction : Changed(node); 256 return reduction.Changed() ? reduction : Changed(node);
216 } 257 }
217 258
218 259
219 // ES6 section 19.2.3.3 Function.prototype.call (thisArg, ...args) 260 // ES6 section 19.2.3.3 Function.prototype.call (thisArg, ...args)
220 Reduction JSCallReducer::ReduceFunctionPrototypeCall(Node* node) { 261 Reduction JSCallReducer::ReduceFunctionPrototypeCall(Node* node) {
221 DCHECK_EQ(IrOpcode::kJSCall, node->opcode()); 262 DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
222 CallParameters const& p = CallParametersOf(node->op()); 263 CallParameters const& p = CallParametersOf(node->op());
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after
367 // JSHasInPrototypeChain operator immediately aborts and yields false. 408 // JSHasInPrototypeChain operator immediately aborts and yields false.
368 NodeProperties::ReplaceValueInput(node, value, 0); 409 NodeProperties::ReplaceValueInput(node, value, 0);
369 NodeProperties::ReplaceValueInput(node, receiver, 1); 410 NodeProperties::ReplaceValueInput(node, receiver, 1);
370 for (int i = node->op()->ValueInputCount(); i-- > 2;) { 411 for (int i = node->op()->ValueInputCount(); i-- > 2;) {
371 node->RemoveInput(i); 412 node->RemoveInput(i);
372 } 413 }
373 NodeProperties::ChangeOp(node, javascript()->HasInPrototypeChain()); 414 NodeProperties::ChangeOp(node, javascript()->HasInPrototypeChain());
374 return Changed(node); 415 return Changed(node);
375 } 416 }
376 417
418 // ES6 section 26.1.1 Reflect.apply ( target, thisArgument, argumentsList )
419 Reduction JSCallReducer::ReduceReflectApply(Node* node) {
420 DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
421 CallParameters const& p = CallParametersOf(node->op());
422 int arity = static_cast<int>(p.arity() - 2);
423 DCHECK_LE(0, arity);
424 // Massage value inputs appropriately.
425 node->RemoveInput(0);
426 node->RemoveInput(0);
427 while (arity < 3) {
428 node->InsertInput(graph()->zone(), arity++, jsgraph()->UndefinedConstant());
429 }
430 while (arity-- > 3) {
431 node->RemoveInput(arity);
432 }
433 NodeProperties::ChangeOp(node,
434 javascript()->CallWithArrayLike(p.frequency()));
435 Reduction const reduction = ReduceJSCallWithArrayLike(node);
436 return reduction.Changed() ? reduction : Changed(node);
437 }
438
377 // ES6 section 26.1.7 Reflect.getPrototypeOf ( target ) 439 // ES6 section 26.1.7 Reflect.getPrototypeOf ( target )
378 Reduction JSCallReducer::ReduceReflectGetPrototypeOf(Node* node) { 440 Reduction JSCallReducer::ReduceReflectGetPrototypeOf(Node* node) {
379 DCHECK_EQ(IrOpcode::kJSCall, node->opcode()); 441 DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
380 Node* target = (node->op()->ValueInputCount() >= 3) 442 Node* target = (node->op()->ValueInputCount() >= 3)
381 ? NodeProperties::GetValueInput(node, 2) 443 ? NodeProperties::GetValueInput(node, 2)
382 : jsgraph()->UndefinedConstant(); 444 : jsgraph()->UndefinedConstant();
383 return ReduceObjectGetPrototype(node, target); 445 return ReduceObjectGetPrototype(node, target);
384 } 446 }
385 447
386 Reduction JSCallReducer::ReduceArrayForEach(Handle<JSFunction> function, 448 Reduction JSCallReducer::ReduceArrayForEach(Handle<JSFunction> function,
(...skipping 204 matching lines...) Expand 10 before | Expand all | Expand 10 after
591 jsgraph()->HeapConstant(stub.GetCode())); 653 jsgraph()->HeapConstant(stub.GetCode()));
592 node->InsertInput(graph()->zone(), 2, jsgraph()->Constant(data)); 654 node->InsertInput(graph()->zone(), 2, jsgraph()->Constant(data));
593 node->InsertInput(graph()->zone(), 3, holder); 655 node->InsertInput(graph()->zone(), 3, holder);
594 node->InsertInput(graph()->zone(), 4, 656 node->InsertInput(graph()->zone(), 4,
595 jsgraph()->ExternalConstant(function_reference)); 657 jsgraph()->ExternalConstant(function_reference));
596 node->ReplaceInput(5, receiver); 658 node->ReplaceInput(5, receiver);
597 NodeProperties::ChangeOp(node, common()->Call(call_descriptor)); 659 NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
598 return Changed(node); 660 return Changed(node);
599 } 661 }
600 662
601 Reduction JSCallReducer::ReduceSpreadCall(Node* node, int arity) { 663 Reduction JSCallReducer::ReduceCallOrConstructWithArrayLikeOrSpread(
602 DCHECK(node->opcode() == IrOpcode::kJSCallWithSpread || 664 Node* node, int arity, CallFrequency const& frequency) {
665 DCHECK(node->opcode() == IrOpcode::kJSCallWithArrayLike ||
666 node->opcode() == IrOpcode::kJSCallWithSpread ||
603 node->opcode() == IrOpcode::kJSConstructWithSpread); 667 node->opcode() == IrOpcode::kJSConstructWithSpread);
604 668
605 // Do check to make sure we can actually avoid iteration. 669 // In case of a call/construct with spread, we need to
606 if (!isolate()->initial_array_iterator_prototype_map()->is_stable()) { 670 // ensure that it's safe to avoid the actual iteration.
671 if ((node->opcode() == IrOpcode::kJSCallWithSpread ||
672 node->opcode() == IrOpcode::kJSConstructWithSpread) &&
673 !isolate()->initial_array_iterator_prototype_map()->is_stable()) {
607 return NoChange(); 674 return NoChange();
608 } 675 }
609 676
610 Node* spread = NodeProperties::GetValueInput(node, arity); 677 // Check if {arguments_list} is an arguments object, and {node} is the only
611 678 // value user of {arguments_list} (except for value uses in frame states).
612 // Check if spread is an arguments object, and {node} is the only value user 679 Node* arguments_list = NodeProperties::GetValueInput(node, arity);
613 // of spread (except for value uses in frame states). 680 if (arguments_list->opcode() != IrOpcode::kJSCreateArguments)
614 if (spread->opcode() != IrOpcode::kJSCreateArguments) return NoChange(); 681 return NoChange();
615 for (Edge edge : spread->use_edges()) { 682 for (Edge edge : arguments_list->use_edges()) {
616 Node* const user = edge.from(); 683 Node* const user = edge.from();
617 if (user == node) continue; 684 if (user == node) continue;
618 // Ignore uses as frame state's locals or parameters. 685 // Ignore uses as frame state's locals or parameters.
619 if (user->opcode() == IrOpcode::kStateValues) continue; 686 if (user->opcode() == IrOpcode::kStateValues) continue;
620 // Ignore uses as frame state's accumulator. 687 // Ignore uses as frame state's accumulator.
621 if (user->opcode() == IrOpcode::kFrameState && user->InputAt(2) == spread) { 688 if (user->opcode() == IrOpcode::kFrameState &&
689 user->InputAt(2) == arguments_list) {
622 continue; 690 continue;
623 } 691 }
624 if (!NodeProperties::IsValueEdge(edge)) continue; 692 if (!NodeProperties::IsValueEdge(edge)) continue;
625 return NoChange(); 693 return NoChange();
626 } 694 }
627 695
628 // Get to the actual frame state from which to extract the arguments; 696 // Get to the actual frame state from which to extract the arguments;
629 // we can only optimize this in case the {node} was already inlined into 697 // we can only optimize this in case the {node} was already inlined into
630 // some other function (and same for the {spread}). 698 // some other function (and same for the {arguments_list}).
631 CreateArgumentsType const type = CreateArgumentsTypeOf(spread->op()); 699 CreateArgumentsType const type = CreateArgumentsTypeOf(arguments_list->op());
632 Node* frame_state = NodeProperties::GetFrameStateInput(spread); 700 Node* frame_state = NodeProperties::GetFrameStateInput(arguments_list);
633 FrameStateInfo state_info = OpParameter<FrameStateInfo>(frame_state); 701 FrameStateInfo state_info = OpParameter<FrameStateInfo>(frame_state);
634 int start_index = 0; 702 int start_index = 0;
635 // Determine the formal parameter count; 703 // Determine the formal parameter count;
636 Handle<SharedFunctionInfo> shared; 704 Handle<SharedFunctionInfo> shared;
637 if (!state_info.shared_info().ToHandle(&shared)) return NoChange(); 705 if (!state_info.shared_info().ToHandle(&shared)) return NoChange();
638 int formal_parameter_count = shared->internal_formal_parameter_count(); 706 int formal_parameter_count = shared->internal_formal_parameter_count();
639 if (type == CreateArgumentsType::kMappedArguments) { 707 if (type == CreateArgumentsType::kMappedArguments) {
640 // Mapped arguments (sloppy mode) that are aliased can only be handled 708 // Mapped arguments (sloppy mode) that are aliased can only be handled
641 // here if there's no side-effect between the {node} and the {arg_array}. 709 // here if there's no side-effect between the {node} and the {arg_array}.
642 // TODO(turbofan): Further relax this constraint. 710 // TODO(turbofan): Further relax this constraint.
643 if (formal_parameter_count != 0) { 711 if (formal_parameter_count != 0) {
644 Node* effect = NodeProperties::GetEffectInput(node); 712 Node* effect = NodeProperties::GetEffectInput(node);
645 while (effect != spread) { 713 while (effect != arguments_list) {
646 if (effect->op()->EffectInputCount() != 1 || 714 if (effect->op()->EffectInputCount() != 1 ||
647 !(effect->op()->properties() & Operator::kNoWrite)) { 715 !(effect->op()->properties() & Operator::kNoWrite)) {
648 return NoChange(); 716 return NoChange();
649 } 717 }
650 effect = NodeProperties::GetEffectInput(effect); 718 effect = NodeProperties::GetEffectInput(effect);
651 } 719 }
652 } 720 }
653 } else if (type == CreateArgumentsType::kRestParameter) { 721 } else if (type == CreateArgumentsType::kRestParameter) {
654 start_index = formal_parameter_count; 722 start_index = formal_parameter_count;
655 723
656 // Only check the array iterator protector when we have a rest object. 724 // For spread calls/constructs with rest parameters we need to ensure that
657 if (!isolate()->IsArrayIteratorLookupChainIntact()) return NoChange(); 725 // the array iterator protector is intact, which guards that the rest
726 // parameter iteration is not observable.
727 if (node->opcode() == IrOpcode::kJSCallWithSpread ||
728 node->opcode() == IrOpcode::kJSConstructWithSpread) {
729 if (!isolate()->IsArrayIteratorLookupChainIntact()) return NoChange();
730 dependencies()->AssumePropertyCell(factory()->array_iterator_protector());
731 }
658 } 732 }
659 733
660 // Install appropriate code dependencies. 734 // For call/construct with spread, we need to also install a code
661 dependencies()->AssumeMapStable( 735 // dependency on the initial %ArrayIteratorPrototype% map here to
662 isolate()->initial_array_iterator_prototype_map()); 736 // ensure that no one messes with the next method.
663 if (type == CreateArgumentsType::kRestParameter) { 737 if (node->opcode() == IrOpcode::kJSCallWithSpread ||
664 dependencies()->AssumePropertyCell(factory()->array_iterator_protector()); 738 node->opcode() == IrOpcode::kJSConstructWithSpread) {
739 dependencies()->AssumeMapStable(
740 isolate()->initial_array_iterator_prototype_map());
665 } 741 }
666 // Remove the spread input from the {node}. 742
743 // Remove the {arguments_list} input from the {node}.
667 node->RemoveInput(arity--); 744 node->RemoveInput(arity--);
668 // Check if are spreading to inlined arguments or to the arguments of 745 // Check if are spreading to inlined arguments or to the arguments of
669 // the outermost function. 746 // the outermost function.
670 Node* outer_state = frame_state->InputAt(kFrameStateOuterStateInput); 747 Node* outer_state = frame_state->InputAt(kFrameStateOuterStateInput);
671 if (outer_state->opcode() != IrOpcode::kFrameState) { 748 if (outer_state->opcode() != IrOpcode::kFrameState) {
672 Operator const* op = 749 Operator const* op =
673 (node->opcode() == IrOpcode::kJSCallWithSpread) 750 (node->opcode() == IrOpcode::kJSCallWithArrayLike ||
751 node->opcode() == IrOpcode::kJSCallWithSpread)
674 ? javascript()->CallForwardVarargs(arity + 1, start_index, 752 ? javascript()->CallForwardVarargs(arity + 1, start_index,
675 TailCallMode::kDisallow) 753 TailCallMode::kDisallow)
676 : javascript()->ConstructForwardVarargs(arity + 2, start_index); 754 : javascript()->ConstructForwardVarargs(arity + 2, start_index);
677 NodeProperties::ChangeOp(node, op); 755 NodeProperties::ChangeOp(node, op);
678 return Changed(node); 756 return Changed(node);
679 } 757 }
680 // Get to the actual frame state from which to extract the arguments; 758 // Get to the actual frame state from which to extract the arguments;
681 // we can only optimize this in case the {node} was already inlined into 759 // we can only optimize this in case the {node} was already inlined into
682 // some other function (and same for the {arg_array}). 760 // some other function (and same for the {arg_array}).
683 FrameStateInfo outer_info = OpParameter<FrameStateInfo>(outer_state); 761 FrameStateInfo outer_info = OpParameter<FrameStateInfo>(outer_state);
684 if (outer_info.type() == FrameStateType::kArgumentsAdaptor) { 762 if (outer_info.type() == FrameStateType::kArgumentsAdaptor) {
685 // Need to take the parameters from the arguments adaptor. 763 // Need to take the parameters from the arguments adaptor.
686 frame_state = outer_state; 764 frame_state = outer_state;
687 } 765 }
688 // Add the actual parameters to the {node}, skipping the receiver. 766 // Add the actual parameters to the {node}, skipping the receiver.
689 Node* const parameters = frame_state->InputAt(kFrameStateParametersInput); 767 Node* const parameters = frame_state->InputAt(kFrameStateParametersInput);
690 for (int i = start_index + 1; i < parameters->InputCount(); ++i) { 768 for (int i = start_index + 1; i < parameters->InputCount(); ++i) {
691 node->InsertInput(graph()->zone(), static_cast<int>(++arity), 769 node->InsertInput(graph()->zone(), static_cast<int>(++arity),
692 parameters->InputAt(i)); 770 parameters->InputAt(i));
693 } 771 }
694 772
695 // TODO(turbofan): Collect call counts on spread call/construct and thread it 773 if (node->opcode() == IrOpcode::kJSCallWithArrayLike ||
696 // through here. 774 node->opcode() == IrOpcode::kJSCallWithSpread) {
697 if (node->opcode() == IrOpcode::kJSCallWithSpread) { 775 NodeProperties::ChangeOp(node, javascript()->Call(arity + 1, frequency));
698 NodeProperties::ChangeOp(node, javascript()->Call(arity + 1)); 776 Reduction const reduction = ReduceJSCall(node);
699 Reduction const r = ReduceJSCall(node); 777 return reduction.Changed() ? reduction : Changed(node);
700 return r.Changed() ? r : Changed(node);
701 } else { 778 } else {
702 NodeProperties::ChangeOp(node, javascript()->Construct(arity + 2)); 779 NodeProperties::ChangeOp(node,
703 Reduction const r = ReduceJSConstruct(node); 780 javascript()->Construct(arity + 2, frequency));
704 return r.Changed() ? r : Changed(node); 781 Reduction const reduction = ReduceJSConstruct(node);
782 return reduction.Changed() ? reduction : Changed(node);
705 } 783 }
706 } 784 }
707 785
708 namespace { 786 namespace {
709 787
710 bool ShouldUseCallICFeedback(Node* node) { 788 bool ShouldUseCallICFeedback(Node* node) {
711 HeapObjectMatcher m(node); 789 HeapObjectMatcher m(node);
712 if (m.HasValue() || m.IsJSCreateClosure()) { 790 if (m.HasValue() || m.IsJSCreateClosure()) {
713 // Don't use CallIC feedback when we know the function 791 // Don't use CallIC feedback when we know the function
714 // being called, i.e. either know the closure itself or 792 // being called, i.e. either know the closure itself or
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
768 case Builtins::kFunctionPrototypeHasInstance: 846 case Builtins::kFunctionPrototypeHasInstance:
769 return ReduceFunctionPrototypeHasInstance(node); 847 return ReduceFunctionPrototypeHasInstance(node);
770 case Builtins::kNumberConstructor: 848 case Builtins::kNumberConstructor:
771 return ReduceNumberConstructor(node); 849 return ReduceNumberConstructor(node);
772 case Builtins::kObjectGetPrototypeOf: 850 case Builtins::kObjectGetPrototypeOf:
773 return ReduceObjectGetPrototypeOf(node); 851 return ReduceObjectGetPrototypeOf(node);
774 case Builtins::kObjectPrototypeGetProto: 852 case Builtins::kObjectPrototypeGetProto:
775 return ReduceObjectPrototypeGetProto(node); 853 return ReduceObjectPrototypeGetProto(node);
776 case Builtins::kObjectPrototypeIsPrototypeOf: 854 case Builtins::kObjectPrototypeIsPrototypeOf:
777 return ReduceObjectPrototypeIsPrototypeOf(node); 855 return ReduceObjectPrototypeIsPrototypeOf(node);
856 case Builtins::kReflectApply:
857 return ReduceReflectApply(node);
778 case Builtins::kReflectGetPrototypeOf: 858 case Builtins::kReflectGetPrototypeOf:
779 return ReduceReflectGetPrototypeOf(node); 859 return ReduceReflectGetPrototypeOf(node);
780 case Builtins::kArrayForEach: 860 case Builtins::kArrayForEach:
781 return ReduceArrayForEach(function, node); 861 return ReduceArrayForEach(function, node);
782 case Builtins::kReturnReceiver: 862 case Builtins::kReturnReceiver:
783 return ReduceReturnReceiver(node); 863 return ReduceReturnReceiver(node);
784 default: 864 default:
785 break; 865 break;
786 } 866 }
787 867
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after
898 NodeProperties::ReplaceEffectInput(node, effect); 978 NodeProperties::ReplaceEffectInput(node, effect);
899 979
900 // Try to further reduce the JSCall {node}. 980 // Try to further reduce the JSCall {node}.
901 Reduction const reduction = ReduceJSCall(node); 981 Reduction const reduction = ReduceJSCall(node);
902 return reduction.Changed() ? reduction : Changed(node); 982 return reduction.Changed() ? reduction : Changed(node);
903 } 983 }
904 } 984 }
905 return NoChange(); 985 return NoChange();
906 } 986 }
907 987
988 Reduction JSCallReducer::ReduceJSCallWithArrayLike(Node* node) {
989 DCHECK_EQ(IrOpcode::kJSCallWithArrayLike, node->opcode());
990 CallFrequency frequency = CallFrequencyOf(node->op());
991 return ReduceCallOrConstructWithArrayLikeOrSpread(node, 2, frequency);
992 }
993
908 Reduction JSCallReducer::ReduceJSCallWithSpread(Node* node) { 994 Reduction JSCallReducer::ReduceJSCallWithSpread(Node* node) {
909 DCHECK_EQ(IrOpcode::kJSCallWithSpread, node->opcode()); 995 DCHECK_EQ(IrOpcode::kJSCallWithSpread, node->opcode());
910 SpreadWithArityParameter const& p = SpreadWithArityParameterOf(node->op()); 996 SpreadWithArityParameter const& p = SpreadWithArityParameterOf(node->op());
911 DCHECK_LE(3u, p.arity()); 997 DCHECK_LE(3u, p.arity());
912 int arity = static_cast<int>(p.arity() - 1); 998 int arity = static_cast<int>(p.arity() - 1);
913 999
914 return ReduceSpreadCall(node, arity); 1000 // TODO(turbofan): Collect call counts on spread call/construct and thread it
1001 // through here.
1002 CallFrequency frequency;
1003 return ReduceCallOrConstructWithArrayLikeOrSpread(node, arity, frequency);
915 } 1004 }
916 1005
917 Reduction JSCallReducer::ReduceJSConstruct(Node* node) { 1006 Reduction JSCallReducer::ReduceJSConstruct(Node* node) {
918 DCHECK_EQ(IrOpcode::kJSConstruct, node->opcode()); 1007 DCHECK_EQ(IrOpcode::kJSConstruct, node->opcode());
919 ConstructParameters const& p = ConstructParametersOf(node->op()); 1008 ConstructParameters const& p = ConstructParametersOf(node->op());
920 DCHECK_LE(2u, p.arity()); 1009 DCHECK_LE(2u, p.arity());
921 int const arity = static_cast<int>(p.arity() - 2); 1010 int const arity = static_cast<int>(p.arity() - 2);
922 Node* target = NodeProperties::GetValueInput(node, 0); 1011 Node* target = NodeProperties::GetValueInput(node, 0);
923 Node* new_target = NodeProperties::GetValueInput(node, arity + 1); 1012 Node* new_target = NodeProperties::GetValueInput(node, arity + 1);
924 Node* effect = NodeProperties::GetEffectInput(node); 1013 Node* effect = NodeProperties::GetEffectInput(node);
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after
1028 1117
1029 return NoChange(); 1118 return NoChange();
1030 } 1119 }
1031 1120
1032 Reduction JSCallReducer::ReduceJSConstructWithSpread(Node* node) { 1121 Reduction JSCallReducer::ReduceJSConstructWithSpread(Node* node) {
1033 DCHECK_EQ(IrOpcode::kJSConstructWithSpread, node->opcode()); 1122 DCHECK_EQ(IrOpcode::kJSConstructWithSpread, node->opcode());
1034 SpreadWithArityParameter const& p = SpreadWithArityParameterOf(node->op()); 1123 SpreadWithArityParameter const& p = SpreadWithArityParameterOf(node->op());
1035 DCHECK_LE(3u, p.arity()); 1124 DCHECK_LE(3u, p.arity());
1036 int arity = static_cast<int>(p.arity() - 2); 1125 int arity = static_cast<int>(p.arity() - 2);
1037 1126
1038 return ReduceSpreadCall(node, arity); 1127 // TODO(turbofan): Collect call counts on spread call/construct and thread it
1128 // through here.
1129 CallFrequency frequency;
1130 return ReduceCallOrConstructWithArrayLikeOrSpread(node, arity, frequency);
1039 } 1131 }
1040 1132
1041 Reduction JSCallReducer::ReduceReturnReceiver(Node* node) { 1133 Reduction JSCallReducer::ReduceReturnReceiver(Node* node) {
1042 DCHECK_EQ(IrOpcode::kJSCall, node->opcode()); 1134 DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
1043 Node* receiver = NodeProperties::GetValueInput(node, 1); 1135 Node* receiver = NodeProperties::GetValueInput(node, 1);
1044 ReplaceWithValue(node, receiver); 1136 ReplaceWithValue(node, receiver);
1045 return Replace(receiver); 1137 return Replace(receiver);
1046 } 1138 }
1047 1139
1048 Graph* JSCallReducer::graph() const { return jsgraph()->graph(); } 1140 Graph* JSCallReducer::graph() const { return jsgraph()->graph(); }
(...skipping 15 matching lines...) Expand all
1064 return jsgraph()->javascript(); 1156 return jsgraph()->javascript();
1065 } 1157 }
1066 1158
1067 SimplifiedOperatorBuilder* JSCallReducer::simplified() const { 1159 SimplifiedOperatorBuilder* JSCallReducer::simplified() const {
1068 return jsgraph()->simplified(); 1160 return jsgraph()->simplified();
1069 } 1161 }
1070 1162
1071 } // namespace compiler 1163 } // namespace compiler
1072 } // namespace internal 1164 } // namespace internal
1073 } // namespace v8 1165 } // namespace v8
OLDNEW
« no previous file with comments | « src/compiler/js-call-reducer.h ('k') | src/compiler/js-generic-lowering.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698