1// Copyright 2014 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-generic-lowering.h"
6
7#include "src/ast/ast.h"
8#include "src/builtins/builtins-constructor.h"
9#include "src/codegen/code-factory.h"
10#include "src/codegen/interface-descriptors-inl.h"
11#include "src/compiler/access-builder.h"
12#include "src/compiler/common-operator.h"
13#include "src/compiler/js-graph.h"
14#include "src/compiler/js-heap-broker.h"
15#include "src/compiler/machine-operator.h"
16#include "src/compiler/node-matchers.h"
17#include "src/compiler/node-properties.h"
18#include "src/compiler/operator-properties.h"
19#include "src/compiler/processed-feedback.h"
20#include "src/compiler/simplified-operator.h"
21#include "src/objects/feedback-cell.h"
22#include "src/objects/feedback-vector.h"
23#include "src/objects/scope-info.h"
24#include "src/objects/template-objects-inl.h"
25
26namespace v8 {
27namespace internal {
28namespace compiler {
29
30namespace {
31
32CallDescriptor::Flags FrameStateFlagForCall(Node* node) {
33  return OperatorProperties::HasFrameStateInput(node->op())
34             ? CallDescriptor::kNeedsFrameState
35             : CallDescriptor::kNoFlags;
36}
37
38}  // namespace
39
40JSGenericLowering::JSGenericLowering(JSGraph* jsgraph, Editor* editor,
41                                     JSHeapBroker* broker)
42    : AdvancedReducer(editor), jsgraph_(jsgraph), broker_(broker) {}
43
44JSGenericLowering::~JSGenericLowering() = default;
45
46
47Reduction JSGenericLowering::Reduce(Node* node) {
48  switch (node->opcode()) {
49#define DECLARE_CASE(x, ...) \
50  case IrOpcode::k##x:       \
51    Lower##x(node);          \
52    break;
53    JS_OP_LIST(DECLARE_CASE)
54#undef DECLARE_CASE
55    default:
56      // Nothing to see.
57      return NoChange();
58  }
59  return Changed(node);
60}
61
62#define REPLACE_STUB_CALL(Name)                       \
63  void JSGenericLowering::LowerJS##Name(Node* node) { \
64    ReplaceWithBuiltinCall(node, Builtin::k##Name);   \
65  }
66REPLACE_STUB_CALL(ToLength)
67REPLACE_STUB_CALL(ToNumber)
68REPLACE_STUB_CALL(ToNumberConvertBigInt)
69REPLACE_STUB_CALL(ToNumeric)
70REPLACE_STUB_CALL(ToName)
71REPLACE_STUB_CALL(ToObject)
72REPLACE_STUB_CALL(ToString)
73REPLACE_STUB_CALL(ForInEnumerate)
74REPLACE_STUB_CALL(AsyncFunctionEnter)
75REPLACE_STUB_CALL(AsyncFunctionReject)
76REPLACE_STUB_CALL(AsyncFunctionResolve)
77REPLACE_STUB_CALL(FulfillPromise)
78REPLACE_STUB_CALL(PerformPromiseThen)
79REPLACE_STUB_CALL(PromiseResolve)
80REPLACE_STUB_CALL(RejectPromise)
81REPLACE_STUB_CALL(ResolvePromise)
82#undef REPLACE_STUB_CALL
83
84void JSGenericLowering::ReplaceWithBuiltinCall(Node* node, Builtin builtin) {
85  CallDescriptor::Flags flags = FrameStateFlagForCall(node);
86  Callable callable = Builtins::CallableFor(isolate(), builtin);
87  ReplaceWithBuiltinCall(node, callable, flags);
88}
89
90void JSGenericLowering::ReplaceWithBuiltinCall(Node* node, Callable callable,
91                                               CallDescriptor::Flags flags) {
92  ReplaceWithBuiltinCall(node, callable, flags, node->op()->properties());
93}
94
95void JSGenericLowering::ReplaceWithBuiltinCall(
96    Node* node, Callable callable, CallDescriptor::Flags flags,
97    Operator::Properties properties) {
98  const CallInterfaceDescriptor& descriptor = callable.descriptor();
99  auto call_descriptor = Linkage::GetStubCallDescriptor(
100      zone(), descriptor, descriptor.GetStackParameterCount(), flags,
101      properties);
102  Node* stub_code = jsgraph()->HeapConstant(callable.code());
103  node->InsertInput(zone(), 0, stub_code);
104  NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
105}
106
107void JSGenericLowering::ReplaceWithRuntimeCall(Node* node,
108                                               Runtime::FunctionId f,
109                                               int nargs_override) {
110  CallDescriptor::Flags flags = FrameStateFlagForCall(node);
111  Operator::Properties properties = node->op()->properties();
112  const Runtime::Function* fun = Runtime::FunctionForId(f);
113  int nargs = (nargs_override < 0) ? fun->nargs : nargs_override;
114  auto call_descriptor =
115      Linkage::GetRuntimeCallDescriptor(zone(), f, nargs, properties, flags);
116  Node* ref = jsgraph()->ExternalConstant(ExternalReference::Create(f));
117  Node* arity = jsgraph()->Int32Constant(nargs);
118  node->InsertInput(zone(), 0, jsgraph()->CEntryStubConstant(fun->result_size));
119  node->InsertInput(zone(), nargs + 1, ref);
120  node->InsertInput(zone(), nargs + 2, arity);
121  NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
122}
123
124void JSGenericLowering::ReplaceUnaryOpWithBuiltinCall(
125    Node* node, Builtin builtin_without_feedback,
126    Builtin builtin_with_feedback) {
127  DCHECK(JSOperator::IsUnaryWithFeedback(node->opcode()));
128  const FeedbackParameter& p = FeedbackParameterOf(node->op());
129  if (CollectFeedbackInGenericLowering() && p.feedback().IsValid()) {
130    Callable callable = Builtins::CallableFor(isolate(), builtin_with_feedback);
131    Node* slot = jsgraph()->UintPtrConstant(p.feedback().slot.ToInt());
132    const CallInterfaceDescriptor& descriptor = callable.descriptor();
133    CallDescriptor::Flags flags = FrameStateFlagForCall(node);
134    auto call_descriptor = Linkage::GetStubCallDescriptor(
135        zone(), descriptor, descriptor.GetStackParameterCount(), flags,
136        node->op()->properties());
137    Node* stub_code = jsgraph()->HeapConstant(callable.code());
138    STATIC_ASSERT(JSUnaryOpNode::ValueIndex() == 0);
139    STATIC_ASSERT(JSUnaryOpNode::FeedbackVectorIndex() == 1);
140    DCHECK_EQ(node->op()->ValueInputCount(), 2);
141    node->InsertInput(zone(), 0, stub_code);
142    node->InsertInput(zone(), 2, slot);
143    NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
144  } else {
145    node->RemoveInput(JSUnaryOpNode::FeedbackVectorIndex());
146    ReplaceWithBuiltinCall(node, builtin_without_feedback);
147  }
148}
149
150#define DEF_UNARY_LOWERING(Name)                                    \
151  void JSGenericLowering::LowerJS##Name(Node* node) {               \
152    ReplaceUnaryOpWithBuiltinCall(node, Builtin::k##Name,           \
153                                  Builtin::k##Name##_WithFeedback); \
154  }
155DEF_UNARY_LOWERING(BitwiseNot)
156DEF_UNARY_LOWERING(Decrement)
157DEF_UNARY_LOWERING(Increment)
158DEF_UNARY_LOWERING(Negate)
159#undef DEF_UNARY_LOWERING
160
161void JSGenericLowering::ReplaceBinaryOpWithBuiltinCall(
162    Node* node, Builtin builtin_without_feedback,
163    Builtin builtin_with_feedback) {
164  DCHECK(JSOperator::IsBinaryWithFeedback(node->opcode()));
165  Builtin builtin;
166  const FeedbackParameter& p = FeedbackParameterOf(node->op());
167  if (CollectFeedbackInGenericLowering() && p.feedback().IsValid()) {
168    Node* slot = jsgraph()->UintPtrConstant(p.feedback().slot.ToInt());
169    STATIC_ASSERT(JSBinaryOpNode::LeftIndex() == 0);
170    STATIC_ASSERT(JSBinaryOpNode::RightIndex() == 1);
171    STATIC_ASSERT(JSBinaryOpNode::FeedbackVectorIndex() == 2);
172    DCHECK_EQ(node->op()->ValueInputCount(), 3);
173    node->InsertInput(zone(), 2, slot);
174    builtin = builtin_with_feedback;
175  } else {
176    node->RemoveInput(JSBinaryOpNode::FeedbackVectorIndex());
177    builtin = builtin_without_feedback;
178  }
179
180  ReplaceWithBuiltinCall(node, builtin);
181}
182
183#define DEF_BINARY_LOWERING(Name)                                    \
184  void JSGenericLowering::LowerJS##Name(Node* node) {                \
185    ReplaceBinaryOpWithBuiltinCall(node, Builtin::k##Name,           \
186                                   Builtin::k##Name##_WithFeedback); \
187  }
188// Binary ops.
189DEF_BINARY_LOWERING(Add)
190DEF_BINARY_LOWERING(BitwiseAnd)
191DEF_BINARY_LOWERING(BitwiseOr)
192DEF_BINARY_LOWERING(BitwiseXor)
193DEF_BINARY_LOWERING(Divide)
194DEF_BINARY_LOWERING(Exponentiate)
195DEF_BINARY_LOWERING(Modulus)
196DEF_BINARY_LOWERING(Multiply)
197DEF_BINARY_LOWERING(ShiftLeft)
198DEF_BINARY_LOWERING(ShiftRight)
199DEF_BINARY_LOWERING(ShiftRightLogical)
200DEF_BINARY_LOWERING(Subtract)
201// Compare ops.
202DEF_BINARY_LOWERING(Equal)
203DEF_BINARY_LOWERING(GreaterThan)
204DEF_BINARY_LOWERING(GreaterThanOrEqual)
205DEF_BINARY_LOWERING(InstanceOf)
206DEF_BINARY_LOWERING(LessThan)
207DEF_BINARY_LOWERING(LessThanOrEqual)
208#undef DEF_BINARY_LOWERING
209
210void JSGenericLowering::LowerJSStrictEqual(Node* node) {
211  // The === operator doesn't need the current context.
212  NodeProperties::ReplaceContextInput(node, jsgraph()->NoContextConstant());
213  DCHECK_EQ(node->op()->ControlInputCount(), 1);
214  node->RemoveInput(NodeProperties::FirstControlIndex(node));
215
216  Builtin builtin;
217  const FeedbackParameter& p = FeedbackParameterOf(node->op());
218  if (CollectFeedbackInGenericLowering() && p.feedback().IsValid()) {
219    Node* slot = jsgraph()->UintPtrConstant(p.feedback().slot.ToInt());
220    STATIC_ASSERT(JSStrictEqualNode::LeftIndex() == 0);
221    STATIC_ASSERT(JSStrictEqualNode::RightIndex() == 1);
222    STATIC_ASSERT(JSStrictEqualNode::FeedbackVectorIndex() == 2);
223    DCHECK_EQ(node->op()->ValueInputCount(), 3);
224    node->InsertInput(zone(), 2, slot);
225    builtin = Builtin::kStrictEqual_WithFeedback;
226  } else {
227    node->RemoveInput(JSStrictEqualNode::FeedbackVectorIndex());
228    builtin = Builtin::kStrictEqual;
229  }
230
231  Callable callable = Builtins::CallableFor(isolate(), builtin);
232  ReplaceWithBuiltinCall(node, callable, CallDescriptor::kNoFlags,
233                         Operator::kEliminatable);
234}
235
236namespace {
237
238// The megamorphic load builtin can be used as a performance optimization in
239// some cases - unlike the full builtin, the megamorphic builtin does fewer
240// checks and does not collect feedback.
241bool ShouldUseMegamorphicLoadBuiltin(FeedbackSource const& source,
242                                     base::Optional<NameRef> name,
243                                     JSHeapBroker* broker) {
244  ProcessedFeedback const& feedback =
245      broker->GetFeedbackForPropertyAccess(source, AccessMode::kLoad, name);
246
247  if (feedback.kind() == ProcessedFeedback::kElementAccess) {
248    return feedback.AsElementAccess().transition_groups().empty();
249  } else if (feedback.kind() == ProcessedFeedback::kNamedAccess) {
250    return feedback.AsNamedAccess().maps().empty();
251  } else if (feedback.kind() == ProcessedFeedback::kInsufficient) {
252    return false;
253  }
254  UNREACHABLE();
255}
256
257}  // namespace
258
259void JSGenericLowering::LowerJSHasProperty(Node* node) {
260  JSHasPropertyNode n(node);
261  const PropertyAccess& p = n.Parameters();
262  if (!p.feedback().IsValid()) {
263    node->RemoveInput(JSHasPropertyNode::FeedbackVectorIndex());
264    ReplaceWithBuiltinCall(node, Builtin::kHasProperty);
265  } else {
266    STATIC_ASSERT(n.FeedbackVectorIndex() == 2);
267    n->InsertInput(zone(), 2,
268                   jsgraph()->TaggedIndexConstant(p.feedback().index()));
269    ReplaceWithBuiltinCall(node, Builtin::kKeyedHasIC);
270  }
271}
272
273void JSGenericLowering::LowerJSLoadProperty(Node* node) {
274  JSLoadPropertyNode n(node);
275  const PropertyAccess& p = n.Parameters();
276  FrameState frame_state = n.frame_state();
277  Node* outer_state = frame_state.outer_frame_state();
278  STATIC_ASSERT(n.FeedbackVectorIndex() == 2);
279  if (outer_state->opcode() != IrOpcode::kFrameState) {
280    n->RemoveInput(n.FeedbackVectorIndex());
281    n->InsertInput(zone(), 2,
282                   jsgraph()->TaggedIndexConstant(p.feedback().index()));
283    ReplaceWithBuiltinCall(
284        node, ShouldUseMegamorphicLoadBuiltin(p.feedback(), {}, broker())
285                  ? Builtin::kKeyedLoadICTrampoline_Megamorphic
286                  : Builtin::kKeyedLoadICTrampoline);
287  } else {
288    n->InsertInput(zone(), 2,
289                   jsgraph()->TaggedIndexConstant(p.feedback().index()));
290    ReplaceWithBuiltinCall(
291        node, ShouldUseMegamorphicLoadBuiltin(p.feedback(), {}, broker())
292                  ? Builtin::kKeyedLoadIC_Megamorphic
293                  : Builtin::kKeyedLoadIC);
294  }
295}
296
297void JSGenericLowering::LowerJSLoadNamed(Node* node) {
298  JSLoadNamedNode n(node);
299  NamedAccess const& p = n.Parameters();
300  FrameState frame_state = n.frame_state();
301  Node* outer_state = frame_state.outer_frame_state();
302  STATIC_ASSERT(n.FeedbackVectorIndex() == 1);
303  if (!p.feedback().IsValid()) {
304    n->RemoveInput(n.FeedbackVectorIndex());
305    node->InsertInput(zone(), 1, jsgraph()->Constant(p.name(broker())));
306    ReplaceWithBuiltinCall(node, Builtin::kGetProperty);
307  } else if (outer_state->opcode() != IrOpcode::kFrameState) {
308    n->RemoveInput(n.FeedbackVectorIndex());
309    node->InsertInput(zone(), 1, jsgraph()->Constant(p.name(broker())));
310    node->InsertInput(zone(), 2,
311                      jsgraph()->TaggedIndexConstant(p.feedback().index()));
312    ReplaceWithBuiltinCall(node, ShouldUseMegamorphicLoadBuiltin(
313                                     p.feedback(), p.name(broker()), broker())
314                                     ? Builtin::kLoadICTrampoline_Megamorphic
315                                     : Builtin::kLoadICTrampoline);
316  } else {
317    node->InsertInput(zone(), 1, jsgraph()->Constant(p.name(broker())));
318    node->InsertInput(zone(), 2,
319                      jsgraph()->TaggedIndexConstant(p.feedback().index()));
320    ReplaceWithBuiltinCall(node, ShouldUseMegamorphicLoadBuiltin(
321                                     p.feedback(), p.name(broker()), broker())
322                                     ? Builtin::kLoadIC_Megamorphic
323                                     : Builtin::kLoadIC);
324  }
325}
326
327void JSGenericLowering::LowerJSLoadNamedFromSuper(Node* node) {
328  JSLoadNamedFromSuperNode n(node);
329  NamedAccess const& p = n.Parameters();
330  Node* effect = NodeProperties::GetEffectInput(node);
331  Node* control = NodeProperties::GetControlInput(node);
332  // Node inputs: receiver, home object, FeedbackVector.
333  // LoadSuperIC expects: receiver, lookup start object, name, slot,
334  // FeedbackVector.
335  Node* home_object_map = effect = graph()->NewNode(
336      jsgraph()->simplified()->LoadField(AccessBuilder::ForMap()),
337      n.home_object(), effect, control);
338  Node* home_object_proto = effect = graph()->NewNode(
339      jsgraph()->simplified()->LoadField(AccessBuilder::ForMapPrototype()),
340      home_object_map, effect, control);
341  n->ReplaceInput(n.HomeObjectIndex(), home_object_proto);
342  NodeProperties::ReplaceEffectInput(node, effect);
343  STATIC_ASSERT(n.FeedbackVectorIndex() == 2);
344  // If the code below will be used for the invalid feedback case, it needs to
345  // be double-checked that the FeedbackVector parameter will be the
346  // UndefinedConstant.
347  DCHECK(p.feedback().IsValid());
348  node->InsertInput(zone(), 2, jsgraph()->Constant(p.name(broker())));
349  node->InsertInput(zone(), 3,
350                    jsgraph()->TaggedIndexConstant(p.feedback().index()));
351  ReplaceWithBuiltinCall(node, Builtin::kLoadSuperIC);
352}
353
354void JSGenericLowering::LowerJSLoadGlobal(Node* node) {
355  JSLoadGlobalNode n(node);
356  const LoadGlobalParameters& p = n.Parameters();
357  CallDescriptor::Flags flags = FrameStateFlagForCall(node);
358  FrameState frame_state = n.frame_state();
359  Node* outer_state = frame_state.outer_frame_state();
360  STATIC_ASSERT(n.FeedbackVectorIndex() == 0);
361  if (outer_state->opcode() != IrOpcode::kFrameState) {
362    n->RemoveInput(n.FeedbackVectorIndex());
363    node->InsertInput(zone(), 0, jsgraph()->Constant(p.name(broker())));
364    node->InsertInput(zone(), 1,
365                      jsgraph()->TaggedIndexConstant(p.feedback().index()));
366    Callable callable = CodeFactory::LoadGlobalIC(isolate(), p.typeof_mode());
367    ReplaceWithBuiltinCall(node, callable, flags);
368  } else {
369    node->InsertInput(zone(), 0, jsgraph()->Constant(p.name(broker())));
370    node->InsertInput(zone(), 1,
371                      jsgraph()->TaggedIndexConstant(p.feedback().index()));
372    Callable callable =
373        CodeFactory::LoadGlobalICInOptimizedCode(isolate(), p.typeof_mode());
374    ReplaceWithBuiltinCall(node, callable, flags);
375  }
376}
377
378void JSGenericLowering::LowerJSGetIterator(Node* node) {
379  // TODO(v8:9625): Currently, the GetIterator operator is desugared in the
380  // native context specialization phase. Thus, the following generic lowering
381  // is not reachable unless that phase is disabled (e.g. for
382  // native-context-independent code).
383  // We can add a check in native context specialization to avoid desugaring
384  // the GetIterator operator when feedback is megamorphic. This would reduce
385  // the size of the compiled code as it would insert 1 call to the builtin
386  // instead of 2 calls resulting from the generic lowering of the LoadNamed
387  // and Call operators.
388
389  JSGetIteratorNode n(node);
390  GetIteratorParameters const& p = n.Parameters();
391  Node* load_slot =
392      jsgraph()->TaggedIndexConstant(p.loadFeedback().slot.ToInt());
393  Node* call_slot =
394      jsgraph()->TaggedIndexConstant(p.callFeedback().slot.ToInt());
395  STATIC_ASSERT(n.FeedbackVectorIndex() == 1);
396  node->InsertInput(zone(), 1, load_slot);
397  node->InsertInput(zone(), 2, call_slot);
398
399  ReplaceWithBuiltinCall(node, Builtin::kGetIteratorWithFeedback);
400}
401
402void JSGenericLowering::LowerJSSetKeyedProperty(Node* node) {
403  JSSetKeyedPropertyNode n(node);
404  const PropertyAccess& p = n.Parameters();
405  FrameState frame_state = n.frame_state();
406  Node* outer_state = frame_state.outer_frame_state();
407  STATIC_ASSERT(n.FeedbackVectorIndex() == 3);
408  if (outer_state->opcode() != IrOpcode::kFrameState) {
409    n->RemoveInput(n.FeedbackVectorIndex());
410    node->InsertInput(zone(), 3,
411                      jsgraph()->TaggedIndexConstant(p.feedback().index()));
412
413    // KeyedStoreIC is currently a base class for multiple keyed property store
414    // operations and contains mixed logic for set and define operations,
415    // the paths are controlled by feedback.
416    // TODO(v8:12548): refactor SetKeyedIC as a subclass of KeyedStoreIC, which
417    // can be called here.
418    ReplaceWithBuiltinCall(node, Builtin::kKeyedStoreICTrampoline);
419  } else {
420    node->InsertInput(zone(), 3,
421                      jsgraph()->TaggedIndexConstant(p.feedback().index()));
422    ReplaceWithBuiltinCall(node, Builtin::kKeyedStoreIC);
423  }
424}
425
426void JSGenericLowering::LowerJSDefineKeyedOwnProperty(Node* node) {
427  JSDefineKeyedOwnPropertyNode n(node);
428  const PropertyAccess& p = n.Parameters();
429  FrameState frame_state = n.frame_state();
430  Node* outer_state = frame_state.outer_frame_state();
431  STATIC_ASSERT(n.FeedbackVectorIndex() == 3);
432  if (outer_state->opcode() != IrOpcode::kFrameState) {
433    n->RemoveInput(n.FeedbackVectorIndex());
434    node->InsertInput(zone(), 3,
435                      jsgraph()->TaggedIndexConstant(p.feedback().index()));
436    ReplaceWithBuiltinCall(node, Builtin::kDefineKeyedOwnICTrampoline);
437  } else {
438    node->InsertInput(zone(), 3,
439                      jsgraph()->TaggedIndexConstant(p.feedback().index()));
440    ReplaceWithBuiltinCall(node, Builtin::kDefineKeyedOwnIC);
441  }
442}
443
444void JSGenericLowering::LowerJSSetNamedProperty(Node* node) {
445  JSSetNamedPropertyNode n(node);
446  NamedAccess const& p = n.Parameters();
447  FrameState frame_state = n.frame_state();
448  Node* outer_state = frame_state.outer_frame_state();
449  STATIC_ASSERT(n.FeedbackVectorIndex() == 2);
450  if (!p.feedback().IsValid()) {
451    n->RemoveInput(n.FeedbackVectorIndex());
452    node->InsertInput(zone(), 1, jsgraph()->Constant(p.name(broker())));
453    ReplaceWithRuntimeCall(node, Runtime::kSetNamedProperty);
454  } else if (outer_state->opcode() != IrOpcode::kFrameState) {
455    n->RemoveInput(n.FeedbackVectorIndex());
456    node->InsertInput(zone(), 1, jsgraph()->Constant(p.name(broker())));
457    node->InsertInput(zone(), 3,
458                      jsgraph()->TaggedIndexConstant(p.feedback().index()));
459    // StoreIC is currently a base class for multiple property store operations
460    // and contains mixed logic for named and keyed, set and define operations,
461    // the paths are controlled by feedback.
462    // TODO(v8:12548): refactor SetNamedIC as a subclass of StoreIC, which can
463    // be called here.
464    ReplaceWithBuiltinCall(node, Builtin::kStoreICTrampoline);
465  } else {
466    node->InsertInput(zone(), 1, jsgraph()->Constant(p.name(broker())));
467    node->InsertInput(zone(), 3,
468                      jsgraph()->TaggedIndexConstant(p.feedback().index()));
469    ReplaceWithBuiltinCall(node, Builtin::kStoreIC);
470  }
471}
472
473void JSGenericLowering::LowerJSDefineNamedOwnProperty(Node* node) {
474  CallDescriptor::Flags flags = FrameStateFlagForCall(node);
475  JSDefineNamedOwnPropertyNode n(node);
476  DefineNamedOwnPropertyParameters const& p = n.Parameters();
477  FrameState frame_state = n.frame_state();
478  Node* outer_state = frame_state.outer_frame_state();
479  STATIC_ASSERT(n.FeedbackVectorIndex() == 2);
480  if (outer_state->opcode() != IrOpcode::kFrameState) {
481    n->RemoveInput(n.FeedbackVectorIndex());
482    node->InsertInput(zone(), 1, jsgraph()->Constant(p.name(broker())));
483    node->InsertInput(zone(), 3,
484                      jsgraph()->TaggedIndexConstant(p.feedback().index()));
485    Callable callable = CodeFactory::DefineNamedOwnIC(isolate());
486    ReplaceWithBuiltinCall(node, callable, flags);
487  } else {
488    node->InsertInput(zone(), 1, jsgraph()->Constant(p.name(broker())));
489    node->InsertInput(zone(), 3,
490                      jsgraph()->TaggedIndexConstant(p.feedback().index()));
491    Callable callable = CodeFactory::DefineNamedOwnICInOptimizedCode(isolate());
492    ReplaceWithBuiltinCall(node, callable, flags);
493  }
494}
495
496void JSGenericLowering::LowerJSStoreGlobal(Node* node) {
497  JSStoreGlobalNode n(node);
498  const StoreGlobalParameters& p = n.Parameters();
499  FrameState frame_state = n.frame_state();
500  Node* outer_state = frame_state.outer_frame_state();
501  STATIC_ASSERT(n.FeedbackVectorIndex() == 1);
502  if (outer_state->opcode() != IrOpcode::kFrameState) {
503    n->RemoveInput(n.FeedbackVectorIndex());
504    node->InsertInput(zone(), 0, jsgraph()->Constant(p.name(broker())));
505    node->InsertInput(zone(), 2,
506                      jsgraph()->TaggedIndexConstant(p.feedback().index()));
507    ReplaceWithBuiltinCall(node, Builtin::kStoreGlobalICTrampoline);
508  } else {
509    node->InsertInput(zone(), 0, jsgraph()->Constant(p.name(broker())));
510    node->InsertInput(zone(), 2,
511                      jsgraph()->TaggedIndexConstant(p.feedback().index()));
512    ReplaceWithBuiltinCall(node, Builtin::kStoreGlobalIC);
513  }
514}
515
516void JSGenericLowering::LowerJSDefineKeyedOwnPropertyInLiteral(Node* node) {
517  JSDefineKeyedOwnPropertyInLiteralNode n(node);
518  FeedbackParameter const& p = n.Parameters();
519  STATIC_ASSERT(n.FeedbackVectorIndex() == 4);
520  RelaxControls(node);
521  node->InsertInput(zone(), 5,
522                    jsgraph()->TaggedIndexConstant(p.feedback().index()));
523  ReplaceWithRuntimeCall(node, Runtime::kDefineKeyedOwnPropertyInLiteral);
524}
525
526void JSGenericLowering::LowerJSStoreInArrayLiteral(Node* node) {
527  JSStoreInArrayLiteralNode n(node);
528  FeedbackParameter const& p = n.Parameters();
529  STATIC_ASSERT(n.FeedbackVectorIndex() == 3);
530  RelaxControls(node);
531  node->InsertInput(zone(), 3,
532                    jsgraph()->TaggedIndexConstant(p.feedback().index()));
533  ReplaceWithBuiltinCall(node, Builtin::kStoreInArrayLiteralIC);
534}
535
536void JSGenericLowering::LowerJSDeleteProperty(Node* node) {
537  ReplaceWithBuiltinCall(node, Builtin::kDeleteProperty);
538}
539
540void JSGenericLowering::LowerJSGetSuperConstructor(Node* node) {
541  Node* active_function = NodeProperties::GetValueInput(node, 0);
542  Node* effect = NodeProperties::GetEffectInput(node);
543  Node* control = NodeProperties::GetControlInput(node);
544
545  Node* function_map = effect = graph()->NewNode(
546      jsgraph()->simplified()->LoadField(AccessBuilder::ForMap()),
547      active_function, effect, control);
548
549  RelaxControls(node);
550  node->ReplaceInput(0, function_map);
551  node->ReplaceInput(1, effect);
552  node->ReplaceInput(2, control);
553  node->TrimInputCount(3);
554  NodeProperties::ChangeOp(node, jsgraph()->simplified()->LoadField(
555                                     AccessBuilder::ForMapPrototype()));
556}
557
558void JSGenericLowering::LowerJSHasInPrototypeChain(Node* node) {
559  ReplaceWithRuntimeCall(node, Runtime::kHasInPrototypeChain);
560}
561
562void JSGenericLowering::LowerJSOrdinaryHasInstance(Node* node) {
563  ReplaceWithBuiltinCall(node, Builtin::kOrdinaryHasInstance);
564}
565
566void JSGenericLowering::LowerJSHasContextExtension(Node* node) {
567  UNREACHABLE();  // Eliminated in typed lowering.
568}
569
570void JSGenericLowering::LowerJSLoadContext(Node* node) {
571  UNREACHABLE();  // Eliminated in typed lowering.
572}
573
574
575void JSGenericLowering::LowerJSStoreContext(Node* node) {
576  UNREACHABLE();  // Eliminated in typed lowering.
577}
578
579
580void JSGenericLowering::LowerJSCreate(Node* node) {
581  ReplaceWithBuiltinCall(node, Builtin::kFastNewObject);
582}
583
584
585void JSGenericLowering::LowerJSCreateArguments(Node* node) {
586  CreateArgumentsType const type = CreateArgumentsTypeOf(node->op());
587  switch (type) {
588    case CreateArgumentsType::kMappedArguments:
589      ReplaceWithRuntimeCall(node, Runtime::kNewSloppyArguments);
590      break;
591    case CreateArgumentsType::kUnmappedArguments:
592      ReplaceWithRuntimeCall(node, Runtime::kNewStrictArguments);
593      break;
594    case CreateArgumentsType::kRestParameter:
595      ReplaceWithRuntimeCall(node, Runtime::kNewRestParameter);
596      break;
597  }
598}
599
600
601void JSGenericLowering::LowerJSCreateArray(Node* node) {
602  CreateArrayParameters const& p = CreateArrayParametersOf(node->op());
603  int const arity = static_cast<int>(p.arity());
604  auto interface_descriptor = ArrayConstructorDescriptor{};
605  auto call_descriptor = Linkage::GetStubCallDescriptor(
606      zone(), interface_descriptor, arity + 1, CallDescriptor::kNeedsFrameState,
607      node->op()->properties());
608  // If this fails, we might need to update the parameter reordering code
609  // to ensure that the additional arguments passed via stack are pushed
610  // between top of stack and JS arguments.
611  DCHECK_EQ(interface_descriptor.GetStackParameterCount(), 0);
612  Node* stub_code = jsgraph()->ArrayConstructorStubConstant();
613  Node* stub_arity = jsgraph()->Int32Constant(JSParameterCount(arity));
614  base::Optional<AllocationSiteRef> const site = p.site(broker());
615  Node* type_info = site.has_value() ? jsgraph()->Constant(site.value())
616                                     : jsgraph()->UndefinedConstant();
617  Node* receiver = jsgraph()->UndefinedConstant();
618  node->InsertInput(zone(), 0, stub_code);
619  node->InsertInput(zone(), 3, stub_arity);
620  node->InsertInput(zone(), 4, type_info);
621  node->InsertInput(zone(), 5, receiver);
622  NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
623}
624
625void JSGenericLowering::LowerJSCreateArrayIterator(Node* node) {
626  UNREACHABLE();  // Eliminated in typed lowering.
627}
628
629void JSGenericLowering::LowerJSCreateAsyncFunctionObject(Node* node) {
630  UNREACHABLE();  // Eliminated in typed lowering.
631}
632
633void JSGenericLowering::LowerJSCreateCollectionIterator(Node* node) {
634  UNREACHABLE();  // Eliminated in typed lowering.
635}
636
637void JSGenericLowering::LowerJSCreateBoundFunction(Node* node) {
638  UNREACHABLE();  // Eliminated in typed lowering.
639}
640
641void JSGenericLowering::LowerJSObjectIsArray(Node* node) {
642  UNREACHABLE();  // Eliminated in typed lowering.
643}
644
645void JSGenericLowering::LowerJSCreateObject(Node* node) {
646  ReplaceWithBuiltinCall(node, Builtin::kCreateObjectWithoutProperties);
647}
648
649void JSGenericLowering::LowerJSParseInt(Node* node) {
650  ReplaceWithBuiltinCall(node, Builtin::kParseInt);
651}
652
653void JSGenericLowering::LowerJSRegExpTest(Node* node) {
654  ReplaceWithBuiltinCall(node, Builtin::kRegExpPrototypeTestFast);
655}
656
657void JSGenericLowering::LowerJSCreateClosure(Node* node) {
658  JSCreateClosureNode n(node);
659  CreateClosureParameters const& p = n.Parameters();
660  SharedFunctionInfoRef shared_info = p.shared_info(broker());
661  STATIC_ASSERT(n.FeedbackCellIndex() == 0);
662  node->InsertInput(zone(), 0, jsgraph()->Constant(shared_info));
663  node->RemoveInput(4);  // control
664
665  // Use the FastNewClosure builtin only for functions allocated in new space.
666  if (p.allocation() == AllocationType::kYoung) {
667    ReplaceWithBuiltinCall(node, Builtin::kFastNewClosure);
668  } else {
669    ReplaceWithRuntimeCall(node, Runtime::kNewClosure_Tenured);
670  }
671}
672
673void JSGenericLowering::LowerJSCreateFunctionContext(Node* node) {
674  const CreateFunctionContextParameters& parameters =
675      CreateFunctionContextParametersOf(node->op());
676  ScopeInfoRef scope_info = parameters.scope_info(broker());
677  int slot_count = parameters.slot_count();
678  ScopeType scope_type = parameters.scope_type();
679  CallDescriptor::Flags flags = FrameStateFlagForCall(node);
680
681  if (slot_count <= ConstructorBuiltins::MaximumFunctionContextSlots()) {
682    Callable callable =
683        CodeFactory::FastNewFunctionContext(isolate(), scope_type);
684    node->InsertInput(zone(), 0, jsgraph()->Constant(scope_info));
685    node->InsertInput(zone(), 1, jsgraph()->Int32Constant(slot_count));
686    ReplaceWithBuiltinCall(node, callable, flags);
687  } else {
688    node->InsertInput(zone(), 0, jsgraph()->Constant(scope_info));
689    ReplaceWithRuntimeCall(node, Runtime::kNewFunctionContext);
690  }
691}
692
693void JSGenericLowering::LowerJSCreateGeneratorObject(Node* node) {
694  node->RemoveInput(4);  // control
695  ReplaceWithBuiltinCall(node, Builtin::kCreateGeneratorObject);
696}
697
698void JSGenericLowering::LowerJSCreateIterResultObject(Node* node) {
699  ReplaceWithBuiltinCall(node, Builtin::kCreateIterResultObject);
700}
701
702void JSGenericLowering::LowerJSCreateStringIterator(Node* node) {
703  UNREACHABLE();  // Eliminated in typed lowering.
704}
705
706void JSGenericLowering::LowerJSCreateKeyValueArray(Node* node) {
707  UNREACHABLE();  // Eliminated in typed lowering.
708}
709
710void JSGenericLowering::LowerJSCreatePromise(Node* node) {
711  UNREACHABLE();  // Eliminated in typed lowering.
712}
713
714void JSGenericLowering::LowerJSCreateTypedArray(Node* node) {
715  ReplaceWithBuiltinCall(node, Builtin::kCreateTypedArray);
716}
717
718void JSGenericLowering::LowerJSCreateLiteralArray(Node* node) {
719  JSCreateLiteralArrayNode n(node);
720  CreateLiteralParameters const& p = n.Parameters();
721  STATIC_ASSERT(n.FeedbackVectorIndex() == 0);
722  node->InsertInput(zone(), 1,
723                    jsgraph()->TaggedIndexConstant(p.feedback().index()));
724  node->InsertInput(zone(), 2, jsgraph()->Constant(p.constant(broker())));
725  node->InsertInput(zone(), 3, jsgraph()->SmiConstant(p.flags()));
726
727  // Use the CreateShallowArrayLiteral builtin only for shallow boilerplates
728  // without properties up to the number of elements that the stubs can handle.
729  if ((p.flags() & AggregateLiteral::kIsShallow) != 0 &&
730      p.length() < ConstructorBuiltins::kMaximumClonedShallowArrayElements) {
731    ReplaceWithBuiltinCall(node, Builtin::kCreateShallowArrayLiteral);
732  } else {
733    ReplaceWithRuntimeCall(node, Runtime::kCreateArrayLiteral);
734  }
735}
736
737void JSGenericLowering::LowerJSGetTemplateObject(Node* node) {
738  JSGetTemplateObjectNode n(node);
739  GetTemplateObjectParameters const& p = n.Parameters();
740  SharedFunctionInfoRef shared = p.shared(broker());
741  TemplateObjectDescriptionRef description = p.description(broker());
742
743  DCHECK_EQ(node->op()->ControlInputCount(), 1);
744  node->RemoveInput(NodeProperties::FirstControlIndex(node));
745
746  STATIC_ASSERT(JSGetTemplateObjectNode::FeedbackVectorIndex() == 0);
747  node->InsertInput(zone(), 0, jsgraph()->Constant(shared));
748  node->InsertInput(zone(), 1, jsgraph()->Constant(description));
749  node->InsertInput(zone(), 2,
750                    jsgraph()->UintPtrConstant(p.feedback().index()));
751
752  ReplaceWithBuiltinCall(node, Builtin::kGetTemplateObject);
753}
754
755void JSGenericLowering::LowerJSCreateEmptyLiteralArray(Node* node) {
756  JSCreateEmptyLiteralArrayNode n(node);
757  FeedbackParameter const& p = n.Parameters();
758  STATIC_ASSERT(n.FeedbackVectorIndex() == 0);
759  node->InsertInput(zone(), 1,
760                    jsgraph()->TaggedIndexConstant(p.feedback().index()));
761  node->RemoveInput(4);  // control
762  ReplaceWithBuiltinCall(node, Builtin::kCreateEmptyArrayLiteral);
763}
764
765void JSGenericLowering::LowerJSCreateArrayFromIterable(Node* node) {
766  ReplaceWithBuiltinCall(node, Builtin::kIterableToListWithSymbolLookup);
767}
768
769void JSGenericLowering::LowerJSCreateLiteralObject(Node* node) {
770  JSCreateLiteralObjectNode n(node);
771  CreateLiteralParameters const& p = n.Parameters();
772  STATIC_ASSERT(n.FeedbackVectorIndex() == 0);
773  node->InsertInput(zone(), 1,
774                    jsgraph()->TaggedIndexConstant(p.feedback().index()));
775  node->InsertInput(zone(), 2, jsgraph()->Constant(p.constant(broker())));
776  node->InsertInput(zone(), 3, jsgraph()->SmiConstant(p.flags()));
777
778  // Use the CreateShallowObjectLiteratal builtin only for shallow boilerplates
779  // without elements up to the number of properties that the stubs can handle.
780  if ((p.flags() & AggregateLiteral::kIsShallow) != 0 &&
781      p.length() <=
782          ConstructorBuiltins::kMaximumClonedShallowObjectProperties) {
783    ReplaceWithBuiltinCall(node, Builtin::kCreateShallowObjectLiteral);
784  } else {
785    ReplaceWithRuntimeCall(node, Runtime::kCreateObjectLiteral);
786  }
787}
788
789void JSGenericLowering::LowerJSCloneObject(Node* node) {
790  JSCloneObjectNode n(node);
791  CloneObjectParameters const& p = n.Parameters();
792  STATIC_ASSERT(n.FeedbackVectorIndex() == 1);
793  node->InsertInput(zone(), 1, jsgraph()->SmiConstant(p.flags()));
794  node->InsertInput(zone(), 2,
795                    jsgraph()->TaggedIndexConstant(p.feedback().index()));
796  ReplaceWithBuiltinCall(node, Builtin::kCloneObjectIC);
797}
798
799void JSGenericLowering::LowerJSCreateEmptyLiteralObject(Node* node) {
800  ReplaceWithBuiltinCall(node, Builtin::kCreateEmptyLiteralObject);
801}
802
803void JSGenericLowering::LowerJSCreateLiteralRegExp(Node* node) {
804  JSCreateLiteralRegExpNode n(node);
805  CreateLiteralParameters const& p = n.Parameters();
806  STATIC_ASSERT(n.FeedbackVectorIndex() == 0);
807  node->InsertInput(zone(), 1,
808                    jsgraph()->TaggedIndexConstant(p.feedback().index()));
809  node->InsertInput(zone(), 2, jsgraph()->Constant(p.constant(broker())));
810  node->InsertInput(zone(), 3, jsgraph()->SmiConstant(p.flags()));
811  ReplaceWithBuiltinCall(node, Builtin::kCreateRegExpLiteral);
812}
813
814
815void JSGenericLowering::LowerJSCreateCatchContext(Node* node) {
816  ScopeInfoRef scope_info = ScopeInfoOf(broker(), node->op());
817  node->InsertInput(zone(), 1, jsgraph()->Constant(scope_info));
818  ReplaceWithRuntimeCall(node, Runtime::kPushCatchContext);
819}
820
821void JSGenericLowering::LowerJSCreateWithContext(Node* node) {
822  ScopeInfoRef scope_info = ScopeInfoOf(broker(), node->op());
823  node->InsertInput(zone(), 1, jsgraph()->Constant(scope_info));
824  ReplaceWithRuntimeCall(node, Runtime::kPushWithContext);
825}
826
827void JSGenericLowering::LowerJSCreateBlockContext(Node* node) {
828  ScopeInfoRef scope_info = ScopeInfoOf(broker(), node->op());
829  node->InsertInput(zone(), 0, jsgraph()->Constant(scope_info));
830  ReplaceWithRuntimeCall(node, Runtime::kPushBlockContext);
831}
832
833// TODO(jgruber,v8:8888): Should this collect feedback?
834void JSGenericLowering::LowerJSConstructForwardVarargs(Node* node) {
835  ConstructForwardVarargsParameters p =
836      ConstructForwardVarargsParametersOf(node->op());
837  int const arg_count = static_cast<int>(p.arity() - 2);
838  CallDescriptor::Flags flags = FrameStateFlagForCall(node);
839  Callable callable = CodeFactory::ConstructForwardVarargs(isolate());
840  // If this fails, we might need to update the parameter reordering code
841  // to ensure that the additional arguments passed via stack are pushed
842  // between top of stack and JS arguments.
843  DCHECK_EQ(callable.descriptor().GetStackParameterCount(), 0);
844  auto call_descriptor = Linkage::GetStubCallDescriptor(
845      zone(), callable.descriptor(), arg_count + 1, flags);
846  Node* stub_code = jsgraph()->HeapConstant(callable.code());
847  Node* stub_arity = jsgraph()->Int32Constant(JSParameterCount(arg_count));
848  Node* start_index = jsgraph()->Uint32Constant(p.start_index());
849  Node* receiver = jsgraph()->UndefinedConstant();
850  node->InsertInput(zone(), 0, stub_code);
851  node->InsertInput(zone(), 3, stub_arity);
852  node->InsertInput(zone(), 4, start_index);
853  node->InsertInput(zone(), 5, receiver);
854  NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
855}
856
857void JSGenericLowering::LowerJSConstruct(Node* node) {
858  JSConstructNode n(node);
859  ConstructParameters const& p = n.Parameters();
860  int const arg_count = p.arity_without_implicit_args();
861  CallDescriptor::Flags flags = FrameStateFlagForCall(node);
862
863  static constexpr int kReceiver = 1;
864
865  const int stack_argument_count = arg_count + kReceiver;
866  Callable callable = Builtins::CallableFor(isolate(), Builtin::kConstruct);
867  auto call_descriptor = Linkage::GetStubCallDescriptor(
868      zone(), callable.descriptor(), stack_argument_count, flags);
869  Node* stub_code = jsgraph()->HeapConstant(callable.code());
870  Node* stub_arity = jsgraph()->Int32Constant(JSParameterCount(arg_count));
871  Node* receiver = jsgraph()->UndefinedConstant();
872  node->RemoveInput(n.FeedbackVectorIndex());
873  node->InsertInput(zone(), 0, stub_code);
874  node->InsertInput(zone(), 3, stub_arity);
875  node->InsertInput(zone(), 4, receiver);
876
877  // After: {code, target, new_target, arity, receiver, ...args}.
878
879  NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
880}
881
882void JSGenericLowering::LowerJSConstructWithArrayLike(Node* node) {
883  JSConstructWithArrayLikeNode n(node);
884  ConstructParameters const& p = n.Parameters();
885  CallDescriptor::Flags flags = FrameStateFlagForCall(node);
886  const int arg_count = p.arity_without_implicit_args();
887  DCHECK_EQ(arg_count, 1);
888
889  static constexpr int kReceiver = 1;
890  static constexpr int kArgumentList = 1;
891
892  const int stack_argument_count = arg_count - kArgumentList + kReceiver;
893  Callable callable =
894      Builtins::CallableFor(isolate(), Builtin::kConstructWithArrayLike);
895  // If this fails, we might need to update the parameter reordering code
896  // to ensure that the additional arguments passed via stack are pushed
897  // between top of stack and JS arguments.
898  DCHECK_EQ(callable.descriptor().GetStackParameterCount(), 0);
899  auto call_descriptor = Linkage::GetStubCallDescriptor(
900      zone(), callable.descriptor(), stack_argument_count, flags);
901  Node* stub_code = jsgraph()->HeapConstant(callable.code());
902  Node* receiver = jsgraph()->UndefinedConstant();
903  node->RemoveInput(n.FeedbackVectorIndex());
904  node->InsertInput(zone(), 0, stub_code);
905  node->InsertInput(zone(), 4, receiver);
906
907  // After: {code, target, new_target, arguments_list, receiver}.
908
909  NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
910}
911
912void JSGenericLowering::LowerJSConstructWithSpread(Node* node) {
913  JSConstructWithSpreadNode n(node);
914  ConstructParameters const& p = n.Parameters();
915  int const arg_count = p.arity_without_implicit_args();
916  DCHECK_GE(arg_count, 1);
917  CallDescriptor::Flags flags = FrameStateFlagForCall(node);
918
919  static constexpr int kReceiver = 1;
920  static constexpr int kTheSpread = 1;  // Included in `arg_count`.
921
922  const int stack_argument_count = arg_count + kReceiver - kTheSpread;
923  Callable callable = CodeFactory::ConstructWithSpread(isolate());
924  // If this fails, we might need to update the parameter reordering code
925  // to ensure that the additional arguments passed via stack are pushed
926  // between top of stack and JS arguments.
927  DCHECK_EQ(callable.descriptor().GetStackParameterCount(), 0);
928  auto call_descriptor = Linkage::GetStubCallDescriptor(
929      zone(), callable.descriptor(), stack_argument_count, flags);
930  Node* stub_code = jsgraph()->HeapConstant(callable.code());
931
932  // We pass the spread in a register, not on the stack.
933  Node* stub_arity =
934      jsgraph()->Int32Constant(JSParameterCount(arg_count - kTheSpread));
935  Node* receiver = jsgraph()->UndefinedConstant();
936  DCHECK(n.FeedbackVectorIndex() > n.LastArgumentIndex());
937  node->RemoveInput(n.FeedbackVectorIndex());
938  Node* spread = node->RemoveInput(n.LastArgumentIndex());
939
940  node->InsertInput(zone(), 0, stub_code);
941  node->InsertInput(zone(), 3, stub_arity);
942  node->InsertInput(zone(), 4, spread);
943  node->InsertInput(zone(), 5, receiver);
944
945  // After: {code, target, new_target, arity, spread, receiver, ...args}.
946
947  NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
948}
949
950void JSGenericLowering::LowerJSCallForwardVarargs(Node* node) {
951  CallForwardVarargsParameters p = CallForwardVarargsParametersOf(node->op());
952  int const arg_count = static_cast<int>(p.arity() - 2);
953  CallDescriptor::Flags flags = FrameStateFlagForCall(node);
954  Callable callable = CodeFactory::CallForwardVarargs(isolate());
955  auto call_descriptor = Linkage::GetStubCallDescriptor(
956      zone(), callable.descriptor(), arg_count + 1, flags);
957  Node* stub_code = jsgraph()->HeapConstant(callable.code());
958  Node* stub_arity = jsgraph()->Int32Constant(JSParameterCount(arg_count));
959  Node* start_index = jsgraph()->Uint32Constant(p.start_index());
960  node->InsertInput(zone(), 0, stub_code);
961  node->InsertInput(zone(), 2, stub_arity);
962  node->InsertInput(zone(), 3, start_index);
963  NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
964}
965
966void JSGenericLowering::LowerJSCall(Node* node) {
967  JSCallNode n(node);
968  CallParameters const& p = n.Parameters();
969  int const arg_count = p.arity_without_implicit_args();
970  ConvertReceiverMode const mode = p.convert_mode();
971
972  node->RemoveInput(n.FeedbackVectorIndex());
973
974  Callable callable = CodeFactory::Call(isolate(), mode);
975  CallDescriptor::Flags flags = FrameStateFlagForCall(node);
976  auto call_descriptor = Linkage::GetStubCallDescriptor(
977      zone(), callable.descriptor(), arg_count + 1, flags);
978  Node* stub_code = jsgraph()->HeapConstant(callable.code());
979  Node* stub_arity = jsgraph()->Int32Constant(JSParameterCount(arg_count));
980  node->InsertInput(zone(), 0, stub_code);
981  node->InsertInput(zone(), 2, stub_arity);
982  NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
983}
984
985void JSGenericLowering::LowerJSCallWithArrayLike(Node* node) {
986  JSCallWithArrayLikeNode n(node);
987  CallParameters const& p = n.Parameters();
988  const int arg_count = p.arity_without_implicit_args();
989  DCHECK_EQ(arg_count, 1);  // The arraylike object.
990  CallDescriptor::Flags flags = FrameStateFlagForCall(node);
991
992  static constexpr int kArgumentsList = 1;
993  static constexpr int kReceiver = 1;
994
995  const int stack_argument_count = arg_count - kArgumentsList + kReceiver;
996  Callable callable = CodeFactory::CallWithArrayLike(isolate());
997  auto call_descriptor = Linkage::GetStubCallDescriptor(
998      zone(), callable.descriptor(), stack_argument_count, flags);
999  Node* stub_code = jsgraph()->HeapConstant(callable.code());
1000  Node* receiver = n.receiver();
1001  Node* arguments_list = n.Argument(0);
1002
1003  // Shuffling inputs.
1004  // Before: {target, receiver, arguments_list, vector}.
1005
1006  node->RemoveInput(n.FeedbackVectorIndex());
1007  node->InsertInput(zone(), 0, stub_code);
1008  node->ReplaceInput(2, arguments_list);
1009  node->ReplaceInput(3, receiver);
1010
1011  // After: {code, target, arguments_list, receiver}.
1012
1013  NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
1014}
1015
1016void JSGenericLowering::LowerJSCallWithSpread(Node* node) {
1017  JSCallWithSpreadNode n(node);
1018  CallParameters const& p = n.Parameters();
1019  int const arg_count = p.arity_without_implicit_args();
1020  DCHECK_GE(arg_count, 1);  // At least the spread.
1021  CallDescriptor::Flags flags = FrameStateFlagForCall(node);
1022
1023  static constexpr int kReceiver = 1;
1024  static constexpr int kTheSpread = 1;
1025
1026  const int stack_argument_count = arg_count - kTheSpread + kReceiver;
1027  Callable callable = CodeFactory::CallWithSpread(isolate());
1028  // If this fails, we might need to update the parameter reordering code
1029  // to ensure that the additional arguments passed via stack are pushed
1030  // between top of stack and JS arguments.
1031  DCHECK_EQ(callable.descriptor().GetStackParameterCount(), 0);
1032  auto call_descriptor = Linkage::GetStubCallDescriptor(
1033      zone(), callable.descriptor(), stack_argument_count, flags);
1034  Node* stub_code = jsgraph()->HeapConstant(callable.code());
1035
1036  // We pass the spread in a register, not on the stack.
1037  Node* stub_arity =
1038      jsgraph()->Int32Constant(JSParameterCount(arg_count - kTheSpread));
1039
1040  // Shuffling inputs.
1041  // Before: {target, receiver, ...args, spread, vector}.
1042
1043  node->RemoveInput(n.FeedbackVectorIndex());
1044  Node* spread = node->RemoveInput(n.LastArgumentIndex());
1045
1046  node->InsertInput(zone(), 0, stub_code);
1047  node->InsertInput(zone(), 2, stub_arity);
1048  node->InsertInput(zone(), 3, spread);
1049
1050  // After: {code, target, arity, spread, receiver, ...args}.
1051
1052  NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
1053}
1054
1055void JSGenericLowering::LowerJSCallRuntime(Node* node) {
1056  const CallRuntimeParameters& p = CallRuntimeParametersOf(node->op());
1057  ReplaceWithRuntimeCall(node, p.id(), static_cast<int>(p.arity()));
1058}
1059
1060#if V8_ENABLE_WEBASSEMBLY
1061// Will be lowered in SimplifiedLowering.
1062void JSGenericLowering::LowerJSWasmCall(Node* node) {}
1063#endif  // V8_ENABLE_WEBASSEMBLY
1064
1065void JSGenericLowering::LowerJSForInPrepare(Node* node) {
1066  JSForInPrepareNode n(node);
1067  Effect effect(node);            // {node} is kept in the effect chain.
1068  Control control = n.control();  // .. but not in the control chain.
1069  Node* enumerator = n.enumerator();
1070  Node* slot =
1071      jsgraph()->UintPtrConstant(n.Parameters().feedback().slot.ToInt());
1072
1073  std::vector<Edge> use_edges;
1074  for (Edge edge : node->use_edges()) use_edges.push_back(edge);
1075
1076  // {node} will be changed to a builtin call (see below). The returned value
1077  // is a fixed array containing {cache_array} and {cache_length}.
1078  // TODO(jgruber): This is awkward; what we really want is two return values,
1079  // the {cache_array} and {cache_length}, or better yet three return values
1080  // s.t. we can avoid the graph rewrites below. Builtin support for multiple
1081  // return types is unclear though.
1082
1083  Node* result_fixed_array = node;
1084  Node* cache_type = enumerator;  // Just to clarify the rename.
1085  Node* cache_array;
1086  Node* cache_length;
1087
1088  cache_array = effect = graph()->NewNode(
1089      machine()->Load(MachineType::AnyTagged()), result_fixed_array,
1090      jsgraph()->IntPtrConstant(FixedArray::OffsetOfElementAt(0) -
1091                                kHeapObjectTag),
1092      effect, control);
1093  cache_length = effect = graph()->NewNode(
1094      machine()->Load(MachineType::AnyTagged()), result_fixed_array,
1095      jsgraph()->IntPtrConstant(FixedArray::OffsetOfElementAt(1) -
1096                                kHeapObjectTag),
1097      effect, control);
1098
1099  // Update the uses of {node}.
1100  for (Edge edge : use_edges) {
1101    Node* const user = edge.from();
1102    if (NodeProperties::IsEffectEdge(edge)) {
1103      edge.UpdateTo(effect);
1104    } else if (NodeProperties::IsControlEdge(edge)) {
1105      edge.UpdateTo(control);
1106    } else {
1107      DCHECK(NodeProperties::IsValueEdge(edge));
1108      switch (ProjectionIndexOf(user->op())) {
1109        case 0:
1110          Replace(user, cache_type);
1111          break;
1112        case 1:
1113          Replace(user, cache_array);
1114          break;
1115        case 2:
1116          Replace(user, cache_length);
1117          break;
1118        default:
1119          UNREACHABLE();
1120      }
1121    }
1122  }
1123
1124  // Finally, change the original node into a builtin call. This happens here,
1125  // after graph rewrites, since the Call does not have a control output and
1126  // thus must not have any control uses. Any previously existing control
1127  // outputs have been replaced by the graph rewrite above.
1128  node->InsertInput(zone(), n.FeedbackVectorIndex(), slot);
1129  ReplaceWithBuiltinCall(node, Builtin::kForInPrepare);
1130}
1131
1132void JSGenericLowering::LowerJSForInNext(Node* node) {
1133  JSForInNextNode n(node);
1134  node->InsertInput(
1135      zone(), 0,
1136      jsgraph()->UintPtrConstant(n.Parameters().feedback().slot.ToInt()));
1137  ReplaceWithBuiltinCall(node, Builtin::kForInNext);
1138}
1139
1140void JSGenericLowering::LowerJSLoadMessage(Node* node) {
1141  UNREACHABLE();  // Eliminated in typed lowering.
1142}
1143
1144
1145void JSGenericLowering::LowerJSStoreMessage(Node* node) {
1146  UNREACHABLE();  // Eliminated in typed lowering.
1147}
1148
1149void JSGenericLowering::LowerJSLoadModule(Node* node) {
1150  UNREACHABLE();  // Eliminated in typed lowering.
1151}
1152
1153void JSGenericLowering::LowerJSStoreModule(Node* node) {
1154  UNREACHABLE();  // Eliminated in typed lowering.
1155}
1156
1157void JSGenericLowering::LowerJSGetImportMeta(Node* node) {
1158  ReplaceWithRuntimeCall(node, Runtime::kGetImportMetaObject);
1159}
1160
1161void JSGenericLowering::LowerJSGeneratorStore(Node* node) {
1162  UNREACHABLE();  // Eliminated in typed lowering.
1163}
1164
1165void JSGenericLowering::LowerJSGeneratorRestoreContinuation(Node* node) {
1166  UNREACHABLE();  // Eliminated in typed lowering.
1167}
1168
1169void JSGenericLowering::LowerJSGeneratorRestoreContext(Node* node) {
1170  UNREACHABLE();  // Eliminated in typed lowering.
1171}
1172
1173void JSGenericLowering::LowerJSGeneratorRestoreInputOrDebugPos(Node* node) {
1174  UNREACHABLE();  // Eliminated in typed lowering.
1175}
1176
1177void JSGenericLowering::LowerJSGeneratorRestoreRegister(Node* node) {
1178  UNREACHABLE();  // Eliminated in typed lowering.
1179}
1180
1181namespace {
1182
1183StackCheckKind StackCheckKindOfJSStackCheck(const Operator* op) {
1184  DCHECK(op->opcode() == IrOpcode::kJSStackCheck);
1185  return OpParameter<StackCheckKind>(op);
1186}
1187
1188}  // namespace
1189
1190void JSGenericLowering::LowerJSStackCheck(Node* node) {
1191  Node* effect = NodeProperties::GetEffectInput(node);
1192  Node* control = NodeProperties::GetControlInput(node);
1193
1194  Node* limit = effect =
1195      graph()->NewNode(machine()->Load(MachineType::Pointer()),
1196                       jsgraph()->ExternalConstant(
1197                           ExternalReference::address_of_jslimit(isolate())),
1198                       jsgraph()->IntPtrConstant(0), effect, control);
1199
1200  StackCheckKind stack_check_kind = StackCheckKindOfJSStackCheck(node->op());
1201  Node* check = effect = graph()->NewNode(
1202      machine()->StackPointerGreaterThan(stack_check_kind), limit, effect);
1203  Node* branch =
1204      graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
1205
1206  Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
1207  Node* etrue = effect;
1208
1209  Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
1210  NodeProperties::ReplaceControlInput(node, if_false);
1211  NodeProperties::ReplaceEffectInput(node, effect);
1212  Node* efalse = if_false = node;
1213
1214  Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
1215  Node* ephi = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, merge);
1216
1217  // Wire the new diamond into the graph, {node} can still throw.
1218  NodeProperties::ReplaceUses(node, node, ephi, merge, merge);
1219  NodeProperties::ReplaceControlInput(merge, if_false, 1);
1220  NodeProperties::ReplaceEffectInput(ephi, efalse, 1);
1221
1222  // This iteration cuts out potential {IfSuccess} or {IfException} projection
1223  // uses of the original node and places them inside the diamond, so that we
1224  // can change the original {node} into the slow-path runtime call.
1225  for (Edge edge : merge->use_edges()) {
1226    if (!NodeProperties::IsControlEdge(edge)) continue;
1227    if (edge.from()->opcode() == IrOpcode::kIfSuccess) {
1228      NodeProperties::ReplaceUses(edge.from(), nullptr, nullptr, merge);
1229      NodeProperties::ReplaceControlInput(merge, edge.from(), 1);
1230      edge.UpdateTo(node);
1231    }
1232    if (edge.from()->opcode() == IrOpcode::kIfException) {
1233      NodeProperties::ReplaceEffectInput(edge.from(), node);
1234      edge.UpdateTo(node);
1235    }
1236  }
1237
1238  // Turn the stack check into a runtime call. At function entry, the runtime
1239  // function takes an offset argument which is subtracted from the stack
1240  // pointer prior to the stack check (i.e. the check is `sp - offset >=
1241  // limit`).
1242  if (stack_check_kind == StackCheckKind::kJSFunctionEntry) {
1243    node->InsertInput(zone(), 0,
1244                      graph()->NewNode(machine()->LoadStackCheckOffset()));
1245    ReplaceWithRuntimeCall(node, Runtime::kStackGuardWithGap);
1246  } else {
1247    ReplaceWithRuntimeCall(node, Runtime::kStackGuard);
1248  }
1249}
1250
1251void JSGenericLowering::LowerJSDebugger(Node* node) {
1252  ReplaceWithRuntimeCall(node, Runtime::kHandleDebuggerStatement);
1253}
1254
1255Zone* JSGenericLowering::zone() const { return graph()->zone(); }
1256
1257
1258Isolate* JSGenericLowering::isolate() const { return jsgraph()->isolate(); }
1259
1260
1261Graph* JSGenericLowering::graph() const { return jsgraph()->graph(); }
1262
1263
1264CommonOperatorBuilder* JSGenericLowering::common() const {
1265  return jsgraph()->common();
1266}
1267
1268
1269MachineOperatorBuilder* JSGenericLowering::machine() const {
1270  return jsgraph()->machine();
1271}
1272
1273}  // namespace compiler
1274}  // namespace internal
1275}  // namespace v8
1276