code-stub-assembler.h 87.6 KB
Newer Older
1 2 3 4 5 6 7
// Copyright 2016 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.

#ifndef V8_CODE_STUB_ASSEMBLER_H_
#define V8_CODE_STUB_ASSEMBLER_H_

8 9
#include <functional>

10
#include "src/compiler/code-assembler.h"
11
#include "src/globals.h"
12 13 14 15 16 17
#include "src/objects.h"

namespace v8 {
namespace internal {

class CallInterfaceDescriptor;
18
class CodeStubArguments;
19
class CodeStubAssembler;
20 21
class StatsCounter;
class StubCache;
22

23 24
enum class PrimitiveType { kBoolean, kNumber, kString, kSymbol };

25 26 27 28 29 30
#define HEAP_CONSTANT_LIST(V)                                            \
  V(AccessorInfoMap, accessor_info_map, AccessorInfoMap)                 \
  V(AccessorPairMap, accessor_pair_map, AccessorPairMap)                 \
  V(AllocationSiteMap, allocation_site_map, AllocationSiteMap)           \
  V(BooleanMap, boolean_map, BooleanMap)                                 \
  V(CodeMap, code_map, CodeMap)                                          \
31 32
  V(EmptyPropertyDictionary, empty_property_dictionary,                  \
    EmptyPropertyDictionary)                                             \
33
  V(EmptyFixedArray, empty_fixed_array, EmptyFixedArray)                 \
34 35
  V(EmptySlowElementDictionary, empty_slow_element_dictionary,           \
    EmptySlowElementDictionary)                                          \
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
  V(empty_string, empty_string, EmptyString)                             \
  V(EmptyWeakCell, empty_weak_cell, EmptyWeakCell)                       \
  V(FalseValue, false_value, False)                                      \
  V(FeedbackVectorMap, feedback_vector_map, FeedbackVectorMap)           \
  V(FixedArrayMap, fixed_array_map, FixedArrayMap)                       \
  V(FixedCOWArrayMap, fixed_cow_array_map, FixedCOWArrayMap)             \
  V(FixedDoubleArrayMap, fixed_double_array_map, FixedDoubleArrayMap)    \
  V(FunctionTemplateInfoMap, function_template_info_map,                 \
    FunctionTemplateInfoMap)                                             \
  V(GlobalPropertyCellMap, global_property_cell_map, PropertyCellMap)    \
  V(has_instance_symbol, has_instance_symbol, HasInstanceSymbol)         \
  V(HeapNumberMap, heap_number_map, HeapNumberMap)                       \
  V(length_string, length_string, LengthString)                          \
  V(ManyClosuresCellMap, many_closures_cell_map, ManyClosuresCellMap)    \
  V(MetaMap, meta_map, MetaMap)                                          \
  V(MinusZeroValue, minus_zero_value, MinusZero)                         \
  V(MutableHeapNumberMap, mutable_heap_number_map, MutableHeapNumberMap) \
  V(NanValue, nan_value, Nan)                                            \
  V(NoClosuresCellMap, no_closures_cell_map, NoClosuresCellMap)          \
  V(NullValue, null_value, Null)                                         \
  V(OneClosureCellMap, one_closure_cell_map, OneClosureCellMap)          \
  V(prototype_string, prototype_string, PrototypeString)                 \
  V(SpeciesProtector, species_protector, SpeciesProtector)               \
  V(SymbolMap, symbol_map, SymbolMap)                                    \
  V(TheHoleValue, the_hole_value, TheHole)                               \
  V(TrueValue, true_value, True)                                         \
  V(Tuple2Map, tuple2_map, Tuple2Map)                                    \
  V(Tuple3Map, tuple3_map, Tuple3Map)                                    \
  V(UndefinedValue, undefined_value, Undefined)                          \
  V(WeakCellMap, weak_cell_map, WeakCellMap)                             \
  V(SharedFunctionInfoMap, shared_function_info_map, SharedFunctionInfoMap)
67

68 69 70 71 72
// Provides JavaScript-specific "macro-assembler" functionality on top of the
// CodeAssembler. By factoring the JavaScript-isms out of the CodeAssembler,
// it's possible to add JavaScript-specific useful CodeAssembler "macros"
// without modifying files in the compiler directory (and requiring a review
// from a compiler directory OWNER).
73
class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
74
 public:
75 76 77 78 79
  using Node = compiler::Node;
  template <class A>
  using TNode = compiler::TNode<A>;
  template <class A>
  using SloppyTNode = compiler::SloppyTNode<A>;
80

81
  CodeStubAssembler(compiler::CodeAssemblerState* state);
82

83 84 85
  enum AllocationFlag : uint8_t {
    kNone = 0,
    kDoubleAlignment = 1,
86 87
    kPretenured = 1 << 1,
    kAllowLargeObjectAllocation = 1 << 2,
88 89 90 91
  };

  typedef base::Flags<AllocationFlag> AllocationFlags;

92
  enum ParameterMode { SMI_PARAMETERS, INTPTR_PARAMETERS };
93 94 95 96 97 98 99 100 101 102
  // On 32-bit platforms, there is a slight performance advantage to doing all
  // of the array offset/index arithmetic with SMIs, since it's possible
  // to save a few tag/untag operations without paying an extra expense when
  // calculating array offset (the smi math can be folded away) and there are
  // fewer live ranges. Thus only convert indices to untagged value on 64-bit
  // platforms.
  ParameterMode OptimalParameterMode() const {
    return Is64() ? INTPTR_PARAMETERS : SMI_PARAMETERS;
  }

103 104 105 106 107
  MachineRepresentation ParameterRepresentation(ParameterMode mode) const {
    return mode == INTPTR_PARAMETERS ? MachineType::PointerRepresentation()
                                     : MachineRepresentation::kTaggedSigned;
  }

108
  MachineRepresentation OptimalParameterRepresentation() const {
109
    return ParameterRepresentation(OptimalParameterMode());
110 111
  }

112 113 114 115 116
  Node* ParameterToWord(Node* value, ParameterMode mode) {
    if (mode == SMI_PARAMETERS) value = SmiUntag(value);
    return value;
  }

117 118
  Node* WordToParameter(SloppyTNode<IntPtrT> value, ParameterMode mode) {
    if (mode == SMI_PARAMETERS) return SmiTag(value);
119 120 121
    return value;
  }

122 123
  Node* Word32ToParameter(SloppyTNode<Int32T> value, ParameterMode mode) {
    return WordToParameter(ChangeInt32ToIntPtr(value), mode);
124 125
  }

126 127 128
  TNode<Smi> ParameterToTagged(Node* value, ParameterMode mode) {
    if (mode != SMI_PARAMETERS) return SmiTag(value);
    return UncheckedCast<Smi>(value);
129 130
  }

131 132
  Node* TaggedToParameter(SloppyTNode<Smi> value, ParameterMode mode) {
    if (mode != SMI_PARAMETERS) return SmiUntag(value);
133 134 135
    return value;
  }

jgruber's avatar
jgruber committed
136 137
  Node* MatchesParameterMode(Node* value, ParameterMode mode);

138 139 140 141 142 143 144 145
#define PARAMETER_BINOP(OpName, IntPtrOpName, SmiOpName) \
  Node* OpName(Node* a, Node* b, ParameterMode mode) {   \
    if (mode == SMI_PARAMETERS) {                        \
      return SmiOpName(a, b);                            \
    } else {                                             \
      DCHECK_EQ(INTPTR_PARAMETERS, mode);                \
      return IntPtrOpName(a, b);                         \
    }                                                    \
146
  }
147
  PARAMETER_BINOP(IntPtrOrSmiMin, IntPtrMin, SmiMin)
148
  PARAMETER_BINOP(IntPtrOrSmiAdd, IntPtrAdd, SmiAdd)
149
  PARAMETER_BINOP(IntPtrOrSmiSub, IntPtrSub, SmiSub)
150
  PARAMETER_BINOP(IntPtrOrSmiLessThan, IntPtrLessThan, SmiLessThan)
151 152
  PARAMETER_BINOP(IntPtrOrSmiLessThanOrEqual, IntPtrLessThanOrEqual,
                  SmiLessThanOrEqual)
153
  PARAMETER_BINOP(IntPtrOrSmiGreaterThan, IntPtrGreaterThan, SmiGreaterThan)
154
  PARAMETER_BINOP(IntPtrOrSmiGreaterThanOrEqual, IntPtrGreaterThanOrEqual,
155 156
                  SmiGreaterThanOrEqual)
  PARAMETER_BINOP(UintPtrOrSmiLessThan, UintPtrLessThan, SmiBelow)
157
  PARAMETER_BINOP(UintPtrOrSmiGreaterThanOrEqual, UintPtrGreaterThanOrEqual,
158
                  SmiAboveOrEqual)
159
#undef PARAMETER_BINOP
160

161
  Node* NoContextConstant();
162 163 164 165
#define HEAP_CONSTANT_ACCESSOR(rootIndexName, rootAccessorName, name) \
  compiler::TNode<std::remove_reference<decltype(                     \
      *std::declval<Heap>().rootAccessorName())>::type>               \
      name##Constant();
166 167 168
  HEAP_CONSTANT_LIST(HEAP_CONSTANT_ACCESSOR)
#undef HEAP_CONSTANT_ACCESSOR

169 170 171
#define HEAP_CONSTANT_TEST(rootIndexName, rootAccessorName, name) \
  TNode<BoolT> Is##name(SloppyTNode<Object> value);               \
  TNode<BoolT> IsNot##name(SloppyTNode<Object> value);
172 173 174
  HEAP_CONSTANT_LIST(HEAP_CONSTANT_TEST)
#undef HEAP_CONSTANT_TEST

175 176
  Node* HashSeed();
  Node* StaleRegisterConstant();
177

178
  Node* IntPtrOrSmiConstant(int value, ParameterMode mode);
179

180
  bool IsIntPtrOrSmiConstantZero(Node* test);
181
  bool TryGetIntPtrOrSmiConstantValue(Node* maybe_constant, int* value);
182

183
  // Round the 32bits payload of the provided word up to the next power of two.
184
  Node* IntPtrRoundUpToPowerOfTwo32(Node* value);
185
  // Select the maximum of the two provided IntPtr values.
186 187
  TNode<IntPtrT> IntPtrMax(SloppyTNode<IntPtrT> left,
                           SloppyTNode<IntPtrT> right);
188
  // Select the minimum of the two provided IntPtr values.
189 190
  TNode<IntPtrT> IntPtrMin(SloppyTNode<IntPtrT> left,
                           SloppyTNode<IntPtrT> right);
191

192
  // Float64 operations.
193 194 195 196 197
  TNode<Float64T> Float64Ceil(SloppyTNode<Float64T> x);
  TNode<Float64T> Float64Floor(SloppyTNode<Float64T> x);
  TNode<Float64T> Float64Round(SloppyTNode<Float64T> x);
  TNode<Float64T> Float64RoundToEven(SloppyTNode<Float64T> x);
  TNode<Float64T> Float64Trunc(SloppyTNode<Float64T> x);
198 199 200 201
  // Select the minimum of the two provided Number values.
  TNode<Object> NumberMax(SloppyTNode<Object> left, SloppyTNode<Object> right);
  // Select the minimum of the two provided Number values.
  TNode<Object> NumberMin(SloppyTNode<Object> left, SloppyTNode<Object> right);
202

203
  // Tag a Word as a Smi value.
204
  TNode<Smi> SmiTag(SloppyTNode<IntPtrT> value);
205
  // Untag a Smi value as a Word.
206
  TNode<IntPtrT> SmiUntag(SloppyTNode<Smi> value);
207

208
  // Smi conversions.
209 210 211 212 213
  TNode<Float64T> SmiToFloat64(SloppyTNode<Smi> value);
  TNode<Smi> SmiFromWord(SloppyTNode<IntPtrT> value) { return SmiTag(value); }
  TNode<Smi> SmiFromWord32(SloppyTNode<Int32T> value);
  TNode<IntPtrT> SmiToWord(SloppyTNode<Smi> value) { return SmiUntag(value); }
  TNode<Int32T> SmiToWord32(SloppyTNode<Smi> value);
214 215

  // Smi operations.
216
#define SMI_ARITHMETIC_BINOP(SmiOpName, IntPtrOpName)                  \
217
  TNode<Smi> SmiOpName(SloppyTNode<Smi> a, SloppyTNode<Smi> b) {       \
218 219 220 221 222 223 224
    return BitcastWordToTaggedSigned(                                  \
        IntPtrOpName(BitcastTaggedToWord(a), BitcastTaggedToWord(b))); \
  }
  SMI_ARITHMETIC_BINOP(SmiAdd, IntPtrAdd)
  SMI_ARITHMETIC_BINOP(SmiSub, IntPtrSub)
  SMI_ARITHMETIC_BINOP(SmiAnd, WordAnd)
  SMI_ARITHMETIC_BINOP(SmiOr, WordOr)
225
#undef SMI_ARITHMETIC_BINOP
226

227 228 229
  Node* SmiShl(Node* a, int shift) {
    return BitcastWordToTaggedSigned(WordShl(BitcastTaggedToWord(a), shift));
  }
230

231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253
  Node* SmiShr(Node* a, int shift) {
    return BitcastWordToTaggedSigned(
        WordAnd(WordShr(BitcastTaggedToWord(a), shift),
                BitcastTaggedToWord(SmiConstant(-1))));
  }

