• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
3 // found in the LICENSE file.
4 
5 #include "src/compiler/js-call-reducer.h"
6 
7 #include "src/api-inl.h"
8 #include "src/builtins/builtins-promise-gen.h"
9 #include "src/builtins/builtins-utils.h"
10 #include "src/code-factory.h"
11 #include "src/code-stubs.h"
12 #include "src/compiler/access-builder.h"
13 #include "src/compiler/access-info.h"
14 #include "src/compiler/allocation-builder.h"
15 #include "src/compiler/compilation-dependencies.h"
16 #include "src/compiler/js-graph.h"
17 #include "src/compiler/linkage.h"
18 #include "src/compiler/node-matchers.h"
19 #include "src/compiler/property-access-builder.h"
20 #include "src/compiler/simplified-operator.h"
21 #include "src/compiler/type-cache.h"
22 #include "src/feedback-vector-inl.h"
23 #include "src/ic/call-optimization.h"
24 #include "src/objects-inl.h"
25 #include "src/objects/arguments-inl.h"
26 #include "src/objects/js-array-buffer-inl.h"
27 #include "src/objects/js-array-inl.h"
28 #include "src/vector-slot-pair.h"
29 
30 namespace v8 {
31 namespace internal {
32 namespace compiler {
33 
ReduceMathUnary(Node * node,const Operator * op)34 Reduction JSCallReducer::ReduceMathUnary(Node* node, const Operator* op) {
35   CallParameters const& p = CallParametersOf(node->op());
36   if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
37     return NoChange();
38   }
39   if (node->op()->ValueInputCount() < 3) {
40     Node* value = jsgraph()->NaNConstant();
41     ReplaceWithValue(node, value);
42     return Replace(value);
43   }
44 
45   Node* effect = NodeProperties::GetEffectInput(node);
46   Node* control = NodeProperties::GetControlInput(node);
47   Node* input = NodeProperties::GetValueInput(node, 2);
48 
49   input = effect =
50       graph()->NewNode(simplified()->SpeculativeToNumber(
51                            NumberOperationHint::kNumberOrOddball, p.feedback()),
52                        input, effect, control);
53   Node* value = graph()->NewNode(op, input);
54   ReplaceWithValue(node, value, effect);
55   return Replace(value);
56 }
57 
ReduceMathBinary(Node * node,const Operator * op)58 Reduction JSCallReducer::ReduceMathBinary(Node* node, const Operator* op) {
59   CallParameters const& p = CallParametersOf(node->op());
60   if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
61     return NoChange();
62   }
63   if (node->op()->ValueInputCount() < 3) {
64     Node* value = jsgraph()->NaNConstant();
65     ReplaceWithValue(node, value);
66     return Replace(value);
67   }
68   Node* effect = NodeProperties::GetEffectInput(node);
69   Node* control = NodeProperties::GetControlInput(node);
70 
71   Node* left = NodeProperties::GetValueInput(node, 2);
72   Node* right = node->op()->ValueInputCount() > 3
73                     ? NodeProperties::GetValueInput(node, 3)
74                     : jsgraph()->NaNConstant();
75   left = effect =
76       graph()->NewNode(simplified()->SpeculativeToNumber(
77                            NumberOperationHint::kNumberOrOddball, p.feedback()),
78                        left, effect, control);
79   right = effect =
80       graph()->NewNode(simplified()->SpeculativeToNumber(
81                            NumberOperationHint::kNumberOrOddball, p.feedback()),
82                        right, effect, control);
83   Node* value = graph()->NewNode(op, left, right);
84   ReplaceWithValue(node, value, effect);
85   return Replace(value);
86 }
87 
88 // ES6 section 20.2.2.19 Math.imul ( x, y )
ReduceMathImul(Node * node)89 Reduction JSCallReducer::ReduceMathImul(Node* node) {
90   CallParameters const& p = CallParametersOf(node->op());
91   if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
92     return NoChange();
93   }
94   if (node->op()->ValueInputCount() < 3) {
95     Node* value = jsgraph()->ZeroConstant();
96     ReplaceWithValue(node, value);
97     return Replace(value);
98   }
99   Node* left = NodeProperties::GetValueInput(node, 2);
100   Node* right = node->op()->ValueInputCount() > 3
101                     ? NodeProperties::GetValueInput(node, 3)
102                     : jsgraph()->ZeroConstant();
103   Node* effect = NodeProperties::GetEffectInput(node);
104   Node* control = NodeProperties::GetControlInput(node);
105 
106   left = effect =
107       graph()->NewNode(simplified()->SpeculativeToNumber(
108                            NumberOperationHint::kNumberOrOddball, p.feedback()),
109                        left, effect, control);
110   right = effect =
111       graph()->NewNode(simplified()->SpeculativeToNumber(
112                            NumberOperationHint::kNumberOrOddball, p.feedback()),
113                        right, effect, control);
114   left = graph()->NewNode(simplified()->NumberToUint32(), left);
115   right = graph()->NewNode(simplified()->NumberToUint32(), right);
116   Node* value = graph()->NewNode(simplified()->NumberImul(), left, right);
117   ReplaceWithValue(node, value, effect);
118   return Replace(value);
119 }
120 
121 // ES6 section 20.2.2.11 Math.clz32 ( x )
ReduceMathClz32(Node * node)122 Reduction JSCallReducer::ReduceMathClz32(Node* node) {
123   CallParameters const& p = CallParametersOf(node->op());
124   if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
125     return NoChange();
126   }
127   if (node->op()->ValueInputCount() < 3) {
128     Node* value = jsgraph()->Constant(32);
129     ReplaceWithValue(node, value);
130     return Replace(value);
131   }
132   Node* input = NodeProperties::GetValueInput(node, 2);
133   Node* effect = NodeProperties::GetEffectInput(node);
134   Node* control = NodeProperties::GetControlInput(node);
135 
136   input = effect =
137       graph()->NewNode(simplified()->SpeculativeToNumber(
138                            NumberOperationHint::kNumberOrOddball, p.feedback()),
139                        input, effect, control);
140   input = graph()->NewNode(simplified()->NumberToUint32(), input);
141   Node* value = graph()->NewNode(simplified()->NumberClz32(), input);
142   ReplaceWithValue(node, value, effect);
143   return Replace(value);
144 }
145 
146 // ES6 section 20.2.2.24 Math.max ( value1, value2, ...values )
147 // ES6 section 20.2.2.25 Math.min ( value1, value2, ...values )
ReduceMathMinMax(Node * node,const Operator * op,Node * empty_value)148 Reduction JSCallReducer::ReduceMathMinMax(Node* node, const Operator* op,
149                                           Node* empty_value) {
150   CallParameters const& p = CallParametersOf(node->op());
151   if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
152     return NoChange();
153   }
154   if (node->op()->ValueInputCount() <= 2) {
155     ReplaceWithValue(node, empty_value);
156     return Replace(empty_value);
157   }
158   Node* effect = NodeProperties::GetEffectInput(node);
159   Node* control = NodeProperties::GetControlInput(node);
160 
161   Node* value = effect =
162       graph()->NewNode(simplified()->SpeculativeToNumber(
163                            NumberOperationHint::kNumberOrOddball, p.feedback()),
164                        NodeProperties::GetValueInput(node, 2), effect, control);
165   for (int i = 3; i < node->op()->ValueInputCount(); i++) {
166     Node* input = effect = graph()->NewNode(
167         simplified()->SpeculativeToNumber(NumberOperationHint::kNumberOrOddball,
168                                           p.feedback()),
169         NodeProperties::GetValueInput(node, i), effect, control);
170     value = graph()->NewNode(op, value, input);
171   }
172 
173   ReplaceWithValue(node, value, effect);
174   return Replace(value);
175 }
176 
Reduce(Node * node)177 Reduction JSCallReducer::Reduce(Node* node) {
178   switch (node->opcode()) {
179     case IrOpcode::kJSConstruct:
180       return ReduceJSConstruct(node);
181     case IrOpcode::kJSConstructWithArrayLike:
182       return ReduceJSConstructWithArrayLike(node);
183     case IrOpcode::kJSConstructWithSpread:
184       return ReduceJSConstructWithSpread(node);
185     case IrOpcode::kJSCall:
186       return ReduceJSCall(node);
187     case IrOpcode::kJSCallWithArrayLike:
188       return ReduceJSCallWithArrayLike(node);
189     case IrOpcode::kJSCallWithSpread:
190       return ReduceJSCallWithSpread(node);
191     default:
192       break;
193   }
194   return NoChange();
195 }
196 
Finalize()197 void JSCallReducer::Finalize() {
198   // TODO(turbofan): This is not the best solution; ideally we would be able
199   // to teach the GraphReducer about arbitrary dependencies between different
200   // nodes, even if they don't show up in the use list of the other node.
201   std::set<Node*> const waitlist = std::move(waitlist_);
202   for (Node* node : waitlist) {
203     if (!node->IsDead()) {
204       Reduction const reduction = Reduce(node);
205       if (reduction.Changed()) {
206         Node* replacement = reduction.replacement();
207         if (replacement != node) {
208           Replace(node, replacement);
209         }
210       }
211     }
212   }
213 }
214 
215 // ES6 section 22.1.1 The Array Constructor
ReduceArrayConstructor(Node * node)216 Reduction JSCallReducer::ReduceArrayConstructor(Node* node) {
217   DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
218   Node* target = NodeProperties::GetValueInput(node, 0);
219   CallParameters const& p = CallParametersOf(node->op());
220 
221   // Turn the {node} into a {JSCreateArray} call.
222   DCHECK_LE(2u, p.arity());
223   size_t const arity = p.arity() - 2;
224   NodeProperties::ReplaceValueInput(node, target, 0);
225   NodeProperties::ReplaceValueInput(node, target, 1);
226   NodeProperties::ChangeOp(
227       node, javascript()->CreateArray(arity, MaybeHandle<AllocationSite>()));
228   return Changed(node);
229 }
230 
231 // ES6 section 19.3.1.1 Boolean ( value )
ReduceBooleanConstructor(Node * node)232 Reduction JSCallReducer::ReduceBooleanConstructor(Node* node) {
233   DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
234   CallParameters const& p = CallParametersOf(node->op());
235 
236   // Replace the {node} with a proper {ToBoolean} operator.
237   DCHECK_LE(2u, p.arity());
238   Node* value = (p.arity() == 2) ? jsgraph()->UndefinedConstant()
239                                  : NodeProperties::GetValueInput(node, 2);
240   value = graph()->NewNode(simplified()->ToBoolean(), value);
241   ReplaceWithValue(node, value);
242   return Replace(value);
243 }
244 
245 // ES section #sec-object-constructor
ReduceObjectConstructor(Node * node)246 Reduction JSCallReducer::ReduceObjectConstructor(Node* node) {
247   DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
248   CallParameters const& p = CallParametersOf(node->op());
249   if (p.arity() < 3) return NoChange();
250   Node* value = (p.arity() >= 3) ? NodeProperties::GetValueInput(node, 2)
251                                  : jsgraph()->UndefinedConstant();
252   Node* effect = NodeProperties::GetEffectInput(node);
253 
254   // We can fold away the Object(x) call if |x| is definitely not a primitive.
255   if (NodeProperties::CanBePrimitive(isolate(), value, effect)) {
256     if (!NodeProperties::CanBeNullOrUndefined(isolate(), value, effect)) {
257       // Turn the {node} into a {JSToObject} call if we know that
258       // the {value} cannot be null or undefined.
259       NodeProperties::ReplaceValueInputs(node, value);
260       NodeProperties::ChangeOp(node, javascript()->ToObject());
261       return Changed(node);
262     }
263   } else {
264     ReplaceWithValue(node, value);
265     return Replace(value);
266   }
267   return NoChange();
268 }
269 
270 // ES6 section 19.2.3.1 Function.prototype.apply ( thisArg, argArray )
ReduceFunctionPrototypeApply(Node * node)271 Reduction JSCallReducer::ReduceFunctionPrototypeApply(Node* node) {
272   DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
273   CallParameters const& p = CallParametersOf(node->op());
274   size_t arity = p.arity();
275   DCHECK_LE(2u, arity);
276   ConvertReceiverMode convert_mode = ConvertReceiverMode::kAny;
277   if (arity == 2) {
278     // Neither thisArg nor argArray was provided.
279     convert_mode = ConvertReceiverMode::kNullOrUndefined;
280     node->ReplaceInput(0, node->InputAt(1));
281     node->ReplaceInput(1, jsgraph()->UndefinedConstant());
282   } else if (arity == 3) {
283     // The argArray was not provided, just remove the {target}.
284     node->RemoveInput(0);
285     --arity;
286   } else {
287     Node* target = NodeProperties::GetValueInput(node, 1);
288     Node* this_argument = NodeProperties::GetValueInput(node, 2);
289     Node* arguments_list = NodeProperties::GetValueInput(node, 3);
290     Node* context = NodeProperties::GetContextInput(node);
291     Node* frame_state = NodeProperties::GetFrameStateInput(node);
292     Node* effect = NodeProperties::GetEffectInput(node);
293     Node* control = NodeProperties::GetControlInput(node);
294 
295     // If {arguments_list} cannot be null or undefined, we don't need
296     // to expand this {node} to control-flow.
297     if (!NodeProperties::CanBeNullOrUndefined(isolate(), arguments_list,
298                                               effect)) {
299       // Massage the value inputs appropriately.
300       node->ReplaceInput(0, target);
301       node->ReplaceInput(1, this_argument);
302       node->ReplaceInput(2, arguments_list);
303       while (arity-- > 3) node->RemoveInput(3);
304 
305       // Morph the {node} to a {JSCallWithArrayLike}.
306       NodeProperties::ChangeOp(node,
307                                javascript()->CallWithArrayLike(p.frequency()));
308       Reduction const reduction = ReduceJSCallWithArrayLike(node);
309       return reduction.Changed() ? reduction : Changed(node);
310     } else {
311       // Check whether {arguments_list} is null.
312       Node* check_null =
313           graph()->NewNode(simplified()->ReferenceEqual(), arguments_list,
314                            jsgraph()->NullConstant());
315       control = graph()->NewNode(common()->Branch(BranchHint::kFalse),
316                                  check_null, control);
317       Node* if_null = graph()->NewNode(common()->IfTrue(), control);
318       control = graph()->NewNode(common()->IfFalse(), control);
319 
320       // Check whether {arguments_list} is undefined.
321       Node* check_undefined =
322           graph()->NewNode(simplified()->ReferenceEqual(), arguments_list,
323                            jsgraph()->UndefinedConstant());
324       control = graph()->NewNode(common()->Branch(BranchHint::kFalse),
325                                  check_undefined, control);
326       Node* if_undefined = graph()->NewNode(common()->IfTrue(), control);
327       control = graph()->NewNode(common()->IfFalse(), control);
328 
329       // Lower to {JSCallWithArrayLike} if {arguments_list} is neither null
330       // nor undefined.
331       Node* effect0 = effect;
332       Node* control0 = control;
333       Node* value0 = effect0 = control0 = graph()->NewNode(
334           javascript()->CallWithArrayLike(p.frequency()), target, this_argument,
335           arguments_list, context, frame_state, effect0, control0);
336 
337       // Lower to {JSCall} if {arguments_list} is either null or undefined.
338       Node* effect1 = effect;
339       Node* control1 =
340           graph()->NewNode(common()->Merge(2), if_null, if_undefined);
341       Node* value1 = effect1 = control1 =
342           graph()->NewNode(javascript()->Call(2), target, this_argument,
343                            context, frame_state, effect1, control1);
344 
345       // Rewire potential exception edges.
346       Node* if_exception = nullptr;
347       if (NodeProperties::IsExceptionalCall(node, &if_exception)) {
348         // Create appropriate {IfException} and {IfSuccess} nodes.
349         Node* if_exception0 =
350             graph()->NewNode(common()->IfException(), control0, effect0);
351         control0 = graph()->NewNode(common()->IfSuccess(), control0);
352         Node* if_exception1 =
353             graph()->NewNode(common()->IfException(), control1, effect1);
354         control1 = graph()->NewNode(common()->IfSuccess(), control1);
355 
356         // Join the exception edges.
357         Node* merge =
358             graph()->NewNode(common()->Merge(2), if_exception0, if_exception1);
359         Node* ephi = graph()->NewNode(common()->EffectPhi(2), if_exception0,
360                                       if_exception1, merge);
361         Node* phi =
362             graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
363                              if_exception0, if_exception1, merge);
364         ReplaceWithValue(if_exception, phi, ephi, merge);
365       }
366 
367       // Join control paths.
368       control = graph()->NewNode(common()->Merge(2), control0, control1);
369       effect =
370           graph()->NewNode(common()->EffectPhi(2), effect0, effect1, control);
371       Node* value =
372           graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
373                            value0, value1, control);
374       ReplaceWithValue(node, value, effect, control);
375       return Replace(value);
376     }
377   }
378   // Change {node} to the new {JSCall} operator.
379   NodeProperties::ChangeOp(
380       node,
381       javascript()->Call(arity, p.frequency(), VectorSlotPair(), convert_mode));
382   // Try to further reduce the JSCall {node}.
383   Reduction const reduction = ReduceJSCall(node);
384   return reduction.Changed() ? reduction : Changed(node);
385 }
386 
387 // ES section #sec-function.prototype.bind
ReduceFunctionPrototypeBind(Node * node)388 Reduction JSCallReducer::ReduceFunctionPrototypeBind(Node* node) {
389   DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
390   // Value inputs to the {node} are as follows:
391   //
392   //  - target, which is Function.prototype.bind JSFunction
393   //  - receiver, which is the [[BoundTargetFunction]]
394   //  - bound_this (optional), which is the [[BoundThis]]
395   //  - and all the remaining value inouts are [[BoundArguments]]
396   Node* receiver = NodeProperties::GetValueInput(node, 1);
397   Node* bound_this = (node->op()->ValueInputCount() < 3)
398                          ? jsgraph()->UndefinedConstant()
399                          : NodeProperties::GetValueInput(node, 2);
400   Node* context = NodeProperties::GetContextInput(node);
401   Node* effect = NodeProperties::GetEffectInput(node);
402   Node* control = NodeProperties::GetControlInput(node);
403 
404   // Ensure that the {receiver} is known to be a JSBoundFunction or
405   // a JSFunction with the same [[Prototype]], and all maps we've
406   // seen for the {receiver} so far indicate that {receiver} is
407   // definitely a constructor or not a constructor.
408   ZoneHandleSet<Map> receiver_maps;
409   NodeProperties::InferReceiverMapsResult result =
410       NodeProperties::InferReceiverMaps(isolate(), receiver, effect,
411                                         &receiver_maps);
412   if (result == NodeProperties::kNoReceiverMaps) return NoChange();
413   DCHECK_NE(0, receiver_maps.size());
414   bool const is_constructor = receiver_maps[0]->is_constructor();
415   Handle<Object> const prototype(receiver_maps[0]->prototype(), isolate());
416   for (Handle<Map> const receiver_map : receiver_maps) {
417     // Check for consistency among the {receiver_maps}.
418     STATIC_ASSERT(LAST_TYPE == LAST_FUNCTION_TYPE);
419     if (receiver_map->prototype() != *prototype) return NoChange();
420     if (receiver_map->is_constructor() != is_constructor) return NoChange();
421     if (receiver_map->instance_type() < FIRST_FUNCTION_TYPE) return NoChange();
422 
423     // Disallow binding of slow-mode functions. We need to figure out
424     // whether the length and name property are in the original state.
425     if (receiver_map->is_dictionary_map()) return NoChange();
426 
427     // Check whether the length and name properties are still present
428     // as AccessorInfo objects. In that case, their values can be
429     // recomputed even if the actual value of the object changes.
430     // This mirrors the checks done in builtins-function-gen.cc at
431     // runtime otherwise.
432     Handle<DescriptorArray> descriptors(receiver_map->instance_descriptors(),
433                                         isolate());
434     if (descriptors->number_of_descriptors() < 2) return NoChange();
435     if (descriptors->GetKey(JSFunction::kLengthDescriptorIndex) !=
436         ReadOnlyRoots(isolate()).length_string()) {
437       return NoChange();
438     }
439     if (!descriptors->GetStrongValue(JSFunction::kLengthDescriptorIndex)
440              ->IsAccessorInfo()) {
441       return NoChange();
442     }
443     if (descriptors->GetKey(JSFunction::kNameDescriptorIndex) !=
444         ReadOnlyRoots(isolate()).name_string()) {
445       return NoChange();
446     }
447     if (!descriptors->GetStrongValue(JSFunction::kNameDescriptorIndex)
448              ->IsAccessorInfo()) {
449       return NoChange();
450     }
451   }
452 
453   // Setup the map for the resulting JSBoundFunction with the
454   // correct instance {prototype}.
455   Handle<Map> map(
456       is_constructor
457           ? native_context()->bound_function_with_constructor_map()
458           : native_context()->bound_function_without_constructor_map(),
459       isolate());
460   if (map->prototype() != *prototype) {
461     map = Map::TransitionToPrototype(isolate(), map, prototype);
462   }
463 
464   // Make sure we can rely on the {receiver_maps}.
465   if (result == NodeProperties::kUnreliableReceiverMaps) {
466     effect = graph()->NewNode(
467         simplified()->CheckMaps(CheckMapsFlag::kNone, receiver_maps), receiver,
468         effect, control);
469   }
470 
471   // Replace the {node} with a JSCreateBoundFunction.
472   int const arity = std::max(0, node->op()->ValueInputCount() - 3);
473   int const input_count = 2 + arity + 3;
474   Node** inputs = graph()->zone()->NewArray<Node*>(input_count);
475   inputs[0] = receiver;
476   inputs[1] = bound_this;
477   for (int i = 0; i < arity; ++i) {
478     inputs[2 + i] = NodeProperties::GetValueInput(node, 3 + i);
479   }
480   inputs[2 + arity + 0] = context;
481   inputs[2 + arity + 1] = effect;
482   inputs[2 + arity + 2] = control;
483   Node* value = effect = graph()->NewNode(
484       javascript()->CreateBoundFunction(arity, map), input_count, inputs);
485   ReplaceWithValue(node, value, effect, control);
486   return Replace(value);
487 }
488 
489 // ES6 section 19.2.3.3 Function.prototype.call (thisArg, ...args)
ReduceFunctionPrototypeCall(Node * node)490 Reduction JSCallReducer::ReduceFunctionPrototypeCall(Node* node) {
491   DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
492   CallParameters const& p = CallParametersOf(node->op());
493   Node* target = NodeProperties::GetValueInput(node, 0);
494   Node* effect = NodeProperties::GetEffectInput(node);
495   Node* control = NodeProperties::GetControlInput(node);
496 
497   // Change context of {node} to the Function.prototype.call context,
498   // to ensure any exception is thrown in the correct context.
499   Node* context;
500   HeapObjectMatcher m(target);
501   if (m.HasValue()) {
502     Handle<JSFunction> function = Handle<JSFunction>::cast(m.Value());
503     context = jsgraph()->HeapConstant(handle(function->context(), isolate()));
504   } else {
505     context = effect = graph()->NewNode(
506         simplified()->LoadField(AccessBuilder::ForJSFunctionContext()), target,
507         effect, control);
508   }
509   NodeProperties::ReplaceContextInput(node, context);
510   NodeProperties::ReplaceEffectInput(node, effect);
511 
512   // Remove the target from {node} and use the receiver as target instead, and
513   // the thisArg becomes the new target.  If thisArg was not provided, insert
514   // undefined instead.
515   size_t arity = p.arity();
516   DCHECK_LE(2u, arity);
517   ConvertReceiverMode convert_mode;
518   if (arity == 2) {
519     // The thisArg was not provided, use undefined as receiver.
520     convert_mode = ConvertReceiverMode::kNullOrUndefined;
521     node->ReplaceInput(0, node->InputAt(1));
522     node->ReplaceInput(1, jsgraph()->UndefinedConstant());
523   } else {
524     // Just remove the target, which is the first value input.
525     convert_mode = ConvertReceiverMode::kAny;
526     node->RemoveInput(0);
527     --arity;
528   }
529   NodeProperties::ChangeOp(
530       node,
531       javascript()->Call(arity, p.frequency(), VectorSlotPair(), convert_mode));
532   // Try to further reduce the JSCall {node}.
533   Reduction const reduction = ReduceJSCall(node);
534   return reduction.Changed() ? reduction : Changed(node);
535 }
536 
537 // ES6 section 19.2.3.6 Function.prototype [ @@hasInstance ] (V)
ReduceFunctionPrototypeHasInstance(Node * node)538 Reduction JSCallReducer::ReduceFunctionPrototypeHasInstance(Node* node) {
539   DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
540   Node* receiver = NodeProperties::GetValueInput(node, 1);
541   Node* object = (node->op()->ValueInputCount() >= 3)
542                      ? NodeProperties::GetValueInput(node, 2)
543                      : jsgraph()->UndefinedConstant();
544   Node* context = NodeProperties::GetContextInput(node);
545   Node* frame_state = NodeProperties::GetFrameStateInput(node);
546   Node* effect = NodeProperties::GetEffectInput(node);
547   Node* control = NodeProperties::GetControlInput(node);
548 
549   // TODO(turbofan): If JSOrdinaryToInstance raises an exception, the
550   // stack trace doesn't contain the @@hasInstance call; we have the
551   // corresponding bug in the baseline case. Some massaging of the frame
552   // state would be necessary here.
553 
554   // Morph this {node} into a JSOrdinaryHasInstance node.
555   node->ReplaceInput(0, receiver);
556   node->ReplaceInput(1, object);
557   node->ReplaceInput(2, context);
558   node->ReplaceInput(3, frame_state);
559   node->ReplaceInput(4, effect);
560   node->ReplaceInput(5, control);
561   node->TrimInputCount(6);
562   NodeProperties::ChangeOp(node, javascript()->OrdinaryHasInstance());
563   return Changed(node);
564 }
565 
ReduceObjectGetPrototype(Node * node,Node * object)566 Reduction JSCallReducer::ReduceObjectGetPrototype(Node* node, Node* object) {
567   Node* effect = NodeProperties::GetEffectInput(node);
568 
569   // Try to determine the {object} map.
570   ZoneHandleSet<Map> object_maps;
571   NodeProperties::InferReceiverMapsResult result =
572       NodeProperties::InferReceiverMaps(isolate(), object, effect,
573                                         &object_maps);
574   if (result != NodeProperties::kNoReceiverMaps) {
575     Handle<Map> candidate_map = object_maps[0];
576     Handle<Object> candidate_prototype(candidate_map->prototype(), isolate());
577 
578     // Check if we can constant-fold the {candidate_prototype}.
579     for (size_t i = 0; i < object_maps.size(); ++i) {
580       Handle<Map> object_map = object_maps[i];
581       if (object_map->IsSpecialReceiverMap() ||
582           object_map->has_hidden_prototype() ||
583           object_map->prototype() != *candidate_prototype) {
584         // We exclude special receivers, like JSProxy or API objects that
585         // might require access checks here; we also don't want to deal
586         // with hidden prototypes at this point.
587         return NoChange();
588       }
589       // The above check also excludes maps for primitive values, which is
590       // important because we are not applying [[ToObject]] here as expected.
591       DCHECK(!object_map->IsPrimitiveMap() && object_map->IsJSReceiverMap());
592       if (result == NodeProperties::kUnreliableReceiverMaps &&
593           !object_map->is_stable()) {
594         return NoChange();
595       }
596     }
597     if (result == NodeProperties::kUnreliableReceiverMaps) {
598       for (size_t i = 0; i < object_maps.size(); ++i) {
599         dependencies()->DependOnStableMap(
600             MapRef(js_heap_broker(), object_maps[i]));
601       }
602     }
603     Node* value = jsgraph()->Constant(candidate_prototype);
604     ReplaceWithValue(node, value);
605     return Replace(value);
606   }
607 
608   return NoChange();
609 }
610 
611 // ES6 section 19.1.2.11 Object.getPrototypeOf ( O )
ReduceObjectGetPrototypeOf(Node * node)612 Reduction JSCallReducer::ReduceObjectGetPrototypeOf(Node* node) {
613   DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
614   Node* object = (node->op()->ValueInputCount() >= 3)
615                      ? NodeProperties::GetValueInput(node, 2)
616                      : jsgraph()->UndefinedConstant();
617   return ReduceObjectGetPrototype(node, object);
618 }
619 
620 // ES section #sec-object.is
ReduceObjectIs(Node * node)621 Reduction JSCallReducer::ReduceObjectIs(Node* node) {
622   DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
623   CallParameters const& params = CallParametersOf(node->op());
624   int const argc = static_cast<int>(params.arity() - 2);
625   Node* lhs = (argc >= 1) ? NodeProperties::GetValueInput(node, 2)
626                           : jsgraph()->UndefinedConstant();
627   Node* rhs = (argc >= 2) ? NodeProperties::GetValueInput(node, 3)
628                           : jsgraph()->UndefinedConstant();
629   Node* value = graph()->NewNode(simplified()->SameValue(), lhs, rhs);
630   ReplaceWithValue(node, value);
631   return Replace(value);
632 }
633 
634 // ES6 section B.2.2.1.1 get Object.prototype.__proto__
ReduceObjectPrototypeGetProto(Node * node)635 Reduction JSCallReducer::ReduceObjectPrototypeGetProto(Node* node) {
636   DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
637   Node* receiver = NodeProperties::GetValueInput(node, 1);
638   return ReduceObjectGetPrototype(node, receiver);
639 }
640 
641 // ES #sec-object.prototype.hasownproperty
ReduceObjectPrototypeHasOwnProperty(Node * node)642 Reduction JSCallReducer::ReduceObjectPrototypeHasOwnProperty(Node* node) {
643   DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
644   CallParameters const& params = CallParametersOf(node->op());
645   int const argc = static_cast<int>(params.arity() - 2);
646   Node* receiver = NodeProperties::GetValueInput(node, 1);
647   Node* name = (argc >= 1) ? NodeProperties::GetValueInput(node, 2)
648                            : jsgraph()->UndefinedConstant();
649   Node* effect = NodeProperties::GetEffectInput(node);
650   Node* control = NodeProperties::GetControlInput(node);
651 
652   // We can optimize a call to Object.prototype.hasOwnProperty if it's being
653   // used inside a fast-mode for..in, so for code like this:
654   //
655   //   for (name in receiver) {
656   //     if (receiver.hasOwnProperty(name)) {
657   //        ...
658   //     }
659   //   }
660   //
661   // If the for..in is in fast-mode, we know that the {receiver} has {name}
662   // as own property, otherwise the enumeration wouldn't include it. The graph
663   // constructed by the BytecodeGraphBuilder in this case looks like this:
664 
665   // receiver
666   //  ^    ^
667   //  |    |
668   //  |    +-+
669   //  |      |
670   //  |   JSToObject
671   //  |      ^
672   //  |      |
673   //  |   JSForInNext
674   //  |      ^
675   //  +----+ |
676   //       | |
677   //  JSCall[hasOwnProperty]
678 
679   // We can constant-fold the {node} to True in this case, and insert
680   // a (potentially redundant) map check to guard the fact that the
681   // {receiver} map didn't change since the dominating JSForInNext. This
682   // map check is only necessary when TurboFan cannot prove that there
683   // is no observable side effect between the {JSForInNext} and the
684   // {JSCall} to Object.prototype.hasOwnProperty.
685   //
686   // Also note that it's safe to look through the {JSToObject}, since the
687   // Object.prototype.hasOwnProperty does an implicit ToObject anyway, and
688   // these operations are not observable.
689   if (name->opcode() == IrOpcode::kJSForInNext) {
690     ForInMode const mode = ForInModeOf(name->op());
691     if (mode != ForInMode::kGeneric) {
692       Node* object = NodeProperties::GetValueInput(name, 0);
693       Node* cache_type = NodeProperties::GetValueInput(name, 2);
694       if (object->opcode() == IrOpcode::kJSToObject) {
695         object = NodeProperties::GetValueInput(object, 0);
696       }
697       if (object == receiver) {
698         // No need to repeat the map check if we can prove that there's no
699         // observable side effect between {effect} and {name].
700         if (!NodeProperties::NoObservableSideEffectBetween(effect, name)) {
701           Node* receiver_map = effect =
702               graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
703                                receiver, effect, control);
704           Node* check = graph()->NewNode(simplified()->ReferenceEqual(),
705                                          receiver_map, cache_type);
706           effect = graph()->NewNode(
707               simplified()->CheckIf(DeoptimizeReason::kWrongMap), check, effect,
708               control);
709         }
710         Node* value = jsgraph()->TrueConstant();
711         ReplaceWithValue(node, value, effect, control);
712         return Replace(value);
713       }
714     }
715   }
716 
717   return NoChange();
718 }
719 
720 // ES #sec-object.prototype.isprototypeof
ReduceObjectPrototypeIsPrototypeOf(Node * node)721 Reduction JSCallReducer::ReduceObjectPrototypeIsPrototypeOf(Node* node) {
722   DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
723   Node* receiver = NodeProperties::GetValueInput(node, 1);
724   Node* value = node->op()->ValueInputCount() > 2
725                     ? NodeProperties::GetValueInput(node, 2)
726                     : jsgraph()->UndefinedConstant();
727   Node* effect = NodeProperties::GetEffectInput(node);
728 
729   // Ensure that the {receiver} is known to be a JSReceiver (so that
730   // the ToObject step of Object.prototype.isPrototypeOf is a no-op).
731   ZoneHandleSet<Map> receiver_maps;
732   NodeProperties::InferReceiverMapsResult result =
733       NodeProperties::InferReceiverMaps(isolate(), receiver, effect,
734                                         &receiver_maps);
735   if (result == NodeProperties::kNoReceiverMaps) return NoChange();
736   for (size_t i = 0; i < receiver_maps.size(); ++i) {
737     if (!receiver_maps[i]->IsJSReceiverMap()) return NoChange();
738   }
739 
740   // We don't check whether {value} is a proper JSReceiver here explicitly,
741   // and don't explicitly rule out Primitive {value}s, since all of them
742   // have null as their prototype, so the prototype chain walk inside the
743   // JSHasInPrototypeChain operator immediately aborts and yields false.
744   NodeProperties::ReplaceValueInput(node, value, 0);
745   NodeProperties::ReplaceValueInput(node, receiver, 1);
746   for (int i = node->op()->ValueInputCount(); i-- > 2;) {
747     node->RemoveInput(i);
748   }
749   NodeProperties::ChangeOp(node, javascript()->HasInPrototypeChain());
750   return Changed(node);
751 }
752 
753 // ES6 section 26.1.1 Reflect.apply ( target, thisArgument, argumentsList )
ReduceReflectApply(Node * node)754 Reduction JSCallReducer::ReduceReflectApply(Node* node) {
755   DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
756   CallParameters const& p = CallParametersOf(node->op());
757   int arity = static_cast<int>(p.arity() - 2);
758   DCHECK_LE(0, arity);
759   // Massage value inputs appropriately.
760   node->RemoveInput(0);
761   node->RemoveInput(0);
762   while (arity < 3) {
763     node->InsertInput(graph()->zone(), arity++, jsgraph()->UndefinedConstant());
764   }
765   while (arity-- > 3) {
766     node->RemoveInput(arity);
767   }
768   NodeProperties::ChangeOp(node,
769                            javascript()->CallWithArrayLike(p.frequency()));
770   Reduction const reduction = ReduceJSCallWithArrayLike(node);
771   return reduction.Changed() ? reduction : Changed(node);
772 }
773 
774 // ES6 section 26.1.2 Reflect.construct ( target, argumentsList [, newTarget] )
ReduceReflectConstruct(Node * node)775 Reduction JSCallReducer::ReduceReflectConstruct(Node* node) {
776   DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
777   CallParameters const& p = CallParametersOf(node->op());
778   int arity = static_cast<int>(p.arity() - 2);
779   DCHECK_LE(0, arity);
780   // Massage value inputs appropriately.
781   node->RemoveInput(0);
782   node->RemoveInput(0);
783   while (arity < 2) {
784     node->InsertInput(graph()->zone(), arity++, jsgraph()->UndefinedConstant());
785   }
786   if (arity < 3) {
787     node->InsertInput(graph()->zone(), arity++, node->InputAt(0));
788   }
789   while (arity-- > 3) {
790     node->RemoveInput(arity);
791   }
792   NodeProperties::ChangeOp(node,
793                            javascript()->ConstructWithArrayLike(p.frequency()));
794   Reduction const reduction = ReduceJSConstructWithArrayLike(node);
795   return reduction.Changed() ? reduction : Changed(node);
796 }
797 
798 // ES6 section 26.1.7 Reflect.getPrototypeOf ( target )
ReduceReflectGetPrototypeOf(Node * node)799 Reduction JSCallReducer::ReduceReflectGetPrototypeOf(Node* node) {
800   DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
801   Node* target = (node->op()->ValueInputCount() >= 3)
802                      ? NodeProperties::GetValueInput(node, 2)
803                      : jsgraph()->UndefinedConstant();
804   return ReduceObjectGetPrototype(node, target);
805 }
806 
807 // ES6 section #sec-object.create Object.create(proto, properties)
ReduceObjectCreate(Node * node)808 Reduction JSCallReducer::ReduceObjectCreate(Node* node) {
809   int arg_count = node->op()->ValueInputCount();
810   Node* properties = arg_count >= 4 ? NodeProperties::GetValueInput(node, 3)
811                                     : jsgraph()->UndefinedConstant();
812   if (properties != jsgraph()->UndefinedConstant()) return NoChange();
813 
814   Node* effect = NodeProperties::GetEffectInput(node);
815   Node* control = NodeProperties::GetControlInput(node);
816   Node* context = NodeProperties::GetContextInput(node);
817   Node* frame_state = NodeProperties::GetFrameStateInput(node);
818   Node* prototype = arg_count >= 3 ? NodeProperties::GetValueInput(node, 2)
819                                    : jsgraph()->UndefinedConstant();
820   node->ReplaceInput(0, prototype);
821   node->ReplaceInput(1, context);
822   node->ReplaceInput(2, frame_state);
823   node->ReplaceInput(3, effect);
824   node->ReplaceInput(4, control);
825   node->TrimInputCount(5);
826   NodeProperties::ChangeOp(node, javascript()->CreateObject());
827   return Changed(node);
828 }
829 
830 // ES section #sec-reflect.get
ReduceReflectGet(Node * node)831 Reduction JSCallReducer::ReduceReflectGet(Node* node) {
832   DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
833   CallParameters const& p = CallParametersOf(node->op());
834   int arity = static_cast<int>(p.arity() - 2);
835   if (arity != 2) return NoChange();
836   Node* target = NodeProperties::GetValueInput(node, 2);
837   Node* key = NodeProperties::GetValueInput(node, 3);
838   Node* context = NodeProperties::GetContextInput(node);
839   Node* frame_state = NodeProperties::GetFrameStateInput(node);
840   Node* effect = NodeProperties::GetEffectInput(node);
841   Node* control = NodeProperties::GetControlInput(node);
842 
843   // Check whether {target} is a JSReceiver.
844   Node* check = graph()->NewNode(simplified()->ObjectIsReceiver(), target);
845   Node* branch =
846       graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
847 
848   // Throw an appropriate TypeError if the {target} is not a JSReceiver.
849   Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
850   Node* efalse = effect;
851   {
852     if_false = efalse = graph()->NewNode(
853         javascript()->CallRuntime(Runtime::kThrowTypeError, 2),
854         jsgraph()->Constant(MessageTemplate::kCalledOnNonObject),
855         jsgraph()->HeapConstant(
856             factory()->NewStringFromAsciiChecked("Reflect.get")),
857         context, frame_state, efalse, if_false);
858   }
859 
860   // Otherwise just use the existing GetPropertyStub.
861   Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
862   Node* etrue = effect;
863   Node* vtrue;
864   {
865     Callable callable =
866         Builtins::CallableFor(isolate(), Builtins::kGetProperty);
867     auto call_descriptor = Linkage::GetStubCallDescriptor(
868         graph()->zone(), callable.descriptor(), 0,
869         CallDescriptor::kNeedsFrameState, Operator::kNoProperties);
870     Node* stub_code = jsgraph()->HeapConstant(callable.code());
871     vtrue = etrue = if_true =
872         graph()->NewNode(common()->Call(call_descriptor), stub_code, target,
873                          key, context, frame_state, etrue, if_true);
874   }
875 
876   // Rewire potential exception edges.
877   Node* on_exception = nullptr;
878   if (NodeProperties::IsExceptionalCall(node, &on_exception)) {
879     // Create appropriate {IfException} and {IfSuccess} nodes.
880     Node* extrue = graph()->NewNode(common()->IfException(), etrue, if_true);
881     if_true = graph()->NewNode(common()->IfSuccess(), if_true);
882     Node* exfalse = graph()->NewNode(common()->IfException(), efalse, if_false);
883     if_false = graph()->NewNode(common()->IfSuccess(), if_false);
884 
885     // Join the exception edges.
886     Node* merge = graph()->NewNode(common()->Merge(2), extrue, exfalse);
887     Node* ephi =
888         graph()->NewNode(common()->EffectPhi(2), extrue, exfalse, merge);
889     Node* phi =
890         graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
891                          extrue, exfalse, merge);
892     ReplaceWithValue(on_exception, phi, ephi, merge);
893   }
894 
895   // Connect the throwing path to end.
896   if_false = graph()->NewNode(common()->Throw(), efalse, if_false);
897   NodeProperties::MergeControlToEnd(graph(), common(), if_false);
898 
899   // Continue on the regular path.
900   ReplaceWithValue(node, vtrue, etrue, if_true);
901   return Changed(vtrue);
902 }
903 
904 // ES section #sec-reflect.has
ReduceReflectHas(Node * node)905 Reduction JSCallReducer::ReduceReflectHas(Node* node) {
906   DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
907   CallParameters const& p = CallParametersOf(node->op());
908   int arity = static_cast<int>(p.arity() - 2);
909   DCHECK_LE(0, arity);
910   Node* target = (arity >= 1) ? NodeProperties::GetValueInput(node, 2)
911                               : jsgraph()->UndefinedConstant();
912   Node* key = (arity >= 2) ? NodeProperties::GetValueInput(node, 3)
913                            : jsgraph()->UndefinedConstant();
914   Node* context = NodeProperties::GetContextInput(node);
915   Node* frame_state = NodeProperties::GetFrameStateInput(node);
916   Node* effect = NodeProperties::GetEffectInput(node);
917   Node* control = NodeProperties::GetControlInput(node);
918 
919   // Check whether {target} is a JSReceiver.
920   Node* check = graph()->NewNode(simplified()->ObjectIsReceiver(), target);
921   Node* branch =
922       graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
923 
924   // Throw an appropriate TypeError if the {target} is not a JSReceiver.
925   Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
926   Node* efalse = effect;
927   {
928     if_false = efalse = graph()->NewNode(
929         javascript()->CallRuntime(Runtime::kThrowTypeError, 2),
930         jsgraph()->Constant(MessageTemplate::kCalledOnNonObject),
931         jsgraph()->HeapConstant(
932             factory()->NewStringFromAsciiChecked("Reflect.has")),
933         context, frame_state, efalse, if_false);
934   }
935 
936   // Otherwise just use the existing {JSHasProperty} logic.
937   Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
938   Node* etrue = effect;
939   Node* vtrue;
940   {
941     vtrue = etrue = if_true =
942         graph()->NewNode(javascript()->HasProperty(), target, key, context,
943                          frame_state, etrue, if_true);
944   }
945 
946   // Rewire potential exception edges.
947   Node* on_exception = nullptr;
948   if (NodeProperties::IsExceptionalCall(node, &on_exception)) {
949     // Create appropriate {IfException} and {IfSuccess} nodes.
950     Node* extrue = graph()->NewNode(common()->IfException(), etrue, if_true);
951     if_true = graph()->NewNode(common()->IfSuccess(), if_true);
952     Node* exfalse = graph()->NewNode(common()->IfException(), efalse, if_false);
953     if_false = graph()->NewNode(common()->IfSuccess(), if_false);
954 
955     // Join the exception edges.
956     Node* merge = graph()->NewNode(common()->Merge(2), extrue, exfalse);
957     Node* ephi =
958         graph()->NewNode(common()->EffectPhi(2), extrue, exfalse, merge);
959     Node* phi =
960         graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
961                          extrue, exfalse, merge);
962     ReplaceWithValue(on_exception, phi, ephi, merge);
963   }
964 
965   // Connect the throwing path to end.
966   if_false = graph()->NewNode(common()->Throw(), efalse, if_false);
967   NodeProperties::MergeControlToEnd(graph(), common(), if_false);
968 
969   // Continue on the regular path.
970   ReplaceWithValue(node, vtrue, etrue, if_true);
971   return Changed(vtrue);
972 }
973 
CanInlineArrayIteratingBuiltin(Isolate * isolate,Handle<Map> receiver_map)974 bool CanInlineArrayIteratingBuiltin(Isolate* isolate,
975                                     Handle<Map> receiver_map) {
976   if (!receiver_map->prototype()->IsJSArray()) return false;
977   Handle<JSArray> receiver_prototype(JSArray::cast(receiver_map->prototype()),
978                                      isolate);
979   return receiver_map->instance_type() == JS_ARRAY_TYPE &&
980          IsFastElementsKind(receiver_map->elements_kind()) &&
981          isolate->IsNoElementsProtectorIntact() &&
982          isolate->IsAnyInitialArrayPrototype(receiver_prototype);
983 }
984 
WireInLoopStart(Node * k,Node ** control,Node ** effect)985 Node* JSCallReducer::WireInLoopStart(Node* k, Node** control, Node** effect) {
986   Node* loop = *control =
987       graph()->NewNode(common()->Loop(2), *control, *control);
988   Node* eloop = *effect =
989       graph()->NewNode(common()->EffectPhi(2), *effect, *effect, loop);
990   Node* terminate = graph()->NewNode(common()->Terminate(), eloop, loop);
991   NodeProperties::MergeControlToEnd(graph(), common(), terminate);
992   return graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), k,
993                           k, loop);
994 }
995 
WireInLoopEnd(Node * loop,Node * eloop,Node * vloop,Node * k,Node * control,Node * effect)996 void JSCallReducer::WireInLoopEnd(Node* loop, Node* eloop, Node* vloop, Node* k,
997                                   Node* control, Node* effect) {
998   loop->ReplaceInput(1, control);
999   vloop->ReplaceInput(1, k);
1000   eloop->ReplaceInput(1, effect);
1001 }
1002 
ReduceArrayForEach(Node * node,Handle<SharedFunctionInfo> shared)1003 Reduction JSCallReducer::ReduceArrayForEach(Node* node,
1004                                             Handle<SharedFunctionInfo> shared) {
1005   if (!FLAG_turbo_inline_array_builtins) return NoChange();
1006   DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
1007   CallParameters const& p = CallParametersOf(node->op());
1008   if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
1009     return NoChange();
1010   }
1011 
1012   Node* outer_frame_state = NodeProperties::GetFrameStateInput(node);
1013   Node* effect = NodeProperties::GetEffectInput(node);
1014   Node* control = NodeProperties::GetControlInput(node);
1015   Node* context = NodeProperties::GetContextInput(node);
1016 
1017   // Try to determine the {receiver} map.
1018   Node* receiver = NodeProperties::GetValueInput(node, 1);
1019   Node* fncallback = node->op()->ValueInputCount() > 2
1020                          ? NodeProperties::GetValueInput(node, 2)
1021                          : jsgraph()->UndefinedConstant();
1022   Node* this_arg = node->op()->ValueInputCount() > 3
1023                        ? NodeProperties::GetValueInput(node, 3)
1024                        : jsgraph()->UndefinedConstant();
1025   ZoneHandleSet<Map> receiver_maps;
1026   NodeProperties::InferReceiverMapsResult result =
1027       NodeProperties::InferReceiverMaps(isolate(), receiver, effect,
1028                                         &receiver_maps);
1029   if (result == NodeProperties::kNoReceiverMaps) return NoChange();
1030 
1031   // By ensuring that {kind} is object or double, we can be polymorphic
1032   // on different elements kinds.
1033   ElementsKind kind = receiver_maps[0]->elements_kind();
1034   if (IsSmiElementsKind(kind)) {
1035     kind = FastSmiToObjectElementsKind(kind);
1036   }
1037   for (Handle<Map> receiver_map : receiver_maps) {
1038     ElementsKind next_kind = receiver_map->elements_kind();
1039     if (!CanInlineArrayIteratingBuiltin(isolate(), receiver_map)) {
1040       return NoChange();
1041     }
1042     if (!IsFastElementsKind(next_kind)) {
1043       return NoChange();
1044     }
1045     if (IsDoubleElementsKind(kind) != IsDoubleElementsKind(next_kind)) {
1046       return NoChange();
1047     }
1048     if (IsHoleyElementsKind(next_kind)) {
1049       kind = GetHoleyElementsKind(kind);
1050     }
1051   }
1052 
1053   // Install code dependencies on the {receiver} prototype maps and the
1054   // global array protector cell.
1055   dependencies()->DependOnProtector(
1056       PropertyCellRef(js_heap_broker(), factory()->no_elements_protector()));
1057 
1058   // If we have unreliable maps, we need a map check.
1059   if (result == NodeProperties::kUnreliableReceiverMaps) {
1060     effect =
1061         graph()->NewNode(simplified()->CheckMaps(CheckMapsFlag::kNone,
1062                                                  receiver_maps, p.feedback()),
1063                          receiver, effect, control);
1064   }
1065 
1066   Node* k = jsgraph()->ZeroConstant();
1067 
1068   Node* original_length = effect = graph()->NewNode(
1069       simplified()->LoadField(AccessBuilder::ForJSArrayLength(kind)), receiver,
1070       effect, control);
1071 
1072   std::vector<Node*> checkpoint_params(
1073       {receiver, fncallback, this_arg, k, original_length});
1074   const int stack_parameters = static_cast<int>(checkpoint_params.size());
1075 
1076   // Check whether the given callback function is callable. Note that this has
1077   // to happen outside the loop to make sure we also throw on empty arrays.
1078   Node* check_frame_state = CreateJavaScriptBuiltinContinuationFrameState(
1079       jsgraph(), shared, Builtins::kArrayForEachLoopLazyDeoptContinuation,
1080       node->InputAt(0), context, &checkpoint_params[0], stack_parameters,
1081       outer_frame_state, ContinuationFrameStateMode::LAZY);
1082   Node* check_fail = nullptr;
1083   Node* check_throw = nullptr;
1084   WireInCallbackIsCallableCheck(fncallback, context, check_frame_state, effect,
1085                                 &control, &check_fail, &check_throw);
1086 
1087   // Start the loop.
1088   Node* vloop = k = WireInLoopStart(k, &control, &effect);
1089   Node *loop = control, *eloop = effect;
1090   checkpoint_params[3] = k;
1091 
1092   Node* continue_test =
1093       graph()->NewNode(simplified()->NumberLessThan(), k, original_length);
1094   Node* continue_branch = graph()->NewNode(common()->Branch(BranchHint::kTrue),
1095                                            continue_test, control);
1096 
1097   Node* if_true = graph()->NewNode(common()->IfTrue(), continue_branch);
1098   Node* if_false = graph()->NewNode(common()->IfFalse(), continue_branch);
1099   control = if_true;
1100 
1101   Node* frame_state = CreateJavaScriptBuiltinContinuationFrameState(
1102       jsgraph(), shared, Builtins::kArrayForEachLoopEagerDeoptContinuation,
1103       node->InputAt(0), context, &checkpoint_params[0], stack_parameters,
1104       outer_frame_state, ContinuationFrameStateMode::EAGER);
1105 
1106   effect =
1107       graph()->NewNode(common()->Checkpoint(), frame_state, effect, control);
1108 
1109   // Make sure the map hasn't changed during the iteration
1110   effect =
1111       graph()->NewNode(simplified()->CheckMaps(CheckMapsFlag::kNone,
1112                                                receiver_maps, p.feedback()),
1113                        receiver, effect, control);
1114 
1115   Node* element =
1116       SafeLoadElement(kind, receiver, control, &effect, &k, p.feedback());
1117 
1118   Node* next_k =
1119       graph()->NewNode(simplified()->NumberAdd(), k, jsgraph()->OneConstant());
1120   checkpoint_params[3] = next_k;
1121 
1122   Node* hole_true = nullptr;
1123   Node* hole_false = nullptr;
1124   Node* effect_true = effect;
1125 
1126   if (IsHoleyElementsKind(kind)) {
1127     // Holey elements kind require a hole check and skipping of the element in
1128     // the case of a hole.
1129     Node* check;
1130     if (IsDoubleElementsKind(kind)) {
1131       check = graph()->NewNode(simplified()->NumberIsFloat64Hole(), element);
1132     } else {
1133       check = graph()->NewNode(simplified()->ReferenceEqual(), element,
1134                                jsgraph()->TheHoleConstant());
1135     }
1136     Node* branch =
1137         graph()->NewNode(common()->Branch(BranchHint::kFalse), check, control);
1138     hole_true = graph()->NewNode(common()->IfTrue(), branch);
1139     hole_false = graph()->NewNode(common()->IfFalse(), branch);
1140     control = hole_false;
1141 
1142     // The contract is that we don't leak "the hole" into "user JavaScript",
1143     // so we must rename the {element} here to explicitly exclude "the hole"
1144     // from the type of {element}.
1145     element = effect = graph()->NewNode(
1146         common()->TypeGuard(Type::NonInternal()), element, effect, control);
1147   }
1148 
1149   frame_state = CreateJavaScriptBuiltinContinuationFrameState(
1150       jsgraph(), shared, Builtins::kArrayForEachLoopLazyDeoptContinuation,
1151       node->InputAt(0), context, &checkpoint_params[0], stack_parameters,
1152       outer_frame_state, ContinuationFrameStateMode::LAZY);
1153 
1154   control = effect = graph()->NewNode(
1155       javascript()->Call(5, p.frequency()), fncallback, this_arg, element, k,
1156       receiver, context, frame_state, effect, control);
1157 
1158   // Rewire potential exception edges.
1159   Node* on_exception = nullptr;
1160   if (NodeProperties::IsExceptionalCall(node, &on_exception)) {
1161     RewirePostCallbackExceptionEdges(check_throw, on_exception, effect,
1162                                      &check_fail, &control);
1163   }
1164 
1165   if (IsHoleyElementsKind(kind)) {
1166     Node* after_call_control = control;
1167     Node* after_call_effect = effect;
1168     control = hole_true;
1169     effect = effect_true;
1170 
1171     control = graph()->NewNode(common()->Merge(2), control, after_call_control);
1172     effect = graph()->NewNode(common()->EffectPhi(2), effect, after_call_effect,
1173                               control);
1174   }
1175 
1176   WireInLoopEnd(loop, eloop, vloop, next_k, control, effect);
1177 
1178   control = if_false;
1179   effect = eloop;
1180 
1181   // Wire up the branch for the case when IsCallable fails for the callback.
1182   // Since {check_throw} is an unconditional throw, it's impossible to
1183   // return a successful completion. Therefore, we simply connect the successful
1184   // completion to the graph end.
1185   Node* throw_node =
1186       graph()->NewNode(common()->Throw(), check_throw, check_fail);
1187   NodeProperties::MergeControlToEnd(graph(), common(), throw_node);
1188 
1189   ReplaceWithValue(node, jsgraph()->UndefinedConstant(), effect, control);
1190   return Replace(jsgraph()->UndefinedConstant());
1191 }
1192 
ReduceArrayReduce(Node * node,ArrayReduceDirection direction,Handle<SharedFunctionInfo> shared)1193 Reduction JSCallReducer::ReduceArrayReduce(Node* node,
1194                                            ArrayReduceDirection direction,
1195                                            Handle<SharedFunctionInfo> shared) {
1196   if (!FLAG_turbo_inline_array_builtins) return NoChange();
1197   DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
1198   CallParameters const& p = CallParametersOf(node->op());
1199   if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
1200     return NoChange();
1201   }
1202   bool left = direction == ArrayReduceDirection::kLeft;
1203 
1204   Node* outer_frame_state = NodeProperties::GetFrameStateInput(node);
1205   Node* effect = NodeProperties::GetEffectInput(node);
1206   Node* control = NodeProperties::GetControlInput(node);
1207   Node* context = NodeProperties::GetContextInput(node);
1208 
1209   // Try to determine the {receiver} map.
1210   Node* receiver = NodeProperties::GetValueInput(node, 1);
1211   Node* fncallback = node->op()->ValueInputCount() > 2
1212                          ? NodeProperties::GetValueInput(node, 2)
1213                          : jsgraph()->UndefinedConstant();
1214 
1215   ZoneHandleSet<Map> receiver_maps;
1216   NodeProperties::InferReceiverMapsResult result =
1217       NodeProperties::InferReceiverMaps(isolate(), receiver, effect,
1218                                         &receiver_maps);
1219   if (result == NodeProperties::kNoReceiverMaps) return NoChange();
1220 
1221   ElementsKind kind = receiver_maps[0]->elements_kind();
1222   for (Handle<Map> receiver_map : receiver_maps) {
1223     if (!CanInlineArrayIteratingBuiltin(isolate(), receiver_map))
1224       return NoChange();
1225     if (!UnionElementsKindUptoSize(&kind, receiver_map->elements_kind()))
1226       return NoChange();
1227   }
1228 
1229   std::function<Node*(Node*)> hole_check = [this, kind](Node* element) {
1230     if (IsDoubleElementsKind(kind)) {
1231       return graph()->NewNode(simplified()->NumberIsFloat64Hole(), element);
1232     } else {
1233       return graph()->NewNode(simplified()->ReferenceEqual(), element,
1234                               jsgraph()->TheHoleConstant());
1235     }
1236   };
1237 
1238   // Install code dependencies on the {receiver} prototype maps and the
1239   // global array protector cell.
1240   dependencies()->DependOnProtector(
1241       PropertyCellRef(js_heap_broker(), factory()->no_elements_protector()));
1242 
1243   // If we have unreliable maps, we need a map check.
1244   if (result == NodeProperties::kUnreliableReceiverMaps) {
1245     effect =
1246         graph()->NewNode(simplified()->CheckMaps(CheckMapsFlag::kNone,
1247                                                  receiver_maps, p.feedback()),
1248                          receiver, effect, control);
1249   }
1250 
1251   Node* original_length = effect = graph()->NewNode(
1252       simplified()->LoadField(AccessBuilder::ForJSArrayLength(PACKED_ELEMENTS)),
1253       receiver, effect, control);
1254 
1255   Node* initial_index =
1256       left ? jsgraph()->ZeroConstant()
1257            : graph()->NewNode(simplified()->NumberSubtract(), original_length,
1258                               jsgraph()->OneConstant());
1259   const Operator* next_op =
1260       left ? simplified()->NumberAdd() : simplified()->NumberSubtract();
1261   Node* k = initial_index;
1262 
1263   Node* check_frame_state;
1264   {
1265     Builtins::Name builtin_lazy =
1266         left ? Builtins::kArrayReduceLoopLazyDeoptContinuation
1267              : Builtins::kArrayReduceRightLoopLazyDeoptContinuation;
1268     const std::vector<Node*> checkpoint_params(
1269         {receiver, fncallback, k, original_length,
1270          jsgraph()->UndefinedConstant()});
1271     const int stack_parameters = static_cast<int>(checkpoint_params.size());
1272     check_frame_state = CreateJavaScriptBuiltinContinuationFrameState(
1273         jsgraph(), shared, builtin_lazy, node->InputAt(0), context,
1274         checkpoint_params.data(), stack_parameters - 1, outer_frame_state,
1275         ContinuationFrameStateMode::LAZY);
1276   }
1277   Node* check_fail = nullptr;
1278   Node* check_throw = nullptr;
1279   // Check whether the given callback function is callable. Note that
1280   // this has to happen outside the loop to make sure we also throw on
1281   // empty arrays.
1282   WireInCallbackIsCallableCheck(fncallback, context, check_frame_state, effect,
1283                                 &control, &check_fail, &check_throw);
1284 
1285   // Set initial accumulator value
1286   Node* cur = jsgraph()->TheHoleConstant();
1287 
1288   if (node->op()->ValueInputCount() > 3) {
1289     cur = NodeProperties::GetValueInput(node, 3);
1290   } else {
1291     // Find first/last non holey element. In case the search fails, we need a
1292     // deopt continuation.
1293     Builtins::Name builtin_eager =
1294         left ? Builtins::kArrayReducePreLoopEagerDeoptContinuation
1295              : Builtins::kArrayReduceRightPreLoopEagerDeoptContinuation;
1296     const std::vector<Node*> checkpoint_params(
1297         {receiver, fncallback, original_length});
1298     const int stack_parameters = static_cast<int>(checkpoint_params.size());
1299     Node* find_first_element_frame_state =
1300         CreateJavaScriptBuiltinContinuationFrameState(
1301             jsgraph(), shared, builtin_eager, node->InputAt(0), context,
1302             checkpoint_params.data(), stack_parameters, outer_frame_state,
1303             ContinuationFrameStateMode::EAGER);
1304 
1305     Node* vloop = k = WireInLoopStart(k, &control, &effect);
1306     Node* loop = control;
1307     Node* eloop = effect;
1308     effect = graph()->NewNode(common()->Checkpoint(),
1309                               find_first_element_frame_state, effect, control);
1310     Node* continue_test =
1311         left ? graph()->NewNode(simplified()->NumberLessThan(), k,
1312                                 original_length)
1313              : graph()->NewNode(simplified()->NumberLessThanOrEqual(),
1314                                 jsgraph()->ZeroConstant(), k);
1315     effect = graph()->NewNode(
1316         simplified()->CheckIf(DeoptimizeReason::kNoInitialElement),
1317         continue_test, effect, control);
1318 
1319     cur = SafeLoadElement(kind, receiver, control, &effect, &k, p.feedback());
1320     Node* next_k = graph()->NewNode(next_op, k, jsgraph()->OneConstant());
1321 
1322     Node* hole_branch = graph()->NewNode(common()->Branch(BranchHint::kTrue),
1323                                          hole_check(cur), control);
1324     Node* found_el = graph()->NewNode(common()->IfFalse(), hole_branch);
1325     control = found_el;
1326     Node* is_hole = graph()->NewNode(common()->IfTrue(), hole_branch);
1327 
1328     WireInLoopEnd(loop, eloop, vloop, next_k, is_hole, effect);
1329     // We did the hole-check, so exclude hole from the type.
1330     cur = effect = graph()->NewNode(common()->TypeGuard(Type::NonInternal()),
1331                                     cur, effect, control);
1332     k = next_k;
1333   }
1334 
1335   // Start the loop.
1336   Node* loop = control = graph()->NewNode(common()->Loop(2), control, control);
1337   Node* eloop = effect =
1338       graph()->NewNode(common()->EffectPhi(2), effect, effect, loop);
1339   Node* terminate = graph()->NewNode(common()->Terminate(), eloop, loop);
1340   NodeProperties::MergeControlToEnd(graph(), common(), terminate);
1341   Node* kloop = k = graph()->NewNode(
1342       common()->Phi(MachineRepresentation::kTagged, 2), k, k, loop);
1343   Node* curloop = cur = graph()->NewNode(
1344       common()->Phi(MachineRepresentation::kTagged, 2), cur, cur, loop);
1345 
1346   control = loop;
1347   effect = eloop;
1348 
1349   Node* continue_test =
1350       left
1351           ? graph()->NewNode(simplified()->NumberLessThan(), k, original_length)
1352           : graph()->NewNode(simplified()->NumberLessThanOrEqual(),
1353                              jsgraph()->ZeroConstant(), k);
1354 
1355   Node* continue_branch = graph()->NewNode(common()->Branch(BranchHint::kTrue),
1356                                            continue_test, control);
1357 
1358   Node* if_true = graph()->NewNode(common()->IfTrue(), continue_branch);
1359   Node* if_false = graph()->NewNode(common()->IfFalse(), continue_branch);
1360   control = if_true;
1361 
1362   {
1363     Builtins::Name builtin_eager =
1364         left ? Builtins::kArrayReduceLoopEagerDeoptContinuation
1365              : Builtins::kArrayReduceRightLoopEagerDeoptContinuation;
1366     const std::vector<Node*> checkpoint_params(
1367         {receiver, fncallback, k, original_length, curloop});
1368     const int stack_parameters = static_cast<int>(checkpoint_params.size());
1369     Node* frame_state = CreateJavaScriptBuiltinContinuationFrameState(
1370         jsgraph(), shared, builtin_eager, node->InputAt(0), context,
1371         checkpoint_params.data(), stack_parameters, outer_frame_state,
1372         ContinuationFrameStateMode::EAGER);
1373     effect =
1374         graph()->NewNode(common()->Checkpoint(), frame_state, effect, control);
1375   }
1376 
1377   // Make sure the map hasn't changed during the iteration
1378   effect = graph()->NewNode(
1379       simplified()->CheckMaps(CheckMapsFlag::kNone, receiver_maps), receiver,
1380       effect, control);
1381 
1382   Node* element =
1383       SafeLoadElement(kind, receiver, control, &effect, &k, p.feedback());
1384 
1385   Node* next_k = graph()->NewNode(next_op, k, jsgraph()->OneConstant());
1386 
1387   Node* hole_true = nullptr;
1388   Node* hole_false = nullptr;
1389   Node* effect_true = effect;
1390 
1391   if (IsHoleyElementsKind(kind)) {
1392     // Holey elements kind require a hole check and skipping of the element in
1393     // the case of a hole.
1394     Node* branch = graph()->NewNode(common()->Branch(BranchHint::kFalse),
1395                                     hole_check(element), control);
1396     hole_true = graph()->NewNode(common()->IfTrue(), branch);
1397     hole_false = graph()->NewNode(common()->IfFalse(), branch);
1398     control = hole_false;
1399 
1400     // The contract is that we don't leak "the hole" into "user JavaScript",
1401     // so we must rename the {element} here to explicitly exclude "the hole"
1402     // from the type of {element}.
1403     element = effect = graph()->NewNode(
1404         common()->TypeGuard(Type::NonInternal()), element, effect, control);
1405   }
1406 
1407   Node* next_cur;
1408   {
1409     Builtins::Name builtin_lazy =
1410         left ? Builtins::kArrayReduceLoopLazyDeoptContinuation
1411              : Builtins::kArrayReduceRightLoopLazyDeoptContinuation;
1412     const std::vector<Node*> checkpoint_params(
1413         {receiver, fncallback, next_k, original_length, curloop});
1414     const int stack_parameters = static_cast<int>(checkpoint_params.size());
1415     Node* frame_state = CreateJavaScriptBuiltinContinuationFrameState(
1416         jsgraph(), shared, builtin_lazy, node->InputAt(0), context,
1417         checkpoint_params.data(), stack_parameters - 1, outer_frame_state,
1418         ContinuationFrameStateMode::LAZY);
1419 
1420     next_cur = control = effect =
1421         graph()->NewNode(javascript()->Call(6, p.frequency()), fncallback,
1422                          jsgraph()->UndefinedConstant(), cur, element, k,
1423                          receiver, context, frame_state, effect, control);
1424   }
1425 
1426   // Rewire potential exception edges.
1427   Node* on_exception = nullptr;
1428   if (NodeProperties::IsExceptionalCall(node, &on_exception)) {
1429     RewirePostCallbackExceptionEdges(check_throw, on_exception, effect,
1430                                      &check_fail, &control);
1431   }
1432 
1433   if (IsHoleyElementsKind(kind)) {
1434     Node* after_call_control = control;
1435     Node* after_call_effect = effect;
1436     control = hole_true;
1437     effect = effect_true;
1438 
1439     control = graph()->NewNode(common()->Merge(2), control, after_call_control);
1440     effect = graph()->NewNode(common()->EffectPhi(2), effect, after_call_effect,
1441                               control);
1442     next_cur =
1443         graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), cur,
1444                          next_cur, control);
1445   }
1446 
1447   k = next_k;
1448   cur = next_cur;
1449 
1450   loop->ReplaceInput(1, control);
1451   kloop->ReplaceInput(1, k);
1452   curloop->ReplaceInput(1, cur);
1453   eloop->ReplaceInput(1, effect);
1454 
1455   control = if_false;
1456   effect = eloop;
1457 
1458   // Wire up the branch for the case when IsCallable fails for the callback.
1459   // Since {check_throw} is an unconditional throw, it's impossible to
1460   // return a successful completion. Therefore, we simply connect the successful
1461   // completion to the graph end.
1462   Node* throw_node =
1463       graph()->NewNode(common()->Throw(), check_throw, check_fail);
1464   NodeProperties::MergeControlToEnd(graph(), common(), throw_node);
1465 
1466   ReplaceWithValue(node, curloop, effect, control);
1467   return Replace(curloop);
1468 }
1469 
ReduceArrayMap(Node * node,Handle<SharedFunctionInfo> shared)1470 Reduction JSCallReducer::ReduceArrayMap(Node* node,
1471                                         Handle<SharedFunctionInfo> shared) {
1472   if (!FLAG_turbo_inline_array_builtins) return NoChange();
1473   DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
1474   CallParameters const& p = CallParametersOf(node->op());
1475   if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
1476     return NoChange();
1477   }
1478 
1479   Node* outer_frame_state = NodeProperties::GetFrameStateInput(node);
1480   Node* effect = NodeProperties::GetEffectInput(node);
1481   Node* control = NodeProperties::GetControlInput(node);
1482   Node* context = NodeProperties::GetContextInput(node);
1483 
1484   // Try to determine the {receiver} map.
1485   Node* receiver = NodeProperties::GetValueInput(node, 1);
1486   Node* fncallback = node->op()->ValueInputCount() > 2
1487                          ? NodeProperties::GetValueInput(node, 2)
1488                          : jsgraph()->UndefinedConstant();
1489   Node* this_arg = node->op()->ValueInputCount() > 3
1490                        ? NodeProperties::GetValueInput(node, 3)
1491                        : jsgraph()->UndefinedConstant();
1492   ZoneHandleSet<Map> receiver_maps;
1493   NodeProperties::InferReceiverMapsResult result =
1494       NodeProperties::InferReceiverMaps(isolate(), receiver, effect,
1495                                         &receiver_maps);
1496   if (result == NodeProperties::kNoReceiverMaps) return NoChange();
1497 
1498   // Ensure that any changes to the Array species constructor cause deopt.
1499   if (!isolate()->IsArraySpeciesLookupChainIntact()) return NoChange();
1500 
1501   const ElementsKind kind = receiver_maps[0]->elements_kind();
1502 
1503   for (Handle<Map> receiver_map : receiver_maps) {
1504     if (!CanInlineArrayIteratingBuiltin(isolate(), receiver_map))
1505       return NoChange();
1506     // We can handle different maps, as long as their elements kind are the
1507     // same.
1508     if (receiver_map->elements_kind() != kind) return NoChange();
1509   }
1510 
1511   if (IsHoleyElementsKind(kind)) {
1512     dependencies()->DependOnProtector(
1513         PropertyCellRef(js_heap_broker(), factory()->no_elements_protector()));
1514   }
1515 
1516   dependencies()->DependOnProtector(
1517       PropertyCellRef(js_heap_broker(), factory()->array_species_protector()));
1518 
1519   Handle<JSFunction> handle_constructor(
1520       JSFunction::cast(
1521           native_context()->GetInitialJSArrayMap(kind)->GetConstructor()),
1522       isolate());
1523   Node* array_constructor = jsgraph()->HeapConstant(handle_constructor);
1524 
1525 
1526   Node* k = jsgraph()->ZeroConstant();
1527 
1528   // If we have unreliable maps, we need a map check.
1529   if (result == NodeProperties::kUnreliableReceiverMaps) {
1530     effect =
1531         graph()->NewNode(simplified()->CheckMaps(CheckMapsFlag::kNone,
1532                                                  receiver_maps, p.feedback()),
1533                          receiver, effect, control);
1534   }
1535 
1536   Node* original_length = effect = graph()->NewNode(
1537       simplified()->LoadField(AccessBuilder::ForJSArrayLength(kind)), receiver,
1538       effect, control);
1539 
1540   // Even though {JSCreateArray} is not marked as {kNoThrow}, we can elide the
1541   // exceptional projections because it cannot throw with the given parameters.
1542   Node* a = control = effect = graph()->NewNode(
1543       javascript()->CreateArray(1, MaybeHandle<AllocationSite>()),
1544       array_constructor, array_constructor, original_length, context,
1545       outer_frame_state, effect, control);
1546 
1547   std::vector<Node*> checkpoint_params(
1548       {receiver, fncallback, this_arg, a, k, original_length});
1549   const int stack_parameters = static_cast<int>(checkpoint_params.size());
1550 
1551   // Check whether the given callback function is callable. Note that this has
1552   // to happen outside the loop to make sure we also throw on empty arrays.
1553   Node* check_frame_state = CreateJavaScriptBuiltinContinuationFrameState(
1554       jsgraph(), shared, Builtins::kArrayMapLoopLazyDeoptContinuation,
1555       node->InputAt(0), context, &checkpoint_params[0], stack_parameters,
1556       outer_frame_state, ContinuationFrameStateMode::LAZY);
1557   Node* check_fail = nullptr;
1558   Node* check_throw = nullptr;
1559   WireInCallbackIsCallableCheck(fncallback, context, check_frame_state, effect,
1560                                 &control, &check_fail, &check_throw);
1561 
1562   // Start the loop.
1563   Node* vloop = k = WireInLoopStart(k, &control, &effect);
1564   Node *loop = control, *eloop = effect;
1565   checkpoint_params[4] = k;
1566 
1567   Node* continue_test =
1568       graph()->NewNode(simplified()->NumberLessThan(), k, original_length);
1569   Node* continue_branch = graph()->NewNode(common()->Branch(BranchHint::kTrue),
1570                                            continue_test, control);
1571 
1572   Node* if_true = graph()->NewNode(common()->IfTrue(), continue_branch);
1573   Node* if_false = graph()->NewNode(common()->IfFalse(), continue_branch);
1574   control = if_true;
1575 
1576   Node* frame_state = CreateJavaScriptBuiltinContinuationFrameState(
1577       jsgraph(), shared, Builtins::kArrayMapLoopEagerDeoptContinuation,
1578       node->InputAt(0), context, &checkpoint_params[0], stack_parameters,
1579       outer_frame_state, ContinuationFrameStateMode::EAGER);
1580 
1581   effect =
1582       graph()->NewNode(common()->Checkpoint(), frame_state, effect, control);
1583 
1584   // Make sure the map hasn't changed during the iteration
1585   effect =
1586       graph()->NewNode(simplified()->CheckMaps(CheckMapsFlag::kNone,
1587                                                receiver_maps, p.feedback()),
1588                        receiver, effect, control);
1589 
1590   Node* element =
1591       SafeLoadElement(kind, receiver, control, &effect, &k, p.feedback());
1592 
1593   Node* next_k =
1594       graph()->NewNode(simplified()->NumberAdd(), k, jsgraph()->OneConstant());
1595 
1596   Node* hole_true = nullptr;
1597   Node* hole_false = nullptr;
1598   Node* effect_true = effect;
1599 
1600   if (IsHoleyElementsKind(kind)) {
1601     // Holey elements kind require a hole check and skipping of the element in
1602     // the case of a hole.
1603     Node* check;
1604     if (IsDoubleElementsKind(kind)) {
1605       check = graph()->NewNode(simplified()->NumberIsFloat64Hole(), element);
1606     } else {
1607       check = graph()->NewNode(simplified()->ReferenceEqual(), element,
1608                                jsgraph()->TheHoleConstant());
1609     }
1610     Node* branch =
1611         graph()->NewNode(common()->Branch(BranchHint::kFalse), check, control);
1612     hole_true = graph()->NewNode(common()->IfTrue(), branch);
1613     hole_false = graph()->NewNode(common()->IfFalse(), branch);
1614     control = hole_false;
1615 
1616     // The contract is that we don't leak "the hole" into "user JavaScript",
1617     // so we must rename the {element} here to explicitly exclude "the hole"
1618     // from the type of {element}.
1619     element = effect = graph()->NewNode(
1620         common()->TypeGuard(Type::NonInternal()), element, effect, control);
1621   }
1622 
1623   // This frame state is dealt with by hand in
1624   // ArrayMapLoopLazyDeoptContinuation.
1625   frame_state = CreateJavaScriptBuiltinContinuationFrameState(
1626       jsgraph(), shared, Builtins::kArrayMapLoopLazyDeoptContinuation,
1627       node->InputAt(0), context, &checkpoint_params[0], stack_parameters,
1628       outer_frame_state, ContinuationFrameStateMode::LAZY);
1629 
1630   Node* callback_value = control = effect = graph()->NewNode(
1631       javascript()->Call(5, p.frequency()), fncallback, this_arg, element, k,
1632       receiver, context, frame_state, effect, control);
1633 
1634   // Rewire potential exception edges.
1635   Node* on_exception = nullptr;
1636   if (NodeProperties::IsExceptionalCall(node, &on_exception)) {
1637     RewirePostCallbackExceptionEdges(check_throw, on_exception, effect,
1638                                      &check_fail, &control);
1639   }
1640 
1641   // The array {a} should be HOLEY_SMI_ELEMENTS because we'd only come into this
1642   // loop if the input array length is non-zero, and "new Array({x > 0})" always
1643   // produces a HOLEY array.
1644   Handle<Map> double_map(Map::cast(native_context()->get(
1645                              Context::ArrayMapIndex(HOLEY_DOUBLE_ELEMENTS))),
1646                          isolate());
1647   Handle<Map> fast_map(
1648       Map::cast(native_context()->get(Context::ArrayMapIndex(HOLEY_ELEMENTS))),
1649       isolate());
1650   effect = graph()->NewNode(
1651       simplified()->TransitionAndStoreElement(double_map, fast_map), a, k,
1652       callback_value, effect, control);
1653 
1654   if (IsHoleyElementsKind(kind)) {
1655     Node* after_call_and_store_control = control;
1656     Node* after_call_and_store_effect = effect;
1657     control = hole_true;
1658     effect = effect_true;
1659 
1660     control = graph()->NewNode(common()->Merge(2), control,
1661                                after_call_and_store_control);
1662     effect = graph()->NewNode(common()->EffectPhi(2), effect,
1663                               after_call_and_store_effect, control);
1664   }
1665 
1666   WireInLoopEnd(loop, eloop, vloop, next_k, control, effect);
1667 
1668   control = if_false;
1669   effect = eloop;
1670 
1671   // Wire up the branch for the case when IsCallable fails for the callback.
1672   // Since {check_throw} is an unconditional throw, it's impossible to
1673   // return a successful completion. Therefore, we simply connect the successful
1674   // completion to the graph end.
1675   Node* throw_node =
1676       graph()->NewNode(common()->Throw(), check_throw, check_fail);
1677   NodeProperties::MergeControlToEnd(graph(), common(), throw_node);
1678 
1679   ReplaceWithValue(node, a, effect, control);
1680   return Replace(a);
1681 }
1682 
ReduceArrayFilter(Node * node,Handle<SharedFunctionInfo> shared)1683 Reduction JSCallReducer::ReduceArrayFilter(Node* node,
1684                                            Handle<SharedFunctionInfo> shared) {
1685   if (!FLAG_turbo_inline_array_builtins) return NoChange();
1686   DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
1687   CallParameters const& p = CallParametersOf(node->op());
1688   if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
1689     return NoChange();
1690   }
1691 
1692   Node* outer_frame_state = NodeProperties::GetFrameStateInput(node);
1693   Node* effect = NodeProperties::GetEffectInput(node);
1694   Node* control = NodeProperties::GetControlInput(node);
1695   Node* context = NodeProperties::GetContextInput(node);
1696   // Try to determine the {receiver} map.
1697   Node* receiver = NodeProperties::GetValueInput(node, 1);
1698   Node* fncallback = node->op()->ValueInputCount() > 2
1699                          ? NodeProperties::GetValueInput(node, 2)
1700                          : jsgraph()->UndefinedConstant();
1701   Node* this_arg = node->op()->ValueInputCount() > 3
1702                        ? NodeProperties::GetValueInput(node, 3)
1703                        : jsgraph()->UndefinedConstant();
1704   ZoneHandleSet<Map> receiver_maps;
1705   NodeProperties::InferReceiverMapsResult result =
1706       NodeProperties::InferReceiverMaps(isolate(), receiver, effect,
1707                                         &receiver_maps);
1708   if (result == NodeProperties::kNoReceiverMaps) return NoChange();
1709 
1710   // And ensure that any changes to the Array species constructor cause deopt.
1711   if (!isolate()->IsArraySpeciesLookupChainIntact()) return NoChange();
1712 
1713   const ElementsKind kind = receiver_maps[0]->elements_kind();
1714   // The output array is packed (filter doesn't visit holes).
1715   const ElementsKind packed_kind = GetPackedElementsKind(kind);
1716 
1717   for (Handle<Map> receiver_map : receiver_maps) {
1718     if (!CanInlineArrayIteratingBuiltin(isolate(), receiver_map)) {
1719       return NoChange();
1720     }
1721     // We can handle different maps, as long as their elements kind are the
1722     // same.
1723     if (receiver_map->elements_kind() != kind) return NoChange();
1724   }
1725 
1726   if (IsHoleyElementsKind(kind)) {
1727     dependencies()->DependOnProtector(
1728         PropertyCellRef(js_heap_broker(), factory()->no_elements_protector()));
1729   }
1730 
1731   dependencies()->DependOnProtector(
1732       PropertyCellRef(js_heap_broker(), factory()->array_species_protector()));
1733 
1734   Handle<Map> initial_map(
1735       Map::cast(native_context()->GetInitialJSArrayMap(packed_kind)),
1736       isolate());
1737 
1738   Node* k = jsgraph()->ZeroConstant();
1739   Node* to = jsgraph()->ZeroConstant();
1740 
1741   // If we have unreliable maps, we need a map check.
1742   if (result == NodeProperties::kUnreliableReceiverMaps) {
1743     effect =
1744         graph()->NewNode(simplified()->CheckMaps(CheckMapsFlag::kNone,
1745                                                  receiver_maps, p.feedback()),
1746                          receiver, effect, control);
1747   }
1748 
1749   Node* a;  // Construct the output array.
1750   {
1751     AllocationBuilder ab(jsgraph(), effect, control);
1752     ab.Allocate(initial_map->instance_size(), NOT_TENURED, Type::Array());
1753     ab.Store(AccessBuilder::ForMap(), initial_map);
1754     Node* empty_fixed_array = jsgraph()->EmptyFixedArrayConstant();
1755     ab.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), empty_fixed_array);
1756     ab.Store(AccessBuilder::ForJSObjectElements(), empty_fixed_array);
1757     ab.Store(AccessBuilder::ForJSArrayLength(packed_kind),
1758              jsgraph()->ZeroConstant());
1759     for (int i = 0; i < initial_map->GetInObjectProperties(); ++i) {
1760       ab.Store(AccessBuilder::ForJSObjectInObjectProperty(
1761                    MapRef(js_heap_broker(), initial_map), i),
1762                jsgraph()->UndefinedConstant());
1763     }
1764     a = effect = ab.Finish();
1765   }
1766 
1767   Node* original_length = effect = graph()->NewNode(
1768       simplified()->LoadField(AccessBuilder::ForJSArrayLength(kind)), receiver,
1769       effect, control);
1770 
1771   // Check whether the given callback function is callable. Note that this has
1772   // to happen outside the loop to make sure we also throw on empty arrays.
1773   Node* check_fail = nullptr;
1774   Node* check_throw = nullptr;
1775   {
1776     // This frame state doesn't ever call the deopt continuation, it's only
1777     // necessary to specifiy a continuation in order to handle the exceptional
1778     // case. We don't have all the values available to completely fill out
1779     // checkpoint_params yet, but that's okay because it'll never be called.
1780     // Therefore, "to" is mentioned twice, once standing in for the k_value
1781     // value.
1782     std::vector<Node*> checkpoint_params(
1783         {receiver, fncallback, this_arg, a, k, original_length, to, to});
1784     const int stack_parameters = static_cast<int>(checkpoint_params.size());
1785 
1786     Node* check_frame_state = CreateJavaScriptBuiltinContinuationFrameState(
1787         jsgraph(), shared, Builtins::kArrayFilterLoopLazyDeoptContinuation,
1788         node->InputAt(0), context, &checkpoint_params[0], stack_parameters,
1789         outer_frame_state, ContinuationFrameStateMode::LAZY);
1790     WireInCallbackIsCallableCheck(fncallback, context, check_frame_state,
1791                                   effect, &control, &check_fail, &check_throw);
1792   }
1793 
1794   // Start the loop.
1795   Node* vloop = k = WireInLoopStart(k, &control, &effect);
1796   Node *loop = control, *eloop = effect;
1797   Node* v_to_loop = to = graph()->NewNode(
1798       common()->Phi(MachineRepresentation::kTaggedSigned, 2), to, to, loop);
1799 
1800   Node* continue_test =
1801       graph()->NewNode(simplified()->NumberLessThan(), k, original_length);
1802   Node* continue_branch = graph()->NewNode(common()->Branch(BranchHint::kTrue),
1803                                            continue_test, control);
1804 
1805   Node* if_true = graph()->NewNode(common()->IfTrue(), continue_branch);
1806   Node* if_false = graph()->NewNode(common()->IfFalse(), continue_branch);
1807   control = if_true;
1808 
1809   {
1810     std::vector<Node*> checkpoint_params(
1811         {receiver, fncallback, this_arg, a, k, original_length, to});
1812     const int stack_parameters = static_cast<int>(checkpoint_params.size());
1813 
1814     Node* frame_state = CreateJavaScriptBuiltinContinuationFrameState(
1815         jsgraph(), shared, Builtins::kArrayFilterLoopEagerDeoptContinuation,
1816         node->InputAt(0), context, &checkpoint_params[0], stack_parameters,
1817         outer_frame_state, ContinuationFrameStateMode::EAGER);
1818 
1819     effect =
1820         graph()->NewNode(common()->Checkpoint(), frame_state, effect, control);
1821   }
1822 
1823   // Make sure the map hasn't changed during the iteration.
1824   effect =
1825       graph()->NewNode(simplified()->CheckMaps(CheckMapsFlag::kNone,
1826                                                receiver_maps, p.feedback()),
1827                        receiver, effect, control);
1828 
1829   Node* element =
1830       SafeLoadElement(kind, receiver, control, &effect, &k, p.feedback());
1831 
1832   Node* next_k =
1833       graph()->NewNode(simplified()->NumberAdd(), k, jsgraph()->OneConstant());
1834 
1835   Node* hole_true = nullptr;
1836   Node* hole_false = nullptr;
1837   Node* effect_true = effect;
1838   Node* hole_true_vto = to;
1839 
1840   if (IsHoleyElementsKind(kind)) {
1841     // Holey elements kind require a hole check and skipping of the element in
1842     // the case of a hole.
1843     Node* check;
1844     if (IsDoubleElementsKind(kind)) {
1845       check = graph()->NewNode(simplified()->NumberIsFloat64Hole(), element);
1846     } else {
1847       check = graph()->NewNode(simplified()->ReferenceEqual(), element,
1848                                jsgraph()->TheHoleConstant());
1849     }
1850     Node* branch =
1851         graph()->NewNode(common()->Branch(BranchHint::kFalse), check, control);
1852     hole_true = graph()->NewNode(common()->IfTrue(), branch);
1853     hole_false = graph()->NewNode(common()->IfFalse(), branch);
1854     control = hole_false;
1855 
1856     // The contract is that we don't leak "the hole" into "user JavaScript",
1857     // so we must rename the {element} here to explicitly exclude "the hole"
1858     // from the type of {element}.
1859     element = effect = graph()->NewNode(
1860         common()->TypeGuard(Type::NonInternal()), element, effect, control);
1861   }
1862 
1863   Node* callback_value = nullptr;
1864   {
1865     // This frame state is dealt with by hand in
1866     // Builtins::kArrayFilterLoopLazyDeoptContinuation.
1867     std::vector<Node*> checkpoint_params(
1868         {receiver, fncallback, this_arg, a, k, original_length, element, to});
1869     const int stack_parameters = static_cast<int>(checkpoint_params.size());
1870 
1871     Node* frame_state = CreateJavaScriptBuiltinContinuationFrameState(
1872         jsgraph(), shared, Builtins::kArrayFilterLoopLazyDeoptContinuation,
1873         node->InputAt(0), context, &checkpoint_params[0], stack_parameters,
1874         outer_frame_state, ContinuationFrameStateMode::LAZY);
1875 
1876     callback_value = control = effect = graph()->NewNode(
1877         javascript()->Call(5, p.frequency()), fncallback, this_arg, element, k,
1878         receiver, context, frame_state, effect, control);
1879   }
1880 
1881   // Rewire potential exception edges.
1882   Node* on_exception = nullptr;
1883   if (NodeProperties::IsExceptionalCall(node, &on_exception)) {
1884     RewirePostCallbackExceptionEdges(check_throw, on_exception, effect,
1885                                      &check_fail, &control);
1886   }
1887 
1888   // We need an eager frame state for right after the callback function
1889   // returned, just in case an attempt to grow the output array fails.
1890   //
1891   // Note that we are intentionally reusing the
1892   // Builtins::kArrayFilterLoopLazyDeoptContinuation as an *eager* entry
1893   // point in this case. This is safe, because re-evaluating a [ToBoolean]
1894   // coercion is safe.
1895   {
1896     std::vector<Node*> checkpoint_params({receiver, fncallback, this_arg, a, k,
1897                                           original_length, element, to,
1898                                           callback_value});
1899     const int stack_parameters = static_cast<int>(checkpoint_params.size());
1900     Node* frame_state = CreateJavaScriptBuiltinContinuationFrameState(
1901         jsgraph(), shared, Builtins::kArrayFilterLoopLazyDeoptContinuation,
1902         node->InputAt(0), context, &checkpoint_params[0], stack_parameters,
1903         outer_frame_state, ContinuationFrameStateMode::EAGER);
1904 
1905     effect =
1906         graph()->NewNode(common()->Checkpoint(), frame_state, effect, control);
1907   }
1908 
1909   // We have to coerce callback_value to boolean, and only store the element in
1910   // a if it's true. The checkpoint above protects against the case that
1911   // growing {a} fails.
1912   to = DoFilterPostCallbackWork(packed_kind, &control, &effect, a, to, element,
1913                                 callback_value);
1914 
1915   if (IsHoleyElementsKind(kind)) {
1916     Node* after_call_control = control;
1917     Node* after_call_effect = effect;
1918     control = hole_true;
1919     effect = effect_true;
1920 
1921     control = graph()->NewNode(common()->Merge(2), control, after_call_control);
1922     effect = graph()->NewNode(common()->EffectPhi(2), effect, after_call_effect,
1923                               control);
1924     to =
1925         graph()->NewNode(common()->Phi(MachineRepresentation::kTaggedSigned, 2),
1926                          hole_true_vto, to, control);
1927   }
1928 
1929   WireInLoopEnd(loop, eloop, vloop, next_k, control, effect);
1930   v_to_loop->ReplaceInput(1, to);
1931 
1932   control = if_false;
1933   effect = eloop;
1934 
1935   // Wire up the branch for the case when IsCallable fails for the callback.
1936   // Since {check_throw} is an unconditional throw, it's impossible to
1937   // return a successful completion. Therefore, we simply connect the successful
1938   // completion to the graph end.
1939   Node* throw_node =
1940       graph()->NewNode(common()->Throw(), check_throw, check_fail);
1941   NodeProperties::MergeControlToEnd(graph(), common(), throw_node);
1942 
1943   ReplaceWithValue(node, a, effect, control);
1944   return Replace(a);
1945 }
1946 
ReduceArrayFind(Node * node,ArrayFindVariant variant,Handle<SharedFunctionInfo> shared)1947 Reduction JSCallReducer::ReduceArrayFind(Node* node, ArrayFindVariant variant,
1948                                          Handle<SharedFunctionInfo> shared) {
1949   if (!FLAG_turbo_inline_array_builtins) return NoChange();
1950   DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
1951   CallParameters const& p = CallParametersOf(node->op());
1952   if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
1953     return NoChange();
1954   }
1955 
1956   Builtins::Name eager_continuation_builtin;
1957   Builtins::Name lazy_continuation_builtin;
1958   Builtins::Name after_callback_lazy_continuation_builtin;
1959   if (variant == ArrayFindVariant::kFind) {
1960     eager_continuation_builtin = Builtins::kArrayFindLoopEagerDeoptContinuation;
1961     lazy_continuation_builtin = Builtins::kArrayFindLoopLazyDeoptContinuation;
1962     after_callback_lazy_continuation_builtin =
1963         Builtins::kArrayFindLoopAfterCallbackLazyDeoptContinuation;
1964   } else {
1965     DCHECK_EQ(ArrayFindVariant::kFindIndex, variant);
1966     eager_continuation_builtin =
1967         Builtins::kArrayFindIndexLoopEagerDeoptContinuation;
1968     lazy_continuation_builtin =
1969         Builtins::kArrayFindIndexLoopLazyDeoptContinuation;
1970     after_callback_lazy_continuation_builtin =
1971         Builtins::kArrayFindIndexLoopAfterCallbackLazyDeoptContinuation;
1972   }
1973 
1974   Node* outer_frame_state = NodeProperties::GetFrameStateInput(node);
1975   Node* effect = NodeProperties::GetEffectInput(node);
1976   Node* control = NodeProperties::GetControlInput(node);
1977   Node* context = NodeProperties::GetContextInput(node);
1978 
1979   // Try to determine the {receiver} map.
1980   Node* receiver = NodeProperties::GetValueInput(node, 1);
1981   Node* fncallback = node->op()->ValueInputCount() > 2
1982                          ? NodeProperties::GetValueInput(node, 2)
1983                          : jsgraph()->UndefinedConstant();
1984   Node* this_arg = node->op()->ValueInputCount() > 3
1985                        ? NodeProperties::GetValueInput(node, 3)
1986                        : jsgraph()->UndefinedConstant();
1987   ZoneHandleSet<Map> receiver_maps;
1988   NodeProperties::InferReceiverMapsResult result =
1989       NodeProperties::InferReceiverMaps(isolate(), receiver, effect,
1990                                         &receiver_maps);
1991   if (result == NodeProperties::kNoReceiverMaps) return NoChange();
1992 
1993   const ElementsKind kind = receiver_maps[0]->elements_kind();
1994 
1995   for (Handle<Map> receiver_map : receiver_maps) {
1996     if (!CanInlineArrayIteratingBuiltin(isolate(), receiver_map))
1997       return NoChange();
1998     // We can handle different maps, as long as their elements kind are the
1999     // same.
2000     if (receiver_map->elements_kind() != kind) return NoChange();
2001   }
2002 
2003   // Install code dependencies on the {receiver} prototype maps and the
2004   // global array protector cell.
2005   dependencies()->DependOnProtector(
2006       PropertyCellRef(js_heap_broker(), factory()->no_elements_protector()));
2007 
2008   // If we have unreliable maps, we need a map check.
2009   if (result == NodeProperties::kUnreliableReceiverMaps) {
2010     effect =
2011         graph()->NewNode(simplified()->CheckMaps(CheckMapsFlag::kNone,
2012                                                  receiver_maps, p.feedback()),
2013                          receiver, effect, control);
2014   }
2015 
2016   Node* k = jsgraph()->ZeroConstant();
2017 
2018   Node* original_length = effect = graph()->NewNode(
2019       simplified()->LoadField(AccessBuilder::ForJSArrayLength(kind)), receiver,
2020       effect, control);
2021 
2022   std::vector<Node*> checkpoint_params(
2023       {receiver, fncallback, this_arg, k, original_length});
2024   const int stack_parameters = static_cast<int>(checkpoint_params.size());
2025 
2026   // Check whether the given callback function is callable. Note that this has
2027   // to happen outside the loop to make sure we also throw on empty arrays.
2028   Node* check_fail = nullptr;
2029   Node* check_throw = nullptr;
2030   {
2031     Node* frame_state = CreateJavaScriptBuiltinContinuationFrameState(
2032         jsgraph(), shared, lazy_continuation_builtin, node->InputAt(0), context,
2033         &checkpoint_params[0], stack_parameters, outer_frame_state,
2034         ContinuationFrameStateMode::LAZY);
2035     WireInCallbackIsCallableCheck(fncallback, context, frame_state, effect,
2036                                   &control, &check_fail, &check_throw);
2037   }
2038 
2039   // Start the loop.
2040   Node* vloop = k = WireInLoopStart(k, &control, &effect);
2041   Node *loop = control, *eloop = effect;
2042   checkpoint_params[3] = k;
2043 
2044   // Check if we've iterated past the last element of the array.
2045   Node* if_false = nullptr;
2046   {
2047     Node* continue_test =
2048         graph()->NewNode(simplified()->NumberLessThan(), k, original_length);
2049     Node* continue_branch = graph()->NewNode(
2050         common()->Branch(BranchHint::kTrue), continue_test, control);
2051     control = graph()->NewNode(common()->IfTrue(), continue_branch);
2052     if_false = graph()->NewNode(common()->IfFalse(), continue_branch);
2053   }
2054 
2055   // Check the map hasn't changed during the iteration.
2056   {
2057     Node* frame_state = CreateJavaScriptBuiltinContinuationFrameState(
2058         jsgraph(), shared, eager_continuation_builtin, node->InputAt(0),
2059         context, &checkpoint_params[0], stack_parameters, outer_frame_state,
2060         ContinuationFrameStateMode::EAGER);
2061 
2062     effect =
2063         graph()->NewNode(common()->Checkpoint(), frame_state, effect, control);
2064 
2065     effect =
2066         graph()->NewNode(simplified()->CheckMaps(CheckMapsFlag::kNone,
2067                                                  receiver_maps, p.feedback()),
2068                          receiver, effect, control);
2069   }
2070 
2071   // Load k-th element from receiver.
2072   Node* element =
2073       SafeLoadElement(kind, receiver, control, &effect, &k, p.feedback());
2074 
2075   // Increment k for the next iteration.
2076   Node* next_k = checkpoint_params[3] =
2077       graph()->NewNode(simplified()->NumberAdd(), k, jsgraph()->OneConstant());
2078 
2079   // Replace holes with undefined.
2080   if (kind == HOLEY_DOUBLE_ELEMENTS) {
2081     // TODO(7409): avoid deopt if not all uses of value are truncated.
2082     CheckFloat64HoleMode mode = CheckFloat64HoleMode::kAllowReturnHole;
2083     element = effect =
2084         graph()->NewNode(simplified()->CheckFloat64Hole(mode, p.feedback()),
2085                          element, effect, control);
2086   } else if (IsHoleyElementsKind(kind)) {
2087     element =
2088         graph()->NewNode(simplified()->ConvertTaggedHoleToUndefined(), element);
2089   }
2090 
2091   Node* if_found_return_value =
2092       (variant == ArrayFindVariant::kFind) ? element : k;
2093 
2094   // Call the callback.
2095   Node* callback_value = nullptr;
2096   {
2097     std::vector<Node*> call_checkpoint_params({receiver, fncallback, this_arg,
2098                                                next_k, original_length,
2099                                                if_found_return_value});
2100     const int call_stack_parameters =
2101         static_cast<int>(call_checkpoint_params.size());
2102 
2103     Node* frame_state = CreateJavaScriptBuiltinContinuationFrameState(
2104         jsgraph(), shared, after_callback_lazy_continuation_builtin,
2105         node->InputAt(0), context, &call_checkpoint_params[0],
2106         call_stack_parameters, outer_frame_state,
2107         ContinuationFrameStateMode::LAZY);
2108 
2109     callback_value = control = effect = graph()->NewNode(
2110         javascript()->Call(5, p.frequency()), fncallback, this_arg, element, k,
2111         receiver, context, frame_state, effect, control);
2112   }
2113 
2114   // Rewire potential exception edges.
2115   Node* on_exception = nullptr;
2116   if (NodeProperties::IsExceptionalCall(node, &on_exception)) {
2117     RewirePostCallbackExceptionEdges(check_throw, on_exception, effect,
2118                                      &check_fail, &control);
2119   }
2120 
2121   // Check whether the given callback function returned a truthy value.
2122   Node* boolean_result =
2123       graph()->NewNode(simplified()->ToBoolean(), callback_value);
2124   Node* efound_branch = effect;
2125   Node* found_branch = graph()->NewNode(common()->Branch(BranchHint::kFalse),
2126                                         boolean_result, control);
2127   Node* if_found = graph()->NewNode(common()->IfTrue(), found_branch);
2128   Node* if_notfound = graph()->NewNode(common()->IfFalse(), found_branch);
2129   control = if_notfound;
2130 
2131   // Close the loop.
2132   WireInLoopEnd(loop, eloop, vloop, next_k, control, effect);
2133 
2134   control = graph()->NewNode(common()->Merge(2), if_found, if_false);
2135   effect =
2136       graph()->NewNode(common()->EffectPhi(2), efound_branch, eloop, control);
2137 
2138   Node* if_not_found_value = (variant == ArrayFindVariant::kFind)
2139                                  ? jsgraph()->UndefinedConstant()
2140                                  : jsgraph()->MinusOneConstant();
2141   Node* return_value =
2142       graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
2143                        if_found_return_value, if_not_found_value, control);
2144 
2145   // Wire up the branch for the case when IsCallable fails for the callback.
2146   // Since {check_throw} is an unconditional throw, it's impossible to
2147   // return a successful completion. Therefore, we simply connect the successful
2148   // completion to the graph end.
2149   Node* throw_node =
2150       graph()->NewNode(common()->Throw(), check_throw, check_fail);
2151   NodeProperties::MergeControlToEnd(graph(), common(), throw_node);
2152 
2153   ReplaceWithValue(node, return_value, effect, control);
2154   return Replace(return_value);
2155 }
2156 
DoFilterPostCallbackWork(ElementsKind kind,Node ** control,Node ** effect,Node * a,Node * to,Node * element,Node * callback_value)2157 Node* JSCallReducer::DoFilterPostCallbackWork(ElementsKind kind, Node** control,
2158                                               Node** effect, Node* a, Node* to,
2159                                               Node* element,
2160                                               Node* callback_value) {
2161   Node* boolean_result =
2162       graph()->NewNode(simplified()->ToBoolean(), callback_value);
2163 
2164   Node* check_boolean_result =
2165       graph()->NewNode(simplified()->ReferenceEqual(), boolean_result,
2166                        jsgraph()->TrueConstant());
2167   Node* boolean_branch = graph()->NewNode(common()->Branch(BranchHint::kTrue),
2168                                           check_boolean_result, *control);
2169 
2170   Node* if_true = graph()->NewNode(common()->IfTrue(), boolean_branch);
2171   Node* etrue = *effect;
2172   Node* vtrue;
2173   {
2174     // Load the elements backing store of the {receiver}.
2175     Node* elements = etrue = graph()->NewNode(
2176         simplified()->LoadField(AccessBuilder::ForJSObjectElements()), a, etrue,
2177         if_true);
2178 
2179     DCHECK(TypeCache::Get().kFixedDoubleArrayLengthType.Is(
2180         TypeCache::Get().kFixedArrayLengthType));
2181     Node* checked_to = etrue = graph()->NewNode(
2182         common()->TypeGuard(TypeCache::Get().kFixedArrayLengthType), to, etrue,
2183         if_true);
2184     Node* elements_length = etrue = graph()->NewNode(
2185         simplified()->LoadField(AccessBuilder::ForFixedArrayLength()), elements,
2186         etrue, if_true);
2187 
2188     GrowFastElementsMode mode =
2189         IsDoubleElementsKind(kind) ? GrowFastElementsMode::kDoubleElements
2190                                    : GrowFastElementsMode::kSmiOrObjectElements;
2191     elements = etrue = graph()->NewNode(
2192         simplified()->MaybeGrowFastElements(mode, VectorSlotPair()), a,
2193         elements, checked_to, elements_length, etrue, if_true);
2194 
2195     // Update the length of {a}.
2196     Node* new_length_a = graph()->NewNode(simplified()->NumberAdd(), checked_to,
2197                                           jsgraph()->OneConstant());
2198 
2199     etrue = graph()->NewNode(
2200         simplified()->StoreField(AccessBuilder::ForJSArrayLength(kind)), a,
2201         new_length_a, etrue, if_true);
2202 
2203     // Append the value to the {elements}.
2204     etrue = graph()->NewNode(
2205         simplified()->StoreElement(AccessBuilder::ForFixedArrayElement(kind)),
2206         elements, checked_to, element, etrue, if_true);
2207 
2208     vtrue = new_length_a;
2209   }
2210 
2211   Node* if_false = graph()->NewNode(common()->IfFalse(), boolean_branch);
2212   Node* efalse = *effect;
2213   Node* vfalse = to;
2214 
2215   *control = graph()->NewNode(common()->Merge(2), if_true, if_false);
2216   *effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, *control);
2217   to = graph()->NewNode(common()->Phi(MachineRepresentation::kTaggedSigned, 2),
2218                         vtrue, vfalse, *control);
2219   return to;
2220 }
2221 
WireInCallbackIsCallableCheck(Node * fncallback,Node * context,Node * check_frame_state,Node * effect,Node ** control,Node ** check_fail,Node ** check_throw)2222 void JSCallReducer::WireInCallbackIsCallableCheck(
2223     Node* fncallback, Node* context, Node* check_frame_state, Node* effect,
2224     Node** control, Node** check_fail, Node** check_throw) {
2225   Node* check = graph()->NewNode(simplified()->ObjectIsCallable(), fncallback);
2226   Node* check_branch =
2227       graph()->NewNode(common()->Branch(BranchHint::kTrue), check, *control);
2228   *check_fail = graph()->NewNode(common()->IfFalse(), check_branch);
2229   *check_throw = *check_fail = graph()->NewNode(
2230       javascript()->CallRuntime(Runtime::kThrowTypeError, 2),
2231       jsgraph()->Constant(MessageTemplate::kCalledNonCallable), fncallback,
2232       context, check_frame_state, effect, *check_fail);
2233   *control = graph()->NewNode(common()->IfTrue(), check_branch);
2234 }
2235 
RewirePostCallbackExceptionEdges(Node * check_throw,Node * on_exception,Node * effect,Node ** check_fail,Node ** control)2236 void JSCallReducer::RewirePostCallbackExceptionEdges(Node* check_throw,
2237                                                      Node* on_exception,
2238                                                      Node* effect,
2239                                                      Node** check_fail,
2240                                                      Node** control) {
2241   // Create appropriate {IfException} and {IfSuccess} nodes.
2242   Node* if_exception0 =
2243       graph()->NewNode(common()->IfException(), check_throw, *check_fail);
2244   *check_fail = graph()->NewNode(common()->IfSuccess(), *check_fail);
2245   Node* if_exception1 =
2246       graph()->NewNode(common()->IfException(), effect, *control);
2247   *control = graph()->NewNode(common()->IfSuccess(), *control);
2248 
2249   // Join the exception edges.
2250   Node* merge =
2251       graph()->NewNode(common()->Merge(2), if_exception0, if_exception1);
2252   Node* ephi = graph()->NewNode(common()->EffectPhi(2), if_exception0,
2253                                 if_exception1, merge);
2254   Node* phi = graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
2255                                if_exception0, if_exception1, merge);
2256   ReplaceWithValue(on_exception, phi, ephi, merge);
2257 }
2258 
SafeLoadElement(ElementsKind kind,Node * receiver,Node * control,Node ** effect,Node ** k,const VectorSlotPair & feedback)2259 Node* JSCallReducer::SafeLoadElement(ElementsKind kind, Node* receiver,
2260                                      Node* control, Node** effect, Node** k,
2261                                      const VectorSlotPair& feedback) {
2262   // Make sure that the access is still in bounds, since the callback could have
2263   // changed the array's size.
2264   Node* length = *effect = graph()->NewNode(
2265       simplified()->LoadField(AccessBuilder::ForJSArrayLength(kind)), receiver,
2266       *effect, control);
2267   *k = *effect = graph()->NewNode(simplified()->CheckBounds(feedback), *k,
2268                                   length, *effect, control);
2269 
2270   // Reload the elements pointer before calling the callback, since the previous
2271   // callback might have resized the array causing the elements buffer to be
2272   // re-allocated.
2273   Node* elements = *effect = graph()->NewNode(
2274       simplified()->LoadField(AccessBuilder::ForJSObjectElements()), receiver,
2275       *effect, control);
2276 
2277   Node* element = *effect = graph()->NewNode(
2278       simplified()->LoadElement(AccessBuilder::ForFixedArrayElement(
2279           kind, LoadSensitivity::kCritical)),
2280       elements, *k, *effect, control);
2281   return element;
2282 }
2283 
ReduceArrayEvery(Node * node,Handle<SharedFunctionInfo> shared)2284 Reduction JSCallReducer::ReduceArrayEvery(Node* node,
2285                                           Handle<SharedFunctionInfo> shared) {
2286   if (!FLAG_turbo_inline_array_builtins) return NoChange();
2287   DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
2288   CallParameters const& p = CallParametersOf(node->op());
2289   if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
2290     return NoChange();
2291   }
2292 
2293   Node* outer_frame_state = NodeProperties::GetFrameStateInput(node);
2294   Node* effect = NodeProperties::GetEffectInput(node);
2295   Node* control = NodeProperties::GetControlInput(node);
2296   Node* context = NodeProperties::GetContextInput(node);
2297   // Try to determine the {receiver} map.
2298   Node* receiver = NodeProperties::GetValueInput(node, 1);
2299   Node* fncallback = node->op()->ValueInputCount() > 2
2300                          ? NodeProperties::GetValueInput(node, 2)
2301                          : jsgraph()->UndefinedConstant();
2302   Node* this_arg = node->op()->ValueInputCount() > 3
2303                        ? NodeProperties::GetValueInput(node, 3)
2304                        : jsgraph()->UndefinedConstant();
2305   ZoneHandleSet<Map> receiver_maps;
2306   NodeProperties::InferReceiverMapsResult result =
2307       NodeProperties::InferReceiverMaps(isolate(), receiver, effect,
2308                                         &receiver_maps);
2309   if (result == NodeProperties::kNoReceiverMaps) return NoChange();
2310 
2311   // And ensure that any changes to the Array species constructor cause deopt.
2312   if (!isolate()->IsArraySpeciesLookupChainIntact()) return NoChange();
2313 
2314   const ElementsKind kind = receiver_maps[0]->elements_kind();
2315 
2316   for (Handle<Map> receiver_map : receiver_maps) {
2317     if (!CanInlineArrayIteratingBuiltin(isolate(), receiver_map))
2318       return NoChange();
2319     // We can handle different maps, as long as their elements kind are the
2320     // same.
2321     if (receiver_map->elements_kind() != kind) return NoChange();
2322   }
2323 
2324   if (IsHoleyElementsKind(kind)) {
2325     dependencies()->DependOnProtector(
2326         PropertyCellRef(js_heap_broker(), factory()->no_elements_protector()));
2327   }
2328 
2329   dependencies()->DependOnProtector(
2330       PropertyCellRef(js_heap_broker(), factory()->array_species_protector()));
2331 
2332   // If we have unreliable maps, we need a map check.
2333   if (result == NodeProperties::kUnreliableReceiverMaps) {
2334     effect =
2335         graph()->NewNode(simplified()->CheckMaps(CheckMapsFlag::kNone,
2336                                                  receiver_maps, p.feedback()),
2337                          receiver, effect, control);
2338   }
2339 
2340   Node* k = jsgraph()->ZeroConstant();
2341 
2342   // Make sure the map hasn't changed before we construct the output array.
2343   effect = graph()->NewNode(
2344       simplified()->CheckMaps(CheckMapsFlag::kNone, receiver_maps), receiver,
2345       effect, control);
2346 
2347   Node* original_length = effect = graph()->NewNode(
2348       simplified()->LoadField(AccessBuilder::ForJSArrayLength(kind)), receiver,
2349       effect, control);
2350 
2351   // Check whether the given callback function is callable. Note that this has
2352   // to happen outside the loop to make sure we also throw on empty arrays.
2353   Node* check_fail = nullptr;
2354   Node* check_throw = nullptr;
2355   {
2356     // This frame state doesn't ever call the deopt continuation, it's only
2357     // necessary to specifiy a continuation in order to handle the exceptional
2358     // case.
2359     std::vector<Node*> checkpoint_params(
2360         {receiver, fncallback, this_arg, k, original_length});
2361     const int stack_parameters = static_cast<int>(checkpoint_params.size());
2362 
2363     Node* check_frame_state = CreateJavaScriptBuiltinContinuationFrameState(
2364         jsgraph(), shared, Builtins::kArrayEveryLoopLazyDeoptContinuation,
2365         node->InputAt(0), context, &checkpoint_params[0], stack_parameters,
2366         outer_frame_state, ContinuationFrameStateMode::LAZY);
2367     WireInCallbackIsCallableCheck(fncallback, context, check_frame_state,
2368                                   effect, &control, &check_fail, &check_throw);
2369   }
2370 
2371   // Start the loop.
2372   Node* vloop = k = WireInLoopStart(k, &control, &effect);
2373   Node *loop = control, *eloop = effect;
2374 
2375   Node* continue_test =
2376       graph()->NewNode(simplified()->NumberLessThan(), k, original_length);
2377   Node* continue_branch = graph()->NewNode(common()->Branch(BranchHint::kTrue),
2378                                            continue_test, control);
2379 
2380   Node* if_true = graph()->NewNode(common()->IfTrue(), continue_branch);
2381   Node* if_false = graph()->NewNode(common()->IfFalse(), continue_branch);
2382   control = if_true;
2383 
2384   {
2385     std::vector<Node*> checkpoint_params(
2386         {receiver, fncallback, this_arg, k, original_length});
2387     const int stack_parameters = static_cast<int>(checkpoint_params.size());
2388 
2389     Node* frame_state = CreateJavaScriptBuiltinContinuationFrameState(
2390         jsgraph(), shared, Builtins::kArrayEveryLoopEagerDeoptContinuation,
2391         node->InputAt(0), context, &checkpoint_params[0], stack_parameters,
2392         outer_frame_state, ContinuationFrameStateMode::EAGER);
2393 
2394     effect =
2395         graph()->NewNode(common()->Checkpoint(), frame_state, effect, control);
2396   }
2397 
2398   // Make sure the map hasn't changed during the iteration.
2399   effect =
2400       graph()->NewNode(simplified()->CheckMaps(CheckMapsFlag::kNone,
2401                                                receiver_maps, p.feedback()),
2402                        receiver, effect, control);
2403 
2404   Node* element =
2405       SafeLoadElement(kind, receiver, control, &effect, &k, p.feedback());
2406 
2407   Node* next_k =
2408       graph()->NewNode(simplified()->NumberAdd(), k, jsgraph()->OneConstant());
2409 
2410   Node* hole_true = nullptr;
2411   Node* hole_false = nullptr;
2412   Node* effect_true = effect;
2413 
2414   if (IsHoleyElementsKind(kind)) {
2415     // Holey elements kind require a hole check and skipping of the element in
2416     // the case of a hole.
2417     Node* check;
2418     if (IsDoubleElementsKind(kind)) {
2419       check = graph()->NewNode(simplified()->NumberIsFloat64Hole(), element);
2420     } else {
2421       check = graph()->NewNode(simplified()->ReferenceEqual(), element,
2422                                jsgraph()->TheHoleConstant());
2423     }
2424     Node* branch =
2425         graph()->NewNode(common()->Branch(BranchHint::kFalse), check, control);
2426     hole_true = graph()->NewNode(common()->IfTrue(), branch);
2427     hole_false = graph()->NewNode(common()->IfFalse(), branch);
2428     control = hole_false;
2429 
2430     // The contract is that we don't leak "the hole" into "user JavaScript",
2431     // so we must rename the {element} here to explicitly exclude "the hole"
2432     // from the type of {element}.
2433     element = effect = graph()->NewNode(
2434         common()->TypeGuard(Type::NonInternal()), element, effect, control);
2435   }
2436 
2437   Node* callback_value = nullptr;
2438   {
2439     // This frame state is dealt with by hand in
2440     // Builtins::kArrayEveryLoopLazyDeoptContinuation.
2441     std::vector<Node*> checkpoint_params(
2442         {receiver, fncallback, this_arg, k, original_length});
2443     const int stack_parameters = static_cast<int>(checkpoint_params.size());
2444 
2445     Node* frame_state = CreateJavaScriptBuiltinContinuationFrameState(
2446         jsgraph(), shared, Builtins::kArrayEveryLoopLazyDeoptContinuation,
2447         node->InputAt(0), context, &checkpoint_params[0], stack_parameters,
2448         outer_frame_state, ContinuationFrameStateMode::LAZY);
2449 
2450     callback_value = control = effect = graph()->NewNode(
2451         javascript()->Call(5, p.frequency()), fncallback, this_arg, element, k,
2452         receiver, context, frame_state, effect, control);
2453   }
2454 
2455   // Rewire potential exception edges.
2456   Node* on_exception = nullptr;
2457   if (NodeProperties::IsExceptionalCall(node, &on_exception)) {
2458     RewirePostCallbackExceptionEdges(check_throw, on_exception, effect,
2459                                      &check_fail, &control);
2460   }
2461 
2462   // We have to coerce callback_value to boolean.
2463   Node* if_false_callback;
2464   Node* efalse_callback;
2465   {
2466     Node* boolean_result =
2467         graph()->NewNode(simplified()->ToBoolean(), callback_value);
2468     Node* check_boolean_result =
2469         graph()->NewNode(simplified()->ReferenceEqual(), boolean_result,
2470                          jsgraph()->TrueConstant());
2471     Node* boolean_branch = graph()->NewNode(common()->Branch(BranchHint::kTrue),
2472                                             check_boolean_result, control);
2473     if_false_callback = graph()->NewNode(common()->IfFalse(), boolean_branch);
2474     efalse_callback = effect;
2475 
2476     // Nothing to do in the true case.
2477     control = graph()->NewNode(common()->IfTrue(), boolean_branch);
2478   }
2479 
2480   if (IsHoleyElementsKind(kind)) {
2481     Node* after_call_control = control;
2482     Node* after_call_effect = effect;
2483     control = hole_true;
2484     effect = effect_true;
2485 
2486     control = graph()->NewNode(common()->Merge(2), control, after_call_control);
2487     effect = graph()->NewNode(common()->EffectPhi(2), effect, after_call_effect,
2488                               control);
2489   }
2490 
2491   WireInLoopEnd(loop, eloop, vloop, next_k, control, effect);
2492 
2493   control = graph()->NewNode(common()->Merge(2), if_false, if_false_callback);
2494   effect =
2495       graph()->NewNode(common()->EffectPhi(2), eloop, efalse_callback, control);
2496   Node* return_value = graph()->NewNode(
2497       common()->Phi(MachineRepresentation::kTagged, 2),
2498       jsgraph()->TrueConstant(), jsgraph()->FalseConstant(), control);
2499 
2500   // Wire up the branch for the case when IsCallable fails for the callback.
2501   // Since {check_throw} is an unconditional throw, it's impossible to
2502   // return a successful completion. Therefore, we simply connect the successful
2503   // completion to the graph end.
2504   Node* throw_node =
2505       graph()->NewNode(common()->Throw(), check_throw, check_fail);
2506   NodeProperties::MergeControlToEnd(graph(), common(), throw_node);
2507 
2508   ReplaceWithValue(node, return_value, effect, control);
2509   return Replace(return_value);
2510 }
2511 
2512 namespace {
2513 
2514 // Returns the correct Callable for Array's indexOf based on the receiver's
2515 // |elements_kind| and |isolate|. Assumes that |elements_kind| is a fast one.
GetCallableForArrayIndexOf(ElementsKind elements_kind,Isolate * isolate)2516 Callable GetCallableForArrayIndexOf(ElementsKind elements_kind,
2517                                     Isolate* isolate) {
2518   switch (elements_kind) {
2519     case PACKED_SMI_ELEMENTS:
2520     case HOLEY_SMI_ELEMENTS:
2521     case PACKED_ELEMENTS:
2522     case HOLEY_ELEMENTS:
2523       return Builtins::CallableFor(isolate, Builtins::kArrayIndexOfSmiOrObject);
2524     case PACKED_DOUBLE_ELEMENTS:
2525       return Builtins::CallableFor(isolate,
2526                                    Builtins::kArrayIndexOfPackedDoubles);
2527     default:
2528       DCHECK_EQ(HOLEY_DOUBLE_ELEMENTS, elements_kind);
2529       return Builtins::CallableFor(isolate,
2530                                    Builtins::kArrayIndexOfHoleyDoubles);
2531   }
2532 }
2533 
2534 // Returns the correct Callable for Array's includes based on the receiver's
2535 // |elements_kind| and |isolate|. Assumes that |elements_kind| is a fast one.
GetCallableForArrayIncludes(ElementsKind elements_kind,Isolate * isolate)2536 Callable GetCallableForArrayIncludes(ElementsKind elements_kind,
2537                                      Isolate* isolate) {
2538   switch (elements_kind) {
2539     case PACKED_SMI_ELEMENTS:
2540     case HOLEY_SMI_ELEMENTS:
2541     case PACKED_ELEMENTS:
2542     case HOLEY_ELEMENTS:
2543       return Builtins::CallableFor(isolate,
2544                                    Builtins::kArrayIncludesSmiOrObject);
2545     case PACKED_DOUBLE_ELEMENTS:
2546       return Builtins::CallableFor(isolate,
2547                                    Builtins::kArrayIncludesPackedDoubles);
2548     default:
2549       DCHECK_EQ(HOLEY_DOUBLE_ELEMENTS, elements_kind);
2550       return Builtins::CallableFor(isolate,
2551                                    Builtins::kArrayIncludesHoleyDoubles);
2552   }
2553 }
2554 
2555 }  // namespace
2556 
2557 // For search_variant == kIndexOf:
2558 // ES6 Array.prototype.indexOf(searchElement[, fromIndex])
2559 // #sec-array.prototype.indexof
2560 // For search_variant == kIncludes:
2561 // ES7 Array.prototype.inludes(searchElement[, fromIndex])
2562 // #sec-array.prototype.includes
ReduceArrayIndexOfIncludes(SearchVariant search_variant,Node * node)2563 Reduction JSCallReducer::ReduceArrayIndexOfIncludes(
2564     SearchVariant search_variant, Node* node) {
2565   CallParameters const& p = CallParametersOf(node->op());
2566   if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
2567     return NoChange();
2568   }
2569 
2570   Handle<Map> receiver_map;
2571   if (!NodeProperties::GetMapWitness(isolate(), node).ToHandle(&receiver_map))
2572     return NoChange();
2573 
2574   if (!CanInlineArrayIteratingBuiltin(isolate(), receiver_map))
2575     return NoChange();
2576 
2577   if (IsHoleyElementsKind(receiver_map->elements_kind())) {
2578     dependencies()->DependOnProtector(
2579         PropertyCellRef(js_heap_broker(), factory()->no_elements_protector()));
2580   }
2581 
2582   Callable const callable =
2583       search_variant == SearchVariant::kIndexOf
2584           ? GetCallableForArrayIndexOf(receiver_map->elements_kind(), isolate())
2585           : GetCallableForArrayIncludes(receiver_map->elements_kind(),
2586                                         isolate());
2587   CallDescriptor const* const desc = Linkage::GetStubCallDescriptor(
2588       graph()->zone(), callable.descriptor(), 0, CallDescriptor::kNoFlags,
2589       Operator::kEliminatable);
2590   // The stub expects the following arguments: the receiver array, its elements,
2591   // the search_element, the array length, and the index to start searching
2592   // from.
2593   Node* receiver = NodeProperties::GetValueInput(node, 1);
2594   Node* effect = NodeProperties::GetEffectInput(node);
2595   Node* control = NodeProperties::GetControlInput(node);
2596   Node* elements = effect = graph()->NewNode(
2597       simplified()->LoadField(AccessBuilder::ForJSObjectElements()), receiver,
2598       effect, control);
2599   Node* search_element = (node->op()->ValueInputCount() >= 3)
2600                              ? NodeProperties::GetValueInput(node, 2)
2601                              : jsgraph()->UndefinedConstant();
2602   Node* length = effect = graph()->NewNode(
2603       simplified()->LoadField(
2604           AccessBuilder::ForJSArrayLength(receiver_map->elements_kind())),
2605       receiver, effect, control);
2606   Node* new_from_index = jsgraph()->ZeroConstant();
2607   if (node->op()->ValueInputCount() >= 4) {
2608     Node* from_index = NodeProperties::GetValueInput(node, 3);
2609     from_index = effect = graph()->NewNode(simplified()->CheckSmi(p.feedback()),
2610                                            from_index, effect, control);
2611     // If the index is negative, it means the offset from the end and therefore
2612     // needs to be added to the length. If the result is still negative, it
2613     // needs to be clamped to 0.
2614     new_from_index = graph()->NewNode(
2615         common()->Select(MachineRepresentation::kTagged, BranchHint::kFalse),
2616         graph()->NewNode(simplified()->NumberLessThan(), from_index,
2617                          jsgraph()->ZeroConstant()),
2618         graph()->NewNode(
2619             simplified()->NumberMax(),
2620             graph()->NewNode(simplified()->NumberAdd(), length, from_index),
2621             jsgraph()->ZeroConstant()),
2622         from_index);
2623   }
2624 
2625   Node* context = NodeProperties::GetContextInput(node);
2626   Node* replacement_node = effect = graph()->NewNode(
2627       common()->Call(desc), jsgraph()->HeapConstant(callable.code()), elements,
2628       search_element, length, new_from_index, context, effect);
2629   ReplaceWithValue(node, replacement_node, effect);
2630   return Replace(replacement_node);
2631 }
2632 
ReduceArraySome(Node * node,Handle<SharedFunctionInfo> shared)2633 Reduction JSCallReducer::ReduceArraySome(Node* node,
2634                                          Handle<SharedFunctionInfo> shared) {
2635   if (!FLAG_turbo_inline_array_builtins) return NoChange();
2636   DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
2637   CallParameters const& p = CallParametersOf(node->op());
2638   if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
2639     return NoChange();
2640   }
2641 
2642   Node* outer_frame_state = NodeProperties::GetFrameStateInput(node);
2643   Node* effect = NodeProperties::GetEffectInput(node);
2644   Node* control = NodeProperties::GetControlInput(node);
2645   Node* context = NodeProperties::GetContextInput(node);
2646   // Try to determine the {receiver} map.
2647   Node* receiver = NodeProperties::GetValueInput(node, 1);
2648   Node* fncallback = node->op()->ValueInputCount() > 2
2649                          ? NodeProperties::GetValueInput(node, 2)
2650                          : jsgraph()->UndefinedConstant();
2651   Node* this_arg = node->op()->ValueInputCount() > 3
2652                        ? NodeProperties::GetValueInput(node, 3)
2653                        : jsgraph()->UndefinedConstant();
2654   ZoneHandleSet<Map> receiver_maps;
2655   NodeProperties::InferReceiverMapsResult result =
2656       NodeProperties::InferReceiverMaps(isolate(), receiver, effect,
2657                                         &receiver_maps);
2658   if (result == NodeProperties::kNoReceiverMaps) return NoChange();
2659 
2660   // And ensure that any changes to the Array species constructor cause deopt.
2661   if (!isolate()->IsArraySpeciesLookupChainIntact()) return NoChange();
2662 
2663   if (receiver_maps.size() == 0) return NoChange();
2664 
2665   const ElementsKind kind = receiver_maps[0]->elements_kind();
2666 
2667   for (Handle<Map> receiver_map : receiver_maps) {
2668     if (!CanInlineArrayIteratingBuiltin(isolate(), receiver_map))
2669       return NoChange();
2670     // We can handle different maps, as long as their elements kind are the
2671     // same.
2672     if (receiver_map->elements_kind() != kind) return NoChange();
2673   }
2674 
2675   if (IsHoleyElementsKind(kind)) {
2676     dependencies()->DependOnProtector(
2677         PropertyCellRef(js_heap_broker(), factory()->no_elements_protector()));
2678   }
2679 
2680   dependencies()->DependOnProtector(
2681       PropertyCellRef(js_heap_broker(), factory()->array_species_protector()));
2682 
2683   Node* k = jsgraph()->ZeroConstant();
2684 
2685   // If we have unreliable maps, we need a map check.
2686   if (result == NodeProperties::kUnreliableReceiverMaps) {
2687     effect =
2688         graph()->NewNode(simplified()->CheckMaps(CheckMapsFlag::kNone,
2689                                                  receiver_maps, p.feedback()),
2690                          receiver, effect, control);
2691   }
2692 
2693   // Make sure the map hasn't changed before we construct the output array.
2694   effect = graph()->NewNode(
2695       simplified()->CheckMaps(CheckMapsFlag::kNone, receiver_maps), receiver,
2696       effect, control);
2697 
2698   Node* original_length = effect = graph()->NewNode(
2699       simplified()->LoadField(AccessBuilder::ForJSArrayLength(kind)), receiver,
2700       effect, control);
2701 
2702   // Check whether the given callback function is callable. Note that this has
2703   // to happen outside the loop to make sure we also throw on empty arrays.
2704   Node* check_fail = nullptr;
2705   Node* check_throw = nullptr;
2706   {
2707     // This frame state doesn't ever call the deopt continuation, it's only
2708     // necessary to specifiy a continuation in order to handle the exceptional
2709     // case.
2710     std::vector<Node*> checkpoint_params(
2711         {receiver, fncallback, this_arg, k, original_length});
2712     const int stack_parameters = static_cast<int>(checkpoint_params.size());
2713 
2714     Node* check_frame_state = CreateJavaScriptBuiltinContinuationFrameState(
2715         jsgraph(), shared, Builtins::kArraySomeLoopLazyDeoptContinuation,
2716         node->InputAt(0), context, &checkpoint_params[0], stack_parameters,
2717         outer_frame_state, ContinuationFrameStateMode::LAZY);
2718     WireInCallbackIsCallableCheck(fncallback, context, check_frame_state,
2719                                   effect, &control, &check_fail, &check_throw);
2720   }
2721 
2722   // Start the loop.
2723   Node* loop = control = graph()->NewNode(common()->Loop(2), control, control);
2724   Node* eloop = effect =
2725       graph()->NewNode(common()->EffectPhi(2), effect, effect, loop);
2726   Node* terminate = graph()->NewNode(common()->Terminate(), eloop, loop);
2727   NodeProperties::MergeControlToEnd(graph(), common(), terminate);
2728   Node* vloop = k = graph()->NewNode(
2729       common()->Phi(MachineRepresentation::kTagged, 2), k, k, loop);
2730 
2731   Node* continue_test =
2732       graph()->NewNode(simplified()->NumberLessThan(), k, original_length);
2733   Node* continue_branch = graph()->NewNode(common()->Branch(BranchHint::kTrue),
2734                                            continue_test, control);
2735 
2736   Node* if_true = graph()->NewNode(common()->IfTrue(), continue_branch);
2737   Node* if_false = graph()->NewNode(common()->IfFalse(), continue_branch);
2738   control = if_true;
2739 
2740   {
2741     std::vector<Node*> checkpoint_params(
2742         {receiver, fncallback, this_arg, k, original_length});
2743     const int stack_parameters = static_cast<int>(checkpoint_params.size());
2744 
2745     Node* frame_state = CreateJavaScriptBuiltinContinuationFrameState(
2746         jsgraph(), shared, Builtins::kArraySomeLoopEagerDeoptContinuation,
2747         node->InputAt(0), context, &checkpoint_params[0], stack_parameters,
2748         outer_frame_state, ContinuationFrameStateMode::EAGER);
2749 
2750     effect =
2751         graph()->NewNode(common()->Checkpoint(), frame_state, effect, control);
2752   }
2753 
2754   // Make sure the map hasn't changed during the iteration.
2755   effect =
2756       graph()->NewNode(simplified()->CheckMaps(CheckMapsFlag::kNone,
2757                                                receiver_maps, p.feedback()),
2758                        receiver, effect, control);
2759 
2760   Node* element =
2761       SafeLoadElement(kind, receiver, control, &effect, &k, p.feedback());
2762 
2763   Node* next_k =
2764       graph()->NewNode(simplified()->NumberAdd(), k, jsgraph()->OneConstant());
2765 
2766   Node* hole_true = nullptr;
2767   Node* hole_false = nullptr;
2768   Node* effect_true = effect;
2769 
2770   if (IsHoleyElementsKind(kind)) {
2771     // Holey elements kind require a hole check and skipping of the element in
2772     // the case of a hole.
2773     Node* check;
2774     if (IsDoubleElementsKind(kind)) {
2775       check = graph()->NewNode(simplified()->NumberIsFloat64Hole(), element);
2776     } else {
2777       check = graph()->NewNode(simplified()->ReferenceEqual(), element,
2778                                jsgraph()->TheHoleConstant());
2779     }
2780     Node* branch =
2781         graph()->NewNode(common()->Branch(BranchHint::kFalse), check, control);
2782     hole_true = graph()->NewNode(common()->IfTrue(), branch);
2783     hole_false = graph()->NewNode(common()->IfFalse(), branch);
2784     control = hole_false;
2785 
2786     // The contract is that we don't leak "the hole" into "user JavaScript",
2787     // so we must rename the {element} here to explicitly exclude "the hole"
2788     // from the type of {element}.
2789     element = effect = graph()->NewNode(
2790         common()->TypeGuard(Type::NonInternal()), element, effect, control);
2791   }
2792 
2793   Node* callback_value = nullptr;
2794   {
2795     // This frame state is dealt with by hand in
2796     // Builtins::kArrayEveryLoopLazyDeoptContinuation.
2797     std::vector<Node*> checkpoint_params(
2798         {receiver, fncallback, this_arg, k, original_length});
2799     const int stack_parameters = static_cast<int>(checkpoint_params.size());
2800 
2801     Node* frame_state = CreateJavaScriptBuiltinContinuationFrameState(
2802         jsgraph(), shared, Builtins::kArraySomeLoopLazyDeoptContinuation,
2803         node->InputAt(0), context, &checkpoint_params[0], stack_parameters,
2804         outer_frame_state, ContinuationFrameStateMode::LAZY);
2805 
2806     callback_value = control = effect = graph()->NewNode(
2807         javascript()->Call(5, p.frequency()), fncallback, this_arg, element, k,
2808         receiver, context, frame_state, effect, control);
2809   }
2810 
2811   // Rewire potential exception edges.
2812   Node* on_exception = nullptr;
2813   if (NodeProperties::IsExceptionalCall(node, &on_exception)) {
2814     RewirePostCallbackExceptionEdges(check_throw, on_exception, effect,
2815                                      &check_fail, &control);
2816   }
2817 
2818   // We have to coerce callback_value to boolean.
2819   Node* if_true_callback;
2820   Node* etrue_callback;
2821   {
2822     Node* boolean_result =
2823         graph()->NewNode(simplified()->ToBoolean(), callback_value);
2824     Node* check_boolean_result =
2825         graph()->NewNode(simplified()->ReferenceEqual(), boolean_result,
2826                          jsgraph()->TrueConstant());
2827     Node* boolean_branch = graph()->NewNode(
2828         common()->Branch(BranchHint::kFalse), check_boolean_result, control);
2829     if_true_callback = graph()->NewNode(common()->IfTrue(), boolean_branch);
2830     etrue_callback = effect;
2831 
2832     // Nothing to do in the false case.
2833     control = graph()->NewNode(common()->IfFalse(), boolean_branch);
2834   }
2835 
2836   if (IsHoleyElementsKind(kind)) {
2837     Node* after_call_control = control;
2838     Node* after_call_effect = effect;
2839     control = hole_true;
2840     effect = effect_true;
2841 
2842     control = graph()->NewNode(common()->Merge(2), control, after_call_control);
2843     effect = graph()->NewNode(common()->EffectPhi(2), effect, after_call_effect,
2844                               control);
2845   }
2846 
2847   loop->ReplaceInput(1, control);
2848   vloop->ReplaceInput(1, next_k);
2849   eloop->ReplaceInput(1, effect);
2850 
2851   control = graph()->NewNode(common()->Merge(2), if_false, if_true_callback);
2852   effect =
2853       graph()->NewNode(common()->EffectPhi(2), eloop, etrue_callback, control);
2854   Node* return_value = graph()->NewNode(
2855       common()->Phi(MachineRepresentation::kTagged, 2),
2856       jsgraph()->FalseConstant(), jsgraph()->TrueConstant(), control);
2857 
2858   // Wire up the branch for the case when IsCallable fails for the callback.
2859   // Since {check_throw} is an unconditional throw, it's impossible to
2860   // return a successful completion. Therefore, we simply connect the successful
2861   // completion to the graph end.
2862   Node* throw_node =
2863       graph()->NewNode(common()->Throw(), check_throw, check_fail);
2864   NodeProperties::MergeControlToEnd(graph(), common(), throw_node);
2865 
2866   ReplaceWithValue(node, return_value, effect, control);
2867   return Replace(return_value);
2868 }
2869 
ReduceCallApiFunction(Node * node,Handle<SharedFunctionInfo> shared)2870 Reduction JSCallReducer::ReduceCallApiFunction(
2871     Node* node, Handle<SharedFunctionInfo> shared) {
2872   DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
2873   CallParameters const& p = CallParametersOf(node->op());
2874   int const argc = static_cast<int>(p.arity()) - 2;
2875   Node* target = NodeProperties::GetValueInput(node, 0);
2876   Node* receiver = (p.convert_mode() == ConvertReceiverMode::kNullOrUndefined)
2877                        ? jsgraph()->HeapConstant(global_proxy())
2878                        : NodeProperties::GetValueInput(node, 1);
2879   Node* effect = NodeProperties::GetEffectInput(node);
2880   Node* control = NodeProperties::GetControlInput(node);
2881 
2882   Handle<FunctionTemplateInfo> function_template_info(
2883       FunctionTemplateInfo::cast(shared->function_data()), isolate());
2884 
2885   // CallApiCallbackStub expects the target in a register, so we count it out,
2886   // and counts the receiver as an implicit argument, so we count the receiver
2887   // out too.
2888   if (argc > CallApiCallbackStub::kArgMax) return NoChange();
2889 
2890   // Infer the {receiver} maps, and check if we can inline the API function
2891   // callback based on those.
2892   ZoneHandleSet<Map> receiver_maps;
2893   NodeProperties::InferReceiverMapsResult result =
2894       NodeProperties::InferReceiverMaps(isolate(), receiver, effect,
2895                                         &receiver_maps);
2896   if (result == NodeProperties::kNoReceiverMaps) return NoChange();
2897   for (size_t i = 0; i < receiver_maps.size(); ++i) {
2898     Handle<Map> receiver_map = receiver_maps[i];
2899     if (!receiver_map->IsJSObjectMap() ||
2900         (!function_template_info->accept_any_receiver() &&
2901          receiver_map->is_access_check_needed())) {
2902       return NoChange();
2903     }
2904     // In case of unreliable {receiver} information, the {receiver_maps}
2905     // must all be stable in order to consume the information.
2906     if (result == NodeProperties::kUnreliableReceiverMaps) {
2907       if (!receiver_map->is_stable()) return NoChange();
2908     }
2909   }
2910 
2911   // See if we can constant-fold the compatible receiver checks.
2912   CallOptimization call_optimization(isolate(), function_template_info);
2913   if (!call_optimization.is_simple_api_call()) return NoChange();
2914   CallOptimization::HolderLookup lookup;
2915   Handle<JSObject> api_holder =
2916       call_optimization.LookupHolderOfExpectedType(receiver_maps[0], &lookup);
2917   if (lookup == CallOptimization::kHolderNotFound) return NoChange();
2918   for (size_t i = 1; i < receiver_maps.size(); ++i) {
2919     CallOptimization::HolderLookup lookupi;
2920     Handle<JSObject> holder = call_optimization.LookupHolderOfExpectedType(
2921         receiver_maps[i], &lookupi);
2922     if (lookup != lookupi) return NoChange();
2923     if (!api_holder.is_identical_to(holder)) return NoChange();
2924   }
2925 
2926   // Install stability dependencies for unreliable {receiver_maps}.
2927   if (result == NodeProperties::kUnreliableReceiverMaps) {
2928     for (size_t i = 0; i < receiver_maps.size(); ++i) {
2929       dependencies()->DependOnStableMap(
2930           MapRef(js_heap_broker(), receiver_maps[i]));
2931     }
2932   }
2933 
2934   // Load the {target}s context.
2935   Node* context = effect = graph()->NewNode(
2936       simplified()->LoadField(AccessBuilder::ForJSFunctionContext()), target,
2937       effect, control);
2938 
2939   // CallApiCallbackStub's register arguments: code, target, call data, holder,
2940   // function address.
2941   // TODO(turbofan): Consider introducing a JSCallApiCallback operator for
2942   // this and lower it during JSGenericLowering, and unify this with the
2943   // JSNativeContextSpecialization::InlineApiCall method a bit.
2944   Handle<CallHandlerInfo> call_handler_info(
2945       CallHandlerInfo::cast(function_template_info->call_code()), isolate());
2946   Handle<Object> data(call_handler_info->data(), isolate());
2947   Callable call_api_callback = CodeFactory::CallApiCallback(isolate(), argc);
2948   CallInterfaceDescriptor cid = call_api_callback.descriptor();
2949   auto call_descriptor = Linkage::GetStubCallDescriptor(
2950       graph()->zone(), cid,
2951       cid.GetStackParameterCount() + argc + 1 /* implicit receiver */,
2952       CallDescriptor::kNeedsFrameState);
2953   ApiFunction api_function(v8::ToCData<Address>(call_handler_info->callback()));
2954   Node* holder = lookup == CallOptimization::kHolderFound
2955                      ? jsgraph()->HeapConstant(api_holder)
2956                      : receiver;
2957   ExternalReference function_reference = ExternalReference::Create(
2958       &api_function, ExternalReference::DIRECT_API_CALL);
2959   node->InsertInput(graph()->zone(), 0,
2960                     jsgraph()->HeapConstant(call_api_callback.code()));
2961   node->ReplaceInput(1, context);
2962   node->InsertInput(graph()->zone(), 2, jsgraph()->Constant(data));
2963   node->InsertInput(graph()->zone(), 3, holder);
2964   node->InsertInput(graph()->zone(), 4,
2965                     jsgraph()->ExternalConstant(function_reference));
2966   node->ReplaceInput(5, receiver);
2967   node->RemoveInput(6 + argc);           // Remove context input.
2968   node->ReplaceInput(7 + argc, effect);  // Update effect input.
2969   NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
2970   return Changed(node);
2971 }
2972 
2973 namespace {
2974 
2975 // Check whether elements aren't mutated; we play it extremely safe here by
2976 // explicitly checking that {node} is only used by {LoadField} or {LoadElement}.
IsSafeArgumentsElements(Node * node)2977 bool IsSafeArgumentsElements(Node* node) {
2978   for (Edge const edge : node->use_edges()) {
2979     if (!NodeProperties::IsValueEdge(edge)) continue;
2980     if (edge.from()->opcode() != IrOpcode::kLoadField &&
2981         edge.from()->opcode() != IrOpcode::kLoadElement) {
2982       return false;
2983     }
2984   }
2985   return true;
2986 }
2987 
2988 }  // namespace
2989 
ReduceCallOrConstructWithArrayLikeOrSpread(Node * node,int arity,CallFrequency const & frequency,VectorSlotPair const & feedback)2990 Reduction JSCallReducer::ReduceCallOrConstructWithArrayLikeOrSpread(
2991     Node* node, int arity, CallFrequency const& frequency,
2992     VectorSlotPair const& feedback) {
2993   DCHECK(node->opcode() == IrOpcode::kJSCallWithArrayLike ||
2994          node->opcode() == IrOpcode::kJSCallWithSpread ||
2995          node->opcode() == IrOpcode::kJSConstructWithArrayLike ||
2996          node->opcode() == IrOpcode::kJSConstructWithSpread);
2997 
2998   // In case of a call/construct with spread, we need to
2999   // ensure that it's safe to avoid the actual iteration.
3000   if ((node->opcode() == IrOpcode::kJSCallWithSpread ||
3001        node->opcode() == IrOpcode::kJSConstructWithSpread) &&
3002       !isolate()->IsArrayIteratorLookupChainIntact()) {
3003     return NoChange();
3004   }
3005 
3006   // Check if {arguments_list} is an arguments object, and {node} is the only
3007   // value user of {arguments_list} (except for value uses in frame states).
3008   Node* arguments_list = NodeProperties::GetValueInput(node, arity);
3009   if (arguments_list->opcode() != IrOpcode::kJSCreateArguments) {
3010     return NoChange();
3011   }
3012   for (Edge edge : arguments_list->use_edges()) {
3013     if (!NodeProperties::IsValueEdge(edge)) continue;
3014     Node* const user = edge.from();
3015     switch (user->opcode()) {
3016       case IrOpcode::kCheckMaps:
3017       case IrOpcode::kFrameState:
3018       case IrOpcode::kStateValues:
3019       case IrOpcode::kReferenceEqual:
3020       case IrOpcode::kReturn:
3021         // Ignore safe uses that definitely don't mess with the arguments.
3022         continue;
3023       case IrOpcode::kLoadField: {
3024         DCHECK_EQ(arguments_list, user->InputAt(0));
3025         FieldAccess const& access = FieldAccessOf(user->op());
3026         if (access.offset == JSArray::kLengthOffset) {
3027           // Ignore uses for arguments#length.
3028           STATIC_ASSERT(JSArray::kLengthOffset ==
3029                         JSArgumentsObject::kLengthOffset);
3030           continue;
3031         } else if (access.offset == JSObject::kElementsOffset) {
3032           // Ignore safe uses for arguments#elements.
3033           if (IsSafeArgumentsElements(user)) continue;
3034         }
3035         break;
3036       }
3037       case IrOpcode::kJSCallWithArrayLike:
3038         // Ignore uses as argumentsList input to calls with array like.
3039         if (user->InputAt(2) == arguments_list) continue;
3040         break;
3041       case IrOpcode::kJSConstructWithArrayLike:
3042         // Ignore uses as argumentsList input to calls with array like.
3043         if (user->InputAt(1) == arguments_list) continue;
3044         break;
3045       case IrOpcode::kJSCallWithSpread: {
3046         // Ignore uses as spread input to calls with spread.
3047         CallParameters p = CallParametersOf(user->op());
3048         int const arity = static_cast<int>(p.arity() - 1);
3049         if (user->InputAt(arity) == arguments_list) continue;
3050         break;
3051       }
3052       case IrOpcode::kJSConstructWithSpread: {
3053         // Ignore uses as spread input to construct with spread.
3054         ConstructParameters p = ConstructParametersOf(user->op());
3055         int const arity = static_cast<int>(p.arity() - 2);
3056         if (user->InputAt(arity) == arguments_list) continue;
3057         break;
3058       }
3059       default:
3060         break;
3061     }
3062     // We cannot currently reduce the {node} to something better than what
3063     // it already is, but we might be able to do something about the {node}
3064     // later, so put it on the waitlist and try again during finalization.
3065     waitlist_.insert(node);
3066     return NoChange();
3067   }
3068 
3069   // Get to the actual frame state from which to extract the arguments;
3070   // we can only optimize this in case the {node} was already inlined into
3071   // some other function (and same for the {arguments_list}).
3072   CreateArgumentsType const type = CreateArgumentsTypeOf(arguments_list->op());
3073   Node* frame_state = NodeProperties::GetFrameStateInput(arguments_list);
3074   FrameStateInfo state_info = FrameStateInfoOf(frame_state->op());
3075   int start_index = 0;
3076   // Determine the formal parameter count;
3077   Handle<SharedFunctionInfo> shared;
3078   if (!state_info.shared_info().ToHandle(&shared)) return NoChange();
3079   int formal_parameter_count = shared->internal_formal_parameter_count();
3080   if (type == CreateArgumentsType::kMappedArguments) {
3081     // Mapped arguments (sloppy mode) that are aliased can only be handled
3082     // here if there's no side-effect between the {node} and the {arg_array}.
3083     // TODO(turbofan): Further relax this constraint.
3084     if (formal_parameter_count != 0) {
3085       Node* effect = NodeProperties::GetEffectInput(node);
3086       if (!NodeProperties::NoObservableSideEffectBetween(effect,
3087                                                          arguments_list)) {
3088         return NoChange();
3089       }
3090     }
3091   } else if (type == CreateArgumentsType::kRestParameter) {
3092     start_index = formal_parameter_count;
3093   }
3094 
3095   // For call/construct with spread, we need to also install a code
3096   // dependency on the array iterator lookup protector cell to ensure
3097   // that no one messed with the %ArrayIteratorPrototype%.next method.
3098   if (node->opcode() == IrOpcode::kJSCallWithSpread ||
3099       node->opcode() == IrOpcode::kJSConstructWithSpread) {
3100     dependencies()->DependOnProtector(PropertyCellRef(
3101         js_heap_broker(), factory()->array_iterator_protector()));
3102   }
3103 
3104   // Remove the {arguments_list} input from the {node}.
3105   node->RemoveInput(arity--);
3106   // Check if are spreading to inlined arguments or to the arguments of
3107   // the outermost function.
3108   Node* outer_state = frame_state->InputAt(kFrameStateOuterStateInput);
3109   if (outer_state->opcode() != IrOpcode::kFrameState) {
3110     Operator const* op =
3111         (node->opcode() == IrOpcode::kJSCallWithArrayLike ||
3112          node->opcode() == IrOpcode::kJSCallWithSpread)
3113             ? javascript()->CallForwardVarargs(arity + 1, start_index)
3114             : javascript()->ConstructForwardVarargs(arity + 2, start_index);
3115     NodeProperties::ChangeOp(node, op);
3116     return Changed(node);
3117   }
3118   // Get to the actual frame state from which to extract the arguments;
3119   // we can only optimize this in case the {node} was already inlined into
3120   // some other function (and same for the {arg_array}).
3121   FrameStateInfo outer_info = FrameStateInfoOf(outer_state->op());
3122   if (outer_info.type() == FrameStateType::kArgumentsAdaptor) {
3123     // Need to take the parameters from the arguments adaptor.
3124     frame_state = outer_state;
3125   }
3126   // Add the actual parameters to the {node}, skipping the receiver.
3127   Node* const parameters = frame_state->InputAt(kFrameStateParametersInput);
3128   for (int i = start_index + 1; i < parameters->InputCount(); ++i) {
3129     node->InsertInput(graph()->zone(), static_cast<int>(++arity),
3130                       parameters->InputAt(i));
3131   }
3132 
3133   if (node->opcode() == IrOpcode::kJSCallWithArrayLike ||
3134       node->opcode() == IrOpcode::kJSCallWithSpread) {
3135     NodeProperties::ChangeOp(
3136         node, javascript()->Call(arity + 1, frequency, feedback));
3137     Reduction const reduction = ReduceJSCall(node);
3138     return reduction.Changed() ? reduction : Changed(node);
3139   } else {
3140     NodeProperties::ChangeOp(
3141         node, javascript()->Construct(arity + 2, frequency, feedback));
3142     Node* new_target = NodeProperties::GetValueInput(node, arity + 1);
3143     Node* frame_state = NodeProperties::GetFrameStateInput(node);
3144     Node* context = NodeProperties::GetContextInput(node);
3145     Node* effect = NodeProperties::GetEffectInput(node);
3146     Node* control = NodeProperties::GetControlInput(node);
3147 
3148     // Check whether the given new target value is a constructor function. The
3149     // replacement {JSConstruct} operator only checks the passed target value
3150     // but relies on the new target value to be implicitly valid.
3151     Node* check =
3152         graph()->NewNode(simplified()->ObjectIsConstructor(), new_target);
3153     Node* check_branch =
3154         graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
3155     Node* check_fail = graph()->NewNode(common()->IfFalse(), check_branch);
3156     Node* check_throw = check_fail =
3157         graph()->NewNode(javascript()->CallRuntime(Runtime::kThrowTypeError, 2),
3158                          jsgraph()->Constant(MessageTemplate::kNotConstructor),
3159                          new_target, context, frame_state, effect, check_fail);
3160     control = graph()->NewNode(common()->IfTrue(), check_branch);
3161     NodeProperties::ReplaceControlInput(node, control);
3162 
3163     // Rewire potential exception edges.
3164     Node* on_exception = nullptr;
3165     if (NodeProperties::IsExceptionalCall(node, &on_exception)) {
3166       // Create appropriate {IfException}  and {IfSuccess} nodes.
3167       Node* if_exception =
3168           graph()->NewNode(common()->IfException(), check_throw, check_fail);
3169       check_fail = graph()->NewNode(common()->IfSuccess(), check_fail);
3170 
3171       // Join the exception edges.
3172       Node* merge =
3173           graph()->NewNode(common()->Merge(2), if_exception, on_exception);
3174       Node* ephi = graph()->NewNode(common()->EffectPhi(2), if_exception,
3175                                     on_exception, merge);
3176       Node* phi =
3177           graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
3178                            if_exception, on_exception, merge);
3179       ReplaceWithValue(on_exception, phi, ephi, merge);
3180       merge->ReplaceInput(1, on_exception);
3181       ephi->ReplaceInput(1, on_exception);
3182       phi->ReplaceInput(1, on_exception);
3183     }
3184 
3185     // The above %ThrowTypeError runtime call is an unconditional throw, making
3186     // it impossible to return a successful completion in this case. We simply
3187     // connect the successful completion to the graph end.
3188     Node* throw_node =
3189         graph()->NewNode(common()->Throw(), check_throw, check_fail);
3190     NodeProperties::MergeControlToEnd(graph(), common(), throw_node);
3191 
3192     Reduction const reduction = ReduceJSConstruct(node);
3193     return reduction.Changed() ? reduction : Changed(node);
3194   }
3195 }
3196 
3197 namespace {
3198 
ShouldUseCallICFeedback(Node * node)3199 bool ShouldUseCallICFeedback(Node* node) {
3200   HeapObjectMatcher m(node);
3201   if (m.HasValue() || m.IsJSCreateClosure()) {
3202     // Don't use CallIC feedback when we know the function
3203     // being called, i.e. either know the closure itself or
3204     // at least the SharedFunctionInfo.
3205     return false;
3206   } else if (m.IsPhi()) {
3207     // Protect against endless loops here.
3208     Node* control = NodeProperties::GetControlInput(node);
3209     if (control->opcode() == IrOpcode::kLoop) return false;
3210     // Check if {node} is a Phi of nodes which shouldn't
3211     // use CallIC feedback (not looking through loops).
3212     int const value_input_count = m.node()->op()->ValueInputCount();
3213     for (int n = 0; n < value_input_count; ++n) {
3214       if (ShouldUseCallICFeedback(node->InputAt(n))) return true;
3215     }
3216     return false;
3217   }
3218   return true;
3219 }
3220 
3221 }  // namespace
3222 
ReduceJSCall(Node * node)3223 Reduction JSCallReducer::ReduceJSCall(Node* node) {
3224   DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
3225   CallParameters const& p = CallParametersOf(node->op());
3226   Node* target = NodeProperties::GetValueInput(node, 0);
3227   Node* control = NodeProperties::GetControlInput(node);
3228   Node* effect = NodeProperties::GetEffectInput(node);
3229   size_t arity = p.arity();
3230   DCHECK_LE(2u, arity);
3231 
3232   // Try to specialize JSCall {node}s with constant {target}s.
3233   HeapObjectMatcher m(target);
3234   if (m.HasValue()) {
3235     if (m.Value()->IsJSFunction()) {
3236       Handle<JSFunction> function = Handle<JSFunction>::cast(m.Value());
3237 
3238       // Don't inline cross native context.
3239       if (function->native_context() != *native_context()) return NoChange();
3240 
3241       return ReduceJSCall(node, handle(function->shared(), isolate()));
3242     } else if (m.Value()->IsJSBoundFunction()) {
3243       Handle<JSBoundFunction> function =
3244           Handle<JSBoundFunction>::cast(m.Value());
3245       Handle<JSReceiver> bound_target_function(
3246           function->bound_target_function(), isolate());
3247       Handle<Object> bound_this(function->bound_this(), isolate());
3248       Handle<FixedArray> bound_arguments(function->bound_arguments(),
3249                                          isolate());
3250       ConvertReceiverMode const convert_mode =
3251           (bound_this->IsNullOrUndefined(isolate()))
3252               ? ConvertReceiverMode::kNullOrUndefined
3253               : ConvertReceiverMode::kNotNullOrUndefined;
3254       // Patch {node} to use [[BoundTargetFunction]] and [[BoundThis]].
3255       NodeProperties::ReplaceValueInput(
3256           node, jsgraph()->Constant(bound_target_function), 0);
3257       NodeProperties::ReplaceValueInput(node, jsgraph()->Constant(bound_this),
3258                                         1);
3259       // Insert the [[BoundArguments]] for {node}.
3260       for (int i = 0; i < bound_arguments->length(); ++i) {
3261         node->InsertInput(
3262             graph()->zone(), i + 2,
3263             jsgraph()->Constant(handle(bound_arguments->get(i), isolate())));
3264         arity++;
3265       }
3266       NodeProperties::ChangeOp(
3267           node, javascript()->Call(arity, p.frequency(), VectorSlotPair(),
3268                                    convert_mode));
3269       // Try to further reduce the JSCall {node}.
3270       Reduction const reduction = ReduceJSCall(node);
3271       return reduction.Changed() ? reduction : Changed(node);
3272     }
3273 
3274     // Don't mess with other {node}s that have a constant {target}.
3275     // TODO(bmeurer): Also support proxies here.
3276     return NoChange();
3277   }
3278 
3279   // If {target} is the result of a JSCreateClosure operation, we can
3280   // just immediately try to inline based on the SharedFunctionInfo,
3281   // since TurboFan generally doesn't inline cross-context, and hence
3282   // the {target} must have the same native context as the call site.
3283   if (target->opcode() == IrOpcode::kJSCreateClosure) {
3284     CreateClosureParameters const& p = CreateClosureParametersOf(target->op());
3285     return ReduceJSCall(node, p.shared_info());
3286   }
3287 
3288   // If {target} is the result of a JSCreateBoundFunction operation,
3289   // we can just fold the construction and call the bound target
3290   // function directly instead.
3291   if (target->opcode() == IrOpcode::kJSCreateBoundFunction) {
3292     Node* bound_target_function = NodeProperties::GetValueInput(target, 0);
3293     Node* bound_this = NodeProperties::GetValueInput(target, 1);
3294     int const bound_arguments_length =
3295         static_cast<int>(CreateBoundFunctionParametersOf(target->op()).arity());
3296 
3297     // Patch the {node} to use [[BoundTargetFunction]] and [[BoundThis]].
3298     NodeProperties::ReplaceValueInput(node, bound_target_function, 0);
3299     NodeProperties::ReplaceValueInput(node, bound_this, 1);
3300 
3301     // Insert the [[BoundArguments]] for {node}.
3302     for (int i = 0; i < bound_arguments_length; ++i) {
3303       Node* value = NodeProperties::GetValueInput(target, 2 + i);
3304       node->InsertInput(graph()->zone(), 2 + i, value);
3305       arity++;
3306     }
3307 
3308     // Update the JSCall operator on {node}.
3309     ConvertReceiverMode const convert_mode =
3310         NodeProperties::CanBeNullOrUndefined(isolate(), bound_this, effect)
3311             ? ConvertReceiverMode::kAny
3312             : ConvertReceiverMode::kNotNullOrUndefined;
3313     NodeProperties::ChangeOp(
3314         node, javascript()->Call(arity, p.frequency(), VectorSlotPair(),
3315                                  convert_mode));
3316 
3317     // Try to further reduce the JSCall {node}.
3318     Reduction const reduction = ReduceJSCall(node);
3319     return reduction.Changed() ? reduction : Changed(node);
3320   }
3321 
3322   // Extract feedback from the {node} using the FeedbackNexus.
3323   if (!p.feedback().IsValid()) return NoChange();
3324   FeedbackNexus nexus(p.feedback().vector(), p.feedback().slot());
3325   if (nexus.IsUninitialized()) {
3326     if (flags() & kBailoutOnUninitialized) {
3327       // Introduce a SOFT deopt if the call {node} wasn't executed so far.
3328       return ReduceSoftDeoptimize(
3329           node, DeoptimizeReason::kInsufficientTypeFeedbackForCall);
3330     }
3331     return NoChange();
3332   }
3333 
3334   HeapObject* heap_object;
3335   if (nexus.GetFeedback()->ToWeakHeapObject(&heap_object)) {
3336     Handle<HeapObject> feedback(heap_object, isolate());
3337     // Check if we want to use CallIC feedback here.
3338     if (!ShouldUseCallICFeedback(target)) return NoChange();
3339 
3340     if (feedback->IsCallable()) {
3341       Node* target_function = jsgraph()->Constant(feedback);
3342 
3343       // Check that the {target} is still the {target_function}.
3344       Node* check = graph()->NewNode(simplified()->ReferenceEqual(), target,
3345                                      target_function);
3346       effect = graph()->NewNode(
3347           simplified()->CheckIf(DeoptimizeReason::kWrongCallTarget), check,
3348           effect, control);
3349 
3350       // Specialize the JSCall node to the {target_function}.
3351       NodeProperties::ReplaceValueInput(node, target_function, 0);
3352       NodeProperties::ReplaceEffectInput(node, effect);
3353 
3354       // Try to further reduce the JSCall {node}.
3355       Reduction const reduction = ReduceJSCall(node);
3356       return reduction.Changed() ? reduction : Changed(node);
3357     }
3358   }
3359   return NoChange();
3360 }
3361 
ReduceJSCall(Node * node,Handle<SharedFunctionInfo> shared)3362 Reduction JSCallReducer::ReduceJSCall(Node* node,
3363                                       Handle<SharedFunctionInfo> shared) {
3364   DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
3365   Node* target = NodeProperties::GetValueInput(node, 0);
3366 
3367   // Do not reduce calls to functions with break points.
3368   if (shared->HasBreakInfo()) return NoChange();
3369 
3370   // Raise a TypeError if the {target} is a "classConstructor".
3371   if (IsClassConstructor(shared->kind())) {
3372     NodeProperties::ReplaceValueInputs(node, target);
3373     NodeProperties::ChangeOp(
3374         node, javascript()->CallRuntime(
3375                   Runtime::kThrowConstructorNonCallableError, 1));
3376     return Changed(node);
3377   }
3378 
3379   // Check for known builtin functions.
3380 
3381   int builtin_id =
3382       shared->HasBuiltinId() ? shared->builtin_id() : Builtins::kNoBuiltinId;
3383   switch (builtin_id) {
3384     case Builtins::kArrayConstructor:
3385       return ReduceArrayConstructor(node);
3386     case Builtins::kBooleanConstructor:
3387       return ReduceBooleanConstructor(node);
3388     case Builtins::kFunctionPrototypeApply:
3389       return ReduceFunctionPrototypeApply(node);
3390     case Builtins::kFastFunctionPrototypeBind:
3391       return ReduceFunctionPrototypeBind(node);
3392     case Builtins::kFunctionPrototypeCall:
3393       return ReduceFunctionPrototypeCall(node);
3394     case Builtins::kFunctionPrototypeHasInstance:
3395       return ReduceFunctionPrototypeHasInstance(node);
3396     case Builtins::kObjectConstructor:
3397       return ReduceObjectConstructor(node);
3398     case Builtins::kObjectCreate:
3399       return ReduceObjectCreate(node);
3400     case Builtins::kObjectGetPrototypeOf:
3401       return ReduceObjectGetPrototypeOf(node);
3402     case Builtins::kObjectIs:
3403       return ReduceObjectIs(node);
3404     case Builtins::kObjectPrototypeGetProto:
3405       return ReduceObjectPrototypeGetProto(node);
3406     case Builtins::kObjectPrototypeHasOwnProperty:
3407       return ReduceObjectPrototypeHasOwnProperty(node);
3408     case Builtins::kObjectPrototypeIsPrototypeOf:
3409       return ReduceObjectPrototypeIsPrototypeOf(node);
3410     case Builtins::kReflectApply:
3411       return ReduceReflectApply(node);
3412     case Builtins::kReflectConstruct:
3413       return ReduceReflectConstruct(node);
3414     case Builtins::kReflectGet:
3415       return ReduceReflectGet(node);
3416     case Builtins::kReflectGetPrototypeOf:
3417       return ReduceReflectGetPrototypeOf(node);
3418     case Builtins::kReflectHas:
3419       return ReduceReflectHas(node);
3420     case Builtins::kArrayForEach:
3421       return ReduceArrayForEach(node, shared);
3422     case Builtins::kArrayMap:
3423       return ReduceArrayMap(node, shared);
3424     case Builtins::kArrayFilter:
3425       return ReduceArrayFilter(node, shared);
3426     case Builtins::kArrayReduce:
3427       return ReduceArrayReduce(node, ArrayReduceDirection::kLeft, shared);
3428     case Builtins::kArrayReduceRight:
3429       return ReduceArrayReduce(node, ArrayReduceDirection::kRight, shared);
3430     case Builtins::kArrayPrototypeFind:
3431       return ReduceArrayFind(node, ArrayFindVariant::kFind, shared);
3432     case Builtins::kArrayPrototypeFindIndex:
3433       return ReduceArrayFind(node, ArrayFindVariant::kFindIndex, shared);
3434     case Builtins::kArrayEvery:
3435       return ReduceArrayEvery(node, shared);
3436     case Builtins::kArrayIndexOf:
3437       return ReduceArrayIndexOfIncludes(SearchVariant::kIndexOf, node);
3438     case Builtins::kArrayIncludes:
3439       return ReduceArrayIndexOfIncludes(SearchVariant::kIncludes, node);
3440     case Builtins::kArraySome:
3441       return ReduceArraySome(node, shared);
3442     case Builtins::kArrayPrototypePush:
3443       return ReduceArrayPrototypePush(node);
3444     case Builtins::kArrayPrototypePop:
3445       return ReduceArrayPrototypePop(node);
3446     case Builtins::kArrayPrototypeShift:
3447       return ReduceArrayPrototypeShift(node);
3448     case Builtins::kArrayPrototypeSlice:
3449       return ReduceArrayPrototypeSlice(node);
3450     case Builtins::kArrayPrototypeEntries:
3451       return ReduceArrayIterator(node, IterationKind::kEntries);
3452     case Builtins::kArrayPrototypeKeys:
3453       return ReduceArrayIterator(node, IterationKind::kKeys);
3454     case Builtins::kArrayPrototypeValues:
3455       return ReduceArrayIterator(node, IterationKind::kValues);
3456     case Builtins::kArrayIteratorPrototypeNext:
3457       return ReduceArrayIteratorPrototypeNext(node);
3458     case Builtins::kArrayIsArray:
3459       return ReduceArrayIsArray(node);
3460     case Builtins::kArrayBufferIsView:
3461       return ReduceArrayBufferIsView(node);
3462     case Builtins::kDataViewPrototypeGetByteLength:
3463       return ReduceArrayBufferViewAccessor(
3464           node, JS_DATA_VIEW_TYPE,
3465           AccessBuilder::ForJSArrayBufferViewByteLength());
3466     case Builtins::kDataViewPrototypeGetByteOffset:
3467       return ReduceArrayBufferViewAccessor(
3468           node, JS_DATA_VIEW_TYPE,
3469           AccessBuilder::ForJSArrayBufferViewByteOffset());
3470     case Builtins::kDataViewPrototypeGetUint8:
3471       return ReduceDataViewPrototypeGet(node,
3472                                         ExternalArrayType::kExternalUint8Array);
3473     case Builtins::kDataViewPrototypeGetInt8:
3474       return ReduceDataViewPrototypeGet(node,
3475                                         ExternalArrayType::kExternalInt8Array);
3476     case Builtins::kDataViewPrototypeGetUint16:
3477       return ReduceDataViewPrototypeGet(
3478           node, ExternalArrayType::kExternalUint16Array);
3479     case Builtins::kDataViewPrototypeGetInt16:
3480       return ReduceDataViewPrototypeGet(node,
3481                                         ExternalArrayType::kExternalInt16Array);
3482     case Builtins::kDataViewPrototypeGetUint32:
3483       return ReduceDataViewPrototypeGet(
3484           node, ExternalArrayType::kExternalUint32Array);
3485     case Builtins::kDataViewPrototypeGetInt32:
3486       return ReduceDataViewPrototypeGet(node,
3487                                         ExternalArrayType::kExternalInt32Array);
3488     case Builtins::kDataViewPrototypeGetFloat32:
3489       return ReduceDataViewPrototypeGet(
3490           node, ExternalArrayType::kExternalFloat32Array);
3491     case Builtins::kDataViewPrototypeGetFloat64:
3492       return ReduceDataViewPrototypeGet(
3493           node, ExternalArrayType::kExternalFloat64Array);
3494     case Builtins::kDataViewPrototypeSetUint8:
3495       return ReduceDataViewPrototypeSet(node,
3496                                         ExternalArrayType::kExternalUint8Array);
3497     case Builtins::kDataViewPrototypeSetInt8:
3498       return ReduceDataViewPrototypeSet(node,
3499                                         ExternalArrayType::kExternalInt8Array);
3500     case Builtins::kDataViewPrototypeSetUint16:
3501       return ReduceDataViewPrototypeSet(
3502           node, ExternalArrayType::kExternalUint16Array);
3503     case Builtins::kDataViewPrototypeSetInt16:
3504       return ReduceDataViewPrototypeSet(node,
3505                                         ExternalArrayType::kExternalInt16Array);
3506     case Builtins::kDataViewPrototypeSetUint32:
3507       return ReduceDataViewPrototypeSet(
3508           node, ExternalArrayType::kExternalUint32Array);
3509     case Builtins::kDataViewPrototypeSetInt32:
3510       return ReduceDataViewPrototypeSet(node,
3511                                         ExternalArrayType::kExternalInt32Array);
3512     case Builtins::kDataViewPrototypeSetFloat32:
3513       return ReduceDataViewPrototypeSet(
3514           node, ExternalArrayType::kExternalFloat32Array);
3515     case Builtins::kDataViewPrototypeSetFloat64:
3516       return ReduceDataViewPrototypeSet(
3517           node, ExternalArrayType::kExternalFloat64Array);
3518     case Builtins::kTypedArrayPrototypeByteLength:
3519       return ReduceArrayBufferViewAccessor(
3520           node, JS_TYPED_ARRAY_TYPE,
3521           AccessBuilder::ForJSArrayBufferViewByteLength());
3522     case Builtins::kTypedArrayPrototypeByteOffset:
3523       return ReduceArrayBufferViewAccessor(
3524           node, JS_TYPED_ARRAY_TYPE,
3525           AccessBuilder::ForJSArrayBufferViewByteOffset());
3526     case Builtins::kTypedArrayPrototypeLength:
3527       return ReduceArrayBufferViewAccessor(
3528           node, JS_TYPED_ARRAY_TYPE, AccessBuilder::ForJSTypedArrayLength());
3529     case Builtins::kTypedArrayPrototypeToStringTag:
3530       return ReduceTypedArrayPrototypeToStringTag(node);
3531     case Builtins::kMathAbs:
3532       return ReduceMathUnary(node, simplified()->NumberAbs());
3533     case Builtins::kMathAcos:
3534       return ReduceMathUnary(node, simplified()->NumberAcos());
3535     case Builtins::kMathAcosh:
3536       return ReduceMathUnary(node, simplified()->NumberAcosh());
3537     case Builtins::kMathAsin:
3538       return ReduceMathUnary(node, simplified()->NumberAsin());
3539     case Builtins::kMathAsinh:
3540       return ReduceMathUnary(node, simplified()->NumberAsinh());
3541     case Builtins::kMathAtan:
3542       return ReduceMathUnary(node, simplified()->NumberAtan());
3543     case Builtins::kMathAtanh:
3544       return ReduceMathUnary(node, simplified()->NumberAtanh());
3545     case Builtins::kMathCbrt:
3546       return ReduceMathUnary(node, simplified()->NumberCbrt());
3547     case Builtins::kMathCeil:
3548       return ReduceMathUnary(node, simplified()->NumberCeil());
3549     case Builtins::kMathCos:
3550       return ReduceMathUnary(node, simplified()->NumberCos());
3551     case Builtins::kMathCosh:
3552       return ReduceMathUnary(node, simplified()->NumberCosh());
3553     case Builtins::kMathExp:
3554       return ReduceMathUnary(node, simplified()->NumberExp());
3555     case Builtins::kMathExpm1:
3556       return ReduceMathUnary(node, simplified()->NumberExpm1());
3557     case Builtins::kMathFloor:
3558       return ReduceMathUnary(node, simplified()->NumberFloor());
3559     case Builtins::kMathFround:
3560       return ReduceMathUnary(node, simplified()->NumberFround());
3561     case Builtins::kMathLog:
3562       return ReduceMathUnary(node, simplified()->NumberLog());
3563     case Builtins::kMathLog1p:
3564       return ReduceMathUnary(node, simplified()->NumberLog1p());
3565     case Builtins::kMathLog10:
3566       return ReduceMathUnary(node, simplified()->NumberLog10());
3567     case Builtins::kMathLog2:
3568       return ReduceMathUnary(node, simplified()->NumberLog2());
3569     case Builtins::kMathRound:
3570       return ReduceMathUnary(node, simplified()->NumberRound());
3571     case Builtins::kMathSign:
3572       return ReduceMathUnary(node, simplified()->NumberSign());
3573     case Builtins::kMathSin:
3574       return ReduceMathUnary(node, simplified()->NumberSin());
3575     case Builtins::kMathSinh:
3576       return ReduceMathUnary(node, simplified()->NumberSinh());
3577     case Builtins::kMathSqrt:
3578       return ReduceMathUnary(node, simplified()->NumberSqrt());
3579     case Builtins::kMathTan:
3580       return ReduceMathUnary(node, simplified()->NumberTan());
3581     case Builtins::kMathTanh:
3582       return ReduceMathUnary(node, simplified()->NumberTanh());
3583     case Builtins::kMathTrunc:
3584       return ReduceMathUnary(node, simplified()->NumberTrunc());
3585     case Builtins::kMathAtan2:
3586       return ReduceMathBinary(node, simplified()->NumberAtan2());
3587     case Builtins::kMathPow:
3588       return ReduceMathBinary(node, simplified()->NumberPow());
3589     case Builtins::kMathClz32:
3590       return ReduceMathClz32(node);
3591     case Builtins::kMathImul:
3592       return ReduceMathImul(node);
3593     case Builtins::kMathMax:
3594       return ReduceMathMinMax(node, simplified()->NumberMax(),
3595                               jsgraph()->Constant(-V8_INFINITY));
3596     case Builtins::kMathMin:
3597       return ReduceMathMinMax(node, simplified()->NumberMin(),
3598                               jsgraph()->Constant(V8_INFINITY));
3599     case Builtins::kNumberIsFinite:
3600       return ReduceNumberIsFinite(node);
3601     case Builtins::kNumberIsInteger:
3602       return ReduceNumberIsInteger(node);
3603     case Builtins::kNumberIsSafeInteger:
3604       return ReduceNumberIsSafeInteger(node);
3605     case Builtins::kNumberIsNaN:
3606       return ReduceNumberIsNaN(node);
3607     case Builtins::kNumberParseInt:
3608       return ReduceNumberParseInt(node);
3609     case Builtins::kGlobalIsFinite:
3610       return ReduceGlobalIsFinite(node);
3611     case Builtins::kGlobalIsNaN:
3612       return ReduceGlobalIsNaN(node);
3613     case Builtins::kMapPrototypeGet:
3614       return ReduceMapPrototypeGet(node);
3615     case Builtins::kMapPrototypeHas:
3616       return ReduceMapPrototypeHas(node);
3617     case Builtins::kRegExpPrototypeTest:
3618       return ReduceRegExpPrototypeTest(node);
3619     case Builtins::kReturnReceiver:
3620       return ReduceReturnReceiver(node);
3621     case Builtins::kStringPrototypeIndexOf:
3622       return ReduceStringPrototypeIndexOf(node);
3623     case Builtins::kStringPrototypeCharAt:
3624       return ReduceStringPrototypeCharAt(node);
3625     case Builtins::kStringPrototypeCharCodeAt:
3626       return ReduceStringPrototypeStringAt(simplified()->StringCharCodeAt(),
3627                                            node);
3628     case Builtins::kStringPrototypeCodePointAt:
3629       return ReduceStringPrototypeStringAt(
3630           simplified()->StringCodePointAt(UnicodeEncoding::UTF32), node);
3631     case Builtins::kStringPrototypeSubstring:
3632       return ReduceStringPrototypeSubstring(node);
3633     case Builtins::kStringPrototypeSlice:
3634       return ReduceStringPrototypeSlice(node);
3635     case Builtins::kStringPrototypeSubstr:
3636       return ReduceStringPrototypeSubstr(node);
3637 #ifdef V8_INTL_SUPPORT
3638     case Builtins::kStringPrototypeToLowerCaseIntl:
3639       return ReduceStringPrototypeToLowerCaseIntl(node);
3640     case Builtins::kStringPrototypeToUpperCaseIntl:
3641       return ReduceStringPrototypeToUpperCaseIntl(node);
3642 #endif  // V8_INTL_SUPPORT
3643     case Builtins::kStringFromCharCode:
3644       return ReduceStringFromCharCode(node);
3645     case Builtins::kStringFromCodePoint:
3646       return ReduceStringFromCodePoint(node);
3647     case Builtins::kStringPrototypeIterator:
3648       return ReduceStringPrototypeIterator(node);
3649     case Builtins::kStringIteratorPrototypeNext:
3650       return ReduceStringIteratorPrototypeNext(node);
3651     case Builtins::kStringPrototypeConcat:
3652       return ReduceStringPrototypeConcat(node, shared);
3653     case Builtins::kTypedArrayPrototypeEntries:
3654       return ReduceArrayIterator(node, IterationKind::kEntries);
3655     case Builtins::kTypedArrayPrototypeKeys:
3656       return ReduceArrayIterator(node, IterationKind::kKeys);
3657     case Builtins::kTypedArrayPrototypeValues:
3658       return ReduceArrayIterator(node, IterationKind::kValues);
3659     case Builtins::kAsyncFunctionPromiseCreate:
3660       return ReduceAsyncFunctionPromiseCreate(node);
3661     case Builtins::kAsyncFunctionPromiseRelease:
3662       return ReduceAsyncFunctionPromiseRelease(node);
3663     case Builtins::kPromiseInternalConstructor:
3664       return ReducePromiseInternalConstructor(node);
3665     case Builtins::kPromiseInternalReject:
3666       return ReducePromiseInternalReject(node);
3667     case Builtins::kPromiseInternalResolve:
3668       return ReducePromiseInternalResolve(node);
3669     case Builtins::kPromisePrototypeCatch:
3670       return ReducePromisePrototypeCatch(node);
3671     case Builtins::kPromisePrototypeFinally:
3672       return ReducePromisePrototypeFinally(node);
3673     case Builtins::kPromisePrototypeThen:
3674       return ReducePromisePrototypeThen(node);
3675     case Builtins::kMapPrototypeEntries:
3676       return ReduceCollectionIteration(node, CollectionKind::kMap,
3677                                        IterationKind::kEntries);
3678     case Builtins::kMapPrototypeKeys:
3679       return ReduceCollectionIteration(node, CollectionKind::kMap,
3680                                        IterationKind::kKeys);
3681     case Builtins::kMapPrototypeGetSize:
3682       return ReduceCollectionPrototypeSize(node, CollectionKind::kMap);
3683     case Builtins::kMapPrototypeValues:
3684       return ReduceCollectionIteration(node, CollectionKind::kMap,
3685                                        IterationKind::kValues);
3686     case Builtins::kMapIteratorPrototypeNext:
3687       return ReduceCollectionIteratorPrototypeNext(
3688           node, OrderedHashMap::kEntrySize, factory()->empty_ordered_hash_map(),
3689           FIRST_MAP_ITERATOR_TYPE, LAST_MAP_ITERATOR_TYPE);
3690     case Builtins::kSetPrototypeEntries:
3691       return ReduceCollectionIteration(node, CollectionKind::kSet,
3692                                        IterationKind::kEntries);
3693     case Builtins::kSetPrototypeGetSize:
3694       return ReduceCollectionPrototypeSize(node, CollectionKind::kSet);
3695     case Builtins::kSetPrototypeValues:
3696       return ReduceCollectionIteration(node, CollectionKind::kSet,
3697                                        IterationKind::kValues);
3698     case Builtins::kSetIteratorPrototypeNext:
3699       return ReduceCollectionIteratorPrototypeNext(
3700           node, OrderedHashSet::kEntrySize, factory()->empty_ordered_hash_set(),
3701           FIRST_SET_ITERATOR_TYPE, LAST_SET_ITERATOR_TYPE);
3702     case Builtins::kDatePrototypeGetTime:
3703       return ReduceDatePrototypeGetTime(node);
3704     case Builtins::kDateNow:
3705       return ReduceDateNow(node);
3706     case Builtins::kNumberConstructor:
3707       return ReduceNumberConstructor(node);
3708     default:
3709       break;
3710   }
3711 
3712   if (!FLAG_runtime_stats && shared->IsApiFunction()) {
3713     return ReduceCallApiFunction(node, shared);
3714   }
3715   return NoChange();
3716 }
3717 
ReduceJSCallWithArrayLike(Node * node)3718 Reduction JSCallReducer::ReduceJSCallWithArrayLike(Node* node) {
3719   DCHECK_EQ(IrOpcode::kJSCallWithArrayLike, node->opcode());
3720   CallFrequency frequency = CallFrequencyOf(node->op());
3721   VectorSlotPair feedback;
3722   return ReduceCallOrConstructWithArrayLikeOrSpread(node, 2, frequency,
3723                                                     feedback);
3724 }
3725 
ReduceJSCallWithSpread(Node * node)3726 Reduction JSCallReducer::ReduceJSCallWithSpread(Node* node) {
3727   DCHECK_EQ(IrOpcode::kJSCallWithSpread, node->opcode());
3728   CallParameters const& p = CallParametersOf(node->op());
3729   DCHECK_LE(3u, p.arity());
3730   int arity = static_cast<int>(p.arity() - 1);
3731   CallFrequency frequency = p.frequency();
3732   VectorSlotPair feedback = p.feedback();
3733   return ReduceCallOrConstructWithArrayLikeOrSpread(node, arity, frequency,
3734                                                     feedback);
3735 }
3736 
ReduceJSConstruct(Node * node)3737 Reduction JSCallReducer::ReduceJSConstruct(Node* node) {
3738   DCHECK_EQ(IrOpcode::kJSConstruct, node->opcode());
3739   ConstructParameters const& p = ConstructParametersOf(node->op());
3740   DCHECK_LE(2u, p.arity());
3741   int arity = static_cast<int>(p.arity() - 2);
3742   Node* target = NodeProperties::GetValueInput(node, 0);
3743   Node* new_target = NodeProperties::GetValueInput(node, arity + 1);
3744   Node* effect = NodeProperties::GetEffectInput(node);
3745   Node* control = NodeProperties::GetControlInput(node);
3746 
3747   // Extract feedback from the {node} using the FeedbackNexus.
3748   if (p.feedback().IsValid()) {
3749     FeedbackNexus nexus(p.feedback().vector(), p.feedback().slot());
3750     if (nexus.IsUninitialized()) {
3751       if (flags() & kBailoutOnUninitialized) {
3752         // Introduce a SOFT deopt if the construct {node} wasn't executed so
3753         // far.
3754         return ReduceSoftDeoptimize(
3755             node, DeoptimizeReason::kInsufficientTypeFeedbackForConstruct);
3756       }
3757       return NoChange();
3758     }
3759 
3760     HeapObject* feedback_object;
3761     if (nexus.GetFeedback()->ToStrongHeapObject(&feedback_object) &&
3762         feedback_object->IsAllocationSite()) {
3763       // The feedback is an AllocationSite, which means we have called the
3764       // Array function and collected transition (and pretenuring) feedback
3765       // for the resulting arrays.  This has to be kept in sync with the
3766       // implementation in Ignition.
3767       Handle<AllocationSite> site(AllocationSite::cast(feedback_object),
3768                                   isolate());
3769 
3770       // Retrieve the Array function from the {node}.
3771       Node* array_function = jsgraph()->HeapConstant(
3772           handle(native_context()->array_function(), isolate()));
3773 
3774       // Check that the {target} is still the {array_function}.
3775       Node* check = graph()->NewNode(simplified()->ReferenceEqual(), target,
3776                                      array_function);
3777       effect = graph()->NewNode(
3778           simplified()->CheckIf(DeoptimizeReason::kWrongCallTarget), check,
3779           effect, control);
3780 
3781       // Turn the {node} into a {JSCreateArray} call.
3782       NodeProperties::ReplaceEffectInput(node, effect);
3783       for (int i = arity; i > 0; --i) {
3784         NodeProperties::ReplaceValueInput(
3785             node, NodeProperties::GetValueInput(node, i), i + 1);
3786       }
3787       NodeProperties::ReplaceValueInput(node, array_function, 1);
3788       NodeProperties::ChangeOp(node, javascript()->CreateArray(arity, site));
3789       return Changed(node);
3790     } else if (nexus.GetFeedback()->ToWeakHeapObject(&feedback_object) &&
3791                !HeapObjectMatcher(new_target).HasValue()) {
3792       Handle<HeapObject> object(feedback_object, isolate());
3793       if (object->IsConstructor()) {
3794         Node* new_target_feedback = jsgraph()->Constant(object);
3795 
3796         // Check that the {new_target} is still the {new_target_feedback}.
3797         Node* check = graph()->NewNode(simplified()->ReferenceEqual(),
3798                                        new_target, new_target_feedback);
3799         effect = graph()->NewNode(
3800             simplified()->CheckIf(DeoptimizeReason::kWrongCallTarget), check,
3801             effect, control);
3802 
3803         // Specialize the JSConstruct node to the {new_target_feedback}.
3804         NodeProperties::ReplaceValueInput(node, new_target_feedback, arity + 1);
3805         NodeProperties::ReplaceEffectInput(node, effect);
3806         if (target == new_target) {
3807           NodeProperties::ReplaceValueInput(node, new_target_feedback, 0);
3808         }
3809 
3810         // Try to further reduce the JSConstruct {node}.
3811         Reduction const reduction = ReduceJSConstruct(node);
3812         return reduction.Changed() ? reduction : Changed(node);
3813       }
3814     }
3815   }
3816 
3817   // Try to specialize JSConstruct {node}s with constant {target}s.
3818   HeapObjectMatcher m(target);
3819   if (m.HasValue()) {
3820     // Raise a TypeError if the {target} is not a constructor.
3821     if (!m.Value()->IsConstructor()) {
3822       NodeProperties::ReplaceValueInputs(node, target);
3823       NodeProperties::ChangeOp(node,
3824                                javascript()->CallRuntime(
3825                                    Runtime::kThrowConstructedNonConstructable));
3826       return Changed(node);
3827     }
3828 
3829     if (m.Value()->IsJSFunction()) {
3830       Handle<JSFunction> function = Handle<JSFunction>::cast(m.Value());
3831 
3832       // Do not reduce constructors with break points.
3833       if (function->shared()->HasBreakInfo()) return NoChange();
3834 
3835       // Don't inline cross native context.
3836       if (function->native_context() != *native_context()) return NoChange();
3837 
3838       // Check for known builtin functions.
3839       int builtin_id = function->shared()->HasBuiltinId()
3840                            ? function->shared()->builtin_id()
3841                            : Builtins::kNoBuiltinId;
3842       switch (builtin_id) {
3843         case Builtins::kArrayConstructor: {
3844           // TODO(bmeurer): Deal with Array subclasses here.
3845           Handle<AllocationSite> site;
3846           // Turn the {node} into a {JSCreateArray} call.
3847           for (int i = arity; i > 0; --i) {
3848             NodeProperties::ReplaceValueInput(
3849                 node, NodeProperties::GetValueInput(node, i), i + 1);
3850           }
3851           NodeProperties::ReplaceValueInput(node, new_target, 1);
3852           NodeProperties::ChangeOp(node,
3853                                    javascript()->CreateArray(arity, site));
3854           return Changed(node);
3855         }
3856         case Builtins::kObjectConstructor: {
3857           // If no value is passed, we can immediately lower to a simple
3858           // JSCreate and don't need to do any massaging of the {node}.
3859           if (arity == 0) {
3860             NodeProperties::ChangeOp(node, javascript()->Create());
3861             return Changed(node);
3862           }
3863 
3864           // Otherwise we can only lower to JSCreate if we know that
3865           // the value parameter is ignored, which is only the case if
3866           // the {new_target} and {target} are definitely not identical.
3867           HeapObjectMatcher mnew_target(new_target);
3868           if (mnew_target.HasValue() && *mnew_target.Value() != *function) {
3869             // Drop the value inputs.
3870             for (int i = arity; i > 0; --i) node->RemoveInput(i);
3871             NodeProperties::ChangeOp(node, javascript()->Create());
3872             return Changed(node);
3873           }
3874           break;
3875         }
3876         case Builtins::kPromiseConstructor:
3877           return ReducePromiseConstructor(node);
3878         case Builtins::kTypedArrayConstructor:
3879           return ReduceTypedArrayConstructor(
3880               node, handle(function->shared(), isolate()));
3881         default:
3882           break;
3883       }
3884     } else if (m.Value()->IsJSBoundFunction()) {
3885       Handle<JSBoundFunction> function =
3886           Handle<JSBoundFunction>::cast(m.Value());
3887       Handle<JSReceiver> bound_target_function(
3888           function->bound_target_function(), isolate());
3889       Handle<FixedArray> bound_arguments(function->bound_arguments(),
3890                                          isolate());
3891 
3892       // Patch {node} to use [[BoundTargetFunction]].
3893       NodeProperties::ReplaceValueInput(
3894           node, jsgraph()->Constant(bound_target_function), 0);
3895 
3896       // Patch {node} to use [[BoundTargetFunction]]
3897       // as new.target if {new_target} equals {target}.
3898       NodeProperties::ReplaceValueInput(
3899           node,
3900           graph()->NewNode(common()->Select(MachineRepresentation::kTagged),
3901                            graph()->NewNode(simplified()->ReferenceEqual(),
3902                                             target, new_target),
3903                            jsgraph()->Constant(bound_target_function),
3904                            new_target),
3905           arity + 1);
3906 
3907       // Insert the [[BoundArguments]] for {node}.
3908       for (int i = 0; i < bound_arguments->length(); ++i) {
3909         node->InsertInput(
3910             graph()->zone(), i + 1,
3911             jsgraph()->Constant(handle(bound_arguments->get(i), isolate())));
3912         arity++;
3913       }
3914 
3915       // Update the JSConstruct operator on {node}.
3916       NodeProperties::ChangeOp(
3917           node,
3918           javascript()->Construct(arity + 2, p.frequency(), VectorSlotPair()));
3919 
3920       // Try to further reduce the JSConstruct {node}.
3921       Reduction const reduction = ReduceJSConstruct(node);
3922       return reduction.Changed() ? reduction : Changed(node);
3923     }
3924 
3925     // TODO(bmeurer): Also support optimizing proxies here.
3926   }
3927 
3928   // If {target} is the result of a JSCreateBoundFunction operation,
3929   // we can just fold the construction and construct the bound target
3930   // function directly instead.
3931   if (target->opcode() == IrOpcode::kJSCreateBoundFunction) {
3932     Node* bound_target_function = NodeProperties::GetValueInput(target, 0);
3933     int const bound_arguments_length =
3934         static_cast<int>(CreateBoundFunctionParametersOf(target->op()).arity());
3935 
3936     // Patch the {node} to use [[BoundTargetFunction]].
3937     NodeProperties::ReplaceValueInput(node, bound_target_function, 0);
3938 
3939     // Patch {node} to use [[BoundTargetFunction]]
3940     // as new.target if {new_target} equals {target}.
3941     NodeProperties::ReplaceValueInput(
3942         node,
3943         graph()->NewNode(common()->Select(MachineRepresentation::kTagged),
3944                          graph()->NewNode(simplified()->ReferenceEqual(),
3945                                           target, new_target),
3946                          bound_target_function, new_target),
3947         arity + 1);
3948 
3949     // Insert the [[BoundArguments]] for {node}.
3950     for (int i = 0; i < bound_arguments_length; ++i) {
3951       Node* value = NodeProperties::GetValueInput(target, 2 + i);
3952       node->InsertInput(graph()->zone(), 1 + i, value);
3953       arity++;
3954     }
3955 
3956     // Update the JSConstruct operator on {node}.
3957     NodeProperties::ChangeOp(
3958         node,
3959         javascript()->Construct(arity + 2, p.frequency(), VectorSlotPair()));
3960 
3961     // Try to further reduce the JSConstruct {node}.
3962     Reduction const reduction = ReduceJSConstruct(node);
3963     return reduction.Changed() ? reduction : Changed(node);
3964   }
3965 
3966   return NoChange();
3967 }
3968 
3969 // ES #sec-string.prototype.indexof
ReduceStringPrototypeIndexOf(Node * node)3970 Reduction JSCallReducer::ReduceStringPrototypeIndexOf(Node* node) {
3971   DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
3972   CallParameters const& p = CallParametersOf(node->op());
3973   if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
3974     return NoChange();
3975   }
3976 
3977   Node* effect = NodeProperties::GetEffectInput(node);
3978   Node* control = NodeProperties::GetControlInput(node);
3979   if (node->op()->ValueInputCount() >= 3) {
3980     Node* receiver = NodeProperties::GetValueInput(node, 1);
3981     Node* new_receiver = effect = graph()->NewNode(
3982         simplified()->CheckString(p.feedback()), receiver, effect, control);
3983 
3984     Node* search_string = NodeProperties::GetValueInput(node, 2);
3985     Node* new_search_string = effect =
3986         graph()->NewNode(simplified()->CheckString(p.feedback()), search_string,
3987                          effect, control);
3988 
3989     Node* new_position = jsgraph()->ZeroConstant();
3990     if (node->op()->ValueInputCount() >= 4) {
3991       Node* position = NodeProperties::GetValueInput(node, 3);
3992       new_position = effect = graph()->NewNode(
3993           simplified()->CheckSmi(p.feedback()), position, effect, control);
3994     }
3995 
3996     NodeProperties::ReplaceEffectInput(node, effect);
3997     RelaxEffectsAndControls(node);
3998     node->ReplaceInput(0, new_receiver);
3999     node->ReplaceInput(1, new_search_string);
4000     node->ReplaceInput(2, new_position);
4001     node->TrimInputCount(3);
4002     NodeProperties::ChangeOp(node, simplified()->StringIndexOf());
4003     return Changed(node);
4004   }
4005   return NoChange();
4006 }
4007 
4008 // ES #sec-string.prototype.substring
ReduceStringPrototypeSubstring(Node * node)4009 Reduction JSCallReducer::ReduceStringPrototypeSubstring(Node* node) {
4010   if (node->op()->ValueInputCount() < 3) return NoChange();
4011   CallParameters const& p = CallParametersOf(node->op());
4012   if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
4013     return NoChange();
4014   }
4015 
4016   Node* effect = NodeProperties::GetEffectInput(node);
4017   Node* control = NodeProperties::GetControlInput(node);
4018   Node* receiver = NodeProperties::GetValueInput(node, 1);
4019   Node* start = NodeProperties::GetValueInput(node, 2);
4020   Node* end = node->op()->ValueInputCount() > 3
4021                   ? NodeProperties::GetValueInput(node, 3)
4022                   : jsgraph()->UndefinedConstant();
4023 
4024   receiver = effect = graph()->NewNode(simplified()->CheckString(p.feedback()),
4025                                        receiver, effect, control);
4026 
4027   start = effect = graph()->NewNode(simplified()->CheckSmi(p.feedback()), start,
4028                                     effect, control);
4029 
4030   Node* length = graph()->NewNode(simplified()->StringLength(), receiver);
4031 
4032   Node* check = graph()->NewNode(simplified()->ReferenceEqual(), end,
4033                                  jsgraph()->UndefinedConstant());
4034   Node* branch =
4035       graph()->NewNode(common()->Branch(BranchHint::kFalse), check, control);
4036 
4037   Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
4038   Node* etrue = effect;
4039   Node* vtrue = length;
4040 
4041   Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
4042   Node* efalse = effect;
4043   Node* vfalse = efalse = graph()->NewNode(simplified()->CheckSmi(p.feedback()),
4044                                            end, efalse, if_false);
4045 
4046   control = graph()->NewNode(common()->Merge(2), if_true, if_false);
4047   effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);
4048   end = graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
4049                          vtrue, vfalse, control);
4050   Node* finalStart =
4051       graph()->NewNode(simplified()->NumberMin(),
4052                        graph()->NewNode(simplified()->NumberMax(), start,
4053                                         jsgraph()->ZeroConstant()),
4054                        length);
4055   Node* finalEnd =
4056       graph()->NewNode(simplified()->NumberMin(),
4057                        graph()->NewNode(simplified()->NumberMax(), end,
4058                                         jsgraph()->ZeroConstant()),
4059                        length);
4060 
4061   Node* from =
4062       graph()->NewNode(simplified()->NumberMin(), finalStart, finalEnd);
4063   Node* to = graph()->NewNode(simplified()->NumberMax(), finalStart, finalEnd);
4064 
4065   Node* value = effect = graph()->NewNode(simplified()->StringSubstring(),
4066                                           receiver, from, to, effect, control);
4067   ReplaceWithValue(node, value, effect, control);
4068   return Replace(value);
4069 }
4070 
4071 // ES #sec-string.prototype.slice
ReduceStringPrototypeSlice(Node * node)4072 Reduction JSCallReducer::ReduceStringPrototypeSlice(Node* node) {
4073   if (node->op()->ValueInputCount() < 3) return NoChange();
4074   CallParameters const& p = CallParametersOf(node->op());
4075   if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
4076     return NoChange();
4077   }
4078 
4079   Node* effect = NodeProperties::GetEffectInput(node);
4080   Node* control = NodeProperties::GetControlInput(node);
4081   Node* receiver = NodeProperties::GetValueInput(node, 1);
4082   Node* start = NodeProperties::GetValueInput(node, 2);
4083   Node* end = node->op()->ValueInputCount() > 3
4084                   ? NodeProperties::GetValueInput(node, 3)
4085                   : jsgraph()->UndefinedConstant();
4086 
4087   receiver = effect = graph()->NewNode(simplified()->CheckString(p.feedback()),
4088                                        receiver, effect, control);
4089 
4090   start = effect = graph()->NewNode(simplified()->CheckSmi(p.feedback()), start,
4091                                     effect, control);
4092 
4093   Node* length = graph()->NewNode(simplified()->StringLength(), receiver);
4094 
4095   // Replace {end} argument with {length} if it is undefined.
4096   {
4097     Node* check = graph()->NewNode(simplified()->ReferenceEqual(), end,
4098                                    jsgraph()->UndefinedConstant());
4099 
4100     Node* branch =
4101         graph()->NewNode(common()->Branch(BranchHint::kFalse), check, control);
4102 
4103     Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
4104     Node* etrue = effect;
4105     Node* vtrue = length;
4106 
4107     Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
4108     Node* efalse = effect;
4109     Node* vfalse = efalse = graph()->NewNode(
4110         simplified()->CheckSmi(p.feedback()), end, efalse, if_false);
4111 
4112     control = graph()->NewNode(common()->Merge(2), if_true, if_false);
4113     effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);
4114     end = graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
4115                            vtrue, vfalse, control);
4116   }
4117 
4118   Node* from = graph()->NewNode(
4119       common()->Select(MachineRepresentation::kTagged, BranchHint::kFalse),
4120       graph()->NewNode(simplified()->NumberLessThan(), start,
4121                        jsgraph()->ZeroConstant()),
4122       graph()->NewNode(
4123           simplified()->NumberMax(),
4124           graph()->NewNode(simplified()->NumberAdd(), length, start),
4125           jsgraph()->ZeroConstant()),
4126       graph()->NewNode(simplified()->NumberMin(), start, length));
4127   // {from} is always in non-negative Smi range, but our typer cannot
4128   // figure that out yet.
4129   from = effect = graph()->NewNode(common()->TypeGuard(Type::UnsignedSmall()),
4130                                    from, effect, control);
4131 
4132   Node* to = graph()->NewNode(
4133       common()->Select(MachineRepresentation::kTagged, BranchHint::kFalse),
4134       graph()->NewNode(simplified()->NumberLessThan(), end,
4135                        jsgraph()->ZeroConstant()),
4136       graph()->NewNode(simplified()->NumberMax(),
4137                        graph()->NewNode(simplified()->NumberAdd(), length, end),
4138                        jsgraph()->ZeroConstant()),
4139       graph()->NewNode(simplified()->NumberMin(), end, length));
4140   // {to} is always in non-negative Smi range, but our typer cannot
4141   // figure that out yet.
4142   to = effect = graph()->NewNode(common()->TypeGuard(Type::UnsignedSmall()), to,
4143                                  effect, control);
4144 
4145   Node* result_string = nullptr;
4146   // Return empty string if {from} is smaller than {to}.
4147   {
4148     Node* check = graph()->NewNode(simplified()->NumberLessThan(), from, to);
4149 
4150     Node* branch =
4151         graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
4152 
4153     Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
4154     Node* etrue = effect;
4155     Node* vtrue = etrue = graph()->NewNode(simplified()->StringSubstring(),
4156                                            receiver, from, to, etrue, if_true);
4157 
4158     Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
4159     Node* efalse = effect;
4160     Node* vfalse = jsgraph()->EmptyStringConstant();
4161 
4162     control = graph()->NewNode(common()->Merge(2), if_true, if_false);
4163     effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);
4164     result_string =
4165         graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
4166                          vtrue, vfalse, control);
4167   }
4168 
4169   ReplaceWithValue(node, result_string, effect, control);
4170   return Replace(result_string);
4171 }
4172 
4173 // ES #sec-string.prototype.substr
ReduceStringPrototypeSubstr(Node * node)4174 Reduction JSCallReducer::ReduceStringPrototypeSubstr(Node* node) {
4175   if (node->op()->ValueInputCount() < 3) return NoChange();
4176   CallParameters const& p = CallParametersOf(node->op());
4177   if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
4178     return NoChange();
4179   }
4180 
4181   Node* effect = NodeProperties::GetEffectInput(node);
4182   Node* control = NodeProperties::GetControlInput(node);
4183   Node* receiver = NodeProperties::GetValueInput(node, 1);
4184   Node* start = NodeProperties::GetValueInput(node, 2);
4185   Node* end = node->op()->ValueInputCount() > 3
4186                   ? NodeProperties::GetValueInput(node, 3)
4187                   : jsgraph()->UndefinedConstant();
4188 
4189   receiver = effect = graph()->NewNode(simplified()->CheckString(p.feedback()),
4190                                        receiver, effect, control);
4191 
4192   start = effect = graph()->NewNode(simplified()->CheckSmi(p.feedback()), start,
4193                                     effect, control);
4194 
4195   Node* length = graph()->NewNode(simplified()->StringLength(), receiver);
4196 
4197   // Replace {end} argument with {length} if it is undefined.
4198   {
4199     Node* check = graph()->NewNode(simplified()->ReferenceEqual(), end,
4200                                    jsgraph()->UndefinedConstant());
4201     Node* branch =
4202         graph()->NewNode(common()->Branch(BranchHint::kFalse), check, control);
4203 
4204     Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
4205     Node* etrue = effect;
4206     Node* vtrue = length;
4207 
4208     Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
4209     Node* efalse = effect;
4210     Node* vfalse = efalse = graph()->NewNode(
4211         simplified()->CheckSmi(p.feedback()), end, efalse, if_false);
4212 
4213     control = graph()->NewNode(common()->Merge(2), if_true, if_false);
4214     effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);
4215     end = graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
4216                            vtrue, vfalse, control);
4217   }
4218 
4219   Node* initStart = graph()->NewNode(
4220       common()->Select(MachineRepresentation::kTagged, BranchHint::kFalse),
4221       graph()->NewNode(simplified()->NumberLessThan(), start,
4222                        jsgraph()->ZeroConstant()),
4223       graph()->NewNode(
4224           simplified()->NumberMax(),
4225           graph()->NewNode(simplified()->NumberAdd(), length, start),
4226           jsgraph()->ZeroConstant()),
4227       start);
4228   // The select above guarantees that initStart is non-negative, but
4229   // our typer can't figure that out yet.
4230   initStart = effect = graph()->NewNode(
4231       common()->TypeGuard(Type::UnsignedSmall()), initStart, effect, control);
4232 
4233   Node* resultLength = graph()->NewNode(
4234       simplified()->NumberMin(),
4235       graph()->NewNode(simplified()->NumberMax(), end,
4236                        jsgraph()->ZeroConstant()),
4237       graph()->NewNode(simplified()->NumberSubtract(), length, initStart));
4238 
4239   // The the select below uses {resultLength} only if {resultLength > 0},
4240   // but our typer can't figure that out yet.
4241   Node* to = effect = graph()->NewNode(
4242       common()->TypeGuard(Type::UnsignedSmall()),
4243       graph()->NewNode(simplified()->NumberAdd(), initStart, resultLength),
4244       effect, control);
4245 
4246   Node* result_string = nullptr;
4247   // Return empty string if {from} is smaller than {to}.
4248   {
4249     Node* check = graph()->NewNode(simplified()->NumberLessThan(),
4250                                    jsgraph()->ZeroConstant(), resultLength);
4251 
4252     Node* branch =
4253         graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
4254 
4255     Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
4256     Node* etrue = effect;
4257     Node* vtrue = etrue =
4258         graph()->NewNode(simplified()->StringSubstring(), receiver, initStart,
4259                          to, etrue, if_true);
4260 
4261     Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
4262     Node* efalse = effect;
4263     Node* vfalse = jsgraph()->EmptyStringConstant();
4264 
4265     control = graph()->NewNode(common()->Merge(2), if_true, if_false);
4266     effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);
4267     result_string =
4268         graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
4269                          vtrue, vfalse, control);
4270   }
4271 
4272   ReplaceWithValue(node, result_string, effect, control);
4273   return Replace(result_string);
4274 }
4275 
ReduceJSConstructWithArrayLike(Node * node)4276 Reduction JSCallReducer::ReduceJSConstructWithArrayLike(Node* node) {
4277   DCHECK_EQ(IrOpcode::kJSConstructWithArrayLike, node->opcode());
4278   CallFrequency frequency = CallFrequencyOf(node->op());
4279   VectorSlotPair feedback;
4280   return ReduceCallOrConstructWithArrayLikeOrSpread(node, 1, frequency,
4281                                                     feedback);
4282 }
4283 
ReduceJSConstructWithSpread(Node * node)4284 Reduction JSCallReducer::ReduceJSConstructWithSpread(Node* node) {
4285   DCHECK_EQ(IrOpcode::kJSConstructWithSpread, node->opcode());
4286   ConstructParameters const& p = ConstructParametersOf(node->op());
4287   DCHECK_LE(3u, p.arity());
4288   int arity = static_cast<int>(p.arity() - 2);
4289   CallFrequency frequency = p.frequency();
4290   VectorSlotPair feedback = p.feedback();
4291   return ReduceCallOrConstructWithArrayLikeOrSpread(node, arity, frequency,
4292                                                     feedback);
4293 }
4294 
ReduceReturnReceiver(Node * node)4295 Reduction JSCallReducer::ReduceReturnReceiver(Node* node) {
4296   DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
4297   Node* receiver = NodeProperties::GetValueInput(node, 1);
4298   ReplaceWithValue(node, receiver);
4299   return Replace(receiver);
4300 }
4301 
ReduceSoftDeoptimize(Node * node,DeoptimizeReason reason)4302 Reduction JSCallReducer::ReduceSoftDeoptimize(Node* node,
4303                                               DeoptimizeReason reason) {
4304   Node* effect = NodeProperties::GetEffectInput(node);
4305   Node* control = NodeProperties::GetControlInput(node);
4306   Node* frame_state = NodeProperties::FindFrameStateBefore(node);
4307   Node* deoptimize = graph()->NewNode(
4308       common()->Deoptimize(DeoptimizeKind::kSoft, reason, VectorSlotPair()),
4309       frame_state, effect, control);
4310   // TODO(bmeurer): This should be on the AdvancedReducer somehow.
4311   NodeProperties::MergeControlToEnd(graph(), common(), deoptimize);
4312   Revisit(graph()->end());
4313   node->TrimInputCount(0);
4314   NodeProperties::ChangeOp(node, common()->Dead());
4315   return Changed(node);
4316 }
4317 
4318 namespace {
4319 
4320 // TODO(turbofan): This was copied from old compiler, might be too restrictive.
IsReadOnlyLengthDescriptor(Isolate * isolate,Handle<Map> jsarray_map)4321 bool IsReadOnlyLengthDescriptor(Isolate* isolate, Handle<Map> jsarray_map) {
4322   DCHECK(!jsarray_map->is_dictionary_map());
4323   Handle<Name> length_string = isolate->factory()->length_string();
4324   DescriptorArray* descriptors = jsarray_map->instance_descriptors();
4325   int number = descriptors->Search(*length_string, *jsarray_map);
4326   DCHECK_NE(DescriptorArray::kNotFound, number);
4327   return descriptors->GetDetails(number).IsReadOnly();
4328 }
4329 
4330 // TODO(turbofan): This was copied from old compiler, might be too restrictive.
CanInlineArrayResizeOperation(Isolate * isolate,Handle<Map> receiver_map)4331 bool CanInlineArrayResizeOperation(Isolate* isolate, Handle<Map> receiver_map) {
4332   if (!receiver_map->prototype()->IsJSArray()) return false;
4333   Handle<JSArray> receiver_prototype(JSArray::cast(receiver_map->prototype()),
4334                                      isolate);
4335   return receiver_map->instance_type() == JS_ARRAY_TYPE &&
4336          IsFastElementsKind(receiver_map->elements_kind()) &&
4337          !receiver_map->is_dictionary_map() && receiver_map->is_extensible() &&
4338          isolate->IsAnyInitialArrayPrototype(receiver_prototype) &&
4339          !IsReadOnlyLengthDescriptor(isolate, receiver_map);
4340 }
4341 
4342 }  // namespace
4343 
4344 // ES6 section 22.1.3.18 Array.prototype.push ( )
ReduceArrayPrototypePush(Node * node)4345 Reduction JSCallReducer::ReduceArrayPrototypePush(Node* node) {
4346   DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
4347   CallParameters const& p = CallParametersOf(node->op());
4348   if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
4349     return NoChange();
4350   }
4351 
4352   if (!isolate()->IsNoElementsProtectorIntact()) return NoChange();
4353 
4354   int const num_values = node->op()->ValueInputCount() - 2;
4355   Node* receiver = NodeProperties::GetValueInput(node, 1);
4356   Node* effect = NodeProperties::GetEffectInput(node);
4357   Node* control = NodeProperties::GetControlInput(node);
4358 
4359   // Try to determine the {receiver} map(s).
4360   ZoneHandleSet<Map> receiver_maps;
4361   NodeProperties::InferReceiverMapsResult result =
4362       NodeProperties::InferReceiverMaps(isolate(), receiver, effect,
4363                                         &receiver_maps);
4364   if (result == NodeProperties::kNoReceiverMaps) return NoChange();
4365   DCHECK_NE(0, receiver_maps.size());
4366 
4367   ElementsKind kind = receiver_maps[0]->elements_kind();
4368 
4369   for (Handle<Map> receiver_map : receiver_maps) {
4370     if (!CanInlineArrayResizeOperation(isolate(), receiver_map))
4371       return NoChange();
4372     if (!UnionElementsKindUptoPackedness(&kind, receiver_map->elements_kind()))
4373       return NoChange();
4374   }
4375 
4376   // Install code dependencies on the {receiver} global array protector cell.
4377   dependencies()->DependOnProtector(
4378       PropertyCellRef(js_heap_broker(), factory()->no_elements_protector()));
4379 
4380   // If the {receiver_maps} information is not reliable, we need
4381   // to check that the {receiver} still has one of these maps.
4382   if (result == NodeProperties::kUnreliableReceiverMaps) {
4383     effect =
4384         graph()->NewNode(simplified()->CheckMaps(CheckMapsFlag::kNone,
4385                                                  receiver_maps, p.feedback()),
4386                          receiver, effect, control);
4387   }
4388 
4389   // Collect the value inputs to push.
4390   std::vector<Node*> values(num_values);
4391   for (int i = 0; i < num_values; ++i) {
4392     values[i] = NodeProperties::GetValueInput(node, 2 + i);
4393   }
4394 
4395   for (auto& value : values) {
4396     if (IsSmiElementsKind(kind)) {
4397       value = effect = graph()->NewNode(simplified()->CheckSmi(p.feedback()),
4398                                         value, effect, control);
4399     } else if (IsDoubleElementsKind(kind)) {
4400       value = effect = graph()->NewNode(simplified()->CheckNumber(p.feedback()),
4401                                         value, effect, control);
4402       // Make sure we do not store signaling NaNs into double arrays.
4403       value = graph()->NewNode(simplified()->NumberSilenceNaN(), value);
4404     }
4405   }
4406 
4407   // Load the "length" property of the {receiver}.
4408   Node* length = effect = graph()->NewNode(
4409       simplified()->LoadField(AccessBuilder::ForJSArrayLength(kind)), receiver,
4410       effect, control);
4411   Node* value = length;
4412 
4413   // Check if we have any {values} to push.
4414   if (num_values > 0) {
4415     // Compute the resulting "length" of the {receiver}.
4416     Node* new_length = value = graph()->NewNode(
4417         simplified()->NumberAdd(), length, jsgraph()->Constant(num_values));
4418 
4419     // Load the elements backing store of the {receiver}.
4420     Node* elements = effect = graph()->NewNode(
4421         simplified()->LoadField(AccessBuilder::ForJSObjectElements()), receiver,
4422         effect, control);
4423     Node* elements_length = effect = graph()->NewNode(
4424         simplified()->LoadField(AccessBuilder::ForFixedArrayLength()), elements,
4425         effect, control);
4426 
4427     GrowFastElementsMode mode =
4428         IsDoubleElementsKind(kind) ? GrowFastElementsMode::kDoubleElements
4429                                    : GrowFastElementsMode::kSmiOrObjectElements;
4430     elements = effect = graph()->NewNode(
4431         simplified()->MaybeGrowFastElements(mode, p.feedback()), receiver,
4432         elements,
4433         graph()->NewNode(simplified()->NumberAdd(), length,
4434                          jsgraph()->Constant(num_values - 1)),
4435         elements_length, effect, control);
4436 
4437     // Update the JSArray::length field. Since this is observable,
4438     // there must be no other check after this.
4439     effect = graph()->NewNode(
4440         simplified()->StoreField(AccessBuilder::ForJSArrayLength(kind)),
4441         receiver, new_length, effect, control);
4442 
4443     // Append the {values} to the {elements}.
4444     for (int i = 0; i < num_values; ++i) {
4445       Node* value = values[i];
4446       Node* index = graph()->NewNode(simplified()->NumberAdd(), length,
4447                                      jsgraph()->Constant(i));
4448       effect = graph()->NewNode(
4449           simplified()->StoreElement(AccessBuilder::ForFixedArrayElement(kind)),
4450           elements, index, value, effect, control);
4451     }
4452   }
4453 
4454   ReplaceWithValue(node, value, effect, control);
4455   return Replace(value);
4456 }
4457 
4458 // ES6 section 22.1.3.17 Array.prototype.pop ( )
ReduceArrayPrototypePop(Node * node)4459 Reduction JSCallReducer::ReduceArrayPrototypePop(Node* node) {
4460   DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
4461   CallParameters const& p = CallParametersOf(node->op());
4462   if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
4463     return NoChange();
4464   }
4465 
4466   if (!isolate()->IsNoElementsProtectorIntact()) return NoChange();
4467 
4468   Node* receiver = NodeProperties::GetValueInput(node, 1);
4469   Node* effect = NodeProperties::GetEffectInput(node);
4470   Node* control = NodeProperties::GetControlInput(node);
4471 
4472   ZoneHandleSet<Map> receiver_maps;
4473   NodeProperties::InferReceiverMapsResult result =
4474       NodeProperties::InferReceiverMaps(isolate(), receiver, effect,
4475                                         &receiver_maps);
4476   if (result == NodeProperties::kNoReceiverMaps) return NoChange();
4477   DCHECK_NE(0, receiver_maps.size());
4478 
4479   ElementsKind kind = receiver_maps[0]->elements_kind();
4480   for (Handle<Map> receiver_map : receiver_maps) {
4481     if (!CanInlineArrayResizeOperation(isolate(), receiver_map))
4482       return NoChange();
4483     // TODO(turbofan): Extend this to also handle fast holey double elements
4484     // once we got the hole NaN mess sorted out in TurboFan/V8.
4485     if (receiver_map->elements_kind() == HOLEY_DOUBLE_ELEMENTS)
4486       return NoChange();
4487     if (!UnionElementsKindUptoSize(&kind, receiver_map->elements_kind()))
4488       return NoChange();
4489   }
4490 
4491   // Install code dependencies on the {receiver} global array protector cell.
4492   dependencies()->DependOnProtector(
4493       PropertyCellRef(js_heap_broker(), factory()->no_elements_protector()));
4494 
4495   // If the {receiver_maps} information is not reliable, we need
4496   // to check that the {receiver} still has one of these maps.
4497   if (result == NodeProperties::kUnreliableReceiverMaps) {
4498     effect =
4499         graph()->NewNode(simplified()->CheckMaps(CheckMapsFlag::kNone,
4500                                                  receiver_maps, p.feedback()),
4501                          receiver, effect, control);
4502   }
4503 
4504   // Load the "length" property of the {receiver}.
4505   Node* length = effect = graph()->NewNode(
4506       simplified()->LoadField(AccessBuilder::ForJSArrayLength(kind)), receiver,
4507       effect, control);
4508 
4509   // Check if the {receiver} has any elements.
4510   Node* check = graph()->NewNode(simplified()->NumberEqual(), length,
4511                                  jsgraph()->ZeroConstant());
4512   Node* branch =
4513       graph()->NewNode(common()->Branch(BranchHint::kFalse), check, control);
4514 
4515   Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
4516   Node* etrue = effect;
4517   Node* vtrue = jsgraph()->UndefinedConstant();
4518 
4519   Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
4520   Node* efalse = effect;
4521   Node* vfalse;
4522   {
4523     // TODO(tebbi): We should trim the backing store if the capacity is too
4524     // big, as implemented in elements.cc:ElementsAccessorBase::SetLengthImpl.
4525 
4526     // Load the elements backing store from the {receiver}.
4527     Node* elements = efalse = graph()->NewNode(
4528         simplified()->LoadField(AccessBuilder::ForJSObjectElements()), receiver,
4529         efalse, if_false);
4530 
4531     // Ensure that we aren't popping from a copy-on-write backing store.
4532     if (IsSmiOrObjectElementsKind(kind)) {
4533       elements = efalse =
4534           graph()->NewNode(simplified()->EnsureWritableFastElements(), receiver,
4535                            elements, efalse, if_false);
4536     }
4537 
4538     // Compute the new {length}.
4539     length = graph()->NewNode(simplified()->NumberSubtract(), length,
4540                               jsgraph()->OneConstant());
4541 
4542     // Store the new {length} to the {receiver}.
4543     efalse = graph()->NewNode(
4544         simplified()->StoreField(AccessBuilder::ForJSArrayLength(kind)),
4545         receiver, length, efalse, if_false);
4546 
4547     // Load the last entry from the {elements}.
4548     vfalse = efalse = graph()->NewNode(
4549         simplified()->LoadElement(AccessBuilder::ForFixedArrayElement(kind)),
4550         elements, length, efalse, if_false);
4551 
4552     // Store a hole to the element we just removed from the {receiver}.
4553     efalse = graph()->NewNode(
4554         simplified()->StoreElement(
4555             AccessBuilder::ForFixedArrayElement(GetHoleyElementsKind(kind))),
4556         elements, length, jsgraph()->TheHoleConstant(), efalse, if_false);
4557   }
4558 
4559   control = graph()->NewNode(common()->Merge(2), if_true, if_false);
4560   effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);
4561   Node* value = graph()->NewNode(
4562       common()->Phi(MachineRepresentation::kTagged, 2), vtrue, vfalse, control);
4563 
4564   // Convert the hole to undefined. Do this last, so that we can optimize
4565   // conversion operator via some smart strength reduction in many cases.
4566   if (IsHoleyElementsKind(kind)) {
4567     value =
4568         graph()->NewNode(simplified()->ConvertTaggedHoleToUndefined(), value);
4569   }
4570 
4571   ReplaceWithValue(node, value, effect, control);
4572   return Replace(value);
4573 }
4574 
4575 // ES6 section 22.1.3.22 Array.prototype.shift ( )
ReduceArrayPrototypeShift(Node * node)4576 Reduction JSCallReducer::ReduceArrayPrototypeShift(Node* node) {
4577   DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
4578   CallParameters const& p = CallParametersOf(node->op());
4579   if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
4580     return NoChange();
4581   }
4582 
4583   if (!isolate()->IsNoElementsProtectorIntact()) return NoChange();
4584   Node* target = NodeProperties::GetValueInput(node, 0);
4585   Node* receiver = NodeProperties::GetValueInput(node, 1);
4586   Node* context = NodeProperties::GetContextInput(node);
4587   Node* frame_state = NodeProperties::GetFrameStateInput(node);
4588   Node* effect = NodeProperties::GetEffectInput(node);
4589   Node* control = NodeProperties::GetControlInput(node);
4590 
4591   ZoneHandleSet<Map> receiver_maps;
4592   NodeProperties::InferReceiverMapsResult result =
4593       NodeProperties::InferReceiverMaps(isolate(), receiver, effect,
4594                                         &receiver_maps);
4595   if (result == NodeProperties::kNoReceiverMaps) return NoChange();
4596   DCHECK_NE(0, receiver_maps.size());
4597 
4598   ElementsKind kind = receiver_maps[0]->elements_kind();
4599   for (Handle<Map> receiver_map : receiver_maps) {
4600     if (!CanInlineArrayResizeOperation(isolate(), receiver_map))
4601       return NoChange();
4602     // TODO(turbofan): Extend this to also handle fast holey double elements
4603     // once we got the hole NaN mess sorted out in TurboFan/V8.
4604     if (receiver_map->elements_kind() == HOLEY_DOUBLE_ELEMENTS)
4605       return NoChange();
4606     if (!UnionElementsKindUptoSize(&kind, receiver_map->elements_kind()))
4607       return NoChange();
4608   }
4609 
4610   // Install code dependencies on the {receiver} global array protector cell.
4611   dependencies()->DependOnProtector(
4612       PropertyCellRef(js_heap_broker(), factory()->no_elements_protector()));
4613 
4614   // If the {receiver_maps} information is not reliable, we need
4615   // to check that the {receiver} still has one of these maps.
4616   if (result == NodeProperties::kUnreliableReceiverMaps) {
4617     effect =
4618         graph()->NewNode(simplified()->CheckMaps(CheckMapsFlag::kNone,
4619                                                  receiver_maps, p.feedback()),
4620                          receiver, effect, control);
4621   }
4622 
4623   // Load length of the {receiver}.
4624   Node* length = effect = graph()->NewNode(
4625       simplified()->LoadField(AccessBuilder::ForJSArrayLength(kind)), receiver,
4626       effect, control);
4627 
4628   // Return undefined if {receiver} has no elements.
4629   Node* check0 = graph()->NewNode(simplified()->NumberEqual(), length,
4630                                   jsgraph()->ZeroConstant());
4631   Node* branch0 =
4632       graph()->NewNode(common()->Branch(BranchHint::kFalse), check0, control);
4633 
4634   Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
4635   Node* etrue0 = effect;
4636   Node* vtrue0 = jsgraph()->UndefinedConstant();
4637 
4638   Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
4639   Node* efalse0 = effect;
4640   Node* vfalse0;
4641   {
4642     // Check if we should take the fast-path.
4643     Node* check1 =
4644         graph()->NewNode(simplified()->NumberLessThanOrEqual(), length,
4645                          jsgraph()->Constant(JSArray::kMaxCopyElements));
4646     Node* branch1 = graph()->NewNode(common()->Branch(BranchHint::kTrue),
4647                                      check1, if_false0);
4648 
4649     Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
4650     Node* etrue1 = efalse0;
4651     Node* vtrue1;
4652     {
4653       Node* elements = etrue1 = graph()->NewNode(
4654           simplified()->LoadField(AccessBuilder::ForJSObjectElements()),
4655           receiver, etrue1, if_true1);
4656 
4657       // Load the first element here, which we return below.
4658       vtrue1 = etrue1 = graph()->NewNode(
4659           simplified()->LoadElement(AccessBuilder::ForFixedArrayElement(kind)),
4660           elements, jsgraph()->ZeroConstant(), etrue1, if_true1);
4661 
4662       // Ensure that we aren't shifting a copy-on-write backing store.
4663       if (IsSmiOrObjectElementsKind(kind)) {
4664         elements = etrue1 =
4665             graph()->NewNode(simplified()->EnsureWritableFastElements(),
4666                              receiver, elements, etrue1, if_true1);
4667       }
4668 
4669       // Shift the remaining {elements} by one towards the start.
4670       Node* loop = graph()->NewNode(common()->Loop(2), if_true1, if_true1);
4671       Node* eloop =
4672           graph()->NewNode(common()->EffectPhi(2), etrue1, etrue1, loop);
4673       Node* terminate = graph()->NewNode(common()->Terminate(), eloop, loop);
4674       NodeProperties::MergeControlToEnd(graph(), common(), terminate);
4675       Node* index = graph()->NewNode(
4676           common()->Phi(MachineRepresentation::kTagged, 2),
4677           jsgraph()->OneConstant(),
4678           jsgraph()->Constant(JSArray::kMaxCopyElements - 1), loop);
4679 
4680       {
4681         Node* check2 =
4682             graph()->NewNode(simplified()->NumberLessThan(), index, length);
4683         Node* branch2 = graph()->NewNode(common()->Branch(), check2, loop);
4684 
4685         if_true1 = graph()->NewNode(common()->IfFalse(), branch2);
4686         etrue1 = eloop;
4687 
4688         Node* control = graph()->NewNode(common()->IfTrue(), branch2);
4689         Node* effect = etrue1;
4690 
4691         ElementAccess const access = AccessBuilder::ForFixedArrayElement(kind);
4692         Node* value = effect =
4693             graph()->NewNode(simplified()->LoadElement(access), elements, index,
4694                              effect, control);
4695         effect =
4696             graph()->NewNode(simplified()->StoreElement(access), elements,
4697                              graph()->NewNode(simplified()->NumberSubtract(),
4698                                               index, jsgraph()->OneConstant()),
4699                              value, effect, control);
4700 
4701         loop->ReplaceInput(1, control);
4702         eloop->ReplaceInput(1, effect);
4703         index->ReplaceInput(1,
4704                             graph()->NewNode(simplified()->NumberAdd(), index,
4705                                              jsgraph()->OneConstant()));
4706       }
4707 
4708       // Compute the new {length}.
4709       length = graph()->NewNode(simplified()->NumberSubtract(), length,
4710                                 jsgraph()->OneConstant());
4711 
4712       // Store the new {length} to the {receiver}.
4713       etrue1 = graph()->NewNode(
4714           simplified()->StoreField(AccessBuilder::ForJSArrayLength(kind)),
4715           receiver, length, etrue1, if_true1);
4716 
4717       // Store a hole to the element we just removed from the {receiver}.
4718       etrue1 = graph()->NewNode(
4719           simplified()->StoreElement(
4720               AccessBuilder::ForFixedArrayElement(GetHoleyElementsKind(kind))),
4721           elements, length, jsgraph()->TheHoleConstant(), etrue1, if_true1);
4722     }
4723 
4724     Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
4725     Node* efalse1 = efalse0;
4726     Node* vfalse1;
4727     {
4728       // Call the generic C++ implementation.
4729       const int builtin_index = Builtins::kArrayShift;
4730       auto call_descriptor = Linkage::GetCEntryStubCallDescriptor(
4731           graph()->zone(), 1, BuiltinArguments::kNumExtraArgsWithReceiver,
4732           Builtins::name(builtin_index), node->op()->properties(),
4733           CallDescriptor::kNeedsFrameState);
4734       Node* stub_code =
4735           jsgraph()->CEntryStubConstant(1, kDontSaveFPRegs, kArgvOnStack, true);
4736       Address builtin_entry = Builtins::CppEntryOf(builtin_index);
4737       Node* entry =
4738           jsgraph()->ExternalConstant(ExternalReference::Create(builtin_entry));
4739       Node* argc =
4740           jsgraph()->Constant(BuiltinArguments::kNumExtraArgsWithReceiver);
4741       if_false1 = efalse1 = vfalse1 =
4742           graph()->NewNode(common()->Call(call_descriptor), stub_code, receiver,
4743                            jsgraph()->PaddingConstant(), argc, target,
4744                            jsgraph()->UndefinedConstant(), entry, argc, context,
4745                            frame_state, efalse1, if_false1);
4746     }
4747 
4748     if_false0 = graph()->NewNode(common()->Merge(2), if_true1, if_false1);
4749     efalse0 =
4750         graph()->NewNode(common()->EffectPhi(2), etrue1, efalse1, if_false0);
4751     vfalse0 = graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
4752                                vtrue1, vfalse1, if_false0);
4753     }
4754 
4755     control = graph()->NewNode(common()->Merge(2), if_true0, if_false0);
4756     effect = graph()->NewNode(common()->EffectPhi(2), etrue0, efalse0, control);
4757     Node* value =
4758         graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
4759                          vtrue0, vfalse0, control);
4760 
4761     // Convert the hole to undefined. Do this last, so that we can optimize
4762     // conversion operator via some smart strength reduction in many cases.
4763     if (IsHoleyElementsKind(kind)) {
4764       value =
4765           graph()->NewNode(simplified()->ConvertTaggedHoleToUndefined(), value);
4766     }
4767 
4768     ReplaceWithValue(node, value, effect, control);
4769     return Replace(value);
4770 }
4771 
4772 // ES6 section 22.1.3.23 Array.prototype.slice ( )
ReduceArrayPrototypeSlice(Node * node)4773 Reduction JSCallReducer::ReduceArrayPrototypeSlice(Node* node) {
4774   if (!FLAG_turbo_inline_array_builtins) return NoChange();
4775   DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
4776   CallParameters const& p = CallParametersOf(node->op());
4777   if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
4778     return NoChange();
4779   }
4780 
4781   int arity = static_cast<int>(p.arity() - 2);
4782   // Here we only optimize for cloning, that is when slice is called
4783   // without arguments, or with a single argument that is the constant 0.
4784   if (arity >= 2) return NoChange();
4785   if (arity == 1) {
4786     NumberMatcher m(NodeProperties::GetValueInput(node, 2));
4787     if (!m.HasValue()) return NoChange();
4788     if (m.Value() != 0) return NoChange();
4789   }
4790 
4791   Node* receiver = NodeProperties::GetValueInput(node, 1);
4792   Node* effect = NodeProperties::GetEffectInput(node);
4793   Node* control = NodeProperties::GetControlInput(node);
4794 
4795   // Try to determine the {receiver} map.
4796   ZoneHandleSet<Map> receiver_maps;
4797   NodeProperties::InferReceiverMapsResult result =
4798       NodeProperties::InferReceiverMaps(isolate(), receiver, effect,
4799                                         &receiver_maps);
4800   if (result == NodeProperties::kNoReceiverMaps) return NoChange();
4801 
4802   // Ensure that any changes to the Array species constructor cause deopt.
4803   if (!isolate()->IsArraySpeciesLookupChainIntact()) return NoChange();
4804   dependencies()->DependOnProtector(
4805       PropertyCellRef(js_heap_broker(), factory()->array_species_protector()));
4806 
4807   bool can_be_holey = false;
4808   // Check that the maps are of JSArray (and more)
4809   for (Handle<Map> receiver_map : receiver_maps) {
4810     if (!CanInlineArrayIteratingBuiltin(isolate(), receiver_map))
4811       return NoChange();
4812 
4813     if (IsHoleyElementsKind(receiver_map->elements_kind())) can_be_holey = true;
4814   }
4815 
4816   // Install code dependency on the array protector for holey arrays.
4817   if (can_be_holey) {
4818     dependencies()->DependOnProtector(
4819         PropertyCellRef(js_heap_broker(), factory()->no_elements_protector()));
4820   }
4821 
4822   // If we have unreliable maps, we need a map check.
4823   // This is actually redundant due to how JSNativeContextSpecialization
4824   // reduces the load of slice, but we do it here nevertheless for consistency
4825   // and robustness.
4826   if (result == NodeProperties::kUnreliableReceiverMaps) {
4827     effect =
4828         graph()->NewNode(simplified()->CheckMaps(CheckMapsFlag::kNone,
4829                                                  receiver_maps, p.feedback()),
4830                          receiver, effect, control);
4831   }
4832 
4833   Node* context = NodeProperties::GetContextInput(node);
4834 
4835   Callable callable =
4836       Builtins::CallableFor(isolate(), Builtins::kCloneFastJSArray);
4837   auto call_descriptor = Linkage::GetStubCallDescriptor(
4838       graph()->zone(), callable.descriptor(), 0, CallDescriptor::kNoFlags,
4839       Operator::kNoThrow | Operator::kNoDeopt);
4840 
4841   // Calls to Builtins::kCloneFastJSArray produce COW arrays
4842   // if the original array is COW
4843   Node* clone = effect = graph()->NewNode(
4844       common()->Call(call_descriptor), jsgraph()->HeapConstant(callable.code()),
4845       receiver, context, effect, control);
4846 
4847   ReplaceWithValue(node, clone, effect, control);
4848   return Replace(clone);
4849 }
4850 
4851 // ES6 section 22.1.2.2 Array.isArray ( arg )
ReduceArrayIsArray(Node * node)4852 Reduction JSCallReducer::ReduceArrayIsArray(Node* node) {
4853   // We certainly know that undefined is not an array.
4854   if (node->op()->ValueInputCount() < 3) {
4855     Node* value = jsgraph()->FalseConstant();
4856     ReplaceWithValue(node, value);
4857     return Replace(value);
4858   }
4859 
4860   Node* effect = NodeProperties::GetEffectInput(node);
4861   Node* control = NodeProperties::GetControlInput(node);
4862   Node* context = NodeProperties::GetContextInput(node);
4863   Node* frame_state = NodeProperties::GetFrameStateInput(node);
4864   Node* object = NodeProperties::GetValueInput(node, 2);
4865   node->ReplaceInput(0, object);
4866   node->ReplaceInput(1, context);
4867   node->ReplaceInput(2, frame_state);
4868   node->ReplaceInput(3, effect);
4869   node->ReplaceInput(4, control);
4870   node->TrimInputCount(5);
4871   NodeProperties::ChangeOp(node, javascript()->ObjectIsArray());
4872   return Changed(node);
4873 }
4874 
ReduceArrayIterator(Node * node,IterationKind kind)4875 Reduction JSCallReducer::ReduceArrayIterator(Node* node, IterationKind kind) {
4876   DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
4877   Node* receiver = NodeProperties::GetValueInput(node, 1);
4878   Node* context = NodeProperties::GetContextInput(node);
4879   Node* effect = NodeProperties::GetEffectInput(node);
4880   Node* control = NodeProperties::GetControlInput(node);
4881 
4882   // Check if we know that {receiver} is a valid JSReceiver.
4883   ZoneHandleSet<Map> receiver_maps;
4884   NodeProperties::InferReceiverMapsResult result =
4885       NodeProperties::InferReceiverMaps(isolate(), receiver, effect,
4886                                         &receiver_maps);
4887   if (result == NodeProperties::kNoReceiverMaps) return NoChange();
4888   DCHECK_NE(0, receiver_maps.size());
4889   for (Handle<Map> receiver_map : receiver_maps) {
4890     if (!receiver_map->IsJSReceiverMap()) return NoChange();
4891   }
4892 
4893   // Morph the {node} into a JSCreateArrayIterator with the given {kind}.
4894   RelaxControls(node);
4895   node->ReplaceInput(0, receiver);
4896   node->ReplaceInput(1, context);
4897   node->ReplaceInput(2, effect);
4898   node->ReplaceInput(3, control);
4899   node->TrimInputCount(4);
4900   NodeProperties::ChangeOp(node, javascript()->CreateArrayIterator(kind));
4901   return Changed(node);
4902 }
4903 
4904 namespace {
4905 
InferIteratedObjectMaps(Isolate * isolate,Node * iterator,ZoneHandleSet<Map> * iterated_object_maps)4906 bool InferIteratedObjectMaps(Isolate* isolate, Node* iterator,
4907                              ZoneHandleSet<Map>* iterated_object_maps) {
4908   DCHECK_EQ(IrOpcode::kJSCreateArrayIterator, iterator->opcode());
4909   Node* iterated_object = NodeProperties::GetValueInput(iterator, 0);
4910   Node* effect = NodeProperties::GetEffectInput(iterator);
4911 
4912   NodeProperties::InferReceiverMapsResult result =
4913       NodeProperties::InferReceiverMaps(isolate, iterated_object, effect,
4914                                         iterated_object_maps);
4915   return result != NodeProperties::kNoReceiverMaps;
4916 }
4917 
4918 }  // namespace
4919 
4920 // ES #sec-%arrayiteratorprototype%.next
ReduceArrayIteratorPrototypeNext(Node * node)4921 Reduction JSCallReducer::ReduceArrayIteratorPrototypeNext(Node* node) {
4922   DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
4923   CallParameters const& p = CallParametersOf(node->op());
4924   Node* iterator = NodeProperties::GetValueInput(node, 1);
4925   Node* context = NodeProperties::GetContextInput(node);
4926   Node* effect = NodeProperties::GetEffectInput(node);
4927   Node* control = NodeProperties::GetControlInput(node);
4928 
4929   if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
4930     return NoChange();
4931   }
4932 
4933   // Check if the {iterator} is a JSCreateArrayIterator.
4934   if (iterator->opcode() != IrOpcode::kJSCreateArrayIterator) return NoChange();
4935   IterationKind const iteration_kind =
4936       CreateArrayIteratorParametersOf(iterator->op()).kind();
4937 
4938   // Try to infer the [[IteratedObject]] maps from the {iterator}.
4939   ZoneHandleSet<Map> iterated_object_maps;
4940   if (!InferIteratedObjectMaps(isolate(), iterator, &iterated_object_maps)) {
4941     return NoChange();
4942   }
4943   DCHECK_NE(0, iterated_object_maps.size());
4944 
4945   // Check that various {iterated_object_maps} have compatible elements kinds.
4946   ElementsKind elements_kind = iterated_object_maps[0]->elements_kind();
4947   if (IsFixedTypedArrayElementsKind(elements_kind)) {
4948     // TurboFan doesn't support loading from BigInt typed arrays yet.
4949     if (elements_kind == BIGUINT64_ELEMENTS ||
4950         elements_kind == BIGINT64_ELEMENTS) {
4951       return NoChange();
4952     }
4953     for (Handle<Map> iterated_object_map : iterated_object_maps) {
4954       if (iterated_object_map->elements_kind() != elements_kind) {
4955         return NoChange();
4956       }
4957     }
4958   } else {
4959     for (Handle<Map> iterated_object_map : iterated_object_maps) {
4960       if (!CanInlineArrayIteratingBuiltin(isolate(), iterated_object_map)) {
4961         return NoChange();
4962       }
4963       if (!UnionElementsKindUptoSize(&elements_kind,
4964                                      iterated_object_map->elements_kind())) {
4965         return NoChange();
4966       }
4967     }
4968   }
4969 
4970   // Install code dependency on the array protector for holey arrays.
4971   if (IsHoleyElementsKind(elements_kind)) {
4972     dependencies()->DependOnProtector(
4973         PropertyCellRef(js_heap_broker(), factory()->no_elements_protector()));
4974   }
4975 
4976   // Load the (current) {iterated_object} from the {iterator}.
4977   Node* iterated_object = effect =
4978       graph()->NewNode(simplified()->LoadField(
4979                            AccessBuilder::ForJSArrayIteratorIteratedObject()),
4980                        iterator, effect, control);
4981 
4982   // Ensure that the {iterated_object} map didn't change.
4983   effect = graph()->NewNode(
4984       simplified()->CheckMaps(CheckMapsFlag::kNone, iterated_object_maps,
4985                               p.feedback()),
4986       iterated_object, effect, control);
4987 
4988   if (IsFixedTypedArrayElementsKind(elements_kind)) {
4989     // See if we can skip the neutering check.
4990     if (isolate()->IsArrayBufferNeuteringIntact()) {
4991       // Add a code dependency so we are deoptimized in case an ArrayBuffer
4992       // gets neutered.
4993       dependencies()->DependOnProtector(PropertyCellRef(
4994           js_heap_broker(), factory()->array_buffer_neutering_protector()));
4995     } else {
4996       // Deoptimize if the array buffer was neutered.
4997       Node* buffer = effect = graph()->NewNode(
4998           simplified()->LoadField(AccessBuilder::ForJSArrayBufferViewBuffer()),
4999           iterated_object, effect, control);
5000 
5001       Node* check = effect = graph()->NewNode(
5002           simplified()->ArrayBufferWasNeutered(), buffer, effect, control);
5003       check = graph()->NewNode(simplified()->BooleanNot(), check);
5004       // TODO(bmeurer): Pass p.feedback(), or better introduce
5005       // CheckArrayBufferNotNeutered?
5006       effect = graph()->NewNode(
5007           simplified()->CheckIf(DeoptimizeReason::kArrayBufferWasNeutered),
5008           check, effect, control);
5009     }
5010   }
5011 
5012   // Load the [[NextIndex]] from the {iterator} and leverage the fact
5013   // that we definitely know that it's in Unsigned32 range since the
5014   // {iterated_object} is either a JSArray or a JSTypedArray. For the
5015   // latter case we even know that it's a Smi in UnsignedSmall range.
5016   FieldAccess index_access = AccessBuilder::ForJSArrayIteratorNextIndex();
5017   if (IsFixedTypedArrayElementsKind(elements_kind)) {
5018     index_access.type = TypeCache::Get().kJSTypedArrayLengthType;
5019     index_access.machine_type = MachineType::TaggedSigned();
5020     index_access.write_barrier_kind = kNoWriteBarrier;
5021   } else {
5022     index_access.type = TypeCache::Get().kJSArrayLengthType;
5023   }
5024   Node* index = effect = graph()->NewNode(simplified()->LoadField(index_access),
5025                                           iterator, effect, control);
5026 
5027   // Load the elements of the {iterated_object}. While it feels
5028   // counter-intuitive to place the elements pointer load before
5029   // the condition below, as it might not be needed (if the {index}
5030   // is out of bounds for the {iterated_object}), it's better this
5031   // way as it allows the LoadElimination to eliminate redundant
5032   // reloads of the elements pointer.
5033   Node* elements = effect = graph()->NewNode(
5034       simplified()->LoadField(AccessBuilder::ForJSObjectElements()),
5035       iterated_object, effect, control);
5036 
5037   // Load the length of the {iterated_object}. Due to the map checks we
5038   // already know something about the length here, which we can leverage
5039   // to generate Word32 operations below without additional checking.
5040   FieldAccess length_access =
5041       IsFixedTypedArrayElementsKind(elements_kind)
5042           ? AccessBuilder::ForJSTypedArrayLength()
5043           : AccessBuilder::ForJSArrayLength(elements_kind);
5044   Node* length = effect = graph()->NewNode(
5045       simplified()->LoadField(length_access), iterated_object, effect, control);
5046 
5047   // Check whether {index} is within the valid range for the {iterated_object}.
5048   Node* check = graph()->NewNode(simplified()->NumberLessThan(), index, length);
5049   Node* branch =
5050       graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
5051 
5052   Node* done_true;
5053   Node* value_true;
5054   Node* etrue = effect;
5055   Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
5056   {
5057     // We know that the {index} is range of the {length} now.
5058     index = etrue = graph()->NewNode(
5059         common()->TypeGuard(
5060             Type::Range(0.0, length_access.type.Max() - 1.0, graph()->zone())),
5061         index, etrue, if_true);
5062 
5063     done_true = jsgraph()->FalseConstant();
5064     if (iteration_kind == IterationKind::kKeys) {
5065       // Just return the {index}.
5066       value_true = index;
5067     } else {
5068       DCHECK(iteration_kind == IterationKind::kEntries ||
5069              iteration_kind == IterationKind::kValues);
5070 
5071       if (IsFixedTypedArrayElementsKind(elements_kind)) {
5072         Node* base_ptr = etrue = graph()->NewNode(
5073             simplified()->LoadField(
5074                 AccessBuilder::ForFixedTypedArrayBaseBasePointer()),
5075             elements, etrue, if_true);
5076         Node* external_ptr = etrue = graph()->NewNode(
5077             simplified()->LoadField(
5078                 AccessBuilder::ForFixedTypedArrayBaseExternalPointer()),
5079             elements, etrue, if_true);
5080 
5081         ExternalArrayType array_type = kExternalInt8Array;
5082         switch (elements_kind) {
5083 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) \
5084   case TYPE##_ELEMENTS:                           \
5085     array_type = kExternal##Type##Array;          \
5086     break;
5087           TYPED_ARRAYS(TYPED_ARRAY_CASE)
5088           default:
5089             UNREACHABLE();
5090 #undef TYPED_ARRAY_CASE
5091         }
5092 
5093         Node* buffer = etrue =
5094             graph()->NewNode(simplified()->LoadField(
5095                                  AccessBuilder::ForJSArrayBufferViewBuffer()),
5096                              iterated_object, etrue, if_true);
5097 
5098         value_true = etrue =
5099             graph()->NewNode(simplified()->LoadTypedElement(array_type), buffer,
5100                              base_ptr, external_ptr, index, etrue, if_true);
5101       } else {
5102         value_true = etrue = graph()->NewNode(
5103             simplified()->LoadElement(
5104                 AccessBuilder::ForFixedArrayElement(elements_kind)),
5105             elements, index, etrue, if_true);
5106 
5107         // Convert hole to undefined if needed.
5108         if (elements_kind == HOLEY_ELEMENTS ||
5109             elements_kind == HOLEY_SMI_ELEMENTS) {
5110           value_true = graph()->NewNode(
5111               simplified()->ConvertTaggedHoleToUndefined(), value_true);
5112         } else if (elements_kind == HOLEY_DOUBLE_ELEMENTS) {
5113           // TODO(6587): avoid deopt if not all uses of value are truncated.
5114           CheckFloat64HoleMode mode = CheckFloat64HoleMode::kAllowReturnHole;
5115           value_true = etrue = graph()->NewNode(
5116               simplified()->CheckFloat64Hole(mode, p.feedback()), value_true,
5117               etrue, if_true);
5118         }
5119       }
5120 
5121       if (iteration_kind == IterationKind::kEntries) {
5122         // Allocate elements for key/value pair
5123         value_true = etrue =
5124             graph()->NewNode(javascript()->CreateKeyValueArray(), index,
5125                              value_true, context, etrue);
5126       } else {
5127         DCHECK_EQ(IterationKind::kValues, iteration_kind);
5128       }
5129     }
5130 
5131     // Increment the [[NextIndex]] field in the {iterator}. The TypeGuards
5132     // above guarantee that the {next_index} is in the UnsignedSmall range.
5133     Node* next_index = graph()->NewNode(simplified()->NumberAdd(), index,
5134                                         jsgraph()->OneConstant());
5135     etrue = graph()->NewNode(simplified()->StoreField(index_access), iterator,
5136                              next_index, etrue, if_true);
5137   }
5138 
5139   Node* done_false;
5140   Node* value_false;
5141   Node* efalse = effect;
5142   Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
5143   {
5144     // iterator.[[NextIndex]] >= array.length, stop iterating.
5145     done_false = jsgraph()->TrueConstant();
5146     value_false = jsgraph()->UndefinedConstant();
5147 
5148     if (!IsFixedTypedArrayElementsKind(elements_kind)) {
5149       // Mark the {iterator} as exhausted by setting the [[NextIndex]] to a
5150       // value that will never pass the length check again (aka the maximum
5151       // value possible for the specific iterated object). Note that this is
5152       // different from what the specification says, which is changing the
5153       // [[IteratedObject]] field to undefined, but that makes it difficult
5154       // to eliminate the map checks and "length" accesses in for..of loops.
5155       //
5156       // This is not necessary for JSTypedArray's, since the length of those
5157       // cannot change later and so if we were ever out of bounds for them
5158       // we will stay out-of-bounds forever.
5159       Node* end_index = jsgraph()->Constant(index_access.type.Max());
5160       efalse = graph()->NewNode(simplified()->StoreField(index_access),
5161                                 iterator, end_index, efalse, if_false);
5162     }
5163   }
5164 
5165   control = graph()->NewNode(common()->Merge(2), if_true, if_false);
5166   effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);
5167   Node* value =
5168       graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
5169                        value_true, value_false, control);
5170   Node* done =
5171       graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
5172                        done_true, done_false, control);
5173 
5174   // Create IteratorResult object.
5175   value = effect = graph()->NewNode(javascript()->CreateIterResultObject(),
5176                                     value, done, context, effect);
5177   ReplaceWithValue(node, value, effect, control);
5178   return Replace(value);
5179 }
5180 
5181 // ES6 section 21.1.3.2 String.prototype.charCodeAt ( pos )
5182 // ES6 section 21.1.3.3 String.prototype.codePointAt ( pos )
ReduceStringPrototypeStringAt(const Operator * string_access_operator,Node * node)5183 Reduction JSCallReducer::ReduceStringPrototypeStringAt(
5184     const Operator* string_access_operator, Node* node) {
5185   DCHECK(string_access_operator->opcode() == IrOpcode::kStringCharCodeAt ||
5186          string_access_operator->opcode() == IrOpcode::kStringCodePointAt);
5187   DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
5188   CallParameters const& p = CallParametersOf(node->op());
5189   if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
5190     return NoChange();
5191   }
5192 
5193   Node* receiver = NodeProperties::GetValueInput(node, 1);
5194   Node* index = node->op()->ValueInputCount() >= 3
5195                     ? NodeProperties::GetValueInput(node, 2)
5196                     : jsgraph()->ZeroConstant();
5197   Node* effect = NodeProperties::GetEffectInput(node);
5198   Node* control = NodeProperties::GetControlInput(node);
5199 
5200   // Ensure that the {receiver} is actually a String.
5201   receiver = effect = graph()->NewNode(simplified()->CheckString(p.feedback()),
5202                                        receiver, effect, control);
5203 
5204   // Determine the {receiver} length.
5205   Node* receiver_length =
5206       graph()->NewNode(simplified()->StringLength(), receiver);
5207 
5208   // Check that the {index} is within range.
5209   index = effect = graph()->NewNode(simplified()->CheckBounds(p.feedback()),
5210                                     index, receiver_length, effect, control);
5211 
5212   // Return the character from the {receiver} as single character string.
5213   Node* masked_index = graph()->NewNode(simplified()->PoisonIndex(), index);
5214   Node* value = effect = graph()->NewNode(string_access_operator, receiver,
5215                                           masked_index, effect, control);
5216 
5217   ReplaceWithValue(node, value, effect, control);
5218   return Replace(value);
5219 }
5220 
5221 // ES section 21.1.3.1 String.prototype.charAt ( pos )
ReduceStringPrototypeCharAt(Node * node)5222 Reduction JSCallReducer::ReduceStringPrototypeCharAt(Node* node) {
5223   DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
5224   CallParameters const& p = CallParametersOf(node->op());
5225   if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
5226     return NoChange();
5227   }
5228 
5229   Node* receiver = NodeProperties::GetValueInput(node, 1);
5230   Node* index = node->op()->ValueInputCount() >= 3
5231                     ? NodeProperties::GetValueInput(node, 2)
5232                     : jsgraph()->ZeroConstant();
5233   Node* effect = NodeProperties::GetEffectInput(node);
5234   Node* control = NodeProperties::GetControlInput(node);
5235 
5236   // Ensure that the {receiver} is actually a String.
5237   receiver = effect = graph()->NewNode(simplified()->CheckString(p.feedback()),
5238                                        receiver, effect, control);
5239 
5240   // Determine the {receiver} length.
5241   Node* receiver_length =
5242       graph()->NewNode(simplified()->StringLength(), receiver);
5243 
5244   // Check that the {index} is within range.
5245   index = effect = graph()->NewNode(simplified()->CheckBounds(p.feedback()),
5246                                     index, receiver_length, effect, control);
5247 
5248   // Return the character from the {receiver} as single character string.
5249   Node* masked_index = graph()->NewNode(simplified()->PoisonIndex(), index);
5250   Node* value = effect =
5251       graph()->NewNode(simplified()->StringCharCodeAt(), receiver, masked_index,
5252                        effect, control);
5253   value = graph()->NewNode(simplified()->StringFromSingleCharCode(), value);
5254 
5255   ReplaceWithValue(node, value, effect, control);
5256   return Replace(value);
5257 }
5258 
5259 #ifdef V8_INTL_SUPPORT
5260 
ReduceStringPrototypeToLowerCaseIntl(Node * node)5261 Reduction JSCallReducer::ReduceStringPrototypeToLowerCaseIntl(Node* node) {
5262   DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
5263   CallParameters const& p = CallParametersOf(node->op());
5264   if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
5265     return NoChange();
5266   }
5267   Node* effect = NodeProperties::GetEffectInput(node);
5268   Node* control = NodeProperties::GetControlInput(node);
5269 
5270   Node* receiver = effect =
5271       graph()->NewNode(simplified()->CheckString(p.feedback()),
5272                        NodeProperties::GetValueInput(node, 1), effect, control);
5273 
5274   NodeProperties::ReplaceEffectInput(node, effect);
5275   RelaxEffectsAndControls(node);
5276   node->ReplaceInput(0, receiver);
5277   node->TrimInputCount(1);
5278   NodeProperties::ChangeOp(node, simplified()->StringToLowerCaseIntl());
5279   NodeProperties::SetType(node, Type::String());
5280   return Changed(node);
5281 }
5282 
ReduceStringPrototypeToUpperCaseIntl(Node * node)5283 Reduction JSCallReducer::ReduceStringPrototypeToUpperCaseIntl(Node* node) {
5284   DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
5285   CallParameters const& p = CallParametersOf(node->op());
5286   if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
5287     return NoChange();
5288   }
5289   Node* effect = NodeProperties::GetEffectInput(node);
5290   Node* control = NodeProperties::GetControlInput(node);
5291 
5292   Node* receiver = effect =
5293       graph()->NewNode(simplified()->CheckString(p.feedback()),
5294                        NodeProperties::GetValueInput(node, 1), effect, control);
5295 
5296   NodeProperties::ReplaceEffectInput(node, effect);
5297   RelaxEffectsAndControls(node);
5298   node->ReplaceInput(0, receiver);
5299   node->TrimInputCount(1);
5300   NodeProperties::ChangeOp(node, simplified()->StringToUpperCaseIntl());
5301   NodeProperties::SetType(node, Type::String());
5302   return Changed(node);
5303 }
5304 
5305 #endif  // V8_INTL_SUPPORT
5306 
5307 // ES #sec-string.fromcharcode
ReduceStringFromCharCode(Node * node)5308 Reduction JSCallReducer::ReduceStringFromCharCode(Node* node) {
5309   DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
5310   CallParameters const& p = CallParametersOf(node->op());
5311   if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
5312     return NoChange();
5313   }
5314   if (node->op()->ValueInputCount() == 3) {
5315     Node* effect = NodeProperties::GetEffectInput(node);
5316     Node* control = NodeProperties::GetControlInput(node);
5317     Node* input = NodeProperties::GetValueInput(node, 2);
5318 
5319     input = effect = graph()->NewNode(
5320         simplified()->SpeculativeToNumber(NumberOperationHint::kNumberOrOddball,
5321                                           p.feedback()),
5322         input, effect, control);
5323 
5324     Node* value =
5325         graph()->NewNode(simplified()->StringFromSingleCharCode(), input);
5326     ReplaceWithValue(node, value, effect);
5327     return Replace(value);
5328   }
5329   return NoChange();
5330 }
5331 
5332 // ES #sec-string.fromcodepoint
ReduceStringFromCodePoint(Node * node)5333 Reduction JSCallReducer::ReduceStringFromCodePoint(Node* node) {
5334   DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
5335   CallParameters const& p = CallParametersOf(node->op());
5336   if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
5337     return NoChange();
5338   }
5339   if (node->op()->ValueInputCount() == 3) {
5340     Node* effect = NodeProperties::GetEffectInput(node);
5341     Node* control = NodeProperties::GetControlInput(node);
5342     Node* input = NodeProperties::GetValueInput(node, 2);
5343 
5344     input = effect = graph()->NewNode(simplified()->CheckSmi(p.feedback()),
5345                                       input, effect, control);
5346 
5347     input = effect =
5348         graph()->NewNode(simplified()->CheckBounds(p.feedback()), input,
5349                          jsgraph()->Constant(0x10FFFF + 1), effect, control);
5350 
5351     Node* value = graph()->NewNode(
5352         simplified()->StringFromSingleCodePoint(UnicodeEncoding::UTF32), input);
5353     ReplaceWithValue(node, value, effect);
5354     return Replace(value);
5355   }
5356   return NoChange();
5357 }
5358 
ReduceStringPrototypeIterator(Node * node)5359 Reduction JSCallReducer::ReduceStringPrototypeIterator(Node* node) {
5360   CallParameters const& p = CallParametersOf(node->op());
5361   if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
5362     return NoChange();
5363   }
5364   Node* effect = NodeProperties::GetEffectInput(node);
5365   Node* control = NodeProperties::GetControlInput(node);
5366   Node* receiver = effect =
5367       graph()->NewNode(simplified()->CheckString(p.feedback()),
5368                        NodeProperties::GetValueInput(node, 1), effect, control);
5369   Node* iterator = effect =
5370       graph()->NewNode(javascript()->CreateStringIterator(), receiver,
5371                        jsgraph()->NoContextConstant(), effect);
5372   ReplaceWithValue(node, iterator, effect, control);
5373   return Replace(iterator);
5374 }
5375 
ReduceStringIteratorPrototypeNext(Node * node)5376 Reduction JSCallReducer::ReduceStringIteratorPrototypeNext(Node* node) {
5377   Node* receiver = NodeProperties::GetValueInput(node, 1);
5378   Node* effect = NodeProperties::GetEffectInput(node);
5379   Node* control = NodeProperties::GetControlInput(node);
5380   Node* context = NodeProperties::GetContextInput(node);
5381   if (NodeProperties::HasInstanceTypeWitness(isolate(), receiver, effect,
5382                                              JS_STRING_ITERATOR_TYPE)) {
5383     Node* string = effect = graph()->NewNode(
5384         simplified()->LoadField(AccessBuilder::ForJSStringIteratorString()),
5385         receiver, effect, control);
5386     Node* index = effect = graph()->NewNode(
5387         simplified()->LoadField(AccessBuilder::ForJSStringIteratorIndex()),
5388         receiver, effect, control);
5389     Node* length = graph()->NewNode(simplified()->StringLength(), string);
5390 
5391     // branch0: if (index < length)
5392     Node* check0 =
5393         graph()->NewNode(simplified()->NumberLessThan(), index, length);
5394     Node* branch0 =
5395         graph()->NewNode(common()->Branch(BranchHint::kTrue), check0, control);
5396 
5397     Node* etrue0 = effect;
5398     Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
5399     Node* done_true;
5400     Node* vtrue0;
5401     {
5402       done_true = jsgraph()->FalseConstant();
5403       Node* codepoint = etrue0 = graph()->NewNode(
5404           simplified()->StringCodePointAt(UnicodeEncoding::UTF16), string,
5405           index, etrue0, if_true0);
5406       vtrue0 = graph()->NewNode(
5407           simplified()->StringFromSingleCodePoint(UnicodeEncoding::UTF16),
5408           codepoint);
5409 
5410       // Update iterator.[[NextIndex]]
5411       Node* char_length =
5412           graph()->NewNode(simplified()->StringLength(), vtrue0);
5413       index = graph()->NewNode(simplified()->NumberAdd(), index, char_length);
5414       etrue0 = graph()->NewNode(
5415           simplified()->StoreField(AccessBuilder::ForJSStringIteratorIndex()),
5416           receiver, index, etrue0, if_true0);
5417     }
5418 
5419     Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
5420     Node* done_false;
5421     Node* vfalse0;
5422     {
5423       vfalse0 = jsgraph()->UndefinedConstant();
5424       done_false = jsgraph()->TrueConstant();
5425     }
5426 
5427     control = graph()->NewNode(common()->Merge(2), if_true0, if_false0);
5428     effect = graph()->NewNode(common()->EffectPhi(2), etrue0, effect, control);
5429     Node* value =
5430         graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
5431                          vtrue0, vfalse0, control);
5432     Node* done =
5433         graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
5434                          done_true, done_false, control);
5435 
5436     value = effect = graph()->NewNode(javascript()->CreateIterResultObject(),
5437                                       value, done, context, effect);
5438 
5439     ReplaceWithValue(node, value, effect, control);
5440     return Replace(value);
5441   }
5442   return NoChange();
5443 }
5444 
5445 // ES #sec-string.prototype.concat
ReduceStringPrototypeConcat(Node * node,Handle<SharedFunctionInfo> shared)5446 Reduction JSCallReducer::ReduceStringPrototypeConcat(
5447     Node* node, Handle<SharedFunctionInfo> shared) {
5448   if (node->op()->ValueInputCount() < 2 || node->op()->ValueInputCount() > 3) {
5449     return NoChange();
5450   }
5451   CallParameters const& p = CallParametersOf(node->op());
5452   if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
5453     return NoChange();
5454   }
5455   Node* effect = NodeProperties::GetEffectInput(node);
5456   Node* control = NodeProperties::GetControlInput(node);
5457   Node* context = NodeProperties::GetContextInput(node);
5458   Node* receiver = effect =
5459       graph()->NewNode(simplified()->CheckString(p.feedback()),
5460                        NodeProperties::GetValueInput(node, 1), effect, control);
5461 
5462   if (node->op()->ValueInputCount() < 3) {
5463     ReplaceWithValue(node, receiver, effect, control);
5464     return Replace(receiver);
5465   }
5466   Node* argument = effect =
5467       graph()->NewNode(simplified()->CheckString(p.feedback()),
5468                        NodeProperties::GetValueInput(node, 2), effect, control);
5469 
5470   Callable const callable =
5471       CodeFactory::StringAdd(isolate(), STRING_ADD_CHECK_NONE, NOT_TENURED);
5472   auto call_descriptor =
5473       Linkage::GetStubCallDescriptor(graph()->zone(), callable.descriptor(), 0,
5474                                      CallDescriptor::kNeedsFrameState,
5475                                      Operator::kNoDeopt | Operator::kNoWrite);
5476 
5477   // TODO(turbofan): Massage the FrameState of the {node} here once we
5478   // have an artificial builtin frame type, so that it looks like the
5479   // exception from StringAdd overflow came from String.prototype.concat
5480   // builtin instead of the calling function.
5481   Node* outer_frame_state = NodeProperties::GetFrameStateInput(node);
5482 
5483   Node* value = effect = control = graph()->NewNode(
5484       common()->Call(call_descriptor), jsgraph()->HeapConstant(callable.code()),
5485       receiver, argument, context, outer_frame_state, effect, control);
5486 
5487   ReplaceWithValue(node, value, effect, control);
5488   return Replace(value);
5489 }
5490 
ReduceAsyncFunctionPromiseCreate(Node * node)5491 Reduction JSCallReducer::ReduceAsyncFunctionPromiseCreate(Node* node) {
5492   DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
5493   Node* context = NodeProperties::GetContextInput(node);
5494   Node* effect = NodeProperties::GetEffectInput(node);
5495   if (!isolate()->IsPromiseHookProtectorIntact()) return NoChange();
5496 
5497   // Install a code dependency on the promise hook protector cell.
5498   dependencies()->DependOnProtector(
5499       PropertyCellRef(js_heap_broker(), factory()->promise_hook_protector()));
5500 
5501   // Morph this {node} into a JSCreatePromise node.
5502   RelaxControls(node);
5503   node->ReplaceInput(0, context);
5504   node->ReplaceInput(1, effect);
5505   node->TrimInputCount(2);
5506   NodeProperties::ChangeOp(node, javascript()->CreatePromise());
5507   return Changed(node);
5508 }
5509 
ReduceAsyncFunctionPromiseRelease(Node * node)5510 Reduction JSCallReducer::ReduceAsyncFunctionPromiseRelease(Node* node) {
5511   DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
5512   if (!isolate()->IsPromiseHookProtectorIntact()) return NoChange();
5513 
5514   dependencies()->DependOnProtector(
5515       PropertyCellRef(js_heap_broker(), factory()->promise_hook_protector()));
5516 
5517   // The AsyncFunctionPromiseRelease builtin is a no-op as long as neither
5518   // the debugger is active nor any promise hook has been installed (ever).
5519   Node* value = jsgraph()->UndefinedConstant();
5520   ReplaceWithValue(node, value);
5521   return Replace(value);
5522 }
5523 
CreateArtificialFrameState(Node * node,Node * outer_frame_state,int parameter_count,BailoutId bailout_id,FrameStateType frame_state_type,Handle<SharedFunctionInfo> shared)5524 Node* JSCallReducer::CreateArtificialFrameState(
5525     Node* node, Node* outer_frame_state, int parameter_count,
5526     BailoutId bailout_id, FrameStateType frame_state_type,
5527     Handle<SharedFunctionInfo> shared) {
5528   const FrameStateFunctionInfo* state_info =
5529       common()->CreateFrameStateFunctionInfo(frame_state_type,
5530                                              parameter_count + 1, 0, shared);
5531 
5532   const Operator* op = common()->FrameState(
5533       bailout_id, OutputFrameStateCombine::Ignore(), state_info);
5534   const Operator* op0 = common()->StateValues(0, SparseInputMask::Dense());
5535   Node* node0 = graph()->NewNode(op0);
5536   std::vector<Node*> params;
5537   for (int parameter = 0; parameter < parameter_count + 1; ++parameter) {
5538     params.push_back(node->InputAt(1 + parameter));
5539   }
5540   const Operator* op_param = common()->StateValues(
5541       static_cast<int>(params.size()), SparseInputMask::Dense());
5542   Node* params_node = graph()->NewNode(
5543       op_param, static_cast<int>(params.size()), &params.front());
5544   return graph()->NewNode(op, params_node, node0, node0,
5545                           jsgraph()->UndefinedConstant(), node->InputAt(0),
5546                           outer_frame_state);
5547 }
5548 
ReducePromiseConstructor(Node * node)5549 Reduction JSCallReducer::ReducePromiseConstructor(Node* node) {
5550   DCHECK_EQ(IrOpcode::kJSConstruct, node->opcode());
5551   ConstructParameters const& p = ConstructParametersOf(node->op());
5552   int arity = static_cast<int>(p.arity() - 2);
5553   // We only inline when we have the executor.
5554   if (arity < 1) return NoChange();
5555   Node* target = NodeProperties::GetValueInput(node, 0);
5556   Node* executor = NodeProperties::GetValueInput(node, 1);
5557   Node* new_target = NodeProperties::GetValueInput(node, arity + 1);
5558 
5559   Node* context = NodeProperties::GetContextInput(node);
5560   Node* outer_frame_state = NodeProperties::GetFrameStateInput(node);
5561   Node* effect = NodeProperties::GetEffectInput(node);
5562   Node* control = NodeProperties::GetControlInput(node);
5563 
5564   if (!FLAG_experimental_inline_promise_constructor) return NoChange();
5565   if (!isolate()->IsPromiseHookProtectorIntact()) return NoChange();
5566 
5567   // Only handle builtins Promises, not subclasses.
5568   if (target != new_target) return NoChange();
5569 
5570   dependencies()->DependOnProtector(
5571       PropertyCellRef(js_heap_broker(), factory()->promise_hook_protector()));
5572 
5573   Handle<SharedFunctionInfo> promise_shared(
5574       handle(native_context()->promise_function()->shared(), isolate()));
5575 
5576   // Insert a construct stub frame into the chain of frame states. This will
5577   // reconstruct the proper frame when deoptimizing within the constructor.
5578   // For the frame state, we only provide the executor parameter, even if more
5579   // arugments were passed. This is not observable from JS.
5580   DCHECK_EQ(1, promise_shared->internal_formal_parameter_count());
5581   Node* constructor_frame_state = CreateArtificialFrameState(
5582       node, outer_frame_state, 1, BailoutId::ConstructStubInvoke(),
5583       FrameStateType::kConstructStub, promise_shared);
5584 
5585   // The deopt continuation of this frame state is never called; the frame state
5586   // is only necessary to obtain the right stack trace.
5587   const std::vector<Node*> checkpoint_parameters({
5588       jsgraph()->UndefinedConstant(), /* receiver */
5589       jsgraph()->UndefinedConstant(), /* promise */
5590       jsgraph()->UndefinedConstant(), /* reject function */
5591       jsgraph()->TheHoleConstant()    /* exception */
5592   });
5593   int checkpoint_parameters_size =
5594       static_cast<int>(checkpoint_parameters.size());
5595   Node* frame_state = CreateJavaScriptBuiltinContinuationFrameState(
5596       jsgraph(), promise_shared,
5597       Builtins::kPromiseConstructorLazyDeoptContinuation, target, context,
5598       checkpoint_parameters.data(), checkpoint_parameters_size,
5599       constructor_frame_state, ContinuationFrameStateMode::LAZY);
5600 
5601   // Check if executor is callable
5602   Node* check_fail = nullptr;
5603   Node* check_throw = nullptr;
5604   WireInCallbackIsCallableCheck(executor, context, frame_state, effect,
5605                                 &control, &check_fail, &check_throw);
5606 
5607   // Create the resulting JSPromise.
5608   Node* promise = effect =
5609       graph()->NewNode(javascript()->CreatePromise(), context, effect);
5610 
5611   // 8. CreatePromiseResolvingFunctions
5612   // Allocate a promise context for the closures below.
5613   Node* promise_context = effect =
5614       graph()->NewNode(javascript()->CreateFunctionContext(
5615                            handle(native_context()->scope_info(), isolate()),
5616                            PromiseBuiltinsAssembler::kPromiseContextLength -
5617                                Context::MIN_CONTEXT_SLOTS,
5618                            FUNCTION_SCOPE),
5619                        context, effect, control);
5620   effect =
5621       graph()->NewNode(simplified()->StoreField(AccessBuilder::ForContextSlot(
5622                            PromiseBuiltinsAssembler::kPromiseSlot)),
5623                        promise_context, promise, effect, control);
5624   effect = graph()->NewNode(
5625       simplified()->StoreField(AccessBuilder::ForContextSlot(
5626           PromiseBuiltinsAssembler::kAlreadyResolvedSlot)),
5627       promise_context, jsgraph()->FalseConstant(), effect, control);
5628   effect = graph()->NewNode(
5629       simplified()->StoreField(AccessBuilder::ForContextSlot(
5630           PromiseBuiltinsAssembler::kDebugEventSlot)),
5631       promise_context, jsgraph()->TrueConstant(), effect, control);
5632 
5633   // Allocate the closure for the resolve case.
5634   Handle<SharedFunctionInfo> resolve_shared(
5635       native_context()->promise_capability_default_resolve_shared_fun(),
5636       isolate());
5637   Node* resolve = effect =
5638       graph()->NewNode(javascript()->CreateClosure(
5639                            resolve_shared, factory()->many_closures_cell(),
5640                            handle(resolve_shared->GetCode(), isolate())),
5641                        promise_context, effect, control);
5642 
5643   // Allocate the closure for the reject case.
5644   Handle<SharedFunctionInfo> reject_shared(
5645       native_context()->promise_capability_default_reject_shared_fun(),
5646       isolate());
5647   Node* reject = effect =
5648       graph()->NewNode(javascript()->CreateClosure(
5649                            reject_shared, factory()->many_closures_cell(),
5650                            handle(reject_shared->GetCode(), isolate())),
5651                        promise_context, effect, control);
5652 
5653   const std::vector<Node*> checkpoint_parameters_continuation(
5654       {jsgraph()->UndefinedConstant() /* receiver */, promise, reject});
5655   int checkpoint_parameters_continuation_size =
5656       static_cast<int>(checkpoint_parameters_continuation.size());
5657   // This continuation just returns the created promise and takes care of
5658   // exceptions thrown by the executor.
5659   frame_state = CreateJavaScriptBuiltinContinuationFrameState(
5660       jsgraph(), promise_shared,
5661       Builtins::kPromiseConstructorLazyDeoptContinuation, target, context,
5662       checkpoint_parameters_continuation.data(),
5663       checkpoint_parameters_continuation_size, constructor_frame_state,
5664       ContinuationFrameStateMode::LAZY_WITH_CATCH);
5665 
5666   // 9. Call executor with both resolving functions
5667   effect = control = graph()->NewNode(
5668       javascript()->Call(4, p.frequency(), VectorSlotPair(),
5669                          ConvertReceiverMode::kNullOrUndefined,
5670                          SpeculationMode::kDisallowSpeculation),
5671       executor, jsgraph()->UndefinedConstant(), resolve, reject, context,
5672       frame_state, effect, control);
5673 
5674   Node* exception_effect = effect;
5675   Node* exception_control = control;
5676   {
5677     Node* reason = exception_effect = exception_control = graph()->NewNode(
5678         common()->IfException(), exception_control, exception_effect);
5679     // 10a. Call reject if the call to executor threw.
5680     exception_effect = exception_control = graph()->NewNode(
5681         javascript()->Call(3, p.frequency(), VectorSlotPair(),
5682                            ConvertReceiverMode::kNullOrUndefined,
5683                            SpeculationMode::kDisallowSpeculation),
5684         reject, jsgraph()->UndefinedConstant(), reason, context, frame_state,
5685         exception_effect, exception_control);
5686 
5687     // Rewire potential exception edges.
5688     Node* on_exception = nullptr;
5689     if (NodeProperties::IsExceptionalCall(node, &on_exception)) {
5690       RewirePostCallbackExceptionEdges(check_throw, on_exception,
5691                                        exception_effect, &check_fail,
5692                                        &exception_control);
5693     }
5694   }
5695 
5696   Node* success_effect = effect;
5697   Node* success_control = control;
5698   {
5699     success_control = graph()->NewNode(common()->IfSuccess(), success_control);
5700   }
5701 
5702   control =
5703       graph()->NewNode(common()->Merge(2), success_control, exception_control);
5704   effect = graph()->NewNode(common()->EffectPhi(2), success_effect,
5705                             exception_effect, control);
5706 
5707   // Wire up the branch for the case when IsCallable fails for the executor.
5708   // Since {check_throw} is an unconditional throw, it's impossible to
5709   // return a successful completion. Therefore, we simply connect the successful
5710   // completion to the graph end.
5711   Node* throw_node =
5712       graph()->NewNode(common()->Throw(), check_throw, check_fail);
5713   NodeProperties::MergeControlToEnd(graph(), common(), throw_node);
5714 
5715   ReplaceWithValue(node, promise, effect, control);
5716   return Replace(promise);
5717 }
5718 
5719 // V8 Extras: v8.createPromise(parent)
ReducePromiseInternalConstructor(Node * node)5720 Reduction JSCallReducer::ReducePromiseInternalConstructor(Node* node) {
5721   DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
5722   Node* context = NodeProperties::GetContextInput(node);
5723   Node* effect = NodeProperties::GetEffectInput(node);
5724 
5725   // Check that promises aren't being observed through (debug) hooks.
5726   if (!isolate()->IsPromiseHookProtectorIntact()) return NoChange();
5727 
5728   dependencies()->DependOnProtector(
5729       PropertyCellRef(js_heap_broker(), factory()->promise_hook_protector()));
5730 
5731   // Create a new pending promise.
5732   Node* value = effect =
5733       graph()->NewNode(javascript()->CreatePromise(), context, effect);
5734 
5735   ReplaceWithValue(node, value, effect);
5736   return Replace(value);
5737 }
5738 
5739 // V8 Extras: v8.rejectPromise(promise, reason)
ReducePromiseInternalReject(Node * node)5740 Reduction JSCallReducer::ReducePromiseInternalReject(Node* node) {
5741   DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
5742   Node* promise = node->op()->ValueInputCount() >= 2
5743                       ? NodeProperties::GetValueInput(node, 2)
5744                       : jsgraph()->UndefinedConstant();
5745   Node* reason = node->op()->ValueInputCount() >= 3
5746                      ? NodeProperties::GetValueInput(node, 3)
5747                      : jsgraph()->UndefinedConstant();
5748   Node* debug_event = jsgraph()->TrueConstant();
5749   Node* frame_state = NodeProperties::GetFrameStateInput(node);
5750   Node* context = NodeProperties::GetContextInput(node);
5751   Node* effect = NodeProperties::GetEffectInput(node);
5752   Node* control = NodeProperties::GetControlInput(node);
5753 
5754   // Reject the {promise} using the given {reason}, and trigger debug logic.
5755   Node* value = effect =
5756       graph()->NewNode(javascript()->RejectPromise(), promise, reason,
5757                        debug_event, context, frame_state, effect, control);
5758 
5759   ReplaceWithValue(node, value, effect, control);
5760   return Replace(value);
5761 }
5762 
5763 // V8 Extras: v8.resolvePromise(promise, resolution)
ReducePromiseInternalResolve(Node * node)5764 Reduction JSCallReducer::ReducePromiseInternalResolve(Node* node) {
5765   DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
5766   Node* promise = node->op()->ValueInputCount() >= 2
5767                       ? NodeProperties::GetValueInput(node, 2)
5768                       : jsgraph()->UndefinedConstant();
5769   Node* resolution = node->op()->ValueInputCount() >= 3
5770                          ? NodeProperties::GetValueInput(node, 3)
5771                          : jsgraph()->UndefinedConstant();
5772   Node* frame_state = NodeProperties::GetFrameStateInput(node);
5773   Node* context = NodeProperties::GetContextInput(node);
5774   Node* effect = NodeProperties::GetEffectInput(node);
5775   Node* control = NodeProperties::GetControlInput(node);
5776 
5777   // Resolve the {promise} using the given {resolution}.
5778   Node* value = effect =
5779       graph()->NewNode(javascript()->ResolvePromise(), promise, resolution,
5780                        context, frame_state, effect, control);
5781 
5782   ReplaceWithValue(node, value, effect, control);
5783   return Replace(value);
5784 }
5785 
5786 // ES section #sec-promise.prototype.catch
ReducePromisePrototypeCatch(Node * node)5787 Reduction JSCallReducer::ReducePromisePrototypeCatch(Node* node) {
5788   DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
5789   CallParameters const& p = CallParametersOf(node->op());
5790   if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
5791     return NoChange();
5792   }
5793   int arity = static_cast<int>(p.arity() - 2);
5794   Node* receiver = NodeProperties::GetValueInput(node, 1);
5795   Node* effect = NodeProperties::GetEffectInput(node);
5796   Node* control = NodeProperties::GetControlInput(node);
5797 
5798   // Check that the Promise.then protector is intact. This protector guards
5799   // that all JSPromise instances whose [[Prototype]] is the initial
5800   // %PromisePrototype% yield the initial %PromisePrototype%.then method
5801   // when looking up "then".
5802   if (!isolate()->IsPromiseThenLookupChainIntact()) return NoChange();
5803 
5804   // Check if we know something about {receiver} already.
5805   ZoneHandleSet<Map> receiver_maps;
5806   NodeProperties::InferReceiverMapsResult result =
5807       NodeProperties::InferReceiverMaps(isolate(), receiver, effect,
5808                                         &receiver_maps);
5809   if (result == NodeProperties::kNoReceiverMaps) return NoChange();
5810   DCHECK_NE(0, receiver_maps.size());
5811 
5812   // Check whether all {receiver_maps} are JSPromise maps and
5813   // have the initial Promise.prototype as their [[Prototype]].
5814   for (Handle<Map> receiver_map : receiver_maps) {
5815     if (!receiver_map->IsJSPromiseMap()) return NoChange();
5816     if (receiver_map->prototype() != native_context()->promise_prototype()) {
5817       return NoChange();
5818     }
5819   }
5820 
5821   dependencies()->DependOnProtector(
5822       PropertyCellRef(js_heap_broker(), factory()->promise_then_protector()));
5823 
5824   // If the {receiver_maps} aren't reliable, we need to repeat the
5825   // map check here, guarded by the CALL_IC.
5826   if (result == NodeProperties::kUnreliableReceiverMaps) {
5827     effect =
5828         graph()->NewNode(simplified()->CheckMaps(CheckMapsFlag::kNone,
5829                                                  receiver_maps, p.feedback()),
5830                          receiver, effect, control);
5831   }
5832 
5833   // Massage the {node} to call "then" instead by first removing all inputs
5834   // following the onRejected parameter, and then filling up the parameters
5835   // to two inputs from the left with undefined.
5836   Node* target =
5837       jsgraph()->Constant(handle(native_context()->promise_then(), isolate()));
5838   NodeProperties::ReplaceValueInput(node, target, 0);
5839   NodeProperties::ReplaceEffectInput(node, effect);
5840   for (; arity > 1; --arity) node->RemoveInput(3);
5841   for (; arity < 2; ++arity) {
5842     node->InsertInput(graph()->zone(), 2, jsgraph()->UndefinedConstant());
5843   }
5844   NodeProperties::ChangeOp(
5845       node, javascript()->Call(2 + arity, p.frequency(), p.feedback(),
5846                                ConvertReceiverMode::kNotNullOrUndefined,
5847                                p.speculation_mode()));
5848   Reduction const reduction = ReducePromisePrototypeThen(node);
5849   return reduction.Changed() ? reduction : Changed(node);
5850 }
5851 
5852 // ES section #sec-promise.prototype.finally
ReducePromisePrototypeFinally(Node * node)5853 Reduction JSCallReducer::ReducePromisePrototypeFinally(Node* node) {
5854   DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
5855   CallParameters const& p = CallParametersOf(node->op());
5856   int arity = static_cast<int>(p.arity() - 2);
5857   Node* receiver = NodeProperties::GetValueInput(node, 1);
5858   Node* on_finally = arity >= 1 ? NodeProperties::GetValueInput(node, 2)
5859                                 : jsgraph()->UndefinedConstant();
5860   Node* effect = NodeProperties::GetEffectInput(node);
5861   Node* control = NodeProperties::GetControlInput(node);
5862   if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
5863     return NoChange();
5864   }
5865 
5866   // Check that promises aren't being observed through (debug) hooks.
5867   if (!isolate()->IsPromiseHookProtectorIntact()) return NoChange();
5868 
5869   // Check that the Promise#then protector is intact. This protector guards
5870   // that all JSPromise instances whose [[Prototype]] is the initial
5871   // %PromisePrototype% yield the initial %PromisePrototype%.then method
5872   // when looking up "then".
5873   if (!isolate()->IsPromiseThenLookupChainIntact()) return NoChange();
5874 
5875   // Also check that the @@species protector is intact, which guards the
5876   // lookup of "constructor" on JSPromise instances, whoch [[Prototype]] is
5877   // the initial %PromisePrototype%, and the Symbol.species lookup on the
5878   // %PromisePrototype%.
5879   if (!isolate()->IsPromiseSpeciesLookupChainIntact()) return NoChange();
5880 
5881   // Check if we know something about {receiver} already.
5882   ZoneHandleSet<Map> receiver_maps;
5883   NodeProperties::InferReceiverMapsResult result =
5884       NodeProperties::InferReceiverMaps(isolate(), receiver, effect,
5885                                         &receiver_maps);
5886   if (result == NodeProperties::kNoReceiverMaps) return NoChange();
5887   DCHECK_NE(0, receiver_maps.size());
5888 
5889   // Check whether all {receiver_maps} are JSPromise maps and
5890   // have the initial Promise.prototype as their [[Prototype]].
5891   for (Handle<Map> receiver_map : receiver_maps) {
5892     if (!receiver_map->IsJSPromiseMap()) return NoChange();
5893     if (receiver_map->prototype() != native_context()->promise_prototype()) {
5894       return NoChange();
5895     }
5896   }
5897 
5898   dependencies()->DependOnProtector(
5899       PropertyCellRef(js_heap_broker(), factory()->promise_hook_protector()));
5900   dependencies()->DependOnProtector(
5901       PropertyCellRef(js_heap_broker(), factory()->promise_then_protector()));
5902   dependencies()->DependOnProtector(PropertyCellRef(
5903       js_heap_broker(), factory()->promise_species_protector()));
5904 
5905   // If the {receiver_maps} aren't reliable, we need to repeat the
5906   // map check here, guarded by the CALL_IC.
5907   if (result == NodeProperties::kUnreliableReceiverMaps) {
5908     effect =
5909         graph()->NewNode(simplified()->CheckMaps(CheckMapsFlag::kNone,
5910                                                  receiver_maps, p.feedback()),
5911                          receiver, effect, control);
5912   }
5913 
5914   // Check if {on_finally} is callable, and if so wrap it into appropriate
5915   // closures that perform the finalization.
5916   Node* check = graph()->NewNode(simplified()->ObjectIsCallable(), on_finally);
5917   Node* branch =
5918       graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
5919 
5920   Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
5921   Node* etrue = effect;
5922   Node* catch_true;
5923   Node* then_true;
5924   {
5925     Node* context = jsgraph()->HeapConstant(native_context());
5926     Node* constructor = jsgraph()->HeapConstant(
5927         handle(native_context()->promise_function(), isolate()));
5928 
5929     // Allocate shared context for the closures below.
5930     context = etrue = graph()->NewNode(
5931         javascript()->CreateFunctionContext(
5932             handle(native_context()->scope_info(), isolate()),
5933             PromiseBuiltinsAssembler::kPromiseFinallyContextLength -
5934                 Context::MIN_CONTEXT_SLOTS,
5935             FUNCTION_SCOPE),
5936         context, etrue, if_true);
5937     etrue =
5938         graph()->NewNode(simplified()->StoreField(AccessBuilder::ForContextSlot(
5939                              PromiseBuiltinsAssembler::kOnFinallySlot)),
5940                          context, on_finally, etrue, if_true);
5941     etrue =
5942         graph()->NewNode(simplified()->StoreField(AccessBuilder::ForContextSlot(
5943                              PromiseBuiltinsAssembler::kConstructorSlot)),
5944                          context, constructor, etrue, if_true);
5945 
5946     // Allocate the closure for the reject case.
5947     Handle<SharedFunctionInfo> catch_finally(
5948         native_context()->promise_catch_finally_shared_fun(), isolate());
5949     catch_true = etrue =
5950         graph()->NewNode(javascript()->CreateClosure(
5951                              catch_finally, factory()->many_closures_cell(),
5952                              handle(catch_finally->GetCode(), isolate())),
5953                          context, etrue, if_true);
5954 
5955     // Allocate the closure for the fulfill case.
5956     Handle<SharedFunctionInfo> then_finally(
5957         native_context()->promise_then_finally_shared_fun(), isolate());
5958     then_true = etrue =
5959         graph()->NewNode(javascript()->CreateClosure(
5960                              then_finally, factory()->many_closures_cell(),
5961                              handle(then_finally->GetCode(), isolate())),
5962                          context, etrue, if_true);
5963   }
5964 
5965   Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
5966   Node* efalse = effect;
5967   Node* catch_false = on_finally;
5968   Node* then_false = on_finally;
5969 
5970   control = graph()->NewNode(common()->Merge(2), if_true, if_false);
5971   effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);
5972   Node* catch_finally =
5973       graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
5974                        catch_true, catch_false, control);
5975   Node* then_finally =
5976       graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
5977                        then_true, then_false, control);
5978 
5979   // At this point we definitely know that {receiver} has one of the
5980   // {receiver_maps}, so insert a MapGuard as a hint for the lowering
5981   // of the call to "then" below.
5982   effect = graph()->NewNode(simplified()->MapGuard(receiver_maps), receiver,
5983                             effect, control);
5984 
5985   // Massage the {node} to call "then" instead by first removing all inputs
5986   // following the onFinally parameter, and then replacing the only parameter
5987   // input with the {on_finally} value.
5988   Node* target =
5989       jsgraph()->Constant(handle(native_context()->promise_then(), isolate()));
5990   NodeProperties::ReplaceValueInput(node, target, 0);
5991   NodeProperties::ReplaceEffectInput(node, effect);
5992   NodeProperties::ReplaceControlInput(node, control);
5993   for (; arity > 2; --arity) node->RemoveInput(2);
5994   for (; arity < 2; ++arity)
5995     node->InsertInput(graph()->zone(), 2, then_finally);
5996   node->ReplaceInput(2, then_finally);
5997   node->ReplaceInput(3, catch_finally);
5998   NodeProperties::ChangeOp(
5999       node, javascript()->Call(2 + arity, p.frequency(), p.feedback(),
6000                                ConvertReceiverMode::kNotNullOrUndefined,
6001                                p.speculation_mode()));
6002   Reduction const reduction = ReducePromisePrototypeThen(node);
6003   return reduction.Changed() ? reduction : Changed(node);
6004 }
6005 
ReducePromisePrototypeThen(Node * node)6006 Reduction JSCallReducer::ReducePromisePrototypeThen(Node* node) {
6007   DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
6008   CallParameters const& p = CallParametersOf(node->op());
6009   if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
6010     return NoChange();
6011   }
6012 
6013   Node* receiver = NodeProperties::GetValueInput(node, 1);
6014   Node* on_fulfilled = node->op()->ValueInputCount() > 2
6015                            ? NodeProperties::GetValueInput(node, 2)
6016                            : jsgraph()->UndefinedConstant();
6017   Node* on_rejected = node->op()->ValueInputCount() > 3
6018                           ? NodeProperties::GetValueInput(node, 3)
6019                           : jsgraph()->UndefinedConstant();
6020   Node* context = NodeProperties::GetContextInput(node);
6021   Node* effect = NodeProperties::GetEffectInput(node);
6022   Node* control = NodeProperties::GetControlInput(node);
6023   Node* frame_state = NodeProperties::GetFrameStateInput(node);
6024 
6025   // Check that promises aren't being observed through (debug) hooks.
6026   if (!isolate()->IsPromiseHookProtectorIntact()) return NoChange();
6027 
6028   // Check if the @@species protector is intact. The @@species protector
6029   // guards the "constructor" lookup on all JSPromise instances and the
6030   // initial Promise.prototype, as well as the  Symbol.species lookup on
6031   // the Promise constructor.
6032   if (!isolate()->IsPromiseSpeciesLookupChainIntact()) return NoChange();
6033 
6034   // Check if we know something about {receiver} already.
6035   ZoneHandleSet<Map> receiver_maps;
6036   NodeProperties::InferReceiverMapsResult infer_receiver_maps_result =
6037       NodeProperties::InferReceiverMaps(isolate(), receiver, effect,
6038                                         &receiver_maps);
6039   if (infer_receiver_maps_result == NodeProperties::kNoReceiverMaps) {
6040     return NoChange();
6041   }
6042   DCHECK_NE(0, receiver_maps.size());
6043 
6044   // Check whether all {receiver_maps} are JSPromise maps and
6045   // have the initial Promise.prototype as their [[Prototype]].
6046   for (Handle<Map> receiver_map : receiver_maps) {
6047     if (!receiver_map->IsJSPromiseMap()) return NoChange();
6048     if (receiver_map->prototype() != native_context()->promise_prototype()) {
6049       return NoChange();
6050     }
6051   }
6052 
6053   dependencies()->DependOnProtector(
6054       PropertyCellRef(js_heap_broker(), factory()->promise_hook_protector()));
6055   dependencies()->DependOnProtector(PropertyCellRef(
6056       js_heap_broker(), factory()->promise_species_protector()));
6057 
6058   // If the {receiver_maps} aren't reliable, we need to repeat the
6059   // map check here, guarded by the CALL_IC.
6060   if (infer_receiver_maps_result == NodeProperties::kUnreliableReceiverMaps) {
6061     effect =
6062         graph()->NewNode(simplified()->CheckMaps(CheckMapsFlag::kNone,
6063                                                  receiver_maps, p.feedback()),
6064                          receiver, effect, control);
6065   }
6066 
6067   // Check that {on_fulfilled} is callable.
6068   on_fulfilled = graph()->NewNode(
6069       common()->Select(MachineRepresentation::kTagged, BranchHint::kTrue),
6070       graph()->NewNode(simplified()->ObjectIsCallable(), on_fulfilled),
6071       on_fulfilled, jsgraph()->UndefinedConstant());
6072 
6073   // Check that {on_rejected} is callable.
6074   on_rejected = graph()->NewNode(
6075       common()->Select(MachineRepresentation::kTagged, BranchHint::kTrue),
6076       graph()->NewNode(simplified()->ObjectIsCallable(), on_rejected),
6077       on_rejected, jsgraph()->UndefinedConstant());
6078 
6079   // Create the resulting JSPromise.
6080   Node* result = effect =
6081       graph()->NewNode(javascript()->CreatePromise(), context, effect);
6082 
6083   // Chain {result} onto {receiver}.
6084   result = effect = graph()->NewNode(
6085       javascript()->PerformPromiseThen(), receiver, on_fulfilled, on_rejected,
6086       result, context, frame_state, effect, control);
6087   ReplaceWithValue(node, result, effect, control);
6088   return Replace(result);
6089 }
6090 
6091 // ES section #sec-promise.resolve
ReducePromiseResolveTrampoline(Node * node)6092 Reduction JSCallReducer::ReducePromiseResolveTrampoline(Node* node) {
6093   DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
6094   Node* receiver = NodeProperties::GetValueInput(node, 1);
6095   Node* value = node->op()->ValueInputCount() > 2
6096                     ? NodeProperties::GetValueInput(node, 2)
6097                     : jsgraph()->UndefinedConstant();
6098   Node* context = NodeProperties::GetContextInput(node);
6099   Node* frame_state = NodeProperties::GetFrameStateInput(node);
6100   Node* effect = NodeProperties::GetEffectInput(node);
6101   Node* control = NodeProperties::GetControlInput(node);
6102 
6103   // Check if we know something about {receiver} already.
6104   ZoneHandleSet<Map> receiver_maps;
6105   NodeProperties::InferReceiverMapsResult infer_receiver_maps_result =
6106       NodeProperties::InferReceiverMaps(isolate(), receiver, effect,
6107                                         &receiver_maps);
6108   if (infer_receiver_maps_result == NodeProperties::kNoReceiverMaps) {
6109     return NoChange();
6110   }
6111   DCHECK_NE(0, receiver_maps.size());
6112 
6113   // Only reduce when all {receiver_maps} are JSReceiver maps.
6114   for (Handle<Map> receiver_map : receiver_maps) {
6115     if (!receiver_map->IsJSReceiverMap()) return NoChange();
6116   }
6117 
6118   // Morph the {node} into a JSPromiseResolve operation.
6119   node->ReplaceInput(0, receiver);
6120   node->ReplaceInput(1, value);
6121   node->ReplaceInput(2, context);
6122   node->ReplaceInput(3, frame_state);
6123   node->ReplaceInput(4, effect);
6124   node->ReplaceInput(5, control);
6125   node->TrimInputCount(6);
6126   NodeProperties::ChangeOp(node, javascript()->PromiseResolve());
6127   return Changed(node);
6128 }
6129 
6130 // ES #sec-typedarray-constructors
ReduceTypedArrayConstructor(Node * node,Handle<SharedFunctionInfo> shared)6131 Reduction JSCallReducer::ReduceTypedArrayConstructor(
6132     Node* node, Handle<SharedFunctionInfo> shared) {
6133   DCHECK_EQ(IrOpcode::kJSConstruct, node->opcode());
6134   ConstructParameters const& p = ConstructParametersOf(node->op());
6135   int arity = static_cast<int>(p.arity() - 2);
6136   Node* target = NodeProperties::GetValueInput(node, 0);
6137   Node* arg1 = (arity >= 1) ? NodeProperties::GetValueInput(node, 1)
6138                             : jsgraph()->UndefinedConstant();
6139   Node* arg2 = (arity >= 2) ? NodeProperties::GetValueInput(node, 2)
6140                             : jsgraph()->UndefinedConstant();
6141   Node* arg3 = (arity >= 3) ? NodeProperties::GetValueInput(node, 3)
6142                             : jsgraph()->UndefinedConstant();
6143   Node* new_target = NodeProperties::GetValueInput(node, arity + 1);
6144   Node* context = NodeProperties::GetContextInput(node);
6145   Node* frame_state = NodeProperties::GetFrameStateInput(node);
6146   Node* effect = NodeProperties::GetEffectInput(node);
6147   Node* control = NodeProperties::GetControlInput(node);
6148 
6149   // Insert a construct stub frame into the chain of frame states. This will
6150   // reconstruct the proper frame when deoptimizing within the constructor.
6151   frame_state = CreateArtificialFrameState(
6152       node, frame_state, arity, BailoutId::ConstructStubInvoke(),
6153       FrameStateType::kConstructStub, shared);
6154 
6155   // This continuation just returns the newly created JSTypedArray. We
6156   // pass the_hole as the receiver, just like the builtin construct stub
6157   // does in this case.
6158   Node* const parameters[] = {jsgraph()->TheHoleConstant()};
6159   int const num_parameters = static_cast<int>(arraysize(parameters));
6160   frame_state = CreateJavaScriptBuiltinContinuationFrameState(
6161       jsgraph(), shared, Builtins::kGenericConstructorLazyDeoptContinuation,
6162       target, context, parameters, num_parameters, frame_state,
6163       ContinuationFrameStateMode::LAZY);
6164 
6165   Node* result =
6166       graph()->NewNode(javascript()->CreateTypedArray(), target, new_target,
6167                        arg1, arg2, arg3, context, frame_state, effect, control);
6168   return Replace(result);
6169 }
6170 
6171 // ES #sec-get-%typedarray%.prototype-@@tostringtag
ReduceTypedArrayPrototypeToStringTag(Node * node)6172 Reduction JSCallReducer::ReduceTypedArrayPrototypeToStringTag(Node* node) {
6173   Node* receiver = NodeProperties::GetValueInput(node, 1);
6174   Node* effect = NodeProperties::GetEffectInput(node);
6175   Node* control = NodeProperties::GetControlInput(node);
6176 
6177   NodeVector values(graph()->zone());
6178   NodeVector effects(graph()->zone());
6179   NodeVector controls(graph()->zone());
6180 
6181   Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), receiver);
6182   control =
6183       graph()->NewNode(common()->Branch(BranchHint::kFalse), check, control);
6184 
6185   values.push_back(jsgraph()->UndefinedConstant());
6186   effects.push_back(effect);
6187   controls.push_back(graph()->NewNode(common()->IfTrue(), control));
6188 
6189   control = graph()->NewNode(common()->IfFalse(), control);
6190   Node* receiver_map = effect =
6191       graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
6192                        receiver, effect, control);
6193   Node* receiver_bit_field2 = effect = graph()->NewNode(
6194       simplified()->LoadField(AccessBuilder::ForMapBitField2()), receiver_map,
6195       effect, control);
6196   Node* receiver_elements_kind = graph()->NewNode(
6197       simplified()->NumberShiftRightLogical(),
6198       graph()->NewNode(simplified()->NumberBitwiseAnd(), receiver_bit_field2,
6199                        jsgraph()->Constant(Map::ElementsKindBits::kMask)),
6200       jsgraph()->Constant(Map::ElementsKindBits::kShift));
6201 
6202   // Offset the elements kind by FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND,
6203   // so that the branch cascade below is turned into a simple table
6204   // switch by the ControlFlowOptimizer later.
6205   receiver_elements_kind = graph()->NewNode(
6206       simplified()->NumberSubtract(), receiver_elements_kind,
6207       jsgraph()->Constant(FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND));
6208 
6209 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype)                      \
6210   do {                                                                 \
6211     Node* check = graph()->NewNode(                                    \
6212         simplified()->NumberEqual(), receiver_elements_kind,           \
6213         jsgraph()->Constant(TYPE##_ELEMENTS -                          \
6214                             FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND));   \
6215     control = graph()->NewNode(common()->Branch(), check, control);    \
6216     values.push_back(jsgraph()->HeapConstant(                          \
6217         factory()->InternalizeUtf8String(#Type "Array")));             \
6218     effects.push_back(effect);                                         \
6219     controls.push_back(graph()->NewNode(common()->IfTrue(), control)); \
6220     control = graph()->NewNode(common()->IfFalse(), control);          \
6221   } while (false);
6222   TYPED_ARRAYS(TYPED_ARRAY_CASE)
6223 #undef TYPED_ARRAY_CASE
6224 
6225   values.push_back(jsgraph()->UndefinedConstant());
6226   effects.push_back(effect);
6227   controls.push_back(control);
6228 
6229   int const count = static_cast<int>(controls.size());
6230   control = graph()->NewNode(common()->Merge(count), count, &controls.front());
6231   effects.push_back(control);
6232   effect =
6233       graph()->NewNode(common()->EffectPhi(count), count + 1, &effects.front());
6234   values.push_back(control);
6235   Node* value =
6236       graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, count),
6237                        count + 1, &values.front());
6238   ReplaceWithValue(node, value, effect, control);
6239   return Replace(value);
6240 }
6241 
6242 // ES #sec-number.isfinite
ReduceNumberIsFinite(Node * node)6243 Reduction JSCallReducer::ReduceNumberIsFinite(Node* node) {
6244   if (node->op()->ValueInputCount() < 3) {
6245     Node* value = jsgraph()->FalseConstant();
6246     ReplaceWithValue(node, value);
6247     return Replace(value);
6248   }
6249   Node* input = NodeProperties::GetValueInput(node, 2);
6250   Node* value = graph()->NewNode(simplified()->ObjectIsFiniteNumber(), input);
6251   ReplaceWithValue(node, value);
6252   return Replace(value);
6253 }
6254 
6255 // ES #sec-number.isfinite
ReduceNumberIsInteger(Node * node)6256 Reduction JSCallReducer::ReduceNumberIsInteger(Node* node) {
6257   if (node->op()->ValueInputCount() < 3) {
6258     Node* value = jsgraph()->FalseConstant();
6259     ReplaceWithValue(node, value);
6260     return Replace(value);
6261   }
6262   Node* input = NodeProperties::GetValueInput(node, 2);
6263   Node* value = graph()->NewNode(simplified()->ObjectIsInteger(), input);
6264   ReplaceWithValue(node, value);
6265   return Replace(value);
6266 }
6267 
6268 // ES #sec-number.issafeinteger
ReduceNumberIsSafeInteger(Node * node)6269 Reduction JSCallReducer::ReduceNumberIsSafeInteger(Node* node) {
6270   if (node->op()->ValueInputCount() < 3) {
6271     Node* value = jsgraph()->FalseConstant();
6272     ReplaceWithValue(node, value);
6273     return Replace(value);
6274   }
6275   Node* input = NodeProperties::GetValueInput(node, 2);
6276   Node* value = graph()->NewNode(simplified()->ObjectIsSafeInteger(), input);
6277   ReplaceWithValue(node, value);
6278   return Replace(value);
6279 }
6280 
6281 // ES #sec-number.isnan
ReduceNumberIsNaN(Node * node)6282 Reduction JSCallReducer::ReduceNumberIsNaN(Node* node) {
6283   if (node->op()->ValueInputCount() < 3) {
6284     Node* value = jsgraph()->FalseConstant();
6285     ReplaceWithValue(node, value);
6286     return Replace(value);
6287   }
6288   Node* input = NodeProperties::GetValueInput(node, 2);
6289   Node* value = graph()->NewNode(simplified()->ObjectIsNaN(), input);
6290   ReplaceWithValue(node, value);
6291   return Replace(value);
6292 }
6293 
ReduceMapPrototypeGet(Node * node)6294 Reduction JSCallReducer::ReduceMapPrototypeGet(Node* node) {
6295   // We only optimize if we have target, receiver and key parameters.
6296   if (node->op()->ValueInputCount() != 3) return NoChange();
6297   Node* receiver = NodeProperties::GetValueInput(node, 1);
6298   Node* effect = NodeProperties::GetEffectInput(node);
6299   Node* control = NodeProperties::GetControlInput(node);
6300   Node* key = NodeProperties::GetValueInput(node, 2);
6301 
6302   if (!NodeProperties::HasInstanceTypeWitness(isolate(), receiver, effect,
6303                                               JS_MAP_TYPE))
6304     return NoChange();
6305 
6306   Node* table = effect = graph()->NewNode(
6307       simplified()->LoadField(AccessBuilder::ForJSCollectionTable()), receiver,
6308       effect, control);
6309 
6310   Node* entry = effect = graph()->NewNode(
6311       simplified()->FindOrderedHashMapEntry(), table, key, effect, control);
6312 
6313   Node* check = graph()->NewNode(simplified()->NumberEqual(), entry,
6314                                  jsgraph()->MinusOneConstant());
6315 
6316   Node* branch = graph()->NewNode(common()->Branch(), check, control);
6317 
6318   // Key not found.
6319   Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
6320   Node* etrue = effect;
6321   Node* vtrue = jsgraph()->UndefinedConstant();
6322 
6323   // Key found.
6324   Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
6325   Node* efalse = effect;
6326   Node* vfalse = efalse = graph()->NewNode(
6327       simplified()->LoadElement(AccessBuilder::ForOrderedHashMapEntryValue()),
6328       table, entry, efalse, if_false);
6329 
6330   control = graph()->NewNode(common()->Merge(2), if_true, if_false);
6331   Node* value = graph()->NewNode(
6332       common()->Phi(MachineRepresentation::kTagged, 2), vtrue, vfalse, control);
6333   effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);
6334 
6335   ReplaceWithValue(node, value, effect, control);
6336   return Replace(value);
6337 }
6338 
ReduceMapPrototypeHas(Node * node)6339 Reduction JSCallReducer::ReduceMapPrototypeHas(Node* node) {
6340   // We only optimize if we have target, receiver and key parameters.
6341   if (node->op()->ValueInputCount() != 3) return NoChange();
6342   Node* receiver = NodeProperties::GetValueInput(node, 1);
6343   Node* effect = NodeProperties::GetEffectInput(node);
6344   Node* control = NodeProperties::GetControlInput(node);
6345   Node* key = NodeProperties::GetValueInput(node, 2);
6346 
6347   if (!NodeProperties::HasInstanceTypeWitness(isolate(), receiver, effect,
6348                                               JS_MAP_TYPE))
6349     return NoChange();
6350 
6351   Node* table = effect = graph()->NewNode(
6352       simplified()->LoadField(AccessBuilder::ForJSCollectionTable()), receiver,
6353       effect, control);
6354 
6355   Node* index = effect = graph()->NewNode(
6356       simplified()->FindOrderedHashMapEntry(), table, key, effect, control);
6357 
6358   Node* value = graph()->NewNode(simplified()->NumberEqual(), index,
6359                                  jsgraph()->MinusOneConstant());
6360   value = graph()->NewNode(simplified()->BooleanNot(), value);
6361 
6362   ReplaceWithValue(node, value, effect, control);
6363   return Replace(value);
6364 }
6365 
6366 namespace {
6367 
InstanceTypeForCollectionKind(CollectionKind kind)6368 InstanceType InstanceTypeForCollectionKind(CollectionKind kind) {
6369   switch (kind) {
6370     case CollectionKind::kMap:
6371       return JS_MAP_TYPE;
6372     case CollectionKind::kSet:
6373       return JS_SET_TYPE;
6374   }
6375   UNREACHABLE();
6376 }
6377 
6378 }  // namespace
6379 
ReduceCollectionIteration(Node * node,CollectionKind collection_kind,IterationKind iteration_kind)6380 Reduction JSCallReducer::ReduceCollectionIteration(
6381     Node* node, CollectionKind collection_kind, IterationKind iteration_kind) {
6382   DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
6383   Node* receiver = NodeProperties::GetValueInput(node, 1);
6384   Node* context = NodeProperties::GetContextInput(node);
6385   Node* effect = NodeProperties::GetEffectInput(node);
6386   Node* control = NodeProperties::GetControlInput(node);
6387   if (NodeProperties::HasInstanceTypeWitness(
6388           isolate(), receiver, effect,
6389           InstanceTypeForCollectionKind(collection_kind))) {
6390     Node* js_create_iterator = effect = graph()->NewNode(
6391         javascript()->CreateCollectionIterator(collection_kind, iteration_kind),
6392         receiver, context, effect, control);
6393     ReplaceWithValue(node, js_create_iterator, effect);
6394     return Replace(js_create_iterator);
6395   }
6396   return NoChange();
6397 }
6398 
ReduceCollectionPrototypeSize(Node * node,CollectionKind collection_kind)6399 Reduction JSCallReducer::ReduceCollectionPrototypeSize(
6400     Node* node, CollectionKind collection_kind) {
6401   DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
6402   Node* receiver = NodeProperties::GetValueInput(node, 1);
6403   Node* effect = NodeProperties::GetEffectInput(node);
6404   Node* control = NodeProperties::GetControlInput(node);
6405   if (NodeProperties::HasInstanceTypeWitness(
6406           isolate(), receiver, effect,
6407           InstanceTypeForCollectionKind(collection_kind))) {
6408     Node* table = effect = graph()->NewNode(
6409         simplified()->LoadField(AccessBuilder::ForJSCollectionTable()),
6410         receiver, effect, control);
6411     Node* value = effect = graph()->NewNode(
6412         simplified()->LoadField(
6413             AccessBuilder::ForOrderedHashTableBaseNumberOfElements()),
6414         table, effect, control);
6415     ReplaceWithValue(node, value, effect, control);
6416     return Replace(value);
6417   }
6418   return NoChange();
6419 }
6420 
ReduceCollectionIteratorPrototypeNext(Node * node,int entry_size,Handle<HeapObject> empty_collection,InstanceType collection_iterator_instance_type_first,InstanceType collection_iterator_instance_type_last)6421 Reduction JSCallReducer::ReduceCollectionIteratorPrototypeNext(
6422     Node* node, int entry_size, Handle<HeapObject> empty_collection,
6423     InstanceType collection_iterator_instance_type_first,
6424     InstanceType collection_iterator_instance_type_last) {
6425   DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
6426   Node* receiver = NodeProperties::GetValueInput(node, 1);
6427   Node* context = NodeProperties::GetContextInput(node);
6428   Node* effect = NodeProperties::GetEffectInput(node);
6429   Node* control = NodeProperties::GetControlInput(node);
6430 
6431   // A word of warning to begin with: This whole method might look a bit
6432   // strange at times, but that's mostly because it was carefully handcrafted
6433   // to allow for full escape analysis and scalar replacement of both the
6434   // collection iterator object and the iterator results, including the
6435   // key-value arrays in case of Set/Map entry iteration.
6436   //
6437   // TODO(turbofan): Currently the escape analysis (and the store-load
6438   // forwarding) is unable to eliminate the allocations for the key-value
6439   // arrays in case of Set/Map entry iteration, and we should investigate
6440   // how to update the escape analysis / arrange the graph in a way that
6441   // this becomes possible.
6442 
6443   // Infer the {receiver} instance type.
6444   InstanceType receiver_instance_type;
6445   ZoneHandleSet<Map> receiver_maps;
6446   NodeProperties::InferReceiverMapsResult result =
6447       NodeProperties::InferReceiverMaps(isolate(), receiver, effect,
6448                                         &receiver_maps);
6449   if (result == NodeProperties::kNoReceiverMaps) return NoChange();
6450   DCHECK_NE(0, receiver_maps.size());
6451   receiver_instance_type = receiver_maps[0]->instance_type();
6452   for (size_t i = 1; i < receiver_maps.size(); ++i) {
6453     if (receiver_maps[i]->instance_type() != receiver_instance_type) {
6454       return NoChange();
6455     }
6456   }
6457   if (receiver_instance_type < collection_iterator_instance_type_first ||
6458       receiver_instance_type > collection_iterator_instance_type_last) {
6459     return NoChange();
6460   }
6461 
6462   // Transition the JSCollectionIterator {receiver} if necessary
6463   // (i.e. there were certain mutations while we're iterating).
6464   {
6465     Node* done_loop;
6466     Node* done_eloop;
6467     Node* loop = control =
6468         graph()->NewNode(common()->Loop(2), control, control);
6469     Node* eloop = effect =
6470         graph()->NewNode(common()->EffectPhi(2), effect, effect, loop);
6471     Node* terminate = graph()->NewNode(common()->Terminate(), eloop, loop);
6472     NodeProperties::MergeControlToEnd(graph(), common(), terminate);
6473 
6474     // Check if reached the final table of the {receiver}.
6475     Node* table = effect = graph()->NewNode(
6476         simplified()->LoadField(AccessBuilder::ForJSCollectionIteratorTable()),
6477         receiver, effect, control);
6478     Node* next_table = effect =
6479         graph()->NewNode(simplified()->LoadField(
6480                              AccessBuilder::ForOrderedHashTableBaseNextTable()),
6481                          table, effect, control);
6482     Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), next_table);
6483     control =
6484         graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
6485 
6486     // Abort the {loop} when we reach the final table.
6487     done_loop = graph()->NewNode(common()->IfTrue(), control);
6488     done_eloop = effect;
6489 
6490     // Migrate to the {next_table} otherwise.
6491     control = graph()->NewNode(common()->IfFalse(), control);
6492 
6493     // Self-heal the {receiver}s index.
6494     Node* index = effect = graph()->NewNode(
6495         simplified()->LoadField(AccessBuilder::ForJSCollectionIteratorIndex()),
6496         receiver, effect, control);
6497     Callable const callable =
6498         Builtins::CallableFor(isolate(), Builtins::kOrderedHashTableHealIndex);
6499     auto call_descriptor = Linkage::GetStubCallDescriptor(
6500         graph()->zone(), callable.descriptor(), 0, CallDescriptor::kNoFlags,
6501         Operator::kEliminatable);
6502     index = effect =
6503         graph()->NewNode(common()->Call(call_descriptor),
6504                          jsgraph()->HeapConstant(callable.code()), table, index,
6505                          jsgraph()->NoContextConstant(), effect);
6506 
6507     index = effect = graph()->NewNode(
6508         common()->TypeGuard(TypeCache::Get().kFixedArrayLengthType), index,
6509         effect, control);
6510 
6511     // Update the {index} and {table} on the {receiver}.
6512     effect = graph()->NewNode(
6513         simplified()->StoreField(AccessBuilder::ForJSCollectionIteratorIndex()),
6514         receiver, index, effect, control);
6515     effect = graph()->NewNode(
6516         simplified()->StoreField(AccessBuilder::ForJSCollectionIteratorTable()),
6517         receiver, next_table, effect, control);
6518 
6519     // Tie the knot.
6520     loop->ReplaceInput(1, control);
6521     eloop->ReplaceInput(1, effect);
6522 
6523     control = done_loop;
6524     effect = done_eloop;
6525   }
6526 
6527   // Get current index and table from the JSCollectionIterator {receiver}.
6528   Node* index = effect = graph()->NewNode(
6529       simplified()->LoadField(AccessBuilder::ForJSCollectionIteratorIndex()),
6530       receiver, effect, control);
6531   Node* table = effect = graph()->NewNode(
6532       simplified()->LoadField(AccessBuilder::ForJSCollectionIteratorTable()),
6533       receiver, effect, control);
6534 
6535   // Create the {JSIteratorResult} first to ensure that we always have
6536   // a dominating Allocate node for the allocation folding phase.
6537   Node* iterator_result = effect = graph()->NewNode(
6538       javascript()->CreateIterResultObject(), jsgraph()->UndefinedConstant(),
6539       jsgraph()->TrueConstant(), context, effect);
6540 
6541   // Look for the next non-holey key, starting from {index} in the {table}.
6542   Node* controls[2];
6543   Node* effects[3];
6544   {
6545     // Compute the currently used capacity.
6546     Node* number_of_buckets = effect = graph()->NewNode(
6547         simplified()->LoadField(
6548             AccessBuilder::ForOrderedHashTableBaseNumberOfBuckets()),
6549         table, effect, control);
6550     Node* number_of_elements = effect = graph()->NewNode(
6551         simplified()->LoadField(
6552             AccessBuilder::ForOrderedHashTableBaseNumberOfElements()),
6553         table, effect, control);
6554     Node* number_of_deleted_elements = effect = graph()->NewNode(
6555         simplified()->LoadField(
6556             AccessBuilder::ForOrderedHashTableBaseNumberOfDeletedElements()),
6557         table, effect, control);
6558     Node* used_capacity =
6559         graph()->NewNode(simplified()->NumberAdd(), number_of_elements,
6560                          number_of_deleted_elements);
6561 
6562     // Skip holes and update the {index}.
6563     Node* loop = graph()->NewNode(common()->Loop(2), control, control);
6564     Node* eloop =
6565         graph()->NewNode(common()->EffectPhi(2), effect, effect, loop);
6566     Node* terminate = graph()->NewNode(common()->Terminate(), eloop, loop);
6567     NodeProperties::MergeControlToEnd(graph(), common(), terminate);
6568     Node* iloop = graph()->NewNode(
6569         common()->Phi(MachineRepresentation::kTagged, 2), index, index, loop);
6570 
6571     Node* index = effect = graph()->NewNode(
6572         common()->TypeGuard(TypeCache::Get().kFixedArrayLengthType), iloop,
6573         eloop, control);
6574     {
6575       Node* check0 = graph()->NewNode(simplified()->NumberLessThan(), index,
6576                                       used_capacity);
6577       Node* branch0 =
6578           graph()->NewNode(common()->Branch(BranchHint::kTrue), check0, loop);
6579 
6580       Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
6581       Node* efalse0 = effect;
6582       {
6583         // Mark the {receiver} as exhausted.
6584         efalse0 = graph()->NewNode(
6585             simplified()->StoreField(
6586                 AccessBuilder::ForJSCollectionIteratorTable()),
6587             receiver, jsgraph()->HeapConstant(empty_collection), efalse0,
6588             if_false0);
6589 
6590         controls[0] = if_false0;
6591         effects[0] = efalse0;
6592       }
6593 
6594       Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
6595       Node* etrue0 = effect;
6596       {
6597         // Load the key of the entry.
6598         Node* entry_start_position = graph()->NewNode(
6599             simplified()->NumberAdd(),
6600             graph()->NewNode(
6601                 simplified()->NumberAdd(),
6602                 graph()->NewNode(simplified()->NumberMultiply(), index,
6603                                  jsgraph()->Constant(entry_size)),
6604                 number_of_buckets),
6605             jsgraph()->Constant(OrderedHashTableBase::kHashTableStartIndex));
6606         Node* entry_key = etrue0 = graph()->NewNode(
6607             simplified()->LoadElement(AccessBuilder::ForFixedArrayElement()),
6608             table, entry_start_position, etrue0, if_true0);
6609 
6610         // Advance the index.
6611         index = graph()->NewNode(simplified()->NumberAdd(), index,
6612                                  jsgraph()->OneConstant());
6613 
6614         Node* check1 =
6615             graph()->NewNode(simplified()->ReferenceEqual(), entry_key,
6616                              jsgraph()->TheHoleConstant());
6617         Node* branch1 = graph()->NewNode(common()->Branch(BranchHint::kFalse),
6618                                          check1, if_true0);
6619 
6620         {
6621           // Abort loop with resulting value.
6622           Node* control = graph()->NewNode(common()->IfFalse(), branch1);
6623           Node* effect = etrue0;
6624           Node* value = effect =
6625               graph()->NewNode(common()->TypeGuard(Type::NonInternal()),
6626                                entry_key, effect, control);
6627           Node* done = jsgraph()->FalseConstant();
6628 
6629           // Advance the index on the {receiver}.
6630           effect = graph()->NewNode(
6631               simplified()->StoreField(
6632                   AccessBuilder::ForJSCollectionIteratorIndex()),
6633               receiver, index, effect, control);
6634 
6635           // The actual {value} depends on the {receiver} iteration type.
6636           switch (receiver_instance_type) {
6637             case JS_MAP_KEY_ITERATOR_TYPE:
6638             case JS_SET_VALUE_ITERATOR_TYPE:
6639               break;
6640 
6641             case JS_SET_KEY_VALUE_ITERATOR_TYPE:
6642               value = effect =
6643                   graph()->NewNode(javascript()->CreateKeyValueArray(), value,
6644                                    value, context, effect);
6645               break;
6646 
6647             case JS_MAP_VALUE_ITERATOR_TYPE:
6648               value = effect = graph()->NewNode(
6649                   simplified()->LoadElement(
6650                       AccessBuilder::ForFixedArrayElement()),
6651                   table,
6652                   graph()->NewNode(
6653                       simplified()->NumberAdd(), entry_start_position,
6654                       jsgraph()->Constant(OrderedHashMap::kValueOffset)),
6655                   effect, control);
6656               break;
6657 
6658             case JS_MAP_KEY_VALUE_ITERATOR_TYPE:
6659               value = effect = graph()->NewNode(
6660                   simplified()->LoadElement(
6661                       AccessBuilder::ForFixedArrayElement()),
6662                   table,
6663                   graph()->NewNode(
6664                       simplified()->NumberAdd(), entry_start_position,
6665                       jsgraph()->Constant(OrderedHashMap::kValueOffset)),
6666                   effect, control);
6667               value = effect =
6668                   graph()->NewNode(javascript()->CreateKeyValueArray(),
6669                                    entry_key, value, context, effect);
6670               break;
6671 
6672             default:
6673               UNREACHABLE();
6674               break;
6675           }
6676 
6677           // Store final {value} and {done} into the {iterator_result}.
6678           effect =
6679               graph()->NewNode(simplified()->StoreField(
6680                                    AccessBuilder::ForJSIteratorResultValue()),
6681                                iterator_result, value, effect, control);
6682           effect =
6683               graph()->NewNode(simplified()->StoreField(
6684                                    AccessBuilder::ForJSIteratorResultDone()),
6685                                iterator_result, done, effect, control);
6686 
6687           controls[1] = control;
6688           effects[1] = effect;
6689         }
6690 
6691         // Continue with next loop index.
6692         loop->ReplaceInput(1, graph()->NewNode(common()->IfTrue(), branch1));
6693         eloop->ReplaceInput(1, etrue0);
6694         iloop->ReplaceInput(1, index);
6695       }
6696     }
6697 
6698     control = effects[2] = graph()->NewNode(common()->Merge(2), 2, controls);
6699     effect = graph()->NewNode(common()->EffectPhi(2), 3, effects);
6700   }
6701 
6702   // Yield the final {iterator_result}.
6703   ReplaceWithValue(node, iterator_result, effect, control);
6704   return Replace(iterator_result);
6705 }
6706 
ReduceArrayBufferIsView(Node * node)6707 Reduction JSCallReducer::ReduceArrayBufferIsView(Node* node) {
6708   Node* value = node->op()->ValueInputCount() >= 3
6709                     ? NodeProperties::GetValueInput(node, 2)
6710                     : jsgraph()->UndefinedConstant();
6711   RelaxEffectsAndControls(node);
6712   node->ReplaceInput(0, value);
6713   node->TrimInputCount(1);
6714   NodeProperties::ChangeOp(node, simplified()->ObjectIsArrayBufferView());
6715   return Changed(node);
6716 }
6717 
ReduceArrayBufferViewAccessor(Node * node,InstanceType instance_type,FieldAccess const & access)6718 Reduction JSCallReducer::ReduceArrayBufferViewAccessor(
6719     Node* node, InstanceType instance_type, FieldAccess const& access) {
6720   Node* receiver = NodeProperties::GetValueInput(node, 1);
6721   Node* effect = NodeProperties::GetEffectInput(node);
6722   Node* control = NodeProperties::GetControlInput(node);
6723   if (NodeProperties::HasInstanceTypeWitness(isolate(), receiver, effect,
6724                                              instance_type)) {
6725     // Load the {receiver}s field.
6726     Node* value = effect = graph()->NewNode(simplified()->LoadField(access),
6727                                             receiver, effect, control);
6728 
6729     // See if we can skip the neutering check.
6730     if (isolate()->IsArrayBufferNeuteringIntact()) {
6731       // Add a code dependency so we are deoptimized in case an ArrayBuffer
6732       // gets neutered.
6733       dependencies()->DependOnProtector(PropertyCellRef(
6734           js_heap_broker(), factory()->array_buffer_neutering_protector()));
6735     } else {
6736       // Check if the {receiver}s buffer was neutered.
6737       Node* buffer = effect = graph()->NewNode(
6738           simplified()->LoadField(AccessBuilder::ForJSArrayBufferViewBuffer()),
6739           receiver, effect, control);
6740       Node* check = effect = graph()->NewNode(
6741           simplified()->ArrayBufferWasNeutered(), buffer, effect, control);
6742 
6743       // Default to zero if the {receiver}s buffer was neutered.
6744       value = graph()->NewNode(
6745           common()->Select(MachineRepresentation::kTagged, BranchHint::kFalse),
6746           check, jsgraph()->ZeroConstant(), value);
6747     }
6748 
6749     ReplaceWithValue(node, value, effect, control);
6750     return Replace(value);
6751   }
6752   return NoChange();
6753 }
6754 
6755 namespace {
ExternalArrayElementSize(const ExternalArrayType element_type)6756 uint32_t ExternalArrayElementSize(const ExternalArrayType element_type) {
6757   switch (element_type) {
6758 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) \
6759   case kExternal##Type##Array:                    \
6760     DCHECK_LE(sizeof(ctype), 8);                  \
6761     return sizeof(ctype);
6762     TYPED_ARRAYS(TYPED_ARRAY_CASE)
6763     default:
6764       UNREACHABLE();
6765 #undef TYPED_ARRAY_CASE
6766   }
6767 }
6768 }  // namespace
6769 
ReduceDataViewPrototypeGet(Node * node,ExternalArrayType element_type)6770 Reduction JSCallReducer::ReduceDataViewPrototypeGet(
6771     Node* node, ExternalArrayType element_type) {
6772   uint32_t const element_size = ExternalArrayElementSize(element_type);
6773   CallParameters const& p = CallParametersOf(node->op());
6774   Node* effect = NodeProperties::GetEffectInput(node);
6775   Node* control = NodeProperties::GetControlInput(node);
6776   Node* receiver = NodeProperties::GetValueInput(node, 1);
6777 
6778   if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
6779     return NoChange();
6780   }
6781 
6782   Node* offset = node->op()->ValueInputCount() > 2
6783                      ? NodeProperties::GetValueInput(node, 2)
6784                      : jsgraph()->ZeroConstant();
6785 
6786   Node* is_little_endian = node->op()->ValueInputCount() > 3
6787                                ? NodeProperties::GetValueInput(node, 3)
6788                                : jsgraph()->FalseConstant();
6789 
6790   // Only do stuff if the {receiver} is really a DataView.
6791   if (NodeProperties::HasInstanceTypeWitness(isolate(), receiver, effect,
6792                                              JS_DATA_VIEW_TYPE)) {
6793     // Check that the {offset} is within range for the {receiver}.
6794     HeapObjectMatcher m(receiver);
6795     if (m.HasValue()) {
6796       // We only deal with DataViews here whose [[ByteLength]] is at least
6797       // {element_size} and less than 2^31-{element_size}.
6798       Handle<JSDataView> dataview = Handle<JSDataView>::cast(m.Value());
6799       if (dataview->byte_length()->Number() < element_size ||
6800           dataview->byte_length()->Number() - element_size > kMaxInt) {
6801         return NoChange();
6802       }
6803 
6804       // The {receiver}s [[ByteOffset]] must be within Unsigned31 range.
6805       if (dataview->byte_offset()->Number() > kMaxInt) {
6806         return NoChange();
6807       }
6808 
6809       // Check that the {offset} is within range of the {byte_length}.
6810       Node* byte_length = jsgraph()->Constant(
6811           dataview->byte_length()->Number() - (element_size - 1));
6812       offset = effect =
6813           graph()->NewNode(simplified()->CheckBounds(p.feedback()), offset,
6814                            byte_length, effect, control);
6815 
6816       // Add the [[ByteOffset]] to compute the effective offset.
6817       Node* byte_offset =
6818           jsgraph()->Constant(dataview->byte_offset()->Number());
6819       offset = graph()->NewNode(simplified()->NumberAdd(), offset, byte_offset);
6820     } else {
6821       // We only deal with DataViews here that have Smi [[ByteLength]]s.
6822       Node* byte_length = effect =
6823           graph()->NewNode(simplified()->LoadField(
6824                                AccessBuilder::ForJSArrayBufferViewByteLength()),
6825                            receiver, effect, control);
6826       byte_length = effect = graph()->NewNode(
6827           simplified()->CheckSmi(p.feedback()), byte_length, effect, control);
6828 
6829       // Check that the {offset} is within range of the {byte_length}.
6830       offset = effect =
6831           graph()->NewNode(simplified()->CheckBounds(p.feedback()), offset,
6832                            byte_length, effect, control);
6833 
6834       if (element_size > 0) {
6835         // For non-byte accesses we also need to check that the {offset}
6836         // plus the {element_size}-1 fits within the given {byte_length}.
6837         Node* end_offset =
6838             graph()->NewNode(simplified()->NumberAdd(), offset,
6839                              jsgraph()->Constant(element_size - 1));
6840         effect = graph()->NewNode(simplified()->CheckBounds(p.feedback()),
6841                                   end_offset, byte_length, effect, control);
6842       }
6843 
6844       // The {receiver}s [[ByteOffset]] also needs to be a (positive) Smi.
6845       Node* byte_offset = effect =
6846           graph()->NewNode(simplified()->LoadField(
6847                                AccessBuilder::ForJSArrayBufferViewByteOffset()),
6848                            receiver, effect, control);
6849       byte_offset = effect = graph()->NewNode(
6850           simplified()->CheckSmi(p.feedback()), byte_offset, effect, control);
6851 
6852       // Compute the buffer index at which we'll read.
6853       offset = graph()->NewNode(simplified()->NumberAdd(), offset, byte_offset);
6854     }
6855 
6856     // Coerce {is_little_endian} to boolean.
6857     is_little_endian =
6858         graph()->NewNode(simplified()->ToBoolean(), is_little_endian);
6859 
6860     // Get the underlying buffer and check that it has not been neutered.
6861     Node* buffer = effect = graph()->NewNode(
6862         simplified()->LoadField(AccessBuilder::ForJSArrayBufferViewBuffer()),
6863         receiver, effect, control);
6864 
6865     if (isolate()->IsArrayBufferNeuteringIntact()) {
6866       // Add a code dependency so we are deoptimized in case an ArrayBuffer
6867       // gets neutered.
6868       dependencies()->DependOnProtector(PropertyCellRef(
6869           js_heap_broker(), factory()->array_buffer_neutering_protector()));
6870     } else {
6871       // If the buffer was neutered, deopt and let the unoptimized code throw.
6872       Node* check_neutered = effect = graph()->NewNode(
6873           simplified()->ArrayBufferWasNeutered(), buffer, effect, control);
6874       check_neutered =
6875           graph()->NewNode(simplified()->BooleanNot(), check_neutered);
6876       effect = graph()->NewNode(
6877           simplified()->CheckIf(DeoptimizeReason::kArrayBufferWasNeutered,
6878                                 p.feedback()),
6879           check_neutered, effect, control);
6880     }
6881 
6882     // Get the buffer's backing store.
6883     Node* backing_store = effect = graph()->NewNode(
6884         simplified()->LoadField(AccessBuilder::ForJSArrayBufferBackingStore()),
6885         buffer, effect, control);
6886 
6887     // Perform the load.
6888     Node* value = effect = graph()->NewNode(
6889         simplified()->LoadDataViewElement(element_type), buffer, backing_store,
6890         offset, is_little_endian, effect, control);
6891 
6892     // Continue on the regular path.
6893     ReplaceWithValue(node, value, effect, control);
6894     return Changed(value);
6895   }
6896 
6897   return NoChange();
6898 }
6899 
ReduceDataViewPrototypeSet(Node * node,ExternalArrayType element_type)6900 Reduction JSCallReducer::ReduceDataViewPrototypeSet(
6901     Node* node, ExternalArrayType element_type) {
6902   uint32_t const element_size = ExternalArrayElementSize(element_type);
6903   CallParameters const& p = CallParametersOf(node->op());
6904   Node* effect = NodeProperties::GetEffectInput(node);
6905   Node* control = NodeProperties::GetControlInput(node);
6906   Node* receiver = NodeProperties::GetValueInput(node, 1);
6907 
6908   if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
6909     return NoChange();
6910   }
6911 
6912   Node* offset = node->op()->ValueInputCount() > 2
6913                      ? NodeProperties::GetValueInput(node, 2)
6914                      : jsgraph()->ZeroConstant();
6915 
6916   Node* value = node->op()->ValueInputCount() > 3
6917                     ? NodeProperties::GetValueInput(node, 3)
6918                     : jsgraph()->ZeroConstant();
6919 
6920   Node* is_little_endian = node->op()->ValueInputCount() > 4
6921                                ? NodeProperties::GetValueInput(node, 4)
6922                                : jsgraph()->FalseConstant();
6923 
6924   // Only do stuff if the {receiver} is really a DataView.
6925   if (NodeProperties::HasInstanceTypeWitness(isolate(), receiver, effect,
6926                                              JS_DATA_VIEW_TYPE)) {
6927     // Check that the {offset} is within range for the {receiver}.
6928     HeapObjectMatcher m(receiver);
6929     if (m.HasValue()) {
6930       // We only deal with DataViews here whose [[ByteLength]] is at least
6931       // {element_size} and less than 2^31-{element_size}.
6932       Handle<JSDataView> dataview = Handle<JSDataView>::cast(m.Value());
6933       if (dataview->byte_length()->Number() < element_size ||
6934           dataview->byte_length()->Number() - element_size > kMaxInt) {
6935         return NoChange();
6936       }
6937 
6938       // The {receiver}s [[ByteOffset]] must be within Unsigned31 range.
6939       if (dataview->byte_offset()->Number() > kMaxInt) {
6940         return NoChange();
6941       }
6942 
6943       // Check that the {offset} is within range of the {byte_length}.
6944       Node* byte_length = jsgraph()->Constant(
6945           dataview->byte_length()->Number() - (element_size - 1));
6946       offset = effect =
6947           graph()->NewNode(simplified()->CheckBounds(p.feedback()), offset,
6948                            byte_length, effect, control);
6949 
6950       // Add the [[ByteOffset]] to compute the effective offset.
6951       Node* byte_offset =
6952           jsgraph()->Constant(dataview->byte_offset()->Number());
6953       offset = graph()->NewNode(simplified()->NumberAdd(), offset, byte_offset);
6954     } else {
6955       // We only deal with DataViews here that have Smi [[ByteLength]]s.
6956       Node* byte_length = effect =
6957           graph()->NewNode(simplified()->LoadField(
6958                                AccessBuilder::ForJSArrayBufferViewByteLength()),
6959                            receiver, effect, control);
6960       byte_length = effect = graph()->NewNode(
6961           simplified()->CheckSmi(p.feedback()), byte_length, effect, control);
6962 
6963       // Check that the {offset} is within range of the {byte_length}.
6964       offset = effect =
6965           graph()->NewNode(simplified()->CheckBounds(p.feedback()), offset,
6966                            byte_length, effect, control);
6967 
6968       if (element_size > 0) {
6969         // For non-byte accesses we also need to check that the {offset}
6970         // plus the {element_size}-1 fits within the given {byte_length}.
6971         Node* end_offset =
6972             graph()->NewNode(simplified()->NumberAdd(), offset,
6973                              jsgraph()->Constant(element_size - 1));
6974         effect = graph()->NewNode(simplified()->CheckBounds(p.feedback()),
6975                                   end_offset, byte_length, effect, control);
6976       }
6977 
6978       // The {receiver}s [[ByteOffset]] also needs to be a (positive) Smi.
6979       Node* byte_offset = effect =
6980           graph()->NewNode(simplified()->LoadField(
6981                                AccessBuilder::ForJSArrayBufferViewByteOffset()),
6982                            receiver, effect, control);
6983       byte_offset = effect = graph()->NewNode(
6984           simplified()->CheckSmi(p.feedback()), byte_offset, effect, control);
6985 
6986       // Compute the buffer index at which we'll read.
6987       offset = graph()->NewNode(simplified()->NumberAdd(), offset, byte_offset);
6988     }
6989 
6990     // Coerce {is_little_endian} to boolean.
6991     is_little_endian =
6992         graph()->NewNode(simplified()->ToBoolean(), is_little_endian);
6993 
6994     // Coerce {value} to Number.
6995     value = effect = graph()->NewNode(
6996         simplified()->SpeculativeToNumber(NumberOperationHint::kNumberOrOddball,
6997                                           p.feedback()),
6998         value, effect, control);
6999 
7000     // Get the underlying buffer and check that it has not been neutered.
7001     Node* buffer = effect = graph()->NewNode(
7002         simplified()->LoadField(AccessBuilder::ForJSArrayBufferViewBuffer()),
7003         receiver, effect, control);
7004 
7005     if (isolate()->IsArrayBufferNeuteringIntact()) {
7006       // Add a code dependency so we are deoptimized in case an ArrayBuffer
7007       // gets neutered.
7008       dependencies()->DependOnProtector(PropertyCellRef(
7009           js_heap_broker(), factory()->array_buffer_neutering_protector()));
7010     } else {
7011       // If the buffer was neutered, deopt and let the unoptimized code throw.
7012       Node* check_neutered = effect = graph()->NewNode(
7013           simplified()->ArrayBufferWasNeutered(), buffer, effect, control);
7014       check_neutered =
7015           graph()->NewNode(simplified()->BooleanNot(), check_neutered);
7016       effect = graph()->NewNode(
7017           simplified()->CheckIf(DeoptimizeReason::kArrayBufferWasNeutered,
7018                                 p.feedback()),
7019           check_neutered, effect, control);
7020     }
7021 
7022     // Get the buffer's backing store.
7023     Node* backing_store = effect = graph()->NewNode(
7024         simplified()->LoadField(AccessBuilder::ForJSArrayBufferBackingStore()),
7025         buffer, effect, control);
7026 
7027     // Perform the store.
7028     effect = graph()->NewNode(simplified()->StoreDataViewElement(element_type),
7029                               buffer, backing_store, offset, value,
7030                               is_little_endian, effect, control);
7031 
7032     Node* value = jsgraph()->UndefinedConstant();
7033 
7034     // Continue on the regular path.
7035     ReplaceWithValue(node, value, effect, control);
7036     return Changed(value);
7037   }
7038 
7039   return NoChange();
7040 }
7041 
7042 // ES6 section 18.2.2 isFinite ( number )
ReduceGlobalIsFinite(Node * node)7043 Reduction JSCallReducer::ReduceGlobalIsFinite(Node* node) {
7044   CallParameters const& p = CallParametersOf(node->op());
7045   if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
7046     return NoChange();
7047   }
7048   if (node->op()->ValueInputCount() < 3) {
7049     Node* value = jsgraph()->FalseConstant();
7050     ReplaceWithValue(node, value);
7051     return Replace(value);
7052   }
7053 
7054   Node* effect = NodeProperties::GetEffectInput(node);
7055   Node* control = NodeProperties::GetControlInput(node);
7056   Node* input = NodeProperties::GetValueInput(node, 2);
7057 
7058   input = effect =
7059       graph()->NewNode(simplified()->SpeculativeToNumber(
7060                            NumberOperationHint::kNumberOrOddball, p.feedback()),
7061                        input, effect, control);
7062   Node* value = graph()->NewNode(simplified()->NumberIsFinite(), input);
7063   ReplaceWithValue(node, value, effect);
7064   return Replace(value);
7065 }
7066 
7067 // ES6 section 18.2.3 isNaN ( number )
ReduceGlobalIsNaN(Node * node)7068 Reduction JSCallReducer::ReduceGlobalIsNaN(Node* node) {
7069   CallParameters const& p = CallParametersOf(node->op());
7070   if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
7071     return NoChange();
7072   }
7073   if (node->op()->ValueInputCount() < 3) {
7074     Node* value = jsgraph()->TrueConstant();
7075     ReplaceWithValue(node, value);
7076     return Replace(value);
7077   }
7078 
7079   Node* effect = NodeProperties::GetEffectInput(node);
7080   Node* control = NodeProperties::GetControlInput(node);
7081   Node* input = NodeProperties::GetValueInput(node, 2);
7082 
7083   input = effect =
7084       graph()->NewNode(simplified()->SpeculativeToNumber(
7085                            NumberOperationHint::kNumberOrOddball, p.feedback()),
7086                        input, effect, control);
7087   Node* value = graph()->NewNode(simplified()->NumberIsNaN(), input);
7088   ReplaceWithValue(node, value, effect);
7089   return Replace(value);
7090 }
7091 
7092 // ES6 section 20.3.4.10 Date.prototype.getTime ( )
ReduceDatePrototypeGetTime(Node * node)7093 Reduction JSCallReducer::ReduceDatePrototypeGetTime(Node* node) {
7094   Node* receiver = NodeProperties::GetValueInput(node, 1);
7095   Node* effect = NodeProperties::GetEffectInput(node);
7096   Node* control = NodeProperties::GetControlInput(node);
7097   if (NodeProperties::HasInstanceTypeWitness(isolate(), receiver, effect,
7098                                              JS_DATE_TYPE)) {
7099     Node* value = effect = graph()->NewNode(
7100         simplified()->LoadField(AccessBuilder::ForJSDateValue()), receiver,
7101         effect, control);
7102     ReplaceWithValue(node, value, effect, control);
7103     return Replace(value);
7104   }
7105   return NoChange();
7106 }
7107 
7108 // ES6 section 20.3.3.1 Date.now ( )
ReduceDateNow(Node * node)7109 Reduction JSCallReducer::ReduceDateNow(Node* node) {
7110   Node* effect = NodeProperties::GetEffectInput(node);
7111   Node* control = NodeProperties::GetControlInput(node);
7112   Node* value = effect =
7113       graph()->NewNode(simplified()->DateNow(), effect, control);
7114   ReplaceWithValue(node, value, effect, control);
7115   return Replace(value);
7116 }
7117 
7118 // ES6 section 20.1.2.13 Number.parseInt ( string, radix )
ReduceNumberParseInt(Node * node)7119 Reduction JSCallReducer::ReduceNumberParseInt(Node* node) {
7120   // We certainly know that undefined is not an array.
7121   if (node->op()->ValueInputCount() < 3) {
7122     Node* value = jsgraph()->NaNConstant();
7123     ReplaceWithValue(node, value);
7124     return Replace(value);
7125   }
7126 
7127   int arg_count = node->op()->ValueInputCount();
7128   Node* effect = NodeProperties::GetEffectInput(node);
7129   Node* control = NodeProperties::GetControlInput(node);
7130   Node* context = NodeProperties::GetContextInput(node);
7131   Node* frame_state = NodeProperties::GetFrameStateInput(node);
7132   Node* object = NodeProperties::GetValueInput(node, 2);
7133   Node* radix = arg_count >= 4 ? NodeProperties::GetValueInput(node, 3)
7134                                : jsgraph()->UndefinedConstant();
7135   node->ReplaceInput(0, object);
7136   node->ReplaceInput(1, radix);
7137   node->ReplaceInput(2, context);
7138   node->ReplaceInput(3, frame_state);
7139   node->ReplaceInput(4, effect);
7140   node->ReplaceInput(5, control);
7141   node->TrimInputCount(6);
7142   NodeProperties::ChangeOp(node, javascript()->ParseInt());
7143   return Changed(node);
7144 }
7145 
ReduceRegExpPrototypeTest(Node * node)7146 Reduction JSCallReducer::ReduceRegExpPrototypeTest(Node* node) {
7147   if (FLAG_force_slow_path) return NoChange();
7148   if (node->op()->ValueInputCount() < 3) return NoChange();
7149   CallParameters const& p = CallParametersOf(node->op());
7150   if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
7151     return NoChange();
7152   }
7153 
7154   Node* effect = NodeProperties::GetEffectInput(node);
7155   Node* control = NodeProperties::GetControlInput(node);
7156   Node* regexp = NodeProperties::GetValueInput(node, 1);
7157 
7158   // Check if we know something about the {regexp}.
7159   ZoneHandleSet<Map> regexp_maps;
7160   NodeProperties::InferReceiverMapsResult result =
7161       NodeProperties::InferReceiverMaps(isolate(), regexp, effect,
7162                                         &regexp_maps);
7163 
7164   bool need_map_check = false;
7165   switch (result) {
7166     case NodeProperties::kNoReceiverMaps:
7167       return NoChange();
7168     case NodeProperties::kUnreliableReceiverMaps:
7169       need_map_check = true;
7170       break;
7171     case NodeProperties::kReliableReceiverMaps:
7172       break;
7173   }
7174 
7175   for (auto map : regexp_maps) {
7176     if (map->instance_type() != JS_REGEXP_TYPE) return NoChange();
7177   }
7178 
7179   // Compute property access info for "exec" on {resolution}.
7180   PropertyAccessInfo ai_exec;
7181   AccessInfoFactory access_info_factory(js_heap_broker(), dependencies(),
7182                                         native_context(), graph()->zone());
7183   if (!access_info_factory.ComputePropertyAccessInfo(
7184           MapHandles(regexp_maps.begin(), regexp_maps.end()),
7185           factory()->exec_string(), AccessMode::kLoad, &ai_exec)) {
7186     return NoChange();
7187   }
7188   // If "exec" has been modified on {regexp}, we can't do anything.
7189   if (!ai_exec.IsDataConstant()) return NoChange();
7190   Handle<Object> exec_on_proto = ai_exec.constant();
7191   if (*exec_on_proto != *isolate()->regexp_exec_function()) return NoChange();
7192 
7193   PropertyAccessBuilder access_builder(jsgraph(), js_heap_broker(),
7194                                        dependencies());
7195 
7196   // Add proper dependencies on the {regexp}s [[Prototype]]s.
7197   Handle<JSObject> holder;
7198   if (ai_exec.holder().ToHandle(&holder)) {
7199     dependencies()->DependOnStablePrototypeChains(
7200         js_heap_broker(), native_context(), ai_exec.receiver_maps(), holder);
7201   }
7202 
7203   if (need_map_check) {
7204     effect =
7205         graph()->NewNode(simplified()->CheckMaps(CheckMapsFlag::kNone,
7206                                                  regexp_maps, p.feedback()),
7207                          regexp, effect, control);
7208   }
7209 
7210   Node* context = NodeProperties::GetContextInput(node);
7211   Node* frame_state = NodeProperties::GetFrameStateInput(node);
7212   Node* search = NodeProperties::GetValueInput(node, 2);
7213   Node* search_string = effect = graph()->NewNode(
7214       simplified()->CheckString(p.feedback()), search, effect, control);
7215 
7216   Node* lastIndex = effect = graph()->NewNode(
7217       simplified()->LoadField(AccessBuilder::ForJSRegExpLastIndex()), regexp,
7218       effect, control);
7219 
7220   Node* lastIndexSmi = effect = graph()->NewNode(
7221       simplified()->CheckSmi(p.feedback()), lastIndex, effect, control);
7222 
7223   Node* is_positive = graph()->NewNode(simplified()->NumberLessThanOrEqual(),
7224                                        jsgraph()->ZeroConstant(), lastIndexSmi);
7225 
7226   effect = graph()->NewNode(
7227       simplified()->CheckIf(DeoptimizeReason::kNotASmi, p.feedback()),
7228       is_positive, effect, control);
7229 
7230   node->ReplaceInput(0, regexp);
7231   node->ReplaceInput(1, search_string);
7232   node->ReplaceInput(2, context);
7233   node->ReplaceInput(3, frame_state);
7234   node->ReplaceInput(4, effect);
7235   node->ReplaceInput(5, control);
7236   node->TrimInputCount(6);
7237   NodeProperties::ChangeOp(node, javascript()->RegExpTest());
7238   return Changed(node);
7239 }
7240 
7241 // ES section #sec-number-constructor
ReduceNumberConstructor(Node * node)7242 Reduction JSCallReducer::ReduceNumberConstructor(Node* node) {
7243   DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
7244   CallParameters const& p = CallParametersOf(node->op());
7245 
7246   if (p.arity() <= 2) {
7247     ReplaceWithValue(node, jsgraph()->ZeroConstant());
7248   }
7249 
7250   // We don't have a new.target argument, so we can convert to number,
7251   // but must also convert BigInts.
7252   if (p.arity() == 3) {
7253     Node* target = NodeProperties::GetValueInput(node, 0);
7254     Node* context = NodeProperties::GetContextInput(node);
7255     Node* value = NodeProperties::GetValueInput(node, 2);
7256     Node* outer_frame_state = NodeProperties::GetFrameStateInput(node);
7257     Handle<SharedFunctionInfo> number_constructor(
7258         handle(native_context()->number_function()->shared(), isolate()));
7259 
7260     const std::vector<Node*> checkpoint_parameters({
7261         jsgraph()->UndefinedConstant(), /* receiver */
7262     });
7263     int checkpoint_parameters_size =
7264         static_cast<int>(checkpoint_parameters.size());
7265 
7266     Node* frame_state = CreateJavaScriptBuiltinContinuationFrameState(
7267         jsgraph(), number_constructor,
7268         Builtins::kGenericConstructorLazyDeoptContinuation, target, context,
7269         checkpoint_parameters.data(), checkpoint_parameters_size,
7270         outer_frame_state, ContinuationFrameStateMode::LAZY);
7271 
7272     NodeProperties::ReplaceValueInputs(node, value);
7273     NodeProperties::ChangeOp(node, javascript()->ToNumberConvertBigInt());
7274     NodeProperties::ReplaceFrameStateInput(node, frame_state);
7275     return Changed(node);
7276   }
7277   return NoChange();
7278 }
7279 
graph() const7280 Graph* JSCallReducer::graph() const { return jsgraph()->graph(); }
7281 
isolate() const7282 Isolate* JSCallReducer::isolate() const { return jsgraph()->isolate(); }
7283 
factory() const7284 Factory* JSCallReducer::factory() const { return isolate()->factory(); }
7285 
global_proxy() const7286 Handle<JSGlobalProxy> JSCallReducer::global_proxy() const {
7287   return handle(JSGlobalProxy::cast(native_context()->global_proxy()),
7288                 isolate());
7289 }
7290 
common() const7291 CommonOperatorBuilder* JSCallReducer::common() const {
7292   return jsgraph()->common();
7293 }
7294 
javascript() const7295 JSOperatorBuilder* JSCallReducer::javascript() const {
7296   return jsgraph()->javascript();
7297 }
7298 
simplified() const7299 SimplifiedOperatorBuilder* JSCallReducer::simplified() const {
7300   return jsgraph()->simplified();
7301 }
7302 
7303 }  // namespace compiler
7304 }  // namespace internal
7305 }  // namespace v8
7306