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