  Node* WordOrSmiShl(Node* a, int shift, ParameterMode mode) {
    if (mode == SMI_PARAMETERS) {
      return SmiShl(a, shift);
    } else {
      DCHECK_EQ(INTPTR_PARAMETERS, mode);
      return WordShl(a, shift);
    }
  }

  Node* WordOrSmiShr(Node* a, int shift, ParameterMode mode) {
    if (mode == SMI_PARAMETERS) {
      return SmiShr(a, shift);
    } else {
      DCHECK_EQ(INTPTR_PARAMETERS, mode);
      return WordShr(a, shift);
    }
  }
254 255 256 257 258 259

#define SMI_COMPARISON_OP(SmiOpName, IntPtrOpName)                       \
  Node* SmiOpName(Node* a, Node* b) {                                    \
    return IntPtrOpName(BitcastTaggedToWord(a), BitcastTaggedToWord(b)); \
  }
  SMI_COMPARISON_OP(SmiEqual, WordEqual)
260
  SMI_COMPARISON_OP(SmiNotEqual, WordNotEqual)
261 262 263 264 265 266
  SMI_COMPARISON_OP(SmiAbove, UintPtrGreaterThan)
  SMI_COMPARISON_OP(SmiAboveOrEqual, UintPtrGreaterThanOrEqual)
  SMI_COMPARISON_OP(SmiBelow, UintPtrLessThan)
  SMI_COMPARISON_OP(SmiLessThan, IntPtrLessThan)
  SMI_COMPARISON_OP(SmiLessThanOrEqual, IntPtrLessThanOrEqual)
  SMI_COMPARISON_OP(SmiGreaterThan, IntPtrGreaterThan)
267
  SMI_COMPARISON_OP(SmiGreaterThanOrEqual, IntPtrGreaterThanOrEqual)
268
#undef SMI_COMPARISON_OP
269 270
  TNode<Smi> SmiMax(SloppyTNode<Smi> a, SloppyTNode<Smi> b);
  TNode<Smi> SmiMin(SloppyTNode<Smi> a, SloppyTNode<Smi> b);
271
  // Computes a % b for Smi inputs a and b; result is not necessarily a Smi.
272
  Node* SmiMod(Node* a, Node* b);
273
  // Computes a * b for Smi inputs a and b; result is not necessarily a Smi.
274
  Node* SmiMul(Node* a, Node* b);
275 276 277
  // Tries to computes dividend / divisor for Smi inputs; branching to bailout
  // if the division needs to be performed as a floating point operation.
  Node* TrySmiDiv(Node* dividend, Node* divisor, Label* bailout);
278

279
  // Smi | HeapNumber operations.
280
  Node* NumberInc(Node* value);
281
  Node* NumberDec(Node* value);
282 283
  Node* NumberAdd(Node* a, Node* b);
  Node* NumberSub(Node* a, Node* b);
284 285
  void GotoIfNotNumber(Node* value, Label* is_not_number);
  void GotoIfNumber(Node* value, Label* is_number);
286

287
  // Allocate an object of the given size.
288 289
  Node* AllocateInNewSpace(Node* size, AllocationFlags flags = kNone);
  Node* AllocateInNewSpace(int size, AllocationFlags flags = kNone);
290 291 292 293 294 295
  Node* Allocate(Node* size, AllocationFlags flags = kNone);
  Node* Allocate(int size, AllocationFlags flags = kNone);
  Node* InnerAllocate(Node* previous, int offset);
  Node* InnerAllocate(Node* previous, Node* offset);
  Node* IsRegularHeapObjectSize(Node* size);

296 297
  typedef std::function<Node*()> NodeGenerator;

298 299 300 301 302 303 304 305 306 307 308 309 310 311 312
  void Assert(const NodeGenerator& condition_body,
              const char* message = nullptr, const char* file = nullptr,
              int line = 0, Node* extra_node1 = nullptr,
              const char* extra_node1_name = "", Node* extra_node2 = nullptr,
              const char* extra_node2_name = "", Node* extra_node3 = nullptr,
              const char* extra_node3_name = "", Node* extra_node4 = nullptr,
              const char* extra_node4_name = "", Node* extra_node5 = nullptr,
              const char* extra_node5_name = "");
  void Check(const NodeGenerator& condition_body, const char* message = nullptr,
             const char* file = nullptr, int line = 0,
             Node* extra_node1 = nullptr, const char* extra_node1_name = "",
             Node* extra_node2 = nullptr, const char* extra_node2_name = "",
             Node* extra_node3 = nullptr, const char* extra_node3_name = "",
             Node* extra_node4 = nullptr, const char* extra_node4_name = "",
             Node* extra_node5 = nullptr, const char* extra_node5_name = "");
313

314
  Node* Select(SloppyTNode<BoolT> condition, const NodeGenerator& true_body,
315
               const NodeGenerator& false_body, MachineRepresentation rep);
316 317 318 319 320 321 322 323 324 325 326 327 328
  template <class A, class F, class G>
  TNode<A> Select(SloppyTNode<BoolT> condition, const F& true_body,
                  const G& false_body, MachineRepresentation rep) {
    return UncheckedCast<A>(
        Select(condition,
               [&]() -> Node* {
                 return base::implicit_cast<SloppyTNode<A>>(true_body());
               },
               [&]() -> Node* {
                 return base::implicit_cast<SloppyTNode<A>>(false_body());
               },
               rep));
  }
329 330 331

  Node* SelectConstant(Node* condition, Node* true_value, Node* false_value,
                       MachineRepresentation rep);
332 333 334 335 336 337 338
  template <class A>
  TNode<A> SelectConstant(TNode<BoolT> condition, TNode<A> true_value,
                          TNode<A> false_value, MachineRepresentation rep) {
    return UncheckedCast<A>(
        SelectConstant(condition, static_cast<Node*>(true_value),
                       static_cast<Node*>(false_value), rep));
  }
339 340 341 342

  Node* SelectInt32Constant(Node* condition, int true_value, int false_value);
  Node* SelectIntPtrConstant(Node* condition, int true_value, int false_value);
  Node* SelectBooleanConstant(Node* condition);
343 344 345 346 347 348 349 350
  template <class A>
  TNode<A> SelectTaggedConstant(SloppyTNode<BoolT> condition,
                                TNode<A> true_value,
                                SloppyTNode<A> false_value) {
    static_assert(std::is_base_of<Object, A>::value, "not a tagged type");
    return SelectConstant(condition, true_value, false_value,
                          MachineRepresentation::kTagged);
  }
351 352 353 354 355 356 357 358 359 360 361
  Node* SelectSmiConstant(Node* condition, Smi* true_value, Smi* false_value);
  Node* SelectSmiConstant(Node* condition, int true_value, Smi* false_value) {
    return SelectSmiConstant(condition, Smi::FromInt(true_value), false_value);
  }
  Node* SelectSmiConstant(Node* condition, Smi* true_value, int false_value) {
    return SelectSmiConstant(condition, true_value, Smi::FromInt(false_value));
  }
  Node* SelectSmiConstant(Node* condition, int true_value, int false_value) {
    return SelectSmiConstant(condition, Smi::FromInt(true_value),
                             Smi::FromInt(false_value));
  }
362

363
  TNode<Int32T> TruncateWordToWord32(SloppyTNode<IntPtrT> value);
364

365
  // Check a value for smi-ness
366 367
  TNode<BoolT> TaggedIsSmi(SloppyTNode<Object> a);
  TNode<BoolT> TaggedIsNotSmi(SloppyTNode<Object> a);
368
  // Check that the value is a non-negative smi.
369
  TNode<BoolT> TaggedIsPositiveSmi(SloppyTNode<Object> a);
370
  // Check that a word has a word-aligned address.
371 372
  TNode<BoolT> WordIsWordAligned(SloppyTNode<WordT> word);
  TNode<BoolT> WordIsPowerOfTwo(SloppyTNode<IntPtrT> value);
373

374 375
  Node* IsNotTheHole(Node* value) { return Word32BinaryNot(IsTheHole(value)); }

376 377 378 379 380 381
#if DEBUG
  void Bind(Label* label, AssemblerDebugInfo debug_info);
#else
  void Bind(Label* label);
#endif  // DEBUG

382
  void BranchIfSmiEqual(Node* a, Node* b, Label* if_true, Label* if_false) {
383
    Branch(SmiEqual(a, b), if_true, if_false);
384 385
  }

386
  void BranchIfSmiLessThan(Node* a, Node* b, Label* if_true, Label* if_false) {
387
    Branch(SmiLessThan(a, b), if_true, if_false);
388 389
  }

390 391
  void BranchIfSmiLessThanOrEqual(Node* a, Node* b, Label* if_true,
                                  Label* if_false) {
392
    Branch(SmiLessThanOrEqual(a, b), if_true, if_false);
393 394
  }

395
  void BranchIfFloat64IsNaN(Node* value, Label* if_true, Label* if_false) {
396
    Branch(Float64Equal(value, value), if_false, if_true);
397 398
  }

399 400
  // Branches to {if_true} if ToBoolean applied to {value} yields true,
  // otherwise goes to {if_false}.
401
  void BranchIfToBooleanIsTrue(Node* value, Label* if_true, Label* if_false);
402

403 404
  void BranchIfJSReceiver(Node* object, Label* if_true, Label* if_false);
  void BranchIfJSObject(Node* object, Label* if_true, Label* if_false);
405

406
  void BranchIfFastJSArray(Node* object, Node* context, Label* if_true,
407
                           Label* if_false);
408 409
  void BranchIfFastJSArrayForCopy(Node* object, Node* context, Label* if_true,
                                  Label* if_false);
410

411
  // Load value from current frame by given offset in bytes.
412
  Node* LoadFromFrame(int offset, MachineType rep = MachineType::AnyTagged());
413
  // Load value from current parent frame by given offset in bytes.
414 415
  Node* LoadFromParentFrame(int offset,
                            MachineType rep = MachineType::AnyTagged());
416

417
  // Load an object pointer from a buffer that isn't in the heap.
418 419
  Node* LoadBufferObject(Node* buffer, int offset,
                         MachineType rep = MachineType::AnyTagged());
420
  // Load a field from an object on the heap.
421 422 423 424 425 426 427 428 429 430 431 432 433
  Node* LoadObjectField(SloppyTNode<HeapObject> object, int offset,
                        MachineType rep);
  TNode<Object> LoadObjectField(SloppyTNode<HeapObject> object, int offset) {
    return UncheckedCast<Object>(
        LoadObjectField(object, offset, MachineType::AnyTagged()));
  }
  Node* LoadObjectField(SloppyTNode<HeapObject> object,
                        SloppyTNode<IntPtrT> offset, MachineType rep);
  TNode<Object> LoadObjectField(SloppyTNode<HeapObject> object,
                                SloppyTNode<IntPtrT> offset) {
    return UncheckedCast<Object>(
        LoadObjectField(object, offset, MachineType::AnyTagged()));
  }
434
  // Load a SMI field and untag it.
435 436
  TNode<IntPtrT> LoadAndUntagObjectField(SloppyTNode<HeapObject> object,
                                         int offset);
437
  // Load a SMI field, untag it, and convert to Word32.
438
  TNode<Int32T> LoadAndUntagToWord32ObjectField(Node* object, int offset);
439
  // Load a SMI and untag it.
440
  TNode<IntPtrT> LoadAndUntagSmi(Node* base, int index);
441
  // Load a SMI root, untag it, and convert to Word32.
442
  Node* LoadAndUntagToWord32Root(Heap::RootListIndex root_index);
443

444 445 446
  // Tag a smi and store it.
  Node* StoreAndTagSmi(Node* base, int offset, Node* value);

447
  // Load the floating point value of a HeapNumber.
448
  TNode<Float64T> LoadHeapNumberValue(SloppyTNode<HeapNumber> object);
449
  // Load the Map of an HeapObject.
450
  TNode<Map> LoadMap(SloppyTNode<HeapObject> object);
451
  // Load the instance type of an HeapObject.
452
  TNode<Int32T> LoadInstanceType(SloppyTNode<HeapObject> object);
453
  // Compare the instance the type of the object against the provided one.
454
  Node* HasInstanceType(Node* object, InstanceType type);
455
  Node* DoesntHaveInstanceType(Node* object, InstanceType type);
456
  Node* TaggedDoesntHaveInstanceType(Node* any_tagged, InstanceType type);
457
  // Load the properties backing store of a JSObject.
458 459
  TNode<HeapObject> LoadSlowProperties(SloppyTNode<JSObject> object);
  TNode<HeapObject> LoadFastProperties(SloppyTNode<JSObject> object);
460 461 462
  // Load the hash from the backing store of a JSObject.
  TNode<Int32T> LoadHashForJSObject(SloppyTNode<JSObject> jsobject,
                                    SloppyTNode<Int32T> instance_type);
463
  // Load the elements backing store of a JSObject.
464
  TNode<FixedArrayBase> LoadElements(SloppyTNode<JSObject> object);
465
  // Load the length of a JSArray instance.
466 467 468
  TNode<Object> LoadJSArrayLength(SloppyTNode<JSArray> array);
  // Load the length of a fast JSArray instance. Returns a positive Smi.
  TNode<Smi> LoadFastJSArrayLength(SloppyTNode<JSArray> array);
469
  // Load the length of a fixed array base instance.
470
  TNode<Smi> LoadFixedArrayBaseLength(SloppyTNode<FixedArrayBase> array);
471
  // Load the length of a fixed array base instance.
472 473
  TNode<IntPtrT> LoadAndUntagFixedArrayBaseLength(
      SloppyTNode<FixedArrayBase> array);
474
  // Load the bit field of a Map.
475
  TNode<Int32T> LoadMapBitField(SloppyTNode<Map> map);
476
  // Load bit field 2 of a map.
477
  TNode<Int32T> LoadMapBitField2(SloppyTNode<Map> map);
478
  // Load bit field 3 of a map.
479
  TNode<Uint32T> LoadMapBitField3(SloppyTNode<Map> map);
480
  // Load the instance type of a map.
481
  TNode<Int32T> LoadMapInstanceType(SloppyTNode<Map> map);
482
  // Load the ElementsKind of a map.
483
  TNode<Int32T> LoadMapElementsKind(SloppyTNode<Map> map);
484
  // Load the instance descriptors of a map.
485
  TNode<DescriptorArray> LoadMapDescriptors(SloppyTNode<Map> map);
486
  // Load the prototype of a map.
487
  TNode<Object> LoadMapPrototype(SloppyTNode<Map> map);
488 489
  // Load the prototype info of a map. The result has to be checked if it is a
  // prototype info object or not.
490 491
  TNode<PrototypeInfo> LoadMapPrototypeInfo(SloppyTNode<Map> map,
                                            Label* if_has_no_proto_info);
492
  // Load the instance size of a Map.
493
  TNode<IntPtrT> LoadMapInstanceSize(SloppyTNode<Map> map);
494
  // Load the inobject properties count of a Map (valid only for JSObjects).
495
  TNode<IntPtrT> LoadMapInobjectProperties(SloppyTNode<Map> map);
496
  // Load the constructor function index of a Map (only for primitive maps).
497 498 499
  TNode<IntPtrT> LoadMapConstructorFunctionIndex(SloppyTNode<Map> map);
  // Load the constructor of a Map (equivalent to Map::GetConstructor()).
  TNode<Object> LoadMapConstructor(SloppyTNode<Map> map);
500 501
  // Load the EnumLength of a Map.
  Node* LoadMapEnumLength(SloppyTNode<Map> map);
502

503 504 505 506 507
  // This is only used on a newly allocated PropertyArray which
  // doesn't have an existing hash.
  void InitializePropertyArrayLength(Node* property_array, Node* length,
                                     ParameterMode mode);

508
  // Check if the map is set for slow properties.
509
  TNode<BoolT> IsDictionaryMap(SloppyTNode<Map> map);
510

511
  // Load the hash field of a name as an uint32 value.
512
  Node* LoadNameHashField(Node* name);
513 514 515
  // Load the hash value of a name as an uint32 value.
  // If {if_hash_not_computed} label is specified then it also checks if
  // hash is actually computed.
516
  Node* LoadNameHash(Node* name, Label* if_hash_not_computed = nullptr);
517 518

