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