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