  // Load length field of a String object.
519
  Node* LoadStringLength(Node* object);
520 521
  // Loads a pointer to the sequential String char array.
  Node* PointerToSeqStringData(Node* seq_string);
522
  // Load value field of a JSValue object.
523
  Node* LoadJSValueValue(Node* object);
524
  // Load value field of a WeakCell object.
525 526
  Node* LoadWeakCellValueUnchecked(Node* weak_cell);
  Node* LoadWeakCellValue(Node* weak_cell, Label* if_cleared = nullptr);
527

528
  // Load an array element from a FixedArray.
529 530 531
  Node* LoadFixedArrayElement(Node* object, Node* index,
                              int additional_offset = 0,
                              ParameterMode parameter_mode = INTPTR_PARAMETERS);
532 533 534
  Node* LoadFixedArrayElement(Node* object, int index,
                              int additional_offset = 0) {
    return LoadFixedArrayElement(object, IntPtrConstant(index),
535
                                 additional_offset);
536
  }
537
  // Load an array element from a FixedArray, untag it and return it as Word32.
538 539
  Node* LoadAndUntagToWord32FixedArrayElement(
      Node* object, Node* index, int additional_offset = 0,
540
      ParameterMode parameter_mode = INTPTR_PARAMETERS);
541
  // Load an array element from a FixedDoubleArray.
542 543
  Node* LoadFixedDoubleArrayElement(
      Node* object, Node* index, MachineType machine_type,
544
      int additional_offset = 0,
545
      ParameterMode parameter_mode = INTPTR_PARAMETERS,
546 547
      Label* if_hole = nullptr);

548 549 550 551 552
  // Load a feedback slot from a FeedbackVector.
  Node* LoadFeedbackVectorSlot(
      Node* object, Node* index, int additional_offset = 0,
      ParameterMode parameter_mode = INTPTR_PARAMETERS);

553 554 555
  // Load Float64 value by |base| + |offset| address. If the value is a double
  // hole then jump to |if_hole|. If |machine_type| is None then only the hole
  // check is generated.
556 557
  Node* LoadDoubleWithHoleCheck(
      Node* base, Node* offset, Label* if_hole,
558
      MachineType machine_type = MachineType::Float64());
559 560
  Node* LoadFixedTypedArrayElement(
      Node* data_pointer, Node* index_node, ElementsKind elements_kind,
561 562 563
      ParameterMode parameter_mode = INTPTR_PARAMETERS);
  Node* LoadFixedTypedArrayElementAsTagged(
      Node* data_pointer, Node* index_node, ElementsKind elements_kind,
564
      ParameterMode parameter_mode = INTPTR_PARAMETERS);
565

566
  // Context manipulation
567 568 569 570
  Node* LoadContextElement(Node* context, int slot_index);
  Node* LoadContextElement(Node* context, Node* slot_index);
  Node* StoreContextElement(Node* context, int slot_index, Node* value);
  Node* StoreContextElement(Node* context, Node* slot_index, Node* value);
571 572
  Node* StoreContextElementNoWriteBarrier(Node* context, int slot_index,
                                          Node* value);
573 574 575
  Node* LoadNativeContext(Node* context);

  Node* LoadJSArrayElementsMap(ElementsKind kind, Node* native_context);
576
  Node* LoadJSArrayElementsMap(Node* kind, Node* native_context);
577

578 579 580
  // Load the "prototype" property of a JSFunction.
  Node* LoadJSFunctionPrototype(Node* function, Label* if_bailout);

581
  // Store the floating point value of a HeapNumber.
582
  Node* StoreHeapNumberValue(Node* object, Node* value);
583
  // Store a field to an object on the heap.
584 585 586 587
  Node* StoreObjectField(Node* object, int offset, Node* value);
  Node* StoreObjectField(Node* object, Node* offset, Node* value);
  Node* StoreObjectFieldNoWriteBarrier(
      Node* object, int offset, Node* value,
588
      MachineRepresentation rep = MachineRepresentation::kTagged);
589 590
  Node* StoreObjectFieldNoWriteBarrier(
      Node* object, Node* offset, Node* value,
591
      MachineRepresentation rep = MachineRepresentation::kTagged);
592
  // Store the Map of an HeapObject.
593 594 595
  Node* StoreMap(Node* object, Node* map);
  Node* StoreMapNoWriteBarrier(Node* object,
                               Heap::RootListIndex map_root_index);
596 597 598
  Node* StoreMapNoWriteBarrier(Node* object, Node* map);
  Node* StoreObjectFieldRoot(Node* object, int offset,
                             Heap::RootListIndex root);
599
  // Store an array element to a FixedArray.
600 601
  Node* StoreFixedArrayElement(
      Node* object, int index, Node* value,
602 603
      WriteBarrierMode barrier_mode = UPDATE_WRITE_BARRIER) {
    return StoreFixedArrayElement(object, IntPtrConstant(index), value,
604
                                  barrier_mode);
605 606
  }

607 608
  Node* StoreFixedArrayElement(
      Node* object, Node* index, Node* value,
609
      WriteBarrierMode barrier_mode = UPDATE_WRITE_BARRIER,
610
      int additional_offset = 0,
611
      ParameterMode parameter_mode = INTPTR_PARAMETERS);
612

613 614
  Node* StoreFixedDoubleArrayElement(
      Node* object, Node* index, Node* value,
615
      ParameterMode parameter_mode = INTPTR_PARAMETERS);
616

617 618 619 620 621 622
  Node* StoreFeedbackVectorSlot(
      Node* object, Node* index, Node* value,
      WriteBarrierMode barrier_mode = UPDATE_WRITE_BARRIER,
      int additional_offset = 0,
      ParameterMode parameter_mode = INTPTR_PARAMETERS);

623 624
  void EnsureArrayLengthWritable(Node* map, Label* bailout);

625 626 627 628 629 630 631 632 633 634 635
  // EnsureArrayPushable verifies that receiver is:
  //   1. Is not a prototype.
  //   2. Is not a dictionary.
  //   3. Has a writeable length property.
  // It returns ElementsKind as a node for further division into cases.
  Node* EnsureArrayPushable(Node* receiver, Label* bailout);

