js-generic-lowering.cc 60.2 KB
Newer Older
1 2 3 4
// Copyright 2014 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

5 6 7
#include "src/compiler/js-generic-lowering.h"

#include "src/ast/ast.h"
8
#include "src/builtins/builtins-constructor.h"
9
#include "src/codegen/code-factory.h"
10
#include "src/compiler/access-builder.h"
11
#include "src/compiler/common-operator.h"
12
#include "src/compiler/js-graph.h"
13
#include "src/compiler/js-heap-broker.h"
14
#include "src/compiler/machine-operator.h"
15
#include "src/compiler/node-matchers.h"
16 17
#include "src/compiler/node-properties.h"
#include "src/compiler/operator-properties.h"
18
#include "src/compiler/processed-feedback.h"
19
#include "src/compiler/simplified-operator.h"
20
#include "src/objects/feedback-cell.h"
21
#include "src/objects/feedback-vector.h"
22
#include "src/objects/scope-info.h"
23
#include "src/objects/template-objects-inl.h"
24 25 26 27 28

namespace v8 {
namespace internal {
namespace compiler {

29 30 31 32 33 34
namespace {

CallDescriptor::Flags FrameStateFlagForCall(Node* node) {
  return OperatorProperties::HasFrameStateInput(node->op())
             ? CallDescriptor::kNeedsFrameState
             : CallDescriptor::kNoFlags;
35 36
}

37 38
}  // namespace

39 40 41
JSGenericLowering::JSGenericLowering(JSGraph* jsgraph, Editor* editor,
                                     JSHeapBroker* broker)
    : AdvancedReducer(editor), jsgraph_(jsgraph), broker_(broker) {}
42

43
JSGenericLowering::~JSGenericLowering() = default;
44 45


46
Reduction JSGenericLowering::Reduce(Node* node) {
47
  switch (node->opcode()) {
48 49 50 51
#define DECLARE_CASE(x, ...) \
  case IrOpcode::k##x:       \
    Lower##x(node);          \
    break;
52 53 54 55
    JS_OP_LIST(DECLARE_CASE)
#undef DECLARE_CASE
    default:
      // Nothing to see.
56
      return NoChange();
57
  }
58
  return Changed(node);
59 60
}

61 62 63
#define REPLACE_STUB_CALL(Name)                       \
  void JSGenericLowering::LowerJS##Name(Node* node) { \
    ReplaceWithBuiltinCall(node, Builtins::k##Name);  \
64
  }
65 66
REPLACE_STUB_CALL(ToLength)
REPLACE_STUB_CALL(ToNumber)
67
REPLACE_STUB_CALL(ToNumberConvertBigInt)
68
REPLACE_STUB_CALL(ToNumeric)
69 70 71
REPLACE_STUB_CALL(ToName)
REPLACE_STUB_CALL(ToObject)
REPLACE_STUB_CALL(ToString)
72
REPLACE_STUB_CALL(ForInEnumerate)
73 74 75
REPLACE_STUB_CALL(AsyncFunctionEnter)
REPLACE_STUB_CALL(AsyncFunctionReject)
REPLACE_STUB_CALL(AsyncFunctionResolve)
76
REPLACE_STUB_CALL(FulfillPromise)
77
REPLACE_STUB_CALL(PerformPromiseThen)
78
REPLACE_STUB_CALL(PromiseResolve)
79 80
REPLACE_STUB_CALL(RejectPromise)
REPLACE_STUB_CALL(ResolvePromise)
81 82
#undef REPLACE_STUB_CALL

83 84 85 86 87 88 89 90 91 92
void JSGenericLowering::ReplaceWithBuiltinCall(Node* node,
                                               Builtins::Name builtin) {
  CallDescriptor::Flags flags = FrameStateFlagForCall(node);
  Callable callable = Builtins::CallableFor(isolate(), builtin);
  ReplaceWithBuiltinCall(node, callable, flags);
}

void JSGenericLowering::ReplaceWithBuiltinCall(Node* node, Callable callable,
                                               CallDescriptor::Flags flags) {
  ReplaceWithBuiltinCall(node, callable, flags, node->op()->properties());
93 94
}

95 96 97
void JSGenericLowering::ReplaceWithBuiltinCall(
    Node* node, Callable callable, CallDescriptor::Flags flags,
    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 107 108 109
}

void JSGenericLowering::ReplaceWithRuntimeCall(Node* node,
                                               Runtime::FunctionId f,
                                               int nargs_override) {
110
  CallDescriptor::Flags flags = FrameStateFlagForCall(node);
111
  Operator::Properties properties = node->op()->properties();
112 113
  const Runtime::Function* fun = Runtime::FunctionForId(f);
  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 119 120
  node->InsertInput(zone(), 0, jsgraph()->CEntryStubConstant(fun->result_size));
  node->InsertInput(zone(), nargs + 1, ref);
  node->InsertInput(zone(), nargs + 2, arity);
121
  NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
122 123
}

124 125 126
void JSGenericLowering::ReplaceUnaryOpWithBuiltinCall(
    Node* node, Builtins::Name builtin_without_feedback,
    Builtins::Name builtin_with_feedback) {
127
  DCHECK(JSOperator::IsUnaryWithFeedback(node->opcode()));
128 129 130
  const FeedbackParameter& p = FeedbackParameterOf(node->op());
  if (CollectFeedbackInGenericLowering() && p.feedback().IsValid()) {
    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 135 136 137
    auto call_descriptor = Linkage::GetStubCallDescriptor(
        zone(), descriptor, descriptor.GetStackParameterCount(), flags,
        node->op()->properties());
    Node* stub_code = jsgraph()->HeapConstant(callable.code());
138 139 140
    STATIC_ASSERT(JSUnaryOpNode::ValueIndex() == 0);
    STATIC_ASSERT(JSUnaryOpNode::FeedbackVectorIndex() == 1);
    DCHECK_EQ(node->op()->ValueInputCount(), 2);
141 142 143 144
    node->InsertInput(zone(), 0, stub_code);
    node->InsertInput(zone(), 2, slot);
    NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
  } else {
145
    node->RemoveInput(JSUnaryOpNode::FeedbackVectorIndex());
146
    ReplaceWithBuiltinCall(node, builtin_without_feedback);
147 148 149 150 151 152 153 154 155 156 157 158 159 160
  }
}

#define DEF_UNARY_LOWERING(Name)                                     \
  void JSGenericLowering::LowerJS##Name(Node* node) {                \
    ReplaceUnaryOpWithBuiltinCall(node, Builtins::k##Name,           \
                                  Builtins::k##Name##_WithFeedback); \
  }
DEF_UNARY_LOWERING(BitwiseNot)
DEF_UNARY_LOWERING(Decrement)
DEF_UNARY_LOWERING(Increment)
DEF_UNARY_LOWERING(Negate)
#undef DEF_UNARY_LOWERING

161
void JSGenericLowering::ReplaceBinaryOpWithBuiltinCall(
162 163
    Node* node, Builtins::Name builtin_without_feedback,
    Builtins::Name builtin_with_feedback) {
164
  DCHECK(JSOperator::IsBinaryWithFeedback(node->opcode()));
165 166 167 168
  Builtins::Name builtin_id;
  const FeedbackParameter& p = FeedbackParameterOf(node->op());
  if (CollectFeedbackInGenericLowering() && p.feedback().IsValid()) {
    Node* slot = jsgraph()->UintPtrConstant(p.feedback().slot.ToInt());
169 170 171 172
    STATIC_ASSERT(JSBinaryOpNode::LeftIndex() == 0);
    STATIC_ASSERT(JSBinaryOpNode::RightIndex() == 1);
    STATIC_ASSERT(JSBinaryOpNode::FeedbackVectorIndex() == 2);
    DCHECK_EQ(node->op()->ValueInputCount(), 3);
173 174 175
    node->InsertInput(zone(), 2, slot);
    builtin_id = builtin_with_feedback;
  } else {
176
    node->RemoveInput(JSBinaryOpNode::FeedbackVectorIndex());
177 178 179
    builtin_id = builtin_without_feedback;
  }

180
  ReplaceWithBuiltinCall(node, builtin_id);
181 182
}

183 184 185 186
#define DEF_BINARY_LOWERING(Name)                                     \
  void JSGenericLowering::LowerJS##Name(Node* node) {                 \
    ReplaceBinaryOpWithBuiltinCall(node, Builtins::k##Name,           \
                                   Builtins::k##Name##_WithFeedback); \
187
  }
188
// Binary ops.
189 190 191 192 193 194 195 196 197 198 199 200
DEF_BINARY_LOWERING(Add)
DEF_BINARY_LOWERING(BitwiseAnd)
DEF_BINARY_LOWERING(BitwiseOr)
DEF_BINARY_LOWERING(BitwiseXor)
DEF_BINARY_LOWERING(Divide)
DEF_BINARY_LOWERING(Exponentiate)
DEF_BINARY_LOWERING(Modulus)
DEF_BINARY_LOWERING(Multiply)
DEF_BINARY_LOWERING(ShiftLeft)
DEF_BINARY_LOWERING(ShiftRight)
DEF_BINARY_LOWERING(ShiftRightLogical)
DEF_BINARY_LOWERING(Subtract)
201
// Compare ops.
202 203 204
DEF_BINARY_LOWERING(Equal)
DEF_BINARY_LOWERING(GreaterThan)
DEF_BINARY_LOWERING(GreaterThanOrEqual)
205
DEF_BINARY_LOWERING(InstanceOf)
206 207 208
DEF_BINARY_LOWERING(LessThan)
DEF_BINARY_LOWERING(LessThanOrEqual)
#undef DEF_BINARY_LOWERING
209 210 211 212

void JSGenericLowering::LowerJSStrictEqual(Node* node) {
  // The === operator doesn't need the current context.
  NodeProperties::ReplaceContextInput(node, jsgraph()->NoContextConstant());
213
  DCHECK_EQ(node->op()->ControlInputCount(), 1);
214
  node->RemoveInput(NodeProperties::FirstControlIndex(node));
215 216 217 218 219

  Builtins::Name builtin_id;
  const FeedbackParameter& p = FeedbackParameterOf(node->op());
  if (CollectFeedbackInGenericLowering() && p.feedback().IsValid()) {
    Node* slot = jsgraph()->UintPtrConstant(p.feedback().slot.ToInt());
220 221 222 223
    STATIC_ASSERT(JSStrictEqualNode::LeftIndex() == 0);
    STATIC_ASSERT(JSStrictEqualNode::RightIndex() == 1);
    STATIC_ASSERT(JSStrictEqualNode::FeedbackVectorIndex() == 2);
    DCHECK_EQ(node->op()->ValueInputCount(), 3);
224 225 226
    node->InsertInput(zone(), 2, slot);
    builtin_id = Builtins::kStrictEqual_WithFeedback;
  } else {
227
    node->RemoveInput(JSStrictEqualNode::FeedbackVectorIndex());
228 229 230 231
    builtin_id = Builtins::kStrictEqual;
  }

  Callable callable = Builtins::CallableFor(isolate(), builtin_id);
232 233
  ReplaceWithBuiltinCall(node, callable, CallDescriptor::kNoFlags,
                         Operator::kEliminatable);
234 235
}

236
namespace {
237 238 239 240

// The megamorphic load builtin can be used as a performance optimization in
// some cases - unlike the full builtin, the megamorphic builtin does fewer
// checks and does not collect feedback.
241
bool ShouldUseMegamorphicLoadBuiltin(FeedbackSource const& source,
242
                                     JSHeapBroker* broker) {
243 244 245 246 247 248 249
  if (broker->is_native_context_independent()) {
    // The decision to use the megamorphic load builtin is made based on
    // current feedback, and is thus context-dependent. It cannot be used when
    // generating NCI code.
    return false;
  }

250
  ProcessedFeedback const& feedback = broker->GetFeedback(source);
251 252

  if (feedback.kind() == ProcessedFeedback::kElementAccess) {
253
    return feedback.AsElementAccess().transition_groups().empty();
254
  } else if (feedback.kind() == ProcessedFeedback::kNamedAccess) {
255
    return feedback.AsNamedAccess().maps().empty();
256 257 258 259 260 261 262
  } else if (feedback.kind() == ProcessedFeedback::kInsufficient) {
    return false;
  }
  UNREACHABLE();
}
}  // namespace

263
void JSGenericLowering::LowerJSHasProperty(Node* node) {
264 265 266 267 268 269 270 271 272 273 274
  JSHasPropertyNode n(node);
  const PropertyAccess& p = n.Parameters();
  if (!p.feedback().IsValid()) {
    node->RemoveInput(JSHasPropertyNode::FeedbackVectorIndex());
    ReplaceWithBuiltinCall(node, Builtins::kHasProperty);
  } else {
    STATIC_ASSERT(n.FeedbackVectorIndex() == 2);
    n->InsertInput(zone(), 2,
                   jsgraph()->TaggedIndexConstant(p.feedback().index()));
    ReplaceWithBuiltinCall(node, Builtins::kKeyedHasIC);
  }
275 276
}

277
void JSGenericLowering::LowerJSLoadProperty(Node* node) {
278 279 280 281 282
  JSLoadPropertyNode n(node);
  const PropertyAccess& p = n.Parameters();
  FrameState frame_state = n.frame_state();
  FrameState outer_state = frame_state.outer_frame_state();
  STATIC_ASSERT(n.FeedbackVectorIndex() == 2);
283
  if (outer_state->opcode() != IrOpcode::kFrameState) {
284 285 286
    n->RemoveInput(n.FeedbackVectorIndex());
    n->InsertInput(zone(), 2,
                   jsgraph()->TaggedIndexConstant(p.feedback().index()));
287 288 289 290
    ReplaceWithBuiltinCall(
        node, ShouldUseMegamorphicLoadBuiltin(p.feedback(), broker())
                  ? Builtins::kKeyedLoadICTrampoline_Megamorphic
                  : Builtins::kKeyedLoadICTrampoline);
291
  } else {
292 293
    n->InsertInput(zone(), 2,
                   jsgraph()->TaggedIndexConstant(p.feedback().index()));
294 295 296 297
    ReplaceWithBuiltinCall(
        node, ShouldUseMegamorphicLoadBuiltin(p.feedback(), broker())
                  ? Builtins::kKeyedLoadIC_Megamorphic
                  : Builtins::kKeyedLoadIC);
298
  }
299 300
}

301
void JSGenericLowering::LowerJSLoadNamed(Node* node) {
302 303 304 305 306
  JSLoadNamedNode n(node);
  NamedAccess const& p = n.Parameters();
  FrameState frame_state = n.frame_state();
  FrameState outer_state = frame_state.outer_frame_state();
  STATIC_ASSERT(n.FeedbackVectorIndex() == 1);
307
  if (!p.feedback().IsValid()) {
308 309
    n->RemoveInput(n.FeedbackVectorIndex());
    node->InsertInput(zone(), 1, jsgraph()->HeapConstant(p.name()));
310
    ReplaceWithBuiltinCall(node, Builtins::kGetProperty);
311 312 313 314 315
  } else if (outer_state->opcode() != IrOpcode::kFrameState) {
    n->RemoveInput(n.FeedbackVectorIndex());
    node->InsertInput(zone(), 1, jsgraph()->HeapConstant(p.name()));
    node->InsertInput(zone(), 2,
                      jsgraph()->TaggedIndexConstant(p.feedback().index()));
316 317 318 319
    ReplaceWithBuiltinCall(
        node, ShouldUseMegamorphicLoadBuiltin(p.feedback(), broker())
                  ? Builtins::kLoadICTrampoline_Megamorphic
                  : Builtins::kLoadICTrampoline);
320
  } else {
321 322 323
    node->InsertInput(zone(), 1, jsgraph()->HeapConstant(p.name()));
    node->InsertInput(zone(), 2,
                      jsgraph()->TaggedIndexConstant(p.feedback().index()));
324 325 326 327
    ReplaceWithBuiltinCall(
        node, ShouldUseMegamorphicLoadBuiltin(p.feedback(), broker())
                  ? Builtins::kLoadIC_Megamorphic
                  : Builtins::kLoadIC);
328
  }
329 330
}

331 332 333
void JSGenericLowering::LowerJSLoadNamedFromSuper(Node* node) {
  JSLoadNamedFromSuperNode n(node);
  NamedAccess const& p = n.Parameters();
334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351
  Node* effect = NodeProperties::GetEffectInput(node);
  Node* control = NodeProperties::GetControlInput(node);
  // Node inputs: receiver, home object, FeedbackVector.
  // LoadSuperIC expects: receiver, lookup start object, name, slot,
  // FeedbackVector.
  Node* home_object_map = effect = graph()->NewNode(
      jsgraph()->simplified()->LoadField(AccessBuilder::ForMap()),
      n.home_object(), effect, control);
  Node* home_object_proto = effect = graph()->NewNode(
      jsgraph()->simplified()->LoadField(AccessBuilder::ForMapPrototype()),
      home_object_map, effect, control);
  n->ReplaceInput(n.HomeObjectIndex(), home_object_proto);
  NodeProperties::ReplaceEffectInput(node, effect);
  STATIC_ASSERT(n.FeedbackVectorIndex() == 2);
  // If the code below will be used for the invalid feedback case, it needs to
  // be double-checked that the FeedbackVector parameter will be the
  // UndefinedConstant.
  DCHECK(p.feedback().IsValid());
352
  node->InsertInput(zone(), 2, jsgraph()->HeapConstant(p.name()));
353 354 355
  node->InsertInput(zone(), 3,
                    jsgraph()->TaggedIndexConstant(p.feedback().index()));
  ReplaceWithBuiltinCall(node, Builtins::kLoadSuperIC);
356 357
}

358
void JSGenericLowering::LowerJSLoadGlobal(Node* node) {
359 360
  JSLoadGlobalNode n(node);
  const LoadGlobalParameters& p = n.Parameters();
361
  CallDescriptor::Flags flags = FrameStateFlagForCall(node);
362 363 364
  FrameState frame_state = n.frame_state();
  FrameState outer_state = frame_state.outer_frame_state();
  STATIC_ASSERT(n.FeedbackVectorIndex() == 0);
365
  if (outer_state->opcode() != IrOpcode::kFrameState) {
366 367 368 369
    n->RemoveInput(n.FeedbackVectorIndex());
    node->InsertInput(zone(), 0, jsgraph()->HeapConstant(p.name()));
    node->InsertInput(zone(), 1,
                      jsgraph()->TaggedIndexConstant(p.feedback().index()));
370
    Callable callable = CodeFactory::LoadGlobalIC(isolate(), p.typeof_mode());
371
    ReplaceWithBuiltinCall(node, callable, flags);
372
  } else {
373 374 375
    node->InsertInput(zone(), 0, jsgraph()->HeapConstant(p.name()));
    node->InsertInput(zone(), 1,
                      jsgraph()->TaggedIndexConstant(p.feedback().index()));
376 377
    Callable callable =
        CodeFactory::LoadGlobalICInOptimizedCode(isolate(), p.typeof_mode());
378
    ReplaceWithBuiltinCall(node, callable, flags);
379
  }
380 381
}

382
void JSGenericLowering::LowerJSGetIterator(Node* node) {
383 384
  // TODO(v8:9625): Currently, the GetIterator operator is desugared in the
  // native context specialization phase. Thus, the following generic lowering
385 386 387 388 389 390 391 392
  // is not reachable unless that phase is disabled (e.g. for
  // native-context-independent code).
  // We can add a check in native context specialization to avoid desugaring
  // the GetIterator operator when feedback is megamorphic. This would reduce
  // the size of the compiled code as it would insert 1 call to the builtin
  // instead of 2 calls resulting from the generic lowering of the LoadNamed
  // and Call operators.

393 394
  JSGetIteratorNode n(node);
  GetIteratorParameters const& p = n.Parameters();
395 396 397 398
  Node* load_slot =
      jsgraph()->TaggedIndexConstant(p.loadFeedback().slot.ToInt());
  Node* call_slot =
      jsgraph()->TaggedIndexConstant(p.callFeedback().slot.ToInt());
399
  STATIC_ASSERT(n.FeedbackVectorIndex() == 1);
400 401 402
  node->InsertInput(zone(), 1, load_slot);
  node->InsertInput(zone(), 2, call_slot);

403
  ReplaceWithBuiltinCall(node, Builtins::kGetIteratorWithFeedback);
404 405
}

406
void JSGenericLowering::LowerJSStoreProperty(Node* node) {
407 408 409 410 411
  JSStorePropertyNode n(node);
  const PropertyAccess& p = n.Parameters();
  FrameState frame_state = n.frame_state();
  FrameState outer_state = frame_state.outer_frame_state();
  STATIC_ASSERT(n.FeedbackVectorIndex() == 3);
412
  if (outer_state->opcode() != IrOpcode::kFrameState) {
413 414 415
    n->RemoveInput(n.FeedbackVectorIndex());
    node->InsertInput(zone(), 3,
                      jsgraph()->TaggedIndexConstant(p.feedback().index()));
416
    ReplaceWithBuiltinCall(node, Builtins::kKeyedStoreICTrampoline);
417
  } else {
418 419
    node->InsertInput(zone(), 3,
                      jsgraph()->TaggedIndexConstant(p.feedback().index()));
420
    ReplaceWithBuiltinCall(node, Builtins::kKeyedStoreIC);
421
  }
422 423
}

424
void JSGenericLowering::LowerJSStoreNamed(Node* node) {
425 426 427 428 429
  JSStoreNamedNode n(node);
  NamedAccess const& p = n.Parameters();
  FrameState frame_state = n.frame_state();
  FrameState outer_state = frame_state.outer_frame_state();
  STATIC_ASSERT(n.FeedbackVectorIndex() == 2);
430
  if (!p.feedback().IsValid()) {
431 432
    n->RemoveInput(n.FeedbackVectorIndex());
    node->InsertInput(zone(), 1, jsgraph()->HeapConstant(p.name()));
433
    ReplaceWithRuntimeCall(node, Runtime::kSetNamedProperty);
434 435 436 437 438
  } else if (outer_state->opcode() != IrOpcode::kFrameState) {
    n->RemoveInput(n.FeedbackVectorIndex());
    node->InsertInput(zone(), 1, jsgraph()->HeapConstant(p.name()));
    node->InsertInput(zone(), 3,
                      jsgraph()->TaggedIndexConstant(p.feedback().index()));
439
    ReplaceWithBuiltinCall(node, Builtins::kStoreICTrampoline);
440
  } else {
441 442 443
    node->InsertInput(zone(), 1, jsgraph()->HeapConstant(p.name()));
    node->InsertInput(zone(), 3,
                      jsgraph()->TaggedIndexConstant(p.feedback().index()));
444
    ReplaceWithBuiltinCall(node, Builtins::kStoreIC);
445
  }
446 447
}

448
void JSGenericLowering::LowerJSStoreNamedOwn(Node* node) {
449
  JSStoreNamedOwnNode n(node);
450
  CallDescriptor::Flags flags = FrameStateFlagForCall(node);
451 452 453 454
  StoreNamedOwnParameters const& p = n.Parameters();
  FrameState frame_state = n.frame_state();
  FrameState outer_state = frame_state.outer_frame_state();
  STATIC_ASSERT(n.FeedbackVectorIndex() == 2);
455
  if (outer_state->opcode() != IrOpcode::kFrameState) {
456 457 458 459
    n->RemoveInput(n.FeedbackVectorIndex());
    node->InsertInput(zone(), 1, jsgraph()->HeapConstant(p.name()));
    node->InsertInput(zone(), 3,
                      jsgraph()->TaggedIndexConstant(p.feedback().index()));
460
    Callable callable = CodeFactory::StoreOwnIC(isolate());
461
    ReplaceWithBuiltinCall(node, callable, flags);
462
  } else {
463 464 465
    node->InsertInput(zone(), 1, jsgraph()->HeapConstant(p.name()));
    node->InsertInput(zone(), 3,
                      jsgraph()->TaggedIndexConstant(p.feedback().index()));
466
    Callable callable = CodeFactory::StoreOwnICInOptimizedCode(isolate());
467
    ReplaceWithBuiltinCall(node, callable, flags);
468
  }
469
}
470

471
void JSGenericLowering::LowerJSStoreGlobal(Node* node) {
472 473 474 475 476
  JSStoreGlobalNode n(node);
  const StoreGlobalParameters& p = n.Parameters();
  FrameState frame_state = n.frame_state();
  FrameState outer_state = frame_state.outer_frame_state();
  STATIC_ASSERT(n.FeedbackVectorIndex() == 1);
477
  if (outer_state->opcode() != IrOpcode::kFrameState) {
478 479 480 481
    n->RemoveInput(n.FeedbackVectorIndex());
    node->InsertInput(zone(), 0, jsgraph()->HeapConstant(p.name()));
    node->InsertInput(zone(), 2,
                      jsgraph()->TaggedIndexConstant(p.feedback().index()));
482
    ReplaceWithBuiltinCall(node, Builtins::kStoreGlobalICTrampoline);
483
  } else {
484 485 486
    node->InsertInput(zone(), 0, jsgraph()->HeapConstant(p.name()));
    node->InsertInput(zone(), 2,
                      jsgraph()->TaggedIndexConstant(p.feedback().index()));
487
    ReplaceWithBuiltinCall(node, Builtins::kStoreGlobalIC);
488
  }
489 490
}

491
void JSGenericLowering::LowerJSStoreDataPropertyInLiteral(Node* node) {
492 493 494
  JSStoreDataPropertyInLiteralNode n(node);
  FeedbackParameter const& p = n.Parameters();
  STATIC_ASSERT(n.FeedbackVectorIndex() == 4);
495
  RelaxControls(node);
496 497
  node->InsertInput(zone(), 5,
                    jsgraph()->TaggedIndexConstant(p.feedback().index()));
498 499
  ReplaceWithRuntimeCall(node, Runtime::kDefineDataPropertyInLiteral);
}
500

501
void JSGenericLowering::LowerJSStoreInArrayLiteral(Node* node) {
502 503 504
  JSStoreInArrayLiteralNode n(node);
  FeedbackParameter const& p = n.Parameters();
  STATIC_ASSERT(n.FeedbackVectorIndex() == 3);
505
  RelaxControls(node);
506 507
  node->InsertInput(zone(), 3,
                    jsgraph()->TaggedIndexConstant(p.feedback().index()));
508
  ReplaceWithBuiltinCall(node, Builtins::kStoreInArrayLiteralIC);
509 510
}

511
void JSGenericLowering::LowerJSDeleteProperty(Node* node) {
512
  ReplaceWithBuiltinCall(node, Builtins::kDeleteProperty);
513 514
}

515
void JSGenericLowering::LowerJSGetSuperConstructor(Node* node) {
516 517 518 519 520 521 522 523 524 525 526 527 528 529 530
  Node* active_function = NodeProperties::GetValueInput(node, 0);
  Node* effect = NodeProperties::GetEffectInput(node);
  Node* control = NodeProperties::GetControlInput(node);

  Node* function_map = effect = graph()->NewNode(
      jsgraph()->simplified()->LoadField(AccessBuilder::ForMap()),
      active_function, effect, control);

  RelaxControls(node);
  node->ReplaceInput(0, function_map);
  node->ReplaceInput(1, effect);
  node->ReplaceInput(2, control);
  node->TrimInputCount(3);
  NodeProperties::ChangeOp(node, jsgraph()->simplified()->LoadField(
                                     AccessBuilder::ForMapPrototype()));
531 532
}

533 534 535 536
void JSGenericLowering::LowerJSHasInPrototypeChain(Node* node) {
  ReplaceWithRuntimeCall(node, Runtime::kHasInPrototypeChain);
}

537
void JSGenericLowering::LowerJSOrdinaryHasInstance(Node* node) {
538
  ReplaceWithBuiltinCall(node, Builtins::kOrdinaryHasInstance);
539
}
540

541 542 543 544
void JSGenericLowering::LowerJSHasContextExtension(Node* node) {
  UNREACHABLE();  // Eliminated in typed lowering.
}

545
void JSGenericLowering::LowerJSLoadContext(Node* node) {
546
  UNREACHABLE();  // Eliminated in typed lowering.
547 548 549
}


550
void JSGenericLowering::LowerJSStoreContext(Node* node) {
551
  UNREACHABLE();  // Eliminated in typed lowering.
552 553 554
}


555
void JSGenericLowering::LowerJSCreate(Node* node) {
556
  ReplaceWithBuiltinCall(node, Builtins::kFastNewObject);
557
}
558 559


560
void JSGenericLowering::LowerJSCreateArguments(Node* node) {
561 562 563
  CreateArgumentsType const type = CreateArgumentsTypeOf(node->op());
  switch (type) {
    case CreateArgumentsType::kMappedArguments:
564
      ReplaceWithRuntimeCall(node, Runtime::kNewSloppyArguments);
565
      break;
566
    case CreateArgumentsType::kUnmappedArguments:
567
      ReplaceWithRuntimeCall(node, Runtime::kNewStrictArguments);
568
      break;
569 570
    case CreateArgumentsType::kRestParameter:
      ReplaceWithRuntimeCall(node, Runtime::kNewRestParameter);
571 572 573 574 575
      break;
  }
}


576 577 578
void JSGenericLowering::LowerJSCreateArray(Node* node) {
  CreateArrayParameters const& p = CreateArrayParametersOf(node->op());
  int const arity = static_cast<int>(p.arity());
579
  auto interface_descriptor = ArrayConstructorDescriptor{};
580
  auto call_descriptor = Linkage::GetStubCallDescriptor(
581 582 583 584 585 586
      zone(), interface_descriptor, arity + 1, CallDescriptor::kNeedsFrameState,
      node->op()->properties());
  // If this fails, we might need to update the parameter reordering code
  // to ensure that the additional arguments passed via stack are pushed
  // between top of stack and JS arguments.
  DCHECK_EQ(interface_descriptor.GetStackParameterCount(), 0);
587 588
  Node* stub_code = jsgraph()->ArrayConstructorStubConstant();
  Node* stub_arity = jsgraph()->Int32Constant(arity);
589 590
  MaybeHandle<AllocationSite> const maybe_site = p.site();
  Handle<AllocationSite> site;
591 592
  DCHECK_IMPLIES(broker()->is_native_context_independent(),
                 maybe_site.is_null());
593 594
  Node* type_info = maybe_site.ToHandle(&site) ? jsgraph()->HeapConstant(site)
                                               : jsgraph()->UndefinedConstant();
595 596 597 598 599
  Node* receiver = jsgraph()->UndefinedConstant();
  node->InsertInput(zone(), 0, stub_code);
  node->InsertInput(zone(), 3, stub_arity);
  node->InsertInput(zone(), 4, type_info);
  node->InsertInput(zone(), 5, receiver);
600
  NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
601 602
}

603 604 605 606
void JSGenericLowering::LowerJSCreateArrayIterator(Node* node) {
  UNREACHABLE();  // Eliminated in typed lowering.
}

607 608 609 610
void JSGenericLowering::LowerJSCreateAsyncFunctionObject(Node* node) {
  UNREACHABLE();  // Eliminated in typed lowering.
}

611 612 613 614
void JSGenericLowering::LowerJSCreateCollectionIterator(Node* node) {
  UNREACHABLE();  // Eliminated in typed lowering.
}

615 616 617
void JSGenericLowering::LowerJSCreateBoundFunction(Node* node) {
  UNREACHABLE();  // Eliminated in typed lowering.
}
618

619 620 621 622
void JSGenericLowering::LowerJSObjectIsArray(Node* node) {
  UNREACHABLE();  // Eliminated in typed lowering.
}

623
void JSGenericLowering::LowerJSCreateObject(Node* node) {
624
  ReplaceWithBuiltinCall(node, Builtins::kCreateObjectWithoutProperties);
625 626
}

627
void JSGenericLowering::LowerJSParseInt(Node* node) {
628
  ReplaceWithBuiltinCall(node, Builtins::kParseInt);
629 630
}

631
void JSGenericLowering::LowerJSRegExpTest(Node* node) {
632
  ReplaceWithBuiltinCall(node, Builtins::kRegExpPrototypeTestFast);
633 634
}

635
void JSGenericLowering::LowerJSCreateClosure(Node* node) {
636 637
  JSCreateClosureNode n(node);
  CreateClosureParameters const& p = n.Parameters();
638
  Handle<SharedFunctionInfo> const shared_info = p.shared_info();
639
  STATIC_ASSERT(n.FeedbackCellIndex() == 0);
640
  node->InsertInput(zone(), 0, jsgraph()->HeapConstant(shared_info));
641
  node->RemoveInput(4);  // control
642

643
  // Use the FastNewClosure builtin only for functions allocated in new space.
644
  if (p.allocation() == AllocationType::kYoung) {
645
    ReplaceWithBuiltinCall(node, Builtins::kFastNewClosure);
646
  } else {
647
    ReplaceWithRuntimeCall(node, Runtime::kNewClosure_Tenured);
648 649 650 651
  }
}

void JSGenericLowering::LowerJSCreateFunctionContext(Node* node) {
652 653
  const CreateFunctionContextParameters& parameters =
      CreateFunctionContextParametersOf(node->op());
654
  Handle<ScopeInfo> scope_info = parameters.scope_info();
655 656
  int slot_count = parameters.slot_count();
  ScopeType scope_type = parameters.scope_type();
657
  CallDescriptor::Flags flags = FrameStateFlagForCall(node);
658

659
  if (slot_count <= ConstructorBuiltins::MaximumFunctionContextSlots()) {
660 661
    Callable callable =
        CodeFactory::FastNewFunctionContext(isolate(), scope_type);
662
    node->InsertInput(zone(), 0, jsgraph()->HeapConstant(scope_info));
663
    node->InsertInput(zone(), 1, jsgraph()->Int32Constant(slot_count));
664
    ReplaceWithBuiltinCall(node, callable, flags);
665
  } else {
666
    node->InsertInput(zone(), 0, jsgraph()->HeapConstant(scope_info));
667 668
    ReplaceWithRuntimeCall(node, Runtime::kNewFunctionContext);
  }
669 670
}

671 672
void JSGenericLowering::LowerJSCreateGeneratorObject(Node* node) {
  node->RemoveInput(4);  // control
673
  ReplaceWithBuiltinCall(node, Builtins::kCreateGeneratorObject);
674
}
675

676
void JSGenericLowering::LowerJSCreateIterResultObject(Node* node) {
677
  ReplaceWithBuiltinCall(node, Builtins::kCreateIterResultObject);
678 679
}

680 681 682 683
void JSGenericLowering::LowerJSCreateStringIterator(Node* node) {
  UNREACHABLE();  // Eliminated in typed lowering.
}

684
void JSGenericLowering::LowerJSCreateKeyValueArray(Node* node) {
685
  UNREACHABLE();  // Eliminated in typed lowering.
686
}
687

688 689 690 691
void JSGenericLowering::LowerJSCreatePromise(Node* node) {
  UNREACHABLE();  // Eliminated in typed lowering.
}

692
void JSGenericLowering::LowerJSCreateTypedArray(Node* node) {
693
  ReplaceWithBuiltinCall(node, Builtins::kCreateTypedArray);
694 695
}

696
void JSGenericLowering::LowerJSCreateLiteralArray(Node* node) {
697 698 699
  JSCreateLiteralArrayNode n(node);
  CreateLiteralParameters const& p = n.Parameters();
  STATIC_ASSERT(n.FeedbackVectorIndex() == 0);
700 701
  node->InsertInput(zone(), 1,
                    jsgraph()->TaggedIndexConstant(p.feedback().index()));
702
  node->InsertInput(zone(), 2, jsgraph()->HeapConstant(p.constant()));
703

704
  // Use the CreateShallowArrayLiteral builtin only for shallow boilerplates
705
  // without properties up to the number of elements that the stubs can handle.
706
  if ((p.flags() & AggregateLiteral::kIsShallow) != 0 &&
707
      p.length() < ConstructorBuiltins::kMaximumClonedShallowArrayElements) {
708
    ReplaceWithBuiltinCall(node, Builtins::kCreateShallowArrayLiteral);
709 710 711 712
  } else {
    node->InsertInput(zone(), 3, jsgraph()->SmiConstant(p.flags()));
    ReplaceWithRuntimeCall(node, Runtime::kCreateArrayLiteral);
  }
713 714
}

715
void JSGenericLowering::LowerJSGetTemplateObject(Node* node) {
716 717
  JSGetTemplateObjectNode n(node);
  GetTemplateObjectParameters const& p = n.Parameters();
718 719 720
  SharedFunctionInfoRef shared(broker(), p.shared());
  TemplateObjectDescriptionRef description(broker(), p.description());

721 722 723 724
  DCHECK_EQ(node->op()->ControlInputCount(), 1);
  node->RemoveInput(NodeProperties::FirstControlIndex(node));

  STATIC_ASSERT(JSGetTemplateObjectNode::FeedbackVectorIndex() == 0);
725 726 727 728 729
  node->InsertInput(zone(), 0, jsgraph()->Constant(shared));
  node->InsertInput(zone(), 1, jsgraph()->Constant(description));
  node->InsertInput(zone(), 2,
                    jsgraph()->UintPtrConstant(p.feedback().index()));

730
  ReplaceWithBuiltinCall(node, Builtins::kGetTemplateObject);
731 732
}

733
void JSGenericLowering::LowerJSCreateEmptyLiteralArray(Node* node) {
734 735 736
  JSCreateEmptyLiteralArrayNode n(node);
  FeedbackParameter const& p = n.Parameters();
  STATIC_ASSERT(n.FeedbackVectorIndex() == 0);
737 738
  node->InsertInput(zone(), 1,
                    jsgraph()->TaggedIndexConstant(p.feedback().index()));
739
  node->RemoveInput(4);  // control
740
  ReplaceWithBuiltinCall(node, Builtins::kCreateEmptyArrayLiteral);
741
}
742

743
void JSGenericLowering::LowerJSCreateArrayFromIterable(Node* node) {
744
  ReplaceWithBuiltinCall(node, Builtins::kIterableToListWithSymbolLookup);
745 746
}

747
void JSGenericLowering::LowerJSCreateLiteralObject(Node* node) {
748 749 750
  JSCreateLiteralObjectNode n(node);
  CreateLiteralParameters const& p = n.Parameters();
  STATIC_ASSERT(n.FeedbackVectorIndex() == 0);
751 752
  node->InsertInput(zone(), 1,
                    jsgraph()->TaggedIndexConstant(p.feedback().index()));
753
  node->InsertInput(zone(), 2, jsgraph()->HeapConstant(p.constant()));
754
  node->InsertInput(zone(), 3, jsgraph()->SmiConstant(p.flags()));
755

756
  // Use the CreateShallowObjectLiteratal builtin only for shallow boilerplates
757
  // without elements up to the number of properties that the stubs can handle.
758
  if ((p.flags() & AggregateLiteral::kIsShallow) != 0 &&
759
      p.length() <=
760
          ConstructorBuiltins::kMaximumClonedShallowObjectProperties) {
761
    ReplaceWithBuiltinCall(node, Builtins::kCreateShallowObjectLiteral);
762 763 764
  } else {
    ReplaceWithRuntimeCall(node, Runtime::kCreateObjectLiteral);
  }
765 766
}

767
void JSGenericLowering::LowerJSCloneObject(Node* node) {
768 769 770
  JSCloneObjectNode n(node);
  CloneObjectParameters const& p = n.Parameters();
  STATIC_ASSERT(n.FeedbackVectorIndex() == 1);
771
  node->InsertInput(zone(), 1, jsgraph()->SmiConstant(p.flags()));
772 773
  node->InsertInput(zone(), 2,
                    jsgraph()->TaggedIndexConstant(p.feedback().index()));
774
  ReplaceWithBuiltinCall(node, Builtins::kCloneObjectIC);
775 776
}

777
void JSGenericLowering::LowerJSCreateEmptyLiteralObject(Node* node) {
778
  ReplaceWithBuiltinCall(node, Builtins::kCreateEmptyLiteralObject);
779
}
780

781
void JSGenericLowering::LowerJSCreateLiteralRegExp(Node* node) {
782 783 784
  JSCreateLiteralRegExpNode n(node);
  CreateLiteralParameters const& p = n.Parameters();
  STATIC_ASSERT(n.FeedbackVectorIndex() == 0);
785 786
  node->InsertInput(zone(), 1,
                    jsgraph()->TaggedIndexConstant(p.feedback().index()));
787 788
  node->InsertInput(zone(), 2, jsgraph()->HeapConstant(p.constant()));
  node->InsertInput(zone(), 3, jsgraph()->SmiConstant(p.flags()));
789
  ReplaceWithBuiltinCall(node, Builtins::kCreateRegExpLiteral);
790 791 792
}


793
void JSGenericLowering::LowerJSCreateCatchContext(Node* node) {
794 795 796
  Handle<ScopeInfo> scope_info = ScopeInfoOf(node->op());
  node->InsertInput(zone(), 1, jsgraph()->HeapConstant(scope_info));
  ReplaceWithRuntimeCall(node, Runtime::kPushCatchContext);
797 798
}

799
void JSGenericLowering::LowerJSCreateWithContext(Node* node) {
800 801 802
  Handle<ScopeInfo> scope_info = ScopeInfoOf(node->op());
  node->InsertInput(zone(), 1, jsgraph()->HeapConstant(scope_info));
  ReplaceWithRuntimeCall(node, Runtime::kPushWithContext);
803
}
804

805
void JSGenericLowering::LowerJSCreateBlockContext(Node* node) {
806
  Handle<ScopeInfo> scope_info = ScopeInfoOf(node->op());
807 808 809 810
  node->InsertInput(zone(), 0, jsgraph()->HeapConstant(scope_info));
  ReplaceWithRuntimeCall(node, Runtime::kPushBlockContext);
}

811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827
namespace {

bool CollectCallAndConstructFeedback(JSHeapBroker* broker) {
  // Call and construct feedback is a special case. Besides shape feedback, we
  // also increment the call count, which is later used to make inlining
  // decisions.  The call count is only comparable/reliable if it is incremented
  // for all calls inside a function. This is not the case in default turbofan
  // mode, in which many calls may be inlined and will thus never reach generic
  // lowering (where we insert the feedback-collecting builtin call).
  // Therefore it should only be collected in native context independent code,
  // where we 1. know every call will reach generic lowering, and 2. we must
  // collect full feedback to properly tier up later.
  return broker->is_native_context_independent();
}

}  // namespace

828
// TODO(jgruber,v8:8888): Should this collect feedback?
829 830 831 832 833 834
void JSGenericLowering::LowerJSConstructForwardVarargs(Node* node) {
  ConstructForwardVarargsParameters p =
      ConstructForwardVarargsParametersOf(node->op());
  int const arg_count = static_cast<int>(p.arity() - 2);
  CallDescriptor::Flags flags = FrameStateFlagForCall(node);
  Callable callable = CodeFactory::ConstructForwardVarargs(isolate());
835 836 837 838
  // If this fails, we might need to update the parameter reordering code
  // to ensure that the additional arguments passed via stack are pushed
  // between top of stack and JS arguments.
  DCHECK_EQ(callable.descriptor().GetStackParameterCount(), 0);
839
  auto call_descriptor = Linkage::GetStubCallDescriptor(
840
      zone(), callable.descriptor(), arg_count + 1, flags);
841 842 843 844 845 846 847 848
  Node* stub_code = jsgraph()->HeapConstant(callable.code());
  Node* stub_arity = jsgraph()->Int32Constant(arg_count);
  Node* start_index = jsgraph()->Uint32Constant(p.start_index());
  Node* receiver = jsgraph()->UndefinedConstant();
  node->InsertInput(zone(), 0, stub_code);
  node->InsertInput(zone(), 3, stub_arity);
  node->InsertInput(zone(), 4, start_index);
  node->InsertInput(zone(), 5, receiver);
849
  NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
850 851
}

852
void JSGenericLowering::LowerJSConstruct(Node* node) {
853 854
  JSConstructNode n(node);
  ConstructParameters const& p = n.Parameters();
855
  int const arg_count = p.arity_without_implicit_args();
856
  CallDescriptor::Flags flags = FrameStateFlagForCall(node);
857 858 859 860

  static constexpr int kReceiver = 1;
  static constexpr int kMaybeFeedbackVector = 1;

861 862
  if (CollectFeedbackInGenericLowering() &&
      CollectCallAndConstructFeedback(broker()) && p.feedback().IsValid()) {
863 864 865 866
    const int stack_argument_count =
        arg_count + kReceiver + kMaybeFeedbackVector;
    Callable callable =
        Builtins::CallableFor(isolate(), Builtins::kConstruct_WithFeedback);
867 868 869 870 871
    // If this fails, we might need to update the parameter reordering code
    // to ensure that the additional arguments passed via stack are pushed
    // between top of stack and JS arguments.
    DCHECK_EQ(callable.descriptor().GetStackParameterCount(),
              kMaybeFeedbackVector);
872 873 874 875 876 877
    auto call_descriptor = Linkage::GetStubCallDescriptor(
        zone(), callable.descriptor(), stack_argument_count, flags);
    Node* stub_code = jsgraph()->HeapConstant(callable.code());
    Node* stub_arity = jsgraph()->Int32Constant(arg_count);
    Node* slot = jsgraph()->Int32Constant(p.feedback().index());
    Node* receiver = jsgraph()->UndefinedConstant();
878
    Node* feedback_vector = node->RemoveInput(n.FeedbackVectorIndex());
879
    // Register argument inputs are followed by stack argument inputs (such as
880
    // feedback_vector). Both are listed in ascending order. Note that
881 882 883 884 885 886
    // the receiver is implicitly placed on the stack and is thus inserted
    // between explicitly-specified register and stack arguments.
    // TODO(jgruber): Implement a simpler way to specify these mutations.
    node->InsertInput(zone(), 0, stub_code);
    node->InsertInput(zone(), 3, stub_arity);
    node->InsertInput(zone(), 4, slot);
887 888 889 890
    node->InsertInput(zone(), 5, feedback_vector);
    node->InsertInput(zone(), 6, receiver);
    // After: {code, target, new_target, arity, slot, vector, receiver,
    // ...args}.
891

892 893 894 895 896 897 898 899 900
    NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
  } else {
    const int stack_argument_count = arg_count + kReceiver;
    Callable callable = Builtins::CallableFor(isolate(), Builtins::kConstruct);
    auto call_descriptor = Linkage::GetStubCallDescriptor(
        zone(), callable.descriptor(), stack_argument_count, flags);
    Node* stub_code = jsgraph()->HeapConstant(callable.code());
    Node* stub_arity = jsgraph()->Int32Constant(arg_count);
    Node* receiver = jsgraph()->UndefinedConstant();
901
    node->RemoveInput(n.FeedbackVectorIndex());
902 903 904
    node->InsertInput(zone(), 0, stub_code);
    node->InsertInput(zone(), 3, stub_arity);
    node->InsertInput(zone(), 4, receiver);
905 906 907

    // After: {code, target, new_target, arity, receiver, ...args}.

908 909
    NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
  }
910 911
}

912
void JSGenericLowering::LowerJSConstructWithArrayLike(Node* node) {
913 914
  JSConstructWithArrayLikeNode n(node);
  ConstructParameters const& p = n.Parameters();
915
  CallDescriptor::Flags flags = FrameStateFlagForCall(node);
916
  const int arg_count = p.arity_without_implicit_args();
917 918 919 920 921 922
  DCHECK_EQ(arg_count, 1);

  static constexpr int kReceiver = 1;
  static constexpr int kArgumentList = 1;
  static constexpr int kMaybeFeedbackVector = 1;

923 924
  if (CollectFeedbackInGenericLowering() &&
      CollectCallAndConstructFeedback(broker()) && p.feedback().IsValid()) {
925 926 927 928
    const int stack_argument_count =
        arg_count - kArgumentList + kReceiver + kMaybeFeedbackVector;
    Callable callable = Builtins::CallableFor(
        isolate(), Builtins::kConstructWithArrayLike_WithFeedback);
929 930 931 932 933
    // If this fails, we might need to update the parameter reordering code
    // to ensure that the additional arguments passed via stack are pushed
    // between top of stack and JS arguments.
    DCHECK_EQ(callable.descriptor().GetStackParameterCount(),
              kMaybeFeedbackVector);
934 935 936 937 938
    auto call_descriptor = Linkage::GetStubCallDescriptor(
        zone(), callable.descriptor(), stack_argument_count, flags);
    Node* stub_code = jsgraph()->HeapConstant(callable.code());
    Node* receiver = jsgraph()->UndefinedConstant();
    Node* slot = jsgraph()->Int32Constant(p.feedback().index());
939
    Node* feedback_vector = node->RemoveInput(n.FeedbackVectorIndex());
940
    // Register argument inputs are followed by stack argument inputs (such as
941
    // feedback_vector). Both are listed in ascending order. Note that
942 943 944
    // the receiver is implicitly placed on the stack and is thus inserted
    // between explicitly-specified register and stack arguments.
    // TODO(jgruber): Implement a simpler way to specify these mutations.
945
    node->InsertInput(zone(), 0, stub_code);
946
    node->InsertInput(zone(), 4, slot);
947 948 949 950
    node->InsertInput(zone(), 5, feedback_vector);
    node->InsertInput(zone(), 6, receiver);
    // After: {code, target, new_target, arguments_list, slot, vector,
    // receiver}.
951

952 953 954 955 956
    NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
  } else {
    const int stack_argument_count = arg_count - kArgumentList + kReceiver;
    Callable callable =
        Builtins::CallableFor(isolate(), Builtins::kConstructWithArrayLike);
957 958 959 960
    // If this fails, we might need to update the parameter reordering code
    // to ensure that the additional arguments passed via stack are pushed
    // between top of stack and JS arguments.
    DCHECK_EQ(callable.descriptor().GetStackParameterCount(), 0);
961 962 963 964
    auto call_descriptor = Linkage::GetStubCallDescriptor(
        zone(), callable.descriptor(), stack_argument_count, flags);
    Node* stub_code = jsgraph()->HeapConstant(callable.code());
    Node* receiver = jsgraph()->UndefinedConstant();
965
    node->RemoveInput(n.FeedbackVectorIndex());
966 967
    node->InsertInput(zone(), 0, stub_code);
    node->InsertInput(zone(), 4, receiver);
968 969 970

    // After: {code, target, new_target, arguments_list, receiver}.

971 972
    NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
  }
973 974
}

975
void JSGenericLowering::LowerJSConstructWithSpread(Node* node) {
976 977
  JSConstructWithSpreadNode n(node);
  ConstructParameters const& p = n.Parameters();
978
  int const arg_count = p.arity_without_implicit_args();
979
  DCHECK_GE(arg_count, 1);
980
  CallDescriptor::Flags flags = FrameStateFlagForCall(node);
981

982 983 984 985
  static constexpr int kReceiver = 1;
  static constexpr int kTheSpread = 1;  // Included in `arg_count`.
  static constexpr int kMaybeFeedbackVector = 1;

986 987
  if (CollectFeedbackInGenericLowering() &&
      CollectCallAndConstructFeedback(broker()) && p.feedback().IsValid()) {
988 989 990 991
    const int stack_argument_count =
        arg_count + kReceiver + kMaybeFeedbackVector;
    Callable callable = Builtins::CallableFor(
        isolate(), Builtins::kConstructWithSpread_WithFeedback);
992 993 994 995 996
    // If this fails, we might need to update the parameter reordering code
    // to ensure that the additional arguments passed via stack are pushed
    // between top of stack and JS arguments.
    DCHECK_EQ(callable.descriptor().GetStackParameterCount(),
              kTheSpread + kMaybeFeedbackVector);
997 998 999 1000 1001 1002 1003 1004 1005
    auto call_descriptor = Linkage::GetStubCallDescriptor(
        zone(), callable.descriptor(), stack_argument_count, flags);
    Node* stub_code = jsgraph()->HeapConstant(callable.code());
    Node* slot = jsgraph()->Int32Constant(p.feedback().index());

    // The single available register is needed for `slot`, thus `spread` remains
    // on the stack here.
    Node* stub_arity = jsgraph()->Int32Constant(arg_count - kTheSpread);
    Node* receiver = jsgraph()->UndefinedConstant();
1006 1007
    Node* feedback_vector = node->RemoveInput(n.FeedbackVectorIndex());
    Node* spread = node->RemoveInput(n.LastArgumentIndex());
1008 1009

    // Register argument inputs are followed by stack argument inputs (such as
1010
    // feedback_vector). Both are listed in ascending order. Note that
1011 1012 1013 1014 1015 1016
    // the receiver is implicitly placed on the stack and is thus inserted
    // between explicitly-specified register and stack arguments.
    // TODO(jgruber): Implement a simpler way to specify these mutations.
    node->InsertInput(zone(), 0, stub_code);
    node->InsertInput(zone(), 3, stub_arity);
    node->InsertInput(zone(), 4, slot);
1017 1018 1019 1020 1021 1022
    // Arguments in the stack should be inserted in reversed order, ie, the last
    // arguments defined in the interface descriptor should be inserted first.
    DCHECK_EQ(callable.descriptor().GetStackArgumentOrder(),
              StackArgumentOrder::kJS);
    node->InsertInput(zone(), 5, feedback_vector);
    node->InsertInput(zone(), 6, spread);
1023
    node->InsertInput(zone(), 7, receiver);
1024
    // After: {code, target, new_target, arity, slot, vector, spread, receiver,
1025
    // ...args}.
1026

1027 1028 1029 1030
    NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
  } else {
    const int stack_argument_count = arg_count + kReceiver - kTheSpread;
    Callable callable = CodeFactory::ConstructWithSpread(isolate());
1031 1032 1033 1034
    // If this fails, we might need to update the parameter reordering code
    // to ensure that the additional arguments passed via stack are pushed
    // between top of stack and JS arguments.
    DCHECK_EQ(callable.descriptor().GetStackParameterCount(), 0);
1035 1036 1037 1038 1039 1040 1041
    auto call_descriptor = Linkage::GetStubCallDescriptor(
        zone(), callable.descriptor(), stack_argument_count, flags);
    Node* stub_code = jsgraph()->HeapConstant(callable.code());

    // We pass the spread in a register, not on the stack.
    Node* stub_arity = jsgraph()->Int32Constant(arg_count - kTheSpread);
    Node* receiver = jsgraph()->UndefinedConstant();
1042 1043
    DCHECK(n.FeedbackVectorIndex() > n.LastArgumentIndex());
    node->RemoveInput(n.FeedbackVectorIndex());
1044
    Node* spread = node->RemoveInput(n.LastArgumentIndex());
1045 1046 1047 1048 1049

    node->InsertInput(zone(), 0, stub_code);
    node->InsertInput(zone(), 3, stub_arity);
    node->InsertInput(zone(), 4, spread);
    node->InsertInput(zone(), 5, receiver);
1050 1051 1052

    // After: {code, target, new_target, arity, spread, receiver, ...args}.

1053 1054
    NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
  }
1055 1056
}

1057
// TODO(jgruber,v8:8888): Should this collect feedback?
1058 1059
void JSGenericLowering::LowerJSCallForwardVarargs(Node* node) {
  CallForwardVarargsParameters p = CallForwardVarargsParametersOf(node->op());
1060
  int const arg_count = static_cast<int>(p.arity() - 2);
1061
  CallDescriptor::Flags flags = FrameStateFlagForCall(node);
1062
  Callable callable = CodeFactory::CallForwardVarargs(isolate());
1063
  auto call_descriptor = Linkage::GetStubCallDescriptor(
1064
      zone(), callable.descriptor(), arg_count + 1, flags);
1065
  Node* stub_code = jsgraph()->HeapConstant(callable.code());
1066
  Node* stub_arity = jsgraph()->Int32Constant(arg_count);
1067 1068
  Node* start_index = jsgraph()->Uint32Constant(p.start_index());
  node->InsertInput(zone(), 0, stub_code);
1069 1070
  node->InsertInput(zone(), 2, stub_arity);
  node->InsertInput(zone(), 3, start_index);
1071
  NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
1072
}
1073

1074
void JSGenericLowering::LowerJSCall(Node* node) {
1075 1076
  JSCallNode n(node);
  CallParameters const& p = n.Parameters();
1077
  int const arg_count = p.arity_without_implicit_args();
1078
  ConvertReceiverMode const mode = p.convert_mode();
1079

1080 1081 1082
  Node* feedback_vector = n.feedback_vector();
  node->RemoveInput(n.FeedbackVectorIndex());

1083 1084
  if (CollectFeedbackInGenericLowering() &&
      CollectCallAndConstructFeedback(broker()) && p.feedback().IsValid()) {
1085 1086 1087 1088 1089 1090 1091 1092 1093 1094
    Callable callable = CodeFactory::Call_WithFeedback(isolate(), mode);
    CallDescriptor::Flags flags = FrameStateFlagForCall(node);
    auto call_descriptor = Linkage::GetStubCallDescriptor(
        zone(), callable.descriptor(), arg_count + 1, flags);
    Node* stub_code = jsgraph()->HeapConstant(callable.code());
    Node* stub_arity = jsgraph()->Int32Constant(arg_count);
    Node* slot = jsgraph()->Int32Constant(p.feedback().index());
    node->InsertInput(zone(), 0, stub_code);
    node->InsertInput(zone(), 2, stub_arity);
    node->InsertInput(zone(), 3, slot);
1095
    node->InsertInput(zone(), 4, feedback_vector);
1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107
    NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
  } else {
    Callable callable = CodeFactory::Call(isolate(), mode);
    CallDescriptor::Flags flags = FrameStateFlagForCall(node);
    auto call_descriptor = Linkage::GetStubCallDescriptor(
        zone(), callable.descriptor(), arg_count + 1, flags);
    Node* stub_code = jsgraph()->HeapConstant(callable.code());
    Node* stub_arity = jsgraph()->Int32Constant(arg_count);
    node->InsertInput(zone(), 0, stub_code);
    node->InsertInput(zone(), 2, stub_arity);
    NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
  }
1108 1109
}

1110
void JSGenericLowering::LowerJSCallWithArrayLike(Node* node) {
1111 1112
  JSCallWithArrayLikeNode n(node);
  CallParameters const& p = n.Parameters();
1113
  const int arg_count = p.arity_without_implicit_args();
1114
  DCHECK_EQ(arg_count, 1);  // The arraylike object.
1115
  CallDescriptor::Flags flags = FrameStateFlagForCall(node);
1116

1117
  static constexpr int kArgumentsList = 1;
1118 1119
  static constexpr int kReceiver = 1;

1120 1121
  if (CollectFeedbackInGenericLowering() &&
      CollectCallAndConstructFeedback(broker()) && p.feedback().IsValid()) {
1122
    const int stack_argument_count = arg_count - kArgumentsList + kReceiver;
1123 1124 1125
    Callable callable = Builtins::CallableFor(
        isolate(), Builtins::kCallWithArrayLike_WithFeedback);
    auto call_descriptor = Linkage::GetStubCallDescriptor(
1126
        zone(), callable.descriptor(), stack_argument_count, flags);
1127
    Node* stub_code = jsgraph()->HeapConstant(callable.code());
1128 1129 1130
    Node* receiver = n.receiver();
    Node* arguments_list = n.Argument(0);
    Node* feedback_vector = n.feedback_vector();
1131
    Node* slot = jsgraph()->Int32Constant(p.feedback().index());
1132 1133 1134 1135 1136 1137

    // Shuffling inputs.
    // Before: {target, receiver, arguments_list, vector}.

    node->ReplaceInput(1, arguments_list);
    node->ReplaceInput(2, feedback_vector);
1138
    node->ReplaceInput(3, receiver);
1139 1140 1141 1142

    // Now: {target, arguments_list, vector, receiver}.

    node->InsertInput(zone(), 0, stub_code);
1143
    node->InsertInput(zone(), 3, slot);
1144 1145 1146

    // After: {code, target, arguments_list, slot, vector, receiver}.

1147 1148
    NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
  } else {
1149
    const int stack_argument_count = arg_count - kArgumentsList + kReceiver;
1150 1151
    Callable callable = CodeFactory::CallWithArrayLike(isolate());
    auto call_descriptor = Linkage::GetStubCallDescriptor(
1152
        zone(), callable.descriptor(), stack_argument_count, flags);
1153
    Node* stub_code = jsgraph()->HeapConstant(callable.code());
1154 1155 1156 1157 1158 1159 1160
    Node* receiver = n.receiver();
    Node* arguments_list = n.Argument(0);

    // Shuffling inputs.
    // Before: {target, receiver, arguments_list, vector}.

    node->RemoveInput(n.FeedbackVectorIndex());
1161 1162 1163
    node->InsertInput(zone(), 0, stub_code);
    node->ReplaceInput(2, arguments_list);
    node->ReplaceInput(3, receiver);
1164 1165 1166

    // After: {code, target, arguments_list, receiver}.

1167 1168
    NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
  }
1169 1170
}

1171
void JSGenericLowering::LowerJSCallWithSpread(Node* node) {
1172 1173
  JSCallWithSpreadNode n(node);
  CallParameters const& p = n.Parameters();
1174
  int const arg_count = p.arity_without_implicit_args();
1175
  DCHECK_GE(arg_count, 1);  // At least the spread.
1176
  CallDescriptor::Flags flags = FrameStateFlagForCall(node);
1177

1178
  static constexpr int kReceiver = 1;
1179 1180 1181
  static constexpr int kTheSpread = 1;
  static constexpr int kMaybeFeedbackVector = 1;

1182 1183
  if (CollectFeedbackInGenericLowering() &&
      CollectCallAndConstructFeedback(broker()) && p.feedback().IsValid()) {
1184 1185
    const int stack_argument_count =
        arg_count - kTheSpread + kReceiver + kMaybeFeedbackVector;
1186 1187
    Callable callable = Builtins::CallableFor(
        isolate(), Builtins::kCallWithSpread_WithFeedback);
1188 1189 1190 1191 1192
    // If this fails, we might need to update the parameter reordering code
    // to ensure that the additional arguments passed via stack are pushed
    // between top of stack and JS arguments.
    DCHECK_EQ(callable.descriptor().GetStackParameterCount(),
              kMaybeFeedbackVector);
1193 1194 1195 1196 1197 1198 1199 1200 1201
    auto call_descriptor = Linkage::GetStubCallDescriptor(
        zone(), callable.descriptor(), stack_argument_count, flags);
    Node* stub_code = jsgraph()->HeapConstant(callable.code());
    Node* slot = jsgraph()->Int32Constant(p.feedback().index());

    // We pass the spread in a register, not on the stack.
    Node* stub_arity = jsgraph()->Int32Constant(arg_count - kTheSpread);

    // Register argument inputs are followed by stack argument inputs (such as
1202
    // feedback_vector). Both are listed in ascending order. Note that
1203 1204 1205
    // the receiver is implicitly placed on the stack and is thus inserted
    // between explicitly-specified register and stack arguments.
    // TODO(jgruber): Implement a simpler way to specify these mutations.
1206 1207 1208

    // Shuffling inputs.
    // Before: {target, receiver, ...args, spread, vector}.
1209
    Node* feedback_vector = node->RemoveInput(n.FeedbackVectorIndex());
1210
    Node* spread = node->RemoveInput(n.LastArgumentIndex());
1211 1212 1213 1214
    node->InsertInput(zone(), 0, stub_code);
    node->InsertInput(zone(), 2, stub_arity);
    node->InsertInput(zone(), 3, spread);
    node->InsertInput(zone(), 4, slot);
1215 1216
    node->InsertInput(zone(), 5, feedback_vector);
    // After: {code, target, arity, spread, slot, vector, receiver, ...args}.
1217

1218 1219
    NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
  } else {
1220
    const int stack_argument_count = arg_count - kTheSpread + kReceiver;
1221
    Callable callable = CodeFactory::CallWithSpread(isolate());
1222 1223 1224 1225
    // If this fails, we might need to update the parameter reordering code
    // to ensure that the additional arguments passed via stack are pushed
    // between top of stack and JS arguments.
    DCHECK_EQ(callable.descriptor().GetStackParameterCount(), 0);
1226 1227 1228 1229 1230 1231
    auto call_descriptor = Linkage::GetStubCallDescriptor(
        zone(), callable.descriptor(), stack_argument_count, flags);
    Node* stub_code = jsgraph()->HeapConstant(callable.code());

    // We pass the spread in a register, not on the stack.
    Node* stub_arity = jsgraph()->Int32Constant(arg_count - kTheSpread);
1232 1233 1234 1235 1236 1237

    // Shuffling inputs.
    // Before: {target, receiver, ...args, spread, vector}.

    node->RemoveInput(n.FeedbackVectorIndex());
    Node* spread = node->RemoveInput(n.LastArgumentIndex());
1238 1239 1240 1241

    node->InsertInput(zone(), 0, stub_code);
    node->InsertInput(zone(), 2, stub_arity);
    node->InsertInput(zone(), 3, spread);
1242 1243 1244

    // After: {code, target, arity, spread, receiver, ...args}.

1245 1246
    NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
  }
1247
}
1248

1249
void JSGenericLowering::LowerJSCallRuntime(Node* node) {
1250 1251
  const CallRuntimeParameters& p = CallRuntimeParametersOf(node->op());
  ReplaceWithRuntimeCall(node, p.id(), static_cast<int>(p.arity()));
1252
}
1253

1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318
void JSGenericLowering::LowerJSForInPrepare(Node* node) {
  JSForInPrepareNode n(node);
  Effect effect(node);            // {node} is kept in the effect chain.
  Control control = n.control();  // .. but not in the control chain.
  Node* enumerator = n.enumerator();
  Node* slot =
      jsgraph()->UintPtrConstant(n.Parameters().feedback().slot.ToInt());

  std::vector<Edge> use_edges;
  for (Edge edge : node->use_edges()) use_edges.push_back(edge);

  // {node} will be changed to a builtin call (see below). The returned value
  // is a fixed array containing {cache_array} and {cache_length}.
  // TODO(jgruber): This is awkward; what we really want is two return values,
  // the {cache_array} and {cache_length}, or better yet three return values
  // s.t. we can avoid the graph rewrites below. Builtin support for multiple
  // return types is unclear though.

  Node* result_fixed_array = node;
  Node* cache_type = enumerator;  // Just to clarify the rename.
  Node* cache_array;
  Node* cache_length;

  cache_array = effect = graph()->NewNode(
      machine()->Load(MachineType::AnyTagged()), result_fixed_array,
      jsgraph()->IntPtrConstant(FixedArray::OffsetOfElementAt(0) -
                                kHeapObjectTag),
      effect, control);
  cache_length = effect = graph()->NewNode(
      machine()->Load(MachineType::AnyTagged()), result_fixed_array,
      jsgraph()->IntPtrConstant(FixedArray::OffsetOfElementAt(1) -
                                kHeapObjectTag),
      effect, control);

  // Update the uses of {node}.
  for (Edge edge : use_edges) {
    Node* const user = edge.from();
    if (NodeProperties::IsEffectEdge(edge)) {
      edge.UpdateTo(effect);
    } else if (NodeProperties::IsControlEdge(edge)) {
      edge.UpdateTo(control);
    } else {
      DCHECK(NodeProperties::IsValueEdge(edge));
      switch (ProjectionIndexOf(user->op())) {
        case 0:
          Replace(user, cache_type);
          break;
        case 1:
          Replace(user, cache_array);
          break;
        case 2:
          Replace(user, cache_length);
          break;
        default:
          UNREACHABLE();
      }
    }
  }

  // Finally, change the original node into a builtin call. This happens here,
  // after graph rewrites, since the Call does not have a control output and
  // thus must not have any control uses. Any previously existing control
  // outputs have been replaced by the graph rewrite above.
  node->InsertInput(zone(), n.FeedbackVectorIndex(), slot);
  ReplaceWithBuiltinCall(node, Builtins::kForInPrepare);
1319 1320
}

1321 1322 1323 1324 1325 1326
void JSGenericLowering::LowerJSForInNext(Node* node) {
  JSForInNextNode n(node);
  node->InsertInput(
      zone(), 0,
      jsgraph()->UintPtrConstant(n.Parameters().feedback().slot.ToInt()));
  ReplaceWithBuiltinCall(node, Builtins::kForInNext);
1327 1328
}

1329
void JSGenericLowering::LowerJSLoadMessage(Node* node) {
1330
  UNREACHABLE();  // Eliminated in typed lowering.
1331 1332 1333 1334
}


void JSGenericLowering::LowerJSStoreMessage(Node* node) {
1335
  UNREACHABLE();  // Eliminated in typed lowering.
1336 1337
}

1338 1339 1340 1341 1342 1343 1344 1345
void JSGenericLowering::LowerJSLoadModule(Node* node) {
  UNREACHABLE();  // Eliminated in typed lowering.
}

void JSGenericLowering::LowerJSStoreModule(Node* node) {
  UNREACHABLE();  // Eliminated in typed lowering.
}

1346 1347 1348 1349
void JSGenericLowering::LowerJSGetImportMeta(Node* node) {
  ReplaceWithRuntimeCall(node, Runtime::kGetImportMetaObject);
}

1350 1351 1352 1353 1354 1355 1356 1357
void JSGenericLowering::LowerJSGeneratorStore(Node* node) {
  UNREACHABLE();  // Eliminated in typed lowering.
}

void JSGenericLowering::LowerJSGeneratorRestoreContinuation(Node* node) {
  UNREACHABLE();  // Eliminated in typed lowering.
}

1358 1359 1360 1361
void JSGenericLowering::LowerJSGeneratorRestoreContext(Node* node) {
  UNREACHABLE();  // Eliminated in typed lowering.
}

1362 1363 1364 1365
void JSGenericLowering::LowerJSGeneratorRestoreInputOrDebugPos(Node* node) {
  UNREACHABLE();  // Eliminated in typed lowering.
}

1366 1367 1368
void JSGenericLowering::LowerJSGeneratorRestoreRegister(Node* node) {
  UNREACHABLE();  // Eliminated in typed lowering.
}
1369

1370 1371 1372 1373 1374 1375 1376 1377 1378
namespace {

StackCheckKind StackCheckKindOfJSStackCheck(const Operator* op) {
  DCHECK(op->opcode() == IrOpcode::kJSStackCheck);
  return OpParameter<StackCheckKind>(op);
}

}  // namespace

1379 1380 1381 1382
void JSGenericLowering::LowerJSStackCheck(Node* node) {
  Node* effect = NodeProperties::GetEffectInput(node);
  Node* control = NodeProperties::GetControlInput(node);

1383 1384 1385 1386 1387
  Node* limit = effect =
      graph()->NewNode(machine()->Load(MachineType::Pointer()),
                       jsgraph()->ExternalConstant(
                           ExternalReference::address_of_jslimit(isolate())),
                       jsgraph()->IntPtrConstant(0), effect, control);
1388

1389 1390 1391
  StackCheckKind stack_check_kind = StackCheckKindOfJSStackCheck(node->op());
  Node* check = effect = graph()->NewNode(
      machine()->StackPointerGreaterThan(stack_check_kind), limit, effect);
1392 1393 1394 1395 1396 1397 1398 1399
  Node* branch =
      graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);

  Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
  Node* etrue = effect;

  Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
  NodeProperties::ReplaceControlInput(node, if_false);
1400
  NodeProperties::ReplaceEffectInput(node, effect);
1401
  Node* efalse = if_false = node;
1402 1403 1404 1405

  Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
  Node* ephi = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, merge);

1406
  // Wire the new diamond into the graph, {node} can still throw.
1407 1408
  NodeProperties::ReplaceUses(node, node, ephi, merge, merge);
  NodeProperties::ReplaceControlInput(merge, if_false, 1);
1409 1410
  NodeProperties::ReplaceEffectInput(ephi, efalse, 1);

1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423
  // This iteration cuts out potential {IfSuccess} or {IfException} projection
  // uses of the original node and places them inside the diamond, so that we
  // can change the original {node} into the slow-path runtime call.
  for (Edge edge : merge->use_edges()) {
    if (!NodeProperties::IsControlEdge(edge)) continue;
    if (edge.from()->opcode() == IrOpcode::kIfSuccess) {
      NodeProperties::ReplaceUses(edge.from(), nullptr, nullptr, merge);
      NodeProperties::ReplaceControlInput(merge, edge.from(), 1);
      edge.UpdateTo(node);
    }
    if (edge.from()->opcode() == IrOpcode::kIfException) {
      NodeProperties::ReplaceEffectInput(edge.from(), node);
      edge.UpdateTo(node);
1424 1425 1426
    }
  }

1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437
  // Turn the stack check into a runtime call. At function entry, the runtime
  // function takes an offset argument which is subtracted from the stack
  // pointer prior to the stack check (i.e. the check is `sp - offset >=
  // limit`).
  if (stack_check_kind == StackCheckKind::kJSFunctionEntry) {
    node->InsertInput(zone(), 0,
                      graph()->NewNode(machine()->LoadStackCheckOffset()));
    ReplaceWithRuntimeCall(node, Runtime::kStackGuardWithGap);
  } else {
    ReplaceWithRuntimeCall(node, Runtime::kStackGuard);
  }
1438 1439
}

1440
void JSGenericLowering::LowerJSDebugger(Node* node) {
1441
  ReplaceWithBuiltinCall(node, Builtins::kHandleDebuggerStatement);
1442
}
1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461

Zone* JSGenericLowering::zone() const { return graph()->zone(); }


Isolate* JSGenericLowering::isolate() const { return jsgraph()->isolate(); }


Graph* JSGenericLowering::graph() const { return jsgraph()->graph(); }


CommonOperatorBuilder* JSGenericLowering::common() const {
  return jsgraph()->common();
}


MachineOperatorBuilder* JSGenericLowering::machine() const {
  return jsgraph()->machine();
}

1462 1463 1464
}  // namespace compiler
}  // namespace internal
}  // namespace v8