• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
OptimalParameterMode()79   ParameterMode OptimalParameterMode() const {
80     return Is64() ? INTPTR_PARAMETERS : SMI_PARAMETERS;
81   }
82 
ParameterRepresentation(ParameterMode mode)83   MachineRepresentation ParameterRepresentation(ParameterMode mode) const {
84     return mode == INTPTR_PARAMETERS ? MachineType::PointerRepresentation()
85                                      : MachineRepresentation::kTaggedSigned;
86   }
87 
OptimalParameterRepresentation()88   MachineRepresentation OptimalParameterRepresentation() const {
89     return ParameterRepresentation(OptimalParameterMode());
90   }
91 
ParameterToWord(Node * value,ParameterMode mode)92   Node* ParameterToWord(Node* value, ParameterMode mode) {
93     if (mode == SMI_PARAMETERS) value = SmiUntag(value);
94     return value;
95   }
96 
WordToParameter(Node * value,ParameterMode mode)97   Node* WordToParameter(Node* value, ParameterMode mode) {
98     if (mode == SMI_PARAMETERS) value = SmiTag(value);
99     return value;
100   }
101 
ParameterToTagged(Node * value,ParameterMode mode)102   Node* ParameterToTagged(Node* value, ParameterMode mode) {
103     if (mode != SMI_PARAMETERS) value = SmiTag(value);
104     return value;
105   }
106 
TaggedToParameter(Node * value,ParameterMode mode)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);
SmiFromWord(Node * value)172   Node* SmiFromWord(Node* value) { return SmiTag(value); }
173   Node* SmiFromWord32(Node* value);
SmiToWord(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   }
SMI_ARITHMETIC_BINOP(SmiAdd,IntPtrAdd)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 
SmiShr(Node * a,int shift)193   Node* SmiShr(Node* a, int shift) {
194     return BitcastWordToTaggedSigned(
195         WordAnd(WordShr(BitcastTaggedToWord(a), shift),
196                 BitcastTaggedToWord(SmiConstant(-1))));
197   }
198 
WordOrSmiShl(Node * a,int shift,ParameterMode mode)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 
WordOrSmiShr(Node * a,int shift,ParameterMode mode)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);
SelectSmiConstant(Node * condition,int 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   }
SelectSmiConstant(Node * condition,Smi * true_value,int false_value)270   Node* SelectSmiConstant(Node* condition, Smi* true_value, int false_value) {
271     return SelectSmiConstant(condition, true_value, Smi::FromInt(false_value));
272   }
SelectSmiConstant(Node * condition,int true_value,int false_value)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 
BranchIfSmiEqual(Node * a,Node * b,Label * if_true,Label * if_false)289   void BranchIfSmiEqual(Node* a, Node* b, Label* if_true, Label* if_false) {
290     Branch(SmiEqual(a, b), if_true, if_false);
291   }
292 
BranchIfSmiLessThan(Node * a,Node * b,Label * if_true,Label * if_false)293   void BranchIfSmiLessThan(Node* a, Node* b, Label* if_true, Label* if_false) {
294     Branch(SmiLessThan(a, b), if_true, if_false);
295   }
296 
BranchIfSmiLessThanOrEqual(Node * a,Node * b,Label * if_true,Label * if_false)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 
BranchIfFloat64IsNaN(Node * value,Label * if_true,Label * if_false)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>
DecodeWord32(Node * word32)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>
DecodeWord(Node * word)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>
DecodeWordFromWord32(Node * word32)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>
DecodeWord32FromWord(Node * word)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>
IsSetWord32(Node * word32)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.
IsSetWord32(Node * word32,uint32_t mask)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>
IsSetWord(Node * word)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.
IsSetWord(Node * word,uint32_t mask)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!
IsSetSmi(Node * smi,int untagged_mask)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>
IsClearWord32(Node * word32)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.
IsClearWord32(Node * word32,uint32_t mask)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>
IsClearWord(Node * word)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.
IsClearWord(Node * word,uint32_t mask)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>
EntryToIndex(Node * entry)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>
LoadDetailsByKeyIndex(Node * container,Node * key_index)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>
LoadValueByKeyIndex(Node * container,Node * key_index)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>
StoreDetailsByKeyIndex(Node * container,Node * key_index,Node * details)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>
StoreValueByKeyIndex(Node * container,Node * key_index,Node * value)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 
GetProperty(Node * context,Node * receiver,Handle<Name> name)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.
LoadKeyedSloppyArguments(Node * receiver,Node * key,Label * bailout)1078   Node* LoadKeyedSloppyArguments(Node* receiver, Node* key, Label* bailout) {
1079     return EmitKeyedSloppyArguments(receiver, key, nullptr, bailout);
1080   }
1081 
1082   // Emits keyed sloppy arguments store.
StoreKeyedSloppyArguments(Node * receiver,Node * key,Node * value,Label * bailout)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 
GetArrayAllocationSize(Node * element_count,ElementsKind kind,ParameterMode mode,int header_size)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 
GetFixedArrayAllocationSize(Node * element_count,ElementsKind kind,ParameterMode mode)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);
Print(Node * tagged_value)1265   inline void Print(Node* tagged_value) { return Print(nullptr, tagged_value); }
1266 
1267   template <class... TArgs>
MakeTypeError(MessageTemplate::Template message,Node * context,TArgs...args)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.
CodeStubArguments(CodeStubAssembler * assembler,Node * argc)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 
GetLength()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