  void TryStoreArrayElement(ElementsKind kind, ParameterMode mode,
                            Label* bailout, Node* elements, Node* index,
                            Node* value);
  // Consumes args into the array, and returns tagged new length.
636 637 638
  TNode<Smi> BuildAppendJSArray(ElementsKind kind, SloppyTNode<JSArray> array,
                                CodeStubArguments* args,
                                TVariable<IntPtrT>* arg_index, Label* bailout);
639 640 641
  // Pushes value onto the end of array.
  void BuildAppendJSArray(ElementsKind kind, Node* array, Node* value,
                          Label* bailout);
642

643 644
  void StoreFieldsNoWriteBarrier(Node* start_address, Node* end_address,
                                 Node* value);
645

646 647 648 649 650 651 652 653 654 655 656
  Node* AllocateCellWithValue(Node* value,
                              WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
  Node* AllocateSmiCell(int value = 0) {
    return AllocateCellWithValue(SmiConstant(value), SKIP_WRITE_BARRIER);
  }

  Node* LoadCellValue(Node* cell);

  Node* StoreCellValue(Node* cell, Node* value,
                       WriteBarrierMode mode = UPDATE_WRITE_BARRIER);

657
  // Allocate a HeapNumber without initializing its value.
658
  Node* AllocateHeapNumber(MutableMode mode = IMMUTABLE);
659
  // Allocate a HeapNumber with a specific value.
660
  Node* AllocateHeapNumberWithValue(Node* value, MutableMode mode = IMMUTABLE);
661
  // Allocate a SeqOneByteString with the given length.
662 663 664 665
  Node* AllocateSeqOneByteString(int length, AllocationFlags flags = kNone);
  Node* AllocateSeqOneByteString(Node* context, Node* length,
                                 ParameterMode mode = INTPTR_PARAMETERS,
                                 AllocationFlags flags = kNone);
666
  // Allocate a SeqTwoByteString with the given length.
667 668 669 670
  Node* AllocateSeqTwoByteString(int length, AllocationFlags flags = kNone);
  Node* AllocateSeqTwoByteString(Node* context, Node* length,
                                 ParameterMode mode = INTPTR_PARAMETERS,
                                 AllocationFlags flags = kNone);
671 672 673

  // Allocate a SlicedOneByteString with the given length, parent and offset.
  // |length| and |offset| are expected to be tagged.
674
  Node* AllocateSlicedOneByteString(Node* length, Node* parent, Node* offset);
675 676
  // Allocate a SlicedTwoByteString with the given length, parent and offset.
  // |length| and |offset| are expected to be tagged.
677
  Node* AllocateSlicedTwoByteString(Node* length, Node* parent, Node* offset);
678

679 680 681
  // Allocate a one-byte ConsString with the given length, first and second
  // parts. |length| is expected to be tagged, and |first| and |second| are
  // expected to be one-byte strings.
682 683
  Node* AllocateOneByteConsString(Node* length, Node* first, Node* second,
                                  AllocationFlags flags = kNone);
684 685 686
  // Allocate a two-byte ConsString with the given length, first and second
  // parts. |length| is expected to be tagged, and |first| and |second| are
  // expected to be two-byte strings.
687 688
  Node* AllocateTwoByteConsString(Node* length, Node* first, Node* second,
                                  AllocationFlags flags = kNone);
689 690 691

  // Allocate an appropriate one- or two-byte ConsString with the first and
  // second parts specified by |first| and |second|.
692 693
  Node* NewConsString(Node* context, Node* length, Node* left, Node* right,
                      AllocationFlags flags = kNone);
694

695 696 697
  Node* AllocateNameDictionary(int at_least_space_for);
  Node* AllocateNameDictionary(Node* at_least_space_for);
  Node* AllocateNameDictionaryWithCapacity(Node* capacity);
698
  Node* CopyNameDictionary(Node* dictionary, Label* large_object_fallback);
699

700 701 702
  Node* AllocateStruct(Node* map, AllocationFlags flags = kNone);
  void InitializeStructBody(Node* object, Node* map, Node* size,
                            int start_offset = Struct::kHeaderSize);
703
  Node* AllocateJSObjectFromMap(Node* map, Node* properties = nullptr,
704 705
                                Node* elements = nullptr,
                                AllocationFlags flags = kNone);
706

707 708 709
  void InitializeJSObjectFromMap(Node* object, Node* map, Node* size,
                                 Node* properties = nullptr,
                                 Node* elements = nullptr);
710

711
  void InitializeJSObjectBody(Node* object, Node* map, Node* size,
712 713
                              int start_offset = JSObject::kHeaderSize);

714
  // Allocate a JSArray without elements and initialize the header fields.
715
  Node* AllocateUninitializedJSArrayWithoutElements(Node* array_map,
716 717
                                                    Node* length,
                                                    Node* allocation_site);
718 719 720
  // Allocate and return a JSArray with initialized header fields and its
  // uninitialized elements.
  // The ParameterMode argument is only used for the capacity parameter.
721 722
  std::pair<Node*, Node*> AllocateUninitializedJSArrayWithElements(
      ElementsKind kind, Node* array_map, Node* length, Node* allocation_site,
723
      Node* capacity, ParameterMode capacity_mode = INTPTR_PARAMETERS);
724 725
  // Allocate a JSArray and fill elements with the hole.
  // The ParameterMode argument is only used for the capacity parameter.
726 727
  Node* AllocateJSArray(ElementsKind kind, Node* array_map, Node* capacity,
                        Node* length, Node* allocation_site = nullptr,
728
                        ParameterMode capacity_mode = INTPTR_PARAMETERS);
729

730
  Node* AllocateFixedArray(ElementsKind kind, Node* capacity,
731
                           ParameterMode mode = INTPTR_PARAMETERS,
732
                           AllocationFlags flags = kNone);
733

734 735 736
  Node* AllocatePropertyArray(Node* capacity,
                              ParameterMode mode = INTPTR_PARAMETERS,
                              AllocationFlags flags = kNone);
737
  // Perform CreateArrayIterator (ES6 #sec-createarrayiterator).
738 739 740 741
  Node* CreateArrayIterator(Node* array, Node* array_map, Node* array_type,
                            Node* context, IterationKind mode);

  Node* AllocateJSArrayIterator(Node* array, Node* array_map, Node* map);
742 743
  Node* AllocateJSIteratorResult(Node* context, Node* value, Node* done);
  Node* AllocateJSIteratorResultForEntry(Node* context, Node* key, Node* value);
744

745 746 747
  Node* TypedArraySpeciesCreateByLength(Node* context, Node* originalArray,
                                        Node* len);

748 749
  void FillFixedArrayWithValue(ElementsKind kind, Node* array, Node* from_index,
                               Node* to_index,
750
                               Heap::RootListIndex value_root_index,
751
                               ParameterMode mode = INTPTR_PARAMETERS);
752

753 754 755 756 757 758 759 760 761
  void FillPropertyArrayWithUndefined(Node* array, Node* from_index,
                                      Node* to_index,
                                      ParameterMode mode = INTPTR_PARAMETERS);

  void CopyPropertyArrayValues(
      Node* from_array, Node* to_array, Node* length,
      WriteBarrierMode barrier_mode = UPDATE_WRITE_BARRIER,
      ParameterMode mode = INTPTR_PARAMETERS);

762 763
  // Copies all elements from |from_array| of |length| size to
  // |to_array| of the same size respecting the elements kind.
764
  void CopyFixedArrayElements(
765
      ElementsKind kind, Node* from_array, Node* to_array, Node* length,
766
      WriteBarrierMode barrier_mode = UPDATE_WRITE_BARRIER,
767
      ParameterMode mode = INTPTR_PARAMETERS) {
768 769 770 771 772 773 774
    CopyFixedArrayElements(kind, from_array, kind, to_array, length, length,
                           barrier_mode, mode);
  }

  // Copies |element_count| elements from |from_array| to |to_array| of
  // |capacity| size respecting both array's elements kinds.
  void CopyFixedArrayElements(
775 776
      ElementsKind from_kind, Node* from_array, ElementsKind to_kind,
      Node* to_array, Node* element_count, Node* capacity,
777
      WriteBarrierMode barrier_mode = UPDATE_WRITE_BARRIER,
778
      ParameterMode mode = INTPTR_PARAMETERS);
779

780
  // Copies |character_count| elements from |from_string| to |to_string|
781
  // starting at the |from_index|'th character. |from_string| and |to_string|
782 783
  // can either be one-byte strings or two-byte strings, although if
  // |from_string| is two-byte, then |to_string| must be two-byte.
784 785 786 787
  // |from_index|, |to_index| and |character_count| must be either Smis or
  // intptr_ts depending on |mode| s.t. 0 <= |from_index| <= |from_index| +
  // |character_count| <= from_string.length and 0 <= |to_index| <= |to_index| +
  // |character_count| <= to_string.length.
788 789 790
  void CopyStringCharacters(Node* from_string, Node* to_string,
                            Node* from_index, Node* to_index,
                            Node* character_count,
791 792
                            String::Encoding from_encoding,
                            String::Encoding to_encoding, ParameterMode mode);
793

794 795 796 797
  // Loads an element from |array| of |from_kind| elements by given |offset|
  // (NOTE: not index!), does a hole check if |if_hole| is provided and
  // converts the value so that it becomes ready for storing to array of
  // |to_kind| elements.
798 799 800
  Node* LoadElementAndPrepareForStore(Node* array, Node* offset,
                                      ElementsKind from_kind,
                                      ElementsKind to_kind, Label* if_hole);
801

802
  Node* CalculateNewElementsCapacity(Node* old_capacity,
803
                                     ParameterMode mode = INTPTR_PARAMETERS);
804

805 806
  // Tries to grow the |elements| array of given |object| to store the |key|
  // or bails out if the growing gap is too big. Returns new elements.
807 808
  Node* TryGrowElementsCapacity(Node* object, Node* elements, ElementsKind kind,
                                Node* key, Label* bailout);
809 810 811 812

  // Tries to grow the |capacity|-length |elements| array of given |object|
  // to store the |key| or bails out if the growing gap is too big. Returns
  // new elements.
813 814 815
  Node* TryGrowElementsCapacity(Node* object, Node* elements, ElementsKind kind,
                                Node* key, Node* capacity, ParameterMode mode,
                                Label* bailout);
816 817

  // Grows elements capacity of given object. Returns new elements.
818 819 820 821
  Node* GrowElementsCapacity(Node* object, Node* elements,
                             ElementsKind from_kind, ElementsKind to_kind,
                             Node* capacity, Node* new_capacity,
                             ParameterMode mode, Label* bailout);
822

823 824 825 826 827 828 829 830
  // Given a need to grow by |growth|, allocate an appropriate new capacity
  // if necessary, and return a new elements FixedArray object. Label |bailout|
  // is followed for allocation failure.
  void PossiblyGrowElementsCapacity(ParameterMode mode, ElementsKind kind,
                                    Node* array, Node* length,
                                    Variable* var_elements, Node* growth,
                                    Label* bailout);

831
  // Allocation site manipulation
832
  void InitializeAllocationMemento(Node* base_allocation,
833
                                   Node* base_allocation_size,
834 835 836 837 838
                                   Node* allocation_site);

  Node* TryTaggedToFloat64(Node* value, Label* if_valueisnotnumber);
  Node* TruncateTaggedToFloat64(Node* context, Node* value);
  Node* TruncateTaggedToWord32(Node* context, Node* value);
839
  // Truncate the floating point value of a HeapNumber to an Int32.
840
  Node* TruncateHeapNumberValueToWord32(Node* object);
841 842

  // Conversions.
843 844 845
  Node* ChangeFloat64ToTagged(Node* value);
  Node* ChangeInt32ToTagged(Node* value);
  Node* ChangeUint32ToTagged(Node* value);
846
  Node* ChangeNumberToFloat64(Node* value);
847
  Node* ChangeNumberToIntPtr(Node* value);
848

849 850
  Node* TimesPointerSize(Node* value);

851 852 853
  // Type conversions.
  // Throws a TypeError for {method_name} if {value} is not coercible to Object,
  // or returns the {value} converted to a String otherwise.
854
  Node* ToThisString(Node* context, Node* value, char const* method_name);
855 856 857
  // Throws a TypeError for {method_name} if {value} is neither of the given
  // {primitive_type} nor a JSValue wrapping a value of {primitive_type}, or
  // returns the {value} (or wrapped value) otherwise.
858 859
  Node* ToThisValue(Node* context, Node* value, PrimitiveType primitive_type,
                    char const* method_name);
860

861 862 863 864
  // Throws a TypeError for {method_name}. Terminates the current block.
  void ThrowIncompatibleMethodReceiver(Node* context, char const* method_name,
                                       Node* receiver);

865 866
  // Throws a TypeError for {method_name} if {value} is not of the given
  // instance type. Returns {value}'s map.
867 868 869
  Node* ThrowIfNotInstanceType(Node* context, Node* value,
                               InstanceType instance_type,
                               char const* method_name);
870 871 872 873
  void ThrowTypeError(Node* context, MessageTemplate::Template message,
                      char const* arg0 = nullptr, char const* arg1 = nullptr);
  void ThrowTypeError(Node* context, MessageTemplate::Template message,
                      Node* arg0, Node* arg1 = nullptr, Node* arg2 = nullptr);
874

875
  // Type checks.
876 877
  // Check whether the map is for an object with special properties, such as a
  // JSProxy or an object with interceptors.
878
  Node* InstanceTypeEqual(Node* instance_type, int type);
879 880 881 882
  Node* IsAccessorInfo(Node* object);
  Node* IsAccessorPair(Node* object);
  Node* IsAllocationSite(Node* object);
  Node* IsAnyHeapNumber(Node* object);
883
  Node* IsArrayIteratorInstanceType(Node* instance_type);
884
  Node* IsBoolean(Node* object);
885
  Node* IsExtensibleMap(Node* map);
886 887
  Node* IsCallableMap(Node* map);
  Node* IsCallable(Node* object);
888
  Node* IsCell(Node* object);
889
  Node* IsConsStringInstanceType(Node* instance_type);
890
  Node* IsConstructorMap(Node* map);
891
  Node* IsConstructor(Node* object);
892
  Node* IsFunctionWithPrototypeSlotMap(Node* map);
893 894 895 896 897 898 899 900 901
  Node* IsDeprecatedMap(Node* map);
  Node* IsDictionary(Node* object);
  Node* IsExternalStringInstanceType(Node* instance_type);
  Node* IsFeedbackVector(Node* object);
  Node* IsFixedArray(Node* object);
  Node* IsFixedArrayWithKind(Node* object, ElementsKind kind);
  Node* IsFixedArrayWithKindOrEmpty(Node* object, ElementsKind kind);
  Node* IsFixedDoubleArray(Node* object);
  Node* IsFixedTypedArray(Node* object);
902
  Node* IsZeroOrFixedArray(Node* object);
903 904
  Node* IsHashTable(Node* object);
  Node* IsHeapNumber(Node* object);
905
  Node* IsIndirectStringInstanceType(Node* instance_type);
906 907 908 909 910 911 912 913
  Node* IsJSArrayBuffer(Node* object);
  Node* IsJSArrayInstanceType(Node* instance_type);
  Node* IsJSArrayMap(Node* object);
  Node* IsJSArray(Node* object);
  Node* IsJSFunctionInstanceType(Node* instance_type);
  Node* IsJSFunctionMap(Node* object);
  Node* IsJSFunction(Node* object);
  Node* IsJSGlobalProxy(Node* object);
914
  Node* IsJSObjectInstanceType(Node* instance_type);
915
  Node* IsJSObjectMap(Node* map);
916
  Node* IsJSObject(Node* object);
917
  Node* IsJSGlobalProxyInstanceType(Node* instance_type);
918
  Node* IsJSProxy(Node* object);
919
  Node* IsJSReceiverInstanceType(Node* instance_type);
920
  Node* IsJSReceiverMap(Node* map);
921
  Node* IsJSReceiver(Node* object);
922
  Node* IsNullOrJSReceiver(Node* object);
923 924 925 926 927
  Node* IsJSRegExp(Node* object);
  Node* IsJSTypedArray(Node* object);
  Node* IsJSValueInstanceType(Node* instance_type);
  Node* IsJSValueMap(Node* map);
  Node* IsJSValue(Node* object);
928
  Node* IsMap(Node* object);
929
  Node* IsMutableHeapNumber(Node* object);
930
  Node* IsName(Node* object);
931 932
  Node* IsNativeContext(Node* object);
  Node* IsOneByteStringInstanceType(Node* instance_type);
933
  Node* IsPrimitiveInstanceType(Node* instance_type);
934
  Node* IsPrivateSymbol(Node* object);
935
  Node* IsPropertyArray(Node* object);
936 937
  Node* IsPropertyCell(Node* object);
  Node* IsSequentialStringInstanceType(Node* instance_type);
938 939 940
  inline Node* IsSharedFunctionInfo(Node* object) {
    return IsSharedFunctionInfoMap(LoadMap(object));
  }
941 942 943 944 945
  Node* IsShortExternalStringInstanceType(Node* instance_type);
  Node* IsSpecialReceiverInstanceType(Node* instance_type);
  Node* IsSpecialReceiverMap(Node* map);
  Node* IsStringInstanceType(Node* instance_type);
  Node* IsString(Node* object);
946
  Node* IsSymbolInstanceType(Node* instance_type);
947
  Node* IsSymbol(Node* object);
948 949
  Node* IsBigIntInstanceType(Node* instance_type);
  Node* IsBigInt(Node* object);
950
  Node* IsUnseededNumberDictionary(Node* object);
951
  Node* IsWeakCell(Node* object);
952
  Node* IsUndetectableMap(Node* map);
953
  Node* IsArrayProtectorCellInvalid();
954 955
  Node* IsSpeciesProtectorCellInvalid();
  Node* IsPrototypeInitialArrayPrototype(Node* context, Node* map);
956

957 958
  // True iff |object| is a Smi or a HeapNumber.
  Node* IsNumber(Node* object);
959 960
  // True iff |object| is a Smi or a HeapNumber or a BigInt.
  Node* IsNumeric(Node* object);
961 962 963 964

  // True iff |number| is either a Smi, or a HeapNumber whose value is not
  // within Smi range.
  Node* IsNumberNormalized(Node* number);
965
  Node* IsNumberPositive(Node* number);
966 967 968
  // True iff {number} is a positive number and a valid array index in the range
  // [0, 2^32-1).
  Node* IsNumberArrayIndex(Node* number);
969

970
  // ElementsKind helpers:
971 972
  Node* IsFastElementsKind(Node* elements_kind);
  Node* IsHoleyFastElementsKind(Node* elements_kind);
973 974
  Node* IsElementsKindGreaterThan(Node* target_kind,
                                  ElementsKind reference_kind);
975

976 977
  // String helpers.
  // Load a character from a String (might flatten a ConsString).
978 979 980
  TNode<Uint32T> StringCharCodeAt(
      SloppyTNode<String> string, Node* index,
      ParameterMode parameter_mode = SMI_PARAMETERS);
981
  // Return the single character string with only {code}.
982
  Node* StringFromCharCode(Node* code);
983 984 985

  enum class SubStringFlags { NONE, FROM_TO_ARE_BOUNDED };

986 987
  // Return a new string object which holds a substring containing the range
  // [from,to[ of string.  |from| and |to| are expected to be tagged.
988 989 990 991
  // If flags has the value FROM_TO_ARE_BOUNDED then from and to are in
  // the range [0, string-length)
  Node* SubString(Node* context, Node* string, Node* from, Node* to,
                  SubStringFlags flags = SubStringFlags::NONE);
992

993
  // Return a new string object produced by concatenating |first| with |second|.
994 995
  Node* StringAdd(Node* context, Node* first, Node* second,
                  AllocationFlags flags = kNone);
996

997 998 999 1000 1001 1002
  // Check if |string| is an indirect (thin or flat cons) string type that can
  // be dereferenced by DerefIndirectString.
  void BranchIfCanDerefIndirectString(Node* string, Node* instance_type,
                                      Label* can_deref, Label* cannot_deref);
  // Unpack an indirect (thin or flat cons) string type.
  void DerefIndirectString(Variable* var_string, Node* instance_type);
1003 1004 1005
  // Check if |var_string| has an indirect (thin or flat cons) string type,
  // and unpack it if so.
  void MaybeDerefIndirectString(Variable* var_string, Node* instance_type,
1006
                                Label* did_deref, Label* cannot_deref);
1007 1008 1009 1010 1011 1012
  // Check if |var_left| or |var_right| has an indirect (thin or flat cons)
  // string type, and unpack it/them if so. Fall through if nothing was done.
  void MaybeDerefIndirectStrings(Variable* var_left, Node* left_instance_type,
                                 Variable* var_right, Node* right_instance_type,
                                 Label* did_something);

1013
  Node* StringFromCodePoint(Node* codepoint, UnicodeEncoding encoding);
1014

1015 1016
  // Type conversion helpers.
  // Convert a String to a Number.
1017 1018
  Node* StringToNumber(Node* context, Node* input);
  Node* NumberToString(Node* context, Node* input);
1019
  // Convert an object to a name.
1020
  Node* ToName(Node* context, Node* input);
1021
  // Convert a Non-Number object to a Number.
1022
  Node* NonNumberToNumber(Node* context, Node* input);
1023 1024
  // Convert a Non-Number object to a Numeric.
  Node* NonNumberToNumeric(Node* context, Node* input);
1025
  // Convert any object to a Number.
1026
  Node* ToNumber(Node* context, Node* input);
1027

1028
  // Converts |input| to one of 2^32 integer values in the range 0 through
1029
  // 2^32-1, inclusive.
1030
  // ES#sec-touint32
1031 1032
  TNode<Object> ToUint32(SloppyTNode<Context> context,
                         SloppyTNode<Object> input);
1033

1034
  // Convert any object to a String.
1035 1036
  TNode<String> ToString(SloppyTNode<Context> context,
                         SloppyTNode<Object> input);
1037
  Node* ToString_Inline(Node* const context, Node* const input);
1038 1039

  // Convert any object to a Primitive.
1040
  Node* JSReceiverToPrimitive(Node* context, Node* input);
1041

1042 1043 1044 1045 1046
  enum ToIntegerTruncationMode {
    kNoTruncation,
    kTruncateMinusZero,
  };

1047 1048 1049
  // ES6 7.1.17 ToIndex, but jumps to range_error if the result is not a Smi.
  Node* ToSmiIndex(Node* const input, Node* const context, Label* range_error);

1050 1051 1052
  // ES6 7.1.15 ToLength, but jumps to range_error if the result is not a Smi.
  Node* ToSmiLength(Node* input, Node* const context, Label* range_error);

1053 1054 1055
  // ES6 7.1.15 ToLength, but with inlined fast path.
  Node* ToLength_Inline(Node* const context, Node* const input);

1056
  // Convert any object to an Integer.
1057 1058 1059
  TNode<Object> ToInteger(SloppyTNode<Context> context,
                          SloppyTNode<Object> input,
                          ToIntegerTruncationMode mode = kNoTruncation);
1060

1061
  // Returns a node that contains a decoded (unsigned!) value of a bit
1062 1063
  // field |BitField| in |word32|. Returns result as an uint32 node.
  template <typename BitField>
1064
  TNode<Uint32T> DecodeWord32(SloppyTNode<Word32T> word32) {
1065
    return DecodeWord32(word32, BitField::kShift, BitField::kMask);
1066 1067 1068
  }

  // Returns a node that contains a decoded (unsigned!) value of a bit
1069 1070
  // field |BitField| in |word|. Returns result as a word-size node.
  template <typename BitField>
1071
  Node* DecodeWord(Node* word) {
1072
    return DecodeWord(word, BitField::kShift, BitField::kMask);
1073 1074
  }

1075
  // Returns a node that contains a decoded (unsigned!) value of a bit
1076 1077
  // field |BitField| in |word32|. Returns result as a word-size node.
  template <typename BitField>
1078
  Node* DecodeWordFromWord32(Node* word32) {
1079
    return DecodeWord<BitField>(ChangeUint32ToWord(word32));
1080 1081
  }

1082
  // Returns a node that contains a decoded (unsigned!) value of a bit
1083 1084
  // field |BitField| in |word|. Returns result as an uint32 node.
  template <typename BitField>
1085
  Node* DecodeWord32FromWord(Node* word) {
1086
    return TruncateWordToWord32(DecodeWord<BitField>(word));
1087 1088
  }

1089
  // Decodes an unsigned (!) value from |word32| to an uint32 node.
1090 1091
  TNode<Uint32T> DecodeWord32(SloppyTNode<Word32T> word32, uint32_t shift,
                              uint32_t mask);
1092 1093

  // Decodes an unsigned (!) value from |word| to a word-size node.
1094
  Node* DecodeWord(Node* word, uint32_t shift, uint32_t mask);
1095

1096 1097 1098 1099 1100 1101 1102 1103 1104 1105
  // Returns a node that contains the updated values of a |BitField|.
  template <typename BitField>
  Node* UpdateWord(Node* word, Node* value) {
    return UpdateWord(word, value, BitField::kShift, BitField::kMask);
  }

  // Returns a node that contains the updated {value} inside {word} starting
  // at {shift} and fitting in {mask}.
  Node* UpdateWord(Node* word, Node* value, uint32_t shift, uint32_t mask);

1106 1107
  // Returns true if any of the |T|'s bits in given |word32| are set.
  template <typename T>
1108
  TNode<BoolT> IsSetWord32(SloppyTNode<Word32T> word32) {
1109 1110 1111 1112
    return IsSetWord32(word32, T::kMask);
  }

  // Returns true if any of the mask's bits in given |word32| are set.
1113
  TNode<BoolT> IsSetWord32(SloppyTNode<Word32T> word32, uint32_t mask) {
1114
    return Word32NotEqual(Word32And(word32, Int32Constant(mask)),
1115 1116 1117
                          Int32Constant(0));
  }

1118 1119 1120 1121 1122 1123
  // Returns true if none of the mask's bits in given |word32| are set.
  TNode<BoolT> IsNotSetWord32(SloppyTNode<Word32T> word32, uint32_t mask) {
    return Word32Equal(Word32And(word32, Int32Constant(mask)),
                       Int32Constant(0));
  }

1124 1125
  // Returns true if any of the |T|'s bits in given |word| are set.
  template <typename T>
1126
  Node* IsSetWord(Node* word) {
1127
    return IsSetWord(word, T::kMask);
1128
  }
1129

1130 1131
  // Returns true if any of the mask's bits in given |word| are set.
  Node* IsSetWord(Node* word, uint32_t mask) {
1132
    return WordNotEqual(WordAnd(word, IntPtrConstant(mask)), IntPtrConstant(0));
1133 1134
  }

1135 1136 1137 1138 1139 1140 1141 1142 1143
  // Returns true if any of the mask's bit are set in the given Smi.
  // Smi-encoding of the mask is performed implicitly!
  Node* IsSetSmi(Node* smi, int untagged_mask) {
    intptr_t mask_word = bit_cast<intptr_t>(Smi::FromInt(untagged_mask));
    return WordNotEqual(
        WordAnd(BitcastTaggedToWord(smi), IntPtrConstant(mask_word)),
        IntPtrConstant(0));
  }

1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166
  // Returns true if all of the |T|'s bits in given |word32| are clear.
  template <typename T>
  Node* IsClearWord32(Node* word32) {
    return IsClearWord32(word32, T::kMask);
  }

  // Returns true if all of the mask's bits in given |word32| are clear.
  Node* IsClearWord32(Node* word32, uint32_t mask) {
    return Word32Equal(Word32And(word32, Int32Constant(mask)),
                       Int32Constant(0));
  }

  // Returns true if all of the |T|'s bits in given |word| are clear.
  template <typename T>
  Node* IsClearWord(Node* word) {
    return IsClearWord(word, T::kMask);
  }

  // Returns true if all of the mask's bits in given |word| are clear.
  Node* IsClearWord(Node* word, uint32_t mask) {
    return WordEqual(WordAnd(word, IntPtrConstant(mask)), IntPtrConstant(0));
  }

1167 1168 1169 1170
  void SetCounter(StatsCounter* counter, int value);
  void IncrementCounter(StatsCounter* counter, int delta);
  void DecrementCounter(StatsCounter* counter, int delta);

1171
  void Increment(Variable* variable, int value = 1,
1172
                 ParameterMode mode = INTPTR_PARAMETERS);
1173
  void Decrement(Variable* variable, int value = 1,
1174 1175 1176
                 ParameterMode mode = INTPTR_PARAMETERS) {
    Increment(variable, -value, mode);
  }
1177

1178 1179 1180 1181 1182
  // Generates "if (false) goto label" code. Useful for marking a label as
  // "live" to avoid assertion failures during graph building. In the resulting
  // code this check will be eliminated.
  void Use(Label* label);

1183
  // Various building blocks for stubs doing property lookups.
1184 1185

  // |if_notinternalized| is optional; |if_bailout| will be used by default.
1186
  void TryToName(Node* key, Label* if_keyisindex, Variable* var_index,
1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201
                 Label* if_keyisunique, Variable* var_unique, Label* if_bailout,
                 Label* if_notinternalized = nullptr);

  // Performs a hash computation and string table lookup for the given string,
  // and jumps to:
  // - |if_index| if the string is an array index like "123"; |var_index|
  //              will contain the intptr representation of that index.
  // - |if_internalized| if the string exists in the string table; the
  //                     internalized version will be in |var_internalized|.
  // - |if_not_internalized| if the string is not in the string table (but
  //                         does not add it).
  // - |if_bailout| for unsupported cases (e.g. uncachable array index).
  void TryInternalizeString(Node* string, Label* if_index, Variable* var_index,
                            Label* if_internalized, Variable* var_internalized,
                            Label* if_not_internalized, Label* if_bailout);
1202

1203 1204 1205
  // Calculates array index for given dictionary entry and entry field.
  // See Dictionary::EntryToIndex().
  template <typename Dictionary>
1206
  Node* EntryToIndex(Node* entry, int field_index);
1207
  template <typename Dictionary>
1208
  Node* EntryToIndex(Node* entry) {
1209 1210
    return EntryToIndex<Dictionary>(entry, Dictionary::kEntryKeyIndex);
  }
1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245

  // Loads the details for the entry with the given key_index.
  // Returns an untagged int32.
  template <class ContainerType>
  Node* LoadDetailsByKeyIndex(Node* container, Node* key_index) {
    const int kKeyToDetailsOffset =
        (ContainerType::kEntryDetailsIndex - ContainerType::kEntryKeyIndex) *
        kPointerSize;
    return LoadAndUntagToWord32FixedArrayElement(container, key_index,
                                                 kKeyToDetailsOffset);
  }

  // Loads the value for the entry with the given key_index.
  // Returns a tagged value.
  template <class ContainerType>
  Node* LoadValueByKeyIndex(Node* container, Node* key_index) {
    const int kKeyToValueOffset =
        (ContainerType::kEntryValueIndex - ContainerType::kEntryKeyIndex) *
        kPointerSize;
    return LoadFixedArrayElement(container, key_index, kKeyToValueOffset);
  }

  // Stores the details for the entry with the given key_index.
  // |details| must be a Smi.
  template <class ContainerType>
  void StoreDetailsByKeyIndex(Node* container, Node* key_index, Node* details) {
    const int kKeyToDetailsOffset =
        (ContainerType::kEntryDetailsIndex - ContainerType::kEntryKeyIndex) *
        kPointerSize;
    StoreFixedArrayElement(container, key_index, details, SKIP_WRITE_BARRIER,
                           kKeyToDetailsOffset);
  }

  // Stores the value for the entry with the given key_index.
  template <class ContainerType>
1246 1247 1248
  void StoreValueByKeyIndex(
      Node* container, Node* key_index, Node* value,
      WriteBarrierMode write_barrier = UPDATE_WRITE_BARRIER) {
1249 1250 1251
    const int kKeyToValueOffset =
        (ContainerType::kEntryValueIndex - ContainerType::kEntryKeyIndex) *
        kPointerSize;
1252
    StoreFixedArrayElement(container, key_index, value, write_barrier,
1253 1254 1255
                           kKeyToValueOffset);
  }

1256
  // Calculate a valid size for the a hash table.
1257 1258
  TNode<IntPtrT> HashTableComputeCapacity(
      SloppyTNode<IntPtrT> at_least_space_for);
1259

1260
  template <class Dictionary>
1261 1262 1263 1264
  Node* GetNumberOfElements(Node* dictionary) {
    return LoadFixedArrayElement(dictionary,
                                 Dictionary::kNumberOfElementsIndex);
  }
1265 1266

  template <class Dictionary>
1267 1268 1269 1270
  void SetNumberOfElements(Node* dictionary, Node* num_elements_smi) {
    StoreFixedArrayElement(dictionary, Dictionary::kNumberOfElementsIndex,
                           num_elements_smi, SKIP_WRITE_BARRIER);
  }
1271 1272

  template <class Dictionary>
1273 1274 1275 1276
  Node* GetNumberOfDeletedElements(Node* dictionary) {
    return LoadFixedArrayElement(dictionary,
                                 Dictionary::kNumberOfDeletedElementsIndex);
  }
1277 1278

  template <class Dictionary>
1279 1280 1281 1282 1283 1284 1285 1286 1287 1288
  void SetNumberOfDeletedElements(Node* dictionary, Node* num_deleted_smi) {
    StoreFixedArrayElement(dictionary,
                           Dictionary::kNumberOfDeletedElementsIndex,
                           num_deleted_smi, SKIP_WRITE_BARRIER);
  }

  template <class Dictionary>
  Node* GetCapacity(Node* dictionary) {
    return LoadFixedArrayElement(dictionary, Dictionary::kCapacityIndex);
  }
1289 1290

  template <class Dictionary>
1291
  Node* GetNextEnumerationIndex(Node* dictionary);
1292 1293

  template <class Dictionary>
1294
  void SetNextEnumerationIndex(Node* dictionary, Node* next_enum_index_smi);
1295

1296 1297 1298 1299
  // Looks up an entry in a NameDictionaryBase successor. If the entry is found
  // control goes to {if_found} and {var_name_index} contains an index of the
  // key field of the entry found. If the key is not found control goes to
  // {if_not_found}.
1300
  static const int kInlinedDictionaryProbes = 4;
1301
  enum LookupMode { kFindExisting, kFindInsertionIndex };
1302 1303 1304 1305

  template <typename Dictionary>
  Node* LoadName(Node* key);

1306
  template <typename Dictionary>
1307 1308 1309
  void NameDictionaryLookup(Node* dictionary, Node* unique_name,
                            Label* if_found, Variable* var_name_index,
                            Label* if_not_found,
1310 1311
                            int inlined_probes = kInlinedDictionaryProbes,
                            LookupMode mode = kFindExisting);
1312

1313
  Node* ComputeIntegerHash(Node* key);
1314
  Node* ComputeIntegerHash(Node* key, Node* seed);
1315 1316

  template <typename Dictionary>
1317 1318 1319
  void NumberDictionaryLookup(Node* dictionary, Node* intptr_index,
                              Label* if_found, Variable* var_entry,
                              Label* if_not_found);
1320

1321
  template <class Dictionary>
1322
  void FindInsertionEntry(Node* dictionary, Node* key, Variable* var_key_index);
1323 1324

  template <class Dictionary>
1325 1326
  void InsertEntry(Node* dictionary, Node* key, Node* value, Node* index,
                   Node* enum_index);
1327 1328

  template <class Dictionary>
1329
  void Add(Node* dictionary, Node* key, Node* value, Label* bailout);
1330

1331
  // Tries to check if {object} has own {unique_name} property.
1332 1333
  void TryHasOwnProperty(Node* object, Node* map, Node* instance_type,
                         Node* unique_name, Label* if_found,
1334
                         Label* if_not_found, Label* if_bailout);
1335

1336 1337 1338
  // Operating mode for TryGetOwnProperty and CallGetterIfAccessor
  // kReturnAccessorPair is used when we're only getting the property descriptor
  enum GetOwnPropertyMode { kCallJSGetter, kReturnAccessorPair };
1339 1340 1341
  // Tries to get {object}'s own {unique_name} property value. If the property
  // is an accessor then it also calls a getter. If the property is a double
  // field it re-wraps value in an immutable heap number.
1342 1343 1344 1345
  void TryGetOwnProperty(Node* context, Node* receiver, Node* object, Node* map,
                         Node* instance_type, Node* unique_name,
                         Label* if_found, Variable* var_value,
                         Label* if_not_found, Label* if_bailout);
1346 1347 1348 1349
  void TryGetOwnProperty(Node* context, Node* receiver, Node* object, Node* map,
                         Node* instance_type, Node* unique_name,
                         Label* if_found, Variable* var_value,
                         Variable* var_details, Variable* var_raw_value,
1350 1351
                         Label* if_not_found, Label* if_bailout,
                         GetOwnPropertyMode mode = kCallJSGetter);
1352

1353
  Node* GetProperty(Node* context, Node* receiver, Handle<Name> name) {
1354 1355 1356 1357
    return GetProperty(context, receiver, HeapConstant(name));
  }

  Node* GetProperty(Node* context, Node* receiver, Node* const name) {
1358
    return CallStub(CodeFactory::GetProperty(isolate()), context, receiver,
1359
                    name);
1360 1361
  }

1362 1363 1364
  Node* GetMethod(Node* context, Node* object, Handle<Name> name,
                  Label* if_null_or_undefined);

1365 1366 1367 1368 1369
  template <class... TArgs>
  Node* CallBuiltin(Builtins::Name id, Node* context, TArgs... args) {
    return CallStub(Builtins::CallableFor(isolate(), id), context, args...);
  }

1370 1371 1372 1373 1374
  template <class... TArgs>
  Node* TailCallBuiltin(Builtins::Name id, Node* context, TArgs... args) {
    return TailCallStub(Builtins::CallableFor(isolate(), id), context, args...);
  }

1375 1376 1377 1378 1379
  void LoadPropertyFromFastObject(Node* object, Node* map, Node* descriptors,
                                  Node* name_index, Variable* var_details,
                                  Variable* var_value);

  void LoadPropertyFromNameDictionary(Node* dictionary, Node* entry,
1380 1381 1382
                                      Variable* var_details,
                                      Variable* var_value);

1383
  void LoadPropertyFromGlobalDictionary(Node* dictionary, Node* entry,
1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398
                                        Variable* var_details,
                                        Variable* var_value, Label* if_deleted);

  // Generic property lookup generator. If the {object} is fast and
  // {unique_name} property is found then the control goes to {if_found_fast}
  // label and {var_meta_storage} and {var_name_index} will contain
  // DescriptorArray and an index of the descriptor's name respectively.
  // If the {object} is slow or global then the control goes to {if_found_dict}
  // or {if_found_global} and the {var_meta_storage} and {var_name_index} will
  // contain a dictionary and an index of the key field of the found entry.
  // If property is not found or given lookup is not supported then
  // the control goes to {if_not_found} or {if_bailout} respectively.
  //
  // Note: this code does not check if the global dictionary points to deleted
  // entry! This has to be done by the caller.
1399 1400
  void TryLookupProperty(Node* object, Node* map, Node* instance_type,
                         Node* unique_name, Label* if_found_fast,
1401 1402 1403 1404
                         Label* if_found_dict, Label* if_found_global,
                         Variable* var_meta_storage, Variable* var_name_index,
                         Label* if_not_found, Label* if_bailout);

1405 1406 1407
  // This method jumps to if_found if the element is known to exist. To
  // if_absent if it's known to not exist. To if_not_found if the prototype
  // chain needs to be checked. And if_bailout if the lookup is unsupported.
1408
  void TryLookupElement(Node* object, Node* map, Node* instance_type,
1409
                        Node* intptr_index, Label* if_found, Label* if_absent,
1410
                        Label* if_not_found, Label* if_bailout);
1411

1412
  // This is a type of a lookup in holder generator function. In case of a
1413
  // property lookup the {key} is guaranteed to be an unique name and in case of
1414
  // element lookup the key is an Int32 index.
1415 1416
  typedef std::function<void(Node* receiver, Node* holder, Node* map,
                             Node* instance_type, Node* key, Label* next_holder,
1417 1418 1419 1420 1421 1422 1423 1424 1425
                             Label* if_bailout)>
      LookupInHolder;

  // Generic property prototype chain lookup generator.
  // For properties it generates lookup using given {lookup_property_in_holder}
  // and for elements it uses {lookup_element_in_holder}.
  // Upon reaching the end of prototype chain the control goes to {if_end}.
  // If it can't handle the case {receiver}/{key} case then the control goes
  // to {if_bailout}.
1426
  // If {if_proxy} is nullptr, proxies go to if_bailout.
1427
  void TryPrototypeChainLookup(Node* receiver, Node* key,
1428 1429
                               const LookupInHolder& lookup_property_in_holder,
                               const LookupInHolder& lookup_element_in_holder,
1430 1431
                               Label* if_end, Label* if_bailout,
                               Label* if_proxy = nullptr);
1432

1433
  // Instanceof helpers.
1434 1435 1436 1437
  // Returns true if {object} has {prototype} somewhere in it's prototype
  // chain, otherwise false is returned. Might cause arbitrary side effects
  // due to [[GetPrototypeOf]] invocations.
  Node* HasInPrototypeChain(Node* context, Node* object, Node* prototype);
1438
  // ES6 section 7.3.19 OrdinaryHasInstance (C, O)
1439
  Node* OrdinaryHasInstance(Node* context, Node* callable, Node* object);
1440

1441
  // Load type feedback vector from the stub caller's frame.
1442
  Node* LoadFeedbackVectorForStub();
1443

1444
  // Load type feedback vector for the given closure.
1445 1446
  Node* LoadFeedbackVector(Node* closure);

1447
  // Update the type feedback vector.
1448
  void UpdateFeedback(Node* feedback, Node* feedback_vector, Node* slot_id);
1449

1450 1451 1452
  // Combine the new feedback with the existing_feedback.
  void CombineFeedback(Variable* existing_feedback, Node* feedback);

1453 1454 1455 1456
  // Check if a property name might require protector invalidation when it is
  // used for a property store or deletion.
  void CheckForAssociatedProtector(Node* name, Label* if_protector);

1457
  Node* LoadReceiverMap(Node* receiver);
1458

1459
  // Emits keyed sloppy arguments load. Returns either the loaded value.
1460
  Node* LoadKeyedSloppyArguments(Node* receiver, Node* key, Label* bailout) {
1461 1462 1463 1464
    return EmitKeyedSloppyArguments(receiver, key, nullptr, bailout);
  }

  // Emits keyed sloppy arguments store.
1465 1466
  void StoreKeyedSloppyArguments(Node* receiver, Node* key, Node* value,
                                 Label* bailout) {
1467 1468 1469 1470
    DCHECK_NOT_NULL(value);
    EmitKeyedSloppyArguments(receiver, key, value, bailout);
  }

1471
  // Loads script context from the script context table.
1472
  Node* LoadScriptContext(Node* context, int context_index);
1473

1474 1475 1476 1477 1478
  Node* Int32ToUint8Clamped(Node* int32_value);
  Node* Float64ToUint8Clamped(Node* float64_value);

  Node* PrepareValueForWriteToTypedArray(Node* key, ElementsKind elements_kind,
                                         Label* bailout);
1479 1480

  // Store value to an elements array with given elements kind.
1481
  void StoreElement(Node* elements, ElementsKind kind, Node* index, Node* value,
1482 1483
                    ParameterMode mode);

1484
  void EmitElementStore(Node* object, Node* key, Node* value, bool is_jsarray,
1485 1486 1487
                        ElementsKind elements_kind,
                        KeyedAccessStoreMode store_mode, Label* bailout);

1488 1489 1490
  Node* CheckForCapacityGrow(Node* object, Node* elements, ElementsKind kind,
                             Node* length, Node* key, ParameterMode mode,
                             bool is_js_array, Label* bailout);
1491

1492 1493
  Node* CopyElementsOnWrite(Node* object, Node* elements, ElementsKind kind,
                            Node* length, ParameterMode mode, Label* bailout);
1494

1495 1496 1497
  void TransitionElementsKind(Node* object, Node* map, ElementsKind from_kind,
                              ElementsKind to_kind, bool is_jsarray,
                              Label* bailout);
1498

1499
  void TrapAllocationMemento(Node* object, Label* memento_found);
1500

1501
  Node* PageFromAddress(Node* address);
1502

1503 1504
  // Create a new weak cell with a specified value and install it into a
  // feedback vector.
1505 1506
  Node* CreateWeakCellInFeedbackVector(Node* feedback_vector, Node* slot,
                                       Node* value);
1507

1508
  // Create a new AllocationSite and install it into a feedback vector.
1509
  Node* CreateAllocationSiteInFeedbackVector(Node* feedback_vector, Node* slot);
1510

1511 1512 1513 1514 1515
  // Given a recently allocated object {object}, with map {initial_map},
  // initialize remaining fields appropriately to comply with slack tracking.
  void HandleSlackTracking(Node* context, Node* object, Node* initial_map,
                           int start_offset);

1516 1517
  enum class IndexAdvanceMode { kPre, kPost };

1518 1519
  typedef std::function<void(Node* index)> FastLoopBody;

1520
  Node* BuildFastLoop(const VariableList& var_list, Node* start_index,
1521
                      Node* end_index, const FastLoopBody& body, int increment,
1522 1523 1524 1525 1526 1527 1528 1529 1530
                      ParameterMode parameter_mode,
                      IndexAdvanceMode advance_mode = IndexAdvanceMode::kPre);

  Node* BuildFastLoop(Node* start_index, Node* end_index,
                      const FastLoopBody& body, int increment,
                      ParameterMode parameter_mode,
                      IndexAdvanceMode advance_mode = IndexAdvanceMode::kPre) {
    return BuildFastLoop(VariableList(0, zone()), start_index, end_index, body,
                         increment, parameter_mode, advance_mode);
1531
  }
1532 1533 1534

  enum class ForEachDirection { kForward, kReverse };

1535 1536 1537
  typedef std::function<void(Node* fixed_array, Node* offset)>
      FastFixedArrayForEachBody;

1538
  void BuildFastFixedArrayForEach(
1539 1540
      const CodeStubAssembler::VariableList& vars, Node* fixed_array,
      ElementsKind kind, Node* first_element_inclusive,
1541
      Node* last_element_exclusive, const FastFixedArrayForEachBody& body,
1542 1543 1544
      ParameterMode mode = INTPTR_PARAMETERS,
      ForEachDirection direction = ForEachDirection::kReverse);

1545 1546 1547 1548 1549 1550 1551 1552 1553 1554
  void BuildFastFixedArrayForEach(
      Node* fixed_array, ElementsKind kind, Node* first_element_inclusive,
      Node* last_element_exclusive, const FastFixedArrayForEachBody& body,
      ParameterMode mode = INTPTR_PARAMETERS,
      ForEachDirection direction = ForEachDirection::kReverse) {
    CodeStubAssembler::VariableList list(0, zone());
    BuildFastFixedArrayForEach(list, fixed_array, kind, first_element_inclusive,
                               last_element_exclusive, body, mode, direction);
  }

1555 1556
  Node* GetArrayAllocationSize(Node* element_count, ElementsKind kind,
                               ParameterMode mode, int header_size) {
1557 1558 1559
    return ElementOffsetFromIndex(element_count, kind, mode, header_size);
  }

1560 1561
  Node* GetFixedArrayAllocationSize(Node* element_count, ElementsKind kind,
                                    ParameterMode mode) {
1562
    return GetArrayAllocationSize(element_count, kind, mode,
1563 1564 1565
                                  FixedArray::kHeaderSize);
  }

1566 1567 1568 1569 1570 1571
  Node* GetPropertyArrayAllocationSize(Node* element_count,
                                       ParameterMode mode) {
    return GetArrayAllocationSize(element_count, PACKED_ELEMENTS, mode,
                                  PropertyArray::kHeaderSize);
  }

1572 1573 1574 1575
  void GotoIfFixedArraySizeDoesntFitInNewSpace(Node* element_count,
                                               Label* doesnt_fit, int base_size,
                                               ParameterMode mode);

1576 1577 1578
  void InitializeFieldsWithRoot(Node* object, Node* start_offset,
                                Node* end_offset, Heap::RootListIndex root);

1579 1580 1581 1582 1583 1584 1585
  enum RelationalComparisonMode {
    kLessThan,
    kLessThanOrEqual,
    kGreaterThan,
    kGreaterThanOrEqual
  };

1586
  Node* RelationalComparison(RelationalComparisonMode mode, Node* lhs,
1587 1588
                             Node* rhs, Node* context,
                             Variable* var_type_feedback = nullptr);
1589

1590
  void BranchIfNumericRelationalComparison(RelationalComparisonMode mode,
1591
                                           Node* lhs, Node* rhs, Label* if_true,
1592 1593
                                           Label* if_false);

1594 1595 1596 1597 1598 1599
  void BranchIfAccessorPair(Node* value, Label* if_accessor_pair,
                            Label* if_not_accessor_pair) {
    GotoIf(TaggedIsSmi(value), if_not_accessor_pair);
    Branch(IsAccessorPair(value), if_accessor_pair, if_not_accessor_pair);
  }

1600
  void GotoIfNumberGreaterThanOrEqual(Node* lhs, Node* rhs, Label* if_false);
1601

1602 1603
  Node* Equal(Node* lhs, Node* rhs, Node* context,
              Variable* var_type_feedback = nullptr);
1604

1605 1606
  Node* StrictEqual(Node* lhs, Node* rhs,
                    Variable* var_type_feedback = nullptr);
1607

1608 1609 1610
  // ECMA#sec-samevalue
  // Similar to StrictEqual except that NaNs are treated as equal and minus zero
  // differs from positive zero.
1611
  void BranchIfSameValue(Node* lhs, Node* rhs, Label* if_true, Label* if_false);
1612

1613 1614 1615 1616
  enum HasPropertyLookupMode { kHasProperty, kForInHasProperty };

  Node* HasProperty(Node* object, Node* key, Node* context,
                    HasPropertyLookupMode mode);
1617

1618 1619
  Node* ClassOf(Node* object);

1620
  Node* Typeof(Node* value);
1621

1622 1623
  Node* GetSuperConstructor(Node* value, Node* context);

1624
  Node* InstanceOf(Node* object, Node* callable, Node* context);
1625

1626
  // Debug helpers
1627
  Node* IsDebugActive();
1628

1629
  // TypedArray/ArrayBuffer helpers
1630
  Node* IsDetachedBuffer(Node* buffer);
1631

1632 1633
  Node* ElementOffsetFromIndex(Node* index, ElementsKind kind,
                               ParameterMode mode, int base_size = 0);
1634

1635 1636 1637
  Node* AllocateFunctionWithMapAndContext(Node* map, Node* shared_info,
                                          Node* context);

1638
  // Promise helpers
1639
  Node* IsPromiseHookEnabledOrDebugIsActive();
1640

1641
  Node* AllocatePromiseReactionJobInfo(Node* value, Node* tasks,
1642 1643 1644
                                       Node* deferred_promise,
                                       Node* deferred_on_resolve,
                                       Node* deferred_on_reject, Node* context);
1645

1646 1647 1648 1649 1650 1651
  // Helpers for StackFrame markers.
  Node* MarkerIsFrameType(Node* marker_or_function,
                          StackFrame::Type frame_type);
  Node* MarkerIsNotFrameType(Node* marker_or_function,
                             StackFrame::Type frame_type);

1652 1653 1654 1655 1656
  // for..in helpers
  void CheckPrototypeEnumCache(Node* receiver, Node* receiver_map,
                               Label* if_fast, Label* if_slow);
  Node* CheckEnumCache(Node* receiver, Label* if_empty, Label* if_runtime);

1657 1658 1659 1660 1661
  // Support for printf-style debugging
  void Print(const char* s);
  void Print(const char* prefix, Node* tagged_value);
  inline void Print(Node* tagged_value) { return Print(nullptr, tagged_value); }

1662 1663 1664 1665 1666 1667 1668 1669 1670 1671
  template <class... TArgs>
  Node* MakeTypeError(MessageTemplate::Template message, Node* context,
                      TArgs... args) {
    STATIC_ASSERT(sizeof...(TArgs) <= 3);
    Node* const make_type_error = LoadContextElement(
        LoadNativeContext(context), Context::MAKE_TYPE_ERROR_INDEX);
    return CallJS(CodeFactory::Call(isolate()), context, make_type_error,
                  UndefinedConstant(), SmiConstant(message), args...);
  }

1672 1673 1674 1675 1676
  void Abort(BailoutReason reason) {
    CallRuntime(Runtime::kAbort, NoContextConstant(), SmiConstant(reason));
    Unreachable();
  }

1677
 protected:
1678 1679 1680
  void DescriptorLookup(Node* unique_name, Node* descriptors, Node* bitfield3,
                        Label* if_found, Variable* var_name_index,
                        Label* if_not_found);
1681
  void DescriptorLookupLinear(Node* unique_name, Node* descriptors, Node* nof,
1682 1683
                              Label* if_found, Variable* var_name_index,
                              Label* if_not_found);
1684 1685 1686
  void DescriptorLookupBinary(Node* unique_name, Node* descriptors, Node* nof,
                              Label* if_found, Variable* var_name_index,
                              Label* if_not_found);
1687 1688 1689
  // Implements DescriptorArray::ToKeyIndex.
  // Returns an untagged IntPtr.
  Node* DescriptorArrayToKeyIndex(Node* descriptor_number);
1690 1691
  // Implements DescriptorArray::GetKey.
  Node* DescriptorArrayGetKey(Node* descriptors, Node* descriptor_number);
1692

1693
  Node* CallGetterIfAccessor(Node* value, Node* details, Node* context,
1694 1695
                             Node* receiver, Label* if_bailout,
                             GetOwnPropertyMode mode = kCallJSGetter);
1696

1697
  Node* TryToIntptr(Node* key, Label* miss);
1698

1699
  void BranchIfPrototypesHaveNoElements(Node* receiver_map,
1700 1701
                                        Label* definitely_no_elements,
                                        Label* possibly_elements);
1702

1703 1704 1705
 private:
  friend class CodeStubArguments;

1706 1707
  void HandleBreakOnNode();

1708 1709
  Node* AllocateRawDoubleAligned(Node* size_in_bytes, AllocationFlags flags,
                                 Node* top_address, Node* limit_address);
1710 1711
  Node* AllocateRawUnaligned(Node* size_in_bytes, AllocationFlags flags,
                             Node* top_adddress, Node* limit_address);
1712 1713
  Node* AllocateRaw(Node* size_in_bytes, AllocationFlags flags,
                    Node* top_address, Node* limit_address);
1714 1715
  // Allocate and return a JSArray of given total size in bytes with header
  // fields initialized.
1716 1717
  Node* AllocateUninitializedJSArray(Node* array_map, Node* length,
                                     Node* allocation_site,
1718
                                     Node* size_in_bytes);
1719

1720
  Node* SmiShiftBitsConstant();
1721

1722 1723
  // Emits keyed sloppy arguments load if the |value| is nullptr or store
  // otherwise. Returns either the loaded value or |value|.
1724 1725 1726 1727 1728 1729 1730 1731
  Node* EmitKeyedSloppyArguments(Node* receiver, Node* key, Node* value,
                                 Label* bailout);

  Node* AllocateSlicedString(Heap::RootListIndex map_root_index, Node* length,
                             Node* parent, Node* offset);

  Node* AllocateConsString(Heap::RootListIndex map_root_index, Node* length,
                           Node* first, Node* second, AllocationFlags flags);
1732

1733 1734 1735 1736 1737 1738 1739 1740
  // Implements DescriptorArray::number_of_entries.
  // Returns an untagged int32.
  Node* DescriptorArrayNumberOfEntries(Node* descriptors);
  // Implements DescriptorArray::GetSortedKeyIndex.
  // Returns an untagged int32.
  Node* DescriptorArrayGetSortedKeyIndex(Node* descriptors,
                                         Node* descriptor_number);

1741 1742 1743 1744 1745 1746 1747
  Node* CollectFeedbackForString(Node* instance_type);
  void GenerateEqual_Same(Node* value, Label* if_equal, Label* if_notequal,
                          Variable* var_type_feedback = nullptr);
  Node* AllocAndCopyStringCharacters(Node* context, Node* from,
                                     Node* from_instance_type, Node* from_index,
                                     Node* character_count);

1748
  static const int kElementLoopUnrollThreshold = 8;
1749 1750 1751

  Node* NonNumberToNumberOrNumeric(Node* context, Node* input,
                                   Object::Conversion mode);
1752 1753
};

1754 1755
class CodeStubArguments {
 public:
1756
  typedef compiler::Node Node;
1757 1758 1759 1760
  template <class A>
  using TNode = compiler::TNode<A>;
  template <class A>
  using SloppyTNode = compiler::SloppyTNode<A>;
1761
  enum ReceiverMode { kHasReceiver, kNoReceiver };
1762

1763
  // |argc| is an intptr value which specifies the number of arguments passed
1764 1765
  // to the builtin excluding the receiver. The arguments will include a
  // receiver iff |receiver_mode| is kHasReceiver.
1766
  CodeStubArguments(CodeStubAssembler* assembler, SloppyTNode<IntPtrT> argc,
1767
                    ReceiverMode receiver_mode = ReceiverMode::kHasReceiver)
1768
      : CodeStubArguments(assembler, argc, nullptr,
1769 1770 1771 1772
                          CodeStubAssembler::INTPTR_PARAMETERS, receiver_mode) {
  }
  // |argc| is either a smi or intptr depending on |param_mode|. The arguments
  // include a receiver iff |receiver_mode| is kHasReceiver.
1773 1774
  CodeStubArguments(CodeStubAssembler* assembler, SloppyTNode<IntPtrT> argc,
                    Node* fp, CodeStubAssembler::ParameterMode param_mode,
1775
                    ReceiverMode receiver_mode = ReceiverMode::kHasReceiver);
1776

1777
  TNode<Object> GetReceiver() const;
1778

1779 1780 1781
  TNode<RawPtr<Object>> AtIndexPtr(
      Node* index, CodeStubAssembler::ParameterMode mode =
                       CodeStubAssembler::INTPTR_PARAMETERS) const;
1782

1783
  // |index| is zero-based and does not include the receiver
1784 1785 1786
  TNode<Object> AtIndex(Node* index,
                        CodeStubAssembler::ParameterMode mode =
                            CodeStubAssembler::INTPTR_PARAMETERS) const;
1787

1788
  TNode<Object> AtIndex(int index) const;
1789

1790
  TNode<Object> GetOptionalArgumentValue(int index) {
1791 1792
    return GetOptionalArgumentValue(index, assembler_->UndefinedConstant());
  }
1793 1794
  TNode<Object> GetOptionalArgumentValue(int index,
                                         SloppyTNode<Object> default_value);
1795

1796
  TNode<IntPtrT> GetLength() const { return argc_; }
1797

1798
  typedef std::function<void(Node* arg)> ForEachBodyFunction;
1799 1800

