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