1// Copyright 2016 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef V8_CODE_STUB_ASSEMBLER_H_
6#define V8_CODE_STUB_ASSEMBLER_H_
7
8#include <functional>
9
10#include "src/compiler/code-assembler.h"
11#include "src/globals.h"
12#include "src/objects.h"
13
14namespace v8 {
15namespace internal {
16
17class CallInterfaceDescriptor;
18class CodeStubArguments;
19class StatsCounter;
20class StubCache;
21
22enum class PrimitiveType { kBoolean, kNumber, kString, kSymbol };
23
24#define HEAP_CONSTANT_LIST(V)                         \
25  V(AccessorInfoMap, AccessorInfoMap)                 \
26  V(AllocationSiteMap, AllocationSiteMap)             \
27  V(BooleanMap, BooleanMap)                           \
28  V(CodeMap, CodeMap)                                 \
29  V(empty_string, EmptyString)                        \
30  V(EmptyFixedArray, EmptyFixedArray)                 \
31  V(FalseValue, False)                                \
32  V(FixedArrayMap, FixedArrayMap)                     \
33  V(FixedCOWArrayMap, FixedCOWArrayMap)               \
34  V(FixedDoubleArrayMap, FixedDoubleArrayMap)         \
35  V(FunctionTemplateInfoMap, FunctionTemplateInfoMap) \
36  V(has_instance_symbol, HasInstanceSymbol)           \
37  V(HeapNumberMap, HeapNumberMap)                     \
38  V(NoClosuresCellMap, NoClosuresCellMap)             \
39  V(OneClosureCellMap, OneClosureCellMap)             \
40  V(ManyClosuresCellMap, ManyClosuresCellMap)         \
41  V(MinusZeroValue, MinusZero)                        \
42  V(NanValue, Nan)                                    \
43  V(NullValue, Null)                                  \
44  V(SymbolMap, SymbolMap)                             \
45  V(TheHoleValue, TheHole)                            \
46  V(TrueValue, True)                                  \
47  V(Tuple2Map, Tuple2Map)                             \
48  V(Tuple3Map, Tuple3Map)                             \
49  V(UndefinedValue, Undefined)
50
51// Provides JavaScript-specific "macro-assembler" functionality on top of the
52// CodeAssembler. By factoring the JavaScript-isms out of the CodeAssembler,
53// it's possible to add JavaScript-specific useful CodeAssembler "macros"
54// without modifying files in the compiler directory (and requiring a review
55// from a compiler directory OWNER).
56class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
57 public:
58  typedef compiler::Node Node;
59
60  CodeStubAssembler(compiler::CodeAssemblerState* state);
61
62  enum AllocationFlag : uint8_t {
63    kNone = 0,
64    kDoubleAlignment = 1,
65    kPretenured = 1 << 1,
66    kAllowLargeObjectAllocation = 1 << 2,
67  };
68
69  typedef base::Flags<AllocationFlag> AllocationFlags;
70
71  enum ParameterMode { SMI_PARAMETERS, INTPTR_PARAMETERS };
72
73  // On 32-bit platforms, there is a slight performance advantage to doing all
74  // of the array offset/index arithmetic with SMIs, since it's possible
75  // to save a few tag/untag operations without paying an extra expense when
76  // calculating array offset (the smi math can be folded away) and there are
77  // fewer live ranges. Thus only convert indices to untagged value on 64-bit
78  // platforms.
79  ParameterMode OptimalParameterMode() const {
80    return Is64() ? INTPTR_PARAMETERS : SMI_PARAMETERS;
81  }
82
83  MachineRepresentation ParameterRepresentation(ParameterMode mode) const {
84    return mode == INTPTR_PARAMETERS ? MachineType::PointerRepresentation()
85                                     : MachineRepresentation::kTaggedSigned;
86  }
87
88  MachineRepresentation OptimalParameterRepresentation() const {
89    return ParameterRepresentation(OptimalParameterMode());
90  }
91
92  Node* ParameterToWord(Node* value, ParameterMode mode) {
93    if (mode == SMI_PARAMETERS) value = SmiUntag(value);
94    return value;
95  }
96
97  Node* WordToParameter(Node* value, ParameterMode mode) {
98    if (mode == SMI_PARAMETERS) value = SmiTag(value);
99    return value;
100  }
101
102  Node* ParameterToTagged(Node* value, ParameterMode mode) {
103    if (mode != SMI_PARAMETERS) value = SmiTag(value);
104    return value;
105  }
106
107  Node* TaggedToParameter(Node* value, ParameterMode mode) {
108    if (mode != SMI_PARAMETERS) value = SmiUntag(value);
109    return value;
110  }
111
112#define PARAMETER_BINOP(OpName, IntPtrOpName, SmiOpName) \
113  Node* OpName(Node* a, Node* b, ParameterMode mode) {   \
114    if (mode == SMI_PARAMETERS) {                        \
115      return SmiOpName(a, b);                            \
116    } else {                                             \
117      DCHECK_EQ(INTPTR_PARAMETERS, mode);                \
118      return IntPtrOpName(a, b);                         \
119    }                                                    \
120  }
121  PARAMETER_BINOP(IntPtrOrSmiMin, IntPtrMin, SmiMin)
122  PARAMETER_BINOP(IntPtrOrSmiAdd, IntPtrAdd, SmiAdd)
123  PARAMETER_BINOP(IntPtrOrSmiSub, IntPtrSub, SmiSub)
124  PARAMETER_BINOP(IntPtrOrSmiLessThan, IntPtrLessThan, SmiLessThan)
125  PARAMETER_BINOP(IntPtrOrSmiLessThanOrEqual, IntPtrLessThanOrEqual,
126                  SmiLessThanOrEqual)
127  PARAMETER_BINOP(IntPtrOrSmiGreaterThan, IntPtrGreaterThan, SmiGreaterThan)
128  PARAMETER_BINOP(IntPtrOrSmiGreaterThanOrEqual, IntPtrGreaterThanOrEqual,
129                  SmiGreaterThanOrEqual)
130  PARAMETER_BINOP(UintPtrOrSmiLessThan, UintPtrLessThan, SmiBelow)
131  PARAMETER_BINOP(UintPtrOrSmiGreaterThanOrEqual, UintPtrGreaterThanOrEqual,
132                  SmiAboveOrEqual)
133#undef PARAMETER_BINOP
134
135  Node* NoContextConstant();
136#define HEAP_CONSTANT_ACCESSOR(rootName, name) Node* name##Constant();
137  HEAP_CONSTANT_LIST(HEAP_CONSTANT_ACCESSOR)
138#undef HEAP_CONSTANT_ACCESSOR
139
140#define HEAP_CONSTANT_TEST(rootName, name) Node* Is##name(Node* value);
141  HEAP_CONSTANT_LIST(HEAP_CONSTANT_TEST)
142#undef HEAP_CONSTANT_TEST
143
144  Node* HashSeed();
145  Node* StaleRegisterConstant();
146
147  Node* IntPtrOrSmiConstant(int value, ParameterMode mode);
148
149  bool IsIntPtrOrSmiConstantZero(Node* test);
150
151  // Round the 32bits payload of the provided word up to the next power of two.
152  Node* IntPtrRoundUpToPowerOfTwo32(Node* value);
153  // Select the maximum of the two provided IntPtr values.
154  Node* IntPtrMax(Node* left, Node* right);
155  // Select the minimum of the two provided IntPtr values.
156  Node* IntPtrMin(Node* left, Node* right);
157
158  // Float64 operations.
159  Node* Float64Ceil(Node* x);
160  Node* Float64Floor(Node* x);
161  Node* Float64Round(Node* x);
162  Node* Float64RoundToEven(Node* x);
163  Node* Float64Trunc(Node* x);
164
165  // Tag a Word as a Smi value.
166  Node* SmiTag(Node* value);
167  // Untag a Smi value as a Word.
168  Node* SmiUntag(Node* value);
169
170  // Smi conversions.
171  Node* SmiToFloat64(Node* value);
172  Node* SmiFromWord(Node* value) { return SmiTag(value); }
173  Node* SmiFromWord32(Node* value);
174  Node* SmiToWord(Node* value) { return SmiUntag(value); }
175  Node* SmiToWord32(Node* value);
176
177  // Smi operations.
178#define SMI_ARITHMETIC_BINOP(SmiOpName, IntPtrOpName)                  \
179  Node* SmiOpName(Node* a, Node* b) {                                  \
180    return BitcastWordToTaggedSigned(                                  \
181        IntPtrOpName(BitcastTaggedToWord(a), BitcastTaggedToWord(b))); \
182  }
183  SMI_ARITHMETIC_BINOP(SmiAdd, IntPtrAdd)
184  SMI_ARITHMETIC_BINOP(SmiSub, IntPtrSub)
185  SMI_ARITHMETIC_BINOP(SmiAnd, WordAnd)
186  SMI_ARITHMETIC_BINOP(SmiOr, WordOr)
187#undef SMI_ARITHMETIC_BINOP
188
189  Node* SmiShl(Node* a, int shift) {
190    return BitcastWordToTaggedSigned(WordShl(BitcastTaggedToWord(a), shift));
191  }
192
193  Node* SmiShr(Node* a, int shift) {
194    return BitcastWordToTaggedSigned(
195        WordAnd(WordShr(BitcastTaggedToWord(a), shift),
196                BitcastTaggedToWord(SmiConstant(-1))));
197  }
198
199  Node* WordOrSmiShl(Node* a, int shift, ParameterMode mode) {
200    if (mode == SMI_PARAMETERS) {
201      return SmiShl(a, shift);
202    } else {
203      DCHECK_EQ(INTPTR_PARAMETERS, mode);
204      return WordShl(a, shift);
205    }
206  }
207
208  Node* WordOrSmiShr(Node* a, int shift, ParameterMode mode) {
209    if (mode == SMI_PARAMETERS) {
210      return SmiShr(a, shift);
211    } else {
212      DCHECK_EQ(INTPTR_PARAMETERS, mode);
213      return WordShr(a, shift);
214    }
215  }
216
217#define SMI_COMPARISON_OP(SmiOpName, IntPtrOpName)                       \
218  Node* SmiOpName(Node* a, Node* b) {                                    \
219    return IntPtrOpName(BitcastTaggedToWord(a), BitcastTaggedToWord(b)); \
220  }
221  SMI_COMPARISON_OP(SmiEqual, WordEqual)
222  SMI_COMPARISON_OP(SmiNotEqual, WordNotEqual)
223  SMI_COMPARISON_OP(SmiAbove, UintPtrGreaterThan)
224  SMI_COMPARISON_OP(SmiAboveOrEqual, UintPtrGreaterThanOrEqual)
225  SMI_COMPARISON_OP(SmiBelow, UintPtrLessThan)
226  SMI_COMPARISON_OP(SmiLessThan, IntPtrLessThan)
227  SMI_COMPARISON_OP(SmiLessThanOrEqual, IntPtrLessThanOrEqual)
228  SMI_COMPARISON_OP(SmiGreaterThan, IntPtrGreaterThan)
229  SMI_COMPARISON_OP(SmiGreaterThanOrEqual, IntPtrGreaterThanOrEqual)
230#undef SMI_COMPARISON_OP
231  Node* SmiMax(Node* a, Node* b);
232  Node* SmiMin(Node* a, Node* b);
233  // Computes a % b for Smi inputs a and b; result is not necessarily a Smi.
234  Node* SmiMod(Node* a, Node* b);
235  // Computes a * b for Smi inputs a and b; result is not necessarily a Smi.
236  Node* SmiMul(Node* a, Node* b);
237
238  // Smi | HeapNumber operations.
239  Node* NumberInc(Node* value);
240  void GotoIfNotNumber(Node* value, Label* is_not_number);
241  void GotoIfNumber(Node* value, Label* is_number);
242
243  // Allocate an object of the given size.
244  Node* Allocate(Node* size, AllocationFlags flags = kNone);
245  Node* Allocate(int size, AllocationFlags flags = kNone);
246  Node* InnerAllocate(Node* previous, int offset);
247  Node* InnerAllocate(Node* previous, Node* offset);
248  Node* IsRegularHeapObjectSize(Node* size);
249
250  typedef std::function<Node*()> NodeGenerator;
251
252  void Assert(const NodeGenerator& condition_body, const char* string = nullptr,
253              const char* file = nullptr, int line = 0);
254
255  Node* Select(Node* condition, const NodeGenerator& true_body,
256               const NodeGenerator& false_body, MachineRepresentation rep);
257
258  Node* SelectConstant(Node* condition, Node* true_value, Node* false_value,
259                       MachineRepresentation rep);
260
261  Node* SelectInt32Constant(Node* condition, int true_value, int false_value);
262  Node* SelectIntPtrConstant(Node* condition, int true_value, int false_value);
263  Node* SelectBooleanConstant(Node* condition);
264  Node* SelectTaggedConstant(Node* condition, Node* true_value,
265                             Node* false_value);
266  Node* SelectSmiConstant(Node* condition, Smi* true_value, Smi* false_value);
267  Node* SelectSmiConstant(Node* condition, int true_value, Smi* false_value) {
268    return SelectSmiConstant(condition, Smi::FromInt(true_value), false_value);
269  }
270  Node* SelectSmiConstant(Node* condition, Smi* true_value, int false_value) {
271    return SelectSmiConstant(condition, true_value, Smi::FromInt(false_value));
272  }
273  Node* SelectSmiConstant(Node* condition, int true_value, int false_value) {
274    return SelectSmiConstant(condition, Smi::FromInt(true_value),
275                             Smi::FromInt(false_value));
276  }
277
278  Node* TruncateWordToWord32(Node* value);
279
280  // Check a value for smi-ness
281  Node* TaggedIsSmi(Node* a);
282  Node* TaggedIsNotSmi(Node* a);
283  // Check that the value is a non-negative smi.
284  Node* TaggedIsPositiveSmi(Node* a);
285  // Check that a word has a word-aligned address.
286  Node* WordIsWordAligned(Node* word);
287  Node* WordIsPowerOfTwo(Node* value);
288
289  void BranchIfSmiEqual(Node* a, Node* b, Label* if_true, Label* if_false) {
290    Branch(SmiEqual(a, b), if_true, if_false);
291  }
292
293  void BranchIfSmiLessThan(Node* a, Node* b, Label* if_true, Label* if_false) {
294    Branch(SmiLessThan(a, b), if_true, if_false);
295  }
296
297  void BranchIfSmiLessThanOrEqual(Node* a, Node* b, Label* if_true,
298                                  Label* if_false) {
299    Branch(SmiLessThanOrEqual(a, b), if_true, if_false);
300  }
301
302  void BranchIfFloat64IsNaN(Node* value, Label* if_true, Label* if_false) {
303    Branch(Float64Equal(value, value), if_false, if_true);
304  }
305
306  // Branches to {if_true} if ToBoolean applied to {value} yields true,
307  // otherwise goes to {if_false}.
308  void BranchIfToBooleanIsTrue(Node* value, Label* if_true, Label* if_false);
309
310  void BranchIfJSReceiver(Node* object, Label* if_true, Label* if_false);
311  void BranchIfJSObject(Node* object, Label* if_true, Label* if_false);
312
313  enum class FastJSArrayAccessMode { INBOUNDS_READ, ANY_ACCESS };
314  void BranchIfFastJSArray(Node* object, Node* context,
315                           FastJSArrayAccessMode mode, Label* if_true,
316                           Label* if_false);
317
318  // Load value from current frame by given offset in bytes.
319  Node* LoadFromFrame(int offset, MachineType rep = MachineType::AnyTagged());
320  // Load value from current parent frame by given offset in bytes.
321  Node* LoadFromParentFrame(int offset,
322                            MachineType rep = MachineType::AnyTagged());
323
324  // Load an object pointer from a buffer that isn't in the heap.
325  Node* LoadBufferObject(Node* buffer, int offset,
326                         MachineType rep = MachineType::AnyTagged());
327  // Load a field from an object on the heap.
328  Node* LoadObjectField(Node* object, int offset,
329                        MachineType rep = MachineType::AnyTagged());
330  Node* LoadObjectField(Node* object, Node* offset,
331                        MachineType rep = MachineType::AnyTagged());
332  // Load a SMI field and untag it.
333  Node* LoadAndUntagObjectField(Node* object, int offset);
334  // Load a SMI field, untag it, and convert to Word32.
335  Node* LoadAndUntagToWord32ObjectField(Node* object, int offset);
336  // Load a SMI and untag it.
337  Node* LoadAndUntagSmi(Node* base, int index);
338  // Load a SMI root, untag it, and convert to Word32.
339  Node* LoadAndUntagToWord32Root(Heap::RootListIndex root_index);
340
341  // Tag a smi and store it.
342  Node* StoreAndTagSmi(Node* base, int offset, Node* value);
343
344  // Load the floating point value of a HeapNumber.
345  Node* LoadHeapNumberValue(Node* object);
346  // Load the Map of an HeapObject.
347  Node* LoadMap(Node* object);
348  // Load the instance type of an HeapObject.
349  Node* LoadInstanceType(Node* object);
350  // Compare the instance the type of the object against the provided one.
351  Node* HasInstanceType(Node* object, InstanceType type);
352  Node* DoesntHaveInstanceType(Node* object, InstanceType type);
353  // Load the properties backing store of a JSObject.
354  Node* LoadProperties(Node* object);
355  // Load the elements backing store of a JSObject.
356  Node* LoadElements(Node* object);
357  // Load the length of a JSArray instance.
358  Node* LoadJSArrayLength(Node* array);
359  // Load the length of a fixed array base instance.
360  Node* LoadFixedArrayBaseLength(Node* array);
361  // Load the length of a fixed array base instance.
362  Node* LoadAndUntagFixedArrayBaseLength(Node* array);
363  // Load the bit field of a Map.
364  Node* LoadMapBitField(Node* map);
365  // Load bit field 2 of a map.
366  Node* LoadMapBitField2(Node* map);
367  // Load bit field 3 of a map.
368  Node* LoadMapBitField3(Node* map);
369  // Load the instance type of a map.
370  Node* LoadMapInstanceType(Node* map);
371  // Load the ElementsKind of a map.
372  Node* LoadMapElementsKind(Node* map);
373  // Load the instance descriptors of a map.
374  Node* LoadMapDescriptors(Node* map);
375  // Load the prototype of a map.
376  Node* LoadMapPrototype(Node* map);
377  // Load the prototype info of a map. The result has to be checked if it is a
378  // prototype info object or not.
379  Node* LoadMapPrototypeInfo(Node* map, Label* if_has_no_proto_info);
380  // Load the instance size of a Map.
381  Node* LoadMapInstanceSize(Node* map);
382  // Load the inobject properties count of a Map (valid only for JSObjects).
383  Node* LoadMapInobjectProperties(Node* map);
384  // Load the constructor function index of a Map (only for primitive maps).
385  Node* LoadMapConstructorFunctionIndex(Node* map);
386  // Load the constructor of a Map (equivalent to Map::GetConstructor()).
387  Node* LoadMapConstructor(Node* map);
388  // Loads a value from the specially encoded integer fields in the
389  // SharedFunctionInfo object.
390  // TODO(danno): This currently only works for the integer fields that are
391  // mapped to the upper part of 64-bit words. We should customize
392  // SFI::BodyDescriptor and store int32 values directly.
393  Node* LoadSharedFunctionInfoSpecialField(Node* shared, int offset,
394                                           ParameterMode param_mode);
395
396  // Check if the map is set for slow properties.
397  Node* IsDictionaryMap(Node* map);
398
399  // Load the hash field of a name as an uint32 value.
400  Node* LoadNameHashField(Node* name);
401  // Load the hash value of a name as an uint32 value.
402  // If {if_hash_not_computed} label is specified then it also checks if
403  // hash is actually computed.
404  Node* LoadNameHash(Node* name, Label* if_hash_not_computed = nullptr);
405
406  // Load length field of a String object.
407  Node* LoadStringLength(Node* object);
408  // Load value field of a JSValue object.
409  Node* LoadJSValueValue(Node* object);
410  // Load value field of a WeakCell object.
411  Node* LoadWeakCellValueUnchecked(Node* weak_cell);
412  Node* LoadWeakCellValue(Node* weak_cell, Label* if_cleared = nullptr);
413
414  // Load an array element from a FixedArray.
415  Node* LoadFixedArrayElement(Node* object, Node* index,
416                              int additional_offset = 0,
417                              ParameterMode parameter_mode = INTPTR_PARAMETERS);
418  Node* LoadFixedArrayElement(Node* object, int index,
419                              int additional_offset = 0) {
420    return LoadFixedArrayElement(object, IntPtrConstant(index),
421                                 additional_offset);
422  }
423  // Load an array element from a FixedArray, untag it and return it as Word32.
424  Node* LoadAndUntagToWord32FixedArrayElement(
425      Node* object, Node* index, int additional_offset = 0,
426      ParameterMode parameter_mode = INTPTR_PARAMETERS);
427  // Load an array element from a FixedDoubleArray.
428  Node* LoadFixedDoubleArrayElement(
429      Node* object, Node* index, MachineType machine_type,
430      int additional_offset = 0,
431      ParameterMode parameter_mode = INTPTR_PARAMETERS,
432      Label* if_hole = nullptr);
433
434  // Load Float64 value by |base| + |offset| address. If the value is a double
435  // hole then jump to |if_hole|. If |machine_type| is None then only the hole
436  // check is generated.
437  Node* LoadDoubleWithHoleCheck(
438      Node* base, Node* offset, Label* if_hole,
439      MachineType machine_type = MachineType::Float64());
440  Node* LoadFixedTypedArrayElement(
441      Node* data_pointer, Node* index_node, ElementsKind elements_kind,
442      ParameterMode parameter_mode = INTPTR_PARAMETERS);
443
444  // Context manipulation
445  Node* LoadContextElement(Node* context, int slot_index);
446  Node* LoadContextElement(Node* context, Node* slot_index);
447  Node* StoreContextElement(Node* context, int slot_index, Node* value);
448  Node* StoreContextElement(Node* context, Node* slot_index, Node* value);
449  Node* StoreContextElementNoWriteBarrier(Node* context, int slot_index,
450                                          Node* value);
451  Node* LoadNativeContext(Node* context);
452
453  Node* LoadJSArrayElementsMap(ElementsKind kind, Node* native_context);
454
455  // Store the floating point value of a HeapNumber.
456  Node* StoreHeapNumberValue(Node* object, Node* value);
457  // Store a field to an object on the heap.
458  Node* StoreObjectField(Node* object, int offset, Node* value);
459  Node* StoreObjectField(Node* object, Node* offset, Node* value);
460  Node* StoreObjectFieldNoWriteBarrier(
461      Node* object, int offset, Node* value,
462      MachineRepresentation rep = MachineRepresentation::kTagged);
463  Node* StoreObjectFieldNoWriteBarrier(
464      Node* object, Node* offset, Node* value,
465      MachineRepresentation rep = MachineRepresentation::kTagged);
466  // Store the Map of an HeapObject.
467  Node* StoreMap(Node* object, Node* map);
468  Node* StoreMapNoWriteBarrier(Node* object,
469                               Heap::RootListIndex map_root_index);
470  Node* StoreMapNoWriteBarrier(Node* object, Node* map);
471  Node* StoreObjectFieldRoot(Node* object, int offset,
472                             Heap::RootListIndex root);
473  // Store an array element to a FixedArray.
474  Node* StoreFixedArrayElement(
475      Node* object, int index, Node* value,
476      WriteBarrierMode barrier_mode = UPDATE_WRITE_BARRIER) {
477    return StoreFixedArrayElement(object, IntPtrConstant(index), value,
478                                  barrier_mode);
479  }
480
481  Node* StoreFixedArrayElement(
482      Node* object, Node* index, Node* value,
483      WriteBarrierMode barrier_mode = UPDATE_WRITE_BARRIER,
484      int additional_offset = 0,
485      ParameterMode parameter_mode = INTPTR_PARAMETERS);
486
487  Node* StoreFixedDoubleArrayElement(
488      Node* object, Node* index, Node* value,
489      ParameterMode parameter_mode = INTPTR_PARAMETERS);
490
491  Node* BuildAppendJSArray(ElementsKind kind, Node* context, Node* array,
492                           CodeStubArguments& args, Variable& arg_index,
493                           Label* bailout);
494
495  void StoreFieldsNoWriteBarrier(Node* start_address, Node* end_address,
496                                 Node* value);
497
498  // Allocate a HeapNumber without initializing its value.
499  Node* AllocateHeapNumber(MutableMode mode = IMMUTABLE);
500  // Allocate a HeapNumber with a specific value.
501  Node* AllocateHeapNumberWithValue(Node* value, MutableMode mode = IMMUTABLE);
502  // Allocate a SeqOneByteString with the given length.
503  Node* AllocateSeqOneByteString(int length, AllocationFlags flags = kNone);
504  Node* AllocateSeqOneByteString(Node* context, Node* length,
505                                 ParameterMode mode = INTPTR_PARAMETERS,
506                                 AllocationFlags flags = kNone);
507  // Allocate a SeqTwoByteString with the given length.
508  Node* AllocateSeqTwoByteString(int length, AllocationFlags flags = kNone);
509  Node* AllocateSeqTwoByteString(Node* context, Node* length,
510                                 ParameterMode mode = INTPTR_PARAMETERS,
511                                 AllocationFlags flags = kNone);
512
513  // Allocate a SlicedOneByteString with the given length, parent and offset.
514  // |length| and |offset| are expected to be tagged.
515  Node* AllocateSlicedOneByteString(Node* length, Node* parent, Node* offset);
516  // Allocate a SlicedTwoByteString with the given length, parent and offset.
517  // |length| and |offset| are expected to be tagged.
518  Node* AllocateSlicedTwoByteString(Node* length, Node* parent, Node* offset);
519
520  // Allocate a one-byte ConsString with the given length, first and second
521  // parts. |length| is expected to be tagged, and |first| and |second| are
522  // expected to be one-byte strings.
523  Node* AllocateOneByteConsString(Node* length, Node* first, Node* second,
524                                  AllocationFlags flags = kNone);
525  // Allocate a two-byte ConsString with the given length, first and second
526  // parts. |length| is expected to be tagged, and |first| and |second| are
527  // expected to be two-byte strings.
528  Node* AllocateTwoByteConsString(Node* length, Node* first, Node* second,
529                                  AllocationFlags flags = kNone);
530
531  // Allocate an appropriate one- or two-byte ConsString with the first and
532  // second parts specified by |first| and |second|.
533  Node* NewConsString(Node* context, Node* length, Node* left, Node* right,
534                      AllocationFlags flags = kNone);
535
536  // Allocate a RegExpResult with the given length (the number of captures,
537  // including the match itself), index (the index where the match starts),
538  // and input string. |length| and |index| are expected to be tagged, and
539  // |input| must be a string.
540  Node* AllocateRegExpResult(Node* context, Node* length, Node* index,
541                             Node* input);
542
543  Node* AllocateNameDictionary(int capacity);
544  Node* AllocateNameDictionary(Node* capacity);
545
546  Node* AllocateJSObjectFromMap(Node* map, Node* properties = nullptr,
547                                Node* elements = nullptr,
548                                AllocationFlags flags = kNone);
549
550  void InitializeJSObjectFromMap(Node* object, Node* map, Node* size,
551                                 Node* properties = nullptr,
552                                 Node* elements = nullptr);
553
554  void InitializeJSObjectBody(Node* object, Node* map, Node* size,
555                              int start_offset = JSObject::kHeaderSize);
556
557  // Allocate a JSArray without elements and initialize the header fields.
558  Node* AllocateUninitializedJSArrayWithoutElements(ElementsKind kind,
559                                                    Node* array_map,
560                                                    Node* length,
561                                                    Node* allocation_site);
562  // Allocate and return a JSArray with initialized header fields and its
563  // uninitialized elements.
564  // The ParameterMode argument is only used for the capacity parameter.
565  std::pair<Node*, Node*> AllocateUninitializedJSArrayWithElements(
566      ElementsKind kind, Node* array_map, Node* length, Node* allocation_site,
567      Node* capacity, ParameterMode capacity_mode = INTPTR_PARAMETERS);
568  // Allocate a JSArray and fill elements with the hole.
569  // The ParameterMode argument is only used for the capacity parameter.
570  Node* AllocateJSArray(ElementsKind kind, Node* array_map, Node* capacity,
571                        Node* length, Node* allocation_site = nullptr,
572                        ParameterMode capacity_mode = INTPTR_PARAMETERS);
573
574  Node* AllocateFixedArray(ElementsKind kind, Node* capacity,
575                           ParameterMode mode = INTPTR_PARAMETERS,
576                           AllocationFlags flags = kNone);
577
578  // Perform CreateArrayIterator (ES6 #sec-createarrayiterator).
579  Node* CreateArrayIterator(Node* array, Node* array_map, Node* array_type,
580                            Node* context, IterationKind mode);
581
582  Node* AllocateJSArrayIterator(Node* array, Node* array_map, Node* map);
583
584  void FillFixedArrayWithValue(ElementsKind kind, Node* array, Node* from_index,
585                               Node* to_index,
586                               Heap::RootListIndex value_root_index,
587                               ParameterMode mode = INTPTR_PARAMETERS);
588
589  // Copies all elements from |from_array| of |length| size to
590  // |to_array| of the same size respecting the elements kind.
591  void CopyFixedArrayElements(
592      ElementsKind kind, Node* from_array, Node* to_array, Node* length,
593      WriteBarrierMode barrier_mode = UPDATE_WRITE_BARRIER,
594      ParameterMode mode = INTPTR_PARAMETERS) {
595    CopyFixedArrayElements(kind, from_array, kind, to_array, length, length,
596                           barrier_mode, mode);
597  }
598
599  // Copies |element_count| elements from |from_array| to |to_array| of
600  // |capacity| size respecting both array's elements kinds.
601  void CopyFixedArrayElements(
602      ElementsKind from_kind, Node* from_array, ElementsKind to_kind,
603      Node* to_array, Node* element_count, Node* capacity,
604      WriteBarrierMode barrier_mode = UPDATE_WRITE_BARRIER,
605      ParameterMode mode = INTPTR_PARAMETERS);
606
607  // Copies |character_count| elements from |from_string| to |to_string|
608  // starting at the |from_index|'th character. |from_string| and |to_string|
609  // can either be one-byte strings or two-byte strings, although if
610  // |from_string| is two-byte, then |to_string| must be two-byte.
611  // |from_index|, |to_index| and |character_count| must be either Smis or
612  // intptr_ts depending on |mode| s.t. 0 <= |from_index| <= |from_index| +
613  // |character_count| <= from_string.length and 0 <= |to_index| <= |to_index| +
614  // |character_count| <= to_string.length.
615  void CopyStringCharacters(Node* from_string, Node* to_string,
616                            Node* from_index, Node* to_index,
617                            Node* character_count,
618                            String::Encoding from_encoding,
619                            String::Encoding to_encoding, ParameterMode mode);
620
621  // Loads an element from |array| of |from_kind| elements by given |offset|
622  // (NOTE: not index!), does a hole check if |if_hole| is provided and
623  // converts the value so that it becomes ready for storing to array of
624  // |to_kind| elements.
625  Node* LoadElementAndPrepareForStore(Node* array, Node* offset,
626                                      ElementsKind from_kind,
627                                      ElementsKind to_kind, Label* if_hole);
628
629  Node* CalculateNewElementsCapacity(Node* old_capacity,
630                                     ParameterMode mode = INTPTR_PARAMETERS);
631
632  // Tries to grow the |elements| array of given |object| to store the |key|
633  // or bails out if the growing gap is too big. Returns new elements.
634  Node* TryGrowElementsCapacity(Node* object, Node* elements, ElementsKind kind,
635                                Node* key, Label* bailout);
636
637  // Tries to grow the |capacity|-length |elements| array of given |object|
638  // to store the |key| or bails out if the growing gap is too big. Returns
639  // new elements.
640  Node* TryGrowElementsCapacity(Node* object, Node* elements, ElementsKind kind,
641                                Node* key, Node* capacity, ParameterMode mode,
642                                Label* bailout);
643
644  // Grows elements capacity of given object. Returns new elements.
645  Node* GrowElementsCapacity(Node* object, Node* elements,
646                             ElementsKind from_kind, ElementsKind to_kind,
647                             Node* capacity, Node* new_capacity,
648                             ParameterMode mode, Label* bailout);
649
650  // Allocation site manipulation
651  void InitializeAllocationMemento(Node* base_allocation,
652                                   int base_allocation_size,
653                                   Node* allocation_site);
654
655  Node* TryTaggedToFloat64(Node* value, Label* if_valueisnotnumber);
656  Node* TruncateTaggedToFloat64(Node* context, Node* value);
657  Node* TruncateTaggedToWord32(Node* context, Node* value);
658  // Truncate the floating point value of a HeapNumber to an Int32.
659  Node* TruncateHeapNumberValueToWord32(Node* object);
660
661  // Conversions.
662  Node* ChangeFloat64ToTagged(Node* value);
663  Node* ChangeInt32ToTagged(Node* value);
664  Node* ChangeUint32ToTagged(Node* value);
665  Node* ChangeNumberToFloat64(Node* value);
666
667  // Type conversions.
668  // Throws a TypeError for {method_name} if {value} is not coercible to Object,
669  // or returns the {value} converted to a String otherwise.
670  Node* ToThisString(Node* context, Node* value, char const* method_name);
671  // Throws a TypeError for {method_name} if {value} is neither of the given
672  // {primitive_type} nor a JSValue wrapping a value of {primitive_type}, or
673  // returns the {value} (or wrapped value) otherwise.
674  Node* ToThisValue(Node* context, Node* value, PrimitiveType primitive_type,
675                    char const* method_name);
676
677  // Throws a TypeError for {method_name} if {value} is not of the given
678  // instance type. Returns {value}'s map.
679  Node* ThrowIfNotInstanceType(Node* context, Node* value,
680                               InstanceType instance_type,
681                               char const* method_name);
682
683  // Type checks.
684  // Check whether the map is for an object with special properties, such as a
685  // JSProxy or an object with interceptors.
686  Node* InstanceTypeEqual(Node* instance_type, int type);
687  Node* IsSpecialReceiverMap(Node* map);
688  Node* IsSpecialReceiverInstanceType(Node* instance_type);
689  Node* IsStringInstanceType(Node* instance_type);
690  Node* IsString(Node* object);
691  Node* IsJSObject(Node* object);
692  Node* IsJSGlobalProxy(Node* object);
693  Node* IsJSReceiverInstanceType(Node* instance_type);
694  Node* IsJSReceiver(Node* object);
695  Node* IsJSReceiverMap(Node* map);
696  Node* IsMap(Node* object);
697  Node* IsCallableMap(Node* map);
698  Node* IsCallable(Node* object);
699  Node* IsBoolean(Node* object);
700  Node* IsHeapNumber(Node* object);
701  Node* IsName(Node* object);
702  Node* IsSymbol(Node* object);
703  Node* IsPrivateSymbol(Node* object);
704  Node* IsJSValue(Node* object);
705  Node* IsJSArray(Node* object);
706  Node* IsNativeContext(Node* object);
707  Node* IsWeakCell(Node* object);
708  Node* IsFixedDoubleArray(Node* object);
709  Node* IsHashTable(Node* object);
710  Node* IsDictionary(Node* object);
711  Node* IsUnseededNumberDictionary(Node* object);
712  Node* IsConstructorMap(Node* map);
713  Node* IsJSFunction(Node* object);
714
715  // ElementsKind helpers:
716  Node* IsFastElementsKind(Node* elements_kind);
717  Node* IsHoleyFastElementsKind(Node* elements_kind);
718
719  // String helpers.
720  // Load a character from a String (might flatten a ConsString).
721  Node* StringCharCodeAt(Node* string, Node* index,
722                         ParameterMode parameter_mode = SMI_PARAMETERS);
723  // Return the single character string with only {code}.
724  Node* StringFromCharCode(Node* code);
725  // Return a new string object which holds a substring containing the range
726  // [from,to[ of string.  |from| and |to| are expected to be tagged.
727  Node* SubString(Node* context, Node* string, Node* from, Node* to);
728
729  // Return a new string object produced by concatenating |first| with |second|.
730  Node* StringAdd(Node* context, Node* first, Node* second,
731                  AllocationFlags flags = kNone);
732
733  // Unpack the external string, returning a pointer that (offset-wise) looks
734  // like a sequential string.
735  // Note that this pointer is not tagged and does not point to a real
736  // sequential string instance, and may only be used to access the string
737  // data. The pointer is GC-safe as long as a reference to the container
738  // ExternalString is live.
739  // |string| must be an external string. Bailout for short external strings.
740  Node* TryDerefExternalString(Node* const string, Node* const instance_type,
741                               Label* if_bailout);
742
743  // Check if |var_string| has an indirect (thin or flat cons) string type,
744  // and unpack it if so.
745  void MaybeDerefIndirectString(Variable* var_string, Node* instance_type,
746                                Variable* var_did_something);
747  // Check if |var_left| or |var_right| has an indirect (thin or flat cons)
748  // string type, and unpack it/them if so. Fall through if nothing was done.
749  void MaybeDerefIndirectStrings(Variable* var_left, Node* left_instance_type,
750                                 Variable* var_right, Node* right_instance_type,
751                                 Label* did_something);
752
753  Node* StringFromCodePoint(Node* codepoint, UnicodeEncoding encoding);
754
755  // Type conversion helpers.
756  // Convert a String to a Number.
757  Node* StringToNumber(Node* context, Node* input);
758  Node* NumberToString(Node* context, Node* input);
759  // Convert an object to a name.
760  Node* ToName(Node* context, Node* input);
761  // Convert a Non-Number object to a Number.
762  Node* NonNumberToNumber(Node* context, Node* input);
763  // Convert any object to a Number.
764  Node* ToNumber(Node* context, Node* input);
765
766  // Converts |input| to one of 2^32 integer values in the range 0 through
767  // 2^32-1, inclusive.
768  // ES#sec-touint32
769  compiler::Node* ToUint32(compiler::Node* context, compiler::Node* input);
770
771  // Convert any object to a String.
772  Node* ToString(Node* context, Node* input);
773
774  // Convert any object to a Primitive.
775  Node* JSReceiverToPrimitive(Node* context, Node* input);
776
777  enum ToIntegerTruncationMode {
778    kNoTruncation,
779    kTruncateMinusZero,
780  };
781
782  // Convert any object to an Integer.
783  Node* ToInteger(Node* context, Node* input,
784                  ToIntegerTruncationMode mode = kNoTruncation);
785
786  // Returns a node that contains a decoded (unsigned!) value of a bit
787  // field |T| in |word32|. Returns result as an uint32 node.
788  template <typename T>
789  Node* DecodeWord32(Node* word32) {
790    return DecodeWord32(word32, T::kShift, T::kMask);
791  }
792
793  // Returns a node that contains a decoded (unsigned!) value of a bit
794  // field |T| in |word|. Returns result as a word-size node.
795  template <typename T>
796  Node* DecodeWord(Node* word) {
797    return DecodeWord(word, T::kShift, T::kMask);
798  }
799
800  // Returns a node that contains a decoded (unsigned!) value of a bit
801  // field |T| in |word32|. Returns result as a word-size node.
802  template <typename T>
803  Node* DecodeWordFromWord32(Node* word32) {
804    return DecodeWord<T>(ChangeUint32ToWord(word32));
805  }
806
807  // Returns a node that contains a decoded (unsigned!) value of a bit
808  // field |T| in |word|. Returns result as an uint32 node.
809  template <typename T>
810  Node* DecodeWord32FromWord(Node* word) {
811    return TruncateWordToWord32(DecodeWord<T>(word));
812  }
813
814  // Decodes an unsigned (!) value from |word32| to an uint32 node.
815  Node* DecodeWord32(Node* word32, uint32_t shift, uint32_t mask);
816
817  // Decodes an unsigned (!) value from |word| to a word-size node.
818  Node* DecodeWord(Node* word, uint32_t shift, uint32_t mask);
819
820  // Returns true if any of the |T|'s bits in given |word32| are set.
821  template <typename T>
822  Node* IsSetWord32(Node* word32) {
823    return IsSetWord32(word32, T::kMask);
824  }
825
826  // Returns true if any of the mask's bits in given |word32| are set.
827  Node* IsSetWord32(Node* word32, uint32_t mask) {
828    return Word32NotEqual(Word32And(word32, Int32Constant(mask)),
829                          Int32Constant(0));
830  }
831
832  // Returns true if any of the |T|'s bits in given |word| are set.
833  template <typename T>
834  Node* IsSetWord(Node* word) {
835    return IsSetWord(word, T::kMask);
836  }
837
838  // Returns true if any of the mask's bits in given |word| are set.
839  Node* IsSetWord(Node* word, uint32_t mask) {
840    return WordNotEqual(WordAnd(word, IntPtrConstant(mask)), IntPtrConstant(0));
841  }
842
843  // Returns true if any of the mask's bit are set in the given Smi.
844  // Smi-encoding of the mask is performed implicitly!
845  Node* IsSetSmi(Node* smi, int untagged_mask) {
846    intptr_t mask_word = bit_cast<intptr_t>(Smi::FromInt(untagged_mask));
847    return WordNotEqual(
848        WordAnd(BitcastTaggedToWord(smi), IntPtrConstant(mask_word)),
849        IntPtrConstant(0));
850  }
851
852  // Returns true if all of the |T|'s bits in given |word32| are clear.
853  template <typename T>
854  Node* IsClearWord32(Node* word32) {
855    return IsClearWord32(word32, T::kMask);
856  }
857
858  // Returns true if all of the mask's bits in given |word32| are clear.
859  Node* IsClearWord32(Node* word32, uint32_t mask) {
860    return Word32Equal(Word32And(word32, Int32Constant(mask)),
861                       Int32Constant(0));
862  }
863
864  // Returns true if all of the |T|'s bits in given |word| are clear.
865  template <typename T>
866  Node* IsClearWord(Node* word) {
867    return IsClearWord(word, T::kMask);
868  }
869
870  // Returns true if all of the mask's bits in given |word| are clear.
871  Node* IsClearWord(Node* word, uint32_t mask) {
872    return WordEqual(WordAnd(word, IntPtrConstant(mask)), IntPtrConstant(0));
873  }
874
875  void SetCounter(StatsCounter* counter, int value);
876  void IncrementCounter(StatsCounter* counter, int delta);
877  void DecrementCounter(StatsCounter* counter, int delta);
878
879  void Increment(Variable& variable, int value = 1,
880                 ParameterMode mode = INTPTR_PARAMETERS);
881
882  // Generates "if (false) goto label" code. Useful for marking a label as
883  // "live" to avoid assertion failures during graph building. In the resulting
884  // code this check will be eliminated.
885  void Use(Label* label);
886
887  // Various building blocks for stubs doing property lookups.
888  void TryToName(Node* key, Label* if_keyisindex, Variable* var_index,
889                 Label* if_keyisunique, Variable* var_unique,
890                 Label* if_bailout);
891
892  // Calculates array index for given dictionary entry and entry field.
893  // See Dictionary::EntryToIndex().
894  template <typename Dictionary>
895  Node* EntryToIndex(Node* entry, int field_index);
896  template <typename Dictionary>
897  Node* EntryToIndex(Node* entry) {
898    return EntryToIndex<Dictionary>(entry, Dictionary::kEntryKeyIndex);
899  }
900
901  // Loads the details for the entry with the given key_index.
902  // Returns an untagged int32.
903  template <class ContainerType>
904  Node* LoadDetailsByKeyIndex(Node* container, Node* key_index) {
905    const int kKeyToDetailsOffset =
906        (ContainerType::kEntryDetailsIndex - ContainerType::kEntryKeyIndex) *
907        kPointerSize;
908    return LoadAndUntagToWord32FixedArrayElement(container, key_index,
909                                                 kKeyToDetailsOffset);
910  }
911
912  // Loads the value for the entry with the given key_index.
913  // Returns a tagged value.
914  template <class ContainerType>
915  Node* LoadValueByKeyIndex(Node* container, Node* key_index) {
916    const int kKeyToValueOffset =
917        (ContainerType::kEntryValueIndex - ContainerType::kEntryKeyIndex) *
918        kPointerSize;
919    return LoadFixedArrayElement(container, key_index, kKeyToValueOffset);
920  }
921
922  // Stores the details for the entry with the given key_index.
923  // |details| must be a Smi.
924  template <class ContainerType>
925  void StoreDetailsByKeyIndex(Node* container, Node* key_index, Node* details) {
926    const int kKeyToDetailsOffset =
927        (ContainerType::kEntryDetailsIndex - ContainerType::kEntryKeyIndex) *
928        kPointerSize;
929    StoreFixedArrayElement(container, key_index, details, SKIP_WRITE_BARRIER,
930                           kKeyToDetailsOffset);
931  }
932
933  // Stores the value for the entry with the given key_index.
934  template <class ContainerType>
935  void StoreValueByKeyIndex(Node* container, Node* key_index, Node* value) {
936    const int kKeyToValueOffset =
937        (ContainerType::kEntryValueIndex - ContainerType::kEntryKeyIndex) *
938        kPointerSize;
939    StoreFixedArrayElement(container, key_index, value, UPDATE_WRITE_BARRIER,
940                           kKeyToValueOffset);
941  }
942
943  // Calculate a valid size for the a hash table.
944  Node* HashTableComputeCapacity(Node* at_least_space_for);
945
946  template <class Dictionary>
947  Node* GetNumberOfElements(Node* dictionary);
948
949  template <class Dictionary>
950  void SetNumberOfElements(Node* dictionary, Node* num_elements_smi);
951
952  template <class Dictionary>
953  Node* GetNumberOfDeletedElements(Node* dictionary);
954
955  template <class Dictionary>
956  Node* GetCapacity(Node* dictionary);
957
958  template <class Dictionary>
959  Node* GetNextEnumerationIndex(Node* dictionary);
960
961  template <class Dictionary>
962  void SetNextEnumerationIndex(Node* dictionary, Node* next_enum_index_smi);
963
964  // Looks up an entry in a NameDictionaryBase successor. If the entry is found
965  // control goes to {if_found} and {var_name_index} contains an index of the
966  // key field of the entry found. If the key is not found control goes to
967  // {if_not_found}.
968  static const int kInlinedDictionaryProbes = 4;
969  enum LookupMode { kFindExisting, kFindInsertionIndex };
970  template <typename Dictionary>
971  void NameDictionaryLookup(Node* dictionary, Node* unique_name,
972                            Label* if_found, Variable* var_name_index,
973                            Label* if_not_found,
974                            int inlined_probes = kInlinedDictionaryProbes,
975                            LookupMode mode = kFindExisting);
976
977  Node* ComputeIntegerHash(Node* key, Node* seed);
978
979  template <typename Dictionary>
980  void NumberDictionaryLookup(Node* dictionary, Node* intptr_index,
981                              Label* if_found, Variable* var_entry,
982                              Label* if_not_found);
983
984  template <class Dictionary>
985  void FindInsertionEntry(Node* dictionary, Node* key, Variable* var_key_index);
986
987  template <class Dictionary>
988  void InsertEntry(Node* dictionary, Node* key, Node* value, Node* index,
989                   Node* enum_index);
990
991  template <class Dictionary>
992  void Add(Node* dictionary, Node* key, Node* value, Label* bailout);
993
994  // Tries to check if {object} has own {unique_name} property.
995  void TryHasOwnProperty(Node* object, Node* map, Node* instance_type,
996                         Node* unique_name, Label* if_found,
997                         Label* if_not_found, Label* if_bailout);
998
999  // Tries to get {object}'s own {unique_name} property value. If the property
1000  // is an accessor then it also calls a getter. If the property is a double
1001  // field it re-wraps value in an immutable heap number.
1002  void TryGetOwnProperty(Node* context, Node* receiver, Node* object, Node* map,
1003                         Node* instance_type, Node* unique_name,
1004                         Label* if_found, Variable* var_value,
1005                         Label* if_not_found, Label* if_bailout);
1006
1007  Node* GetProperty(Node* context, Node* receiver, Handle<Name> name) {
1008    return CallStub(CodeFactory::GetProperty(isolate()), context, receiver,
1009                    HeapConstant(name));
1010  }
1011
1012  void LoadPropertyFromFastObject(Node* object, Node* map, Node* descriptors,
1013                                  Node* name_index, Variable* var_details,
1014                                  Variable* var_value);
1015
1016  void LoadPropertyFromNameDictionary(Node* dictionary, Node* entry,
1017                                      Variable* var_details,
1018                                      Variable* var_value);
1019
1020  void LoadPropertyFromGlobalDictionary(Node* dictionary, Node* entry,
1021                                        Variable* var_details,
1022                                        Variable* var_value, Label* if_deleted);
1023
1024  // Generic property lookup generator. If the {object} is fast and
1025  // {unique_name} property is found then the control goes to {if_found_fast}
1026  // label and {var_meta_storage} and {var_name_index} will contain
1027  // DescriptorArray and an index of the descriptor's name respectively.
1028  // If the {object} is slow or global then the control goes to {if_found_dict}
1029  // or {if_found_global} and the {var_meta_storage} and {var_name_index} will
1030  // contain a dictionary and an index of the key field of the found entry.
1031  // If property is not found or given lookup is not supported then
1032  // the control goes to {if_not_found} or {if_bailout} respectively.
1033  //
1034  // Note: this code does not check if the global dictionary points to deleted
1035  // entry! This has to be done by the caller.
1036  void TryLookupProperty(Node* object, Node* map, Node* instance_type,
1037                         Node* unique_name, Label* if_found_fast,
1038                         Label* if_found_dict, Label* if_found_global,
1039                         Variable* var_meta_storage, Variable* var_name_index,
1040                         Label* if_not_found, Label* if_bailout);
1041
1042  void TryLookupElement(Node* object, Node* map, Node* instance_type,
1043                        Node* intptr_index, Label* if_found,
1044                        Label* if_not_found, Label* if_bailout);
1045
1046  // This is a type of a lookup in holder generator function. In case of a
1047  // property lookup the {key} is guaranteed to be an unique name and in case of
1048  // element lookup the key is an Int32 index.
1049  typedef std::function<void(Node* receiver, Node* holder, Node* map,
1050                             Node* instance_type, Node* key, Label* next_holder,
1051                             Label* if_bailout)>
1052      LookupInHolder;
1053
1054  // Generic property prototype chain lookup generator.
1055  // For properties it generates lookup using given {lookup_property_in_holder}
1056  // and for elements it uses {lookup_element_in_holder}.
1057  // Upon reaching the end of prototype chain the control goes to {if_end}.
1058  // If it can't handle the case {receiver}/{key} case then the control goes
1059  // to {if_bailout}.
1060  void TryPrototypeChainLookup(Node* receiver, Node* key,
1061                               const LookupInHolder& lookup_property_in_holder,
1062                               const LookupInHolder& lookup_element_in_holder,
1063                               Label* if_end, Label* if_bailout);
1064
1065  // Instanceof helpers.
1066  // ES6 section 7.3.19 OrdinaryHasInstance (C, O)
1067  Node* OrdinaryHasInstance(Node* context, Node* callable, Node* object);
1068
1069  // Load type feedback vector from the stub caller's frame.
1070  Node* LoadFeedbackVectorForStub();
1071
1072  // Update the type feedback vector.
1073  void UpdateFeedback(Node* feedback, Node* feedback_vector, Node* slot_id);
1074
1075  Node* LoadReceiverMap(Node* receiver);
1076
1077  // Emits keyed sloppy arguments load. Returns either the loaded value.
1078  Node* LoadKeyedSloppyArguments(Node* receiver, Node* key, Label* bailout) {
1079    return EmitKeyedSloppyArguments(receiver, key, nullptr, bailout);
1080  }
1081
1082  // Emits keyed sloppy arguments store.
1083  void StoreKeyedSloppyArguments(Node* receiver, Node* key, Node* value,
1084                                 Label* bailout) {
1085    DCHECK_NOT_NULL(value);
1086    EmitKeyedSloppyArguments(receiver, key, value, bailout);
1087  }
1088
1089  // Loads script context from the script context table.
1090  Node* LoadScriptContext(Node* context, int context_index);
1091
1092  Node* Int32ToUint8Clamped(Node* int32_value);
1093  Node* Float64ToUint8Clamped(Node* float64_value);
1094
1095  Node* PrepareValueForWriteToTypedArray(Node* key, ElementsKind elements_kind,
1096                                         Label* bailout);
1097
1098  // Store value to an elements array with given elements kind.
1099  void StoreElement(Node* elements, ElementsKind kind, Node* index, Node* value,
1100                    ParameterMode mode);
1101
1102  void EmitElementStore(Node* object, Node* key, Node* value, bool is_jsarray,
1103                        ElementsKind elements_kind,
1104                        KeyedAccessStoreMode store_mode, Label* bailout);
1105
1106  Node* CheckForCapacityGrow(Node* object, Node* elements, ElementsKind kind,
1107                             Node* length, Node* key, ParameterMode mode,
1108                             bool is_js_array, Label* bailout);
1109
1110  Node* CopyElementsOnWrite(Node* object, Node* elements, ElementsKind kind,
1111                            Node* length, ParameterMode mode, Label* bailout);
1112
1113  void TransitionElementsKind(Node* object, Node* map, ElementsKind from_kind,
1114                              ElementsKind to_kind, bool is_jsarray,
1115                              Label* bailout);
1116
1117  void TrapAllocationMemento(Node* object, Label* memento_found);
1118
1119  Node* PageFromAddress(Node* address);
1120
1121  // Get the enumerable length from |map| and return the result as a Smi.
1122  Node* EnumLength(Node* map);
1123
1124  // Check the cache validity for |receiver|. Branch to |use_cache| if
1125  // the cache is valid, otherwise branch to |use_runtime|.
1126  void CheckEnumCache(Node* receiver, CodeStubAssembler::Label* use_cache,
1127                      CodeStubAssembler::Label* use_runtime);
1128
1129  // Create a new weak cell with a specified value and install it into a
1130  // feedback vector.
1131  Node* CreateWeakCellInFeedbackVector(Node* feedback_vector, Node* slot,
1132                                       Node* value);
1133
1134  // Create a new AllocationSite and install it into a feedback vector.
1135  Node* CreateAllocationSiteInFeedbackVector(Node* feedback_vector, Node* slot);
1136
1137  enum class IndexAdvanceMode { kPre, kPost };
1138
1139  typedef std::function<void(Node* index)> FastLoopBody;
1140
1141  Node* BuildFastLoop(const VariableList& var_list, Node* start_index,
1142                      Node* end_index, const FastLoopBody& body, int increment,
1143                      ParameterMode parameter_mode,
1144                      IndexAdvanceMode advance_mode = IndexAdvanceMode::kPre);
1145
1146  Node* BuildFastLoop(Node* start_index, Node* end_index,
1147                      const FastLoopBody& body, int increment,
1148                      ParameterMode parameter_mode,
1149                      IndexAdvanceMode advance_mode = IndexAdvanceMode::kPre) {
1150    return BuildFastLoop(VariableList(0, zone()), start_index, end_index, body,
1151                         increment, parameter_mode, advance_mode);
1152  }
1153
1154  enum class ForEachDirection { kForward, kReverse };
1155
1156  typedef std::function<void(Node* fixed_array, Node* offset)>
1157      FastFixedArrayForEachBody;
1158
1159  void BuildFastFixedArrayForEach(
1160      const CodeStubAssembler::VariableList& vars, Node* fixed_array,
1161      ElementsKind kind, Node* first_element_inclusive,
1162      Node* last_element_exclusive, const FastFixedArrayForEachBody& body,
1163      ParameterMode mode = INTPTR_PARAMETERS,
1164      ForEachDirection direction = ForEachDirection::kReverse);
1165
1166  void BuildFastFixedArrayForEach(
1167      Node* fixed_array, ElementsKind kind, Node* first_element_inclusive,
1168      Node* last_element_exclusive, const FastFixedArrayForEachBody& body,
1169      ParameterMode mode = INTPTR_PARAMETERS,
1170      ForEachDirection direction = ForEachDirection::kReverse) {
1171    CodeStubAssembler::VariableList list(0, zone());
1172    BuildFastFixedArrayForEach(list, fixed_array, kind, first_element_inclusive,
1173                               last_element_exclusive, body, mode, direction);
1174  }
1175
1176  Node* GetArrayAllocationSize(Node* element_count, ElementsKind kind,
1177                               ParameterMode mode, int header_size) {
1178    return ElementOffsetFromIndex(element_count, kind, mode, header_size);
1179  }
1180
1181  Node* GetFixedArrayAllocationSize(Node* element_count, ElementsKind kind,
1182                                    ParameterMode mode) {
1183    return GetArrayAllocationSize(element_count, kind, mode,
1184                                  FixedArray::kHeaderSize);
1185  }
1186
1187  void GotoIfFixedArraySizeDoesntFitInNewSpace(Node* element_count,
1188                                               Label* doesnt_fit, int base_size,
1189                                               ParameterMode mode);
1190
1191  void InitializeFieldsWithRoot(Node* object, Node* start_offset,
1192                                Node* end_offset, Heap::RootListIndex root);
1193
1194  enum RelationalComparisonMode {
1195    kLessThan,
1196    kLessThanOrEqual,
1197    kGreaterThan,
1198    kGreaterThanOrEqual
1199  };
1200
1201  Node* RelationalComparison(RelationalComparisonMode mode, Node* lhs,
1202                             Node* rhs, Node* context);
1203
1204  void BranchIfNumericRelationalComparison(RelationalComparisonMode mode,
1205                                           Node* lhs, Node* rhs, Label* if_true,
1206                                           Label* if_false);
1207
1208  void GotoUnlessNumberLessThan(Node* lhs, Node* rhs, Label* if_false);
1209
1210  enum ResultMode { kDontNegateResult, kNegateResult };
1211
1212  Node* Equal(ResultMode mode, Node* lhs, Node* rhs, Node* context);
1213
1214  Node* StrictEqual(ResultMode mode, Node* lhs, Node* rhs, Node* context);
1215
1216  // ECMA#sec-samevalue
1217  // Similar to StrictEqual except that NaNs are treated as equal and minus zero
1218  // differs from positive zero.
1219  // Unlike Equal and StrictEqual, returns a value suitable for use in Branch
1220  // instructions, e.g. Branch(SameValue(...), &label).
1221  Node* SameValue(Node* lhs, Node* rhs, Node* context);
1222
1223  Node* HasProperty(
1224      Node* object, Node* key, Node* context,
1225      Runtime::FunctionId fallback_runtime_function_id = Runtime::kHasProperty);
1226  Node* ForInFilter(Node* key, Node* object, Node* context);
1227
1228  Node* ClassOf(Node* object);
1229
1230  Node* Typeof(Node* value, Node* context);
1231
1232  Node* GetSuperConstructor(Node* value, Node* context);
1233
1234  Node* InstanceOf(Node* object, Node* callable, Node* context);
1235
1236  // Debug helpers
1237  Node* IsDebugActive();
1238
1239  // TypedArray/ArrayBuffer helpers
1240  Node* IsDetachedBuffer(Node* buffer);
1241
1242  Node* ElementOffsetFromIndex(Node* index, ElementsKind kind,
1243                               ParameterMode mode, int base_size = 0);
1244
1245  Node* AllocateFunctionWithMapAndContext(Node* map, Node* shared_info,
1246                                          Node* context);
1247
1248  // Promise helpers
1249  Node* IsPromiseHookEnabledOrDebugIsActive();
1250
1251  Node* AllocatePromiseReactionJobInfo(Node* value, Node* tasks,
1252                                       Node* deferred_promise,
1253                                       Node* deferred_on_resolve,
1254                                       Node* deferred_on_reject, Node* context);
1255
1256  // Helpers for StackFrame markers.
1257  Node* MarkerIsFrameType(Node* marker_or_function,
1258                          StackFrame::Type frame_type);
1259  Node* MarkerIsNotFrameType(Node* marker_or_function,
1260                             StackFrame::Type frame_type);
1261
1262  // Support for printf-style debugging
1263  void Print(const char* s);
1264  void Print(const char* prefix, Node* tagged_value);
1265  inline void Print(Node* tagged_value) { return Print(nullptr, tagged_value); }
1266
1267  template <class... TArgs>
1268  Node* MakeTypeError(MessageTemplate::Template message, Node* context,
1269                      TArgs... args) {
1270    STATIC_ASSERT(sizeof...(TArgs) <= 3);
1271    Node* const make_type_error = LoadContextElement(
1272        LoadNativeContext(context), Context::MAKE_TYPE_ERROR_INDEX);
1273    return CallJS(CodeFactory::Call(isolate()), context, make_type_error,
1274                  UndefinedConstant(), SmiConstant(message), args...);
1275  }
1276
1277 protected:
1278  void DescriptorLookup(Node* unique_name, Node* descriptors, Node* bitfield3,
1279                        Label* if_found, Variable* var_name_index,
1280                        Label* if_not_found);
1281  void DescriptorLookupLinear(Node* unique_name, Node* descriptors, Node* nof,
1282                              Label* if_found, Variable* var_name_index,
1283                              Label* if_not_found);
1284  void DescriptorLookupBinary(Node* unique_name, Node* descriptors, Node* nof,
1285                              Label* if_found, Variable* var_name_index,
1286                              Label* if_not_found);
1287
1288  Node* CallGetterIfAccessor(Node* value, Node* details, Node* context,
1289                             Node* receiver, Label* if_bailout);
1290
1291  Node* TryToIntptr(Node* key, Label* miss);
1292
1293  void BranchIfPrototypesHaveNoElements(Node* receiver_map,
1294                                        Label* definitely_no_elements,
1295                                        Label* possibly_elements);
1296
1297 private:
1298  friend class CodeStubArguments;
1299
1300  void HandleBreakOnNode();
1301
1302  Node* AllocateRawAligned(Node* size_in_bytes, AllocationFlags flags,
1303                           Node* top_address, Node* limit_address);
1304  Node* AllocateRawUnaligned(Node* size_in_bytes, AllocationFlags flags,
1305                             Node* top_adddress, Node* limit_address);
1306  // Allocate and return a JSArray of given total size in bytes with header
1307  // fields initialized.
1308  Node* AllocateUninitializedJSArray(ElementsKind kind, Node* array_map,
1309                                     Node* length, Node* allocation_site,
1310                                     Node* size_in_bytes);
1311
1312  Node* SmiShiftBitsConstant();
1313
1314  // Emits keyed sloppy arguments load if the |value| is nullptr or store
1315  // otherwise. Returns either the loaded value or |value|.
1316  Node* EmitKeyedSloppyArguments(Node* receiver, Node* key, Node* value,
1317                                 Label* bailout);
1318
1319  Node* AllocateSlicedString(Heap::RootListIndex map_root_index, Node* length,
1320                             Node* parent, Node* offset);
1321
1322  Node* AllocateConsString(Heap::RootListIndex map_root_index, Node* length,
1323                           Node* first, Node* second, AllocationFlags flags);
1324
1325  // Implements DescriptorArray::number_of_entries.
1326  // Returns an untagged int32.
1327  Node* DescriptorArrayNumberOfEntries(Node* descriptors);
1328  // Implements DescriptorArray::ToKeyIndex.
1329  // Returns an untagged IntPtr.
1330  Node* DescriptorArrayToKeyIndex(Node* descriptor_number);
1331  // Implements DescriptorArray::GetSortedKeyIndex.
1332  // Returns an untagged int32.
1333  Node* DescriptorArrayGetSortedKeyIndex(Node* descriptors,
1334                                         Node* descriptor_number);
1335  // Implements DescriptorArray::GetKey.
1336  Node* DescriptorArrayGetKey(Node* descriptors, Node* descriptor_number);
1337
1338  static const int kElementLoopUnrollThreshold = 8;
1339};
1340
1341class CodeStubArguments {
1342 public:
1343  typedef compiler::Node Node;
1344
1345  // |argc| is an uint32 value which specifies the number of arguments passed
1346  // to the builtin excluding the receiver.
1347  CodeStubArguments(CodeStubAssembler* assembler, Node* argc)
1348      : CodeStubArguments(assembler, argc, nullptr,
1349                          CodeStubAssembler::INTPTR_PARAMETERS) {}
1350  CodeStubArguments(CodeStubAssembler* assembler, Node* argc, Node* fp,
1351                    CodeStubAssembler::ParameterMode param_mode);
1352
1353  Node* GetReceiver() const;
1354
1355  Node* AtIndexPtr(Node* index, CodeStubAssembler::ParameterMode mode =
1356                                    CodeStubAssembler::INTPTR_PARAMETERS) const;
1357
1358  // |index| is zero-based and does not include the receiver
1359  Node* AtIndex(Node* index, CodeStubAssembler::ParameterMode mode =
1360                                 CodeStubAssembler::INTPTR_PARAMETERS) const;
1361
1362  Node* AtIndex(int index) const;
1363
1364  Node* GetLength() const { return argc_; }
1365
1366  typedef std::function<void(Node* arg)> ForEachBodyFunction;
1367
1368  // Iteration doesn't include the receiver. |first| and |last| are zero-based.
1369  void ForEach(const ForEachBodyFunction& body, Node* first = nullptr,
1370               Node* last = nullptr, CodeStubAssembler::ParameterMode mode =
1371                                         CodeStubAssembler::INTPTR_PARAMETERS) {
1372    CodeStubAssembler::VariableList list(0, assembler_->zone());
1373    ForEach(list, body, first, last);
1374  }
1375
1376  // Iteration doesn't include the receiver. |first| and |last| are zero-based.
1377  void ForEach(const CodeStubAssembler::VariableList& vars,
1378               const ForEachBodyFunction& body, Node* first = nullptr,
1379               Node* last = nullptr, CodeStubAssembler::ParameterMode mode =
1380                                         CodeStubAssembler::INTPTR_PARAMETERS);
1381
1382  void PopAndReturn(Node* value);
1383
1384 private:
1385  Node* GetArguments();
1386
1387  CodeStubAssembler* assembler_;
1388  CodeStubAssembler::ParameterMode argc_mode_;
1389  Node* argc_;
1390  Node* arguments_;
1391  Node* fp_;
1392};
1393
1394#ifdef DEBUG
1395#define CSA_ASSERT(csa, x) \
1396  (csa)->Assert([&] { return (x); }, #x, __FILE__, __LINE__)
1397#define CSA_ASSERT_JS_ARGC_OP(csa, Op, op, expected)               \
1398  (csa)->Assert(                                                   \
1399      [&] {                                                        \
1400        const CodeAssemblerState* state = (csa)->state();          \
1401        /* See Linkage::GetJSCallDescriptor(). */                  \
1402        int argc_index = state->parameter_count() - 2;             \
1403        compiler::Node* const argc = (csa)->Parameter(argc_index); \
1404        return (csa)->Op(argc, (csa)->Int32Constant(expected));    \
1405      },                                                           \
1406      "argc " #op " " #expected, __FILE__, __LINE__)
1407
1408#define CSA_ASSERT_JS_ARGC_EQ(csa, expected) \
1409  CSA_ASSERT_JS_ARGC_OP(csa, Word32Equal, ==, expected)
1410
1411#else
1412#define CSA_ASSERT(csa, x) ((void)0)
1413#define CSA_ASSERT_JS_ARGC_EQ(csa, expected) ((void)0)
1414#endif
1415
1416#ifdef ENABLE_SLOW_DCHECKS
1417#define CSA_SLOW_ASSERT(csa, x)                                 \
1418  if (FLAG_enable_slow_asserts) {                               \
1419    (csa)->Assert([&] { return (x); }, #x, __FILE__, __LINE__); \
1420  }
1421#else
1422#define CSA_SLOW_ASSERT(csa, x) ((void)0)
1423#endif
1424
1425DEFINE_OPERATORS_FOR_FLAGS(CodeStubAssembler::AllocationFlags);
1426
1427}  // namespace internal
1428}  // namespace v8
1429#endif  // V8_CODE_STUB_ASSEMBLER_H_
1430