  // Iteration doesn't include the receiver. |first| and |last| are zero-based.
1801
  void ForEach(const ForEachBodyFunction& body, Node* first = nullptr,
1802 1803
               Node* last = nullptr, CodeStubAssembler::ParameterMode mode =
                                         CodeStubAssembler::INTPTR_PARAMETERS) {
1804 1805 1806 1807 1808 1809
    CodeStubAssembler::VariableList list(0, assembler_->zone());
    ForEach(list, body, first, last);
  }

  // Iteration doesn't include the receiver. |first| and |last| are zero-based.
  void ForEach(const CodeStubAssembler::VariableList& vars,
1810
               const ForEachBodyFunction& body, Node* first = nullptr,
1811 1812
               Node* last = nullptr, CodeStubAssembler::ParameterMode mode =
                                         CodeStubAssembler::INTPTR_PARAMETERS);
1813

1814
  void PopAndReturn(Node* value);
1815 1816

 private:
1817
  Node* GetArguments();
1818 1819

  CodeStubAssembler* assembler_;
1820
  CodeStubAssembler::ParameterMode argc_mode_;
1821
  ReceiverMode receiver_mode_;
1822 1823
  TNode<IntPtrT> argc_;
  TNode<RawPtr<Object>> arguments_;
1824
  Node* fp_;
1825 1826
};

1827 1828 1829 1830 1831
class ToDirectStringAssembler : public CodeStubAssembler {
 private:
  enum StringPointerKind { PTR_TO_DATA, PTR_TO_STRING };

