Home | History | Annotate | Download | only in src
      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 
     14 namespace v8 {
     15 namespace internal {
     16 
     17 class CallInterfaceDescriptor;
     18 class CodeStubArguments;
     19 class StatsCounter;
     20 class StubCache;
     21 
     22 enum 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).
     56 class 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 
   1341 class 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 
   1425 DEFINE_OPERATORS_FOR_FLAGS(CodeStubAssembler::AllocationFlags);
   1426 
   1427 }  // namespace internal
   1428 }  // namespace v8
   1429 #endif  // V8_CODE_STUB_ASSEMBLER_H_
   1430