 public:
1832 1833 1834 1835 1836 1837 1838
  enum Flag {
    kDontUnpackSlicedStrings = 1 << 0,
  };
  typedef base::Flags<Flag> Flags;

  ToDirectStringAssembler(compiler::CodeAssemblerState* state, Node* string,
                          Flags flags = Flags());
1839 1840 1841

  // Converts flat cons, thin, and sliced strings and returns the direct
  // string. The result can be either a sequential or external string.
1842 1843
  // Jumps to if_bailout if the string if the string is indirect and cannot
  // be unpacked.
1844 1845 1846
  Node* TryToDirect(Label* if_bailout);

  // Returns a pointer to the beginning of the string data.
1847
  // Jumps to if_bailout if the external string cannot be unpacked.
1848 1849 1850 1851 1852
  Node* PointerToData(Label* if_bailout) {
    return TryToSequential(PTR_TO_DATA, if_bailout);
  }

  // Returns a pointer that, offset-wise, looks like a String.
1853
  // Jumps to if_bailout if the external string cannot be unpacked.
1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869
  Node* PointerToString(Label* if_bailout) {
    return TryToSequential(PTR_TO_STRING, if_bailout);
  }

  Node* string() { return var_string_.value(); }
  Node* instance_type() { return var_instance_type_.value(); }
  Node* offset() { return var_offset_.value(); }
  Node* is_external() { return var_is_external_.value(); }

 private:
  Node* TryToSequential(StringPointerKind ptr_kind, Label* if_bailout);

  Variable var_string_;
  Variable var_instance_type_;
  Variable var_offset_;
  Variable var_is_external_;
1870 1871

  const Flags flags_;
1872 1873
};

1874 1875 1876 1877 1878 1879
#define CSA_CHECK(csa, x)                                              \
  (csa)->Check(                                                        \
      [&]() -> compiler::Node* {                                       \
        return base::implicit_cast<compiler::SloppyTNode<Word32T>>(x); \
      },                                                               \
      #x, __FILE__, __LINE__)
1880 1881

#ifdef DEBUG
1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907
// Add stringified versions to the given values, except the first. That is,
// transform
//   x, a, b, c, d, e, f
// to
//   a, "a", b, "b", c, "c", d, "d", e, "e", f, "f"
//
// __VA_ARGS__  is ignored to allow the caller to pass through too many
// parameters, and the first element is ignored to support having no extra
// values without empty __VA_ARGS__ (which cause all sorts of problems with
// extra commas).
#define CSA_ASSERT_STRINGIFY_EXTRA_VALUES_5(_, v1, v2, v3, v4, v5, ...) \
  v1, #v1, v2, #v2, v3, #v3, v4, #v4, v5, #v5

// Stringify the given variable number of arguments. The arguments are trimmed
// to 5 if there are too many, and padded with nullptr if there are not enough.
#define CSA_ASSERT_STRINGIFY_EXTRA_VALUES(...)                                \
  CSA_ASSERT_STRINGIFY_EXTRA_VALUES_5(__VA_ARGS__, nullptr, nullptr, nullptr, \
                                      nullptr, nullptr)

#define CSA_ASSERT_GET_CONDITION(x, ...) (x)
#define CSA_ASSERT_GET_CONDITION_STR(x, ...) #x

// CSA_ASSERT(csa, <condition>, <extra values to print...>)

// We have to jump through some hoops to allow <extra values to print...> to be
// empty.
1908 1909 1910 1911 1912 1913 1914 1915
#define CSA_ASSERT(csa, ...)                                                 \
  (csa)->Assert(                                                             \
      [&]() -> compiler::Node* {                                             \
        return base::implicit_cast<compiler::SloppyTNode<Word32T>>(          \
            EXPAND(CSA_ASSERT_GET_CONDITION(__VA_ARGS__)));                  \
      },                                                                     \
      EXPAND(CSA_ASSERT_GET_CONDITION_STR(__VA_ARGS__)), __FILE__, __LINE__, \
      CSA_ASSERT_STRINGIFY_EXTRA_VALUES(__VA_ARGS__))
1916 1917 1918

#define CSA_ASSERT_JS_ARGC_OP(csa, Op, op, expected)                      \
  (csa)->Assert(                                                          \
1919
      [&]() -> compiler::Node* {                                          \
1920 1921 1922 1923 1924 1925 1926
        compiler::Node* const argc =                                      \
            (csa)->Parameter(Descriptor::kActualArgumentsCount);          \
        return (csa)->Op(argc, (csa)->Int32Constant(expected));           \
      },                                                                  \
      "argc " #op " " #expected, __FILE__, __LINE__,                      \
      SmiFromWord32((csa)->Parameter(Descriptor::kActualArgumentsCount)), \
      "argc")
1927 1928 1929 1930

#define CSA_ASSERT_JS_ARGC_EQ(csa, expected) \
  CSA_ASSERT_JS_ARGC_OP(csa, Word32Equal, ==, expected)

1931
#define CSA_DEBUG_INFO(name) \
1932 1933
  { #name, __FILE__, __LINE__ }
#define BIND(label) Bind(label, CSA_DEBUG_INFO(label))
1934
#define VARIABLE(name, ...) \
1935 1936 1937
  Variable name(this, CSA_DEBUG_INFO(name), __VA_ARGS__)
#define VARIABLE_CONSTRUCTOR(name, ...) \
  name(this, CSA_DEBUG_INFO(name), __VA_ARGS__)
1938
#define TYPED_VARIABLE_DEF(type, name, ...) \
1939
  TVariable<type> name(CSA_DEBUG_INFO(name), __VA_ARGS__)
1940
#else  // DEBUG
1941
#define CSA_ASSERT(csa, ...) ((void)0)
1942
#define CSA_ASSERT_JS_ARGC_EQ(csa, expected) ((void)0)
1943 1944 1945 1946
#define BIND(label) Bind(label)
#define VARIABLE(name, ...) Variable name(this, __VA_ARGS__)
#define VARIABLE_CONSTRUCTOR(name, ...) name(this, __VA_ARGS__)
#define TYPED_VARIABLE_DEF(type, name, ...) TVariable<type> name(__VA_ARGS__)
1947 1948
#endif  // DEBUG

1949 1950
#define TVARIABLE(...) EXPAND(TYPED_VARIABLE_DEF(__VA_ARGS__, this))

1951
#ifdef ENABLE_SLOW_DCHECKS
1952
#define CSA_SLOW_ASSERT(csa, ...) \
1953
  if (FLAG_enable_slow_asserts) { \
1954
    CSA_ASSERT(csa, __VA_ARGS__); \
1955 1956
  }
#else
1957
#define CSA_SLOW_ASSERT(csa, ...) ((void)0)
1958 1959
#endif

1960 1961
DEFINE_OPERATORS_FOR_FLAGS(CodeStubAssembler::AllocationFlags);

1962 1963 1964
}  // namespace internal
}  // namespace v8
#endif  // V8_CODE_STUB_ASSEMBLER_H_